lib/quic/src/tls/identity.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

 1 const std = @import("std");
 2 
 3 const Ed25519 = std.crypto.sign.Ed25519;
 4 
 5 pub const PublicKey = [Ed25519.PublicKey.encoded_length]u8;
 6 pub const spki_length: usize = 44;
 7 
 8 const spki_prefix = [_]u8{
 9     0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00,
10 };
11 
12 pub const Identity = struct {
13     key_pair: Ed25519.KeyPair,
14 
15     pub fn fromSeed(seed: [Ed25519.KeyPair.seed_length]u8) error{InvalidSeed}!Identity {
16         const key_pair = Ed25519.KeyPair.generateDeterministic(seed) catch {
17             return error.InvalidSeed;
18         };
19         return .{ .key_pair = key_pair };
20     }
21 
22     pub fn public(self: Identity) PublicKey {
23         return self.key_pair.public_key.toBytes();
24     }
25 
26     pub fn sign(self: Identity, content: []const u8) error{SigningFailed}![64]u8 {
27         const signature = self.key_pair.sign(content, null) catch {
28             return error.SigningFailed;
29         };
30         return signature.toBytes();
31     }
32 };
33 
34 pub fn verify(public_key: PublicKey, content: []const u8, signature: [64]u8) !void {
35     const parsed_key = try Ed25519.PublicKey.fromBytes(public_key);
36     const parsed_signature = Ed25519.Signature.fromBytes(signature);
37     try parsed_signature.verify(content, parsed_key);
38 }
39 
40 pub fn encodeSubjectPublicKeyInfo(public_key: PublicKey) [spki_length]u8 {
41     var encoded: [spki_length]u8 = undefined;
42     encoded[0..spki_prefix.len].* = spki_prefix;
43     encoded[spki_prefix.len..].* = public_key;
44     return encoded;
45 }
46 
47 pub fn decodeSubjectPublicKeyInfo(
48     encoded: []const u8,
49 ) error{ InvalidLength, InvalidPrefix }!PublicKey {
50     if (encoded.len != spki_length) return error.InvalidLength;
51     if (!std.mem.eql(u8, encoded[0..spki_prefix.len], &spki_prefix)) {
52         return error.InvalidPrefix;
53     }
54     return encoded[spki_prefix.len..][0..@sizeOf(PublicKey)].*;
55 }
56 
57 test "RFC 8410 section 4 and RFC 7250 section 3 Ed25519 SPKI round trip" {
58     const public_key: PublicKey = @splat(0xa5);
59     const encoded = encodeSubjectPublicKeyInfo(public_key);
60     try std.testing.expectEqualSlices(u8, &spki_prefix, encoded[0..spki_prefix.len]);
61     try std.testing.expectEqual(public_key, try decodeSubjectPublicKeyInfo(&encoded));
62 }
63 
64 test "RFC 8410 section 4 rejects short and wrong-prefix Ed25519 SPKI" {
65     const public_key: PublicKey = @splat(0x5a);
66     var encoded = encodeSubjectPublicKeyInfo(public_key);
67     try std.testing.expectError(error.InvalidLength, decodeSubjectPublicKeyInfo(encoded[0..43]));
68     encoded[0] ^= 1;
69     try std.testing.expectError(error.InvalidPrefix, decodeSubjectPublicKeyInfo(&encoded));
70 }