| ... | ... | @@ -17,6 +17,7 @@ pub const Algorithm = enum { |
| 17 | 17 | ecdsa_with_SHA512, |
| 18 | 18 | md2WithRSAEncryption, |
| 19 | 19 | md5WithRSAEncryption, |
| 20 | curveEd25519, |
| 20 | 21 | |
| 21 | 22 | pub const map = std.ComptimeStringMap(Algorithm, .{ |
| 22 | 23 | .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05 }, .sha1WithRSAEncryption }, |
| ... | ... | @@ -30,6 +31,7 @@ pub const Algorithm = enum { |
| 30 | 31 | .{ &[_]u8{ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x04 }, .ecdsa_with_SHA512 }, |
| 31 | 32 | .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x02 }, .md2WithRSAEncryption }, |
| 32 | 33 | .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x04 }, .md5WithRSAEncryption }, |
| 34 | .{ &[_]u8{ 0x2B, 0x65, 0x70 }, .curveEd25519 }, |
| 33 | 35 | }); |
| 34 | 36 | |
| 35 | 37 | pub fn Hash(comptime algorithm: Algorithm) type { |
| ... | ... | @@ -38,7 +40,7 @@ pub const Algorithm = enum { |
| 38 | 40 | .ecdsa_with_SHA224, .sha224WithRSAEncryption => crypto.hash.sha2.Sha224, |
| 39 | 41 | .ecdsa_with_SHA256, .sha256WithRSAEncryption => crypto.hash.sha2.Sha256, |
| 40 | 42 | .ecdsa_with_SHA384, .sha384WithRSAEncryption => crypto.hash.sha2.Sha384, |
| 41 | | .ecdsa_with_SHA512, .sha512WithRSAEncryption => crypto.hash.sha2.Sha512, |
| 43 | .ecdsa_with_SHA512, .sha512WithRSAEncryption, .curveEd25519 => crypto.hash.sha2.Sha512, |
| 42 | 44 | .md2WithRSAEncryption => @compileError("unimplemented"), |
| 43 | 45 | .md5WithRSAEncryption => crypto.hash.Md5, |
| 44 | 46 | }; |
| ... | ... | @@ -48,10 +50,12 @@ pub const Algorithm = enum { |
| 48 | 50 | pub const AlgorithmCategory = enum { |
| 49 | 51 | rsaEncryption, |
| 50 | 52 | X9_62_id_ecPublicKey, |
| 53 | curveEd25519, |
| 51 | 54 | |
| 52 | 55 | pub const map = std.ComptimeStringMap(AlgorithmCategory, .{ |
| 53 | 56 | .{ &[_]u8{ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 }, .rsaEncryption }, |
| 54 | 57 | .{ &[_]u8{ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01 }, .X9_62_id_ecPublicKey }, |
| 58 | .{ &[_]u8{ 0x2B, 0x65, 0x70 }, .curveEd25519 }, |
| 55 | 59 | }); |
| 56 | 60 | }; |
| 57 | 61 | |
| ... | ... | @@ -182,6 +186,7 @@ pub const Parsed = struct { |
| 182 | 186 | pub const PubKeyAlgo = union(AlgorithmCategory) { |
| 183 | 187 | rsaEncryption: void, |
| 184 | 188 | X9_62_id_ecPublicKey: NamedCurve, |
| 189 | curveEd25519: void, |
| 185 | 190 | }; |
| 186 | 191 | |
| 187 | 192 | pub const Validity = struct { |
| ... | ... | @@ -287,6 +292,13 @@ pub const Parsed = struct { |
| 287 | 292 | .md2WithRSAEncryption, .md5WithRSAEncryption => { |
| 288 | 293 | return error.CertificateSignatureAlgorithmUnsupported; |
| 289 | 294 | }, |
| 295 | |
| 296 | .curveEd25519 => return verifyEd25519( |
| 297 | parsed_subject.message(), |
| 298 | parsed_subject.signature(), |
| 299 | parsed_issuer.pub_key_algo, |
| 300 | parsed_issuer.pubKey(), |
| 301 | ), |
| 290 | 302 | } |
| 291 | 303 | } |
| 292 | 304 | |
| ... | ... | @@ -415,6 +427,9 @@ pub fn parse(cert: Certificate) ParseError!Parsed { |
| 415 | 427 | const named_curve = try parseNamedCurve(cert_bytes, params_elem); |
| 416 | 428 | pub_key_algo = .{ .X9_62_id_ecPublicKey = named_curve }; |
| 417 | 429 | }, |
| 430 | .curveEd25519 => { |
| 431 | pub_key_algo = .{ .curveEd25519 = {} }; |
| 432 | }, |
| 418 | 433 | } |
| 419 | 434 | const pub_key_elem = try der.Element.parse(cert_bytes, pub_key_signature_algorithm.slice.end); |
| 420 | 435 | const pub_key = try parseBitString(cert, pub_key_elem); |
| ... | ... | @@ -818,6 +833,29 @@ fn verify_ecdsa( |
| 818 | 833 | } |
| 819 | 834 | } |
| 820 | 835 | |
| 836 | fn verifyEd25519( |
| 837 | message: []const u8, |
| 838 | encoded_sig: []const u8, |
| 839 | pub_key_algo: Parsed.PubKeyAlgo, |
| 840 | encoded_pub_key: []const u8, |
| 841 | ) !void { |
| 842 | if (pub_key_algo != .curveEd25519) return error.CertificateSignatureAlgorithmMismatch; |
| 843 | const Ed25519 = crypto.sign.Ed25519; |
| 844 | if (encoded_sig.len != Ed25519.Signature.encoded_length) return error.CertificateSignatureInvalid; |
| 845 | const sig = Ed25519.Signature.fromBytes(encoded_sig[0..Ed25519.Signature.encoded_length].*); |
| 846 | if (encoded_pub_key.len != Ed25519.PublicKey.encoded_length) return error.CertificateSignatureInvalid; |
| 847 | const pub_key = Ed25519.PublicKey.fromBytes(encoded_pub_key[0..Ed25519.PublicKey.encoded_length].*) catch |err| switch (err) { |
| 848 | error.NonCanonical => return error.CertificateSignatureInvalid, |
| 849 | }; |
| 850 | sig.verify(message, pub_key) catch |err| switch (err) { |
| 851 | error.IdentityElement => return error.CertificateSignatureInvalid, |
| 852 | error.NonCanonical => return error.CertificateSignatureInvalid, |
| 853 | error.SignatureVerificationFailed => return error.CertificateSignatureInvalid, |
| 854 | error.InvalidEncoding => return error.CertificateSignatureInvalid, |
| 855 | error.WeakPublicKey => return error.CertificateSignatureInvalid, |
| 856 | }; |
| 857 | } |
| 858 | |
| 821 | 859 | const std = @import("../std.zig"); |
| 822 | 860 | const crypto = std.crypto; |
| 823 | 861 | const mem = std.mem; |