authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-01-15 14:59:49-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-01-15 14:59:49-07:00
log9a0e1704aee1db4a7ca29706e11dd5ec6739c094
treeea342add4bca3d29583f960970fb162791992882
parentbb15e4057c9c8bb22084990de475ab10a44592c0

std.crypto.Certificate: support v1

closes #14304

1 files changed, 30 insertions(+), 8 deletions(-)

lib/std/crypto/Certificate.zig+30-8
...@@ -3,6 +3,8 @@ index: u32,...@@ -3,6 +3,8 @@ index: u32,
33
4pub const Bundle = @import("Certificate/Bundle.zig");4pub const Bundle = @import("Certificate/Bundle.zig");
55
6pub const Version = enum { v1, v2, v3 };
7
6pub const Algorithm = enum {8pub const Algorithm = enum {
7 sha1WithRSAEncryption,9 sha1WithRSAEncryption,
8 sha224WithRSAEncryption,10 sha224WithRSAEncryption,
...@@ -130,6 +132,7 @@ pub const Parsed = struct {...@@ -130,6 +132,7 @@ pub const Parsed = struct {
130 message_slice: Slice,132 message_slice: Slice,
131 subject_alt_name_slice: Slice,133 subject_alt_name_slice: Slice,
132 validity: Validity,134 validity: Validity,
135 version: Version,
133136
134 pub const PubKeyAlgo = union(AlgorithmCategory) {137 pub const PubKeyAlgo = union(AlgorithmCategory) {
135 rsaEncryption: void,138 rsaEncryption: void,
...@@ -299,9 +302,12 @@ pub fn parse(cert: Certificate) !Parsed {...@@ -299,9 +302,12 @@ pub fn parse(cert: Certificate) !Parsed {
299 const cert_bytes = cert.buffer;302 const cert_bytes = cert.buffer;
300 const certificate = try der.Element.parse(cert_bytes, cert.index);303 const certificate = try der.Element.parse(cert_bytes, cert.index);
301 const tbs_certificate = try der.Element.parse(cert_bytes, certificate.slice.start);304 const tbs_certificate = try der.Element.parse(cert_bytes, certificate.slice.start);
302 const version = try der.Element.parse(cert_bytes, tbs_certificate.slice.start);305 const version_elem = try der.Element.parse(cert_bytes, tbs_certificate.slice.start);
303 try checkVersion(cert_bytes, version);306 const version = try parseVersion(cert_bytes, version_elem);
304 const serial_number = try der.Element.parse(cert_bytes, version.slice.end);307 const serial_number = if (@bitCast(u8, version_elem.identifier) == 0xa0)
308 try der.Element.parse(cert_bytes, version_elem.slice.end)
309 else
310 version_elem;
305 // RFC 5280, section 4.1.2.3:311 // RFC 5280, section 4.1.2.3:
306 // "This field MUST contain the same algorithm identifier as312 // "This field MUST contain the same algorithm identifier as
307 // the signatureAlgorithm field in the sequence Certificate."313 // the signatureAlgorithm field in the sequence Certificate."
...@@ -370,6 +376,9 @@ pub fn parse(cert: Certificate) !Parsed {...@@ -370,6 +376,9 @@ pub fn parse(cert: Certificate) !Parsed {
370 // Extensions376 // Extensions
371 var subject_alt_name_slice = der.Element.Slice.empty;377 var subject_alt_name_slice = der.Element.Slice.empty;
372 ext: {378 ext: {
379 if (version == .v1)
380 break :ext;
381
373 if (pub_key_info.slice.end >= tbs_certificate.slice.end)382 if (pub_key_info.slice.end >= tbs_certificate.slice.end)
374 break :ext;383 break :ext;
375384
...@@ -415,6 +424,7 @@ pub fn parse(cert: Certificate) !Parsed {...@@ -415,6 +424,7 @@ pub fn parse(cert: Certificate) !Parsed {
415 .not_after = not_after_utc,424 .not_after = not_after_utc,
416 },425 },
417 .subject_alt_name_slice = subject_alt_name_slice,426 .subject_alt_name_slice = subject_alt_name_slice,
427 .version = version,
418 };428 };
419}429}
420430
...@@ -588,12 +598,24 @@ fn parseEnum(comptime E: type, bytes: []const u8, element: der.Element) !E {...@@ -588,12 +598,24 @@ fn parseEnum(comptime E: type, bytes: []const u8, element: der.Element) !E {
588 return E.map.get(oid_bytes) orelse return error.CertificateHasUnrecognizedObjectId;598 return E.map.get(oid_bytes) orelse return error.CertificateHasUnrecognizedObjectId;
589}599}
590600
591pub fn checkVersion(bytes: []const u8, version: der.Element) !void {601pub fn parseVersion(bytes: []const u8, version_elem: der.Element) !Version {
592 if (@bitCast(u8, version.identifier) != 0xa0 or602 if (@bitCast(u8, version_elem.identifier) != 0xa0)
593 !mem.eql(u8, bytes[version.slice.start..version.slice.end], "\x02\x01\x02"))603 return .v1;
594 {604
595 return error.UnsupportedCertificateVersion;605 if (version_elem.slice.end - version_elem.slice.start != 3)
606 return error.CertificateFieldHasInvalidLength;
607
608 const encoded_version = bytes[version_elem.slice.start..version_elem.slice.end];
609
610 if (mem.eql(u8, encoded_version, "\x02\x01\x02")) {
611 return .v3;
612 } else if (mem.eql(u8, encoded_version, "\x02\x01\x01")) {
613 return .v2;
614 } else if (mem.eql(u8, encoded_version, "\x02\x01\x00")) {
615 return .v1;
596 }616 }
617
618 return error.UnsupportedCertificateVersion;
597}619}
598620
599fn verifyRsa(621fn verifyRsa(