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 }