Igor Anić c41b9d7508
ECDSA signature der encoding should produce smallest number of octets (#25177)
I noticed this by stress testing my tls server implementation. From time to time curl (and other tools: ab, vegeta) will report invalid signature. I trace the problem to the way how std lib is encoding raw signature into der format. Using raw signature I got in some cases different encoding using std and openssl. Std is not producing minimal der when signature `r` or `s` integers has leading zero(es).

Here is an example to illustrate difference. Notice leading 00 in `s`
integer which is removed in openssl encoding but not in std encoding.

```Zig
const std = @import("std");

test "ecdsa signature to der" {
    // raw signature r and s bytes
    const raw = hexToBytes(
        \\ 49  63  0c  94  95  2e  ff  4b  02  bf  35  c4  97  9e  a7  24
        \\ 20  dc  94  de  aa  1b  17  ff  e1  49  25  3e  34  ef  e8  d0
        \\ c4  43  aa  7b  a9  f3  9c  b9  f8  72  7d  d7  0c  9a  13  1e
        \\
        \\ 00  56  85  43  d3  d4  05  62  a1  1d  d8  a1  45  44  b5  dd
        \\ 62  9f  d1  e0  ab  f1  cd  4a  85  d0  1f  5d  11  d9  f8  89
        \\ 89  d4  59  0c  b0  6e  ea  3c  19  6a  f7  0b  1a  4a  ce  f1
    );
    // encoded by openssl
    const expected = hexToBytes(
        \\ 30  63  02  30
        \\ 49  63  0c  94  95  2e  ff  4b  02  bf  35  c4  97  9e  a7  24
        \\ 20  dc  94  de  aa  1b  17  ff  e1  49  25  3e  34  ef  e8  d0
        \\ c4  43  aa  7b  a9  f3  9c  b9  f8  72  7d  d7  0c  9a  13  1e
        \\
        \\ 02  2f
        \\ 56  85  43  d3  d4  05  62  a1  1d  d8  a1  45  44  b5  dd
        \\ 62  9f  d1  e0  ab  f1  cd  4a  85  d0  1f  5d  11  d9  f8  89
        \\ 89  d4  59  0c  b0  6e  ea  3c  19  6a  f7  0b  1a  4a  ce  f1
    );
    // encoded by std
    const actual = hexToBytes(
        \\ 30  64  02  30
        \\ 49  63  0c  94  95  2e  ff  4b  02  bf  35  c4  97  9e  a7  24
        \\ 20  dc  94  de  aa  1b  17  ff  e1  49  25  3e  34  ef  e8  d0
        \\ c4  43  aa  7b  a9  f3  9c  b9  f8  72  7d  d7  0c  9a  13  1e
        \\
        \\ 02  30
        \\ 00  56  85  43  d3  d4  05  62  a1  1d  d8  a1  45  44  b5  dd
        \\ 62  9f  d1  e0  ab  f1  cd  4a  85  d0  1f  5d  11  d9  f8  89
        \\ 89  d4  59  0c  b0  6e  ea  3c  19  6a  f7  0b  1a  4a  ce  f1
    );
    _ = actual;

    const Ecdsa = std.crypto.sign.ecdsa.EcdsaP384Sha384;
    const sig = Ecdsa.Signature.fromBytes(raw);
    var buf: [Ecdsa.Signature.der_encoded_length_max]u8 = undefined;
    const encoded = sig.toDer(&buf);

    try std.testing.expectEqualSlices(u8, &expected, encoded);
}

pub fn hexToBytes(comptime hex: []const u8) [removeNonHex(hex).len / 2]u8 {
    @setEvalBranchQuota(1000 * 100);
    const hex2 = comptime removeNonHex(hex);
    comptime var res: [hex2.len / 2]u8 = undefined;
    _ = comptime std.fmt.hexToBytes(&res, hex2) catch unreachable;
    return res;
}
fn removeNonHex(comptime hex: []const u8) []const u8 {
    @setEvalBranchQuota(1000 * 100);
    var res: [hex.len]u8 = undefined;
    var i: usize = 0;
    for (hex) |c| {
        if (std.ascii.isHex(c)) {
            res[i] = c;
            i += 1;
        }
    }
    return res[0..i];
}
```

Trimming leading zeroes from signature integers fixes encoding.
2025-09-08 22:53:03 +02:00
..
2025-09-03 21:45:03 -07:00
2025-09-03 01:48:46 -07:00
2024-12-19 17:10:03 -05:00
2025-07-07 22:43:51 -07:00
2025-08-29 17:14:26 -07:00
2025-09-03 21:46:01 -07:00
2025-07-14 00:16:49 -07:00
2025-09-03 21:45:03 -07:00
2025-07-07 22:43:51 -07:00
2025-08-29 17:14:26 -07:00
2025-07-07 22:43:51 -07:00
2025-08-30 00:48:50 -07:00
2025-08-31 12:49:18 -07:00
2025-08-28 18:30:57 -07:00
2025-08-29 17:14:26 -07:00
2025-08-29 17:14:26 -07:00
2025-09-03 21:45:03 -07:00
2025-08-29 17:14:26 -07:00
2025-07-14 00:14:21 -07:00
2024-08-22 08:44:08 +02:00
2025-09-04 01:16:23 +02:00
2025-07-31 22:10:11 -07:00
2025-08-29 17:14:26 -07:00
2025-08-29 17:14:26 -07:00
2025-08-29 17:14:26 -07:00
2025-08-29 17:14:26 -07:00
2025-07-07 22:43:51 -07:00
2025-08-29 17:14:26 -07:00
2025-08-25 16:15:17 +02:00
2025-08-29 17:14:26 -07:00
2025-08-29 17:14:26 -07:00
2025-08-29 17:14:26 -07:00
2025-07-22 09:41:44 -07:00
2025-08-29 17:14:26 -07:00
2025-08-28 18:30:57 -07:00
2025-08-31 12:49:18 -07:00
2025-08-31 12:49:18 -07:00
2025-07-16 10:27:39 -07:00
2025-08-31 12:49:18 -07:00
2025-08-29 17:14:26 -07:00