diff --git a/lib/std/crypto/Certificate.zig b/lib/std/crypto/Certificate.zig index ba36958ae8..330c380e5d 100644 --- a/lib/std/crypto/Certificate.zig +++ b/lib/std/crypto/Certificate.zig @@ -116,9 +116,23 @@ pub const Parsed = struct { return p.slice(p.message_slice); } + pub const VerifyError = error{ + CertificateIssuerMismatch, + CertificateNotYetValid, + CertificateExpired, + CertificateSignatureAlgorithmUnsupported, + CertificateSignatureAlgorithmMismatch, + CertificateFieldHasInvalidLength, + CertificateFieldHasWrongDataType, + CertificatePublicKeyInvalid, + CertificateSignatureInvalidLength, + CertificateSignatureInvalid, + CertificateSignatureUnsupportedBitCount, + }; + /// This function checks the time validity for the subject only. Checking /// the issuer's time validity is out of scope. - pub fn verify(parsed_subject: Parsed, parsed_issuer: Parsed) !void { + pub fn verify(parsed_subject: Parsed, parsed_issuer: Parsed) VerifyError!void { // Check that the subject's issuer name matches the issuer's // subject name. if (!mem.eql(u8, parsed_subject.issuer(), parsed_issuer.subject())) { @@ -452,11 +466,19 @@ fn verifyRsa( hash_der ++ msg_hashed; - const public_key = try rsa.PublicKey.fromBytes(exponent, modulus, rsa.poop); - const em_dec = try rsa.encrypt(modulus_len, sig[0..modulus_len].*, public_key, rsa.poop); + const public_key = rsa.PublicKey.fromBytes(exponent, modulus, rsa.poop) catch |err| switch (err) { + error.OutOfMemory => @panic("TODO don't heap allocate"), + }; + const em_dec = rsa.encrypt(modulus_len, sig[0..modulus_len].*, public_key, rsa.poop) catch |err| switch (err) { + error.OutOfMemory => @panic("TODO don't heap allocate"), + + error.MessageTooLong => unreachable, + error.NegativeIntoUnsigned => @panic("TODO make RSA not emit this error"), + error.TargetTooSmall => @panic("TODO make RSA not emit this error"), + error.BufferTooSmall => @panic("TODO make RSA not emit this error"), + }; if (!mem.eql(u8, &em, &em_dec)) { - try std.testing.expectEqualSlices(u8, &em, &em_dec); return error.CertificateSignatureInvalid; } }, diff --git a/lib/std/crypto/Certificate/Bundle.zig b/lib/std/crypto/Certificate/Bundle.zig index 68b2967d10..ea2831bcd9 100644 --- a/lib/std/crypto/Certificate/Bundle.zig +++ b/lib/std/crypto/Certificate/Bundle.zig @@ -9,13 +9,19 @@ map: std.HashMapUnmanaged(der.Element.Slice, u32, MapContext, std.hash_map.default_max_load_percentage) = .{}, bytes: std.ArrayListUnmanaged(u8) = .{}, -pub fn verify(cb: Bundle, subject: Certificate.Parsed) !void { - const bytes_index = cb.find(subject.issuer()) orelse return error.IssuerNotFound; +pub const VerifyError = Certificate.Parsed.VerifyError || error{ + CertificateIssuerNotFound, +}; + +pub fn verify(cb: Bundle, subject: Certificate.Parsed) VerifyError!void { + const bytes_index = cb.find(subject.issuer()) orelse return error.CertificateIssuerNotFound; const issuer_cert: Certificate = .{ .buffer = cb.bytes.items, .index = bytes_index, }; - const issuer = try issuer_cert.parse(); + // Every certificate in the bundle is pre-parsed before adding it, ensuring + // that parsing will succeed here. + const issuer = issuer_cert.parse() catch unreachable; try subject.verify(issuer); } diff --git a/lib/std/crypto/der.zig b/lib/std/crypto/der.zig index 27c8049758..9f4065eeb7 100644 --- a/lib/std/crypto/der.zig +++ b/lib/std/crypto/der.zig @@ -111,7 +111,7 @@ pub const Element = struct { }; }; -pub const ParseElementError = error{CertificateHasFieldWithInvalidLength}; +pub const ParseElementError = error{CertificateFieldHasInvalidLength}; pub fn parseElement(bytes: []const u8, index: u32) ParseElementError!Element { var i = index; @@ -131,7 +131,7 @@ pub fn parseElement(bytes: []const u8, index: u32) ParseElementError!Element { const len_size = @truncate(u7, size_byte); if (len_size > @sizeOf(u32)) { - return error.CertificateHasFieldWithInvalidLength; + return error.CertificateFieldHasInvalidLength; } const end_i = i + len_size; diff --git a/lib/std/crypto/tls/Client.zig b/lib/std/crypto/tls/Client.zig index f46b233fb3..8e46ce5053 100644 --- a/lib/std/crypto/tls/Client.zig +++ b/lib/std/crypto/tls/Client.zig @@ -470,7 +470,7 @@ pub fn init(stream: net.Stream, ca_bundle: Certificate.Bundle, host: []const u8) handshake_state = .trust_chain_established; break :cert; } else |err| switch (err) { - error.IssuerNotFound => {}, + error.CertificateIssuerNotFound => {}, else => |e| { std.debug.print("unable to validate cert against system root CAs: {s}\n", .{ @errorName(e),