1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
|
/*
* (C) 2016 Juraj Somorovsky
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#include "tests.h"
#if defined(BOTAN_HAS_TLS)
#include <exception>
#include <botan/hex.h>
#include <botan/mac.h>
#include <botan/tls_ciphersuite.h>
#include <botan/tls_handshake_msg.h>
#include <botan/tls_messages.h>
#include <botan/tls_alert.h>
#endif
namespace Botan_Tests {
namespace {
#if defined(BOTAN_HAS_TLS)
Test::Result test_hello_verify_request()
{
Test::Result result("hello_verify_request construction");
std::vector<uint8_t> test_data;
std::vector<uint8_t> key_data(32);
Botan::SymmetricKey sk(key_data);
// Compute cookie over an empty string with an empty test data
Botan::TLS::Hello_Verify_Request hfr(test_data, "", sk);
// Compute HMAC
std::unique_ptr<Botan::MessageAuthenticationCode> hmac(Botan::MessageAuthenticationCode::create("HMAC(SHA-256)"));
hmac->set_key(sk);
hmac->update_be(size_t(0));
hmac->update_be(size_t(0));
std::vector<uint8_t> test = unlock(hmac->final());
result.test_eq("Cookie comparison", hfr.cookie(), test);
return result;
}
class TLS_Message_Parsing_Test final : public Text_Based_Test
{
public:
TLS_Message_Parsing_Test()
: Text_Based_Test("tls", "Buffer,Protocol,Ciphersuite,AdditionalData,Name,Exception") {}
Test::Result run_one_test(const std::string& algo, const VarMap& vars) override
{
const std::vector<uint8_t> buffer = vars.get_req_bin("Buffer");
const std::vector<uint8_t> protocol = vars.get_opt_bin("Protocol");
const std::vector<uint8_t> ciphersuite = vars.get_opt_bin("Ciphersuite");
const std::string exception = vars.get_req_str("Exception");
const std::string expected_name = vars.get_opt_str("Name", "");
const bool is_positive_test = exception.empty();
Test::Result result(algo + " parsing");
if(is_positive_test)
{
try
{
if(algo == "cert_verify")
{
Botan::TLS::Protocol_Version pv(protocol[0], protocol[1]);
Botan::TLS::Certificate_Verify message(buffer, pv);
}
else if(algo == "client_hello")
{
const std::string extensions = vars.get_req_str("AdditionalData");
Botan::TLS::Protocol_Version pv(protocol[0], protocol[1]);
Botan::TLS::Client_Hello message(buffer);
result.test_eq("Protocol version", message.version().to_string(), pv.to_string());
std::vector<uint8_t> buf;
for(Botan::TLS::Handshake_Extension_Type const& type : message.extension_types())
{
uint16_t u16type = static_cast<uint16_t>(type);
buf.push_back(Botan::get_byte(0, u16type));
buf.push_back(Botan::get_byte(1, u16type));
}
result.test_eq("Hello extensions", Botan::hex_encode(buf), extensions);
}
else if(algo == "hello_verify")
{
Botan::TLS::Hello_Verify_Request message(buffer);
}
else if(algo == "hello_request")
{
Botan::TLS::Hello_Request message(buffer);
}
else if(algo == "new_session_ticket")
{
Botan::TLS::New_Session_Ticket message(buffer);
}
else if(algo == "server_hello")
{
const std::string extensions = vars.get_req_str("AdditionalData");
Botan::TLS::Protocol_Version pv(protocol[0], protocol[1]);
Botan::TLS::Ciphersuite cs = Botan::TLS::Ciphersuite::by_id(Botan::make_uint16(ciphersuite[0], ciphersuite[1]));
Botan::TLS::Server_Hello message(buffer);
result.test_eq("Protocol version", message.version().to_string(), pv.to_string());
result.confirm("Ciphersuite", (message.ciphersuite() == cs.ciphersuite_code()));
std::vector<uint8_t> buf;
for(Botan::TLS::Handshake_Extension_Type const& type : message.extension_types())
{
uint16_t u16type = static_cast<uint16_t>(type);
buf.push_back(Botan::get_byte(0, u16type));
buf.push_back(Botan::get_byte(1, u16type));
}
result.test_eq("Hello extensions", Botan::hex_encode(buf), extensions);
}
else if(algo == "alert")
{
Botan::secure_vector<uint8_t> sb(buffer.begin(), buffer.end());
Botan::TLS::Alert message(sb);
result.test_lt("Alert type vectors result to UNKNOWN_CA or ACCESS_DENIED, which is shorter than 15",
message.type_string().size(), 15);
}
else if(algo == "cert_status")
{
Botan::TLS::Certificate_Status message(buffer);
std::shared_ptr<const Botan::OCSP::Response> resp = message.response();
if(result.confirm("Decoded response", resp != nullptr))
{
const std::vector<std::string> CNs = resp->signer_name().get_attribute("CN");
// This is not requird by OCSP protocol, we are just using it as a test here
if(result.test_eq("OCSP response has signer name", CNs.size(), 1))
{
result.test_eq("Expected name", CNs[0], expected_name);
}
}
}
else
{
throw Test_Error("Unknown message type " + algo + " in TLS parsing tests");
}
result.test_success("Correct parsing");
}
catch(std::exception& e)
{
result.test_failure(e.what());
}
}
else
{
if(algo == "cert_verify")
{
Botan::TLS::Protocol_Version pv(protocol[0], protocol[1]);
result.test_throws("invalid cert_verify input", exception, [&buffer, &pv]()
{
Botan::TLS::Certificate_Verify message(buffer, pv);
});
}
else if(algo == "client_hello")
{
result.test_throws("invalid client_hello input", exception, [&buffer]()
{
Botan::TLS::Client_Hello message(buffer);
});
}
else if(algo == "hello_verify")
{
result.test_throws("invalid hello_verify input", exception, [&buffer]()
{
Botan::TLS::Hello_Verify_Request message(buffer);
});
}
else if(algo == "hello_request")
{
result.test_throws("invalid hello_request input", exception, [&buffer]()
{
Botan::TLS::Hello_Request message(buffer);
});
}
else if(algo == "cert_status")
{
result.test_throws("invalid cert_status input", exception, [&buffer]()
{
Botan::TLS::Certificate_Status message(buffer);
});
}
else if(algo == "new_session_ticket")
{
result.test_throws("invalid new_session_ticket input", exception, [&buffer]()
{
Botan::TLS::New_Session_Ticket message(buffer);
});
}
else if(algo == "server_hello")
{
result.test_throws("invalid server_hello input", exception, [&buffer]()
{
Botan::TLS::Server_Hello message(buffer);
});
}
else if(algo == "alert")
{
result.test_throws("invalid alert input", exception, [&buffer]()
{
Botan::secure_vector<uint8_t> sb(buffer.begin(), buffer.end());
Botan::TLS::Alert message(sb);
});
}
else
{
throw Test_Error("Unknown message type " + algo + " in TLS parsing tests");
}
}
return result;
}
std::vector<Test::Result> run_final_tests() override
{
std::vector<Test::Result> results;
results.push_back(test_hello_verify_request());
return results;
}
};
BOTAN_REGISTER_TEST("tls_messages", TLS_Message_Parsing_Test);
#endif
}
}
|