authorgravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2026-07-16 02:01:26 -07:00
committergravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2026-07-16 02:01:26 -07:00
logbc0b3669c619c1093e903ce41300df3e3571a6e1
tree8622bf3c332b2b7d6d0dbb80ed43e2d13ef8f5ea
parent1d3fefe41c151f8e7f1bb2f33dde2861cc809ca6
signaturebadge-check Signed by SSH key SHA256:4hHJbtBRU58AYXwjL7fkz2fnQHdiye8x1QpTCQ0sHNw

Signature: ssh: support ecdsa-sha2-nistp256


1 files changed, 27 insertions(+), 5 deletions(-)

git.zig+27-5
......@@ -2391,6 +2391,7 @@ pub const Signature = union(enum) {
23912391 // https://pkg.go.dev/golang.org/x/crypto/ssh#pkg-constants
23922392 // https://datatracker.ietf.org/doc/html/rfc9580#section-4
23932393 // https://datatracker.ietf.org/doc/html/rfc9580#signature-packet
2394 // https://datatracker.ietf.org/doc/html/rfc5656
23942395 pub fn fromReader(kind: NonVoidUnionFieldEnum(Signature), allocator: std.mem.Allocator, b64r: anytype, message: []const u8) !Signature {
23952396 if (kind == .pgp) {
23962397 var signed_data: nio.AllocatingWriter = .init(allocator);
......@@ -2552,11 +2553,10 @@ pub const Signature = union(enum) {
25522553
25532554 var valid: ?bool = null;
25542555 var sigfixed: nio.FixedBufferStream([]const u8) = .init(signature);
2555 const sigformat = try sigfixed.readAlloc(allocator, try sigfixed.readInt(u32, .big));
2556 defer allocator.free(sigformat);
2556 const sigformat = try sigfixed.readSlice(try sigfixed.readInt(u32, .big));
25572557 var pkfixed: nio.FixedBufferStream([]const u8) = .init(publickey);
2558 const pkformat = try pkfixed.readAlloc(allocator, try pkfixed.readInt(u32, .big));
2559 defer allocator.free(pkformat);
2558 const pkformat = try pkfixed.readSlice(try pkfixed.readInt(u32, .big));
2559 _ = pkformat;
25602560
25612561 if (std.mem.eql(u8, sigformat, "ssh-rsa")) {
25622562 // intentionally skipped
......@@ -2573,8 +2573,30 @@ pub const Signature = union(enum) {
25732573 const sig = ed.Signature.fromBytes(sig_bytes);
25742574 valid = if (sig.verifyStrict(signed_data.items, pk)) true else |_| false;
25752575 }
2576 if (std.mem.eql(u8, sigformat, "ecdsa-sha2-nistp256")) blk: {
2577 const C = std.crypto.ecc.P256;
2578 const H = std.crypto.hash.sha2.Sha256;
2579 const ns = std.crypto.sign.ecdsa.Ecdsa(C, H);
2580 const ident_len = pkfixed.readInt(u32, .big) catch break :blk;
2581 if (ident_len != "nistp256".len) break :blk;
2582 if (!(pkfixed.readExpected("nistp256") catch break :blk)) break :blk;
2583 const q_len = pkfixed.readInt(u32, .big) catch break :blk;
2584 const q = pkfixed.readSlice(q_len) catch break :blk;
2585 const pk = ns.PublicKey.fromSec1(q) catch break :blk;
2586 const sigblob_len = sigfixed.readInt(u32, .big) catch break :blk;
2587 _ = sigblob_len;
2588 const r_len = sigfixed.readInt(u32, .big) catch break :blk;
2589 var r = sigfixed.readSlice(r_len) catch break :blk;
2590 if (r[0] == 0) r = r[1..];
2591 if (r.len != C.scalar.encoded_length) break :blk;
2592 const s_len = sigfixed.readInt(u32, .big) catch break :blk;
2593 var s = sigfixed.readSlice(s_len) catch break :blk;
2594 if (s[0] == 0) s = s[1..];
2595 if (s.len != C.scalar.encoded_length) break :blk;
2596 const sig = ns.Signature.fromBytes((r[0..C.scalar.encoded_length] ++ s[0..C.scalar.encoded_length]).*);
2597 valid = if (sig.verify(signed_data.items, pk)) true else |_| false;
2598 }
25762599 // ssh-dss (dsa)
2577 // ecdsa-sha2-nistp256
25782600 // sk-ecdsa-sha2-nistp256@openssh.com
25792601 // ecdsa-sha2-nistp384
25802602 // ecdsa-sha2-nistp521