Skip to content

Commit

Permalink
Merge pull request #21872 from jacobly0/tlsv1.2
Browse files Browse the repository at this point in the history
std.crypto.tls: implement TLSv1.2
  • Loading branch information
jacobly0 authored Nov 8, 2024
2 parents ee9f00d + 9373abf commit e5f5229
Show file tree
Hide file tree
Showing 8 changed files with 1,814 additions and 941 deletions.
27 changes: 17 additions & 10 deletions lib/std/crypto/25519/ed25519.zig
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,9 @@ pub const Ed25519 = struct {
a: Curve,
expected_r: Curve,

fn init(sig: Signature, public_key: PublicKey) (NonCanonicalError || EncodingError || IdentityElementError)!Verifier {
pub const InitError = NonCanonicalError || EncodingError || IdentityElementError;

fn init(sig: Signature, public_key: PublicKey) InitError!Verifier {
const r = sig.r;
const s = sig.s;
try Curve.scalar.rejectNonCanonical(s);
Expand All @@ -173,8 +175,11 @@ pub const Ed25519 = struct {
self.h.update(msg);
}

pub const VerifyError = WeakPublicKeyError || IdentityElementError ||
SignatureVerificationError;

/// Verify that the signature is valid for the entire message.
pub fn verify(self: *Verifier) (SignatureVerificationError || WeakPublicKeyError || IdentityElementError)!void {
pub fn verify(self: *Verifier) VerifyError!void {
var hram64: [Sha512.digest_length]u8 = undefined;
self.h.final(&hram64);
const hram = Curve.scalar.reduce64(hram64);
Expand All @@ -197,10 +202,10 @@ pub const Ed25519 = struct {
s: CompressedScalar,

/// Return the raw signature (r, s) in little-endian format.
pub fn toBytes(self: Signature) [encoded_length]u8 {
pub fn toBytes(sig: Signature) [encoded_length]u8 {
var bytes: [encoded_length]u8 = undefined;
bytes[0..Curve.encoded_length].* = self.r;
bytes[Curve.encoded_length..].* = self.s;
bytes[0..Curve.encoded_length].* = sig.r;
bytes[Curve.encoded_length..].* = sig.s;
return bytes;
}

Expand All @@ -214,17 +219,19 @@ pub const Ed25519 = struct {
}

/// Create a Verifier for incremental verification of a signature.
pub fn verifier(self: Signature, public_key: PublicKey) (NonCanonicalError || EncodingError || IdentityElementError)!Verifier {
return Verifier.init(self, public_key);
pub fn verifier(sig: Signature, public_key: PublicKey) Verifier.InitError!Verifier {
return Verifier.init(sig, public_key);
}

pub const VerifyError = Verifier.InitError || Verifier.VerifyError;

/// Verify the signature against a message and public key.
/// Return IdentityElement or NonCanonical if the public key or signature are not in the expected range,
/// or SignatureVerificationError if the signature is invalid for the given message and key.
pub fn verify(self: Signature, msg: []const u8, public_key: PublicKey) (IdentityElementError || NonCanonicalError || SignatureVerificationError || EncodingError || WeakPublicKeyError)!void {
var st = try Verifier.init(self, public_key);
pub fn verify(sig: Signature, msg: []const u8, public_key: PublicKey) VerifyError!void {
var st = try sig.verifier(public_key);
st.update(msg);
return st.verify();
try st.verify();
}
};

Expand Down
369 changes: 227 additions & 142 deletions lib/std/crypto/Certificate.zig

Large diffs are not rendered by default.

41 changes: 24 additions & 17 deletions lib/std/crypto/ecdsa.zig
Original file line number Diff line number Diff line change
Expand Up @@ -91,24 +91,26 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type {
s: Curve.scalar.CompressedScalar,

/// Create a Verifier for incremental verification of a signature.
pub fn verifier(self: Signature, public_key: PublicKey) (NonCanonicalError || EncodingError || IdentityElementError)!Verifier {
return Verifier.init(self, public_key);
pub fn verifier(sig: Signature, public_key: PublicKey) Verifier.InitError!Verifier {
return Verifier.init(sig, public_key);
}

pub const VerifyError = Verifier.InitError || Verifier.VerifyError;

/// Verify the signature against a message and public key.
/// Return IdentityElement or NonCanonical if the public key or signature are not in the expected range,
/// or SignatureVerificationError if the signature is invalid for the given message and key.
pub fn verify(self: Signature, msg: []const u8, public_key: PublicKey) (IdentityElementError || NonCanonicalError || SignatureVerificationError)!void {
var st = try Verifier.init(self, public_key);
pub fn verify(sig: Signature, msg: []const u8, public_key: PublicKey) VerifyError!void {
var st = try sig.verifier(public_key);
st.update(msg);
return st.verify();
try st.verify();
}

/// Return the raw signature (r, s) in big-endian format.
pub fn toBytes(self: Signature) [encoded_length]u8 {
pub fn toBytes(sig: Signature) [encoded_length]u8 {
var bytes: [encoded_length]u8 = undefined;
@memcpy(bytes[0 .. encoded_length / 2], &self.r);
@memcpy(bytes[encoded_length / 2 ..], &self.s);
@memcpy(bytes[0 .. encoded_length / 2], &sig.r);
@memcpy(bytes[encoded_length / 2 ..], &sig.s);
return bytes;
}

Expand All @@ -124,23 +126,23 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type {
/// Encode the signature using the DER format.
/// The maximum length of the DER encoding is der_encoded_length_max.
/// The function returns a slice, that can be shorter than der_encoded_length_max.
pub fn toDer(self: Signature, buf: *[der_encoded_length_max]u8) []u8 {
pub fn toDer(sig: Signature, buf: *[der_encoded_length_max]u8) []u8 {
var fb = io.fixedBufferStream(buf);
const w = fb.writer();
const r_len = @as(u8, @intCast(self.r.len + (self.r[0] >> 7)));
const s_len = @as(u8, @intCast(self.s.len + (self.s[0] >> 7)));
const r_len = @as(u8, @intCast(sig.r.len + (sig.r[0] >> 7)));
const s_len = @as(u8, @intCast(sig.s.len + (sig.s[0] >> 7)));
const seq_len = @as(u8, @intCast(2 + r_len + 2 + s_len));
w.writeAll(&[_]u8{ 0x30, seq_len }) catch unreachable;
w.writeAll(&[_]u8{ 0x02, r_len }) catch unreachable;
if (self.r[0] >> 7 != 0) {
if (sig.r[0] >> 7 != 0) {
w.writeByte(0x00) catch unreachable;
}
w.writeAll(&self.r) catch unreachable;
w.writeAll(&sig.r) catch unreachable;
w.writeAll(&[_]u8{ 0x02, s_len }) catch unreachable;
if (self.s[0] >> 7 != 0) {
if (sig.s[0] >> 7 != 0) {
w.writeByte(0x00) catch unreachable;
}
w.writeAll(&self.s) catch unreachable;
w.writeAll(&sig.s) catch unreachable;
return fb.getWritten();
}

Expand Down Expand Up @@ -236,7 +238,9 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type {
s: Curve.scalar.Scalar,
public_key: PublicKey,

fn init(sig: Signature, public_key: PublicKey) (IdentityElementError || NonCanonicalError)!Verifier {
pub const InitError = IdentityElementError || NonCanonicalError;

fn init(sig: Signature, public_key: PublicKey) InitError!Verifier {
const r = try Curve.scalar.Scalar.fromBytes(sig.r, .big);
const s = try Curve.scalar.Scalar.fromBytes(sig.s, .big);
if (r.isZero() or s.isZero()) return error.IdentityElement;
Expand All @@ -254,8 +258,11 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type {
self.h.update(data);
}

pub const VerifyError = IdentityElementError || NonCanonicalError ||
SignatureVerificationError;

/// Verify that the signature is valid for the entire message.
pub fn verify(self: *Verifier) (IdentityElementError || NonCanonicalError || SignatureVerificationError)!void {
pub fn verify(self: *Verifier) VerifyError!void {
const ht = Curve.scalar.encoded_length;
const h_len = @max(Hash.digest_length, ht);
var h: [h_len]u8 = [_]u8{0} ** h_len;
Expand Down
Loading

0 comments on commit e5f5229

Please sign in to comment.