Source
pub fn parse(cert: Certificate) ParseError!Parsed {
const cert_bytes = cert.buffer;
const certificate = try der.Element.parse(cert_bytes, cert.index);
const tbs_certificate = try der.Element.parse(cert_bytes, certificate.slice.start);
const version_elem = try der.Element.parse(cert_bytes, tbs_certificate.slice.start);
const version = try parseVersion(cert_bytes, version_elem);
const serial_number = if (@as(u8, @bitCast(version_elem.identifier)) == 0xa0)
try der.Element.parse(cert_bytes, version_elem.slice.end)
else
version_elem;
// RFC 5280, section 4.1.2.3:
// "This field MUST contain the same algorithm identifier as
// the signatureAlgorithm field in the sequence Certificate."
const tbs_signature = try der.Element.parse(cert_bytes, serial_number.slice.end);
const issuer = try der.Element.parse(cert_bytes, tbs_signature.slice.end);
const validity = try der.Element.parse(cert_bytes, issuer.slice.end);
const not_before = try der.Element.parse(cert_bytes, validity.slice.start);
const not_before_utc = try parseTime(cert, not_before);
const not_after = try der.Element.parse(cert_bytes, not_before.slice.end);
const not_after_utc = try parseTime(cert, not_after);
const subject = try der.Element.parse(cert_bytes, validity.slice.end);
const pub_key_info = try der.Element.parse(cert_bytes, subject.slice.end);
const pub_key_signature_algorithm = try der.Element.parse(cert_bytes, pub_key_info.slice.start);
const pub_key_algo_elem = try der.Element.parse(cert_bytes, pub_key_signature_algorithm.slice.start);
const pub_key_algo: Parsed.PubKeyAlgo = switch (try parseAlgorithmCategory(cert_bytes, pub_key_algo_elem)) {
inline else => |tag| @unionInit(Parsed.PubKeyAlgo, @tagName(tag), {}),
.X9_62_id_ecPublicKey => pub_key_algo: {
// RFC 5480 Section 2.1.1.1 Named Curve
// ECParameters ::= CHOICE {
// namedCurve OBJECT IDENTIFIER
// -- implicitCurve NULL
// -- specifiedCurve SpecifiedECDomain
// }
const params_elem = try der.Element.parse(cert_bytes, pub_key_algo_elem.slice.end);
const named_curve = try parseNamedCurve(cert_bytes, params_elem);
break :pub_key_algo .{ .X9_62_id_ecPublicKey = named_curve };
},
};
const pub_key_elem = try der.Element.parse(cert_bytes, pub_key_signature_algorithm.slice.end);
const pub_key = try parseBitString(cert, pub_key_elem);
var common_name = der.Element.Slice.empty;
var name_i = subject.slice.start;
while (name_i < subject.slice.end) {
const rdn = try der.Element.parse(cert_bytes, name_i);
var rdn_i = rdn.slice.start;
while (rdn_i < rdn.slice.end) {
const atav = try der.Element.parse(cert_bytes, rdn_i);
var atav_i = atav.slice.start;
while (atav_i < atav.slice.end) {
const ty_elem = try der.Element.parse(cert_bytes, atav_i);
const val = try der.Element.parse(cert_bytes, ty_elem.slice.end);
atav_i = val.slice.end;
const ty = parseAttribute(cert_bytes, ty_elem) catch |err| switch (err) {
error.CertificateHasUnrecognizedObjectId => continue,
else => |e| return e,
};
switch (ty) {
.commonName => common_name = val.slice,
else => {},
}
}
rdn_i = atav.slice.end;
}
name_i = rdn.slice.end;
}
const sig_algo = try der.Element.parse(cert_bytes, tbs_certificate.slice.end);
const algo_elem = try der.Element.parse(cert_bytes, sig_algo.slice.start);
const signature_algorithm = try parseAlgorithm(cert_bytes, algo_elem);
const sig_elem = try der.Element.parse(cert_bytes, sig_algo.slice.end);
const signature = try parseBitString(cert, sig_elem);
// Extensions
var subject_alt_name_slice = der.Element.Slice.empty;
ext: {
if (version == .v1)
break :ext;
if (pub_key_info.slice.end >= tbs_certificate.slice.end)
break :ext;
const outer_extensions = try der.Element.parse(cert_bytes, pub_key_info.slice.end);
if (outer_extensions.identifier.tag != .bitstring)
break :ext;
const extensions = try der.Element.parse(cert_bytes, outer_extensions.slice.start);
var ext_i = extensions.slice.start;
while (ext_i < extensions.slice.end) {
const extension = try der.Element.parse(cert_bytes, ext_i);
ext_i = extension.slice.end;
const oid_elem = try der.Element.parse(cert_bytes, extension.slice.start);
const ext_id = parseExtensionId(cert_bytes, oid_elem) catch |err| switch (err) {
error.CertificateHasUnrecognizedObjectId => continue,
else => |e| return e,
};
const critical_elem = try der.Element.parse(cert_bytes, oid_elem.slice.end);
const ext_bytes_elem = if (critical_elem.identifier.tag != .boolean)
critical_elem
else
try der.Element.parse(cert_bytes, critical_elem.slice.end);
switch (ext_id) {
.subject_alt_name => subject_alt_name_slice = ext_bytes_elem.slice,
else => continue,
}
}
}
return .{
.certificate = cert,
.common_name_slice = common_name,
.issuer_slice = issuer.slice,
.subject_slice = subject.slice,
.signature_slice = signature,
.signature_algorithm = signature_algorithm,
.message_slice = .{ .start = certificate.slice.start, .end = tbs_certificate.slice.end },
.pub_key_algo = pub_key_algo,
.pub_key_slice = pub_key,
.validity = .{
.not_before = not_before_utc,
.not_after = not_after_utc,
},
.subject_alt_name_slice = subject_alt_name_slice,
.version = version,
};
}