authorgravatar for 124872+jedisct1@users.noreply.github.comFrank Denis <124872+jedisct1@users.noreply.github.com> 2026-10-15 10:05:32+02:00
committergravatar for 124872+jedisct1@users.noreply.github.comFrank Denis <124872+jedisct1@users.noreply.github.com> 2026-10-15 10:05:32+02:00
logf5f4063029f1cbedb1cde0048138c9b1a56fc114
treee31e8c6665f4e3a20c58128fc750b366c22c5bff
parent4b8b9cedb301a313cc3f1720ada31fd4f6ecb493
parent6f4477ffdc658a19ad83e192e2c8ea6362032a59

Merge pull request 'crypto.ecdsa: fix edge cases in DER encoding/decoding' (#37088) from jedisct1/zig:ecdsader into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/37088

1 files changed, 23 insertions(+), 3 deletions(-)

lib/std/crypto/ecdsa.zig+23-3
......@@ -138,8 +138,10 @@ pub fn Ecdsa(comptime C: type, comptime H: type) type {
138138 /// The function returns a slice, that can be shorter than der_encoded_length_max.
139139 pub fn toDer(sig: Signature, buf: *[der_encoded_length_max]u8) []u8 {
140140 var w: std.Io.Writer = .fixed(buf);
141 const sig_r = mem.trimStart(u8, &sig.r, &.{0});
142 const sig_s = mem.trimStart(u8, &sig.s, &.{0});
141 const trimmed_r = mem.trimStart(u8, &sig.r, &.{0});
142 const trimmed_s = mem.trimStart(u8, &sig.s, &.{0});
143 const sig_r: []const u8 = if (trimmed_r.len == 0) &.{0} else trimmed_r;
144 const sig_s: []const u8 = if (trimmed_s.len == 0) &.{0} else trimmed_s;
143145 const r_len = @as(u8, @intCast(sig_r.len + (sig_r[0] >> 7)));
144146 const s_len = @as(u8, @intCast(sig_s.len + (sig_s[0] >> 7)));
145147 const seq_len = @as(u8, @intCast(2 + r_len + 2 + s_len));
......@@ -171,7 +173,8 @@ pub fn Ecdsa(comptime C: type, comptime H: type) type {
171173 }
172174 const out_slice = out[out.len - expected_len ..];
173175 reader.readSliceAll(out_slice) catch return error.InvalidEncoding;
174 if (@intFromBool(has_top_bit) != out[0] >> 7) return error.InvalidEncoding;
176 if (@intFromBool(has_top_bit) != out_slice[0] >> 7) return error.InvalidEncoding;
177 if (expected_len > 1 and out_slice[0] == 0 and out_slice[1] >> 7 == 0) return error.InvalidEncoding;
175178 }
176179
177180 /// Create a signature from a DER representation.
......@@ -534,6 +537,23 @@ test "Prehashed message operations" {
534537 try sig.verify(msg, kp.public_key);
535538}
536539
540test "DER decoding edge cases" {
541 const Scheme = EcdsaP256Sha256;
542 const negative_r = [_]u8{ 0x30, 0x06, 0x02, 0x01, 0x80, 0x02, 0x01, 0x01 };
543 const padded_r = [_]u8{ 0x30, 0x07, 0x02, 0x02, 0x00, 0x01, 0x02, 0x01, 0x01 };
544 try testing.expectError(error.InvalidEncoding, Scheme.Signature.fromDer(&negative_r));
545 try testing.expectError(error.InvalidEncoding, Scheme.Signature.fromDer(&padded_r));
546
547 const raw: [Scheme.Signature.encoded_length]u8 = @splat(0);
548 const sig = Scheme.Signature.fromBytes(raw);
549 var der: [Scheme.Signature.der_encoded_length_max]u8 = undefined;
550 try testing.expectEqualSlices(
551 u8,
552 &.{ 0x30, 0x06, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00 },
553 sig.toDer(&der),
554 );
555}
556
537557const TestVector = struct {
538558 key: []const u8,
539559 msg: []const u8,