authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-10-31 20:55:34-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-11-07 20:25:26-05:00
logc2a779ae79facc0c6a102825723ae707fdbf8c19
tree22043923bf37b6475617ab570d7366beda478a91
parentee9f00d673f2bccddc2751c328758a2820d2bb70

std.crypto.tls: implement TLSv1.2


6 files changed, 1538 insertions(+), 816 deletions(-)

lib/std/crypto/25519/ed25519.zig+25-11
......@@ -151,7 +151,9 @@ pub const Ed25519 = struct {
151151 a: Curve,
152152 expected_r: Curve,
153153
154 fn init(sig: Signature, public_key: PublicKey) (NonCanonicalError || EncodingError || IdentityElementError)!Verifier {
154 pub const InitError = NonCanonicalError || EncodingError || IdentityElementError;
155
156 fn init(sig: Signature, public_key: PublicKey) InitError!Verifier {
155157 const r = sig.r;
156158 const s = sig.s;
157159 try Curve.scalar.rejectNonCanonical(s);
......@@ -173,8 +175,11 @@ pub const Ed25519 = struct {
173175 self.h.update(msg);
174176 }
175177
178 pub const VerifyError = WeakPublicKeyError || IdentityElementError ||
179 SignatureVerificationError;
180
176181 /// Verify that the signature is valid for the entire message.
177 pub fn verify(self: *Verifier) (SignatureVerificationError || WeakPublicKeyError || IdentityElementError)!void {
182 pub fn verify(self: *Verifier) VerifyError!void {
178183 var hram64: [Sha512.digest_length]u8 = undefined;
179184 self.h.final(&hram64);
180185 const hram = Curve.scalar.reduce64(hram64);
......@@ -197,10 +202,10 @@ pub const Ed25519 = struct {
197202 s: CompressedScalar,
198203
199204 /// Return the raw signature (r, s) in little-endian format.
200 pub fn toBytes(self: Signature) [encoded_length]u8 {
205 pub fn toBytes(sig: Signature) [encoded_length]u8 {
201206 var bytes: [encoded_length]u8 = undefined;
202 bytes[0..Curve.encoded_length].* = self.r;
203 bytes[Curve.encoded_length..].* = self.s;
207 bytes[0..Curve.encoded_length].* = sig.r;
208 bytes[Curve.encoded_length..].* = sig.s;
204209 return bytes;
205210 }
206211
......@@ -214,17 +219,26 @@ pub const Ed25519 = struct {
214219 }
215220
216221 /// Create a Verifier for incremental verification of a signature.
217 pub fn verifier(self: Signature, public_key: PublicKey) (NonCanonicalError || EncodingError || IdentityElementError)!Verifier {
218 return Verifier.init(self, public_key);
222 pub fn verifier(sig: Signature, public_key: PublicKey) Verifier.InitError!Verifier {
223 return Verifier.init(sig, public_key);
219224 }
220225
226 pub const VerifyError = Verifier.InitError || Verifier.VerifyError;
227
221228 /// Verify the signature against a message and public key.
222229 /// Return IdentityElement or NonCanonical if the public key or signature are not in the expected range,
223230 /// or SignatureVerificationError if the signature is invalid for the given message and key.
224 pub fn verify(self: Signature, msg: []const u8, public_key: PublicKey) (IdentityElementError || NonCanonicalError || SignatureVerificationError || EncodingError || WeakPublicKeyError)!void {
225 var st = try Verifier.init(self, public_key);
226 st.update(msg);
227 return st.verify();
231 pub fn verify(sig: Signature, msg: []const u8, public_key: PublicKey) VerifyError!void {
232 try sig.concatVerify(&.{msg}, public_key);
233 }
234
235 /// Verify the signature against a concatenated message and public key.
236 /// Return IdentityElement or NonCanonical if the public key or signature are not in the expected range,
237 /// or SignatureVerificationError if the signature is invalid for the given message and key.
238 pub fn concatVerify(sig: Signature, msg: []const []const u8, public_key: PublicKey) VerifyError!void {
239 var st = try Verifier.init(sig, public_key);
240 for (msg) |part| st.update(part);
241 try st.verify();
228242 }
229243 };
230244
lib/std/crypto/Certificate.zig+227-142
......@@ -20,18 +20,18 @@ pub const Algorithm = enum {
2020 curveEd25519,
2121
2222 pub const map = std.StaticStringMap(Algorithm).initComptime(.{
23 .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05 }, .sha1WithRSAEncryption },
24 .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B }, .sha256WithRSAEncryption },
25 .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0C }, .sha384WithRSAEncryption },
26 .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0D }, .sha512WithRSAEncryption },
27 .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0E }, .sha224WithRSAEncryption },
28 .{ &[_]u8{ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x01 }, .ecdsa_with_SHA224 },
29 .{ &[_]u8{ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02 }, .ecdsa_with_SHA256 },
30 .{ &[_]u8{ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x03 }, .ecdsa_with_SHA384 },
31 .{ &[_]u8{ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x04 }, .ecdsa_with_SHA512 },
32 .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x02 }, .md2WithRSAEncryption },
33 .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x04 }, .md5WithRSAEncryption },
34 .{ &[_]u8{ 0x2B, 0x65, 0x70 }, .curveEd25519 },
23 .{ &.{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05 }, .sha1WithRSAEncryption },
24 .{ &.{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B }, .sha256WithRSAEncryption },
25 .{ &.{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0C }, .sha384WithRSAEncryption },
26 .{ &.{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0D }, .sha512WithRSAEncryption },
27 .{ &.{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0E }, .sha224WithRSAEncryption },
28 .{ &.{ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x01 }, .ecdsa_with_SHA224 },
29 .{ &.{ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02 }, .ecdsa_with_SHA256 },
30 .{ &.{ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x03 }, .ecdsa_with_SHA384 },
31 .{ &.{ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x04 }, .ecdsa_with_SHA512 },
32 .{ &.{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x02 }, .md2WithRSAEncryption },
33 .{ &.{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x04 }, .md5WithRSAEncryption },
34 .{ &.{ 0x2B, 0x65, 0x70 }, .curveEd25519 },
3535 });
3636
3737 pub fn Hash(comptime algorithm: Algorithm) type {
......@@ -49,13 +49,15 @@ pub const Algorithm = enum {
4949
5050pub const AlgorithmCategory = enum {
5151 rsaEncryption,
52 rsassa_pss,
5253 X9_62_id_ecPublicKey,
5354 curveEd25519,
5455
5556 pub const map = std.StaticStringMap(AlgorithmCategory).initComptime(.{
56 .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 }, .rsaEncryption },
57 .{ &[_]u8{ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01 }, .X9_62_id_ecPublicKey },
58 .{ &[_]u8{ 0x2B, 0x65, 0x70 }, .curveEd25519 },
57 .{ &.{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 }, .rsaEncryption },
58 .{ &.{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0A }, .rsassa_pss },
59 .{ &.{ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01 }, .X9_62_id_ecPublicKey },
60 .{ &.{ 0x2B, 0x65, 0x70 }, .curveEd25519 },
5961 });
6062};
6163
......@@ -74,18 +76,18 @@ pub const Attribute = enum {
7476 domainComponent,
7577
7678 pub const map = std.StaticStringMap(Attribute).initComptime(.{
77 .{ &[_]u8{ 0x55, 0x04, 0x03 }, .commonName },
78 .{ &[_]u8{ 0x55, 0x04, 0x05 }, .serialNumber },
79 .{ &[_]u8{ 0x55, 0x04, 0x06 }, .countryName },
80 .{ &[_]u8{ 0x55, 0x04, 0x07 }, .localityName },
81 .{ &[_]u8{ 0x55, 0x04, 0x08 }, .stateOrProvinceName },
82 .{ &[_]u8{ 0x55, 0x04, 0x09 }, .streetAddress },
83 .{ &[_]u8{ 0x55, 0x04, 0x0A }, .organizationName },
84 .{ &[_]u8{ 0x55, 0x04, 0x0B }, .organizationalUnitName },
85 .{ &[_]u8{ 0x55, 0x04, 0x11 }, .postalCode },
86 .{ &[_]u8{ 0x55, 0x04, 0x61 }, .organizationIdentifier },
87 .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x01 }, .pkcs9_emailAddress },
88 .{ &[_]u8{ 0x09, 0x92, 0x26, 0x89, 0x93, 0xF2, 0x2C, 0x64, 0x01, 0x19 }, .domainComponent },
79 .{ &.{ 0x55, 0x04, 0x03 }, .commonName },
80 .{ &.{ 0x55, 0x04, 0x05 }, .serialNumber },
81 .{ &.{ 0x55, 0x04, 0x06 }, .countryName },
82 .{ &.{ 0x55, 0x04, 0x07 }, .localityName },
83 .{ &.{ 0x55, 0x04, 0x08 }, .stateOrProvinceName },
84 .{ &.{ 0x55, 0x04, 0x09 }, .streetAddress },
85 .{ &.{ 0x55, 0x04, 0x0A }, .organizationName },
86 .{ &.{ 0x55, 0x04, 0x0B }, .organizationalUnitName },
87 .{ &.{ 0x55, 0x04, 0x11 }, .postalCode },
88 .{ &.{ 0x55, 0x04, 0x61 }, .organizationIdentifier },
89 .{ &.{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x01 }, .pkcs9_emailAddress },
90 .{ &.{ 0x09, 0x92, 0x26, 0x89, 0x93, 0xF2, 0x2C, 0x64, 0x01, 0x19 }, .domainComponent },
8991 });
9092};
9193
......@@ -95,9 +97,9 @@ pub const NamedCurve = enum {
9597 X9_62_prime256v1,
9698
9799 pub const map = std.StaticStringMap(NamedCurve).initComptime(.{
98 .{ &[_]u8{ 0x2B, 0x81, 0x04, 0x00, 0x22 }, .secp384r1 },
99 .{ &[_]u8{ 0x2B, 0x81, 0x04, 0x00, 0x23 }, .secp521r1 },
100 .{ &[_]u8{ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07 }, .X9_62_prime256v1 },
100 .{ &.{ 0x2B, 0x81, 0x04, 0x00, 0x22 }, .secp384r1 },
101 .{ &.{ 0x2B, 0x81, 0x04, 0x00, 0x23 }, .secp521r1 },
102 .{ &.{ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07 }, .X9_62_prime256v1 },
101103 });
102104
103105 pub fn Curve(comptime curve: NamedCurve) type {
......@@ -131,28 +133,28 @@ pub const ExtensionId = enum {
131133 netscape_comment,
132134
133135 pub const map = std.StaticStringMap(ExtensionId).initComptime(.{
134 .{ &[_]u8{ 0x55, 0x04, 0x03 }, .commonName },
135 .{ &[_]u8{ 0x55, 0x1D, 0x01 }, .authority_key_identifier },
136 .{ &[_]u8{ 0x55, 0x1D, 0x07 }, .subject_alt_name },
137 .{ &[_]u8{ 0x55, 0x1D, 0x0E }, .subject_key_identifier },
138 .{ &[_]u8{ 0x55, 0x1D, 0x0F }, .key_usage },
139 .{ &[_]u8{ 0x55, 0x1D, 0x0A }, .basic_constraints },
140 .{ &[_]u8{ 0x55, 0x1D, 0x10 }, .private_key_usage_period },
141 .{ &[_]u8{ 0x55, 0x1D, 0x11 }, .subject_alt_name },
142 .{ &[_]u8{ 0x55, 0x1D, 0x12 }, .issuer_alt_name },
143 .{ &[_]u8{ 0x55, 0x1D, 0x13 }, .basic_constraints },
144 .{ &[_]u8{ 0x55, 0x1D, 0x14 }, .crl_number },
145 .{ &[_]u8{ 0x55, 0x1D, 0x1F }, .crl_distribution_points },
146 .{ &[_]u8{ 0x55, 0x1D, 0x20 }, .certificate_policies },
147 .{ &[_]u8{ 0x55, 0x1D, 0x23 }, .authority_key_identifier },
148 .{ &[_]u8{ 0x55, 0x1D, 0x25 }, .ext_key_usage },
149 .{ &[_]u8{ 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x15, 0x01 }, .msCertsrvCAVersion },
150 .{ &[_]u8{ 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01 }, .info_access },
151 .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF6, 0x7D, 0x07, 0x41, 0x00 }, .entrustVersInfo },
152 .{ &[_]u8{ 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x14, 0x02 }, .enroll_certtype },
153 .{ &[_]u8{ 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x0c }, .pe_logotype },
154 .{ &[_]u8{ 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x01 }, .netscape_cert_type },
155 .{ &[_]u8{ 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x0d }, .netscape_comment },
136 .{ &.{ 0x55, 0x04, 0x03 }, .commonName },
137 .{ &.{ 0x55, 0x1D, 0x01 }, .authority_key_identifier },
138 .{ &.{ 0x55, 0x1D, 0x07 }, .subject_alt_name },
139 .{ &.{ 0x55, 0x1D, 0x0E }, .subject_key_identifier },
140 .{ &.{ 0x55, 0x1D, 0x0F }, .key_usage },
141 .{ &.{ 0x55, 0x1D, 0x0A }, .basic_constraints },
142 .{ &.{ 0x55, 0x1D, 0x10 }, .private_key_usage_period },
143 .{ &.{ 0x55, 0x1D, 0x11 }, .subject_alt_name },
144 .{ &.{ 0x55, 0x1D, 0x12 }, .issuer_alt_name },
145 .{ &.{ 0x55, 0x1D, 0x13 }, .basic_constraints },
146 .{ &.{ 0x55, 0x1D, 0x14 }, .crl_number },
147 .{ &.{ 0x55, 0x1D, 0x1F }, .crl_distribution_points },
148 .{ &.{ 0x55, 0x1D, 0x20 }, .certificate_policies },
149 .{ &.{ 0x55, 0x1D, 0x23 }, .authority_key_identifier },
150 .{ &.{ 0x55, 0x1D, 0x25 }, .ext_key_usage },
151 .{ &.{ 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x15, 0x01 }, .msCertsrvCAVersion },
152 .{ &.{ 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01 }, .info_access },
153 .{ &.{ 0x2A, 0x86, 0x48, 0x86, 0xF6, 0x7D, 0x07, 0x41, 0x00 }, .entrustVersInfo },
154 .{ &.{ 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x14, 0x02 }, .enroll_certtype },
155 .{ &.{ 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x0c }, .pe_logotype },
156 .{ &.{ 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x01 }, .netscape_cert_type },
157 .{ &.{ 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x0d }, .netscape_comment },
156158 });
157159};
158160
......@@ -185,6 +187,7 @@ pub const Parsed = struct {
185187
186188 pub const PubKeyAlgo = union(AlgorithmCategory) {
187189 rsaEncryption: void,
190 rsassa_pss: void,
188191 X9_62_id_ecPublicKey: NamedCurve,
189192 curveEd25519: void,
190193 };
......@@ -386,7 +389,7 @@ test "Parsed.checkHostName" {
386389 try expectEqual(true, Parsed.checkHostName("bar.ziglang.org", "*.Ziglang.ORG"));
387390}
388391
389pub const ParseError = der.Element.ParseElementError || ParseVersionError || ParseTimeError || ParseEnumError || ParseBitStringError;
392pub const ParseError = der.Element.ParseError || ParseVersionError || ParseTimeError || ParseEnumError || ParseBitStringError;
390393
391394pub fn parse(cert: Certificate) ParseError!Parsed {
392395 const cert_bytes = cert.buffer;
......@@ -413,13 +416,9 @@ pub fn parse(cert: Certificate) ParseError!Parsed {
413416 const pub_key_info = try der.Element.parse(cert_bytes, subject.slice.end);
414417 const pub_key_signature_algorithm = try der.Element.parse(cert_bytes, pub_key_info.slice.start);
415418 const pub_key_algo_elem = try der.Element.parse(cert_bytes, pub_key_signature_algorithm.slice.start);
416 const pub_key_algo_tag = try parseAlgorithmCategory(cert_bytes, pub_key_algo_elem);
417 var pub_key_algo: Parsed.PubKeyAlgo = undefined;
418 switch (pub_key_algo_tag) {
419 .rsaEncryption => {
420 pub_key_algo = .{ .rsaEncryption = {} };
421 },
422 .X9_62_id_ecPublicKey => {
419 const pub_key_algo: Parsed.PubKeyAlgo = switch (try parseAlgorithmCategory(cert_bytes, pub_key_algo_elem)) {
420 inline else => |tag| @unionInit(Parsed.PubKeyAlgo, @tagName(tag), {}),
421 .X9_62_id_ecPublicKey => pub_key_algo: {
423422 // RFC 5480 Section 2.1.1.1 Named Curve
424423 // ECParameters ::= CHOICE {
425424 // namedCurve OBJECT IDENTIFIER
......@@ -428,12 +427,9 @@ pub fn parse(cert: Certificate) ParseError!Parsed {
428427 // }
429428 const params_elem = try der.Element.parse(cert_bytes, pub_key_algo_elem.slice.end);
430429 const named_curve = try parseNamedCurve(cert_bytes, params_elem);
431 pub_key_algo = .{ .X9_62_id_ecPublicKey = named_curve };
432 },
433 .curveEd25519 => {
434 pub_key_algo = .{ .curveEd25519 = {} };
430 break :pub_key_algo .{ .X9_62_id_ecPublicKey = named_curve };
435431 },
436 }
432 };
437433 const pub_key_elem = try der.Element.parse(cert_bytes, pub_key_signature_algorithm.slice.end);
438434 const pub_key = try parseBitString(cert, pub_key_elem);
439435
......@@ -731,7 +727,7 @@ pub fn parseVersion(bytes: []const u8, version_elem: der.Element) ParseVersionEr
731727
732728fn verifyRsa(
733729 comptime Hash: type,
734 message: []const u8,
730 msg: []const u8,
735731 sig: []const u8,
736732 pub_key_algo: Parsed.PubKeyAlgo,
737733 pub_key: []const u8,
......@@ -743,59 +739,14 @@ fn verifyRsa(
743739 if (exponent.len > modulus.len) return error.CertificatePublicKeyInvalid;
744740 if (sig.len != modulus.len) return error.CertificateSignatureInvalidLength;
745741
746 const hash_der = switch (Hash) {
747 crypto.hash.Sha1 => [_]u8{
748 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e,
749 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14,
750 },
751 crypto.hash.sha2.Sha224 => [_]u8{
752 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
753 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05,
754 0x00, 0x04, 0x1c,
755 },
756 crypto.hash.sha2.Sha256 => [_]u8{
757 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
758 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
759 0x00, 0x04, 0x20,
760 },
761 crypto.hash.sha2.Sha384 => [_]u8{
762 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
763 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05,
764 0x00, 0x04, 0x30,
765 },
766 crypto.hash.sha2.Sha512 => [_]u8{
767 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
768 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
769 0x00, 0x04, 0x40,
770 },
771 else => @compileError("unreachable"),
772 };
773
774 var msg_hashed: [Hash.digest_length]u8 = undefined;
775 Hash.hash(message, &msg_hashed, .{});
776
777742 switch (modulus.len) {
778743 inline 128, 256, 384, 512 => |modulus_len| {
779 const ps_len = modulus_len - (hash_der.len + msg_hashed.len) - 3;
780 const em: [modulus_len]u8 =
781 [2]u8{ 0, 1 } ++
782 ([1]u8{0xff} ** ps_len) ++
783 [1]u8{0} ++
784 hash_der ++
785 msg_hashed;
786
787 const public_key = rsa.PublicKey.fromBytes(exponent, modulus) catch return error.CertificateSignatureInvalid;
788 const em_dec = rsa.encrypt(modulus_len, sig[0..modulus_len].*, public_key) catch |err| switch (err) {
789 error.MessageTooLong => unreachable,
790 };
791
792 if (!mem.eql(u8, &em, &em_dec)) {
744 const public_key = rsa.PublicKey.fromBytes(exponent, modulus) catch
745 return error.CertificateSignatureInvalid;
746 rsa.PKCS1v1_5Signature.verify(modulus_len, sig[0..modulus_len].*, msg, public_key, Hash) catch
793747 return error.CertificateSignatureInvalid;
794 }
795 },
796 else => {
797 return error.CertificateSignatureUnsupportedBitCount;
798748 },
749 else => return error.CertificateSignatureUnsupportedBitCount,
799750 }
800751}
801752
......@@ -908,9 +859,9 @@ pub const der = struct {
908859 pub const empty: Slice = .{ .start = 0, .end = 0 };
909860 };
910861
911 pub const ParseElementError = error{CertificateFieldHasInvalidLength};
862 pub const ParseError = error{CertificateFieldHasInvalidLength};
912863
913 pub fn parse(bytes: []const u8, index: u32) ParseElementError!Element {
864 pub fn parse(bytes: []const u8, index: u32) Element.ParseError!Element {
914865 var i = index;
915866 const identifier = @as(Identifier, @bitCast(bytes[i]));
916867 i += 1;
......@@ -958,21 +909,41 @@ pub const rsa = struct {
958909 const Modulus = std.crypto.ff.Modulus(max_modulus_bits);
959910 const Fe = Modulus.Fe;
960911
912 /// RFC 3447 8.1 RSASSA-PSS
961913 pub const PSSSignature = struct {
962914 pub fn fromBytes(comptime modulus_len: usize, msg: []const u8) [modulus_len]u8 {
963 var result = [1]u8{0} ** modulus_len;
964 std.mem.copyForwards(u8, &result, msg);
915 var result: [modulus_len]u8 = undefined;
916 @memcpy(result[0..msg.len], msg);
917 @memset(result[msg.len..], 0);
965918 return result;
966919 }
967920
968 pub fn verify(comptime modulus_len: usize, sig: [modulus_len]u8, msg: []const u8, public_key: PublicKey, comptime Hash: type) !void {
921 pub const VerifyError = EncryptError || error{InvalidSignature};
922
923 pub fn verify(
924 comptime modulus_len: usize,
925 sig: [modulus_len]u8,
926 msg: []const u8,
927 public_key: PublicKey,
928 comptime Hash: type,
929 ) VerifyError!void {
930 try concatVerify(modulus_len, sig, &.{msg}, public_key, Hash);
931 }
932
933 pub fn concatVerify(
934 comptime modulus_len: usize,
935 sig: [modulus_len]u8,
936 msg: []const []const u8,
937 public_key: PublicKey,
938 comptime Hash: type,
939 ) VerifyError!void {
969940 const mod_bits = public_key.n.bits();
970941 const em_dec = try encrypt(modulus_len, sig, public_key);
971942
972 EMSA_PSS_VERIFY(msg, &em_dec, mod_bits - 1, Hash.digest_length, Hash) catch unreachable;
943 try EMSA_PSS_VERIFY(msg, &em_dec, mod_bits - 1, Hash.digest_length, Hash);
973944 }
974945
975 fn EMSA_PSS_VERIFY(msg: []const u8, em: []const u8, emBit: usize, sLen: usize, comptime Hash: type) !void {
946 fn EMSA_PSS_VERIFY(msg: []const []const u8, em: []const u8, emBit: usize, sLen: usize, comptime Hash: type) VerifyError!void {
976947 // 1. If the length of M is greater than the input limitation for
977948 // the hash function (2^61 - 1 octets for SHA-1), output
978949 // "inconsistent" and stop.
......@@ -986,7 +957,11 @@ pub const rsa = struct {
986957
987958 // 2. Let mHash = Hash(M), an octet string of length hLen.
988959 var mHash: [Hash.digest_length]u8 = undefined;
989 Hash.hash(msg, &mHash, .{});
960 {
961 var hasher: Hash = .init(.{});
962 for (msg) |part| hasher.update(part);
963 hasher.final(&mHash);
964 }
990965
991966 // 3. If emLen < hLen + sLen + 2, output "inconsistent" and stop.
992967 if (emLen < Hash.digest_length + sLen + 2) {
......@@ -1082,25 +1057,14 @@ pub const rsa = struct {
10821057 }
10831058
10841059 fn MGF1(comptime Hash: type, out: []u8, seed: *const [Hash.digest_length]u8, len: usize) ![]u8 {
1085 var counter: usize = 0;
1060 var counter: u32 = 0;
10861061 var idx: usize = 0;
1087 var c: [4]u8 = undefined;
1088 var hash: [Hash.digest_length + c.len]u8 = undefined;
1089 @memcpy(hash[0..Hash.digest_length], seed);
1090 var hashed: [Hash.digest_length]u8 = undefined;
1062 var hash = seed.* ++ @as([4]u8, undefined);
10911063
10921064 while (idx < len) {
1093 c[0] = @as(u8, @intCast((counter >> 24) & 0xFF));
1094 c[1] = @as(u8, @intCast((counter >> 16) & 0xFF));
1095 c[2] = @as(u8, @intCast((counter >> 8) & 0xFF));
1096 c[3] = @as(u8, @intCast(counter & 0xFF));
1097
1098 std.mem.copyForwards(u8, hash[seed.len..], &c);
1099 Hash.hash(&hash, &hashed, .{});
1100
1101 std.mem.copyForwards(u8, out[idx..], &hashed);
1102 idx += hashed.len;
1103
1065 std.mem.writeInt(u32, hash[seed.len..][0..4], counter, .big);
1066 Hash.hash(&hash, out[idx..][0..Hash.digest_length], .{});
1067 idx += Hash.digest_length;
11041068 counter += 1;
11051069 }
11061070
......@@ -1108,11 +1072,128 @@ pub const rsa = struct {
11081072 }
11091073 };
11101074
1075 /// RFC 3447 8.2 RSASSA-PKCS1-v1_5
1076 pub const PKCS1v1_5Signature = struct {
1077 pub fn fromBytes(comptime modulus_len: usize, msg: []const u8) [modulus_len]u8 {
1078 var result: [modulus_len]u8 = undefined;
1079 @memcpy(result[0..msg.len], msg);
1080 @memset(result[msg.len..], 0);
1081 return result;
1082 }
1083
1084 pub const VerifyError = EncryptError || error{InvalidSignature};
1085
1086 pub fn verify(
1087 comptime modulus_len: usize,
1088 sig: [modulus_len]u8,
1089 msg: []const u8,
1090 public_key: PublicKey,
1091 comptime Hash: type,
1092 ) VerifyError!void {
1093 try concatVerify(modulus_len, sig, &.{msg}, public_key, Hash);
1094 }
1095
1096 pub fn concatVerify(
1097 comptime modulus_len: usize,
1098 sig: [modulus_len]u8,
1099 msg: []const []const u8,
1100 public_key: PublicKey,
1101 comptime Hash: type,
1102 ) VerifyError!void {
1103 const em_dec = try encrypt(modulus_len, sig, public_key);
1104 const em = try EMSA_PKCS1_V1_5_ENCODE(msg, modulus_len, Hash);
1105 if (!std.mem.eql(u8, &em_dec, &em)) return error.InvalidSignature;
1106 }
1107
1108 fn EMSA_PKCS1_V1_5_ENCODE(msg: []const []const u8, comptime emLen: usize, comptime Hash: type) VerifyError![emLen]u8 {
1109 comptime var em_index = emLen;
1110 var em: [emLen]u8 = undefined;
1111
1112 // 1. Apply the hash function to the message M to produce a hash value
1113 // H:
1114 //
1115 // H = Hash(M).
1116 //
1117 // If the hash function outputs "message too long," output "message
1118 // too long" and stop.
1119 var hasher: Hash = .init(.{});
1120 for (msg) |part| hasher.update(part);
1121 em_index -= Hash.digest_length;
1122 hasher.final(em[em_index..]);
1123
1124 // 2. Encode the algorithm ID for the hash function and the hash value
1125 // into an ASN.1 value of type DigestInfo (see Appendix A.2.4) with
1126 // the Distinguished Encoding Rules (DER), where the type DigestInfo
1127 // has the syntax
1128 //
1129 // DigestInfo ::= SEQUENCE {
1130 // digestAlgorithm AlgorithmIdentifier,
1131 // digest OCTET STRING
1132 // }
1133 //
1134 // The first field identifies the hash function and the second
1135 // contains the hash value. Let T be the DER encoding of the
1136 // DigestInfo value (see the notes below) and let tLen be the length
1137 // in octets of T.
1138 const hash_der: []const u8 = &switch (Hash) {
1139 crypto.hash.Sha1 => .{
1140 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e,
1141 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14,
1142 },
1143 crypto.hash.sha2.Sha224 => .{
1144 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
1145 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05,
1146 0x00, 0x04, 0x1c,
1147 },
1148 crypto.hash.sha2.Sha256 => .{
1149 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
1150 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
1151 0x00, 0x04, 0x20,
1152 },
1153 crypto.hash.sha2.Sha384 => .{
1154 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
1155 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05,
1156 0x00, 0x04, 0x30,
1157 },
1158 crypto.hash.sha2.Sha512 => .{
1159 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
1160 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
1161 0x00, 0x04, 0x40,
1162 },
1163 else => @compileError("unreachable"),
1164 };
1165 em_index -= hash_der.len;
1166 @memcpy(em[em_index..][0..hash_der.len], hash_der);
1167
1168 // 3. If emLen < tLen + 11, output "intended encoded message length too
1169 // short" and stop.
1170
1171 // 4. Generate an octet string PS consisting of emLen - tLen - 3 octets
1172 // with hexadecimal value 0xff. The length of PS will be at least 8
1173 // octets.
1174 em_index -= 1;
1175 @memset(em[2..em_index], 0xff);
1176
1177 // 5. Concatenate PS, the DER encoding T, and other padding to form the
1178 // encoded message EM as
1179 //
1180 // EM = 0x00 || 0x01 || PS || 0x00 || T.
1181 em[em_index] = 0x00;
1182 em[1] = 0x01;
1183 em[0] = 0x00;
1184
1185 // 6. Output EM.
1186 return em;
1187 }
1188 };
1189
11111190 pub const PublicKey = struct {
11121191 n: Modulus,
11131192 e: Fe,
11141193
1115 pub fn fromBytes(pub_bytes: []const u8, modulus_bytes: []const u8) !PublicKey {
1194 pub const FromBytesError = error{CertificatePublicKeyInvalid};
1195
1196 pub fn fromBytes(pub_bytes: []const u8, modulus_bytes: []const u8) FromBytesError!PublicKey {
11161197 // Reject modulus below 512 bits.
11171198 // 512-bit RSA was factored in 1999, so this limit barely means anything,
11181199 // but establish some limit now to ratchet in what we can.
......@@ -1137,7 +1218,9 @@ pub const rsa = struct {
11371218 };
11381219 }
11391220
1140 pub fn parseDer(pub_key: []const u8) !struct { modulus: []const u8, exponent: []const u8 } {
1221 pub const ParseDerError = der.Element.ParseError || error{CertificateFieldHasWrongDataType};
1222
1223 pub fn parseDer(pub_key: []const u8) ParseDerError!struct { modulus: []const u8, exponent: []const u8 } {
11411224 const pub_key_seq = try der.Element.parse(pub_key, 0);
11421225 if (pub_key_seq.identifier.tag != .sequence) return error.CertificateFieldHasWrongDataType;
11431226 const modulus_elem = try der.Element.parse(pub_key, pub_key_seq.slice.start);
......@@ -1156,7 +1239,9 @@ pub const rsa = struct {
11561239 }
11571240 };
11581241
1159 fn encrypt(comptime modulus_len: usize, msg: [modulus_len]u8, public_key: PublicKey) ![modulus_len]u8 {
1242 const EncryptError = error{MessageTooLong};
1243
1244 fn encrypt(comptime modulus_len: usize, msg: [modulus_len]u8, public_key: PublicKey) EncryptError![modulus_len]u8 {
11601245 const m = Fe.fromBytes(public_key.n, &msg, .big) catch return error.MessageTooLong;
11611246 const e = public_key.n.powPublic(m, public_key.e) catch unreachable;
11621247 var res: [modulus_len]u8 = undefined;
lib/std/crypto/ecdsa.zig+32-18
......@@ -91,24 +91,33 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type {
9191 s: Curve.scalar.CompressedScalar,
9292
9393 /// Create a Verifier for incremental verification of a signature.
94 pub fn verifier(self: Signature, public_key: PublicKey) (NonCanonicalError || EncodingError || IdentityElementError)!Verifier {
95 return Verifier.init(self, public_key);
94 pub fn verifier(sig: Signature, public_key: PublicKey) Verifier.InitError!Verifier {
95 return Verifier.init(sig, public_key);
9696 }
9797
98 pub const VerifyError = Verifier.InitError || Verifier.VerifyError;
99
98100 /// Verify the signature against a message and public key.
99101 /// Return IdentityElement or NonCanonical if the public key or signature are not in the expected range,
100102 /// or SignatureVerificationError if the signature is invalid for the given message and key.
101 pub fn verify(self: Signature, msg: []const u8, public_key: PublicKey) (IdentityElementError || NonCanonicalError || SignatureVerificationError)!void {
102 var st = try Verifier.init(self, public_key);
103 st.update(msg);
104 return st.verify();
103 pub fn verify(sig: Signature, msg: []const u8, public_key: PublicKey) VerifyError!void {
104 try sig.concatVerify(&.{msg}, public_key);
105 }
106
107 /// Verify the signature against a concatenated message and public key.
108 /// Return IdentityElement or NonCanonical if the public key or signature are not in the expected range,
109 /// or SignatureVerificationError if the signature is invalid for the given message and key.
110 pub fn concatVerify(sig: Signature, msg: []const []const u8, public_key: PublicKey) VerifyError!void {
111 var st = try Verifier.init(sig, public_key);
112 for (msg) |part| st.update(part);
113 try st.verify();
105114 }
106115
107116 /// Return the raw signature (r, s) in big-endian format.
108 pub fn toBytes(self: Signature) [encoded_length]u8 {
117 pub fn toBytes(sig: Signature) [encoded_length]u8 {
109118 var bytes: [encoded_length]u8 = undefined;
110 @memcpy(bytes[0 .. encoded_length / 2], &self.r);
111 @memcpy(bytes[encoded_length / 2 ..], &self.s);
119 @memcpy(bytes[0 .. encoded_length / 2], &sig.r);
120 @memcpy(bytes[encoded_length / 2 ..], &sig.s);
112121 return bytes;
113122 }
114123
......@@ -124,23 +133,23 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type {
124133 /// Encode the signature using the DER format.
125134 /// The maximum length of the DER encoding is der_encoded_length_max.
126135 /// The function returns a slice, that can be shorter than der_encoded_length_max.
127 pub fn toDer(self: Signature, buf: *[der_encoded_length_max]u8) []u8 {
136 pub fn toDer(sig: Signature, buf: *[der_encoded_length_max]u8) []u8 {
128137 var fb = io.fixedBufferStream(buf);
129138 const w = fb.writer();
130 const r_len = @as(u8, @intCast(self.r.len + (self.r[0] >> 7)));
131 const s_len = @as(u8, @intCast(self.s.len + (self.s[0] >> 7)));
139 const r_len = @as(u8, @intCast(sig.r.len + (sig.r[0] >> 7)));
140 const s_len = @as(u8, @intCast(sig.s.len + (sig.s[0] >> 7)));
132141 const seq_len = @as(u8, @intCast(2 + r_len + 2 + s_len));
133142 w.writeAll(&[_]u8{ 0x30, seq_len }) catch unreachable;
134143 w.writeAll(&[_]u8{ 0x02, r_len }) catch unreachable;
135 if (self.r[0] >> 7 != 0) {
144 if (sig.r[0] >> 7 != 0) {
136145 w.writeByte(0x00) catch unreachable;
137146 }
138 w.writeAll(&self.r) catch unreachable;
147 w.writeAll(&sig.r) catch unreachable;
139148 w.writeAll(&[_]u8{ 0x02, s_len }) catch unreachable;
140 if (self.s[0] >> 7 != 0) {
149 if (sig.s[0] >> 7 != 0) {
141150 w.writeByte(0x00) catch unreachable;
142151 }
143 w.writeAll(&self.s) catch unreachable;
152 w.writeAll(&sig.s) catch unreachable;
144153 return fb.getWritten();
145154 }
146155
......@@ -236,7 +245,9 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type {
236245 s: Curve.scalar.Scalar,
237246 public_key: PublicKey,
238247
239 fn init(sig: Signature, public_key: PublicKey) (IdentityElementError || NonCanonicalError)!Verifier {
248 pub const InitError = IdentityElementError || NonCanonicalError;
249
250 fn init(sig: Signature, public_key: PublicKey) InitError!Verifier {
240251 const r = try Curve.scalar.Scalar.fromBytes(sig.r, .big);
241252 const s = try Curve.scalar.Scalar.fromBytes(sig.s, .big);
242253 if (r.isZero() or s.isZero()) return error.IdentityElement;
......@@ -254,8 +265,11 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type {
254265 self.h.update(data);
255266 }
256267
268 pub const VerifyError = IdentityElementError || NonCanonicalError ||
269 SignatureVerificationError;
270
257271 /// Verify that the signature is valid for the entire message.
258 pub fn verify(self: *Verifier) (IdentityElementError || NonCanonicalError || SignatureVerificationError)!void {
272 pub fn verify(self: *Verifier) VerifyError!void {
259273 const ht = Curve.scalar.encoded_length;
260274 const h_len = @max(Hash.digest_length, ht);
261275 var h: [h_len]u8 = [_]u8{0} ** h_len;
lib/std/crypto/tls.zig+229-71
......@@ -54,6 +54,8 @@ pub const close_notify_alert = [_]u8{
5454};
5555
5656pub const ProtocolVersion = enum(u16) {
57 tls_1_0 = 0x0301,
58 tls_1_1 = 0x0302,
5759 tls_1_2 = 0x0303,
5860 tls_1_3 = 0x0304,
5961 _,
......@@ -69,14 +71,18 @@ pub const ContentType = enum(u8) {
6971};
7072
7173pub const HandshakeType = enum(u8) {
74 hello_request = 0,
7275 client_hello = 1,
7376 server_hello = 2,
7477 new_session_ticket = 4,
7578 end_of_early_data = 5,
7679 encrypted_extensions = 8,
7780 certificate = 11,
81 server_key_exchange = 12,
7882 certificate_request = 13,
83 server_hello_done = 14,
7984 certificate_verify = 15,
85 client_key_exchange = 16,
8086 finished = 20,
8187 key_update = 24,
8288 message_hash = 254,
......@@ -198,36 +204,36 @@ pub const AlertDescription = enum(u8) {
198204 _,
199205
200206 pub fn toError(alert: AlertDescription) Error!void {
201 return switch (alert) {
207 switch (alert) {
202208 .close_notify => {}, // not an error
203 .unexpected_message => error.TlsAlertUnexpectedMessage,
204 .bad_record_mac => error.TlsAlertBadRecordMac,
205 .record_overflow => error.TlsAlertRecordOverflow,
206 .handshake_failure => error.TlsAlertHandshakeFailure,
207 .bad_certificate => error.TlsAlertBadCertificate,
208 .unsupported_certificate => error.TlsAlertUnsupportedCertificate,
209 .certificate_revoked => error.TlsAlertCertificateRevoked,
210 .certificate_expired => error.TlsAlertCertificateExpired,
211 .certificate_unknown => error.TlsAlertCertificateUnknown,
212 .illegal_parameter => error.TlsAlertIllegalParameter,
213 .unknown_ca => error.TlsAlertUnknownCa,
214 .access_denied => error.TlsAlertAccessDenied,
215 .decode_error => error.TlsAlertDecodeError,
216 .decrypt_error => error.TlsAlertDecryptError,
217 .protocol_version => error.TlsAlertProtocolVersion,
218 .insufficient_security => error.TlsAlertInsufficientSecurity,
219 .internal_error => error.TlsAlertInternalError,
220 .inappropriate_fallback => error.TlsAlertInappropriateFallback,
209 .unexpected_message => return error.TlsAlertUnexpectedMessage,
210 .bad_record_mac => return error.TlsAlertBadRecordMac,
211 .record_overflow => return error.TlsAlertRecordOverflow,
212 .handshake_failure => return error.TlsAlertHandshakeFailure,
213 .bad_certificate => return error.TlsAlertBadCertificate,
214 .unsupported_certificate => return error.TlsAlertUnsupportedCertificate,
215 .certificate_revoked => return error.TlsAlertCertificateRevoked,
216 .certificate_expired => return error.TlsAlertCertificateExpired,
217 .certificate_unknown => return error.TlsAlertCertificateUnknown,
218 .illegal_parameter => return error.TlsAlertIllegalParameter,
219 .unknown_ca => return error.TlsAlertUnknownCa,
220 .access_denied => return error.TlsAlertAccessDenied,
221 .decode_error => return error.TlsAlertDecodeError,
222 .decrypt_error => return error.TlsAlertDecryptError,
223 .protocol_version => return error.TlsAlertProtocolVersion,
224 .insufficient_security => return error.TlsAlertInsufficientSecurity,
225 .internal_error => return error.TlsAlertInternalError,
226 .inappropriate_fallback => return error.TlsAlertInappropriateFallback,
221227 .user_canceled => {}, // not an error
222 .missing_extension => error.TlsAlertMissingExtension,
223 .unsupported_extension => error.TlsAlertUnsupportedExtension,
224 .unrecognized_name => error.TlsAlertUnrecognizedName,
225 .bad_certificate_status_response => error.TlsAlertBadCertificateStatusResponse,
226 .unknown_psk_identity => error.TlsAlertUnknownPskIdentity,
227 .certificate_required => error.TlsAlertCertificateRequired,
228 .no_application_protocol => error.TlsAlertNoApplicationProtocol,
229 _ => error.TlsAlertUnknown,
230 };
228 .missing_extension => return error.TlsAlertMissingExtension,
229 .unsupported_extension => return error.TlsAlertUnsupportedExtension,
230 .unrecognized_name => return error.TlsAlertUnrecognizedName,
231 .bad_certificate_status_response => return error.TlsAlertBadCertificateStatusResponse,
232 .unknown_psk_identity => return error.TlsAlertUnknownPskIdentity,
233 .certificate_required => return error.TlsAlertCertificateRequired,
234 .no_application_protocol => return error.TlsAlertNoApplicationProtocol,
235 _ => return error.TlsAlertUnknown,
236 }
231237 }
232238};
233239
......@@ -286,6 +292,20 @@ pub const NamedGroup = enum(u16) {
286292};
287293
288294pub const CipherSuite = enum(u16) {
295 RSA_WITH_AES_128_CBC_SHA = 0x002F,
296 DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033,
297 RSA_WITH_AES_256_CBC_SHA = 0x0035,
298 DHE_RSA_WITH_AES_256_CBC_SHA = 0x0039,
299 RSA_WITH_AES_128_CBC_SHA256 = 0x003C,
300 RSA_WITH_AES_256_CBC_SHA256 = 0x003D,
301 DHE_RSA_WITH_AES_128_CBC_SHA256 = 0x0067,
302 DHE_RSA_WITH_AES_256_CBC_SHA256 = 0x006B,
303 RSA_WITH_AES_128_GCM_SHA256 = 0x009C,
304 RSA_WITH_AES_256_GCM_SHA384 = 0x009D,
305 DHE_RSA_WITH_AES_128_GCM_SHA256 = 0x009E,
306 DHE_RSA_WITH_AES_256_GCM_SHA384 = 0x009F,
307 EMPTY_RENEGOTIATION_INFO_SCSV = 0x00FF,
308
289309 AES_128_GCM_SHA256 = 0x1301,
290310 AES_256_GCM_SHA384 = 0x1302,
291311 CHACHA20_POLY1305_SHA256 = 0x1303,
......@@ -293,7 +313,98 @@ pub const CipherSuite = enum(u16) {
293313 AES_128_CCM_8_SHA256 = 0x1305,
294314 AEGIS_256_SHA512 = 0x1306,
295315 AEGIS_128L_SHA256 = 0x1307,
316
317 ECDHE_ECDSA_WITH_AES_128_CBC_SHA = 0xC009,
318 ECDHE_ECDSA_WITH_AES_256_CBC_SHA = 0xC00A,
319 ECDHE_RSA_WITH_AES_128_CBC_SHA = 0xC013,
320 ECDHE_RSA_WITH_AES_256_CBC_SHA = 0xC014,
321 ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC023,
322 ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC024,
323 ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xC027,
324 ECDHE_RSA_WITH_AES_256_CBC_SHA384 = 0xC028,
325 ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02B,
326 ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = 0xC02C,
327 ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xC02F,
328 ECDHE_RSA_WITH_AES_256_GCM_SHA384 = 0xC030,
329
330 ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCA8,
331 ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCA9,
332 DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCAA,
333
296334 _,
335
336 pub const With = enum {
337 AES_128_CBC_SHA,
338 AES_256_CBC_SHA,
339 AES_128_CBC_SHA256,
340 AES_256_CBC_SHA256,
341 AES_256_CBC_SHA384,
342
343 AES_128_GCM_SHA256,
344 AES_256_GCM_SHA384,
345
346 CHACHA20_POLY1305_SHA256,
347
348 AES_128_CCM_SHA256,
349 AES_128_CCM_8_SHA256,
350
351 AEGIS_256_SHA512,
352 AEGIS_128L_SHA256,
353 };
354
355 pub fn with(cipher_suite: CipherSuite) With {
356 return switch (cipher_suite) {
357 .RSA_WITH_AES_128_CBC_SHA,
358 .DHE_RSA_WITH_AES_128_CBC_SHA,
359 .ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
360 .ECDHE_RSA_WITH_AES_128_CBC_SHA,
361 => .AES_128_CBC_SHA,
362 .RSA_WITH_AES_256_CBC_SHA,
363 .DHE_RSA_WITH_AES_256_CBC_SHA,
364 .ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
365 .ECDHE_RSA_WITH_AES_256_CBC_SHA,
366 => .AES_256_CBC_SHA,
367 .RSA_WITH_AES_128_CBC_SHA256,
368 .DHE_RSA_WITH_AES_128_CBC_SHA256,
369 .ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
370 .ECDHE_RSA_WITH_AES_128_CBC_SHA256,
371 => .AES_128_CBC_SHA256,
372 .RSA_WITH_AES_256_CBC_SHA256,
373 .DHE_RSA_WITH_AES_256_CBC_SHA256,
374 => .AES_256_CBC_SHA256,
375 .ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
376 .ECDHE_RSA_WITH_AES_256_CBC_SHA384,
377 => .AES_256_CBC_SHA384,
378
379 .RSA_WITH_AES_128_GCM_SHA256,
380 .DHE_RSA_WITH_AES_128_GCM_SHA256,
381 .AES_128_GCM_SHA256,
382 .ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
383 .ECDHE_RSA_WITH_AES_128_GCM_SHA256,
384 => .AES_128_GCM_SHA256,
385 .RSA_WITH_AES_256_GCM_SHA384,
386 .DHE_RSA_WITH_AES_256_GCM_SHA384,
387 .AES_256_GCM_SHA384,
388 .ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
389 .ECDHE_RSA_WITH_AES_256_GCM_SHA384,
390 => .AES_256_GCM_SHA384,
391
392 .CHACHA20_POLY1305_SHA256,
393 .ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
394 .ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
395 .DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
396 => .CHACHA20_POLY1305_SHA256,
397
398 .AES_128_CCM_SHA256 => .AES_128_CCM_SHA256,
399 .AES_128_CCM_8_SHA256 => .AES_128_CCM_8_SHA256,
400
401 .AEGIS_256_SHA512 => .AEGIS_256_SHA512,
402 .AEGIS_128L_SHA256 => .AEGIS_128L_SHA256,
403
404 .EMPTY_RENEGOTIATION_INFO_SCSV => unreachable,
405 _ => unreachable,
406 };
407 }
297408};
298409
299410pub const CertificateType = enum(u8) {
......@@ -308,58 +419,108 @@ pub const KeyUpdateRequest = enum(u8) {
308419 _,
309420};
310421
311pub fn HandshakeCipherT(comptime AeadType: type, comptime HashType: type) type {
422pub fn HandshakeCipherT(comptime AeadType: type, comptime HashType: type, comptime explicit_iv_length: comptime_int) type {
312423 return struct {
313 pub const AEAD = AeadType;
314 pub const Hash = HashType;
315 pub const Hmac = crypto.auth.hmac.Hmac(Hash);
316 pub const Hkdf = crypto.kdf.hkdf.Hkdf(Hmac);
424 pub const A = ApplicationCipherT(AeadType, HashType, explicit_iv_length);
317425
318 handshake_secret: [Hkdf.prk_length]u8,
319 master_secret: [Hkdf.prk_length]u8,
320 client_handshake_key: [AEAD.key_length]u8,
321 server_handshake_key: [AEAD.key_length]u8,
322 client_finished_key: [Hmac.key_length]u8,
323 server_finished_key: [Hmac.key_length]u8,
324 client_handshake_iv: [AEAD.nonce_length]u8,
325 server_handshake_iv: [AEAD.nonce_length]u8,
326 transcript_hash: Hash,
426 transcript_hash: A.Hash,
427 version: union {
428 tls_1_2: struct {
429 server_verify_data: [12]u8,
430 app_cipher: A.Tls_1_2,
431 },
432 tls_1_3: struct {
433 handshake_secret: [A.Hkdf.prk_length]u8,
434 master_secret: [A.Hkdf.prk_length]u8,
435 client_handshake_key: [A.AEAD.key_length]u8,
436 server_handshake_key: [A.AEAD.key_length]u8,
437 client_finished_key: [A.Hmac.key_length]u8,
438 server_finished_key: [A.Hmac.key_length]u8,
439 client_handshake_iv: [A.AEAD.nonce_length]u8,
440 server_handshake_iv: [A.AEAD.nonce_length]u8,
441 },
442 },
327443 };
328444}
329445
330446pub const HandshakeCipher = union(enum) {
331 AES_128_GCM_SHA256: HandshakeCipherT(crypto.aead.aes_gcm.Aes128Gcm, crypto.hash.sha2.Sha256),
332 AES_256_GCM_SHA384: HandshakeCipherT(crypto.aead.aes_gcm.Aes256Gcm, crypto.hash.sha2.Sha384),
333 CHACHA20_POLY1305_SHA256: HandshakeCipherT(crypto.aead.chacha_poly.ChaCha20Poly1305, crypto.hash.sha2.Sha256),
334 AEGIS_256_SHA512: HandshakeCipherT(crypto.aead.aegis.Aegis256, crypto.hash.sha2.Sha512),
335 AEGIS_128L_SHA256: HandshakeCipherT(crypto.aead.aegis.Aegis128L, crypto.hash.sha2.Sha256),
447 AES_128_GCM_SHA256: HandshakeCipherT(crypto.aead.aes_gcm.Aes128Gcm, crypto.hash.sha2.Sha256, 8),
448 AES_256_GCM_SHA384: HandshakeCipherT(crypto.aead.aes_gcm.Aes256Gcm, crypto.hash.sha2.Sha384, 8),
449 CHACHA20_POLY1305_SHA256: HandshakeCipherT(crypto.aead.chacha_poly.ChaCha20Poly1305, crypto.hash.sha2.Sha256, 0),
450 AEGIS_256_SHA512: HandshakeCipherT(crypto.aead.aegis.Aegis256, crypto.hash.sha2.Sha512, 0),
451 AEGIS_128L_SHA256: HandshakeCipherT(crypto.aead.aegis.Aegis128L, crypto.hash.sha2.Sha256, 0),
336452};
337453
338pub fn ApplicationCipherT(comptime AeadType: type, comptime HashType: type) type {
339 return struct {
454pub fn ApplicationCipherT(comptime AeadType: type, comptime HashType: type, comptime explicit_iv_length: comptime_int) type {
455 return union {
340456 pub const AEAD = AeadType;
341457 pub const Hash = HashType;
342458 pub const Hmac = crypto.auth.hmac.Hmac(Hash);
343459 pub const Hkdf = crypto.kdf.hkdf.Hkdf(Hmac);
344460
345 client_secret: [Hash.digest_length]u8,
346 server_secret: [Hash.digest_length]u8,
347 client_key: [AEAD.key_length]u8,
348 server_key: [AEAD.key_length]u8,
349 client_iv: [AEAD.nonce_length]u8,
350 server_iv: [AEAD.nonce_length]u8,
461 pub const enc_key_length = AEAD.key_length;
462 pub const fixed_iv_length = AEAD.nonce_length - explicit_iv_length;
463 pub const record_iv_length = explicit_iv_length;
464 pub const mac_length = AEAD.tag_length;
465 pub const mac_key_length = Hmac.key_length_min;
466
467 tls_1_2: Tls_1_2,
468 tls_1_3: Tls_1_3,
469
470 pub const Tls_1_2 = extern struct {
471 client_write_MAC_key: [mac_key_length]u8,
472 server_write_MAC_key: [mac_key_length]u8,
473 client_write_key: [enc_key_length]u8,
474 server_write_key: [enc_key_length]u8,
475 client_write_IV: [fixed_iv_length]u8,
476 server_write_IV: [fixed_iv_length]u8,
477 // non-standard entropy
478 client_salt: [record_iv_length]u8,
479 };
480
481 pub const Tls_1_3 = struct {
482 client_secret: [Hash.digest_length]u8,
483 server_secret: [Hash.digest_length]u8,
484 client_key: [AEAD.key_length]u8,
485 server_key: [AEAD.key_length]u8,
486 client_iv: [AEAD.nonce_length]u8,
487 server_iv: [AEAD.nonce_length]u8,
488 };
351489 };
352490}
353491
354492/// Encryption parameters for application traffic.
355493pub const ApplicationCipher = union(enum) {
356 AES_128_GCM_SHA256: ApplicationCipherT(crypto.aead.aes_gcm.Aes128Gcm, crypto.hash.sha2.Sha256),
357 AES_256_GCM_SHA384: ApplicationCipherT(crypto.aead.aes_gcm.Aes256Gcm, crypto.hash.sha2.Sha384),
358 CHACHA20_POLY1305_SHA256: ApplicationCipherT(crypto.aead.chacha_poly.ChaCha20Poly1305, crypto.hash.sha2.Sha256),
359 AEGIS_256_SHA512: ApplicationCipherT(crypto.aead.aegis.Aegis256, crypto.hash.sha2.Sha512),
360 AEGIS_128L_SHA256: ApplicationCipherT(crypto.aead.aegis.Aegis128L, crypto.hash.sha2.Sha256),
494 AES_128_GCM_SHA256: ApplicationCipherT(crypto.aead.aes_gcm.Aes128Gcm, crypto.hash.sha2.Sha256, 8),
495 AES_256_GCM_SHA384: ApplicationCipherT(crypto.aead.aes_gcm.Aes256Gcm, crypto.hash.sha2.Sha384, 8),
496 CHACHA20_POLY1305_SHA256: ApplicationCipherT(crypto.aead.chacha_poly.ChaCha20Poly1305, crypto.hash.sha2.Sha256, 0),
497 AEGIS_256_SHA512: ApplicationCipherT(crypto.aead.aegis.Aegis256, crypto.hash.sha2.Sha512, 0),
498 AEGIS_128L_SHA256: ApplicationCipherT(crypto.aead.aegis.Aegis128L, crypto.hash.sha2.Sha256, 0),
361499};
362500
501pub fn hmacExpandLabel(
502 comptime Hmac: type,
503 secret: []const u8,
504 label_then_seed: []const []const u8,
505 comptime len: usize,
506) [len]u8 {
507 const initial_hmac: Hmac = .init(secret);
508 var a: [Hmac.mac_length]u8 = undefined;
509 var result: [std.mem.alignForwardAnyAlign(usize, len, Hmac.mac_length)]u8 = undefined;
510 var index: usize = 0;
511 while (index < result.len) : (index += Hmac.mac_length) {
512 var a_hmac = initial_hmac;
513 if (index > 0) a_hmac.update(&a) else for (label_then_seed) |part| a_hmac.update(part);
514 a_hmac.final(&a);
515
516 var result_hmac = initial_hmac;
517 result_hmac.update(&a);
518 for (label_then_seed) |part| result_hmac.update(part);
519 result_hmac.final(result[index..][0..Hmac.mac_length]);
520 }
521 return result[0..len].*;
522}
523
363524pub fn hkdfExpandLabel(
364525 comptime Hkdf: type,
365526 key: [Hkdf.prk_length]u8,
......@@ -418,19 +579,16 @@ pub inline fn enum_array(comptime E: type, comptime tags: []const E) [2 + @sizeO
418579 return array(2, result);
419580}
420581
421pub inline fn int2(x: u16) [2]u8 {
422 return .{
423 @as(u8, @truncate(x >> 8)),
424 @as(u8, @truncate(x)),
425 };
582pub inline fn int2(int: u16) [2]u8 {
583 var arr: [2]u8 = undefined;
584 std.mem.writeInt(u16, &arr, int, .big);
585 return arr;
426586}
427587
428pub inline fn int3(x: u24) [3]u8 {
429 return .{
430 @as(u8, @truncate(x >> 16)),
431 @as(u8, @truncate(x >> 8)),
432 @as(u8, @truncate(x)),
433 };
588pub inline fn int3(int: u24) [3]u8 {
589 var arr: [3]u8 = undefined;
590 std.mem.writeInt(u24, &arr, int, .big);
591 return arr;
434592}
435593
436594/// An abstraction to ensure that protocol-parsing code does not perform an
lib/std/crypto/tls/Client.zig+1004-571
......@@ -8,12 +8,14 @@ const assert = std.debug.assert;
88const Certificate = std.crypto.Certificate;
99
1010const max_ciphertext_len = tls.max_ciphertext_len;
11const hmacExpandLabel = tls.hmacExpandLabel;
1112const hkdfExpandLabel = tls.hkdfExpandLabel;
1213const int2 = tls.int2;
1314const int3 = tls.int3;
1415const array = tls.array;
1516const enum_array = tls.enum_array;
1617
18tls_version: tls.ProtocolVersion,
1719read_seq: u64,
1820write_seq: u64,
1921/// The starting index of cleartext bytes inside `partially_read_buffer`.
......@@ -136,7 +138,7 @@ pub fn InitError(comptime Stream: type) type {
136138 };
137139}
138140
139/// Initiates a TLS handshake and establishes a TLSv1.3 session with `stream`, which
141/// Initiates a TLS handshake and establishes a TLSv1.2 or TLSv1.3 session with `stream`, which
140142/// must conform to `StreamInterface`.
141143///
142144/// `host` is only borrowed during this function call.
......@@ -145,26 +147,20 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
145147
146148 var random_buffer: [128]u8 = undefined;
147149 crypto.random.bytes(&random_buffer);
148 const hello_rand = random_buffer[0..32].*;
150 const client_hello_rand = random_buffer[0..32].*;
151 var server_hello_rand: [32]u8 = undefined;
149152 const legacy_session_id = random_buffer[32..64].*;
150 const x25519_kp_seed = random_buffer[64..96].*;
151 const secp256r1_kp_seed = random_buffer[96..128].*;
152153
153 const x25519_kp = crypto.dh.X25519.KeyPair.create(x25519_kp_seed) catch |err| switch (err) {
154 // Only possible to happen if the private key is all zeroes.
154 var key_share = KeyShare.init(random_buffer[64..128].*) catch |err| switch (err) {
155 // Only possible to happen if the seed is all zeroes.
155156 error.IdentityElement => return error.InsufficientEntropy,
156157 };
157 const secp256r1_kp = crypto.sign.ecdsa.EcdsaP256Sha256.KeyPair.create(secp256r1_kp_seed) catch |err| switch (err) {
158 // Only possible to happen if the private key is all zeroes.
159 error.IdentityElement => return error.InsufficientEntropy,
160 };
161 const ml_kem768_kp = crypto.kem.ml_kem.MLKem768.KeyPair.create(null) catch {};
162158
163159 const extensions_payload =
164 tls.extension(.supported_versions, [_]u8{
165 0x02, // byte length of supported versions
166 0x03, 0x04, // TLS 1.3
167 }) ++ tls.extension(.signature_algorithms, enum_array(tls.SignatureScheme, &.{
160 tls.extension(.supported_versions, [_]u8{2 + 2} ++ // byte length of supported versions
161 int2(@intFromEnum(tls.ProtocolVersion.tls_1_3)) ++
162 int2(@intFromEnum(tls.ProtocolVersion.tls_1_2))) ++
163 tls.extension(.signature_algorithms, enum_array(tls.SignatureScheme, &.{
168164 .ecdsa_secp256r1_sha256,
169165 .ecdsa_secp384r1_sha384,
170166 .rsa_pss_rsae_sha256,
......@@ -178,11 +174,11 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
178174 })) ++ tls.extension(
179175 .key_share,
180176 array(1, int2(@intFromEnum(tls.NamedGroup.x25519)) ++
181 array(1, x25519_kp.public_key) ++
177 array(1, key_share.x25519_kp.public_key) ++
182178 int2(@intFromEnum(tls.NamedGroup.secp256r1)) ++
183 array(1, secp256r1_kp.public_key.toUncompressedSec1()) ++
179 array(1, key_share.secp256r1_kp.public_key.toUncompressedSec1()) ++
184180 int2(@intFromEnum(tls.NamedGroup.x25519_ml_kem768)) ++
185 array(1, x25519_kp.public_key ++ ml_kem768_kp.public_key.toBytes())),
181 array(1, key_share.x25519_kp.public_key ++ key_share.ml_kem768_kp.public_key.toBytes())),
186182 ) ++
187183 int2(@intFromEnum(tls.ExtensionType.server_name)) ++
188184 int2(host_len + 5) ++ // byte length of this extension payload
......@@ -198,7 +194,7 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
198194
199195 const client_hello =
200196 int2(@intFromEnum(tls.ProtocolVersion.tls_1_2)) ++
201 hello_rand ++
197 client_hello_rand ++
202198 [1]u8{32} ++ legacy_session_id ++
203199 cipher_suites ++
204200 int2(legacy_compression_methods) ++
......@@ -209,16 +205,16 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
209205 int3(@intCast(client_hello.len + host_len)) ++
210206 client_hello;
211207
212 const plaintext_header = [_]u8{
213 @intFromEnum(tls.ContentType.handshake),
214 0x03, 0x01, // legacy_record_version
215 } ++ int2(@intCast(out_handshake.len + host_len)) ++ out_handshake;
208 const cleartext_header = [_]u8{@intFromEnum(tls.ContentType.handshake)} ++
209 int2(@intFromEnum(tls.ProtocolVersion.tls_1_0)) ++ // legacy_record_version
210 int2(@intCast(out_handshake.len + host_len)) ++
211 out_handshake;
216212
217213 {
218214 var iovecs = [_]std.posix.iovec_const{
219215 .{
220 .base = &plaintext_header,
221 .len = plaintext_header.len,
216 .base = &cleartext_header,
217 .len = cleartext_header.len,
222218 },
223219 .{
224220 .base = host.ptr,
......@@ -228,8 +224,10 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
228224 try stream.writevAll(&iovecs);
229225 }
230226
231 const client_hello_bytes1 = plaintext_header[5..];
227 const client_hello_bytes1 = cleartext_header[tls.record_header_len..];
232228
229 var tls_version: tls.ProtocolVersion = undefined;
230 var cipher_suite_tag: tls.CipherSuite = undefined;
233231 var handshake_cipher: tls.HandshakeCipher = undefined;
234232 var handshake_buffer: [8000]u8 = undefined;
235233 var d: tls.Decoder = .{ .buf = &handshake_buffer };
......@@ -259,10 +257,10 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
259257 if (handshake_type != .server_hello) return error.TlsUnexpectedMessage;
260258 const length = ptd.decode(u24);
261259 var hsd = try ptd.sub(length);
262 try hsd.ensure(2 + 32 + 1 + 32 + 2 + 1 + 2);
260 try hsd.ensure(2 + 32 + 1 + 32 + 2 + 1);
263261 const legacy_version = hsd.decode(u16);
264 const random = hsd.array(32);
265 if (mem.eql(u8, random, &tls.hello_retry_request_sequence)) {
262 @memcpy(&server_hello_rand, hsd.array(32));
263 if (mem.eql(u8, &server_hello_rand, &tls.hello_retry_request_sequence)) {
266264 // This is a HelloRetryRequest message. This client implementation
267265 // does not expect to get one.
268266 return error.TlsUnexpectedMessage;
......@@ -270,83 +268,44 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
270268 const legacy_session_id_echo_len = hsd.decode(u8);
271269 if (legacy_session_id_echo_len != 32) return error.TlsIllegalParameter;
272270 const legacy_session_id_echo = hsd.array(32);
273 if (!mem.eql(u8, legacy_session_id_echo, &legacy_session_id))
274 return error.TlsIllegalParameter;
275 const cipher_suite_tag = hsd.decode(tls.CipherSuite);
271 cipher_suite_tag = hsd.decode(tls.CipherSuite);
276272 hsd.skip(1); // legacy_compression_method
277 const extensions_size = hsd.decode(u16);
278 var all_extd = try hsd.sub(extensions_size);
279 var supported_version: u16 = 0;
280 var shared_key: []const u8 = undefined;
281 var have_shared_key = false;
282 while (!all_extd.eof()) {
283 try all_extd.ensure(2 + 2);
284 const et = all_extd.decode(tls.ExtensionType);
285 const ext_size = all_extd.decode(u16);
286 var extd = try all_extd.sub(ext_size);
287 switch (et) {
288 .supported_versions => {
289 if (supported_version != 0) return error.TlsIllegalParameter;
290 try extd.ensure(2);
291 supported_version = extd.decode(u16);
292 },
293 .key_share => {
294 if (have_shared_key) return error.TlsIllegalParameter;
295 have_shared_key = true;
296 try extd.ensure(4);
297 const named_group = extd.decode(tls.NamedGroup);
298 const key_size = extd.decode(u16);
299 try extd.ensure(key_size);
300 switch (named_group) {
301 .x25519_ml_kem768 => {
302 const xksl = crypto.dh.X25519.public_length;
303 const hksl = xksl + crypto.kem.ml_kem.MLKem768.ciphertext_length;
304 if (key_size != hksl)
305 return error.TlsIllegalParameter;
306 const server_ks = extd.array(hksl);
307
308 shared_key = &((crypto.dh.X25519.scalarmult(
309 x25519_kp.secret_key,
310 server_ks[0..xksl].*,
311 ) catch return error.TlsDecryptFailure) ++ (ml_kem768_kp.secret_key.decaps(
312 server_ks[xksl..hksl],
313 ) catch return error.TlsDecryptFailure));
314 },
315 .x25519 => {
316 const ksl = crypto.dh.X25519.public_length;
317 if (key_size != ksl) return error.TlsIllegalParameter;
318 const server_pub_key = extd.array(ksl);
319
320 shared_key = &(crypto.dh.X25519.scalarmult(
321 x25519_kp.secret_key,
322 server_pub_key.*,
323 ) catch return error.TlsDecryptFailure);
324 },
325 .secp256r1 => {
326 const server_pub_key = extd.slice(key_size);
327
328 const PublicKey = crypto.sign.ecdsa.EcdsaP256Sha256.PublicKey;
329 const pk = PublicKey.fromSec1(server_pub_key) catch {
330 return error.TlsDecryptFailure;
331 };
332 const mul = pk.p.mulPublic(secp256r1_kp.secret_key.bytes, .big) catch {
333 return error.TlsDecryptFailure;
334 };
335 shared_key = &mul.affineCoordinates().x.toBytes(.big);
336 },
337 else => {
338 return error.TlsIllegalParameter;
339 },
340 }
341 },
342 else => {},
273 var supported_version: ?u16 = null;
274 if (!hsd.eof()) {
275 try hsd.ensure(2);
276 const extensions_size = hsd.decode(u16);
277 var all_extd = try hsd.sub(extensions_size);
278 while (!all_extd.eof()) {
279 try all_extd.ensure(2 + 2);
280 const et = all_extd.decode(tls.ExtensionType);
281 const ext_size = all_extd.decode(u16);
282 var extd = try all_extd.sub(ext_size);
283 switch (et) {
284 .supported_versions => {
285 if (supported_version) |_| return error.TlsIllegalParameter;
286 try extd.ensure(2);
287 supported_version = extd.decode(u16);
288 },
289 .key_share => {
290 if (key_share.getSharedSecret()) |_| return error.TlsIllegalParameter;
291 try extd.ensure(4);
292 const named_group = extd.decode(tls.NamedGroup);
293 const key_size = extd.decode(u16);
294 try extd.ensure(key_size);
295 try key_share.exchange(named_group, extd.slice(key_size));
296 },
297 else => {},
298 }
343299 }
344300 }
345 if (!have_shared_key) return error.TlsIllegalParameter;
346301
347 const tls_version = if (supported_version == 0) legacy_version else supported_version;
348 if (tls_version != @intFromEnum(tls.ProtocolVersion.tls_1_3))
349 return error.TlsIllegalParameter;
302 tls_version = @enumFromInt(supported_version orelse legacy_version);
303 switch (tls_version) {
304 .tls_1_3 => if (!mem.eql(u8, legacy_session_id_echo, &legacy_session_id)) return error.TlsIllegalParameter,
305 .tls_1_2 => if (mem.eql(u8, server_hello_rand[24..31], "DOWNGRD") and
306 server_hello_rand[31] >> 1 == 0x00) return error.TlsIllegalParameter,
307 else => return error.TlsIllegalParameter,
308 }
350309
351310 switch (cipher_suite_tag) {
352311 inline .AES_128_GCM_SHA256,
......@@ -354,43 +313,63 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
354313 .CHACHA20_POLY1305_SHA256,
355314 .AEGIS_256_SHA512,
356315 .AEGIS_128L_SHA256,
316
317 .ECDHE_RSA_WITH_AES_128_GCM_SHA256,
318 .ECDHE_RSA_WITH_AES_256_GCM_SHA384,
319 .ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
357320 => |tag| {
358 const P = std.meta.TagPayloadByName(tls.HandshakeCipher, @tagName(tag));
359 handshake_cipher = @unionInit(tls.HandshakeCipher, @tagName(tag), .{
360 .handshake_secret = undefined,
361 .master_secret = undefined,
362 .client_handshake_key = undefined,
363 .server_handshake_key = undefined,
364 .client_finished_key = undefined,
365 .server_finished_key = undefined,
366 .client_handshake_iv = undefined,
367 .server_handshake_iv = undefined,
368 .transcript_hash = P.Hash.init(.{}),
321 handshake_cipher = @unionInit(tls.HandshakeCipher, @tagName(tag.with()), .{
322 .transcript_hash = .init(.{}),
323 .version = undefined,
369324 });
370 const p = &@field(handshake_cipher, @tagName(tag));
325 const p = &@field(handshake_cipher, @tagName(tag.with()));
371326 p.transcript_hash.update(client_hello_bytes1); // Client Hello part 1
372327 p.transcript_hash.update(host); // Client Hello part 2
373328 p.transcript_hash.update(server_hello_fragment);
374 const hello_hash = p.transcript_hash.peek();
375 const zeroes = [1]u8{0} ** P.Hash.digest_length;
376 const early_secret = P.Hkdf.extract(&[1]u8{0}, &zeroes);
377 const empty_hash = tls.emptyHash(P.Hash);
378 const hs_derived_secret = hkdfExpandLabel(P.Hkdf, early_secret, "derived", &empty_hash, P.Hash.digest_length);
379 p.handshake_secret = P.Hkdf.extract(&hs_derived_secret, shared_key);
380 const ap_derived_secret = hkdfExpandLabel(P.Hkdf, p.handshake_secret, "derived", &empty_hash, P.Hash.digest_length);
381 p.master_secret = P.Hkdf.extract(&ap_derived_secret, &zeroes);
382 const client_secret = hkdfExpandLabel(P.Hkdf, p.handshake_secret, "c hs traffic", &hello_hash, P.Hash.digest_length);
383 const server_secret = hkdfExpandLabel(P.Hkdf, p.handshake_secret, "s hs traffic", &hello_hash, P.Hash.digest_length);
384 p.client_finished_key = hkdfExpandLabel(P.Hkdf, client_secret, "finished", "", P.Hmac.key_length);
385 p.server_finished_key = hkdfExpandLabel(P.Hkdf, server_secret, "finished", "", P.Hmac.key_length);
386 p.client_handshake_key = hkdfExpandLabel(P.Hkdf, client_secret, "key", "", P.AEAD.key_length);
387 p.server_handshake_key = hkdfExpandLabel(P.Hkdf, server_secret, "key", "", P.AEAD.key_length);
388 p.client_handshake_iv = hkdfExpandLabel(P.Hkdf, client_secret, "iv", "", P.AEAD.nonce_length);
389 p.server_handshake_iv = hkdfExpandLabel(P.Hkdf, server_secret, "iv", "", P.AEAD.nonce_length);
390329 },
391 else => {
392 return error.TlsIllegalParameter;
330
331 else => return error.TlsIllegalParameter,
332 }
333 switch (tls_version) {
334 .tls_1_3 => switch (cipher_suite_tag) {
335 inline .AES_128_GCM_SHA256,
336 .AES_256_GCM_SHA384,
337 .CHACHA20_POLY1305_SHA256,
338 .AEGIS_256_SHA512,
339 .AEGIS_128L_SHA256,
340 => |tag| {
341 const sk = key_share.getSharedSecret() orelse return error.TlsIllegalParameter;
342 const p = &@field(handshake_cipher, @tagName(tag.with()));
343 const P = @TypeOf(p.*).A;
344 const hello_hash = p.transcript_hash.peek();
345 const zeroes = [1]u8{0} ** P.Hash.digest_length;
346 const early_secret = P.Hkdf.extract(&[1]u8{0}, &zeroes);
347 const empty_hash = tls.emptyHash(P.Hash);
348 p.version = .{ .tls_1_3 = undefined };
349 const pv = &p.version.tls_1_3;
350 const hs_derived_secret = hkdfExpandLabel(P.Hkdf, early_secret, "derived", &empty_hash, P.Hash.digest_length);
351 pv.handshake_secret = P.Hkdf.extract(&hs_derived_secret, sk);
352 const ap_derived_secret = hkdfExpandLabel(P.Hkdf, pv.handshake_secret, "derived", &empty_hash, P.Hash.digest_length);
353 pv.master_secret = P.Hkdf.extract(&ap_derived_secret, &zeroes);
354 const client_secret = hkdfExpandLabel(P.Hkdf, pv.handshake_secret, "c hs traffic", &hello_hash, P.Hash.digest_length);
355 const server_secret = hkdfExpandLabel(P.Hkdf, pv.handshake_secret, "s hs traffic", &hello_hash, P.Hash.digest_length);
356 pv.client_finished_key = hkdfExpandLabel(P.Hkdf, client_secret, "finished", "", P.Hmac.key_length);
357 pv.server_finished_key = hkdfExpandLabel(P.Hkdf, server_secret, "finished", "", P.Hmac.key_length);
358 pv.client_handshake_key = hkdfExpandLabel(P.Hkdf, client_secret, "key", "", P.AEAD.key_length);
359 pv.server_handshake_key = hkdfExpandLabel(P.Hkdf, server_secret, "key", "", P.AEAD.key_length);
360 pv.client_handshake_iv = hkdfExpandLabel(P.Hkdf, client_secret, "iv", "", P.AEAD.nonce_length);
361 pv.server_handshake_iv = hkdfExpandLabel(P.Hkdf, server_secret, "iv", "", P.AEAD.nonce_length);
362 },
363 else => return error.TlsIllegalParameter,
364 },
365 .tls_1_2 => switch (cipher_suite_tag) {
366 .ECDHE_RSA_WITH_AES_128_GCM_SHA256,
367 .ECDHE_RSA_WITH_AES_256_GCM_SHA384,
368 .ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
369 => {},
370 else => return error.TlsIllegalParameter,
393371 },
372 else => return error.TlsIllegalParameter,
394373 }
395374 },
396375 else => return error.TlsUnexpectedMessage,
......@@ -404,58 +383,74 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
404383 // the previous certificate in memory so that it can be verified by the
405384 // next one.
406385 var cert_index: usize = 0;
386 var write_seq: u64 = 0;
407387 var read_seq: u64 = 0;
408388 var prev_cert: Certificate.Parsed = undefined;
409 // Set to true once a trust chain has been established from the first
410 // certificate to a root CA.
389 const CipherState = enum {
390 /// No cipher is in use
391 cleartext,
392 /// Handshake cipher is in use
393 handshake,
394 /// Application cipher is in use
395 application,
396 };
397 var pending_cipher_state: CipherState = switch (tls_version) {
398 .tls_1_3 => .handshake,
399 .tls_1_2 => .cleartext,
400 else => unreachable,
401 };
402 var cipher_state: CipherState = .cleartext;
411403 const HandshakeState = enum {
412404 /// In this state we expect only an encrypted_extensions message.
413405 encrypted_extensions,
414 /// In this state we expect certificate messages.
406 /// In this state we expect certificate handshake messages.
415407 certificate,
416408 /// In this state we expect certificate or certificate_verify messages.
417409 /// certificate messages are ignored since the trust chain is already
418410 /// established.
419411 trust_chain_established,
420 /// In this state, we expect only the finished message.
412 /// In this state, we expect only the server_hello_done handshake message.
413 server_hello_done,
414 /// In this state, we expect only the finished handshake message.
421415 finished,
422416 };
423 var handshake_state: HandshakeState = .encrypted_extensions;
417 var handshake_state: HandshakeState = switch (tls_version) {
418 .tls_1_3 => .encrypted_extensions,
419 .tls_1_2 => .certificate,
420 else => unreachable,
421 };
424422 var cleartext_bufs: [2][8000]u8 = undefined;
425 var main_cert_pub_key_algo: Certificate.AlgorithmCategory = undefined;
426 var main_cert_pub_key_buf: [600]u8 = undefined;
427 var main_cert_pub_key_len: u16 = undefined;
423 var main_cert_pub_key: CertificatePublicKey = undefined;
428424 const now_sec = std.time.timestamp();
429425
430426 while (true) {
431427 try d.readAtLeastOurAmt(stream, tls.record_header_len);
432 const record_header = d.buf[d.idx..][0..5];
433 const ct = d.decode(tls.ContentType);
428 const record_header = d.buf[d.idx..][0..tls.record_header_len];
429 const record_ct = d.decode(tls.ContentType);
434430 d.skip(2); // legacy_version
435431 const record_len = d.decode(u16);
436432 try d.readAtLeast(stream, record_len);
437433 var record_decoder = try d.sub(record_len);
438 switch (ct) {
439 .change_cipher_spec => {
440 try record_decoder.ensure(1);
441 if (record_decoder.decode(u8) != 0x01) return error.TlsIllegalParameter;
442 },
443 .application_data => {
434 var ctd, const ct = content: switch (cipher_state) {
435 .cleartext => .{ record_decoder, record_ct },
436 .handshake => {
437 std.debug.assert(tls_version == .tls_1_3);
438 if (record_ct != .application_data) return error.TlsUnexpectedMessage;
439 try record_decoder.ensure(record_len);
444440 const cleartext_buf = &cleartext_bufs[cert_index % 2];
445
446 const cleartext = switch (handshake_cipher) {
447 inline else => |*p| c: {
448 const P = @TypeOf(p.*);
449 const ciphertext_len = record_len - P.AEAD.tag_length;
450 try record_decoder.ensure(ciphertext_len + P.AEAD.tag_length);
451 const ciphertext = record_decoder.slice(ciphertext_len);
441 const cleartext = cleartext: switch (handshake_cipher) {
442 inline else => |*p| {
443 const pv = &p.version.tls_1_3;
444 const P = @TypeOf(p.*).A;
445 if (record_len < P.AEAD.tag_length) return error.TlsRecordOverflow;
446 const ciphertext = record_decoder.slice(record_len - P.AEAD.tag_length);
452447 if (ciphertext.len > cleartext_buf.len) return error.TlsRecordOverflow;
453448 const cleartext = cleartext_buf[0..ciphertext.len];
454449 const auth_tag = record_decoder.array(P.AEAD.tag_length).*;
455450 const nonce = if (builtin.zig_backend == .stage2_x86_64 and
456451 P.AEAD.nonce_length > comptime std.simd.suggestVectorLength(u8) orelse 1)
457452 nonce: {
458 var nonce = p.server_handshake_iv;
453 var nonce = pv.server_handshake_iv;
459454 const operand = std.mem.readInt(u64, nonce[nonce.len - 8 ..], .big);
460455 std.mem.writeInt(u64, nonce[nonce.len - 8 ..], operand ^ read_seq, .big);
461456 break :nonce nonce;
......@@ -463,200 +458,320 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
463458 const V = @Vector(P.AEAD.nonce_length, u8);
464459 const pad = [1]u8{0} ** (P.AEAD.nonce_length - 8);
465460 const operand: V = pad ++ @as([8]u8, @bitCast(big(read_seq)));
466 break :nonce @as(V, p.server_handshake_iv) ^ operand;
461 break :nonce @as(V, pv.server_handshake_iv) ^ operand;
467462 };
468 read_seq += 1;
469 P.AEAD.decrypt(cleartext, ciphertext, auth_tag, record_header, nonce, p.server_handshake_key) catch
463 P.AEAD.decrypt(cleartext, ciphertext, auth_tag, record_header, nonce, pv.server_handshake_key) catch
470464 return error.TlsBadRecordMac;
471 break :c @constCast(mem.trimRight(u8, cleartext, "\x00"));
465 break :cleartext mem.trimRight(u8, cleartext, "\x00");
472466 },
473467 };
468 read_seq += 1;
469 const ct: tls.ContentType = @enumFromInt(cleartext[cleartext.len - 1]);
470 if (ct != .handshake) return error.TlsUnexpectedMessage;
471 break :content .{ tls.Decoder.fromTheirSlice(@constCast(cleartext[0 .. cleartext.len - 1])), ct };
472 },
473 .application => {
474 std.debug.assert(tls_version == .tls_1_2);
475 if (record_ct != .handshake) return error.TlsUnexpectedMessage;
476 try record_decoder.ensure(record_len);
477 const cleartext_buf = &cleartext_bufs[cert_index % 2];
478 const cleartext = cleartext: switch (handshake_cipher) {
479 inline else => |*p| {
480 const pv = &p.version.tls_1_2;
481 const P = @TypeOf(p.*).A;
482 if (record_len < P.record_iv_length + P.mac_length) return error.TlsRecordOverflow;
483 const message_len: u16 = record_len - P.record_iv_length - P.mac_length;
484 if (message_len > cleartext_buf.len) return error.TlsRecordOverflow;
485 const cleartext = cleartext_buf[0..message_len];
486 const ad = std.mem.toBytes(big(read_seq)) ++
487 record_header[0 .. 1 + 2] ++
488 std.mem.toBytes(big(message_len));
489 const record_iv = record_decoder.array(P.record_iv_length).*;
490 const masked_read_seq = read_seq &
491 comptime std.math.shl(u64, std.math.maxInt(u64), 8 * P.record_iv_length);
492 const nonce: [P.AEAD.nonce_length]u8 = if (builtin.zig_backend == .stage2_x86_64 and
493 P.AEAD.nonce_length > comptime std.simd.suggestVectorLength(u8) orelse 1)
494 nonce: {
495 var nonce = pv.app_cipher.server_write_IV ++ record_iv;
496 const operand = std.mem.readInt(u64, nonce[nonce.len - 8 ..], .big);
497 std.mem.writeInt(u64, nonce[nonce.len - 8 ..], operand ^ masked_read_seq, .big);
498 break :nonce nonce;
499 } else nonce: {
500 const V = @Vector(P.AEAD.nonce_length, u8);
501 const pad = [1]u8{0} ** (P.AEAD.nonce_length - 8);
502 const operand: V = pad ++ @as([8]u8, @bitCast(big(masked_read_seq)));
503 break :nonce @as(V, pv.app_cipher.server_write_IV ++ record_iv) ^ operand;
504 };
505 const ciphertext = record_decoder.slice(message_len);
506 const auth_tag = record_decoder.array(P.mac_length);
507 P.AEAD.decrypt(cleartext, ciphertext, auth_tag.*, ad, nonce, pv.app_cipher.server_write_key) catch return error.TlsBadRecordMac;
508 break :cleartext cleartext;
509 },
510 };
511 read_seq += 1;
512 break :content .{ tls.Decoder.fromTheirSlice(cleartext), record_ct };
513 },
514 };
515 switch (ct) {
516 .alert => {
517 try ctd.ensure(2);
518 const level = ctd.decode(tls.AlertLevel);
519 const desc = ctd.decode(tls.AlertDescription);
520 _ = level;
474521
475 const inner_ct: tls.ContentType = @enumFromInt(cleartext[cleartext.len - 1]);
476 if (inner_ct != .handshake) return error.TlsUnexpectedMessage;
477
478 var ctd = tls.Decoder.fromTheirSlice(cleartext[0 .. cleartext.len - 1]);
479 while (true) {
480 try ctd.ensure(4);
481 const handshake_type = ctd.decode(tls.HandshakeType);
482 const handshake_len = ctd.decode(u24);
483 var hsd = try ctd.sub(handshake_len);
484 const wrapped_handshake = ctd.buf[ctd.idx - handshake_len - 4 .. ctd.idx];
485 const handshake = ctd.buf[ctd.idx - handshake_len .. ctd.idx];
486 switch (handshake_type) {
487 .encrypted_extensions => {
488 if (handshake_state != .encrypted_extensions) return error.TlsUnexpectedMessage;
489 handshake_state = .certificate;
490 switch (handshake_cipher) {
491 inline else => |*p| p.transcript_hash.update(wrapped_handshake),
492 }
493 try hsd.ensure(2);
494 const total_ext_size = hsd.decode(u16);
495 var all_extd = try hsd.sub(total_ext_size);
496 while (!all_extd.eof()) {
497 try all_extd.ensure(4);
498 const et = all_extd.decode(tls.ExtensionType);
499 const ext_size = all_extd.decode(u16);
500 const extd = try all_extd.sub(ext_size);
501 _ = extd;
502 switch (et) {
503 .server_name => {},
504 else => {},
505 }
522 // if this isn't a error alert, then it's a closure alert, which makes no sense in a handshake
523 try desc.toError();
524 // TODO: handle server-side closures
525 return error.TlsUnexpectedMessage;
526 },
527 .change_cipher_spec => {
528 try ctd.ensure(1);
529 if (ctd.decode(u8) != 0x01) return error.TlsIllegalParameter;
530 cipher_state = pending_cipher_state;
531 },
532 .handshake => while (true) {
533 try ctd.ensure(4);
534 const handshake_type = ctd.decode(tls.HandshakeType);
535 const handshake_len = ctd.decode(u24);
536 var hsd = try ctd.sub(handshake_len);
537 const wrapped_handshake = ctd.buf[ctd.idx - handshake_len - 4 .. ctd.idx];
538 switch (handshake_type) {
539 .encrypted_extensions => {
540 if (tls_version != .tls_1_3) return error.TlsUnexpectedMessage;
541 if (cipher_state != .handshake) return error.TlsUnexpectedMessage;
542 if (handshake_state != .encrypted_extensions) return error.TlsUnexpectedMessage;
543 handshake_state = .certificate;
544 switch (handshake_cipher) {
545 inline else => |*p| p.transcript_hash.update(wrapped_handshake),
546 }
547 try hsd.ensure(2);
548 const total_ext_size = hsd.decode(u16);
549 var all_extd = try hsd.sub(total_ext_size);
550 while (!all_extd.eof()) {
551 try all_extd.ensure(4);
552 const et = all_extd.decode(tls.ExtensionType);
553 const ext_size = all_extd.decode(u16);
554 const extd = try all_extd.sub(ext_size);
555 _ = extd;
556 switch (et) {
557 .server_name => {},
558 else => {},
506559 }
507 },
508 .certificate => cert: {
509 switch (handshake_cipher) {
510 inline else => |*p| p.transcript_hash.update(wrapped_handshake),
560 }
561 },
562 .certificate => cert: {
563 switch (handshake_cipher) {
564 inline else => |*p| p.transcript_hash.update(wrapped_handshake),
565 }
566 switch (handshake_state) {
567 .certificate => {},
568 .trust_chain_established => break :cert,
569 else => return error.TlsUnexpectedMessage,
570 }
571
572 switch (tls_version) {
573 .tls_1_3 => {
574 try hsd.ensure(1 + 3);
575 const cert_req_ctx_len = hsd.decode(u8);
576 if (cert_req_ctx_len != 0) return error.TlsIllegalParameter;
577 },
578 .tls_1_2 => try hsd.ensure(3),
579 else => unreachable,
580 }
581 const certs_size = hsd.decode(u24);
582 var certs_decoder = try hsd.sub(certs_size);
583 while (!certs_decoder.eof()) {
584 try certs_decoder.ensure(3);
585 const cert_size = certs_decoder.decode(u24);
586 const certd = try certs_decoder.sub(cert_size);
587
588 const subject_cert: Certificate = .{
589 .buffer = certd.buf,
590 .index = @intCast(certd.idx),
591 };
592 const subject = try subject_cert.parse();
593 if (cert_index == 0) {
594 // Verify the host on the first certificate.
595 try subject.verifyHostName(host);
596
597 // Keep track of the public key for the
598 // certificate_verify message later.
599 try main_cert_pub_key.init(subject.pub_key_algo, subject.pubKey());
600 } else {
601 try prev_cert.verify(subject, now_sec);
511602 }
512 switch (handshake_state) {
513 .certificate => {},
514 .trust_chain_established => break :cert,
515 else => return error.TlsUnexpectedMessage,
603
604 if (ca_bundle.verify(subject, now_sec)) |_| {
605 handshake_state = .trust_chain_established;
606 break :cert;
607 } else |err| switch (err) {
608 error.CertificateIssuerNotFound => {},
609 else => |e| return e,
516610 }
517 try hsd.ensure(1 + 4);
518 const cert_req_ctx_len = hsd.decode(u8);
519 if (cert_req_ctx_len != 0) return error.TlsIllegalParameter;
520 const certs_size = hsd.decode(u24);
521 var certs_decoder = try hsd.sub(certs_size);
522 while (!certs_decoder.eof()) {
523 try certs_decoder.ensure(3);
524 const cert_size = certs_decoder.decode(u24);
525 const certd = try certs_decoder.sub(cert_size);
526
527 const subject_cert: Certificate = .{
528 .buffer = certd.buf,
529 .index = @intCast(certd.idx),
530 };
531 const subject = try subject_cert.parse();
532 if (cert_index == 0) {
533 // Verify the host on the first certificate.
534 try subject.verifyHostName(host);
535
536 // Keep track of the public key for the
537 // certificate_verify message later.
538 main_cert_pub_key_algo = subject.pub_key_algo;
539 const pub_key = subject.pubKey();
540 if (pub_key.len > main_cert_pub_key_buf.len)
541 return error.CertificatePublicKeyInvalid;
542 @memcpy(main_cert_pub_key_buf[0..pub_key.len], pub_key);
543 main_cert_pub_key_len = @intCast(pub_key.len);
544 } else {
545 try prev_cert.verify(subject, now_sec);
546 }
547
548 if (ca_bundle.verify(subject, now_sec)) |_| {
549 handshake_state = .trust_chain_established;
550 break :cert;
551 } else |err| switch (err) {
552 error.CertificateIssuerNotFound => {},
553 else => |e| return e,
554 }
555
556 prev_cert = subject;
557 cert_index += 1;
558611
612 prev_cert = subject;
613 cert_index += 1;
614
615 if (tls_version == .tls_1_3) {
559616 try certs_decoder.ensure(2);
560617 const total_ext_size = certs_decoder.decode(u16);
561618 const all_extd = try certs_decoder.sub(total_ext_size);
562619 _ = all_extd;
563620 }
564 },
565 .certificate_verify => {
566 switch (handshake_state) {
567 .trust_chain_established => handshake_state = .finished,
568 .certificate => return error.TlsCertificateNotVerified,
569 else => return error.TlsUnexpectedMessage,
570 }
621 }
622 },
623 .server_key_exchange => {
624 if (tls_version != .tls_1_2) return error.TlsUnexpectedMessage;
625 if (cipher_state != .cleartext) return error.TlsUnexpectedMessage;
626 switch (handshake_state) {
627 .trust_chain_established => handshake_state = .server_hello_done,
628 .certificate => return error.TlsCertificateNotVerified,
629 else => return error.TlsUnexpectedMessage,
630 }
571631
572 try hsd.ensure(4);
573 const scheme = hsd.decode(tls.SignatureScheme);
574 const sig_len = hsd.decode(u16);
575 try hsd.ensure(sig_len);
576 const encoded_sig = hsd.slice(sig_len);
577 const max_digest_len = 64;
578 var verify_buffer: [64 + 34 + max_digest_len]u8 =
579 ([1]u8{0x20} ** 64) ++
580 "TLS 1.3, server CertificateVerify\x00".* ++
581 @as([max_digest_len]u8, undefined);
582
583 const verify_bytes = switch (handshake_cipher) {
584 inline else => |*p| v: {
585 const transcript_digest = p.transcript_hash.peek();
586 verify_buffer[verify_buffer.len - max_digest_len ..][0..transcript_digest.len].* = transcript_digest;
587 p.transcript_hash.update(wrapped_handshake);
588 break :v verify_buffer[0 .. verify_buffer.len - max_digest_len + transcript_digest.len];
589 },
590 };
591 const main_cert_pub_key = main_cert_pub_key_buf[0..main_cert_pub_key_len];
592
593 switch (scheme) {
594 inline .ecdsa_secp256r1_sha256,
595 .ecdsa_secp384r1_sha384,
596 => |comptime_scheme| {
597 if (main_cert_pub_key_algo != .X9_62_id_ecPublicKey)
598 return error.TlsBadSignatureScheme;
599 const Ecdsa = SchemeEcdsa(comptime_scheme);
600 const sig = try Ecdsa.Signature.fromDer(encoded_sig);
601 const key = try Ecdsa.PublicKey.fromSec1(main_cert_pub_key);
602 try sig.verify(verify_bytes, key);
603 },
604 inline .rsa_pss_rsae_sha256,
605 .rsa_pss_rsae_sha384,
606 .rsa_pss_rsae_sha512,
607 => |comptime_scheme| {
608 if (main_cert_pub_key_algo != .rsaEncryption)
609 return error.TlsBadSignatureScheme;
610
611 const Hash = SchemeHash(comptime_scheme);
612 const rsa = Certificate.rsa;
613 const components = try rsa.PublicKey.parseDer(main_cert_pub_key);
614 const exponent = components.exponent;
615 const modulus = components.modulus;
616 switch (modulus.len) {
617 inline 128, 256, 512 => |modulus_len| {
618 const key = try rsa.PublicKey.fromBytes(exponent, modulus);
619 const sig = rsa.PSSSignature.fromBytes(modulus_len, encoded_sig);
620 try rsa.PSSSignature.verify(modulus_len, sig, verify_bytes, key, Hash);
621 },
622 else => {
623 return error.TlsBadRsaSignatureBitCount;
624 },
625 }
626 },
627 inline .ed25519 => |comptime_scheme| {
628 if (main_cert_pub_key_algo != .curveEd25519) return error.TlsBadSignatureScheme;
629 const Eddsa = SchemeEddsa(comptime_scheme);
630 if (encoded_sig.len != Eddsa.Signature.encoded_length) return error.InvalidEncoding;
631 const sig = Eddsa.Signature.fromBytes(encoded_sig[0..Eddsa.Signature.encoded_length].*);
632 if (main_cert_pub_key.len != Eddsa.PublicKey.encoded_length) return error.InvalidEncoding;
633 const key = try Eddsa.PublicKey.fromBytes(main_cert_pub_key[0..Eddsa.PublicKey.encoded_length].*);
634 try sig.verify(verify_bytes, key);
635 },
636 else => {
637 return error.TlsBadSignatureScheme;
638 },
639 }
640 },
641 .finished => {
642 if (handshake_state != .finished) return error.TlsUnexpectedMessage;
643 // This message is to trick buggy proxies into behaving correctly.
644 const client_change_cipher_spec_msg = [_]u8{
645 @intFromEnum(tls.ContentType.change_cipher_spec),
646 0x03, 0x03, // legacy protocol version
647 0x00, 0x01, // length
648 0x01,
649 };
650 const app_cipher = switch (handshake_cipher) {
651 inline else => |*p, tag| c: {
652 const P = @TypeOf(p.*);
632 switch (handshake_cipher) {
633 inline else => |*p| p.transcript_hash.update(wrapped_handshake),
634 }
635 try hsd.ensure(1 + 2 + 1);
636 const curve_type = hsd.decode(u8);
637 if (curve_type != 0x03) return error.TlsIllegalParameter; // named_curve
638 const named_group = hsd.decode(tls.NamedGroup);
639 if (named_group != .secp256r1) return error.TlsIllegalParameter;
640 const key_size = hsd.decode(u8);
641 try hsd.ensure(key_size);
642 const server_pub_key = hsd.slice(key_size);
643 try main_cert_pub_key.verifySignature(&hsd, &.{ &client_hello_rand, &server_hello_rand, hsd.buf[0..hsd.idx] });
644 try key_share.exchange(named_group, server_pub_key);
645 },
646 .server_hello_done => {
647 if (tls_version != .tls_1_2) return error.TlsUnexpectedMessage;
648 if (cipher_state != .cleartext) return error.TlsUnexpectedMessage;
649 if (handshake_state != .server_hello_done) return error.TlsUnexpectedMessage;
650 handshake_state = .finished;
651
652 const client_key_exchange_msg =
653 [_]u8{@intFromEnum(tls.ContentType.handshake)} ++ // record content type
654 int2(@intFromEnum(tls.ProtocolVersion.tls_1_2)) ++ // legacy protocol version
655 int2(0x46) ++ // record length
656 .{@intFromEnum(tls.HandshakeType.client_key_exchange)} ++ // handshake type
657 int3(0x42) ++ // params length
658 .{0x41} ++ // pubkey length
659 key_share.secp256r1_kp.public_key.toUncompressedSec1();
660 // This message is to trick buggy proxies into behaving correctly.
661 const client_change_cipher_spec_msg =
662 [_]u8{@intFromEnum(tls.ContentType.change_cipher_spec)} ++ // record content type
663 int2(@intFromEnum(tls.ProtocolVersion.tls_1_2)) ++ // legacy protocol version
664 int2(1) ++ // record length
665 .{0x01};
666 const pre_master_secret = key_share.getSharedSecret().?;
667 switch (handshake_cipher) {
668 inline else => |*p| {
669 const P = @TypeOf(p.*).A;
670 p.transcript_hash.update(wrapped_handshake);
671 p.transcript_hash.update(client_key_exchange_msg[tls.record_header_len..]);
672 const master_secret = hmacExpandLabel(P.Hmac, pre_master_secret, &.{
673 "master secret",
674 &client_hello_rand,
675 &server_hello_rand,
676 }, 48);
677 const key_block = hmacExpandLabel(
678 P.Hmac,
679 &master_secret,
680 &.{ "key expansion", &server_hello_rand, &client_hello_rand },
681 @sizeOf(P.Tls_1_2),
682 );
683 const verify_data_len = 12;
684 const client_verify_cleartext =
685 [_]u8{@intFromEnum(tls.HandshakeType.finished)} ++ // handshake type
686 int3(verify_data_len) ++ // verify data length
687 hmacExpandLabel(P.Hmac, &master_secret, &.{ "client finished", &p.transcript_hash.peek() }, verify_data_len);
688 p.transcript_hash.update(&client_verify_cleartext);
689 p.version = .{ .tls_1_2 = .{
690 .server_verify_data = hmacExpandLabel(
691 P.Hmac,
692 &master_secret,
693 &.{ "server finished", &p.transcript_hash.finalResult() },
694 verify_data_len,
695 ),
696 .app_cipher = std.mem.bytesToValue(P.Tls_1_2, &key_block),
697 } };
698 const pv = &p.version.tls_1_2;
699 pending_cipher_state = .application;
700 const nonce: [P.AEAD.nonce_length]u8 = if (builtin.zig_backend == .stage2_x86_64 and
701 P.AEAD.nonce_length > comptime std.simd.suggestVectorLength(u8) orelse 1)
702 nonce: {
703 var nonce = pv.app_cipher.client_write_IV ++ pv.app_cipher.client_salt;
704 const operand = std.mem.readInt(u64, nonce[nonce.len - 8 ..], .big);
705 std.mem.writeInt(u64, nonce[nonce.len - 8 ..], operand ^ write_seq, .big);
706 break :nonce nonce;
707 } else nonce: {
708 const V = @Vector(P.AEAD.nonce_length, u8);
709 const pad = [1]u8{0} ** (P.AEAD.nonce_length - 8);
710 const operand: V = pad ++ @as([8]u8, @bitCast(big(write_seq)));
711 break :nonce @as(V, pv.app_cipher.client_write_IV ++ pv.app_cipher.client_salt) ^ operand;
712 };
713 var client_verify_msg = [_]u8{@intFromEnum(tls.ContentType.handshake)} ++ // record content type
714 int2(@intFromEnum(tls.ProtocolVersion.tls_1_2)) ++ // legacy protocol version
715 int2(P.record_iv_length + client_verify_cleartext.len + P.mac_length) ++ // record length
716 nonce[P.fixed_iv_length..].* ++
717 @as([client_verify_cleartext.len + P.mac_length]u8, undefined);
718 P.AEAD.encrypt(
719 client_verify_msg[client_verify_msg.len - P.mac_length -
720 client_verify_cleartext.len ..][0..client_verify_cleartext.len],
721 client_verify_msg[client_verify_msg.len - P.mac_length ..][0..P.mac_length],
722 &client_verify_cleartext,
723 std.mem.toBytes(big(write_seq)) ++ client_verify_msg[0 .. 1 + 2] ++ int2(client_verify_cleartext.len),
724 nonce,
725 pv.app_cipher.client_write_key,
726 );
727 const all_msgs = client_key_exchange_msg ++ client_change_cipher_spec_msg ++ client_verify_msg;
728 var all_msgs_vec = [_]std.posix.iovec_const{.{
729 .base = &all_msgs,
730 .len = all_msgs.len,
731 }};
732 try stream.writevAll(&all_msgs_vec);
733 },
734 }
735 write_seq += 1;
736 },
737 .certificate_verify => {
738 if (tls_version != .tls_1_3) return error.TlsUnexpectedMessage;
739 if (cipher_state != .handshake) return error.TlsUnexpectedMessage;
740 switch (handshake_state) {
741 .trust_chain_established => handshake_state = .finished,
742 .certificate => return error.TlsCertificateNotVerified,
743 else => return error.TlsUnexpectedMessage,
744 }
745 switch (handshake_cipher) {
746 inline else => |*p| {
747 try main_cert_pub_key.verifySignature(&hsd, &.{
748 " " ** 64 ++ "TLS 1.3, server CertificateVerify\x00",
749 &p.transcript_hash.peek(),
750 });
751 p.transcript_hash.update(wrapped_handshake);
752 },
753 }
754 },
755 .finished => {
756 if (cipher_state == .cleartext) return error.TlsUnexpectedMessage;
757 if (handshake_state != .finished) return error.TlsUnexpectedMessage;
758 // This message is to trick buggy proxies into behaving correctly.
759 const client_change_cipher_spec_msg =
760 [_]u8{@intFromEnum(tls.ContentType.change_cipher_spec)} ++
761 int2(@intFromEnum(tls.ProtocolVersion.tls_1_2)) ++ // legacy protocol version
762 int2(1) ++ // length
763 .{0x01};
764 const app_cipher = app_cipher: switch (handshake_cipher) {
765 inline else => |*p, tag| switch (tls_version) {
766 .tls_1_3 => {
767 const pv = &p.version.tls_1_3;
768 const P = @TypeOf(p.*).A;
653769 const finished_digest = p.transcript_hash.peek();
654770 p.transcript_hash.update(wrapped_handshake);
655 const expected_server_verify_data = tls.hmac(P.Hmac, &finished_digest, p.server_finished_key);
656 if (!mem.eql(u8, &expected_server_verify_data, handshake))
657 return error.TlsDecryptError;
771 const expected_server_verify_data = tls.hmac(P.Hmac, &finished_digest, pv.server_finished_key);
772 if (!mem.eql(u8, &expected_server_verify_data, hsd.buf)) return error.TlsDecryptError;
658773 const handshake_hash = p.transcript_hash.finalResult();
659 const verify_data = tls.hmac(P.Hmac, &handshake_hash, p.client_finished_key);
774 const verify_data = tls.hmac(P.Hmac, &handshake_hash, pv.client_finished_key);
660775 const out_cleartext = [_]u8{
661776 @intFromEnum(tls.HandshakeType.finished),
662777 0, 0, verify_data.len, // length
......@@ -664,67 +779,78 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
664779
665780 const wrapped_len = out_cleartext.len + P.AEAD.tag_length;
666781
667 var finished_msg = [_]u8{
668 @intFromEnum(tls.ContentType.application_data),
669 0x03, 0x03, // legacy protocol version
670 0, wrapped_len, // byte length of encrypted record
671 } ++ @as([wrapped_len]u8, undefined);
782 var finished_msg = [_]u8{@intFromEnum(tls.ContentType.application_data)} ++
783 int2(@intFromEnum(tls.ProtocolVersion.tls_1_2)) ++ // legacy protocol version
784 int2(wrapped_len) ++ // byte length of encrypted record
785 @as([wrapped_len]u8, undefined);
672786
673 const ad = finished_msg[0..5];
674 const ciphertext = finished_msg[5..][0..out_cleartext.len];
787 const ad = finished_msg[0..tls.record_header_len];
788 const ciphertext = finished_msg[tls.record_header_len..][0..out_cleartext.len];
675789 const auth_tag = finished_msg[finished_msg.len - P.AEAD.tag_length ..];
676 const nonce = p.client_handshake_iv;
677 P.AEAD.encrypt(ciphertext, auth_tag, &out_cleartext, ad, nonce, p.client_handshake_key);
790 const nonce = pv.client_handshake_iv;
791 P.AEAD.encrypt(ciphertext, auth_tag, &out_cleartext, ad, nonce, pv.client_handshake_key);
678792
679 const both_msgs = client_change_cipher_spec_msg ++ finished_msg;
680 var both_msgs_vec = [_]std.posix.iovec_const{.{
681 .base = &both_msgs,
682 .len = both_msgs.len,
793 const all_msgs = client_change_cipher_spec_msg ++ finished_msg;
794 var all_msgs_vec = [_]std.posix.iovec_const{.{
795 .base = &all_msgs,
796 .len = all_msgs.len,
683797 }};
684 try stream.writevAll(&both_msgs_vec);
798 try stream.writevAll(&all_msgs_vec);
685799
686 const client_secret = hkdfExpandLabel(P.Hkdf, p.master_secret, "c ap traffic", &handshake_hash, P.Hash.digest_length);
687 const server_secret = hkdfExpandLabel(P.Hkdf, p.master_secret, "s ap traffic", &handshake_hash, P.Hash.digest_length);
688 break :c @unionInit(tls.ApplicationCipher, @tagName(tag), .{
800 const client_secret = hkdfExpandLabel(P.Hkdf, pv.master_secret, "c ap traffic", &handshake_hash, P.Hash.digest_length);
801 const server_secret = hkdfExpandLabel(P.Hkdf, pv.master_secret, "s ap traffic", &handshake_hash, P.Hash.digest_length);
802 break :app_cipher @unionInit(tls.ApplicationCipher, @tagName(tag), .{ .tls_1_3 = .{
689803 .client_secret = client_secret,
690804 .server_secret = server_secret,
691805 .client_key = hkdfExpandLabel(P.Hkdf, client_secret, "key", "", P.AEAD.key_length),
692806 .server_key = hkdfExpandLabel(P.Hkdf, server_secret, "key", "", P.AEAD.key_length),
693807 .client_iv = hkdfExpandLabel(P.Hkdf, client_secret, "iv", "", P.AEAD.nonce_length),
694808 .server_iv = hkdfExpandLabel(P.Hkdf, server_secret, "iv", "", P.AEAD.nonce_length),
695 });
809 } });
696810 },
697 };
698 const leftover = d.rest();
699 var client: Client = .{
700 .read_seq = 0,
701 .write_seq = 0,
702 .partial_cleartext_idx = 0,
703 .partial_ciphertext_idx = 0,
704 .partial_ciphertext_end = @intCast(leftover.len),
705 .received_close_notify = false,
706 .application_cipher = app_cipher,
707 .partially_read_buffer = undefined,
708 };
709 @memcpy(client.partially_read_buffer[0..leftover.len], leftover);
710 return client;
711 },
712 else => {
713 return error.TlsUnexpectedMessage;
714 },
715 }
716 if (ctd.eof()) break;
811 .tls_1_2 => {
812 const pv = &p.version.tls_1_2;
813 try hsd.ensure(12);
814 if (!std.mem.eql(u8, hsd.array(12), &pv.server_verify_data)) return error.TlsDecryptError;
815 break :app_cipher @unionInit(tls.ApplicationCipher, @tagName(tag), .{ .tls_1_2 = pv.app_cipher });
816 },
817 else => unreachable,
818 },
819 };
820 const leftover = d.rest();
821 var client: Client = .{
822 .tls_version = tls_version,
823 .read_seq = switch (tls_version) {
824 .tls_1_3 => 0,
825 .tls_1_2 => read_seq,
826 else => unreachable,
827 },
828 .write_seq = switch (tls_version) {
829 .tls_1_3 => 0,
830 .tls_1_2 => write_seq,
831 else => unreachable,
832 },
833 .partial_cleartext_idx = 0,
834 .partial_ciphertext_idx = 0,
835 .partial_ciphertext_end = @intCast(leftover.len),
836 .received_close_notify = false,
837 .application_cipher = app_cipher,
838 .partially_read_buffer = undefined,
839 };
840 @memcpy(client.partially_read_buffer[0..leftover.len], leftover);
841 return client;
842 },
843 else => return error.TlsUnexpectedMessage,
717844 }
845 if (ctd.eof()) break;
718846 },
719 else => {
720 return error.TlsUnexpectedMessage;
721 },
847 else => return error.TlsUnexpectedMessage,
722848 }
723849 }
724850}
725851
726852/// Sends TLS-encrypted data to `stream`, which must conform to `StreamInterface`.
727/// Returns the number of plaintext bytes sent, which may be fewer than `bytes.len`.
853/// Returns the number of cleartext bytes sent, which may be fewer than `bytes.len`.
728854pub fn write(c: *Client, stream: anytype, bytes: []const u8) !usize {
729855 return writeEnd(c, stream, bytes, false);
730856}
......@@ -749,7 +875,7 @@ pub fn writeAllEnd(c: *Client, stream: anytype, bytes: []const u8, end: bool) !v
749875}
750876
751877/// Sends TLS-encrypted data to `stream`, which must conform to `StreamInterface`.
752/// Returns the number of plaintext bytes sent, which may be fewer than `bytes.len`.
878/// Returns the number of cleartext bytes sent, which may be fewer than `bytes.len`.
753879/// If `end` is true, then this function additionally sends a `close_notify` alert,
754880/// which is necessary for the server to distinguish between a properly finished
755881/// TLS session, or a truncation attack.
......@@ -813,62 +939,127 @@ fn prepareCiphertextRecord(
813939 var iovec_end: usize = 0;
814940 var bytes_i: usize = 0;
815941 switch (c.application_cipher) {
816 inline else => |*p| {
817 const P = @TypeOf(p.*);
818 const overhead_len = tls.record_header_len + P.AEAD.tag_length + 1;
819 const close_notify_alert_reserved = tls.close_notify_alert.len + overhead_len;
820 while (true) {
821 const encrypted_content_len: u16 = @intCast(@min(
822 @min(bytes.len - bytes_i, tls.max_ciphertext_inner_record_len),
823 ciphertext_buf.len -|
824 (close_notify_alert_reserved + overhead_len + ciphertext_end),
825 ));
826 if (encrypted_content_len == 0) return .{
827 .iovec_end = iovec_end,
828 .ciphertext_end = ciphertext_end,
829 .overhead_len = overhead_len,
830 };
831
832 @memcpy(cleartext_buf[0..encrypted_content_len], bytes[bytes_i..][0..encrypted_content_len]);
833 cleartext_buf[encrypted_content_len] = @intFromEnum(inner_content_type);
834 bytes_i += encrypted_content_len;
835 const ciphertext_len = encrypted_content_len + 1;
836 const cleartext = cleartext_buf[0..ciphertext_len];
837
838 const record_start = ciphertext_end;
839 const ad = ciphertext_buf[ciphertext_end..][0..5];
840 ad.* =
841 [_]u8{@intFromEnum(tls.ContentType.application_data)} ++
842 int2(@intFromEnum(tls.ProtocolVersion.tls_1_2)) ++
843 int2(ciphertext_len + P.AEAD.tag_length);
844 ciphertext_end += ad.len;
845 const ciphertext = ciphertext_buf[ciphertext_end..][0..ciphertext_len];
846 ciphertext_end += ciphertext_len;
847 const auth_tag = ciphertext_buf[ciphertext_end..][0..P.AEAD.tag_length];
848 ciphertext_end += auth_tag.len;
849 const nonce = if (builtin.zig_backend == .stage2_x86_64 and
850 P.AEAD.nonce_length > comptime std.simd.suggestVectorLength(u8) orelse 1)
851 nonce: {
852 var nonce = p.client_iv;
853 const operand = std.mem.readInt(u64, nonce[nonce.len - 8 ..], .big);
854 std.mem.writeInt(u64, nonce[nonce.len - 8 ..], operand ^ c.write_seq, .big);
855 break :nonce nonce;
856 } else nonce: {
857 const V = @Vector(P.AEAD.nonce_length, u8);
858 const pad = [1]u8{0} ** (P.AEAD.nonce_length - 8);
859 const operand: V = pad ++ @as([8]u8, @bitCast(big(c.write_seq)));
860 break :nonce @as(V, p.client_iv) ^ operand;
861 };
862 c.write_seq += 1; // TODO send key_update on overflow
863 P.AEAD.encrypt(ciphertext, auth_tag, cleartext, ad, nonce, p.client_key);
864
865 const record = ciphertext_buf[record_start..ciphertext_end];
866 iovecs[iovec_end] = .{
867 .base = record.ptr,
868 .len = record.len,
869 };
870 iovec_end += 1;
871 }
942 inline else => |*p| switch (c.tls_version) {
943 .tls_1_3 => {
944 const pv = &p.tls_1_3;
945 const P = @TypeOf(p.*);
946 const overhead_len = tls.record_header_len + P.AEAD.tag_length + 1;
947 const close_notify_alert_reserved = tls.close_notify_alert.len + overhead_len;
948 while (true) {
949 const encrypted_content_len: u16 = @min(
950 bytes.len - bytes_i,
951 tls.max_ciphertext_inner_record_len,
952 ciphertext_buf.len -|
953 (close_notify_alert_reserved + overhead_len + ciphertext_end),
954 );
955 if (encrypted_content_len == 0) return .{
956 .iovec_end = iovec_end,
957 .ciphertext_end = ciphertext_end,
958 .overhead_len = overhead_len,
959 };
960
961 @memcpy(cleartext_buf[0..encrypted_content_len], bytes[bytes_i..][0..encrypted_content_len]);
962 cleartext_buf[encrypted_content_len] = @intFromEnum(inner_content_type);
963 bytes_i += encrypted_content_len;
964 const ciphertext_len = encrypted_content_len + 1;
965 const cleartext = cleartext_buf[0..ciphertext_len];
966
967 const record_start = ciphertext_end;
968 const ad = ciphertext_buf[ciphertext_end..][0..tls.record_header_len];
969 ad.* =
970 [_]u8{@intFromEnum(tls.ContentType.application_data)} ++
971 int2(@intFromEnum(tls.ProtocolVersion.tls_1_2)) ++
972 int2(ciphertext_len + P.AEAD.tag_length);
973 ciphertext_end += ad.len;
974 const ciphertext = ciphertext_buf[ciphertext_end..][0..ciphertext_len];
975 ciphertext_end += ciphertext_len;
976 const auth_tag = ciphertext_buf[ciphertext_end..][0..P.AEAD.tag_length];
977 ciphertext_end += auth_tag.len;
978 const nonce = if (builtin.zig_backend == .stage2_x86_64 and
979 P.AEAD.nonce_length > comptime std.simd.suggestVectorLength(u8) orelse 1)
980 nonce: {
981 var nonce = pv.client_iv;
982 const operand = std.mem.readInt(u64, nonce[nonce.len - 8 ..], .big);
983 std.mem.writeInt(u64, nonce[nonce.len - 8 ..], operand ^ c.write_seq, .big);
984 break :nonce nonce;
985 } else nonce: {
986 const V = @Vector(P.AEAD.nonce_length, u8);
987 const pad = [1]u8{0} ** (P.AEAD.nonce_length - 8);
988 const operand: V = pad ++ std.mem.toBytes(big(c.write_seq));
989 break :nonce @as(V, pv.client_iv) ^ operand;
990 };
991 P.AEAD.encrypt(ciphertext, auth_tag, cleartext, ad, nonce, pv.client_key);
992 c.write_seq += 1; // TODO send key_update on overflow
993
994 const record = ciphertext_buf[record_start..ciphertext_end];
995 iovecs[iovec_end] = .{
996 .base = record.ptr,
997 .len = record.len,
998 };
999 iovec_end += 1;
1000 }
1001 },
1002 .tls_1_2 => {
1003 const pv = &p.tls_1_2;
1004 const P = @TypeOf(p.*);
1005 const overhead_len = tls.record_header_len + P.record_iv_length + P.mac_length;
1006 const close_notify_alert_reserved = tls.close_notify_alert.len + overhead_len;
1007 while (true) {
1008 const message_len: u16 = @min(
1009 bytes.len - bytes_i,
1010 tls.max_ciphertext_inner_record_len,
1011 ciphertext_buf.len -|
1012 (close_notify_alert_reserved + overhead_len + ciphertext_end),
1013 );
1014 if (message_len == 0) return .{
1015 .iovec_end = iovec_end,
1016 .ciphertext_end = ciphertext_end,
1017 .overhead_len = overhead_len,
1018 };
1019
1020 @memcpy(cleartext_buf[0..message_len], bytes[bytes_i..][0..message_len]);
1021 bytes_i += message_len;
1022 const cleartext = cleartext_buf[0..message_len];
1023
1024 const record_start = ciphertext_end;
1025 const record_header = ciphertext_buf[ciphertext_end..][0..tls.record_header_len];
1026 ciphertext_end += tls.record_header_len;
1027 record_header.* = [_]u8{@intFromEnum(inner_content_type)} ++
1028 int2(@intFromEnum(tls.ProtocolVersion.tls_1_2)) ++
1029 int2(P.record_iv_length + message_len + P.mac_length);
1030 const ad = std.mem.toBytes(big(c.write_seq)) ++ record_header[0 .. 1 + 2] ++ int2(message_len);
1031 const record_iv = ciphertext_buf[ciphertext_end..][0..P.record_iv_length];
1032 ciphertext_end += P.record_iv_length;
1033 const nonce: [P.AEAD.nonce_length]u8 = if (builtin.zig_backend == .stage2_x86_64 and
1034 P.AEAD.nonce_length > comptime std.simd.suggestVectorLength(u8) orelse 1)
1035 nonce: {
1036 var nonce = pv.client_write_IV ++ pv.client_salt;
1037 const operand = std.mem.readInt(u64, nonce[nonce.len - 8 ..], .big);
1038 std.mem.writeInt(u64, nonce[nonce.len - 8 ..], operand ^ c.write_seq, .big);
1039 break :nonce nonce;
1040 } else nonce: {
1041 const V = @Vector(P.AEAD.nonce_length, u8);
1042 const pad = [1]u8{0} ** (P.AEAD.nonce_length - 8);
1043 const operand: V = pad ++ @as([8]u8, @bitCast(big(c.write_seq)));
1044 break :nonce @as(V, pv.client_write_IV ++ pv.client_salt) ^ operand;
1045 };
1046 record_iv.* = nonce[P.fixed_iv_length..].*;
1047 const ciphertext = ciphertext_buf[ciphertext_end..][0..message_len];
1048 ciphertext_end += message_len;
1049 const auth_tag = ciphertext_buf[ciphertext_end..][0..P.mac_length];
1050 ciphertext_end += P.mac_length;
1051 P.AEAD.encrypt(ciphertext, auth_tag, cleartext, ad, nonce, pv.client_write_key);
1052 c.write_seq += 1; // TODO send key_update on overflow
1053
1054 const record = ciphertext_buf[record_start..ciphertext_end];
1055 iovecs[iovec_end] = .{
1056 .base = record.ptr,
1057 .len = record.len,
1058 };
1059 iovec_end += 1;
1060 }
1061 },
1062 else => unreachable,
8721063 },
8731064 }
8741065}
......@@ -990,7 +1181,7 @@ pub fn readvAdvanced(c: *Client, stream: anytype, iovecs: []const std.posix.iove
9901181 // beginning of the buffer will be used for such purposes.
9911182 const cleartext_buf_len = free_size - ciphertext_buf_len;
9921183
993 // Recoup `partially_read_buffer space`. This is necessary because it is assumed
1184 // Recoup `partially_read_buffer` space. This is necessary because it is assumed
9941185 // below that `frag0` is big enough to hold at least one record.
9951186 limitedOverlapCopy(c.partially_read_buffer[0..c.partial_ciphertext_end], c.partial_ciphertext_idx);
9961187 c.partial_ciphertext_end -= c.partial_ciphertext_idx;
......@@ -1105,159 +1296,182 @@ pub fn readvAdvanced(c: *Client, stream: anytype, iovecs: []const std.posix.iove
11051296 in = 0;
11061297 continue;
11071298 }
1108 switch (ct) {
1299 const cleartext, const inner_ct: tls.ContentType = cleartext: switch (c.application_cipher) {
1300 inline else => |*p| switch (c.tls_version) {
1301 .tls_1_3 => {
1302 const pv = &p.tls_1_3;
1303 const P = @TypeOf(p.*);
1304 const ad = frag[in - tls.record_header_len ..][0..tls.record_header_len];
1305 const ciphertext_len = record_len - P.AEAD.tag_length;
1306 const ciphertext = frag[in..][0..ciphertext_len];
1307 in += ciphertext_len;
1308 const auth_tag = frag[in..][0..P.AEAD.tag_length].*;
1309 const nonce = if (builtin.zig_backend == .stage2_x86_64 and
1310 P.AEAD.nonce_length > comptime std.simd.suggestVectorLength(u8) orelse 1)
1311 nonce: {
1312 var nonce = pv.server_iv;
1313 const operand = std.mem.readInt(u64, nonce[nonce.len - 8 ..], .big);
1314 std.mem.writeInt(u64, nonce[nonce.len - 8 ..], operand ^ c.read_seq, .big);
1315 break :nonce nonce;
1316 } else nonce: {
1317 const V = @Vector(P.AEAD.nonce_length, u8);
1318 const pad = [1]u8{0} ** (P.AEAD.nonce_length - 8);
1319 const operand: V = pad ++ std.mem.toBytes(big(c.read_seq));
1320 break :nonce @as(V, pv.server_iv) ^ operand;
1321 };
1322 const out_buf = vp.peek();
1323 const cleartext_buf = if (ciphertext.len <= out_buf.len)
1324 out_buf
1325 else
1326 &cleartext_stack_buffer;
1327 const cleartext = cleartext_buf[0..ciphertext.len];
1328 P.AEAD.decrypt(cleartext, ciphertext, auth_tag, ad, nonce, pv.server_key) catch
1329 return error.TlsBadRecordMac;
1330 const msg = mem.trimRight(u8, cleartext, "\x00");
1331 break :cleartext .{ msg[0 .. msg.len - 1], @enumFromInt(msg[msg.len - 1]) };
1332 },
1333 .tls_1_2 => {
1334 const pv = &p.tls_1_2;
1335 const P = @TypeOf(p.*);
1336 const message_len: u16 = record_len - P.record_iv_length - P.mac_length;
1337 const ad = std.mem.toBytes(big(c.read_seq)) ++
1338 frag[in - tls.record_header_len ..][0 .. 1 + 2] ++
1339 std.mem.toBytes(big(message_len));
1340 const record_iv = frag[in..][0..P.record_iv_length].*;
1341 in += P.record_iv_length;
1342 const masked_read_seq = c.read_seq &
1343 comptime std.math.shl(u64, std.math.maxInt(u64), 8 * P.record_iv_length);
1344 const nonce: [P.AEAD.nonce_length]u8 = if (builtin.zig_backend == .stage2_x86_64 and
1345 P.AEAD.nonce_length > comptime std.simd.suggestVectorLength(u8) orelse 1)
1346 nonce: {
1347 var nonce = pv.server_write_IV ++ record_iv;
1348 const operand = std.mem.readInt(u64, nonce[nonce.len - 8 ..], .big);
1349 std.mem.writeInt(u64, nonce[nonce.len - 8 ..], operand ^ masked_read_seq, .big);
1350 break :nonce nonce;
1351 } else nonce: {
1352 const V = @Vector(P.AEAD.nonce_length, u8);
1353 const pad = [1]u8{0} ** (P.AEAD.nonce_length - 8);
1354 const operand: V = pad ++ @as([8]u8, @bitCast(big(masked_read_seq)));
1355 break :nonce @as(V, pv.server_write_IV ++ record_iv) ^ operand;
1356 };
1357 const ciphertext = frag[in..][0..message_len];
1358 in += message_len;
1359 const auth_tag = frag[in..][0..P.mac_length].*;
1360 in += P.mac_length;
1361 const out_buf = vp.peek();
1362 const cleartext_buf = if (message_len <= out_buf.len)
1363 out_buf
1364 else
1365 &cleartext_stack_buffer;
1366 const cleartext = cleartext_buf[0..ciphertext.len];
1367 P.AEAD.decrypt(cleartext, ciphertext, auth_tag, ad, nonce, pv.server_write_key) catch
1368 return error.TlsBadRecordMac;
1369 break :cleartext .{ cleartext, ct };
1370 },
1371 else => unreachable,
1372 },
1373 };
1374 c.read_seq = try std.math.add(u64, c.read_seq, 1);
1375 switch (inner_ct) {
11091376 .alert => {
1110 if (in + 2 > frag.len) return error.TlsDecodeError;
1111 const level: tls.AlertLevel = @enumFromInt(frag[in]);
1112 const desc: tls.AlertDescription = @enumFromInt(frag[in + 1]);
1377 if (cleartext.len != 2) return error.TlsDecodeError;
1378 const level: tls.AlertLevel = @enumFromInt(cleartext[0]);
1379 const desc: tls.AlertDescription = @enumFromInt(cleartext[1]);
1380 if (desc == .close_notify) {
1381 c.received_close_notify = true;
1382 c.partial_ciphertext_end = c.partial_ciphertext_idx;
1383 return vp.total;
1384 }
11131385 _ = level;
11141386
11151387 try desc.toError();
11161388 // TODO: handle server-side closures
11171389 return error.TlsUnexpectedMessage;
11181390 },
1119 .application_data => {
1120 const cleartext = switch (c.application_cipher) {
1121 inline else => |*p| c: {
1122 const P = @TypeOf(p.*);
1123 const ad = frag[in - 5 ..][0..5];
1124 const ciphertext_len = record_len - P.AEAD.tag_length;
1125 const ciphertext = frag[in..][0..ciphertext_len];
1126 in += ciphertext_len;
1127 const auth_tag = frag[in..][0..P.AEAD.tag_length].*;
1128 const nonce = if (builtin.zig_backend == .stage2_x86_64 and
1129 P.AEAD.nonce_length > comptime std.simd.suggestVectorLength(u8) orelse 1)
1130 nonce: {
1131 var nonce = p.server_iv;
1132 const operand = std.mem.readInt(u64, nonce[nonce.len - 8 ..], .big);
1133 std.mem.writeInt(u64, nonce[nonce.len - 8 ..], operand ^ c.read_seq, .big);
1134 break :nonce nonce;
1135 } else nonce: {
1136 const V = @Vector(P.AEAD.nonce_length, u8);
1137 const pad = [1]u8{0} ** (P.AEAD.nonce_length - 8);
1138 const operand: V = pad ++ @as([8]u8, @bitCast(big(c.read_seq)));
1139 break :nonce @as(V, p.server_iv) ^ operand;
1140 };
1141 const out_buf = vp.peek();
1142 const cleartext_buf = if (ciphertext.len <= out_buf.len)
1143 out_buf
1144 else
1145 &cleartext_stack_buffer;
1146 const cleartext = cleartext_buf[0..ciphertext.len];
1147 P.AEAD.decrypt(cleartext, ciphertext, auth_tag, ad, nonce, p.server_key) catch
1148 return error.TlsBadRecordMac;
1149 break :c mem.trimRight(u8, cleartext, "\x00");
1150 },
1151 };
1152
1153 c.read_seq = try std.math.add(u64, c.read_seq, 1);
1154
1155 const inner_ct: tls.ContentType = @enumFromInt(cleartext[cleartext.len - 1]);
1156 switch (inner_ct) {
1157 .alert => {
1158 const level: tls.AlertLevel = @enumFromInt(cleartext[0]);
1159 const desc: tls.AlertDescription = @enumFromInt(cleartext[1]);
1160 if (desc == .close_notify) {
1161 c.received_close_notify = true;
1162 c.partial_ciphertext_end = c.partial_ciphertext_idx;
1163 return vp.total;
1164 }
1165 _ = level;
1166
1167 try desc.toError();
1168 // TODO: handle server-side closures
1169 return error.TlsUnexpectedMessage;
1170 },
1171 .handshake => {
1172 var ct_i: usize = 0;
1173 while (true) {
1174 const handshake_type: tls.HandshakeType = @enumFromInt(cleartext[ct_i]);
1175 ct_i += 1;
1176 const handshake_len = mem.readInt(u24, cleartext[ct_i..][0..3], .big);
1177 ct_i += 3;
1178 const next_handshake_i = ct_i + handshake_len;
1179 if (next_handshake_i > cleartext.len - 1)
1180 return error.TlsBadLength;
1181 const handshake = cleartext[ct_i..next_handshake_i];
1182 switch (handshake_type) {
1183 .new_session_ticket => {
1184 // This client implementation ignores new session tickets.
1391 .handshake => {
1392 var ct_i: usize = 0;
1393 while (true) {
1394 const handshake_type: tls.HandshakeType = @enumFromInt(cleartext[ct_i]);
1395 ct_i += 1;
1396 const handshake_len = mem.readInt(u24, cleartext[ct_i..][0..3], .big);
1397 ct_i += 3;
1398 const next_handshake_i = ct_i + handshake_len;
1399 if (next_handshake_i > cleartext.len)
1400 return error.TlsBadLength;
1401 const handshake = cleartext[ct_i..next_handshake_i];
1402 switch (handshake_type) {
1403 .new_session_ticket => {
1404 // This client implementation ignores new session tickets.
1405 },
1406 .key_update => {
1407 switch (c.application_cipher) {
1408 inline else => |*p| {
1409 const pv = &p.tls_1_3;
1410 const P = @TypeOf(p.*);
1411 const server_secret = hkdfExpandLabel(P.Hkdf, pv.server_secret, "traffic upd", "", P.Hash.digest_length);
1412 pv.server_secret = server_secret;
1413 pv.server_key = hkdfExpandLabel(P.Hkdf, server_secret, "key", "", P.AEAD.key_length);
1414 pv.server_iv = hkdfExpandLabel(P.Hkdf, server_secret, "iv", "", P.AEAD.nonce_length);
11851415 },
1186 .key_update => {
1416 }
1417 c.read_seq = 0;
1418
1419 switch (@as(tls.KeyUpdateRequest, @enumFromInt(handshake[0]))) {
1420 .update_requested => {
11871421 switch (c.application_cipher) {
11881422 inline else => |*p| {
1423 const pv = &p.tls_1_3;
11891424 const P = @TypeOf(p.*);
1190 const server_secret = hkdfExpandLabel(P.Hkdf, p.server_secret, "traffic upd", "", P.Hash.digest_length);
1191 p.server_secret = server_secret;
1192 p.server_key = hkdfExpandLabel(P.Hkdf, server_secret, "key", "", P.AEAD.key_length);
1193 p.server_iv = hkdfExpandLabel(P.Hkdf, server_secret, "iv", "", P.AEAD.nonce_length);
1194 },
1195 }
1196 c.read_seq = 0;
1197
1198 switch (@as(tls.KeyUpdateRequest, @enumFromInt(handshake[0]))) {
1199 .update_requested => {
1200 switch (c.application_cipher) {
1201 inline else => |*p| {
1202 const P = @TypeOf(p.*);
1203 const client_secret = hkdfExpandLabel(P.Hkdf, p.client_secret, "traffic upd", "", P.Hash.digest_length);
1204 p.client_secret = client_secret;
1205 p.client_key = hkdfExpandLabel(P.Hkdf, client_secret, "key", "", P.AEAD.key_length);
1206 p.client_iv = hkdfExpandLabel(P.Hkdf, client_secret, "iv", "", P.AEAD.nonce_length);
1207 },
1208 }
1209 c.write_seq = 0;
1425 const client_secret = hkdfExpandLabel(P.Hkdf, pv.client_secret, "traffic upd", "", P.Hash.digest_length);
1426 pv.client_secret = client_secret;
1427 pv.client_key = hkdfExpandLabel(P.Hkdf, client_secret, "key", "", P.AEAD.key_length);
1428 pv.client_iv = hkdfExpandLabel(P.Hkdf, client_secret, "iv", "", P.AEAD.nonce_length);
12101429 },
1211 .update_not_requested => {},
1212 _ => return error.TlsIllegalParameter,
12131430 }
1431 c.write_seq = 0;
12141432 },
1215 else => {
1216 return error.TlsUnexpectedMessage;
1217 },
1218 }
1219 ct_i = next_handshake_i;
1220 if (ct_i >= cleartext.len - 1) break;
1221 }
1222 },
1223 .application_data => {
1224 // Determine whether the output buffer or a stack
1225 // buffer was used for storing the cleartext.
1226 if (cleartext.ptr == &cleartext_stack_buffer) {
1227 // Stack buffer was used, so we must copy to the output buffer.
1228 const msg = cleartext[0 .. cleartext.len - 1];
1229 if (c.partial_ciphertext_idx > c.partial_cleartext_idx) {
1230 // We have already run out of room in iovecs. Continue
1231 // appending to `partially_read_buffer`.
1232 @memcpy(
1233 c.partially_read_buffer[c.partial_ciphertext_idx..][0..msg.len],
1234 msg,
1235 );
1236 c.partial_ciphertext_idx = @intCast(c.partial_ciphertext_idx + msg.len);
1237 } else {
1238 const amt = vp.put(msg);
1239 if (amt < msg.len) {
1240 const rest = msg[amt..];
1241 c.partial_cleartext_idx = 0;
1242 c.partial_ciphertext_idx = @intCast(rest.len);
1243 @memcpy(c.partially_read_buffer[0..rest.len], rest);
1244 }
1433 .update_not_requested => {},
1434 _ => return error.TlsIllegalParameter,
12451435 }
1246 } else {
1247 // Output buffer was used directly which means no
1248 // memory copying needs to occur, and we can move
1249 // on to the next ciphertext record.
1250 vp.next(cleartext.len - 1);
1251 }
1252 },
1253 else => {
1254 return error.TlsUnexpectedMessage;
1255 },
1436 },
1437 else => {
1438 return error.TlsUnexpectedMessage;
1439 },
1440 }
1441 ct_i = next_handshake_i;
1442 if (ct_i >= cleartext.len) break;
12561443 }
12571444 },
1258 else => {
1259 return error.TlsUnexpectedMessage;
1445 .application_data => {
1446 // Determine whether the output buffer or a stack
1447 // buffer was used for storing the cleartext.
1448 if (cleartext.ptr == &cleartext_stack_buffer) {
1449 // Stack buffer was used, so we must copy to the output buffer.
1450 if (c.partial_ciphertext_idx > c.partial_cleartext_idx) {
1451 // We have already run out of room in iovecs. Continue
1452 // appending to `partially_read_buffer`.
1453 @memcpy(
1454 c.partially_read_buffer[c.partial_ciphertext_idx..][0..cleartext.len],
1455 cleartext,
1456 );
1457 c.partial_ciphertext_idx = @intCast(c.partial_ciphertext_idx + cleartext.len);
1458 } else {
1459 const amt = vp.put(cleartext);
1460 if (amt < cleartext.len) {
1461 const rest = cleartext[amt..];
1462 c.partial_cleartext_idx = 0;
1463 c.partial_ciphertext_idx = @intCast(rest.len);
1464 @memcpy(c.partially_read_buffer[0..rest.len], rest);
1465 }
1466 }
1467 } else {
1468 // Output buffer was used directly which means no
1469 // memory copying needs to occur, and we can move
1470 // on to the next ciphertext record.
1471 vp.next(cleartext.len);
1472 }
12601473 },
1474 else => return error.TlsUnexpectedMessage,
12611475 }
12621476 in = end;
12631477 }
......@@ -1326,6 +1540,74 @@ inline fn big(x: anytype) @TypeOf(x) {
13261540 };
13271541}
13281542
1543const KeyShare = struct {
1544 x25519_kp: crypto.dh.X25519.KeyPair,
1545 secp256r1_kp: crypto.sign.ecdsa.EcdsaP256Sha256.KeyPair,
1546 ml_kem768_kp: crypto.kem.ml_kem.MLKem768.KeyPair,
1547 sk_buf: [sk_max_len]u8,
1548 sk_len: std.math.IntFittingRange(0, sk_max_len),
1549
1550 const sk_max_len = @max(
1551 crypto.dh.X25519.shared_length + crypto.kem.ml_kem.MLKem768.shared_length,
1552 crypto.dh.X25519.shared_length,
1553 crypto.ecc.P256.scalar.encoded_length,
1554 );
1555
1556 fn init(seed: [64]u8) error{IdentityElement}!KeyShare {
1557 return .{
1558 .x25519_kp = try .create(seed[0..32].*),
1559 .secp256r1_kp = try .create(seed[32..64].*),
1560 .ml_kem768_kp = try .create(null),
1561 .sk_buf = undefined,
1562 .sk_len = 0,
1563 };
1564 }
1565
1566 fn exchange(
1567 ks: *KeyShare,
1568 named_group: tls.NamedGroup,
1569 server_pub_key: []const u8,
1570 ) error{ TlsIllegalParameter, TlsDecryptFailure }!void {
1571 switch (named_group) {
1572 .x25519_ml_kem768 => {
1573 const xksl = crypto.dh.X25519.public_length;
1574 const hksl = xksl + crypto.kem.ml_kem.MLKem768.ciphertext_length;
1575 if (server_pub_key.len != hksl) return error.TlsIllegalParameter;
1576
1577 const xsk = crypto.dh.X25519.scalarmult(ks.x25519_kp.secret_key, server_pub_key[0..xksl].*) catch
1578 return error.TlsDecryptFailure;
1579 const hsk = ks.ml_kem768_kp.secret_key.decaps(server_pub_key[xksl..hksl]) catch
1580 return error.TlsDecryptFailure;
1581 @memcpy(ks.sk_buf[0..xsk.len], &xsk);
1582 @memcpy(ks.sk_buf[xsk.len..][0..hsk.len], &hsk);
1583 ks.sk_len = xsk.len + hsk.len;
1584 },
1585 .x25519 => {
1586 const ksl = crypto.dh.X25519.public_length;
1587 if (server_pub_key.len != ksl) return error.TlsIllegalParameter;
1588 const sk = crypto.dh.X25519.scalarmult(ks.x25519_kp.secret_key, server_pub_key[0..ksl].*) catch
1589 return error.TlsDecryptFailure;
1590 @memcpy(ks.sk_buf[0..sk.len], &sk);
1591 ks.sk_len = sk.len;
1592 },
1593 .secp256r1 => {
1594 const PublicKey = crypto.sign.ecdsa.EcdsaP256Sha256.PublicKey;
1595 const pk = PublicKey.fromSec1(server_pub_key) catch return error.TlsDecryptFailure;
1596 const mul = pk.p.mulPublic(ks.secp256r1_kp.secret_key.bytes, .big) catch
1597 return error.TlsDecryptFailure;
1598 const sk = mul.affineCoordinates().x.toBytes(.big);
1599 @memcpy(ks.sk_buf[0..sk.len], &sk);
1600 ks.sk_len = sk.len;
1601 },
1602 else => return error.TlsIllegalParameter,
1603 }
1604 }
1605
1606 fn getSharedSecret(ks: *const KeyShare) ?[]const u8 {
1607 return if (ks.sk_len > 0) ks.sk_buf[0..ks.sk_len] else null;
1608 }
1609};
1610
13291611fn SchemeEcdsa(comptime scheme: tls.SignatureScheme) type {
13301612 return switch (scheme) {
13311613 .ecdsa_secp256r1_sha256 => crypto.sign.ecdsa.EcdsaP256Sha256,
......@@ -1334,11 +1616,20 @@ fn SchemeEcdsa(comptime scheme: tls.SignatureScheme) type {
13341616 };
13351617}
13361618
1337fn SchemeHash(comptime scheme: tls.SignatureScheme) type {
1619fn SchemeRsa(comptime scheme: tls.SignatureScheme) type {
13381620 return switch (scheme) {
1339 .rsa_pss_rsae_sha256 => crypto.hash.sha2.Sha256,
1340 .rsa_pss_rsae_sha384 => crypto.hash.sha2.Sha384,
1341 .rsa_pss_rsae_sha512 => crypto.hash.sha2.Sha512,
1621 .rsa_pkcs1_sha256,
1622 .rsa_pkcs1_sha384,
1623 .rsa_pkcs1_sha512,
1624 .rsa_pkcs1_sha1,
1625 => Certificate.rsa.PKCS1v1_5Signature,
1626 .rsa_pss_rsae_sha256,
1627 .rsa_pss_rsae_sha384,
1628 .rsa_pss_rsae_sha512,
1629 .rsa_pss_pss_sha256,
1630 .rsa_pss_pss_sha384,
1631 .rsa_pss_pss_sha512,
1632 => Certificate.rsa.PSSSignature,
13421633 else => @compileError("bad scheme"),
13431634 };
13441635}
......@@ -1350,6 +1641,142 @@ fn SchemeEddsa(comptime scheme: tls.SignatureScheme) type {
13501641 };
13511642}
13521643
1644fn SchemeHash(comptime scheme: tls.SignatureScheme) type {
1645 return switch (scheme) {
1646 .rsa_pkcs1_sha256,
1647 .ecdsa_secp256r1_sha256,
1648 .rsa_pss_rsae_sha256,
1649 .rsa_pss_pss_sha256,
1650 => crypto.hash.sha2.Sha256,
1651 .rsa_pkcs1_sha384,
1652 .ecdsa_secp384r1_sha384,
1653 .rsa_pss_rsae_sha384,
1654 .rsa_pss_pss_sha384,
1655 => crypto.hash.sha2.Sha384,
1656 .rsa_pkcs1_sha512,
1657 .ecdsa_secp521r1_sha512,
1658 .rsa_pss_rsae_sha512,
1659 .rsa_pss_pss_sha512,
1660 => crypto.hash.sha2.Sha512,
1661 .rsa_pkcs1_sha1,
1662 .ecdsa_sha1,
1663 => crypto.hash.Sha1,
1664 else => @compileError("bad scheme"),
1665 };
1666}
1667
1668const CertificatePublicKey = struct {
1669 algo: Certificate.AlgorithmCategory,
1670 buf: [600]u8,
1671 len: u16,
1672
1673 fn init(
1674 cert_pub_key: *CertificatePublicKey,
1675 algo: Certificate.AlgorithmCategory,
1676 pub_key: []const u8,
1677 ) error{CertificatePublicKeyInvalid}!void {
1678 if (pub_key.len > cert_pub_key.buf.len) return error.CertificatePublicKeyInvalid;
1679 cert_pub_key.algo = algo;
1680 @memcpy(cert_pub_key.buf[0..pub_key.len], pub_key);
1681 cert_pub_key.len = @intCast(pub_key.len);
1682 }
1683
1684 const VerifyError = error{ TlsDecodeError, TlsBadSignatureScheme, InvalidEncoding } ||
1685 // ecdsa
1686 crypto.errors.EncodingError ||
1687 crypto.errors.NotSquareError ||
1688 crypto.errors.NonCanonicalError ||
1689 SchemeEcdsa(.ecdsa_secp256r1_sha256).Signature.VerifyError ||
1690 SchemeEcdsa(.ecdsa_secp384r1_sha384).Signature.VerifyError ||
1691 // rsa
1692 error{TlsBadRsaSignatureBitCount} ||
1693 Certificate.rsa.PublicKey.ParseDerError ||
1694 Certificate.rsa.PublicKey.FromBytesError ||
1695 Certificate.rsa.PSSSignature.VerifyError ||
1696 Certificate.rsa.PKCS1v1_5Signature.VerifyError ||
1697 // eddsa
1698 SchemeEddsa(.ed25519).Signature.VerifyError;
1699
1700 fn verifySignature(
1701 cert_pub_key: *const CertificatePublicKey,
1702 sigd: *tls.Decoder,
1703 msg: []const []const u8,
1704 ) VerifyError!void {
1705 const pub_key = cert_pub_key.buf[0..cert_pub_key.len];
1706
1707 try sigd.ensure(2 + 2);
1708 const scheme = sigd.decode(tls.SignatureScheme);
1709 const sig_len = sigd.decode(u16);
1710 try sigd.ensure(sig_len);
1711 const encoded_sig = sigd.slice(sig_len);
1712
1713 if (cert_pub_key.algo != @as(Certificate.AlgorithmCategory, switch (scheme) {
1714 .ecdsa_secp256r1_sha256,
1715 .ecdsa_secp384r1_sha384,
1716 => .X9_62_id_ecPublicKey,
1717 .rsa_pkcs1_sha256,
1718 .rsa_pkcs1_sha384,
1719 .rsa_pkcs1_sha512,
1720 .rsa_pss_rsae_sha256,
1721 .rsa_pss_rsae_sha384,
1722 .rsa_pss_rsae_sha512,
1723 .rsa_pkcs1_sha1,
1724 => .rsaEncryption,
1725 .rsa_pss_pss_sha256,
1726 .rsa_pss_pss_sha384,
1727 .rsa_pss_pss_sha512,
1728 => .rsassa_pss,
1729 else => return error.TlsBadSignatureScheme,
1730 })) return error.TlsBadSignatureScheme;
1731
1732 switch (scheme) {
1733 inline .ecdsa_secp256r1_sha256,
1734 .ecdsa_secp384r1_sha384,
1735 => |comptime_scheme| {
1736 const Ecdsa = SchemeEcdsa(comptime_scheme);
1737 const sig = try Ecdsa.Signature.fromDer(encoded_sig);
1738 const key = try Ecdsa.PublicKey.fromSec1(pub_key);
1739 try sig.concatVerify(msg, key);
1740 },
1741 inline .rsa_pkcs1_sha256,
1742 .rsa_pkcs1_sha384,
1743 .rsa_pkcs1_sha512,
1744 .rsa_pss_rsae_sha256,
1745 .rsa_pss_rsae_sha384,
1746 .rsa_pss_rsae_sha512,
1747 .rsa_pss_pss_sha256,
1748 .rsa_pss_pss_sha384,
1749 .rsa_pss_pss_sha512,
1750 .rsa_pkcs1_sha1,
1751 => |comptime_scheme| {
1752 const RsaSignature = SchemeRsa(comptime_scheme);
1753 const Hash = SchemeHash(comptime_scheme);
1754 const PublicKey = Certificate.rsa.PublicKey;
1755 const components = try PublicKey.parseDer(pub_key);
1756 const exponent = components.exponent;
1757 const modulus = components.modulus;
1758 switch (modulus.len) {
1759 inline 128, 256, 512 => |modulus_len| {
1760 const key: PublicKey = try .fromBytes(exponent, modulus);
1761 const sig = RsaSignature.fromBytes(modulus_len, encoded_sig);
1762 try RsaSignature.concatVerify(modulus_len, sig, msg, key, Hash);
1763 },
1764 else => return error.TlsBadRsaSignatureBitCount,
1765 }
1766 },
1767 inline .ed25519 => |comptime_scheme| {
1768 const Eddsa = SchemeEddsa(comptime_scheme);
1769 if (encoded_sig.len != Eddsa.Signature.encoded_length) return error.InvalidEncoding;
1770 const sig = Eddsa.Signature.fromBytes(encoded_sig[0..Eddsa.Signature.encoded_length].*);
1771 if (pub_key.len != Eddsa.PublicKey.encoded_length) return error.InvalidEncoding;
1772 const key = try Eddsa.PublicKey.fromBytes(pub_key[0..Eddsa.PublicKey.encoded_length].*);
1773 try sig.concatVerify(msg, key);
1774 },
1775 else => unreachable,
1776 }
1777 }
1778};
1779
13531780/// Abstraction for sending multiple byte buffers to a slice of iovecs.
13541781const VecPut = struct {
13551782 iovecs: []const std.posix.iovec,
......@@ -1451,16 +1878,22 @@ const cipher_suites = if (crypto.core.aes.has_hardware_support)
14511878 .AEGIS_128L_SHA256,
14521879 .AEGIS_256_SHA512,
14531880 .AES_128_GCM_SHA256,
1881 .ECDHE_RSA_WITH_AES_128_GCM_SHA256,
14541882 .AES_256_GCM_SHA384,
1883 .ECDHE_RSA_WITH_AES_256_GCM_SHA384,
14551884 .CHACHA20_POLY1305_SHA256,
1885 .ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
14561886 })
14571887else
14581888 enum_array(tls.CipherSuite, &.{
14591889 .CHACHA20_POLY1305_SHA256,
1890 .ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
14601891 .AEGIS_128L_SHA256,
14611892 .AEGIS_256_SHA512,
14621893 .AES_128_GCM_SHA256,
1894 .ECDHE_RSA_WITH_AES_128_GCM_SHA256,
14631895 .AES_256_GCM_SHA384,
1896 .ECDHE_RSA_WITH_AES_256_GCM_SHA384,
14641897 });
14651898
14661899test {
lib/std/http/protocol.zig+21-3
......@@ -172,7 +172,13 @@ pub const HeadersParser = struct {
172172 const data_avail = r.next_chunk_length;
173173
174174 if (skip) {
175 try conn.fill();
175 conn.fill() catch |err| switch (err) {
176 error.EndOfStream => {
177 r.done = true;
178 return 0;
179 },
180 else => |e| return e,
181 };
176182
177183 const nread = @min(conn.peek().len, data_avail);
178184 conn.drop(@intCast(nread));
......@@ -196,7 +202,13 @@ pub const HeadersParser = struct {
196202 }
197203 },
198204 .chunk_data_suffix, .chunk_data_suffix_r, .chunk_head_size, .chunk_head_ext, .chunk_head_r => {
199 try conn.fill();
205 conn.fill() catch |err| switch (err) {
206 error.EndOfStream => {
207 r.done = true;
208 return 0;
209 },
210 else => |e| return e,
211 };
200212
201213 const i = r.findChunkedLen(conn.peek());
202214 conn.drop(@intCast(i));
......@@ -226,7 +238,13 @@ pub const HeadersParser = struct {
226238 const out_avail = buffer.len - out_index;
227239
228240 if (skip) {
229 try conn.fill();
241 conn.fill() catch |err| switch (err) {
242 error.EndOfStream => {
243 r.done = true;
244 return 0;
245 },
246 else => |e| return e,
247 };
230248
231249 const nread = @min(conn.peek().len, data_avail);
232250 conn.drop(@intCast(nread));