• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 21851334357

10 Feb 2026 01:47AM UTC coverage: 90.073% (+0.004%) from 90.069%
21851334357

push

github

web-flow
Merge pull request #5296 from randombit/jack/tls-header-patrol

Various changes to reduce header dependencies in TLS

102230 of 113497 relevant lines covered (90.07%)

11359047.13 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.5
/src/tests/test_tls_cipher_state.cpp
1
/*
2
* (C) 2021 Jack Lloyd
3
* (C) 2021 Hannes Rantzsch, René Meusel - neXenio
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7

8
#include "tests.h"
9

10
#if defined(BOTAN_HAS_TLS_13)
11

12
   #include <botan/hex.h>
13
   #include <botan/secmem.h>
14
   #include <botan/tls_ciphersuite.h>
15

16
   #include <botan/internal/tls_channel_impl_13.h>
17
   #include <botan/internal/tls_cipher_state.h>
18
   #include <map>
19

20
namespace Botan_Tests {
21

22
namespace {
23

24
using namespace Botan;
25
using namespace Botan::TLS;
26

27
class Journaling_Secret_Logger : public Secret_Logger {
2✔
28
   public:
29
      void maybe_log_secret(std::string_view label, std::span<const uint8_t> secret) const override {
26✔
30
         secrets[std::string(label)] = std::vector<uint8_t>(secret.begin(), secret.end());
52✔
31
      }
26✔
32

33
   public:
34
      mutable std::map<std::string, std::vector<uint8_t>> secrets;  // NOLINT(*-non-private-member-variable*)
35
};
36

37
decltype(auto) make_CHECK_both(Cipher_State* cs_client,
2✔
38
                               Journaling_Secret_Logger* sl_client,
39
                               Cipher_State* cs_server,
40
                               Journaling_Secret_Logger* sl_server) {
41
   using namespace std::placeholders;
2✔
42
   return [=](const std::string& name, auto lambda) -> std::vector<Test::Result> {
16✔
43
      // NOLINTBEGIN(*-avoid-bind)
44
      return {CHECK(std::string(name + " (client)").c_str(),
×
45
                    std::bind(lambda, cs_client, sl_client, Connection_Side::Client, _1)),
14✔
46
              CHECK(std::string(name + " (server)").c_str(),
×
47
                    std::bind(lambda, cs_server, sl_server, Connection_Side::Server, _1))};
56✔
48
      // NOLINTEND(*-avoid-bind)
49
   };
30✔
50
}
51

52
class RFC8448_TestData {
53
   private:
54
      const std::string name;
55
      const Connection_Side emitter;
56
      const std::vector<uint8_t> record_header;
57
      const secure_vector<uint8_t> encrypted_fragment;
58
      const secure_vector<uint8_t> plaintext_fragment;
59

60
   public:
61
      RFC8448_TestData(std::string n,
9✔
62
                       Connection_Side em,
63
                       std::vector<uint8_t> rh,
64
                       secure_vector<uint8_t> ef,
65
                       secure_vector<uint8_t> pf) :
9✔
66
            name(std::move(n)),
9✔
67
            emitter(em),
9✔
68
            record_header(std::move(rh)),
9✔
69
            encrypted_fragment(std::move(ef)),
9✔
70
            plaintext_fragment(std::move(pf)) {}
9✔
71

72
      void encrypt(Test::Result& result, Cipher_State* cs) const {
9✔
73
         auto plaintext_fragment_copy = plaintext_fragment;
9✔
74
         result.test_no_throw("encryption is successful for " + name,
18✔
75
                              [&] { cs->encrypt_record_fragment(record_header, plaintext_fragment_copy); });
18✔
76

77
         result.test_eq("encrypted payload for " + name, plaintext_fragment_copy, encrypted_fragment);
18✔
78
      }
9✔
79

80
      void decrypt(Test::Result& result, Cipher_State* cs) const {
9✔
81
         auto encrypted_fragment_copy = encrypted_fragment;
9✔
82
         result.test_no_throw("decryption is successful for " + name,
18✔
83
                              [&] { cs->decrypt_record_fragment(record_header, encrypted_fragment_copy); });
18✔
84

85
         result.test_eq("plaintext for " + name, encrypted_fragment_copy, plaintext_fragment);
18✔
86
      }
9✔
87

88
      void xxcrypt(Test::Result& result, Cipher_State* cs, Connection_Side side) const {
18✔
89
         if(emitter == side) {
18✔
90
            encrypt(result, cs);
9✔
91
         } else {
92
            decrypt(result, cs);
9✔
93
         }
94
      }
18✔
95
};
96

97
std::vector<Test::Result> test_secret_derivation_rfc8448_rtt1() {
1✔
98
   // shared secret
99
   const auto shared_secret = Botan::hex_decode_locked(
1✔
100
      "8b d4 05 4f b5 5b 9d 63 fd fb ac f9 f0 4b 9f 0d"
101
      "35 e6 d6 3f 53 75 63 ef d4 62 72 90 0f 89 49 2d");
1✔
102

103
   const auto expected_psk = Botan::hex_decode_locked(
1✔
104
      "4e cd 0e b6 ec 3b 4d 87 f5 d6 02 8f 92 2c a4 c5"
105
      "85 1a 27 7f d4 13 11 c9 e6 2d 2c 94 92 e1 c4 f3");
1✔
106

107
   // this is not part of RFC 8448
108
   const std::string export_label = "export_test_label";
1✔
109
   const std::string export_context = "rfc8448_rtt1";
1✔
110
   const auto expected_key_export = Botan::hex_decode_locked("f2 00 58 a6 5c e0 43 0a 19 79 44 c8 12 43 1c 2d");
1✔
111

112
   // transcript hash from client hello and server hello
113
   const auto th_server_hello = Botan::hex_decode(
1✔
114
      "86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 ed"
115
      "d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8");
1✔
116

117
   // transcript hash from client hello up to (excluding) server finished
118
   const auto th_pre_server_finished = Botan::hex_decode(
1✔
119
      "ed b7 72 5f a7 a3 47 3b 03 1e c8 ef 65 a2 48 54"
120
      "93 90 01 38 a2 b9 12 91 40 7d 79 51 a0 61 10 ed");
1✔
121

122
   // transcript hash from client hello up to (including) server finished
123
   const auto th_server_finished = Botan::hex_decode(
1✔
124
      "96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a"
125
      "00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13");
1✔
126

127
   // transcript hash from client hello up to (including) client finished
128
   const auto th_client_finished = Botan::hex_decode(
1✔
129
      "20 91 45 a9 6e e8 e2 a1 22 ff 81 00 47 cc 95 26"
130
      "84 65 8d 60 49 e8 64 29 42 6d b8 7c 54 ad 14 3d");
1✔
131

132
   // handshake traffic secret for the client
133
   const auto client_handshake_traffic_secret = Botan::hex_decode(
1✔
134
      "b3 ed db 12 6e 06 7f 35 a7 80 b3 ab f4 5e 2d 8f"
135
      "3b 1a 95 07 38 f5 2e 96 00 74 6a 0e 27 a5 5a 21");
1✔
136

137
   // handshake traffic secret for the server
138
   const auto server_handshake_traffic_secret = Botan::hex_decode(
1✔
139
      "b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d 37 b4"
140
      "e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38");
1✔
141

142
   // application traffic secret (0) for the client
143
   const auto client_traffic_secret = Botan::hex_decode(
1✔
144
      "9e 40 64 6c e7 9a 7f 9d c0 5a f8 88 9b ce 65 52"
145
      "87 5a fa 0b 06 df 00 87 f7 92 eb b7 c1 75 04 a5");
1✔
146

147
   // application traffic secret (0) for the server
148
   const auto server_traffic_secret = Botan::hex_decode(
1✔
149
      "a1 1a f9 f0 55 31 f8 56 ad 47 11 6b 45 a9 50 32"
150
      "82 04 b4 f4 4b fb 6b 3a 4b 4f 1f 3f cb 63 16 43");
1✔
151

152
   // application traffic secret (1) for the client (not in RFC 8448)
153
   const auto updated_client_traffic_secret = Botan::hex_decode(
1✔
154
      "fc df cc 72 72 5a ae e4 8b f6 4e 4f d8 b7 49 cd"
155
      "bd ba b3 9d 90 da 0b 26 e2 24 5c a6 ea 16 72 07");
1✔
156

157
   // application traffic secret (1) for the server (not in RFC 8448)
158
   const auto updated_server_traffic_secret = Botan::hex_decode(
1✔
159
      "51 92 1b 8a a3 00 19 76 eb 40 1d 0a 43 19 a8 51"
160
      "64 16 a6 c5 60 01 a3 57 e5 d1 62 03 1e 84 f9 16");
1✔
161

162
   // encrypted with server_handshake_traffic_secret
163
   const auto encrypted_extensions =
1✔
164
      RFC8448_TestData("encrypted_extensions",
165
                       Connection_Side::Server,
166
                       Botan::hex_decode("17 03 03 02 a2"),
2✔
167
                       Botan::hex_decode_locked("d1 ff 33 4a 56 f5 bf"
2✔
168
                                                "f6 59 4a 07 cc 87 b5 80 23 3f 50 0f 45 e4 89 e7 f3 3a f3 5e df"
169
                                                "78 69 fc f4 0a a4 0a a2 b8 ea 73 f8 48 a7 ca 07 61 2e f9 f9 45"
170
                                                "cb 96 0b 40 68 90 51 23 ea 78 b1 11 b4 29 ba 91 91 cd 05 d2 a3"
171
                                                "89 28 0f 52 61 34 aa dc 7f c7 8c 4b 72 9d f8 28 b5 ec f7 b1 3b"
172
                                                "d9 ae fb 0e 57 f2 71 58 5b 8e a9 bb 35 5c 7c 79 02 07 16 cf b9"
173
                                                "b1 18 3e f3 ab 20 e3 7d 57 a6 b9 d7 47 76 09 ae e6 e1 22 a4 cf"
174
                                                "51 42 73 25 25 0c 7d 0e 50 92 89 44 4c 9b 3a 64 8f 1d 71 03 5d"
175
                                                "2e d6 5b 0e 3c dd 0c ba e8 bf 2d 0b 22 78 12 cb b3 60 98 72 55"
176
                                                "cc 74 41 10 c4 53 ba a4 fc d6 10 92 8d 80 98 10 e4 b7 ed 1a 8f"
177
                                                "d9 91 f0 6a a6 24 82 04 79 7e 36 a6 a7 3b 70 a2 55 9c 09 ea d6"
178
                                                "86 94 5b a2 46 ab 66 e5 ed d8 04 4b 4c 6d e3 fc f2 a8 94 41 ac"
179
                                                "66 27 2f d8 fb 33 0e f8 19 05 79 b3 68 45 96 c9 60 bd 59 6e ea"
180
                                                "52 0a 56 a8 d6 50 f5 63 aa d2 74 09 96 0d ca 63 d3 e6 88 61 1e"
181
                                                "a5 e2 2f 44 15 cf 95 38 d5 1a 20 0c 27 03 42 72 96 8a 26 4e d6"
182
                                                "54 0c 84 83 8d 89 f7 2c 24 46 1a ad 6d 26 f5 9e ca ba 9a cb bb"
183
                                                "31 7b 66 d9 02 f4 f2 92 a3 6a c1 b6 39 c6 37 ce 34 31 17 b6 59"
184
                                                "62 22 45 31 7b 49 ee da 0c 62 58 f1 00 d7 d9 61 ff b1 38 64 7e"
185
                                                "92 ea 33 0f ae ea 6d fa 31 c7 a8 4d c3 bd 7e 1b 7a 6c 71 78 af"
186
                                                "36 87 90 18 e3 f2 52 10 7f 24 3d 24 3d c7 33 9d 56 84 c8 b0 37"
187
                                                "8b f3 02 44 da 8c 87 c8 43 f5 e5 6e b4 c5 e8 28 0a 2b 48 05 2c"
188
                                                "f9 3b 16 49 9a 66 db 7c ca 71 e4 59 94 26 f7 d4 61 e6 6f 99 88"
189
                                                "2b d8 9f c5 08 00 be cc a6 2d 6c 74 11 6d bd 29 72 fd a1 fa 80"
190
                                                "f8 5d f8 81 ed be 5a 37 66 89 36 b3 35 58 3b 59 91 86 dc 5c 69"
191
                                                "18 a3 96 fa 48 a1 81 d6 b6 fa 4f 9d 62 d5 13 af bb 99 2f 2b 99"
192
                                                "2f 67 f8 af e6 7f 76 91 3f a3 88 cb 56 30 c8 ca 01 e0 c6 5d 11"
193
                                                "c6 6a 1e 2a c4 c8 59 77 b7 c7 a6 99 9b bf 10 dc 35 ae 69 f5 51"
194
                                                "56 14 63 6c 0b 9b 68 c1 9e d2 e3 1c 0b 3b 66 76 30 38 eb ba 42"
195
                                                "f3 b3 8e dc 03 99 f3 a9 f2 3f aa 63 97 8c 31 7f c9 fa 66 a7 3f"
196
                                                "60 f0 50 4d e9 3b 5b 84 5e 27 55 92 c1 23 35 ee 34 0b bc 4f dd"
197
                                                "d5 02 78 40 16 e4 b3 be 7e f0 4d da 49 f4 b4 40 a3 0c b5 d2 af"
198
                                                "93 98 28 fd 4a e3 79 4e 44 f9 4d f5 a6 31 ed e4 2c 17 19 bf da"
199
                                                "bf 02 53 fe 51 75 be 89 8e 75 0e dc 53 37 0d 2b"),
200
                       Botan::hex_decode_locked("08 00 00 24 00 22 00 0a 00 14 00 12 00 1d"
1✔
201
                                                "00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 1c 00 02 40"
202
                                                "01 00 00 00 00 0b 00 01 b9 00 00 01 b5 00 01 b0 30 82 01 ac 30"
203
                                                "82 01 15 a0 03 02 01 02 02 01 02 30 0d 06 09 2a 86 48 86 f7 0d"
204
                                                "01 01 0b 05 00 30 0e 31 0c 30 0a 06 03 55 04 03 13 03 72 73 61"
205
                                                "30 1e 17 0d 31 36 30 37 33 30 30 31 32 33 35 39 5a 17 0d 32 36"
206
                                                "30 37 33 30 30 31 32 33 35 39 5a 30 0e 31 0c 30 0a 06 03 55 04"
207
                                                "03 13 03 72 73 61 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01"
208
                                                "01 05 00 03 81 8d 00 30 81 89 02 81 81 00 b4 bb 49 8f 82 79 30"
209
                                                "3d 98 08 36 39 9b 36 c6 98 8c 0c 68 de 55 e1 bd b8 26 d3 90 1a"
210
                                                "24 61 ea fd 2d e4 9a 91 d0 15 ab bc 9a 95 13 7a ce 6c 1a f1 9e"
211
                                                "aa 6a f9 8c 7c ed 43 12 09 98 e1 87 a8 0e e0 cc b0 52 4b 1b 01"
212
                                                "8c 3e 0b 63 26 4d 44 9a 6d 38 e2 2a 5f da 43 08 46 74 80 30 53"
213
                                                "0e f0 46 1c 8c a9 d9 ef bf ae 8e a6 d1 d0 3e 2b d1 93 ef f0 ab"
214
                                                "9a 80 02 c4 74 28 a6 d3 5a 8d 88 d7 9f 7f 1e 3f 02 03 01 00 01"
215
                                                "a3 1a 30 18 30 09 06 03 55 1d 13 04 02 30 00 30 0b 06 03 55 1d"
216
                                                "0f 04 04 03 02 05 a0 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05"
217
                                                "00 03 81 81 00 85 aa d2 a0 e5 b9 27 6b 90 8c 65 f7 3a 72 67 17"
218
                                                "06 18 a5 4c 5f 8a 7b 33 7d 2d f7 a5 94 36 54 17 f2 ea e8 f8 a5"
219
                                                "8c 8f 81 72 f9 31 9c f3 6b 7f d6 c5 5b 80 f2 1a 03 01 51 56 72"
220
                                                "60 96 fd 33 5e 5e 67 f2 db f1 02 70 2e 60 8c ca e6 be c1 fc 63"
221
                                                "a4 2a 99 be 5c 3e b7 10 7c 3c 54 e9 b9 eb 2b d5 20 3b 1c 3b 84"
222
                                                "e0 a8 b2 f7 59 40 9b a3 ea c9 d9 1d 40 2d cc 0c c8 f8 96 12 29"
223
                                                "ac 91 87 b4 2b 4d e1 00 00 0f 00 00 84 08 04 00 80 5a 74 7c 5d"
224
                                                "88 fa 9b d2 e5 5a b0 85 a6 10 15 b7 21 1f 82 4c d4 84 14 5a b3"
225
                                                "ff 52 f1 fd a8 47 7b 0b 7a bc 90 db 78 e2 d3 3a 5c 14 1a 07 86"
226
                                                "53 fa 6b ef 78 0c 5e a2 48 ee aa a7 85 c4 f3 94 ca b6 d3 0b be"
227
                                                "8d 48 59 ee 51 1f 60 29 57 b1 54 11 ac 02 76 71 45 9e 46 44 5c"
228
                                                "9e a5 8c 18 1e 81 8e 95 b8 c3 fb 0b f3 27 84 09 d3 be 15 2a 3d"
229
                                                "a5 04 3e 06 3d da 65 cd f5 ae a2 0d 53 df ac d4 2f 74 f3 14 00"
230
                                                "00 20 9b 9b 14 1d 90 63 37 fb d2 cb dc e7 1d f4 de da 4a b4 2c"
231
                                                "30 95 72 cb 7f ff ee 54 54 b7 8f 07 18"
232
                                                "16" /* to-be-encrypted content type */));
