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

randombit / botan / 28278764342

26 Jun 2026 01:00PM UTC coverage: 89.352% (-0.002%) from 89.354%
28278764342

push

github

web-flow
Merge pull request #5700 from Rohde-Schwarz/chore/span_in_tls_msgs_and_exts

[std::span] For TLS message and extension parsing and usage

112053 of 125406 relevant lines covered (89.35%)

11047919.25 hits per line

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

99.25
/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_bin_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_bin_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_sz_eq("logged expected secrets", sl->secrets.size(), 2);
2✔
322
             result.require("has client traffic secret", sl->secrets.contains("CLIENT_HANDSHAKE_TRAFFIC_SECRET"));
2✔
323
             result.require("has server traffic secret", sl->secrets.contains("SERVER_HANDSHAKE_TRAFFIC_SECRET"));
2✔
324

325
             result.test_bin_eq("client traffic secret",
4✔
326
                                sl->secrets.at("CLIENT_HANDSHAKE_TRAFFIC_SECRET"),
2✔
327
                                client_handshake_traffic_secret);
328
             result.test_bin_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.test_is_true("self-compatibility", cs->is_compatible_with(cipher));
2✔
336
                     result.test_is_true(
2✔
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.test_is_true("Clients don't expect unprotected alerts after server hello",
1✔
343
                                            !cs->must_expect_unprotected_alert_traffic());
1✔
344
                     } else {
345
                        result.test_is_true("Servers must expect unprotected alerts in response to their server hello",
1✔
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",
2✔
353
                                                              [&] { cs->next_ticket_nonce(); });
4✔
354
                  }),
2✔
355

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

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

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

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

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

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

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

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

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

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

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

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

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

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

453
       CHECK_both("ticket nonce counter counts",
1✔
454
                  [&](Cipher_State* cs, Journaling_Secret_Logger*, Connection_Side, Test::Result& result) {
2✔
455
                     result.test_bin_eq("nonce is 0x00, 0x00", cs->next_ticket_nonce().get(), "0000");
2✔
456
                     result.test_bin_eq("nonce is 0x00, 0x01", cs->next_ticket_nonce().get(), "0001");
2✔
457
                     result.test_bin_eq("nonce is 0x00, 0x02", cs->next_ticket_nonce().get(), "0002");
2✔
458

459
                     for(uint32_t i = 3; i <= std::numeric_limits<uint16_t>::max(); ++i) {
131,068✔
460
                        cs->next_ticket_nonce();
262,132✔
461
                     }
462

463
                     // Cannot generate more than 2^16 ticket nonces
464
                     result.test_throws<Botan::Invalid_State>("nonces are depleted", [&] { cs->next_ticket_nonce(); });
4✔
465
                  }),
2✔
466

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

475
       CHECK_both("key update",
1✔
476
                  [&](Cipher_State* cs, Journaling_Secret_Logger* sl, Connection_Side side, Test::Result& result) {
2✔
477
                     const auto* const read_label =
2✔
478
                        side == Connection_Side::Client ? "SERVER_TRAFFIC_SECRET_1" : "CLIENT_TRAFFIC_SECRET_1";
479
                     const auto* const write_label =
1✔
480
                        side == Connection_Side::Client ? "CLIENT_TRAFFIC_SECRET_1" : "SERVER_TRAFFIC_SECRET_1";
481

482
                     cs->update_read_keys(*sl);
2✔
483
                     result.test_sz_eq("read secret update is here", sl->secrets.size(), 6);
2✔
484
                     result.require("has new read traffic secret", sl->secrets.contains(read_label));
2✔
485

486
                     cs->update_write_keys(*sl);
2✔
487
                     result.test_sz_eq("write secret update is here", sl->secrets.size(), 7);
2✔
488
                     result.require("has new write traffic secret", sl->secrets.contains(write_label));
2✔
489

490
                     result.test_bin_eq("client traffic secret (1)",
4✔
491
                                        sl->secrets.at("CLIENT_TRAFFIC_SECRET_1"),
2✔
492
                                        updated_client_traffic_secret);
493
                     result.test_bin_eq("server traffic secret (1)",
4✔
494
                                        sl->secrets.at("SERVER_TRAFFIC_SECRET_1"),
2✔
495
                                        updated_server_traffic_secret);
496

497
                     result.test_is_true("can encrypt application traffic", cs->can_encrypt_application_traffic());
2✔
498
                  }),
2✔
499

500
       CHECK_both("cleanup", [&](Cipher_State* cs, Journaling_Secret_Logger*, Connection_Side, Test::Result& result) {
1✔
501
          // cleanup
502
          cs->clear_write_keys();
2✔
503
          result.test_is_true("can no longer write application data", !cs->can_encrypt_application_traffic());
2✔
504
          result.test_is_true("can still read application data", cs->can_decrypt_application_traffic());
2✔
505

506
          cs->clear_read_keys();
2✔
507
          result.test_is_true("can no longer write application data", !cs->can_encrypt_application_traffic());
2✔
508
          result.test_is_true("can no longer read application data", !cs->can_decrypt_application_traffic());
2✔
509
       })});
9✔
510
}
8✔
511

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

587
   // this is not part of RFC 8448
588
   const std::string export_label = "export_test_label";
1✔
589
   const std::string export_context = "rfc8448_psk";
1✔
590
   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✔
591

592
   // this is not part of RFC 8448
