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