Function parse [src]

Prototype

pub fn parse(cert: Certificate) ParseError!Parsed

Parameters

cert: Certificate

Possible Errors

CertificateFieldHasInvalidLength ParseError
CertificateFieldHasWrongDataType ParseTimeError
CertificateHasInvalidBitString ParseBitStringError
CertificateHasUnrecognizedObjectId ParseEnumError
CertificateTimeInvalid ParseTimeError
UnsupportedCertificateVersion ParseVersionError

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, }; }