| ... | ... | @@ -3,6 +3,8 @@ index: u32, |
| 3 | 3 | |
| 4 | 4 | pub const Bundle = @import("Certificate/Bundle.zig"); |
| 5 | 5 | |
| 6 | pub const Version = enum { v1, v2, v3 }; |
| 7 | |
| 6 | 8 | pub const Algorithm = enum { |
| 7 | 9 | sha1WithRSAEncryption, |
| 8 | 10 | sha224WithRSAEncryption, |
| ... | ... | @@ -130,6 +132,7 @@ pub const Parsed = struct { |
| 130 | 132 | message_slice: Slice, |
| 131 | 133 | subject_alt_name_slice: Slice, |
| 132 | 134 | validity: Validity, |
| 135 | version: Version, |
| 133 | 136 | |
| 134 | 137 | pub const PubKeyAlgo = union(AlgorithmCategory) { |
| 135 | 138 | rsaEncryption: void, |
| ... | ... | @@ -299,9 +302,12 @@ pub fn parse(cert: Certificate) !Parsed { |
| 299 | 302 | const cert_bytes = cert.buffer; |
| 300 | 303 | const certificate = try der.Element.parse(cert_bytes, cert.index); |
| 301 | 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); |
| 303 | | try checkVersion(cert_bytes, version); |
| 304 | | const serial_number = try der.Element.parse(cert_bytes, version.slice.end); |
| 305 | const version_elem = try der.Element.parse(cert_bytes, tbs_certificate.slice.start); |
| 306 | const version = try parseVersion(cert_bytes, version_elem); |
| 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 | 311 | // RFC 5280, section 4.1.2.3: |
| 306 | 312 | // "This field MUST contain the same algorithm identifier as |
| 307 | 313 | // the signatureAlgorithm field in the sequence Certificate." |
| ... | ... | @@ -370,6 +376,9 @@ pub fn parse(cert: Certificate) !Parsed { |
| 370 | 376 | // Extensions |
| 371 | 377 | var subject_alt_name_slice = der.Element.Slice.empty; |
| 372 | 378 | ext: { |
| 379 | if (version == .v1) |
| 380 | break :ext; |
| 381 | |
| 373 | 382 | if (pub_key_info.slice.end >= tbs_certificate.slice.end) |
| 374 | 383 | break :ext; |
| 375 | 384 | |
| ... | ... | @@ -415,6 +424,7 @@ pub fn parse(cert: Certificate) !Parsed { |
| 415 | 424 | .not_after = not_after_utc, |
| 416 | 425 | }, |
| 417 | 426 | .subject_alt_name_slice = subject_alt_name_slice, |
| 427 | .version = version, |
| 418 | 428 | }; |
| 419 | 429 | } |
| 420 | 430 | |
| ... | ... | @@ -588,12 +598,24 @@ fn parseEnum(comptime E: type, bytes: []const u8, element: der.Element) !E { |
| 588 | 598 | return E.map.get(oid_bytes) orelse return error.CertificateHasUnrecognizedObjectId; |
| 589 | 599 | } |
| 590 | 600 | |
| 591 | | pub fn checkVersion(bytes: []const u8, version: der.Element) !void { |
| 592 | | if (@bitCast(u8, version.identifier) != 0xa0 or |
| 593 | | !mem.eql(u8, bytes[version.slice.start..version.slice.end], "\x02\x01\x02")) |
| 594 | | { |
| 595 | | return error.UnsupportedCertificateVersion; |
| 601 | pub fn parseVersion(bytes: []const u8, version_elem: der.Element) !Version { |
| 602 | if (@bitCast(u8, version_elem.identifier) != 0xa0) |
| 603 | return .v1; |
| 604 | |
| 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 | } |
| 598 | 620 | |
| 599 | 621 | fn verifyRsa( |