authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-12-27 17:36:04-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-01-02 16:57:15-07:00
logb24f178029f20cacb559b14e5e5e095fabea4e62
tree18090910e800be16c6b5e856b0b1fc74acd62475
parenta1f6a08dcb91c74f31d9a2c75a73c7efb724bf92

std.crypto.tls.Certificate: fix parsing missing subsequent fields

Instead of seeing all the attributed types and values, the code was only seeing the first one.

2 files changed, 53 insertions(+), 19 deletions(-)

lib/std/crypto/Certificate.zig+40-14
...@@ -56,6 +56,8 @@ pub const Attribute = enum {...@@ -56,6 +56,8 @@ pub const Attribute = enum {
56 organizationName,56 organizationName,
57 organizationalUnitName,57 organizationalUnitName,
58 organizationIdentifier,58 organizationIdentifier,
59 subject_alt_name,
60 pkcs9_emailAddress,
5961
60 pub const map = std.ComptimeStringMap(Attribute, .{62 pub const map = std.ComptimeStringMap(Attribute, .{
61 .{ &[_]u8{ 0x55, 0x04, 0x03 }, .commonName },63 .{ &[_]u8{ 0x55, 0x04, 0x03 }, .commonName },
...@@ -66,6 +68,8 @@ pub const Attribute = enum {...@@ -66,6 +68,8 @@ pub const Attribute = enum {
66 .{ &[_]u8{ 0x55, 0x04, 0x0A }, .organizationName },68 .{ &[_]u8{ 0x55, 0x04, 0x0A }, .organizationName },
67 .{ &[_]u8{ 0x55, 0x04, 0x0B }, .organizationalUnitName },69 .{ &[_]u8{ 0x55, 0x04, 0x0B }, .organizationalUnitName },
68 .{ &[_]u8{ 0x55, 0x04, 0x61 }, .organizationIdentifier },70 .{ &[_]u8{ 0x55, 0x04, 0x61 }, .organizationIdentifier },
71 .{ &[_]u8{ 0x55, 0x1D, 0x11 }, .subject_alt_name },
72 .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x01 }, .pkcs9_emailAddress },
69 });73 });
70};74};
7175
...@@ -74,6 +78,7 @@ pub const Parsed = struct {...@@ -74,6 +78,7 @@ pub const Parsed = struct {
74 issuer_slice: Slice,78 issuer_slice: Slice,
75 subject_slice: Slice,79 subject_slice: Slice,
76 common_name_slice: Slice,80 common_name_slice: Slice,
81 subject_alt_name_slice: Slice,
77 signature_slice: Slice,82 signature_slice: Slice,
78 signature_algorithm: Algorithm,83 signature_algorithm: Algorithm,
79 pub_key_algo: AlgorithmCategory,84 pub_key_algo: AlgorithmCategory,
...@@ -104,6 +109,10 @@ pub const Parsed = struct {...@@ -104,6 +109,10 @@ pub const Parsed = struct {
104 return p.slice(p.common_name_slice);109 return p.slice(p.common_name_slice);
105 }110 }
106111
112 pub fn subjectAltName(p: Parsed) []const u8 {
113 return p.slice(p.subject_alt_name_slice);
114 }
115
107 pub fn signature(p: Parsed) []const u8 {116 pub fn signature(p: Parsed) []const u8 {
108 return p.slice(p.signature_slice);117 return p.slice(p.signature_slice);
109 }118 }
...@@ -195,20 +204,33 @@ pub fn parse(cert: Certificate) !Parsed {...@@ -195,20 +204,33 @@ pub fn parse(cert: Certificate) !Parsed {
195 const pub_key_elem = try der.parseElement(cert_bytes, pub_key_signature_algorithm.slice.end);204 const pub_key_elem = try der.parseElement(cert_bytes, pub_key_signature_algorithm.slice.end);
196 const pub_key = try parseBitString(cert, pub_key_elem);205 const pub_key = try parseBitString(cert, pub_key_elem);
197206
198 const rdn = try der.parseElement(cert_bytes, subject.slice.start);
199 const atav = try der.parseElement(cert_bytes, rdn.slice.start);
200
201 var common_name = der.Element.Slice.empty;207 var common_name = der.Element.Slice.empty;
202 var atav_i = atav.slice.start;208 var subject_alt_name = der.Element.Slice.empty;
203 while (atav_i < atav.slice.end) {209 var name_i = subject.slice.start;
204 const ty_elem = try der.parseElement(cert_bytes, atav_i);210 //std.debug.print("subject name:\n", .{});
205 const ty = try parseAttribute(cert_bytes, ty_elem);211 while (name_i < subject.slice.end) {
206 const val = try der.parseElement(cert_bytes, ty_elem.slice.end);212 const rdn = try der.parseElement(cert_bytes, name_i);
207 switch (ty) {213 var rdn_i = rdn.slice.start;
208 .commonName => common_name = val.slice,214 while (rdn_i < rdn.slice.end) {
209 else => {},215 const atav = try der.parseElement(cert_bytes, rdn_i);
216 var atav_i = atav.slice.start;
217 while (atav_i < atav.slice.end) {
218 const ty_elem = try der.parseElement(cert_bytes, atav_i);
219 const ty = try parseAttribute(cert_bytes, ty_elem);
220 const val = try der.parseElement(cert_bytes, ty_elem.slice.end);
221 //std.debug.print(" {s}: '{s}'\n", .{
222 // @tagName(ty), cert_bytes[val.slice.start..val.slice.end],
223 //});
224 switch (ty) {
225 .commonName => common_name = val.slice,
226 .subject_alt_name => subject_alt_name = val.slice,
227 else => {},
228 }
229 atav_i = val.slice.end;
230 }
231 rdn_i = atav.slice.end;
210 }232 }
211 atav_i = val.slice.end;233 name_i = rdn.slice.end;
212 }234 }
213235
214 const sig_algo = try der.parseElement(cert_bytes, tbs_certificate.slice.end);236 const sig_algo = try der.parseElement(cert_bytes, tbs_certificate.slice.end);
...@@ -220,6 +242,7 @@ pub fn parse(cert: Certificate) !Parsed {...@@ -220,6 +242,7 @@ pub fn parse(cert: Certificate) !Parsed {
220 return .{242 return .{
221 .certificate = cert,243 .certificate = cert,
222 .common_name_slice = common_name,244 .common_name_slice = common_name,
245 .subject_alt_name_slice = subject_alt_name,
223 .issuer_slice = issuer.slice,246 .issuer_slice = issuer.slice,
224 .subject_slice = subject.slice,247 .subject_slice = subject.slice,
225 .signature_slice = signature,248 .signature_slice = signature,
...@@ -397,8 +420,11 @@ pub fn parseAlgorithmCategory(bytes: []const u8, element: der.Element) !Algorith...@@ -397,8 +420,11 @@ pub fn parseAlgorithmCategory(bytes: []const u8, element: der.Element) !Algorith
397pub fn parseAttribute(bytes: []const u8, element: der.Element) !Attribute {420pub fn parseAttribute(bytes: []const u8, element: der.Element) !Attribute {
398 if (element.identifier.tag != .object_identifier)421 if (element.identifier.tag != .object_identifier)
399 return error.CertificateFieldHasWrongDataType;422 return error.CertificateFieldHasWrongDataType;
400 return Attribute.map.get(bytes[element.slice.start..element.slice.end]) orelse423 const oid_bytes = bytes[element.slice.start..element.slice.end];
401 return error.CertificateHasUnrecognizedAlgorithm;424 return Attribute.map.get(oid_bytes) orelse {
425 //std.debug.print("attr: {}\n", .{std.fmt.fmtSliceHexLower(oid_bytes)});
426 return error.CertificateHasUnrecognizedAttribute;
427 };
402}428}
403429
404fn verifyRsa(430fn verifyRsa(
lib/std/crypto/tls/Client.zig+13-5
...@@ -323,8 +323,8 @@ pub fn init(stream: net.Stream, ca_bundle: Certificate.Bundle, host: []const u8)...@@ -323,8 +323,8 @@ pub fn init(stream: net.Stream, ca_bundle: Certificate.Bundle, host: []const u8)
323 var handshake_state: HandshakeState = .encrypted_extensions;323 var handshake_state: HandshakeState = .encrypted_extensions;
324 var cleartext_bufs: [2][8000]u8 = undefined;324 var cleartext_bufs: [2][8000]u8 = undefined;
325 var main_cert_pub_key_algo: Certificate.AlgorithmCategory = undefined;325 var main_cert_pub_key_algo: Certificate.AlgorithmCategory = undefined;
326 var main_cert_pub_key_buf: [128]u8 = undefined;326 var main_cert_pub_key_buf: [300]u8 = undefined;
327 var main_cert_pub_key_len: u8 = undefined;327 var main_cert_pub_key_len: u16 = undefined;
328328
329 while (true) {329 while (true) {
330 const end_hdr = i + 5;330 const end_hdr = i + 5;
...@@ -503,7 +503,7 @@ pub fn init(stream: net.Stream, ca_bundle: Certificate.Bundle, host: []const u8)...@@ -503,7 +503,7 @@ pub fn init(stream: net.Stream, ca_bundle: Certificate.Bundle, host: []const u8)
503 var verify_buffer =503 var verify_buffer =
504 ([1]u8{0x20} ** 64) ++504 ([1]u8{0x20} ** 64) ++
505 "TLS 1.3, server CertificateVerify\x00".* ++505 "TLS 1.3, server CertificateVerify\x00".* ++
506 ([1]u8{undefined} ** max_digest_len);506 @as([max_digest_len]u8, undefined);
507507
508 const verify_bytes = switch (handshake_cipher) {508 const verify_bytes = switch (handshake_cipher) {
509 inline else => |*p| v: {509 inline else => |*p| v: {
...@@ -524,7 +524,15 @@ pub fn init(stream: net.Stream, ca_bundle: Certificate.Bundle, host: []const u8)...@@ -524,7 +524,15 @@ pub fn init(stream: net.Stream, ca_bundle: Certificate.Bundle, host: []const u8)
524 const key = try P256.PublicKey.fromSec1(main_cert_pub_key);524 const key = try P256.PublicKey.fromSec1(main_cert_pub_key);
525 try sig.verify(verify_bytes, key);525 try sig.verify(verify_bytes, key);
526 },526 },
527 else => return error.TlsBadSignatureAlgorithm,527 .rsa_pss_rsae_sha256 => {
528 @panic("TODO signature algorithm: rsa_pss_rsae_sha256");
529 },
530 else => {
531 //std.debug.print("signature algorithm: {any}\n", .{
532 // algorithm,
533 //});
534 return error.TlsBadSignatureAlgorithm;
535 },
528 }536 }
529 },537 },
530 @enumToInt(HandshakeType.finished) => {538 @enumToInt(HandshakeType.finished) => {
...@@ -557,7 +565,7 @@ pub fn init(stream: net.Stream, ca_bundle: Certificate.Bundle, host: []const u8)...@@ -557,7 +565,7 @@ pub fn init(stream: net.Stream, ca_bundle: Certificate.Bundle, host: []const u8)
557 @enumToInt(ContentType.application_data),565 @enumToInt(ContentType.application_data),
558 0x03, 0x03, // legacy protocol version566 0x03, 0x03, // legacy protocol version
559 0, wrapped_len, // byte length of encrypted record567 0, wrapped_len, // byte length of encrypted record
560 } ++ ([1]u8{undefined} ** wrapped_len);568 } ++ @as([wrapped_len]u8, undefined);
561569
562 const ad = finished_msg[0..5];570 const ad = finished_msg[0..5];
563 const ciphertext = finished_msg[5..][0..out_cleartext.len];571 const ciphertext = finished_msg[5..][0..out_cleartext.len];