1✔
233

234
   // encrypted with client_handshake_traffic_secret
235
   const auto encrypted_client_finished_message =
1✔
236
      RFC8448_TestData("encrypted_client_finished_message",
237
                       Connection_Side::Client,
238
                       Botan::hex_decode("17 03 03 00 35"),
2✔
239
                       Botan::hex_decode_locked("75 ec 4d c2 38 cc e6"
2✔
240
                                                "0b 29 80 44 a7 1e 21 9c 56 cc 77 b0 51 7f e9 b9 3c 7a 4b fc 44"
241
                                                "d8 7f 38 f8 03 38 ac 98 fc 46 de b3 84 bd 1c ae ac ab 68 67 d7"
242
                                                "26 c4 05 46"),
243
                       Botan::hex_decode_locked("14 00 00 20 a8 ec 43 6d 67 76 34 ae 52 5a c1"
1✔
244
                                                "fc eb e1 1a 03 9e c1 76 94 fa c6 e9 85 27 b6 42 f2 ed d5 ce 61"
245
                                                "16" /* to-be-encrypted content type */));
1✔
246

247
   // encrypted with server_application_traffic_secret
248
   const auto encrypted_new_session_ticket =
1✔
249
      RFC8448_TestData("encrypted_new_session_ticket",
250
                       Connection_Side::Server,
251
                       Botan::hex_decode("17 03 03 00 de"),
2✔
252
                       Botan::hex_decode_locked("3a 6b 8f 90 41 4a 97"
2✔
253
                                                "d6 95 9c 34 87 68 0d e5 13 4a 2b 24 0e 6c ff ac 11 6e 95 d4 1d"
254
                                                "6a f8 f6 b5 80 dc f3 d1 1d 63 c7 58 db 28 9a 01 59 40 25 2f 55"
255
                                                "71 3e 06 1d c1 3e 07 88 91 a3 8e fb cf 57 53 ad 8e f1 70 ad 3c"
256
                                                "73 53 d1 6d 9d a7 73 b9 ca 7f 2b 9f a1 b6 c0 d4 a3 d0 3f 75 e0"
257
                                                "9c 30 ba 1e 62 97 2a c4 6f 75 f7 b9 81 be 63 43 9b 29 99 ce 13"
258
                                                "06 46 15 13 98 91 d5 e4 c5 b4 06 f1 6e 3f c1 81 a7 7c a4 75 84"
259
                                                "00 25 db 2f 0a 77 f8 1b 5a b0 5b 94 c0 13 46 75 5f 69 23 2c 86"
260
                                                "51 9d 86 cb ee ac 87 aa c3 47 d1 43 f9 60 5d 64 f6 50 db 4d 02"
261
                                                "3e 70 e9 52 ca 49 fe 51 37 12 1c 74 bc 26 97 68 7e 24 87 46 d6"
262
                                                "df 35 30 05 f3 bc e1 86 96 12 9c 81 53 55 6b 3b 6c 67 79 b3 7b"
263
                                                "f1 59 85 68 4f"),
264
                       Botan::hex_decode_locked("04 00 00 c9 00 00 00 1e fa d6 aa c5 02 00"
1✔
265
                                                "00 00 b2 2c 03 5d 82 93 59 ee 5f f7 af 4e c9 00 00 00 00 26 2a"
266
                                                "64 94 dc 48 6d 2c 8a 34 cb 33 fa 90 bf 1b 00 70 ad 3c 49 88 83"
267
                                                "c9 36 7c 09 a2 be 78 5a bc 55 cd 22 60 97 a3 a9 82 11 72 83 f8"
268
                                                "2a 03 a1 43 ef d3 ff 5d d3 6d 64 e8 61 be 7f d6 1d 28 27 db 27"
269
                                                "9c ce 14 50 77 d4 54 a3 66 4d 4e 6d a4 d2 9e e0 37 25 a6 a4 da"
270
                                                "fc d0 fc 67 d2 ae a7 05 29 51 3e 3d a2 67 7f a5 90 6c 5b 3f 7d"
271
                                                "8f 92 f2 28 bd a4 0d da 72 14 70 f9 fb f2 97 b5 ae a6 17 64 6f"
272
                                                "ac 5c 03 27 2e 97 07 27 c6 21 a7 91 41 ef 5f 7d e6 50 5e 5b fb"
273
                                                "c3 88 e9 33 43 69 40 93 93 4a e4 d3 57 00 08 00 2a 00 04 00 00"
274
                                                "04 00"
275
                                                "16" /* to-be-encrypted content type */));
