mirror of
https://github.com/ziglang/zig.git
synced 2026-01-20 22:35:24 +00:00
tls: support ed25519 signatures
Which were claimed to be supported during the handshake but were not actually implemented.
This commit is contained in:
parent
92deebcd66
commit
5e791e8e07
@ -199,8 +199,8 @@ pub const Ed25519 = struct {
|
||||
/// Return the raw signature (r, s) in little-endian format.
|
||||
pub fn toBytes(self: Signature) [encoded_length]u8 {
|
||||
var bytes: [encoded_length]u8 = undefined;
|
||||
bytes[0 .. encoded_length / 2].* = self.r;
|
||||
bytes[encoded_length / 2 ..].* = self.s;
|
||||
bytes[0..Curve.encoded_length].* = self.r;
|
||||
bytes[Curve.encoded_length..].* = self.s;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@ -208,8 +208,8 @@ pub const Ed25519 = struct {
|
||||
/// EdDSA always assumes little-endian.
|
||||
pub fn fromBytes(bytes: [encoded_length]u8) Signature {
|
||||
return Signature{
|
||||
.r = bytes[0 .. encoded_length / 2].*,
|
||||
.s = bytes[encoded_length / 2 ..].*,
|
||||
.r = bytes[0..Curve.encoded_length].*,
|
||||
.s = bytes[Curve.encoded_length..].*,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -17,6 +17,7 @@ pub const Algorithm = enum {
|
||||
ecdsa_with_SHA512,
|
||||
md2WithRSAEncryption,
|
||||
md5WithRSAEncryption,
|
||||
curveEd25519,
|
||||
|
||||
pub const map = std.ComptimeStringMap(Algorithm, .{
|
||||
.{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05 }, .sha1WithRSAEncryption },
|
||||
@ -30,6 +31,7 @@ pub const Algorithm = enum {
|
||||
.{ &[_]u8{ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x04 }, .ecdsa_with_SHA512 },
|
||||
.{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x02 }, .md2WithRSAEncryption },
|
||||
.{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x04 }, .md5WithRSAEncryption },
|
||||
.{ &[_]u8{ 0x2B, 0x65, 0x70 }, .curveEd25519 },
|
||||
});
|
||||
|
||||
pub fn Hash(comptime algorithm: Algorithm) type {
|
||||
@ -38,7 +40,7 @@ pub const Algorithm = enum {
|
||||
.ecdsa_with_SHA224, .sha224WithRSAEncryption => crypto.hash.sha2.Sha224,
|
||||
.ecdsa_with_SHA256, .sha256WithRSAEncryption => crypto.hash.sha2.Sha256,
|
||||
.ecdsa_with_SHA384, .sha384WithRSAEncryption => crypto.hash.sha2.Sha384,
|
||||
.ecdsa_with_SHA512, .sha512WithRSAEncryption => crypto.hash.sha2.Sha512,
|
||||
.ecdsa_with_SHA512, .sha512WithRSAEncryption, .curveEd25519 => crypto.hash.sha2.Sha512,
|
||||
.md2WithRSAEncryption => @compileError("unimplemented"),
|
||||
.md5WithRSAEncryption => crypto.hash.Md5,
|
||||
};
|
||||
@ -48,10 +50,12 @@ pub const Algorithm = enum {
|
||||
pub const AlgorithmCategory = enum {
|
||||
rsaEncryption,
|
||||
X9_62_id_ecPublicKey,
|
||||
curveEd25519,
|
||||
|
||||
pub const map = std.ComptimeStringMap(AlgorithmCategory, .{
|
||||
.{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 }, .rsaEncryption },
|
||||
.{ &[_]u8{ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01 }, .X9_62_id_ecPublicKey },
|
||||
.{ &[_]u8{ 0x2B, 0x65, 0x70 }, .curveEd25519 },
|
||||
});
|
||||
};
|
||||
|
||||
@ -182,6 +186,7 @@ pub const Parsed = struct {
|
||||
pub const PubKeyAlgo = union(AlgorithmCategory) {
|
||||
rsaEncryption: void,
|
||||
X9_62_id_ecPublicKey: NamedCurve,
|
||||
curveEd25519: void,
|
||||
};
|
||||
|
||||
pub const Validity = struct {
|
||||
@ -287,6 +292,13 @@ pub const Parsed = struct {
|
||||
.md2WithRSAEncryption, .md5WithRSAEncryption => {
|
||||
return error.CertificateSignatureAlgorithmUnsupported;
|
||||
},
|
||||
|
||||
.curveEd25519 => return verifyEd25519(
|
||||
parsed_subject.message(),
|
||||
parsed_subject.signature(),
|
||||
parsed_issuer.pub_key_algo,
|
||||
parsed_issuer.pubKey(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@ -415,6 +427,9 @@ pub fn parse(cert: Certificate) ParseError!Parsed {
|
||||
const named_curve = try parseNamedCurve(cert_bytes, params_elem);
|
||||
pub_key_algo = .{ .X9_62_id_ecPublicKey = named_curve };
|
||||
},
|
||||
.curveEd25519 => {
|
||||
pub_key_algo = .{ .curveEd25519 = {} };
|
||||
},
|
||||
}
|
||||
const pub_key_elem = try der.Element.parse(cert_bytes, pub_key_signature_algorithm.slice.end);
|
||||
const pub_key = try parseBitString(cert, pub_key_elem);
|
||||
@ -818,6 +833,29 @@ fn verify_ecdsa(
|
||||
}
|
||||
}
|
||||
|
||||
fn verifyEd25519(
|
||||
message: []const u8,
|
||||
encoded_sig: []const u8,
|
||||
pub_key_algo: Parsed.PubKeyAlgo,
|
||||
encoded_pub_key: []const u8,
|
||||
) !void {
|
||||
if (pub_key_algo != .curveEd25519) return error.CertificateSignatureAlgorithmMismatch;
|
||||
const Ed25519 = crypto.sign.Ed25519;
|
||||
if (encoded_sig.len != Ed25519.Signature.encoded_length) return error.CertificateSignatureInvalid;
|
||||
const sig = Ed25519.Signature.fromBytes(encoded_sig[0..Ed25519.Signature.encoded_length].*);
|
||||
if (encoded_pub_key.len != Ed25519.PublicKey.encoded_length) return error.CertificateSignatureInvalid;
|
||||
const pub_key = Ed25519.PublicKey.fromBytes(encoded_pub_key[0..Ed25519.PublicKey.encoded_length].*) catch |err| switch (err) {
|
||||
error.NonCanonical => return error.CertificateSignatureInvalid,
|
||||
};
|
||||
sig.verify(message, pub_key) catch |err| switch (err) {
|
||||
error.IdentityElement => return error.CertificateSignatureInvalid,
|
||||
error.NonCanonical => return error.CertificateSignatureInvalid,
|
||||
error.SignatureVerificationFailed => return error.CertificateSignatureInvalid,
|
||||
error.InvalidEncoding => return error.CertificateSignatureInvalid,
|
||||
error.WeakPublicKey => return error.CertificateSignatureInvalid,
|
||||
};
|
||||
}
|
||||
|
||||
const std = @import("../std.zig");
|
||||
const crypto = std.crypto;
|
||||
const mem = std.mem;
|
||||
|
||||
@ -132,6 +132,7 @@ pub fn InitError(comptime Stream: type) type {
|
||||
InvalidSignature,
|
||||
NotSquare,
|
||||
NonCanonical,
|
||||
WeakPublicKey,
|
||||
};
|
||||
}
|
||||
|
||||
@ -166,13 +167,9 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
|
||||
}) ++ tls.extension(.signature_algorithms, enum_array(tls.SignatureScheme, &.{
|
||||
.ecdsa_secp256r1_sha256,
|
||||
.ecdsa_secp384r1_sha384,
|
||||
.ecdsa_secp521r1_sha512,
|
||||
.rsa_pss_rsae_sha256,
|
||||
.rsa_pss_rsae_sha384,
|
||||
.rsa_pss_rsae_sha512,
|
||||
.rsa_pkcs1_sha256,
|
||||
.rsa_pkcs1_sha384,
|
||||
.rsa_pkcs1_sha512,
|
||||
.ed25519,
|
||||
})) ++ tls.extension(.supported_groups, enum_array(tls.NamedGroup, &.{
|
||||
.x25519_kyber768d00,
|
||||
@ -618,6 +615,15 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
|
||||
},
|
||||
}
|
||||
},
|
||||
inline .ed25519 => |comptime_scheme| {
|
||||
if (main_cert_pub_key_algo != .curveEd25519) return error.TlsBadSignatureScheme;
|
||||
const Eddsa = SchemeEddsa(comptime_scheme);
|
||||
if (encoded_sig.len != Eddsa.Signature.encoded_length) return error.InvalidEncoding;
|
||||
const sig = Eddsa.Signature.fromBytes(encoded_sig[0..Eddsa.Signature.encoded_length].*);
|
||||
if (main_cert_pub_key.len != Eddsa.PublicKey.encoded_length) return error.InvalidEncoding;
|
||||
const key = try Eddsa.PublicKey.fromBytes(main_cert_pub_key[0..Eddsa.PublicKey.encoded_length].*);
|
||||
try sig.verify(verify_bytes, key);
|
||||
},
|
||||
else => {
|
||||
return error.TlsBadSignatureScheme;
|
||||
},
|
||||
@ -1297,7 +1303,6 @@ fn SchemeEcdsa(comptime scheme: tls.SignatureScheme) type {
|
||||
return switch (scheme) {
|
||||
.ecdsa_secp256r1_sha256 => crypto.sign.ecdsa.EcdsaP256Sha256,
|
||||
.ecdsa_secp384r1_sha384 => crypto.sign.ecdsa.EcdsaP384Sha384,
|
||||
.ecdsa_secp521r1_sha512 => crypto.sign.ecdsa.EcdsaP512Sha512,
|
||||
else => @compileError("bad scheme"),
|
||||
};
|
||||
}
|
||||
@ -1311,6 +1316,13 @@ fn SchemeHash(comptime scheme: tls.SignatureScheme) type {
|
||||
};
|
||||
}
|
||||
|
||||
fn SchemeEddsa(comptime scheme: tls.SignatureScheme) type {
|
||||
return switch (scheme) {
|
||||
.ed25519 => crypto.sign.Ed25519,
|
||||
else => @compileError("bad scheme"),
|
||||
};
|
||||
}
|
||||
|
||||
/// Abstraction for sending multiple byte buffers to a slice of iovecs.
|
||||
const VecPut = struct {
|
||||
iovecs: []const std.os.iovec,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user