Skip to content

Commit 99c9087

Browse files
committed
std.crypto.tls.Certificate: explicit error set for verify
1 parent 05257ac commit 99c9087

File tree

4 files changed

+38
-10
lines changed

4 files changed

+38
-10
lines changed

lib/std/crypto/Certificate.zig

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,23 @@ pub const Parsed = struct {
116116
return p.slice(p.message_slice);
117117
}
118118

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+
119133
/// This function checks the time validity for the subject only. Checking
120134
/// 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 {
122136
// Check that the subject's issuer name matches the issuer's
123137
// subject name.
124138
if (!mem.eql(u8, parsed_subject.issuer(), parsed_issuer.subject())) {
@@ -452,11 +466,19 @@ fn verifyRsa(
452466
hash_der ++
453467
msg_hashed;
454468

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+
};
457480

458481
if (!mem.eql(u8, &em, &em_dec)) {
459-
try std.testing.expectEqualSlices(u8, &em, &em_dec);
460482
return error.CertificateSignatureInvalid;
461483
}
462484
},

lib/std/crypto/Certificate/Bundle.zig

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,19 @@
99
map: std.HashMapUnmanaged(der.Element.Slice, u32, MapContext, std.hash_map.default_max_load_percentage) = .{},
1010
bytes: std.ArrayListUnmanaged(u8) = .{},
1111

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;
1418
const issuer_cert: Certificate = .{
1519
.buffer = cb.bytes.items,
1620
.index = bytes_index,
1721
};
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;
1925
try subject.verify(issuer);
2026
}
2127

lib/std/crypto/der.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ pub const Element = struct {
111111
};
112112
};
113113

114-
pub const ParseElementError = error{CertificateHasFieldWithInvalidLength};
114+
pub const ParseElementError = error{CertificateFieldHasInvalidLength};
115115

116116
pub fn parseElement(bytes: []const u8, index: u32) ParseElementError!Element {
117117
var i = index;
@@ -131,7 +131,7 @@ pub fn parseElement(bytes: []const u8, index: u32) ParseElementError!Element {
131131

132132
const len_size = @truncate(u7, size_byte);
133133
if (len_size > @sizeOf(u32)) {
134-
return error.CertificateHasFieldWithInvalidLength;
134+
return error.CertificateFieldHasInvalidLength;
135135
}
136136

137137
const end_i = i + len_size;

lib/std/crypto/tls/Client.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,7 @@ pub fn init(stream: net.Stream, ca_bundle: Certificate.Bundle, host: []const u8)
470470
handshake_state = .trust_chain_established;
471471
break :cert;
472472
} else |err| switch (err) {
473-
error.IssuerNotFound => {},
473+
error.CertificateIssuerNotFound => {},
474474
else => |e| {
475475
std.debug.print("unable to validate cert against system root CAs: {s}\n", .{
476476
@errorName(e),

0 commit comments

Comments
 (0)