1✔
276

277
   // encrypted with client_application_traffic_secret
278
   const auto encrypted_application_data_client =
1✔
279
      RFC8448_TestData("encrypted_application_data_client",
280
                       Connection_Side::Client,
281
                       Botan::hex_decode("17 03 03 00 43"),
2✔
282
                       Botan::hex_decode_locked("a2 3f 70 54 b6 2c 94"
2✔
283
                                                "d0 af fa fe 82 28 ba 55 cb ef ac ea 42 f9 14 aa 66 bc ab 3f 2b"
284
                                                "98 19 a8 a5 b4 6b 39 5b d5 4a 9a 20 44 1e 2b 62 97 4e 1f 5a 62"
285
                                                "92 a2 97 70 14 bd 1e 3d ea e6 3a ee bb 21 69 49 15 e4"),
286
                       Botan::hex_decode_locked("00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e"
1✔
287
                                                "0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23"
288
                                                "24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31"
289
                                                "17" /* to-be-encrypted content type */));
1✔
290

291
   // encrypted with server_application_traffic_secret
292
   const auto encrypted_application_data_server =
1✔
293
      RFC8448_TestData("encrypted_application_data_server",
294
                       Connection_Side::Server,
295
                       Botan::hex_decode("17 03 03 00 43"),
2✔
296
                       Botan::hex_decode_locked("2e 93 7e 11 ef 4a c7"
2✔
297
                                                "40 e5 38 ad 36 00 5f c4 a4 69 32 fc 32 25 d0 5f 82 aa 1b 36 e3"
298
                                                "0e fa f9 7d 90 e6 df fc 60 2d cb 50 1a 59 a8 fc c4 9c 4b f2 e5"
299
                                                "f0 a2 1c 00 47 c2 ab f3 32 54 0d d0 32 e1 67 c2 95 5d"),
300
                       Botan::hex_decode_locked("00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e"
1✔
301
                                                "0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23"
302
                                                "24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31"
303
                                                "17" /* to-be-encrypted content type */));