593
   const std::string early_export_label = "export_test_label_early";
1✔
594
   const std::string early_export_context = "rfc8448_psk_early";
1✔
595
   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✔
596

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

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

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

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

656
   auto cipher = Ciphersuite::from_name("AES_128_GCM_SHA256").value();
1✔
657

658
   Journaling_Secret_Logger sl_client;
1✔
659
   Journaling_Secret_Logger sl_server;
1✔
660

661
   auto cs_client = Cipher_State::init_with_psk(Connection_Side::Client,
1✔
662
                                                Cipher_State::PSK_Type::Resumption,
663
                                                secure_vector<uint8_t>(psk.begin(), psk.end()),
2✔
664
                                                cipher.prf_algo());
1✔
665
   auto cs_server = Cipher_State::init_with_psk(Connection_Side::Server,
1✔
666
                                                Cipher_State::PSK_Type::Resumption,
667
                                                secure_vector<uint8_t>(psk.begin(), psk.end()),
2✔
668
                                                cipher.prf_algo());
1✔
669

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

672
   return Test::flatten_result_lists(
6✔
673
      {CHECK_both("no secrets logged for PSK initialization",
1✔
674
                  [&](Cipher_State*, Journaling_Secret_Logger* sl, Connection_Side, Test::Result& result) {
2✔
675
                     result.test_sz_eq("no secrets logged", sl->secrets.size(), 0);
2✔
676
                  }),
677

678
       CHECK_both("calculating PSK binder",
1✔
679
                  [&](Cipher_State* cs, Journaling_Secret_Logger*, Connection_Side, Test::Result& result) {
2✔
680
                     const auto mac = cs->psk_binder_mac(th_client_hello_prefix);
2✔
681
                     result.test_bin_eq("PSK binder is as expected", mac, expected_psk_binder);
2✔
682
                  }),
2✔
683

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

693
                     result.test_is_true(
2✔
694
                        "partially defined state is not compatible with other hashes or protocol versions",
695
                        !cs->is_compatible_with(Ciphersuite::from_name("PSK_WITH_AES_128_GCM_SHA256").value()) &&
6✔
696
                           !cs->is_compatible_with(Ciphersuite::from_name("AES_256_GCM_SHA384").value()));
4✔
697
                  }),
2✔
698

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

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

716
                     result.test_sz_eq("logged early secrets", sl->secrets.size(), 1);
2✔
717
                     result.require("has early exporter secret", sl->secrets.contains("EARLY_EXPORTER_MASTER_SECRET"));
2✔
718
                     result.test_bin_eq(
4✔
719
                        "early exporter secret", sl->secrets.at("EARLY_EXPORTER_MASTER_SECRET"), early_exporter_secret);
2✔
720

721
                     // TODO: Once 0-RTT traffic is implemented this will likely allow handling of
722
                     //       application traffic in this state.
723
                     result.test_is_true("can not yet write application data", !cs->can_encrypt_application_traffic());
2✔
724
                     result.test_is_true("can not yet read application data", !cs->can_decrypt_application_traffic());
2✔
725
                  }),
2✔
726

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

731
                     // decrypt encrypted extensions from server
732
                     encrypted_extensions.xxcrypt(result, cs, side);
2✔
733

734
                     // check the logged key material
735
                     result.test_sz_eq("contains expected number of keys", sl->secrets.size(), 3);
2✔
736
                     result.require("has client handshake traffic secret",
2✔
737
                                    sl->secrets.contains("CLIENT_HANDSHAKE_TRAFFIC_SECRET"));
2✔
738
                     result.require("has server handshake traffic secret",
2✔
739
                                    sl->secrets.contains("SERVER_HANDSHAKE_TRAFFIC_SECRET"));
2✔
740
                     result.test_bin_eq("client handshake traffic secret",
4✔
741
                                        sl->secrets.at("CLIENT_HANDSHAKE_TRAFFIC_SECRET"),
2✔
742
                                        client_handshake_traffic_secret);
743
                     result.test_bin_eq("server handshake traffic secret",
4✔
744
                                        sl->secrets.at("SERVER_HANDSHAKE_TRAFFIC_SECRET"),
2✔
745
                                        server_handshake_traffic_secret);
746

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

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

766
                     result.test_is_true("cannot read application data", !cs->can_decrypt_application_traffic());
2✔
767
                     result.test_is_true("cannot write application data", !cs->can_encrypt_application_traffic());
2✔
768

769
                     // advance Cipher_State with client_hello...server_Finished
770
                     // (allows receiving of application data, but no such sending)
771
                     result.test_no_throw("state advancement is legal",
2✔
772
                                          [&] { cs->advance_with_server_finished(th_server_finished, *sl); });
4✔
773

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

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

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

810
                     // encrypt client Finished message by client
811
                     // (under the client handshake traffic secret)
812
                     encrypted_client_finished_message.xxcrypt(result, cs, side);
2✔
813
                  }),
2✔
814

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

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

831
                     // encrypt application data by client
832
                     encrypted_application_data_client.xxcrypt(result, cs, side);
2✔
833

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

840
BOTAN_REGISTER_TEST_FN("tls",
841
                       "tls_cipher_state",
842
                       test_secret_derivation_rfc8448_rtt1,
843
                       test_secret_derivation_rfc8448_rtt0);
844
}  // namespace
845

846
}  // namespace Botan_Tests
847

848
#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