std.crypto.Certificate: support v1

closes #14304
This commit is contained in:
Andrew Kelley 2023-01-15 14:59:49 -07:00
parent bb15e4057c
commit 9a0e1704ae

View File

@ -3,6 +3,8 @@ index: u32,
pub const Bundle = @import("Certificate/Bundle.zig"); pub const Bundle = @import("Certificate/Bundle.zig");
pub const Version = enum { v1, v2, v3 };
pub const Algorithm = enum { pub const Algorithm = enum {
sha1WithRSAEncryption, sha1WithRSAEncryption,
sha224WithRSAEncryption, sha224WithRSAEncryption,
@ -130,6 +132,7 @@ pub const Parsed = struct {
message_slice: Slice, message_slice: Slice,
subject_alt_name_slice: Slice, subject_alt_name_slice: Slice,
validity: Validity, validity: Validity,
version: Version,
pub const PubKeyAlgo = union(AlgorithmCategory) { pub const PubKeyAlgo = union(AlgorithmCategory) {
rsaEncryption: void, rsaEncryption: void,
@ -299,9 +302,12 @@ pub fn parse(cert: Certificate) !Parsed {
const cert_bytes = cert.buffer; const cert_bytes = cert.buffer;
const certificate = try der.Element.parse(cert_bytes, cert.index); const certificate = try der.Element.parse(cert_bytes, cert.index);
const tbs_certificate = try der.Element.parse(cert_bytes, certificate.slice.start); const tbs_certificate = try der.Element.parse(cert_bytes, certificate.slice.start);
const version = try der.Element.parse(cert_bytes, tbs_certificate.slice.start); const version_elem = try der.Element.parse(cert_bytes, tbs_certificate.slice.start);
try checkVersion(cert_bytes, version); const version = try parseVersion(cert_bytes, version_elem);
const serial_number = try der.Element.parse(cert_bytes, version.slice.end); const serial_number = if (@bitCast(u8, version_elem.identifier) == 0xa0)
try der.Element.parse(cert_bytes, version_elem.slice.end)
else
version_elem;
// RFC 5280, section 4.1.2.3: // RFC 5280, section 4.1.2.3:
// "This field MUST contain the same algorithm identifier as // "This field MUST contain the same algorithm identifier as
// the signatureAlgorithm field in the sequence Certificate." // the signatureAlgorithm field in the sequence Certificate."
@ -370,6 +376,9 @@ pub fn parse(cert: Certificate) !Parsed {
// Extensions // Extensions
var subject_alt_name_slice = der.Element.Slice.empty; var subject_alt_name_slice = der.Element.Slice.empty;
ext: { ext: {
if (version == .v1)
break :ext;
if (pub_key_info.slice.end >= tbs_certificate.slice.end) if (pub_key_info.slice.end >= tbs_certificate.slice.end)
break :ext; break :ext;
@ -415,6 +424,7 @@ pub fn parse(cert: Certificate) !Parsed {
.not_after = not_after_utc, .not_after = not_after_utc,
}, },
.subject_alt_name_slice = subject_alt_name_slice, .subject_alt_name_slice = subject_alt_name_slice,
.version = version,
}; };
} }
@ -588,12 +598,24 @@ fn parseEnum(comptime E: type, bytes: []const u8, element: der.Element) !E {
return E.map.get(oid_bytes) orelse return error.CertificateHasUnrecognizedObjectId; return E.map.get(oid_bytes) orelse return error.CertificateHasUnrecognizedObjectId;
} }
pub fn checkVersion(bytes: []const u8, version: der.Element) !void { pub fn parseVersion(bytes: []const u8, version_elem: der.Element) !Version {
if (@bitCast(u8, version.identifier) != 0xa0 or if (@bitCast(u8, version_elem.identifier) != 0xa0)
!mem.eql(u8, bytes[version.slice.start..version.slice.end], "\x02\x01\x02")) return .v1;
{
return error.UnsupportedCertificateVersion; if (version_elem.slice.end - version_elem.slice.start != 3)
return error.CertificateFieldHasInvalidLength;
const encoded_version = bytes[version_elem.slice.start..version_elem.slice.end];
if (mem.eql(u8, encoded_version, "\x02\x01\x02")) {
return .v3;
} else if (mem.eql(u8, encoded_version, "\x02\x01\x01")) {
return .v2;
} else if (mem.eql(u8, encoded_version, "\x02\x01\x00")) {
return .v1;
} }
return error.UnsupportedCertificateVersion;
} }
fn verifyRsa( fn verifyRsa(