1✔
304

305
   auto cipher = Ciphersuite::from_name("AES_128_GCM_SHA256").value();
1✔
306

307
   // initialize Cipher_State with client_hello...server_hello
308
   Journaling_Secret_Logger sl_client;
1✔
309
   Journaling_Secret_Logger sl_server;
1✔
310
   auto cs_client = Cipher_State::init_with_server_hello(
1✔
311
      Connection_Side::Client, secure_vector<uint8_t>(shared_secret), cipher, th_server_hello, sl_client);
1✔
312
   auto cs_server = Cipher_State::init_with_server_hello(
1✔
313
      Connection_Side::Server, secure_vector<uint8_t>(shared_secret), cipher, th_server_hello, sl_server);
1✔
314

315
   auto CHECK_both = make_CHECK_both(cs_client.get(), &sl_client, cs_server.get(), &sl_server);
1✔
316

317
   return Test::flatten_result_lists(
8✔
318
      {CHECK_both(
1✔
319
          "secret logging during initialization",
320
          [&](Cipher_State*, Journaling_Secret_Logger* sl, Connection_Side, Test::Result& result) {
2✔
321
             result.test_eq("logged expected secrets", sl->secrets.size(), 2);
2✔
322
             result.require("has client traffic secret", sl->secrets.contains("CLIENT_HANDSHAKE_TRAFFIC_SECRET"));
4✔
323
             result.require("has server traffic secret", sl->secrets.contains("SERVER_HANDSHAKE_TRAFFIC_SECRET"));
4✔
324

325
             result.test_is_eq("client traffic secret",
4✔
326
                               sl->secrets.at("CLIENT_HANDSHAKE_TRAFFIC_SECRET"),
2✔
327
                               client_handshake_traffic_secret);
328
             result.test_is_eq("server traffic secret",
4✔
329
                               sl->secrets.at("SERVER_HANDSHAKE_TRAFFIC_SECRET"),
2✔
330
                               server_handshake_traffic_secret);
331
          }),
2✔
332

333
       CHECK_both("ciphersuite compatibility",
1✔
334
                  [&](Cipher_State* cs, Journaling_Secret_Logger*, Connection_Side side, Test::Result& result) {
2✔
335
                     result.confirm("self-compatibility", cs->is_compatible_with(cipher));
4✔
336
                     result.confirm(
4✔
337
                        "fully defined state is not compatible to other suites",
338
                        !cs->is_compatible_with(Ciphersuite::from_name("CHACHA20_POLY1305_SHA256").value()) &&
6✔
339
                           !cs->is_compatible_with(Ciphersuite::from_name("AES_128_CCM_SHA256").value()) &&
6✔
340
                           !cs->is_compatible_with(Ciphersuite::from_name("PSK_WITH_AES_128_GCM_SHA256").value()));
4✔
341
                     if(side == Connection_Side::Client) {
2✔
342
                        result.confirm("Clients don't expect unprotected alerts after server hello",
1✔
343
                                       !cs->must_expect_unprotected_alert_traffic());
1✔
344
                     } else {
345
                        result.confirm("Servers must expect unprotected alerts in response to their server hello",
2✔
346
                                       cs->must_expect_unprotected_alert_traffic());
1✔
347
                     }
348
                  }),
2✔
349

350
       CHECK_both("ticket nonce counter is not yet available",
1✔
351
                  [&](Cipher_State* cs, Journaling_Secret_Logger*, Connection_Side, Test::Result& result) {
2✔
352
                     result.test_throws<Botan::Invalid_State>("nonce counter is disabled",
4✔
353
                                                              [&] { cs->next_ticket_nonce(); });
4✔
354
                  }),
2✔
355

356
       CHECK_both("handshake traffic without PSK",
1✔
357
                  [&](Cipher_State* cs, Journaling_Secret_Logger* sl, Connection_Side side, Test::Result& result) {
2✔
358
                     result.confirm("can not yet write application data", !cs->can_encrypt_application_traffic());
4✔
359
                     result.confirm("can not yet export key material", !cs->can_export_keys());
6✔
360

361
                     // decrypt encrypted extensions from server
362
                     encrypted_extensions.xxcrypt(result, cs, side);
2✔
363

364
                     // validate the MAC we receive in server Finished message
365
                     const auto expected_server_mac = Botan::hex_decode(
2✔
366
                        "9b 9b 14 1d 90 63 37 fb d2 cb dc e7 1d f4"
367
                        "de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07 18");
2✔
368
                     if(side == Connection_Side::Client) {
2✔
369
                        result.confirm("expecting the correct MAC for server finished",
2✔
370
                                       cs->verify_peer_finished_mac(th_pre_server_finished, expected_server_mac));
1✔
371
                     } else {
372
                        result.test_eq("expecting the correct MAC for server finished",
2✔
373
                                       cs->finished_mac(th_pre_server_finished),
2✔
374
                                       expected_server_mac);
375
                     }
376

377
                     // advance Cipher_State with client_hello...server_Finished
378
                     // (allows receiving of application data, but does not yet allow such sending)
379
                     result.test_no_throw("state advancement is legal",
4✔
380
                                          [&] { cs->advance_with_server_finished(th_server_finished, *sl); });
4✔
381

382
                     if(side == Connection_Side::Client) {
2✔
383
                        result.confirm("can read application data", cs->can_decrypt_application_traffic());
2✔
384
                        result.confirm("can not yet write application data", !cs->can_encrypt_application_traffic());
2✔
385
                        result.confirm("Clients don't expect unprotected alerts after server hello",
1✔
386
                                       !cs->must_expect_unprotected_alert_traffic());
1✔
387
                     } else {
388
                        result.confirm("can not yet read application data", !cs->can_decrypt_application_traffic());
2✔
389
                        result.confirm("can write application data", cs->can_encrypt_application_traffic());
2✔
390
                        result.confirm("Servers must expect unprotected alerts in response to their first flight",
2✔
391
                                       cs->must_expect_unprotected_alert_traffic());
1✔
392
                     }
393

394
                     // check the logged key material
395
                     result.test_eq("contains expected number of keys", sl->secrets.size(), 5);
2✔
396
                     result.require("has client traffic secret", sl->secrets.contains("CLIENT_TRAFFIC_SECRET_0"));
4✔
397
                     result.require("has server traffic secret", sl->secrets.contains("SERVER_TRAFFIC_SECRET_0"));
6✔
398
                     result.require("has exporter secret", sl->secrets.contains("EXPORTER_SECRET"));
4✔
399
                     result.test_eq(
6✔
400
                        "client traffic secret (0)", sl->secrets.at("CLIENT_TRAFFIC_SECRET_0"), client_traffic_secret);
2✔
401
                     result.test_eq(
6✔
402
                        "server traffic secret (0)", sl->secrets.at("SERVER_TRAFFIC_SECRET_0"), server_traffic_secret);
2✔
403

404
                     // generate the MAC for the client Finished message
405
                     const auto expected_client_mac = Botan::hex_decode(
2✔
406
                        "a8 ec 43 6d 67 76 34 ae 52 5a c1 fc eb e1 1a 03"
407
                        "9e c1 76 94 fa c6 e9 85 27 b6 42 f2 ed d5 ce 61");
2✔
408
                     if(side == Connection_Side::Client) {
2✔
409
                        result.test_eq("generating the correct MAC for client finished",
2✔
410
                                       cs->finished_mac(th_server_finished),
2✔
411
                                       expected_client_mac);
412
                     } else {
413
                        result.confirm("verify the correct MAC for client finished",
2✔
414
                                       cs->verify_peer_finished_mac(th_server_finished, expected_client_mac));
1✔
415
                     }
416

417
                     // encrypt client Finished message by client
418
                     // (under the client handshake traffic secret)
419
                     encrypted_client_finished_message.xxcrypt(result, cs, side);
2✔
420

421
                     // advance Cipher_State with client_hello...client_Finished
422
                     // (allows generation of resumption PSKs)
423
                     result.test_no_throw("state advancement is legal",
4✔
424
                                          [&] { cs->advance_with_client_finished(th_client_finished); });
4✔
425

426
                     result.confirm("can write application data", cs->can_encrypt_application_traffic());
4✔
427
                     result.confirm("can read application data", cs->can_decrypt_application_traffic());
4✔
428
                     result.confirm("doesn't need to expect unprotected alerts",
2✔
429
                                    !cs->must_expect_unprotected_alert_traffic());
2✔
430
                     result.confirm("can export key material", cs->can_export_keys());
6✔
431
                     result.test_eq("key export produces expected result",
4✔
432
                                    cs->export_key(export_label, export_context, 16),
2✔
433
                                    expected_key_export);
434

435
                     // decrypt "new session ticket" post-handshake message from server
436
                     // (encrypted under the application traffic secret)
437
                     encrypted_new_session_ticket.xxcrypt(result, cs, side);
2✔
438

439
                     // encrypt application data by client
440
                     encrypted_application_data_client.xxcrypt(result, cs, side);
2✔
441

442
                     // decrypt application data from server
443
                     // (encrypted under the application traffic secret -- and a new sequence number)
444
                     encrypted_application_data_server.xxcrypt(result, cs, side);
2✔
445

446
                     result.confirm("can export key material still", cs->can_export_keys());
6✔
447
                     result.test_eq("key export result did not change",
4✔
448
                                    cs->export_key(export_label, export_context, 16),
4✔
449
                                    expected_key_export);
450
                  }),
4✔
451

452
       CHECK_both("ticket nonce counter counts",
1✔
453
                  [&](Cipher_State* cs, Journaling_Secret_Logger*, Connection_Side, Test::Result& result) {
2✔
454
                     result.test_is_eq("nonce is 0x00, 0x00",
4✔
455
                                       cs->next_ticket_nonce(),
2✔
456
                                       Botan::TLS::Ticket_Nonce(std::vector<uint8_t>{0x00, 0x00}));
4✔
457
                     result.test_is_eq("nonce is 0x00, 0x01",
4✔
458
                                       cs->next_ticket_nonce(),
2✔
459
                                       Botan::TLS::Ticket_Nonce(std::vector<uint8_t>{0x00, 0x01}));
4✔
460
                     result.test_is_eq("nonce is 0x00, 0x02",
4✔
461
                                       cs->next_ticket_nonce(),
2✔
462
                                       Botan::TLS::Ticket_Nonce(std::vector<uint8_t>{0x00, 0x02}));
4✔
463

464
                     for(uint32_t i = 3; i < std::numeric_limits<uint16_t>::max(); ++i) {
131,066✔
465
                        cs->next_ticket_nonce();
262,128✔
466
                     }
467

468
                     // Cannot generate more than 2^16 ticket nonces
469
                     result.test_throws<Botan::Invalid_State>("nonces are depleted", [&] { cs->next_ticket_nonce(); });
6✔
470
                  }),
2✔
471

472
       CHECK_both("PSK",
1✔
473
                  [&](Cipher_State* cs, Journaling_Secret_Logger*, Connection_Side, Test::Result& result) {
2✔
474
                     // derive PSK for resumption
475
                     const auto psk = cs->psk(Botan::TLS::Ticket_Nonce(
2✔
476
                        std::vector<uint8_t>{0x00, 0x00}) /* ticket_nonce as defined in RFC 8448 */);
2✔
477
                     result.test_eq("PSK matches", psk, expected_psk);
4✔
478
                  }),
2✔
479

480
       CHECK_both("key update",
1✔
481
                  [&](Cipher_State* cs, Journaling_Secret_Logger* sl, Connection_Side side, Test::Result& result) {
2✔
482
                     const auto* const read_label =
2✔
483
                        side == Connection_Side::Client ? "SERVER_TRAFFIC_SECRET_1" : "CLIENT_TRAFFIC_SECRET_1";
484
                     const auto* const write_label =
1✔
485
                        side == Connection_Side::Client ? "CLIENT_TRAFFIC_SECRET_1" : "SERVER_TRAFFIC_SECRET_1";
486

487
                     cs->update_read_keys(*sl);
2✔
488
                     result.test_eq("read secret update is here", sl->secrets.size(), 6);
2✔
489
                     result.require("has new read traffic secret", sl->secrets.contains(read_label));
4✔
490

491
                     cs->update_write_keys(*sl);
2✔
492
                     result.test_eq("write secret update is here", sl->secrets.size(), 7);
2✔
493
                     result.require("has new write traffic secret", sl->secrets.contains(write_label));
4✔
494

495
                     result.test_eq("client traffic secret (1)",
6✔
496
                                    sl->secrets.at("CLIENT_TRAFFIC_SECRET_1"),
2✔
497
                                    updated_client_traffic_secret);
498
                     result.test_eq("server traffic secret (1)",
6✔
499
                                    sl->secrets.at("SERVER_TRAFFIC_SECRET_1"),
2✔
500
                                    updated_server_traffic_secret);
501

502
                     result.confirm("can encrypt application traffic", cs->can_encrypt_application_traffic());
4✔
503
                  }),
2✔
504

505
       CHECK_both("cleanup", [&](Cipher_State* cs, Journaling_Secret_Logger*, Connection_Side, Test::Result& result) {
1✔
506
          // cleanup
507
          cs->clear_write_keys();
2✔
508
          result.confirm("can no longer write application data", !cs->can_encrypt_application_traffic());
4✔
509
          result.confirm("can still read application data", cs->can_decrypt_application_traffic());
4✔
510

511
          cs->clear_read_keys();
2✔
512
          result.confirm("can no longer write application data", !cs->can_encrypt_application_traffic());
4✔
513
          result.confirm("can no longer read application data", !cs->can_decrypt_application_traffic());
4✔
514
       })});
