| author | |
| committer | |
| log | 642a8b05c3687d5c084ed164c773bd4d0a4faaef |
| tree | 53fd0a8880b54b0e2dd51d0bb93fb188014a4a38 |
| parent | 7cb535d4b54a4e5627edc6b558d1f31b41651328 |
4 files changed, 38 insertions(+), 10 deletions(-)
lib/std/crypto/Certificate.zig+26-4| ... | ... | @@ -116,9 +116,23 @@ pub const Parsed = struct { |
| 116 | 116 | return p.slice(p.message_slice); |
| 117 | 117 | } |
| 118 | 118 | |
| 119 | pub const VerifyError = error{ | |
| 120 | CertificateIssuerMismatch, | |
| 121 | CertificateNotYetValid, | |
| 122 | CertificateExpired, | |
| 123 | CertificateSignatureAlgorithmUnsupported, | |
| 124 | CertificateSignatureAlgorithmMismatch, | |
| 125 | CertificateFieldHasInvalidLength, | |
| 126 | CertificateFieldHasWrongDataType, | |
| 127 | CertificatePublicKeyInvalid, | |
| 128 | CertificateSignatureInvalidLength, | |
| 129 | CertificateSignatureInvalid, | |
| 130 | CertificateSignatureUnsupportedBitCount, | |
| 131 | }; | |
| 132 | ||
| 119 | 133 | /// This function checks the time validity for the subject only. Checking |
| 120 | 134 | /// the issuer's time validity is out of scope. |
| 121 | pub fn verify(parsed_subject: Parsed, parsed_issuer: Parsed) !void { | |
| 135 | pub fn verify(parsed_subject: Parsed, parsed_issuer: Parsed) VerifyError!void { | |
| 122 | 136 | // Check that the subject's issuer name matches the issuer's |
| 123 | 137 | // subject name. |
| 124 | 138 | if (!mem.eql(u8, parsed_subject.issuer(), parsed_issuer.subject())) { |
| ... | ... | @@ -452,11 +466,19 @@ fn verifyRsa( |
| 452 | 466 | hash_der ++ |
| 453 | 467 | msg_hashed; |
| 454 | 468 | |
| 455 | const public_key = try rsa.PublicKey.fromBytes(exponent, modulus, rsa.poop); | |
| 456 | const em_dec = try rsa.encrypt(modulus_len, sig[0..modulus_len].*, public_key, rsa.poop); | |
| 469 | const public_key = rsa.PublicKey.fromBytes(exponent, modulus, rsa.poop) catch |err| switch (err) { | |
| 470 | error.OutOfMemory => @panic("TODO don't heap allocate"), | |
| 471 | }; | |
| 472 | const em_dec = rsa.encrypt(modulus_len, sig[0..modulus_len].*, public_key, rsa.poop) catch |err| switch (err) { | |
| 473 | error.OutOfMemory => @panic("TODO don't heap allocate"), | |
| 474 | ||
| 475 | error.MessageTooLong => unreachable, | |
| 476 | error.NegativeIntoUnsigned => @panic("TODO make RSA not emit this error"), | |
| 477 | error.TargetTooSmall => @panic("TODO make RSA not emit this error"), | |
| 478 | error.BufferTooSmall => @panic("TODO make RSA not emit this error"), | |
| 479 | }; | |
| 457 | 480 | |
| 458 | 481 | if (!mem.eql(u8, &em, &em_dec)) { |
| 459 | try std.testing.expectEqualSlices(u8, &em, &em_dec); | |
| 460 | 482 | return error.CertificateSignatureInvalid; |
| 461 | 483 | } |
| 462 | 484 | }, |
lib/std/crypto/Certificate/Bundle.zig+9-3| ... | ... | @@ -9,13 +9,19 @@ |
| 9 | 9 | map: std.HashMapUnmanaged(der.Element.Slice, u32, MapContext, std.hash_map.default_max_load_percentage) = .{}, |
| 10 | 10 | bytes: std.ArrayListUnmanaged(u8) = .{}, |
| 11 | 11 | |
| 12 | pub fn verify(cb: Bundle, subject: Certificate.Parsed) !void { | |
| 13 | const bytes_index = cb.find(subject.issuer()) orelse return error.IssuerNotFound; | |
| 12 | pub const VerifyError = Certificate.Parsed.VerifyError || error{ | |
| 13 | CertificateIssuerNotFound, | |
| 14 | }; | |
| 15 | ||
| 16 | pub fn verify(cb: Bundle, subject: Certificate.Parsed) VerifyError!void { | |
| 17 | const bytes_index = cb.find(subject.issuer()) orelse return error.CertificateIssuerNotFound; | |
| 14 | 18 | const issuer_cert: Certificate = .{ |
| 15 | 19 | .buffer = cb.bytes.items, |
| 16 | 20 | .index = bytes_index, |
| 17 | 21 | }; |
| 18 | const issuer = try issuer_cert.parse(); | |
| 22 | // Every certificate in the bundle is pre-parsed before adding it, ensuring | |
| 23 | // that parsing will succeed here. | |
| 24 | const issuer = issuer_cert.parse() catch unreachable; | |
| 19 | 25 | try subject.verify(issuer); |
| 20 | 26 | } |
| 21 | 27 |
lib/std/crypto/der.zig+2-2| ... | ... | @@ -111,7 +111,7 @@ pub const Element = struct { |
| 111 | 111 | }; |
| 112 | 112 | }; |
| 113 | 113 | |
| 114 | pub const ParseElementError = error{CertificateHasFieldWithInvalidLength}; | |
| 114 | pub const ParseElementError = error{CertificateFieldHasInvalidLength}; | |
| 115 | 115 | |
| 116 | 116 | pub fn parseElement(bytes: []const u8, index: u32) ParseElementError!Element { |
| 117 | 117 | var i = index; |
| ... | ... | @@ -131,7 +131,7 @@ pub fn parseElement(bytes: []const u8, index: u32) ParseElementError!Element { |
| 131 | 131 | |
| 132 | 132 | const len_size = @truncate(u7, size_byte); |
| 133 | 133 | if (len_size > @sizeOf(u32)) { |
| 134 | return error.CertificateHasFieldWithInvalidLength; | |
| 134 | return error.CertificateFieldHasInvalidLength; | |
| 135 | 135 | } |
| 136 | 136 | |
| 137 | 137 | const end_i = i + len_size; |
lib/std/crypto/tls/Client.zig+1-1| ... | ... | @@ -470,7 +470,7 @@ pub fn init(stream: net.Stream, ca_bundle: Certificate.Bundle, host: []const u8) |
| 470 | 470 | handshake_state = .trust_chain_established; |
| 471 | 471 | break :cert; |
| 472 | 472 | } else |err| switch (err) { |
| 473 | error.IssuerNotFound => {}, | |
| 473 | error.CertificateIssuerNotFound => {}, | |
| 474 | 474 | else => |e| { |
| 475 | 475 | std.debug.print("unable to validate cert against system root CAs: {s}\n", .{ |
| 476 | 476 | @errorName(e), |