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