secret_tree_test.go raw
1 package mls
2
3 import (
4 "bytes"
5 "fmt"
6 "testing"
7 )
8
9 type secretTreeTest struct {
10 CipherSuite CipherSuite `json:"cipher_suite"`
11
12 SenderData struct {
13 SenderDataSecret testBytes `json:"sender_data_secret"`
14 Ciphertext testBytes `json:"ciphertext"`
15 Key testBytes `json:"key"`
16 Nonce testBytes `json:"nonce"`
17 } `json:"sender_data"`
18
19 EncryptionSecret testBytes `json:"encryption_secret"`
20 Leaves [][]secretTreeTestGen `json:"leaves"`
21 }
22
23 type secretTreeTestGen struct {
24 Generation uint32 `json:"generation"`
25 HandshakeKey testBytes `json:"handshake_key"`
26 HandshakeNonce testBytes `json:"handshake_nonce"`
27 ApplicationKey testBytes `json:"application_key"`
28 ApplicationNonce testBytes `json:"application_nonce"`
29 }
30
31 func testSecretTree(t *testing.T, tc *secretTreeTest) {
32 senderDataSecret := []byte(tc.SenderData.SenderDataSecret)
33 ciphertext := []byte(tc.SenderData.Ciphertext)
34
35 key, err := expandSenderDataKey(tc.CipherSuite, senderDataSecret, ciphertext)
36 if err != nil {
37 t.Errorf("expandSenderDataKey() = %v", err)
38 } else if !bytes.Equal(key, []byte(tc.SenderData.Key)) {
39 t.Errorf("expandSenderDataKey() = %v, want %v", key, tc.SenderData.Key)
40 }
41
42 nonce, err := expandSenderDataNonce(tc.CipherSuite, senderDataSecret, ciphertext)
43 if err != nil {
44 t.Errorf("expandSenderDataNonce() = %v", err)
45 } else if !bytes.Equal(nonce, []byte(tc.SenderData.Nonce)) {
46 t.Errorf("expandSenderDataNonce() = %v, want %v", nonce, tc.SenderData.Nonce)
47 }
48
49 tree, err := deriveSecretTree(tc.CipherSuite, numLeaves(len(tc.Leaves)), []byte(tc.EncryptionSecret))
50 if err != nil {
51 t.Fatalf("generateSecretTree() = %v", err)
52 }
53
54 for i, gens := range tc.Leaves {
55 li := leafIndex(i)
56 t.Run(fmt.Sprintf("leaf-%v/handshake", li), func(t *testing.T) {
57 testRatchetSecret(t, tc.CipherSuite, tree, li, ratchetLabelHandshake, gens)
58 })
59 t.Run(fmt.Sprintf("leaf-%v/application", li), func(t *testing.T) {
60 testRatchetSecret(t, tc.CipherSuite, tree, li, ratchetLabelApplication, gens)
61 })
62 }
63 }
64
65 func testRatchetSecret(t *testing.T, cs CipherSuite, tree secretTree, li leafIndex, label ratchetLabel, gens []secretTreeTestGen) {
66 secret, err := tree.deriveRatchetRoot(cs, li.nodeIndex(), label)
67 if err != nil {
68 t.Fatalf("deriveRatchetRoot() = %v", err)
69 }
70
71 for _, gen := range gens {
72 if gen.Generation < secret.generation {
73 panic("unreachable")
74 }
75
76 for secret.generation != gen.Generation {
77 secret, err = secret.deriveNext(cs)
78 if err != nil {
79 t.Fatalf("deriveNext() = %v", err)
80 }
81 }
82
83 var wantKey, wantNonce testBytes
84 switch string(label) {
85 case string(ratchetLabelHandshake):
86 wantKey, wantNonce = gen.HandshakeKey, gen.HandshakeNonce
87 case string(ratchetLabelApplication):
88 wantKey, wantNonce = gen.ApplicationKey, gen.ApplicationNonce
89 default:
90 panic("unreachable")
91 }
92
93 key, err := secret.deriveKey(cs)
94 if err != nil {
95 t.Fatalf("deriveKey() = %v", err)
96 } else if !bytes.Equal(key, []byte(wantKey)) {
97 t.Errorf("deriveKey() = %v, want %v", key, wantKey)
98 }
99
100 nonce, err := secret.deriveNonce(cs)
101 if err != nil {
102 t.Fatalf("deriveNonce() = %v", err)
103 } else if !bytes.Equal(nonce, []byte(wantNonce)) {
104 t.Errorf("deriveNonce() = %v, want %v", nonce, wantNonce)
105 }
106 }
107 }
108
109 func TestSecretTree(t *testing.T) {
110 var tests []secretTreeTest
111 loadTestVector(t, "testdata/secret-tree.json", &tests)
112
113 for i, tc := range tests {
114 t.Run(fmt.Sprintf("[%v]", i), func(t *testing.T) {
115 testSecretTree(t, &tc)
116 })
117 }
118 }
119