11✔
515
}
18✔
516

517
std::vector<Test::Result> test_secret_derivation_rfc8448_rtt0() {
1✔
518
   // this is the PSK that was negotiated for session resumption in RFC 8448 (see test case above)
519
   const auto psk = Botan::hex_decode_locked(
1✔
520
      "4e cd 0e b6 ec 3b 4d 87 f5 d6 02 8f 92 2c a4 c5"
521
      "85 1a 27 7f d4 13 11 c9 e6 2d 2c 94 92 e1 c4 f3");
1✔
522

523
   // this shared secret is obtained by a key exchange performed additionally to
524
   // the pre-shared-key.
525
   const auto shared_secret = Botan::hex_decode_locked(
1✔
526
      "f4 41 94 75 6f f9 ec 9d 25 18 06 35 d6 6e a6 82"
527
      "4c 6a b3 bf 17 99 77 be 37 f7 23 57 0e 7c cb 2e");
1✔
528

529
   // transcript hash of the client hello up to (including) the PSK modes
530
   // (used to calculate the PSK binder)
531
   const auto th_client_hello_prefix = Botan::hex_decode(
1✔
532
      "63 22 4b 2e 45 73 f2 d3 45 4c a8 4b 9d 00 9a 04"
533
      "f6 be 9e 05 71 1a 83 96 47 3a ef a0 1e 92 4a 14");
1✔
534

535
   // transcript hash of the client hello including the PSK identity and binders
536
   const auto th_client_hello = Botan::hex_decode(
1✔
537
      "08 ad 0f a0 5d 7c 72 33 b1 77 5b a2 ff 9f 4c 5b"
538
      "8b 59 27 6b 7f 22 7f 13 a9 76 24 5f 5d 96 09 13");
1✔
539

540
   const auto th_server_hello = Botan::hex_decode(
1✔
541
      "f7 36 cb 34 fe 25 e7 01 55 1b ee 6f d2 4c 1c c7"
542
      "10 2a 7d af 94 05 cb 15 d9 7a af e1 6f 75 7d 03");
1✔
543

544
   // this is not directly exposed in RFC 8448 but calculated as
545
   // SHA-256(ClientHello..EncryptedExtensions)
546
   const auto th_pre_server_finished = Botan::hex_decode(
1✔
547
      "04 05 54 55 ef 74 b2 32 2b a3 66 cb c4 cf e0 27"
548
      "23 43 4b 37 b9 b3 67 1b b5 a3 00 60 56 d8 f0 2f");
1✔
549

550
   const auto th_server_finished = Botan::hex_decode(
1✔
551
      "b0 ae ff c4 6a 2c fe 33 11 4e 6f d7 d5 1f 9f 04"
552
      "b1 ca 3c 49 7d ab 08 93 4a 77 4a 9d 9a d7 db f3");
1✔
553

554
   // this is not directly exposed in RFC 8448 but calculated as
555
   // SHA-256(ClientHello..EndOfEarlyData)
556
   const auto th_end_of_early_data = Botan::hex_decode(
1✔
557
      "9f 23 a0 0c 1f 08 fc 18 80 7b 8b 68 23 7b 56 5d"
558
      "f2 0d 4c 50 dd 8e 49 ef 61 2e 1a 5b b1 6c 58 67");
1✔
559

560
   const auto th_client_finished = Botan::hex_decode(
1✔
561
      "c3 c1 22 e0 bd 90 7a 4a 3f f6 11 2d 8f d5 3d bf"
562
      "89 c7 73 d9 55 2e 8b 6b 9d 56 d3 61 b3 a9 7b f6");
1✔
563

564
   const auto expected_psk_binder = Botan::hex_decode(
1✔
565
      "3a dd 4f b2 d8 fd f8 22 a0 ca 3c f7 67 8e f5 e8"
566
      "8d ae 99 01 41 c5 92 4d 57 bb 6f a3 1b 9e 5f 9d");
1✔
567

568
   const auto early_exporter_secret = Botan::hex_decode(
1✔
569
      "b2 02 68 66 61 09 37 d7 42 3e 5b e9 08 62 cc f2"
570
      "4c 0e 60 91 18 6d 34 f8 12 08 9f f5 be 2e f7 df");
1✔
571

572
   const auto client_handshake_traffic_secret = Botan::hex_decode(
1✔
573
      "2f aa c0 8f 85 1d 35 fe a3 60 4f cb 4d e8 2d c6"
574
      "2c 9b 16 4a 70 97 4d 04 62 e2 7f 1a b2 78 70 0f");
1✔
575

576
   const auto server_handshake_traffic_secret = Botan::hex_decode(
1✔
577
      "fe 92 7a e2 71 31 2e 8b f0 27 5b 58 1c 54 ee f0"
578
      "20 45 0d c4 ec ff aa 05 a1 a3 5d 27 51 8e 78 03");
1✔
579

580
   const auto client_traffic_secret = Botan::hex_decode(
1✔
581
      "2a bb f2 b8 e3 81 d2 3d be be 1d d2 a7 d1 6a 8b"
582
      "f4 84 cb 49 50 d2 3f b7 fb 7f a8 54 70 62 d9 a1");
1✔
583

584
   const auto server_traffic_secret = Botan::hex_decode(
1✔
585
      "cc 21 f1 bf 8f eb 7d d5 fa 50 5b d9 c4 b4 68 a9"
586
      "98 4d 55 4a 99 3d c4 9e 6d 28 55 98 fb 67 26 91");
1✔
587

588
   const auto exporter_secret = Botan::hex_decode(
1✔
589
      "3f d9 3d 4f fd dc 98 e6 4b 14 dd 10 7a ed f8 ee"
590
      "4a dd 23 f4 51 0f 58 a4 59 2d 0b 20 1b ee 56 b4");
1✔
591

592
   // this is not part of RFC 8448
593
   const std::string export_label = "export_test_label";
1✔
594
   const std::string export_context = "rfc8448_psk";
1✔
595
   const auto expected_key_export = Botan::hex_decode_locked("b5 89 bc b4 0b 7f 94 d7 6f 2d d6 fc f9 e5 87 8e");
1✔
596

597
   // this is not part of RFC 8448
598
   const std::string early_export_label = "export_test_label_early";
1✔
599
   const std::string early_export_context = "rfc8448_psk_early";
1✔
600
   const auto early_expected_key_export = Botan::hex_decode_locked("b6 fb 7d 9e b5 4e 97 59 6f e4 ed 93 cc b0 bf 0c");
1✔
601

602
   // encrypted with server_handshake_traffic_secret
603
   const auto encrypted_extensions =
1✔
604
      RFC8448_TestData("encrypted_extensions",
605
                       Connection_Side::Server,
606
                       Botan::hex_decode("17 03 03 00 61"),
2✔
607
                       Botan::hex_decode_locked("dc 48 23 7b 4b 87 9f"
2✔
608
                                                "50 d0 d4 d2 62 ea 8b 47 16 eb 40 dd c1 eb 95 7e 11 12 6e 8a 71"
609
                                                "49 c2 d0 12 d3 7a 71 15 95 7e 64 ce 30 00 8b 9e 03 23 f2 c0 5a"
610
                                                "9c 1c 77 b4 f3 78 49 a6 95 ab 25 50 60 a3 3f ee 77 0c a9 5c b8"
611
                                                "48 6b fd 08 43 b8 70 24 86 5c a3 5c c4 1c 4e 51 5c 64 dc b1 36"
612
                                                "9f 98 63 5b c7 a5"),
613
                       Botan::hex_decode_locked("08 00 00 28 00 26 00 0a 00 14 00 12 00 1d 00"
1✔
614
                                                "17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 1c 00 02 40 01"
615
                                                "00 00 00 00 00 2a 00 00 14 00 00 20 48 d3 e0 e1 b3 d9 07 c6 ac"
616
                                                "ff 14 5e 16 09 03 88 c7 7b 05 c0 50 b6 34 ab 1a 88 bb d0 dd 1a"
617
                                                "34 b2"
618
                                                "16" /* to-be-encrypted content type */));
1✔
619

620
   // encrypted with client_handshake_traffic_secret
621
   const auto encrypted_client_finished_message =
1✔
622
      RFC8448_TestData("encrypted_client_finished_message",
623
                       Connection_Side::Client,
624
                       Botan::hex_decode("17 03 03 00 35"),
2✔
625
                       Botan::hex_decode_locked("00 f8 b4 67 d1 4c f2"
2✔
626
                                                "2a 4b 3f 0b 6a e0 d8 e6 cc 8d 08 e0 db 35 15 ef 5c 2b df 19 22"
627
                                                "ea fb b7 00 09 96 47 16 d8 34 fb 70 c3 d2 a5 6c 5b 1f 5f 6b db"
628
                                                "a6 c3 33 cf"),
629
                       Botan::hex_decode_locked("14 00 00 20 72 30 a9 c9 52 c2 5c d6 13 8f"
1✔
630
                                                "c5 e6 62 83 08 c4 1c 53 35 dd 81 b9 f9 6b ce a5 0f d3 2b da 41 6d"
631
                                                "16" /* to-be-encrypted content type */));
1✔
632

633
   // encrypted with client_application_traffic_secret
634
   const auto encrypted_application_data_client =
1✔
635
      RFC8448_TestData("encrypted_application_data_client",
636
                       Connection_Side::Client,
637
                       Botan::hex_decode("17 03 03 00 43"),
2✔
638
                       Botan::hex_decode_locked("b1 ce bc e2 42 aa 20"
2✔
639
                                                "1b e9 ae 5e 1c b2 a9 aa 4b 33 d4 e8 66 af 1e db 06 89 19 23 77"
640
                                                "41 aa 03 1d 7a 74 d4 91 c9 9b 9d 4e 23 2b 74 20 6b c6 fb aa 04"
641
                                                "fe 78 be 44 a9 b4 f5 43 20 a1 7e b7 69 92 af ac 31 03"),
642
                       Botan::hex_decode_locked("00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e"
1✔
643
                                                "0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23"
644
                                                "24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31"
645
                                                "17" /* to-be-encrypted content type */));
1✔
646

647
   // encrypted with server_application_traffic_secret
648
   const auto encrypted_application_data_server =
1✔
649
      RFC8448_TestData("encrypted_application_data_server",
650
                       Connection_Side::Server,
651
                       Botan::hex_decode("17 03 03 00 43"),
2✔
652
                       Botan::hex_decode_locked("27 5e 9f 20 ac ff 57"
2✔
653
                                                "bc 00 06 57 d3 86 7d f0 39 cc cf 79 04 78 84 cf 75 77 17 46 f7"
654
                                                "40 b5 a8 3f 46 2a 09 54 c3 58 13 93 a2 03 a2 5a 7d d1 41 41 ef"
655
                                                "1a 37 90 0c db 62 ff 62 de e1 ba 39 ab 25 90 cb f1 94"),
656
                       Botan::hex_decode_locked("00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e"
1✔
657
                                                "0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23"
658
                                                "24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31"
659
                                                "17" /* to-be-encrypted content type */));
1✔
660

661
   auto cipher = Ciphersuite::from_name("AES_128_GCM_SHA256").value();
1✔
662

663
   Journaling_Secret_Logger sl_client;
1✔
664
   Journaling_Secret_Logger sl_server;
1✔
665

666
   auto cs_client = Cipher_State::init_with_psk(Connection_Side::Client,
1✔
667
                                                Cipher_State::PSK_Type::Resumption,
668
                                                secure_vector<uint8_t>(psk.begin(), psk.end()),
2✔
669
                                                cipher.prf_algo());
1✔
670
   auto cs_server = Cipher_State::init_with_psk(Connection_Side::Server,
1✔
671
                                                Cipher_State::PSK_Type::Resumption,
672
                                                secure_vector<uint8_t>(psk.begin(), psk.end()),
2✔
673
                                                cipher.prf_algo());
1✔
674

675
   auto CHECK_both = make_CHECK_both(cs_client.get(), &sl_client, cs_server.get(), &sl_server);
1✔
676

677
   return Test::flatten_result_lists(
6✔
678
      {CHECK_both("no secrets logged for PSK initialization",
1✔
679
                  [&](Cipher_State*, Journaling_Secret_Logger* sl, Connection_Side, Test::Result& result) {
2✔
680
                     result.test_eq("no secrets logged", sl->secrets.size(), 0);
2✔
681
                  }),
2✔
682

683
       CHECK_both("calculating PSK binder",
1✔
684
                  [&](Cipher_State* cs, Journaling_Secret_Logger*, Connection_Side, Test::Result& result) {
2✔
685
                     const auto mac = cs->psk_binder_mac(th_client_hello_prefix);
2✔
686
                     result.test_eq("PSK binder is as expected", mac, expected_psk_binder);
4✔
687
                  }),
2✔
688

689
       CHECK_both(
1✔
690
          "ciphersuite compatibility",
691
          [&](Cipher_State* cs, Journaling_Secret_Logger*, Connection_Side, Test::Result& result) {
2✔
692
             result.confirm("self-compatibility", cs->is_compatible_with(cipher));
4✔
693
             result.confirm("partially defined state is compatible with suites using the same hash",
4✔
694
                            cs->is_compatible_with(Ciphersuite::from_name("CHACHA20_POLY1305_SHA256").value()) &&
6✔
695
                               cs->is_compatible_with(Ciphersuite::from_name("AES_128_CCM_SHA256").value()) &&
6✔
696
                               cs->is_compatible_with(Ciphersuite::from_name("AES_128_CCM_8_SHA256").value()));
4✔
697

698
             result.confirm("partially defined state is not compatible with other hashes or protocol versions",
4✔
699
                            !cs->is_compatible_with(Ciphersuite::from_name("PSK_WITH_AES_128_GCM_SHA256").value()) &&
6✔
700
                               !cs->is_compatible_with(Ciphersuite::from_name("AES_256_GCM_SHA384").value()));
4✔
701
          }),
2✔
702

703
       CHECK_both("calculate the early traffic secrets",
1✔
704
                  [&](Cipher_State* cs, Journaling_Secret_Logger* sl, Connection_Side side, Test::Result& result) {
2✔
705
                     cs->advance_with_client_hello(th_client_hello, *sl);
2✔
706
                     result.require("early key export is possible", cs->can_export_keys());
4✔
707
                     result.test_eq("early key export produces expected result",
4✔
708
                                    cs->export_key(early_export_label, early_export_context, 16),
2✔
709
                                    early_expected_key_export);
710

711
                     if(side == Connection_Side::Client) {
2✔
712
                        result.confirm("Clients must expect servers to respond with an unprotected alert",
2✔
713
                                       cs->must_expect_unprotected_alert_traffic());
1✔
714
                     } else {
715
                        result.confirm(
1✔
716
                           "Servers do not expect clients to send alerts protected with the early data secret",
717
                           !cs->must_expect_unprotected_alert_traffic());
1✔
718
                     }
719

720
                     result.test_eq("logged early secrets", sl->secrets.size(), 1);
2✔
721
                     result.require("has early exporter secret", sl->secrets.contains("EARLY_EXPORTER_MASTER_SECRET"));
4✔
722
                     result.test_eq(
6✔
723
                        "early exporter secret", sl->secrets.at("EARLY_EXPORTER_MASTER_SECRET"), early_exporter_secret);
2✔
724

725
                     // TODO: Once 0-RTT traffic is implemented this will likely allow handling of
726
                     //       application traffic in this state.
727
                     result.confirm("can not yet write application data", !cs->can_encrypt_application_traffic());
4✔
728
                     result.confirm("can not yet read application data", !cs->can_decrypt_application_traffic());
4✔
729
                  }),
2✔
730

731
       CHECK_both(
1✔
732
          "handshake traffic after PSK",
733
          [&](Cipher_State* cs, Journaling_Secret_Logger* sl, Connection_Side side, Test::Result& result) {
2✔
734
             cs->advance_with_server_hello(cipher, secure_vector<uint8_t>(shared_secret), th_server_hello, *sl);
2✔
735

736
             // decrypt encrypted extensions from server
737
             encrypted_extensions.xxcrypt(result, cs, side);
2✔
738

739
             // check the logged key material
740
             result.test_eq("contains expected number of keys", sl->secrets.size(), 3);
2✔
741
             result.require("has client handshake traffic secret",
4✔
742
                            sl->secrets.contains("CLIENT_HANDSHAKE_TRAFFIC_SECRET"));
2✔
743
             result.require("has server handshake traffic secret",
4✔
744
                            sl->secrets.contains("SERVER_HANDSHAKE_TRAFFIC_SECRET"));
2✔
745
             result.test_eq("client handshake traffic secret",
6✔
746
                            sl->secrets.at("CLIENT_HANDSHAKE_TRAFFIC_SECRET"),
2✔
747
                            client_handshake_traffic_secret);
748
             result.test_eq("server handshake traffic secret",
6✔
749
                            sl->secrets.at("SERVER_HANDSHAKE_TRAFFIC_SECRET"),
2✔
750
                            server_handshake_traffic_secret);
751

752
             // TODO: Handling of early traffic is left out as 0-RTT is not implemented yet.
753

754
             // validate the MAC we receive in server Finished message
755
             const auto expected_server_mac = Botan::hex_decode(
2✔
756
                "48 d3 e0 e1 b3 d9 07 c6 ac ff 14 5e 16 09 03 88"
757
                "c7 7b 05 c0 50 b6 34 ab 1a 88 bb d0 dd 1a 34 b2");
2✔
758
             if(side == Connection_Side::Client) {
2✔
759
                result.confirm("expecting the correct MAC for server finished",
2✔
760
                               cs->verify_peer_finished_mac(th_pre_server_finished, expected_server_mac));
1✔
761
                result.confirm("Clients don't expect unprotected alerts after server hello",
1✔
762
                               !cs->must_expect_unprotected_alert_traffic());
1✔
763
             } else {
764
                result.test_eq("expecting the correct MAC for server finished",
2✔
765
                               cs->finished_mac(th_pre_server_finished),
1✔
766
                               expected_server_mac);
767
                result.confirm("Servers must expect unprotected alerts in response to their server hello",
2✔
768
                               cs->must_expect_unprotected_alert_traffic());
1✔
769
             }
770

771
             result.confirm("cannot read application data", !cs->can_decrypt_application_traffic());
4✔
772
             result.confirm("cannot write application data", !cs->can_encrypt_application_traffic());
4✔
773

774
             // advance Cipher_State with client_hello...server_Finished
775
             // (allows receiving of application data, but no such sending)
776
             result.test_no_throw("state advancement is legal",
4✔
777
                                  [&] { cs->advance_with_server_finished(th_server_finished, *sl); });
4✔
778

779
             if(side == Connection_Side::Client) {
2✔
780
                result.confirm("can read application data", cs->can_decrypt_application_traffic());
2✔
781
                result.confirm("cannot write application data", !cs->can_encrypt_application_traffic());
2✔
782
                result.confirm("Clients don't expect unprotected alerts after server hello",
1✔
783
                               !cs->must_expect_unprotected_alert_traffic());
1✔
784
             } else {
785
                result.confirm("cannot read application data", !cs->can_decrypt_application_traffic());
2✔
786
                result.confirm("can write application data", cs->can_encrypt_application_traffic());
2✔
787
                result.confirm("Servers must expect unprotected alerts in response to their first flight",
2✔
788
                               cs->must_expect_unprotected_alert_traffic());
1✔
789
             }
790

791
             // check the logged key material
792
             result.test_eq("contains expected number of keys", sl->secrets.size(), 6);
2✔
793
             result.require("has client traffic secret", sl->secrets.contains("CLIENT_TRAFFIC_SECRET_0"));
4✔
794
             result.require("has server traffic secret", sl->secrets.contains("SERVER_TRAFFIC_SECRET_0"));
4✔
795
             result.require("has exporter secret", sl->secrets.contains("EXPORTER_SECRET"));
4✔
796
             result.test_eq("client traffic secret", sl->secrets.at("CLIENT_TRAFFIC_SECRET_0"), client_traffic_secret);
4✔
797
             result.test_eq("server traffic secret", sl->secrets.at("SERVER_TRAFFIC_SECRET_0"), server_traffic_secret);
4✔
798
             result.test_eq("exporter secret", sl->secrets.at("EXPORTER_SECRET"), exporter_secret);
4✔
799

800
             // generate the MAC for the client Finished message
801
             const auto expected_client_mac = Botan::hex_decode(
2✔
802
                "72 30 a9 c9 52 c2 5c d6 13 8f c5 e6 62 83 08 c4"
803
                "1c 53 35 dd 81 b9 f9 6b ce a5 0f d3 2b da 41 6d");
2✔
804
             if(side == Connection_Side::Client) {
2✔
805
                result.test_eq("generating the correct MAC for client finished",
2✔
806
                               cs->finished_mac(th_end_of_early_data),
2✔
807
                               expected_client_mac);
808
             } else {
809
                result.confirm("verify the correct MAC for client finished",
2✔
810
                               cs->verify_peer_finished_mac(th_end_of_early_data, expected_client_mac));
1✔
811
             }
812

813
             // encrypt client Finished message by client
814
             // (under the client handshake traffic secret)
815
             encrypted_client_finished_message.xxcrypt(result, cs, side);
2✔
816
          }),
4✔
817

818
       CHECK_both("application traffic after PSK",
1✔
819
                  [&](Cipher_State* cs, Journaling_Secret_Logger*, Connection_Side side, Test::Result& result) {
2✔
820
                     // advance Cipher_State with client_hello...client_Finished
821
                     // (allows generation of resumption PSKs)
822
                     result.test_no_throw("state advancement is legal",
4✔
823
                                          [&] { cs->advance_with_client_finished(th_client_finished); });
4✔
824

825
                     result.confirm("can read application data", cs->can_decrypt_application_traffic());
4✔
826
                     result.confirm("can write application data", cs->can_encrypt_application_traffic());
4✔
827
                     result.confirm("doesn't need to expect unprotected alerts",
2✔
828
                                    !cs->must_expect_unprotected_alert_traffic());
2✔
829
                     result.confirm("can export key material", cs->can_export_keys());
6✔
830
                     result.test_eq("key export produces expected result",
4✔
831
                                    cs->export_key(export_label, export_context, 16),
2✔
832
                                    expected_key_export);
833

834
                     // encrypt application data by client
835
                     encrypted_application_data_client.xxcrypt(result, cs, side);
2✔
836

837
                     // decrypt application data from server
838
                     // (encrypted under the application traffic secret -- and a new sequence number)
839
                     encrypted_application_data_server.xxcrypt(result, cs, side);
2✔
840
                  })});
9✔
841
}
20✔
842

843
BOTAN_REGISTER_TEST_FN("tls",
844
                       "tls_cipher_state",
845
                       test_secret_derivation_rfc8448_rtt1,
846
                       test_secret_derivation_rfc8448_rtt0);
847
}  // namespace
848

849
}  // namespace Botan_Tests
850

851
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc