1 /*
2 * (C) 2019 Jack Lloyd
3 *
4 * Botan is released under the Simplified BSD License (see license.txt)
5 */
6 
7 /*
8 * This is a shim for testing Botan against BoringSSL's test TLS stack (BoGo).
9 *
10 * Instructions on use should go here.
11 */
12 
13 #include <botan/tls_client.h>
14 #include <botan/tls_server.h>
15 #include <botan/tls_exceptn.h>
16 #include <botan/tls_algos.h>
17 #include <botan/data_src.h>
18 #include <botan/pkcs8.h>
19 #include <botan/loadstor.h>
20 #include <botan/oids.h>
21 #include <botan/chacha_rng.h>
22 #include <botan/base64.h>
23 #include <botan/hex.h>
24 #include <botan/parsing.h>
25 #include <botan/mem_ops.h>
26 #include <iostream>
27 #include <vector>
28 #include <string>
29 #include <map>
30 #include <set>
31 #include <ctime>
32 #include <unordered_map>
33 
34 #if defined(BOTAN_TARGET_OS_HAS_SOCKETS)
35   #include <sys/socket.h>
36   #include <sys/time.h>
37   #include <netinet/in.h>
38   #include <netdb.h>
39   #include <string.h>
40   #include <unistd.h>
41   #include <errno.h>
42   #include <fcntl.h>
43 #endif
44 
45 namespace {
46 
shim_output(const std::string & s,int rc=0)47 int shim_output(const std::string& s, int rc = 0)
48    {
49    std::cout << s << "\n";
50    return rc;
51    }
52 
shim_log(const std::string & s)53 void shim_log(const std::string& s)
54    {
55    if(::getenv("BOTAN_BOGO_SHIM_LOG"))
56       {
57       static FILE* log = std::fopen("/tmp/bogo_shim.log", "w");
58       struct timeval tv;
59       ::gettimeofday(&tv, nullptr);
60       std::fprintf(log, "%lld.%lu: %s\n", static_cast<unsigned long long>(tv.tv_sec), tv.tv_usec, s.c_str());
61       std::fflush(log);
62       }
63    }
64 
shim_exit_with_error(const std::string & s,int rc=1)65 void BOTAN_NORETURN shim_exit_with_error(const std::string& s, int rc = 1)
66    {
67    shim_log("Exiting with " + s);
68    std::cerr << s << "\n";
69    std::exit(rc);
70    }
71 
map_to_bogo_error(const std::string & e)72 std::string map_to_bogo_error(const std::string& e)
73    {
74    shim_log("Original error " + e);
75 
76    static const std::unordered_map<std::string, std::string> err_map
77       {
78          { "Application data before handshake done", ":APPLICATION_DATA_INSTEAD_OF_HANDSHAKE:" },
79          { "Bad Hello_Request, has non-zero size", ":BAD_HELLO_REQUEST:" },
80          { "Bad code for TLS alert level", ":UNKNOWN_ALERT_TYPE:" },
81          { "Bad extension size", ":DECODE_ERROR:" },
82          { "Bad length in hello verify request", ":DECODE_ERROR:" },
83          { "Bad lengths in DTLS header", ":BAD_HANDSHAKE_RECORD:" },
84          { "Bad signature on server key exchange", ":BAD_SIGNATURE:" },
85          { "Bad size (1) for TLS alert message", ":BAD_ALERT:" },
86          { "Bad size (4) for TLS alert message", ":BAD_ALERT:" },
87          { "CERTIFICATE decoding failed with PEM: No PEM header found", ":CANNOT_PARSE_LEAF_CERT:" },
88          { "Can't agree on a ciphersuite with client", ":NO_SHARED_CIPHER:" },
89          { "Can't interleave application and handshake data", ":UNEXPECTED_RECORD:" },
90          { "Certificate chain exceeds policy specified maximum size", ":EXCESSIVE_MESSAGE_SIZE:" },
91          { "Certificate key type did not match ciphersuite", ":WRONG_CERTIFICATE_TYPE:" },
92          { "Certificate usage constraints do not allow this ciphersuite", ":KEY_USAGE_BIT_INCORRECT:" },
93          { "Certificate: Message malformed", ":DECODE_ERROR:" },
94          { "Channel::key_material_export cannot export during renegotiation", "failed to export keying material" },
95          { "Client cert verify failed", ":BAD_SIGNATURE:" },
96          { "Client did not offer NULL compression", ":INVALID_COMPRESSION_LIST:" },
97          { "Client offered TLS version with major version under 3", ":UNSUPPORTED_PROTOCOL:" },
98          { "Client offered DTLS version with major version 0xFF",  ":UNSUPPORTED_PROTOCOL:" },
99          { "Client policy prohibits insecure renegotiation", ":RENEGOTIATION_MISMATCH:" },
100          { "Client policy prohibits renegotiation", ":NO_RENEGOTIATION:" },
101          { "Client resumed extended ms session without sending extension", ":RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION:" },
102          { "Client signalled fallback SCSV, possible attack", ":INAPPROPRIATE_FALLBACK:" },
103          { "Client version DTLS v1.0 is unacceptable by policy", ":UNSUPPORTED_PROTOCOL:" },
104          { "Client version TLS v1.0 is unacceptable by policy", ":UNSUPPORTED_PROTOCOL:" },
105          { "Client version TLS v1.1 is unacceptable by policy", ":UNSUPPORTED_PROTOCOL:" },
106          { "Client: No certificates sent by server", ":DECODE_ERROR:" },
107          { "Counterparty sent inconsistent key and sig types", ":WRONG_SIGNATURE_TYPE:" },
108          { "Downgrade attack detected", ":TLS13_DOWNGRADE:" },
109          { "Empty ALPN protocol not allowed", ":PARSE_TLSEXT:" },
110          { "Encoding error: Cannot encode PSS string, output length too small", ":NO_COMMON_SIGNATURE_ALGORITHMS:" },
111          { "Expected TLS but got a record with DTLS version", ":WRONG_VERSION_NUMBER:" },
112          { "Finished message didn't verify", ":DIGEST_CHECK_FAILED:" },
113          { "Got unexpected TLS record version", ":WRONG_VERSION_NUMBER:" },
114          { "Inconsistent length in certificate request", ":DECODE_ERROR:" },
115          { "Inconsistent values in fragmented DTLS handshake header", ":FRAGMENT_MISMATCH:" },
116          { "Invalid CertificateRequest: Length field outside parameters", ":DECODE_ERROR:" },
117          { "Invalid CertificateVerify: Extra bytes at end of message", ":DECODE_ERROR:" },
118          { "Invalid Certificate_Status: invalid length field", ":DECODE_ERROR:" },
119          { "Invalid ChangeCipherSpec", ":BAD_CHANGE_CIPHER_SPEC:" },
120          { "Invalid ClientHello: Length field outside parameters", ":DECODE_ERROR:" },
121          { "Invalid ClientKeyExchange: Extra bytes at end of message", ":DECODE_ERROR:" },
122          { "Invalid ServerKeyExchange: Extra bytes at end of message", ":DECODE_ERROR:" },
123          { "Invalid SessionTicket: Extra bytes at end of message", ":DECODE_ERROR:" },
124          { "Invalid authentication tag: ChaCha20Poly1305 tag check failed", ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:" },
125          { "Invalid authentication tag: GCM tag check failed", ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:" },
126          { "Message authentication failure", ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:" },
127          { "No shared TLS version", ":UNSUPPORTED_PROTOCOL:" },
128          { "No shared DTLS version", ":UNSUPPORTED_PROTOCOL:" },
129          { "OS2ECP: Unknown format type 251", ":BAD_ECPOINT:" },
130          { "Policy forbids all available TLS version", ":NO_SUPPORTED_VERSIONS_ENABLED:" },
131          { "Policy forbids all available DTLS version", ":NO_SUPPORTED_VERSIONS_ENABLED:" },
132          { "Policy refuses to accept signing with any hash supported by peer", ":NO_COMMON_SIGNATURE_ALGORITHMS:" },
133          { "Policy requires client send a certificate, but it did not", ":PEER_DID_NOT_RETURN_A_CERTIFICATE:" },
134          { "Received a record that exceeds maximum size", ":ENCRYPTED_LENGTH_TOO_LONG:" },
135          { "Received unexpected record version in initial record", ":WRONG_VERSION_NUMBER:" },
136          { "Received unexpected record version", ":WRONG_VERSION_NUMBER:" },
137          { "Received application data after connection closure", ":APPLICATION_DATA_ON_SHUTDOWN:" },
138          { "Received handshake data after connection closure", ":NO_RENEGOTIATION:" },
139          { "Server certificate changed during renegotiation", ":SERVER_CERT_CHANGED:" },
140          { "Server changed its mind about extended master secret", ":RENEGOTIATION_EMS_MISMATCH:" },
141          { "Server changed its mind about secure renegotiation", ":RENEGOTIATION_MISMATCH:" },
142          { "Server changed version after renegotiation", ":WRONG_SSL_VERSION:" },
143          { "Server downgraded version after renegotiation", ":WRONG_SSL_VERSION:" },
144          { "Server policy prohibits renegotiation", ":NO_RENEGOTIATION:" },
145          { "Server replied using a ciphersuite not allowed in version it offered", ":WRONG_CIPHER_RETURNED:" },
146          { "Server replied with DTLS-SRTP alg we did not send", ":BAD_SRTP_PROTECTION_PROFILE_LIST:" },
147          { "Server replied with ciphersuite we didn't send", ":WRONG_CIPHER_RETURNED:" },
148          { "Server replied with later version than client offered", ":UNSUPPORTED_PROTOCOL:" },
149          { "Server replied with non-null compression method", ":UNSUPPORTED_COMPRESSION_ALGORITHM:" },
150          { "Server replied with some unknown ciphersuite", ":UNKNOWN_CIPHER_RETURNED:" },
151          { "Server replied with unsupported extensions: 0", ":UNEXPECTED_EXTENSION:" },
152          { "Server replied with unsupported extensions: 1234", ":UNEXPECTED_EXTENSION:" },
153          { "Server replied with unsupported extensions: 16", ":UNEXPECTED_EXTENSION:" },
154          { "Server replied with unsupported extensions: 43", ":UNEXPECTED_EXTENSION:" },
155          { "Server replied with unsupported extensions: 5", ":UNEXPECTED_EXTENSION:" },
156          { "Server resumed session and removed extended master secret", ":RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION:" },
157          { "Server resumed session but added extended master secret", ":RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION:" },
158          { "Server resumed session but with wrong version", ":OLD_SESSION_VERSION_NOT_RETURNED:" },
159          { "Server sent ECC curve prohibited by policy", ":WRONG_CURVE:" },
160          { "Server sent an unsupported extension", ":UNEXPECTED_EXTENSION:" },
161          { "Server sent bad values for secure renegotiation", ":RENEGOTIATION_MISMATCH:" },
162          { "Server version DTLS v1.0 is unacceptable by policy", ":UNSUPPORTED_PROTOCOL:" },
163          { "Server version TLS v1.0 is unacceptable by policy", ":UNSUPPORTED_PROTOCOL:" },
164          { "Server version TLS v1.1 is unacceptable by policy", ":UNSUPPORTED_PROTOCOL:" },
165          { "Server_Hello_Done: Must be empty, and is not", ":DECODE_ERROR:" },
166          { "Simulated OCSP callback failure", ":OCSP_CB_ERROR:" },
167          { "Simulating cert verify callback failure", ":CERT_CB_ERROR:" },
168          { "Simulating failure from OCSP response callback", ":OCSP_CB_ERROR:" },
169          { "TLS plaintext record is larger than allowed maximum", ":DATA_LENGTH_TOO_LONG:" },
170          { "TLS signature extension did not allow for RSA/SHA-256 signature", ":WRONG_SIGNATURE_TYPE:", },
171          { "Test requires rejecting cert", ":CERTIFICATE_VERIFY_FAILED:" },
172          { "Unexpected ALPN protocol", ":INVALID_ALPN_PROTOCOL:" },
173          { "Unexpected record type 42 from counterparty", ":UNEXPECTED_RECORD:" },
174 
175          { "Unexpected state transition in handshake got a certificate_request expected server_hello_done seen server_hello+server_key_exchange", ":UNEXPECTED_MESSAGE:" },
176          { "Unexpected state transition in handshake got a certificate_request expected server_key_exchange|server_hello_done seen server_hello", ":UNEXPECTED_MESSAGE:" },
177          { "Unexpected state transition in handshake got a certificate_status expected certificate seen server_hello", ":UNEXPECTED_MESSAGE:" },
178          { "Unexpected state transition in handshake got a change_cipher_spec expected certificate_verify seen client_hello+certificate+client_key_exchange", ":UNEXPECTED_RECORD:" },
179          { "Unexpected state transition in handshake got a change_cipher_spec expected client_key_exchange seen client_hello", ":UNEXPECTED_RECORD:" },
180          { "Unexpected state transition in handshake got a change_cipher_spec expected new_session_ticket seen server_hello+certificate+certificate_status+server_key_exchange+server_hello_done", ":UNEXPECTED_RECORD:" },
181          { "Unexpected state transition in handshake got a client_key_exchange expected certificate seen client_hello", ":UNEXPECTED_MESSAGE:" },
182          { "Unexpected state transition in handshake got a finished expected change_cipher_spec seen client_hello", ":UNEXPECTED_RECORD:" },
183          { "Unexpected state transition in handshake got a finished expected change_cipher_spec seen client_hello+client_key_exchange", ":UNEXPECTED_RECORD:" },
184          { "Unexpected state transition in handshake got a finished expected change_cipher_spec seen server_hello", ":UNEXPECTED_RECORD:" },
185          { "Unexpected state transition in handshake got a finished expected change_cipher_spec seen server_hello+certificate+certificate_status+server_key_exchange+server_hello_done+new_session_ticket", ":UNEXPECTED_RECORD:" },
186          { "Unexpected state transition in handshake got a hello_request expected server_hello", ":UNEXPECTED_MESSAGE:" },
187          { "Unexpected state transition in handshake got a server_hello_done expected server_key_exchange seen server_hello+certificate+certificate_status", ":UNEXPECTED_MESSAGE:" },
188          { "Unexpected state transition in handshake got a server_key_exchange not expecting messages", ":BAD_HELLO_REQUEST:" },
189          { "Unexpected state transition in handshake got a server_key_exchange expected certificate_request|server_hello_done seen server_hello+certificate+certificate_status", ":UNEXPECTED_MESSAGE:" },
190 
191          { "Unknown TLS handshake message type 43", ":UNEXPECTED_MESSAGE:" },
192          { "Unknown TLS handshake message type 44", ":UNEXPECTED_MESSAGE:" },
193          { "Unknown TLS handshake message type 45", ":UNEXPECTED_MESSAGE:" },
194          { "Unknown TLS handshake message type 46", ":UNEXPECTED_MESSAGE:" },
195          { "Unknown TLS handshake message type 53", ":UNEXPECTED_MESSAGE:" },
196          { "Unknown TLS handshake message type 54", ":UNEXPECTED_MESSAGE:" },
197          { "Unknown TLS handshake message type 55", ":UNEXPECTED_MESSAGE:" },
198          { "Unknown TLS handshake message type 56", ":UNEXPECTED_MESSAGE:" },
199          { "Unknown TLS handshake message type 57", ":UNEXPECTED_MESSAGE:" },
200          { "Unknown TLS handshake message type 58", ":UNEXPECTED_MESSAGE:" },
201          { "Unknown TLS handshake message type 6", ":UNEXPECTED_MESSAGE:" },
202          { "Unknown TLS handshake message type 62", ":UNEXPECTED_MESSAGE:" },
203          { "Unknown TLS handshake message type 64", ":UNEXPECTED_MESSAGE:" },
204          { "signature_algorithm_of_scheme: Unknown signature algorithm enum", ":WRONG_SIGNATURE_TYPE:" },
205       };
206 
207    auto err_map_i = err_map.find(e);
208    if(err_map_i != err_map.end())
209       return err_map_i->second;
210 
211    return "Unmapped error: '" + e + "'";
212    }
213 
214 class Shim_Exception final : public std::exception
215    {
216    public:
Shim_Exception(const std::string & msg,int rc=1)217       Shim_Exception(const std::string& msg, int rc = 1) :
218          m_msg(msg), m_rc(rc) {}
219 
what() const220       const char* what() const noexcept override { return m_msg.c_str(); }
221 
rc() const222       int rc() const { return m_rc; }
223    private:
224       const std::string m_msg;
225       int m_rc;
226    };
227 
228 #if defined(BOTAN_TARGET_OS_HAS_SOCKETS)
229 
230 class Shim_Socket final
231    {
232    private:
233       typedef int socket_type;
234       typedef ssize_t socket_op_ret_type;
close_socket(socket_type s)235       static void close_socket(socket_type s) { ::close(s); }
get_last_socket_error()236       static std::string get_last_socket_error() { return ::strerror(errno); }
237 
238    public:
Shim_Socket(const std::string & hostname,int port)239       Shim_Socket(const std::string& hostname, int port) : m_socket(-1)
240          {
241          addrinfo hints;
242          std::memset(&hints, 0, sizeof(hints));
243          hints.ai_family = AF_UNSPEC;
244          hints.ai_socktype = SOCK_STREAM;
245          hints.ai_flags = AI_NUMERICSERV;
246          addrinfo* res;
247 
248          const std::string service = std::to_string(port);
249          int rc = ::getaddrinfo(hostname.c_str(), service.c_str(), &hints, &res);
250          shim_log("Connecting " + hostname + ":" + service);
251 
252          if(rc != 0)
253             {
254             throw Shim_Exception("Name resolution failed for " + hostname);
255             }
256 
257          for(addrinfo* rp = res; (m_socket == -1) && (rp != nullptr); rp = rp->ai_next)
258             {
259             if(rp->ai_family != AF_INET && rp->ai_family != AF_INET6)
260                continue;
261 
262             m_socket = ::socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
263 
264             if(m_socket == -1)
265                {
266                // unsupported socket type?
267                continue;
268                }
269 
270             int err = ::connect(m_socket, rp->ai_addr, rp->ai_addrlen);
271 
272             if(err != 0)
273                {
274                ::close(m_socket);
275                m_socket = -1;
276                }
277             }
278 
279          if(m_socket < 0)
280             throw Shim_Exception("Failed to connect to host");
281          }
282 
~Shim_Socket()283       ~Shim_Socket()
284          {
285          ::close(m_socket);
286          m_socket = -1;
287          }
288 
write(const uint8_t buf[],size_t len)289       void write(const uint8_t buf[], size_t len)
290          {
291          if(m_socket < 0)
292             throw Shim_Exception("Socket was bad on write");
293          size_t sent_so_far = 0;
294          while(sent_so_far != len)
295             {
296             const size_t left = len - sent_so_far;
297             socket_op_ret_type sent = ::send(m_socket, Botan::cast_uint8_ptr_to_char(&buf[sent_so_far]), left, MSG_NOSIGNAL);
298             if(sent < 0)
299                {
300                if(errno == EPIPE)
301                   return;
302                else
303                   throw Shim_Exception("Socket write failed", errno);
304                }
305             else
306                sent_so_far += static_cast<size_t>(sent);
307             }
308          }
309 
read(uint8_t buf[],size_t len)310       size_t read(uint8_t buf[], size_t len)
311          {
312          if(m_socket < 0)
313             throw Shim_Exception("Socket was bad on read");
314          socket_op_ret_type got = ::read(m_socket, Botan::cast_uint8_ptr_to_char(buf), len);
315 
316          if(got < 0)
317             {
318             if(errno == ECONNRESET)
319                return 0;
320             throw Shim_Exception("Socket read failed: " + std::string(strerror(errno)));
321             }
322 
323          return static_cast<size_t>(got);
324          }
325 
read_exactly(uint8_t buf[],size_t len)326       void read_exactly(uint8_t buf[], size_t len)
327          {
328          if(m_socket < 0)
329             throw Shim_Exception("Socket was bad on read");
330 
331          while(len > 0)
332             {
333             socket_op_ret_type got = ::read(m_socket, Botan::cast_uint8_ptr_to_char(buf), len);
334 
335             if(got == 0)
336                throw Shim_Exception("Socket read EOF");
337             else if(got < 0)
338                throw Shim_Exception("Socket read failed: " + std::string(strerror(errno)));
339 
340             buf += static_cast<size_t>(got);
341             len -= static_cast<size_t>(got);
342             }
343          }
344 
345    private:
346       socket_type m_socket;
347    };
348 
349 #endif
350 
combine_options(const std::set<std::string> & a,const std::set<std::string> & b,const std::set<std::string> & c,const std::set<std::string> & d)351 std::set<std::string> combine_options(
352    const std::set<std::string>& a,
353    const std::set<std::string>& b,
354    const std::set<std::string>& c,
355    const std::set<std::string>& d)
356    {
357    std::set<std::string> combined;
358 
359    for(auto i : a)
360       combined.insert(i);
361    for(auto i : b)
362       combined.insert(i);
363    for(auto i : c)
364       combined.insert(i);
365    for(auto i : d)
366       combined.insert(i);
367 
368    return combined;
369    }
370 
371 class Shim_Arguments final
372    {
373    public:
Shim_Arguments(const std::set<std::string> & flags,const std::set<std::string> & string_opts,const std::set<std::string> & base64_opts,const std::set<std::string> & int_opts,const std::set<std::string> & int_vec_opts)374       Shim_Arguments(const std::set<std::string>& flags,
375                      const std::set<std::string>& string_opts,
376                      const std::set<std::string>& base64_opts,
377                      const std::set<std::string>& int_opts,
378                      const std::set<std::string>& int_vec_opts) :
379          m_flags(flags),
380          m_string_opts(string_opts),
381          m_base64_opts(base64_opts),
382          m_int_opts(int_opts),
383          m_int_vec_opts(int_vec_opts),
384          m_all_options(combine_options(string_opts, base64_opts, int_opts, int_vec_opts))
385          {}
386 
387       void parse_args(char* argv[]);
388 
flag_set(const std::string & flag) const389       bool flag_set(const std::string& flag) const
390          {
391          if(m_flags.count(flag) == 0)
392             throw Shim_Exception("Unknown bool flag " + flag);
393 
394          return m_parsed_flags.count(flag);
395          }
396 
test_name() const397       std::string test_name() const
398          {
399          return get_string_opt("test-name");
400          }
401 
get_string_opt(const std::string & key) const402       std::string get_string_opt(const std::string& key) const
403          {
404          if(m_string_opts.count(key) == 0)
405             throw Shim_Exception("Unknown string key " + key);
406          return get_opt(key);
407          }
408 
get_string_opt_or_else(const std::string & key,const std::string & def) const409       std::string get_string_opt_or_else(const std::string& key, const std::string& def) const
410          {
411          if(m_string_opts.count(key) == 0)
412             throw Shim_Exception("Unknown string key " + key);
413          if(!option_used(key))
414             return def;
415          return get_opt(key);
416          }
417 
get_b64_opt(const std::string & key) const418       std::vector<uint8_t> get_b64_opt(const std::string& key) const
419          {
420          if(m_base64_opts.count(key) == 0)
421             throw Shim_Exception("Unknown base64 key " + key);
422          return Botan::unlock(Botan::base64_decode(get_opt(key)));
423          }
424 
get_int_opt(const std::string & key) const425       size_t get_int_opt(const std::string& key) const
426          {
427          if(m_int_opts.count(key) == 0)
428             throw Shim_Exception("Unknown int key " + key);
429          return Botan::to_u32bit(get_opt(key));
430          }
431 
get_int_opt_or_else(const std::string & key,size_t def) const432       size_t get_int_opt_or_else(const std::string& key, size_t def) const
433          {
434          if(m_int_opts.count(key) == 0)
435             throw Shim_Exception("Unknown int key " + key);
436          if(!option_used(key))
437             return def;
438 
439          return Botan::to_u32bit(get_opt(key));
440          }
441 
get_int_vec_opt(const std::string & key) const442       std::vector<size_t> get_int_vec_opt(const std::string& key) const
443          {
444          if(m_int_vec_opts.count(key) == 0)
445             throw Shim_Exception("Unknown int vec key " + key);
446 
447          auto i = m_parsed_int_vec_opts.find(key);
448          if(i == m_parsed_int_vec_opts.end())
449             return std::vector<size_t>();
450          else
451             return i->second;
452          }
453 
get_alpn_string_vec_opt(const std::string & option) const454       std::vector<std::string> get_alpn_string_vec_opt(const std::string& option) const
455          {
456          // hack used for alpn list (relies on all ALPNs being 3 chars long...)
457          char delim = 0x03;
458 
459          if(option_used(option))
460             return Botan::split_on(get_string_opt(option), delim);
461          else
462             return std::vector<std::string>();
463          }
464 
option_used(const std::string & key) const465       bool option_used(const std::string& key) const
466          {
467          if(m_all_options.count(key) == 0)
468             throw Shim_Exception("Invalid option " + key);
469          if(m_parsed_opts.find(key) != m_parsed_opts.end())
470             return true;
471          if(m_parsed_int_vec_opts.find(key) != m_parsed_int_vec_opts.end())
472             return true;
473          return false;
474          }
475 
476    private:
get_opt(const std::string & key) const477       std::string get_opt(const std::string& key) const
478          {
479          auto i = m_parsed_opts.find(key);
480          if(i == m_parsed_opts.end())
481             throw Shim_Exception("Option " + key + " was not provided");
482          return i->second;
483          }
484 
485       const std::set<std::string> m_flags;
486       const std::set<std::string> m_string_opts;
487       const std::set<std::string> m_base64_opts;
488       const std::set<std::string> m_int_opts;
489       const std::set<std::string> m_int_vec_opts;
490       const std::set<std::string> m_all_options;
491 
492       std::set<std::string> m_parsed_flags;
493       std::map<std::string, std::string> m_parsed_opts;
494       std::map<std::string, std::vector<size_t>> m_parsed_int_vec_opts;
495    };
496 
parse_args(char * argv[])497 void Shim_Arguments::parse_args(char* argv[])
498    {
499    int i = 1; // skip argv[0]
500 
501    while(argv[i] != nullptr)
502       {
503       const std::string param(argv[i]);
504 
505       if(param.find("-") == 0)
506          {
507          const std::string flag_name = param.substr(1, std::string::npos);
508 
509          if(m_flags.count(flag_name))
510             {
511             shim_log("flag " + flag_name);
512             m_parsed_flags.insert(flag_name);
513             i += 1;
514             }
515          else if(m_all_options.count(flag_name))
516             {
517             if(argv[i+1] == nullptr)
518                throw Shim_Exception("Expected argument following " + param);
519             std::string val(argv[i+1]);
520             shim_log("param " + flag_name + "=" + val);
521 
522             if(m_int_vec_opts.count(flag_name))
523                {
524                const size_t v = Botan::to_u32bit(val);
525                m_parsed_int_vec_opts[flag_name].push_back(v);
526                }
527             else
528                {
529                m_parsed_opts[flag_name] = val;
530                }
531             i += 2;
532             }
533          else
534             {
535             shim_log("Unknown option " + param);
536             throw Shim_Exception("Unknown option " + param, 89);
537             }
538          }
539       else
540          {
541          shim_log("Unknown option " + param);
542          throw Shim_Exception("Unknown option " + param, 89);
543          }
544       }
545    }
546 
parse_options(char * argv[])547 std::unique_ptr<Shim_Arguments> parse_options(char* argv[])
548    {
549    const std::set<std::string> bogo_shim_flags = {
550       "allow-false-start-without-alpn",
551       "allow-unknown-alpn-protos",
552       "async",
553       "cbc-record-splitting",
554       "check-close-notify",
555       "decline-alpn",
556       "decline-ocsp-callback",
557       "dtls",
558       "enable-all-curves",
559       "enable-channel-id",
560       "enable-early-data",
561       "enable-ed25519",
562       "enable-grease",
563       "enable-ocsp-stapling",
564       "enable-signed-cert-timestamps",
565       "enforce-rsa-key-usage",
566       //"expect-accept-early-data",
567       "expect-extended-master-secret",
568       "expect-no-offer-early-data",
569       "expect-no-secure-renegotiation",
570       "expect-no-session",
571       "expect-no-session-id",
572       //"expect-reject-early-data",
573       "expect-secure-renegotiation",
574       "expect-session-id",
575       "expect-session-miss",
576       "expect-sha256-client-cert",
577       "expect-ticket-renewal",
578       "expect-ticket-supports-early-data",
579       //"expect-tls13-downgrade",
580       "expect-verify-result",
581       "expect-no-hrr",
582       //"export-traffic-secrets",
583       "fail-cert-callback",
584       //"fail-ddos-callback",
585       //"fail-early-callback",
586       "fail-ocsp-callback",
587       "fallback-scsv",
588       //"false-start",
589       "forbid-renegotiation-after-handshake",
590       "handoff",
591       "handshake-never-done",
592       "handshake-twice",
593       "handshaker-resume",
594       //"ignore-tls13-downgrade",
595       "implicit-handshake",
596       "install-cert-compression-algs",
597       "install-ddos-callback",
598       "is-handshaker-supported",
599       //"jdk11-workaround",
600       //"key-update",
601       "no-op-extra-handshake",
602       "no-rsa-pss-rsae-certs",
603       "no-ticket",
604       "no-tls1",
605       "no-tls11",
606       "no-tls12",
607       "no-tls13", // implict due to 1.3 not being implemented
608       "on-resume-no-ticket",
609       //"on-resume-verify-fail",
610       //"partial-write",
611       //"peek-then-read",
612       //"read-with-unfinished-write",
613       "renegotiate-freely",
614       "renegotiate-ignore",
615       "renegotiate-once",
616       //"renew-ticket",
617       "require-any-client-certificate",
618       "retain-only-sha256-client-cert",
619       //"reverify-on-resume",
620       "select-empty-alpn",
621       "send-alert",
622       "server",
623       "server-preference",
624       "set-ocsp-in-callback",
625       "shim-shuts-down",
626       "shim-writes-first",
627       //"tls-unique",
628       "use-custom-verify-callback",
629       "use-early-callback",
630       "use-export-context",
631       "use-exporter-between-reads",
632       "use-ocsp-callback",
633       //"use-old-client-cert-callback",
634       //"use-ticket-callback",
635       "verify-fail",
636       "verify-peer",
637       //"verify-peer-if-no-obc",
638       "write-different-record-sizes",
639    };
640 
641    const std::set<std::string> bogo_shim_string_opts = {
642       "advertise-alpn",
643       //"advertise-npn",
644       "cert-file",
645       "cipher",
646       //"delegated-credential",
647       "expect-advertised-alpn",
648       "expect-alpn",
649       "expect-client-ca-list",
650       "expect-late-alpn",
651       "expect-msg-callback",
652       //"expect-next-proto",
653       "expect-peer-cert-file",
654       "expect-server-name",
655       "export-context",
656       "export-label",
657       "handshaker-path",
658       "host-name",
659       "key-file",
660       "psk",
661       "psk-identity",
662       "select-alpn",
663       "select-next-proto",
664       "srtp-profiles",
665       "test-name",
666       "use-client-ca-list",
667       //"send-channel-id",
668       //"write-settings",
669    };
670 
671    const std::set<std::string> bogo_shim_base64_opts = {
672       "expect-certificate-types",
673       //"expect-channel-id",
674       "expect-ocsp-response",
675       //"expect-quic-transport-params",
676       //"expect-signed-cert-timestamps",
677       "ocsp-response",
678       //"quic-transport-params",
679       //"signed-cert-timestamps",
680       //"ticket-key", /* we use a different ticket format from Boring */
681       //"token-binding-params",
682    };
683 
684    const std::set<std::string> bogo_shim_int_opts {
685       "expect-cipher-aes",
686       "expect-cipher-no-aes",
687       "expect-curve-id",
688       "expect-peer-signature-algorithm",
689       "expect-ticket-age-skew",
690       "expect-token-binding-param",
691       "expect-total-renegotiations",
692       "expect-version",
693       //"export-early-keying-material",
694       "export-keying-material",
695       "initial-timeout-duration-ms",
696       "max-cert-list",
697       //"max-send-fragment",
698       "max-version",
699       "min-version",
700       "mtu",
701       "port",
702       "read-size",
703       "resume-count",
704       "resumption-delay",
705    };
706 
707    const std::set<std::string> bogo_shim_int_vec_opts {
708       "curves",
709       "expect-peer-verify-pref",
710       "signing-prefs",
711       "verify-prefs",
712    };
713 
714    std::unique_ptr<Shim_Arguments> args(
715       new Shim_Arguments(bogo_shim_flags,
716                          bogo_shim_string_opts,
717                          bogo_shim_base64_opts,
718                          bogo_shim_int_opts,
719                          bogo_shim_int_vec_opts));
720 
721    // may throw:
722    args->parse_args(argv);
723 
724    return args;
725    }
726 
727 class Shim_Policy final : public Botan::TLS::Policy
728    {
729    public:
Shim_Policy(const Shim_Arguments & args)730       Shim_Policy(const Shim_Arguments& args) : m_args(args), m_sessions(0) {}
731 
incr_session_established()732       void incr_session_established() { m_sessions += 1; }
733 
allowed_ciphers() const734       std::vector<std::string> allowed_ciphers() const override
735          {
736          return {
737             "AES-256/OCB(12)",
738             "AES-128/OCB(12)",
739             "ChaCha20Poly1305",
740             "AES-256/GCM",
741             "AES-128/GCM",
742             "AES-256/CCM",
743             "AES-128/CCM",
744             "AES-256/CCM(8)",
745             "AES-128/CCM(8)",
746             "Camellia-256/GCM",
747             "Camellia-128/GCM",
748             "ARIA-256/GCM",
749             "ARIA-128/GCM",
750             "AES-256",
751             "AES-128",
752             "Camellia-256",
753             "Camellia-128",
754             "SEED",
755             "3DES",
756          };
757 
758          }
759 
allowed_signature_hashes() const760       std::vector<std::string> allowed_signature_hashes() const override
761          {
762          if(m_args.option_used("signing-prefs"))
763             {
764             std::vector<std::string> pref_hash;
765             for(size_t pref : m_args.get_int_vec_opt("signing-prefs"))
766                {
767                const auto scheme = static_cast<Botan::TLS::Signature_Scheme>(pref);
768                if(Botan::TLS::signature_scheme_is_known(scheme) == false)
769                   continue;
770                pref_hash.push_back(Botan::TLS::hash_function_of_scheme(scheme));
771                }
772 
773             if(m_args.flag_set("server"))
774                pref_hash.push_back("SHA-256");
775             return pref_hash;
776             }
777          else
778             {
779             return { "SHA-512", "SHA-384", "SHA-256", "SHA-1" };
780             }
781          }
782 
783       //std::vector<std::string> allowed_macs() const override;
784 
allowed_key_exchange_methods() const785       std::vector<std::string> allowed_key_exchange_methods() const override
786          {
787          return {
788             "ECDHE_PSK",
789             "DHE_PSK",
790             "PSK",
791             "CECPQ1",
792             "ECDH",
793             "DH",
794             "RSA",
795          };
796          }
797 
allowed_signature_methods() const798       std::vector<std::string> allowed_signature_methods() const override
799          {
800          return {
801             "ECDSA",
802             "RSA",
803             "IMPLICIT",
804          };
805 
806          }
807 
allowed_signature_schemes() const808       std::vector<Botan::TLS::Signature_Scheme> allowed_signature_schemes() const override
809          {
810          if(m_args.option_used("signing-prefs"))
811             {
812             std::vector<Botan::TLS::Signature_Scheme> schemes;
813             for(size_t pref : m_args.get_int_vec_opt("signing-prefs"))
814                {
815                schemes.push_back(static_cast<Botan::TLS::Signature_Scheme>(pref));
816                }
817 
818             // BoGo gets sad if these are not included in our signature_algorithms extension
819             if(!m_args.flag_set("server"))
820                {
821                schemes.push_back(Botan::TLS::Signature_Scheme::RSA_PKCS1_SHA256);
822                schemes.push_back(Botan::TLS::Signature_Scheme::ECDSA_SHA256);
823                }
824 
825             return schemes;
826             }
827 
828          if(m_args.option_used("verify-prefs"))
829             {
830             std::vector<Botan::TLS::Signature_Scheme> schemes;
831             for(size_t pref : m_args.get_int_vec_opt("verify-prefs"))
832                {
833                schemes.push_back(static_cast<Botan::TLS::Signature_Scheme>(pref));
834                }
835 
836             return schemes;
837             }
838 
839          return Botan::TLS::Policy::allowed_signature_schemes();
840          }
841 
842       //size_t minimum_signature_strength() const override;
843 
844       //bool require_cert_revocation_info() const override;
845 
key_exchange_groups() const846       std::vector<Botan::TLS::Group_Params> key_exchange_groups() const override
847          {
848          if(m_args.option_used("curves"))
849             {
850             std::vector<Botan::TLS::Group_Params> groups;
851             for(size_t pref : m_args.get_int_vec_opt("curves"))
852                {
853                groups.push_back(static_cast<Botan::TLS::Group_Params>(pref));
854                }
855 
856             return groups;
857             }
858 
859          return Botan::TLS::Policy::key_exchange_groups();
860          }
861 
use_ecc_point_compression() const862       bool use_ecc_point_compression() const override { return false; } // BoGo expects this
863 
864       //Botan::TLS::Group_Params choose_key_exchange_group(const std::vector<Botan::TLS::Group_Params>& peer_groups) const override;
865 
require_client_certificate_authentication() const866       bool require_client_certificate_authentication() const override
867          {
868          return m_args.flag_set("require-any-client-certificate");
869          }
870 
request_client_certificate_authentication() const871       bool request_client_certificate_authentication() const override
872          {
873          return m_args.flag_set("verify-peer") ||
874             m_args.flag_set("fail-cert-callback") ||
875             require_client_certificate_authentication();
876          }
877 
allow_insecure_renegotiation() const878       bool allow_insecure_renegotiation() const override
879          {
880          if(m_args.flag_set("expect-no-secure-renegotiation"))
881             return true;
882          else
883             return false;
884          }
885 
886       //bool include_time_in_hello_random() const override;
887 
allow_client_initiated_renegotiation() const888       bool allow_client_initiated_renegotiation() const override
889          {
890          if(m_args.flag_set("renegotiate-freely"))
891             return true;
892 
893          if(m_args.flag_set("renegotiate-once") && m_sessions <= 1)
894             return true;
895 
896          return false;
897          }
898 
allow_server_initiated_renegotiation() const899       bool allow_server_initiated_renegotiation() const override
900          {
901          return allow_client_initiated_renegotiation(); // same logic
902          }
903 
allow_version(Botan::TLS::Protocol_Version version) const904       bool allow_version(Botan::TLS::Protocol_Version version) const
905          {
906          if(m_args.option_used("min-version"))
907             {
908             const uint16_t min_version_16 = static_cast<uint16_t>(m_args.get_int_opt("min-version"));
909             Botan::TLS::Protocol_Version min_version(min_version_16 >> 8, min_version_16 & 0xFF);
910             if(min_version > version)
911                return false;
912             }
913 
914          if(m_args.option_used("max-version"))
915             {
916             const uint16_t max_version_16 = static_cast<uint16_t>(m_args.get_int_opt("max-version"));
917             Botan::TLS::Protocol_Version max_version(max_version_16 >> 8, max_version_16 & 0xFF);
918             if(version > max_version)
919                return false;
920             }
921 
922          return version.known_version();
923          }
924 
allow_tls10() const925       bool allow_tls10() const override
926          {
927          return !m_args.flag_set("dtls") &&
928             !m_args.flag_set("no-tls1") &&
929             allow_version(Botan::TLS::Protocol_Version::TLS_V10);
930          }
931 
allow_tls11() const932       bool allow_tls11() const override
933          {
934          return !m_args.flag_set("dtls") && !m_args.flag_set("no-tls11") && allow_version(Botan::TLS::Protocol_Version::TLS_V11);
935          }
936 
allow_tls12() const937       bool allow_tls12() const override
938          {
939          return !m_args.flag_set("dtls") && !m_args.flag_set("no-tls12") && allow_version(Botan::TLS::Protocol_Version::TLS_V12);
940          }
941 
allow_dtls10() const942       bool allow_dtls10() const override
943          {
944          return m_args.flag_set("dtls") && !m_args.flag_set("no-tls1") && allow_version(Botan::TLS::Protocol_Version::DTLS_V10);
945          }
946 
allow_dtls12() const947       bool allow_dtls12() const override
948          {
949          return m_args.flag_set("dtls") && !m_args.flag_set("no-tls12") && allow_version(Botan::TLS::Protocol_Version::DTLS_V12);
950          }
951 
952       //Botan::TLS::Group_Params default_dh_group() const override;
953 
954       //size_t minimum_dh_group_size() const override;
955 
minimum_ecdsa_group_size() const956       size_t minimum_ecdsa_group_size() const override { return 224; }
957 
minimum_ecdh_group_size() const958       size_t minimum_ecdh_group_size() const override { return 224; }
959 
960       //size_t minimum_rsa_bits() const override;
961 
962       //size_t minimum_dsa_group_size() const override;
963 
964       //void check_peer_key_acceptable(const Botan::Public_Key& public_key) const override;
965 
966       //bool hide_unknown_users() const override;
967 
968       //uint32_t session_ticket_lifetime() const override;
969 
srtp_profiles() const970       std::vector<uint16_t> srtp_profiles() const override
971          {
972          if(m_args.option_used("srtp-profiles"))
973             {
974             std::string srtp = m_args.get_string_opt("srtp-profiles");
975 
976             if(srtp == "SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32")
977                return {1,2};
978             else if(srtp == "SRTP_AES128_CM_SHA1_80")
979                return {1};
980             else
981                shim_exit_with_error("unknown srtp-profiles");
982             }
983          else
984             return {};
985          }
986 
only_resume_with_exact_version() const987       bool only_resume_with_exact_version() const override
988          {
989          return false;
990          }
991 
send_fallback_scsv(Botan::TLS::Protocol_Version) const992       bool send_fallback_scsv(Botan::TLS::Protocol_Version) const override
993          {
994          return m_args.flag_set("fallback-scsv");
995          }
996 
997       //bool server_uses_own_ciphersuite_preferences() const override;
998 
999       //bool negotiate_encrypt_then_mac() const override;
1000 
support_cert_status_message() const1001       bool support_cert_status_message() const override
1002          {
1003          if(m_args.flag_set("server"))
1004             {
1005             if(!m_args.option_used("ocsp-response"))
1006                return false;
1007             if(m_args.flag_set("decline-ocsp-callback"))
1008                return false;
1009             }
1010          return true;
1011          }
1012 
1013       std::vector<uint16_t> ciphersuite_list(Botan::TLS::Protocol_Version version,
1014                                              bool have_srp) const override;
1015 
dtls_default_mtu() const1016       size_t dtls_default_mtu() const override
1017          {
1018          return m_args.get_int_opt_or_else("mtu", 1500);
1019          }
1020 
1021       //size_t dtls_initial_timeout() const override;
1022 
1023       //size_t dtls_maximum_timeout() const override;
1024 
allow_resumption_for_renegotiation() const1025       bool allow_resumption_for_renegotiation() const override
1026          {
1027          return false; // BoGo expects this
1028          }
1029 
abort_connection_on_undesired_renegotiation() const1030       bool abort_connection_on_undesired_renegotiation() const override
1031          {
1032          if(m_args.flag_set("renegotiate-ignore"))
1033             return false;
1034          else
1035             return true;
1036          }
1037 
maximum_certificate_chain_size() const1038       size_t maximum_certificate_chain_size() const override
1039          {
1040          return m_args.get_int_opt_or_else("max-cert-list", 0);
1041          }
1042 
1043    private:
1044       const Shim_Arguments& m_args;
1045       size_t m_sessions;
1046    };
1047 
ciphersuite_list(Botan::TLS::Protocol_Version version,bool have_srp) const1048 std::vector<uint16_t> Shim_Policy::ciphersuite_list(Botan::TLS::Protocol_Version version,
1049                                                     bool have_srp) const
1050    {
1051    std::vector<uint16_t> ciphersuite_codes;
1052 
1053    const std::string cipher_limit = m_args.get_string_opt_or_else("cipher", "");
1054    if(cipher_limit == "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:[TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384|TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256|TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA]:TLS_RSA_WITH_AES_128_GCM_SHA256:TLS_RSA_WITH_AES_128_CBC_SHA:[TLS_RSA_WITH_AES_256_GCM_SHA384|TLS_RSA_WITH_AES_256_CBC_SHA]")
1055       {
1056       std::vector<std::string> suites = {
1057          "ECDHE_RSA_WITH_AES_128_GCM_SHA256",
1058          "ECDHE_RSA_WITH_AES_256_GCM_SHA384",
1059          "ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
1060          "ECDHE_RSA_WITH_AES_256_CBC_SHA",
1061          "RSA_WITH_AES_256_GCM_SHA384",
1062          "RSA_WITH_AES_256_CBC_SHA",
1063       };
1064 
1065       for(auto suite_name : suites)
1066          {
1067          const auto suite = Botan::TLS::Ciphersuite::from_name(suite_name);
1068          if(suite.valid() == false)
1069             shim_exit_with_error("Bad ciphersuite name " + suite_name);
1070          ciphersuite_codes.push_back(suite.ciphersuite_code());
1071          }
1072       }
1073    else
1074       {
1075       // Hack: go in reverse order to avoid preferring 3DES
1076       auto ciphersuites = Botan::TLS::Ciphersuite::all_known_ciphersuites();
1077       for(auto i = ciphersuites.rbegin(); i != ciphersuites.rend(); ++i)
1078          {
1079          const auto suite = *i;
1080          // Can we use it?
1081          if(suite.valid() == false)
1082             continue;
1083 
1084          // Are we doing SRP?
1085          if(!have_srp && suite.kex_method() == Botan::TLS::Kex_Algo::SRP_SHA)
1086             continue;
1087 
1088          if(cipher_limit != "")
1089             {
1090             if(cipher_limit == "DEFAULT:!AES")
1091                {
1092                const std::string suite_algo = suite.cipher_algo();
1093 
1094                if(suite_algo == "AES-128" || suite_algo == "AES-256" ||
1095                   suite_algo == "AES-128/GCM" || suite_algo == "AES-256/GCM" ||
1096                   suite_algo == "AES-128/CCM" || suite_algo == "AES-256/CCM" ||
1097                   suite_algo == "AES-128/CCM(8)" || suite_algo == "AES-256/CCM(8)" ||
1098                   suite_algo == "AES-128/OCB(12)" || suite_algo == "AES-256/OCB(12)")
1099                   {
1100                   continue;
1101                   }
1102                }
1103             else
1104                {
1105                shim_exit_with_error("Unknown cipher " + cipher_limit);
1106                }
1107             }
1108 
1109          if(!version.supports_aead_modes())
1110             {
1111             // Are we doing AEAD in a non-AEAD version?
1112             if(suite.mac_algo() == "AEAD")
1113                continue;
1114 
1115             // Older (v1.0/v1.1) versions also do not support any hash but SHA-1
1116             if(suite.mac_algo() != "SHA-1")
1117                continue;
1118             }
1119 
1120          ciphersuite_codes.push_back(suite.ciphersuite_code());
1121          }
1122       }
1123 
1124    return ciphersuite_codes;
1125    }
1126 
1127 class Shim_Credentials final : public Botan::Credentials_Manager
1128    {
1129    public:
Shim_Credentials(const Shim_Arguments & args)1130       Shim_Credentials(const Shim_Arguments& args) : m_args(args)
1131          {
1132          m_psk_identity = m_args.get_string_opt_or_else("psk-identity", "");
1133 
1134          const std::string psk_str = m_args.get_string_opt_or_else("psk", "");
1135          m_psk = Botan::SymmetricKey(reinterpret_cast<const uint8_t*>(psk_str.data()), psk_str.size());
1136 
1137          if(m_args.option_used("key-file") && m_args.option_used("cert-file"))
1138             {
1139             Botan::DataSource_Stream key_stream(m_args.get_string_opt("key-file"));
1140             m_key = Botan::PKCS8::load_key(key_stream);
1141 
1142             Botan::DataSource_Stream cert_stream(m_args.get_string_opt("cert-file"));
1143 
1144             while(!cert_stream.end_of_data())
1145                {
1146                try
1147                   {
1148                   m_cert_chain.push_back(Botan::X509_Certificate(cert_stream));
1149                   }
1150                catch(...) {}
1151                }
1152             }
1153          }
1154 
psk_identity(const std::string &,const std::string &,const std::string &)1155       std::string psk_identity(const std::string& /*type*/,
1156                                const std::string& /*context*/,
1157                                const std::string& /*identity_hint*/) override
1158          {
1159          return m_psk_identity;
1160          }
1161 
psk_identity_hint(const std::string &,const std::string &)1162       std::string psk_identity_hint(const std::string& /*type*/,
1163                                     const std::string& /*context*/) override
1164          {
1165          return m_psk_identity;
1166          }
1167 
psk(const std::string & type,const std::string & context,const std::string & identity)1168       Botan::SymmetricKey psk(const std::string& type,
1169                               const std::string& context,
1170                               const std::string& identity) override
1171          {
1172          if(type == "tls-server" && context == "session-ticket")
1173             {
1174             if(!m_args.flag_set("no-ticket") && !m_args.flag_set("on-resume-no-ticket"))
1175                return Botan::SymmetricKey("ABCDEF0123456789");
1176             }
1177 
1178          if(type == "tls-server" && context == "dtls-cookie-secret")
1179             {
1180             return Botan::SymmetricKey("F00FB00FD00F100F700F");
1181             }
1182 
1183          if(identity != m_psk_identity)
1184             throw Shim_Exception("Unexpected PSK identity");
1185          return m_psk;
1186          }
1187 
cert_chain(const std::vector<std::string> & cert_key_types,const std::string &,const std::string &)1188       std::vector<Botan::X509_Certificate> cert_chain(
1189          const std::vector<std::string>& cert_key_types,
1190          const std::string& /*type*/,
1191          const std::string& /*context*/) override
1192          {
1193          if(m_args.flag_set("fail-cert-callback"))
1194             throw std::runtime_error("Simulating cert verify callback failure");
1195 
1196          if(m_key != nullptr && m_cert_chain.size() > 0)
1197             {
1198             for(std::string t : cert_key_types)
1199                {
1200                if(t == m_key->algo_name())
1201                   return m_cert_chain;
1202                }
1203             }
1204 
1205          return {};
1206          }
1207 
private_key_for(const Botan::X509_Certificate &,const std::string &,const std::string &)1208       Botan::Private_Key* private_key_for(const Botan::X509_Certificate& /*cert*/,
1209                                           const std::string& /*type*/,
1210                                           const std::string& /*context*/) override
1211          {
1212          // assumes cert == m_cert
1213          return m_key.get();
1214          }
1215 
1216    private:
1217       const Shim_Arguments& m_args;
1218       Botan::SymmetricKey m_psk;
1219       std::string m_psk_identity;
1220       std::unique_ptr<Botan::Private_Key> m_key;
1221       std::vector<Botan::X509_Certificate> m_cert_chain;
1222    };
1223 
1224 class Shim_Callbacks final : public Botan::TLS::Callbacks
1225    {
1226    public:
Shim_Callbacks(const Shim_Arguments & args,Shim_Socket & socket,Shim_Policy & policy)1227       Shim_Callbacks(const Shim_Arguments& args, Shim_Socket& socket, Shim_Policy& policy) :
1228          m_channel(nullptr),
1229          m_args(args),
1230          m_policy(policy),
1231          m_socket(socket),
1232          m_is_datagram(args.flag_set("dtls")),
1233          m_warning_alerts(0),
1234          m_empty_records(0),
1235          m_sessions_established(0),
1236          m_got_close(false)
1237          {}
1238 
sessions_established() const1239       size_t sessions_established() const { return m_sessions_established; }
1240 
set_channel(Botan::TLS::Channel * channel)1241       void set_channel(Botan::TLS::Channel* channel)
1242          {
1243          m_channel = channel;
1244          }
1245 
saw_close_notify() const1246       bool saw_close_notify() const { return m_got_close; }
1247 
tls_emit_data(const uint8_t data[],size_t size)1248       void tls_emit_data(const uint8_t data[], size_t size) override
1249          {
1250          shim_log("sending record of len " + std::to_string(size));
1251 
1252          if(m_is_datagram)
1253             {
1254             std::vector<uint8_t> packet(size + 5);
1255 
1256             packet[0] = 'P';
1257             for(size_t i = 0; i != 4; ++i)
1258                packet[i+1] = static_cast<uint8_t>((size >> (24-8*i)) & 0xFF);
1259             std::memcpy(packet.data() + 5, data, size);
1260 
1261             m_socket.write(packet.data(), packet.size());
1262             }
1263          else
1264             {
1265             m_socket.write(data, size);
1266             }
1267          }
1268 
tls_provide_cert_status(const std::vector<Botan::X509_Certificate> &,const Botan::TLS::Certificate_Status_Request &)1269       std::vector<uint8_t> tls_provide_cert_status(const std::vector<Botan::X509_Certificate>&,
1270                                                    const Botan::TLS::Certificate_Status_Request&) override
1271           {
1272           if(m_args.flag_set("use-ocsp-callback") && m_args.flag_set("fail-ocsp-callback"))
1273              throw std::runtime_error("Simulating failure from OCSP response callback");
1274 
1275           if(m_args.flag_set("decline-ocsp-callback"))
1276              return {};
1277 
1278           if(m_args.option_used("ocsp-response"))
1279              {
1280              return m_args.get_b64_opt("ocsp-response");
1281              }
1282 
1283           return {};
1284           }
1285 
tls_record_received(uint64_t,const uint8_t data[],size_t size)1286       void tls_record_received(uint64_t /*seq_no*/, const uint8_t data[], size_t size) override
1287          {
1288          if(size == 0)
1289             {
1290             m_empty_records += 1;
1291             if(m_empty_records > 32)
1292                shim_exit_with_error(":TOO_MANY_EMPTY_FRAGMENTS:");
1293             }
1294          else
1295             {
1296             m_empty_records = 0;
1297             }
1298 
1299          shim_log("Reflecting application_data len " + std::to_string(size));
1300 
1301          std::vector<uint8_t> buf(data, data + size);
1302          for(size_t i = 0; i != size; ++i)
1303             buf[i] ^= 0xFF;
1304 
1305          m_channel->send(buf);
1306          }
1307 
tls_verify_message(const Botan::Public_Key & key,const std::string & emsa,Botan::Signature_Format format,const std::vector<uint8_t> & msg,const std::vector<uint8_t> & sig)1308       bool tls_verify_message(const Botan::Public_Key& key,
1309                               const std::string& emsa,
1310                               Botan::Signature_Format format,
1311                               const std::vector<uint8_t>& msg,
1312                               const std::vector<uint8_t>& sig) override
1313          {
1314          if(m_args.option_used("expect-peer-signature-algorithm"))
1315             {
1316             const auto scheme = static_cast<Botan::TLS::Signature_Scheme>(m_args.get_int_opt("expect-peer-signature-algorithm"));
1317             if(scheme != Botan::TLS::Signature_Scheme::NONE)
1318                {
1319                const std::string exp_emsa = Botan::TLS::padding_string_for_scheme(scheme);
1320                if(emsa != exp_emsa)
1321                   shim_exit_with_error("Unexpected signature scheme got " + emsa + " expected " + exp_emsa);
1322                }
1323             }
1324          return Botan::TLS::Callbacks::tls_verify_message(key, emsa, format, msg, sig);
1325          }
1326 
tls_verify_cert_chain(const std::vector<Botan::X509_Certificate> &,const std::vector<std::shared_ptr<const Botan::OCSP::Response>> &,const std::vector<Botan::Certificate_Store * > &,Botan::Usage_Type,const std::string &,const Botan::TLS::Policy &)1327       void tls_verify_cert_chain(const std::vector<Botan::X509_Certificate>& /*cert_chain*/,
1328                                  const std::vector<std::shared_ptr<const Botan::OCSP::Response>>& /*ocsp_responses*/,
1329                                  const std::vector<Botan::Certificate_Store*>& /*trusted_roots*/,
1330                                  Botan::Usage_Type /*usage*/,
1331                                  const std::string& /*hostname*/,
1332                                  const Botan::TLS::Policy& /*policy*/) override
1333          {
1334          if(m_args.flag_set("enable-ocsp-stapling") &&
1335             m_args.flag_set("use-ocsp-callback") &&
1336             m_args.flag_set("fail-ocsp-callback"))
1337             {
1338             throw Botan::TLS::TLS_Exception(Botan::TLS::Alert::BAD_CERTIFICATE_STATUS_RESPONSE,
1339                                             "Simulated OCSP callback failure");
1340             }
1341 
1342          if(m_args.flag_set("verify-peer") && m_args.flag_set("verify-fail"))
1343             {
1344             throw Botan::TLS::TLS_Exception(Botan::TLS::Alert::BAD_CERTIFICATE,
1345                                             "Test requires rejecting cert");
1346             }
1347          }
1348 
tls_server_choose_app_protocol(const std::vector<std::string> & client_protos)1349       std::string tls_server_choose_app_protocol(const std::vector<std::string>& client_protos) override
1350          {
1351          if(client_protos.empty())
1352             return ""; // shouldn't happen?
1353 
1354          if(m_args.flag_set("decline-alpn"))
1355             return "";
1356 
1357          if(m_args.option_used("expect-advertised-alpn"))
1358             {
1359             const std::vector<std::string> expected = m_args.get_alpn_string_vec_opt("expect-advertised-alpn");
1360 
1361             if(client_protos != expected)
1362                shim_exit_with_error("Bad ALPN from client");
1363             }
1364 
1365          if(m_args.option_used("select-alpn"))
1366             return m_args.get_string_opt("select-alpn");
1367 
1368          return client_protos[0]; // if not configured just pick something
1369          }
1370 
tls_alert(Botan::TLS::Alert alert)1371       void tls_alert(Botan::TLS::Alert alert) override
1372          {
1373          if(alert.is_fatal())
1374             shim_log("Got a fatal alert " + alert.type_string());
1375          else
1376             shim_log("Got a warning alert " + alert.type_string());
1377 
1378          if(alert.type() == Botan::TLS::Alert::RECORD_OVERFLOW)
1379             {
1380             shim_exit_with_error(":TLSV1_ALERT_RECORD_OVERFLOW:");
1381             }
1382 
1383          if(alert.type() == Botan::TLS::Alert::DECOMPRESSION_FAILURE)
1384             {
1385             shim_exit_with_error(":SSLV3_ALERT_DECOMPRESSION_FAILURE:");
1386             }
1387 
1388          if(!alert.is_fatal())
1389             {
1390             m_warning_alerts++;
1391             if(m_warning_alerts > 5)
1392                shim_exit_with_error(":TOO_MANY_WARNING_ALERTS:");
1393             }
1394 
1395          if(alert.type() == Botan::TLS::Alert::CLOSE_NOTIFY)
1396             {
1397             if(m_got_close == false && !m_args.flag_set("shim-shuts-down"))
1398                {
1399                shim_log("Sending return close notify");
1400                m_channel->send_alert(alert);
1401                }
1402             m_got_close = true;
1403             }
1404          else if(alert.is_fatal())
1405             {
1406             shim_exit_with_error("Unexpected fatal alert " + alert.type_string());
1407             }
1408          }
1409 
tls_session_established(const Botan::TLS::Session & session)1410       bool tls_session_established(const Botan::TLS::Session& session) override
1411          {
1412          shim_log("Session established: " + Botan::hex_encode(session.session_id()) +
1413                   " version " + session.version().to_string() +
1414                   " cipher " + session.ciphersuite().to_string() +
1415                   " EMS " + std::to_string(session.supports_extended_master_secret()));
1416          // probably need tests here?
1417 
1418          m_policy.incr_session_established();
1419          m_sessions_established++;
1420 
1421          if(m_args.flag_set("expect-no-session-id"))
1422             {
1423             // BoGo expects that ticket issuance implies no stateful session...
1424             if(!m_args.flag_set("server") && session.session_id().size() > 0)
1425                shim_exit_with_error("Unexpectedly got a session ID");
1426             }
1427          else if(m_args.flag_set("expect-session-id"))
1428             {
1429             if(session.session_id().empty())
1430                shim_exit_with_error("Unexpectedly got no session ID");
1431             }
1432 
1433          if(m_args.option_used("expect-version"))
1434             {
1435             if(session.version().version_code() != m_args.get_int_opt("expect-version"))
1436                shim_exit_with_error("Unexpected version");
1437             }
1438 
1439          if(m_args.flag_set("expect-secure-renegotiation"))
1440             {
1441             if(m_channel->secure_renegotiation_supported() == false)
1442                shim_exit_with_error("Expected secure renegotiation");
1443             }
1444          else if(m_args.flag_set("expect-no-secure-renegotiation"))
1445             {
1446             if(m_channel->secure_renegotiation_supported() == true)
1447                shim_exit_with_error("Expected no secure renegotation");
1448             }
1449 
1450          if(m_args.flag_set("expect-extended-master-secret"))
1451             {
1452             if(session.supports_extended_master_secret() == false)
1453                shim_exit_with_error("Expected extended maseter secret");
1454             }
1455 
1456          return true;
1457          }
1458 
tls_session_activated()1459       void tls_session_activated() override
1460          {
1461          if(m_args.flag_set("send-alert"))
1462             {
1463             m_channel->send_fatal_alert(Botan::TLS::Alert::DECOMPRESSION_FAILURE);
1464             return;
1465             }
1466 
1467          if(size_t length = m_args.get_int_opt_or_else("export-keying-material", 0))
1468             {
1469             const std::string label = m_args.get_string_opt("export-label");
1470             const std::string context = m_args.get_string_opt("export-context");
1471             const auto exported = m_channel->key_material_export(label, context, length);
1472             shim_log("Sending " + std::to_string(length) + " bytes of key material");
1473             m_channel->send(exported.bits_of());
1474             }
1475 
1476          const std::string alpn = m_channel->application_protocol();
1477 
1478          if(m_args.option_used("expect-alpn"))
1479             {
1480             if(alpn != m_args.get_string_opt("expect-alpn"))
1481                shim_exit_with_error("Got unexpected ALPN");
1482             }
1483 
1484          if(alpn == "baz" && !m_args.flag_set("allow-unknown-alpn-protos"))
1485             {
1486             throw Botan::TLS::TLS_Exception(Botan::TLS::Alert::ILLEGAL_PARAMETER,
1487                                             "Unexpected ALPN protocol");
1488             }
1489 
1490          if(m_args.flag_set("shim-shuts-down"))
1491             {
1492             shim_log("Shim shutting down");
1493             m_channel->close();
1494             }
1495 
1496          if(m_args.flag_set("write-different-record-sizes"))
1497             {
1498             static const size_t record_sizes[] = {
1499                0, 1, 255, 256, 257, 16383, 16384, 16385, 32767, 32768, 32769
1500             };
1501 
1502             std::vector<uint8_t> buf(32769, 0x42);
1503 
1504             for(size_t sz : record_sizes)
1505                {
1506                m_channel->send(buf.data(), sz);
1507                }
1508 
1509             m_channel->close();
1510             }
1511          }
1512 
1513    private:
1514       Botan::TLS::Channel* m_channel;
1515       const Shim_Arguments& m_args;
1516       Shim_Policy& m_policy;
1517       Shim_Socket& m_socket;
1518       const bool m_is_datagram;
1519       size_t m_warning_alerts;
1520       size_t m_empty_records;
1521       size_t m_sessions_established;
1522       bool m_got_close;
1523    };
1524 
1525 }
1526 
main(int,char * argv[])1527 int main(int /*argc*/, char* argv[])
1528    {
1529    try
1530       {
1531       std::unique_ptr<Shim_Arguments> args = parse_options(argv);
1532 
1533       if(args->flag_set("is-handshaker-supported"))
1534          {
1535          return shim_output("No\n");
1536          }
1537 
1538       const uint16_t port = static_cast<uint16_t>(args->get_int_opt("port"));
1539       const size_t resume_count = args->get_int_opt_or_else("resume-count", 0);
1540       const bool is_server = args->flag_set("server");
1541       const bool is_datagram = args->flag_set("dtls");
1542 
1543       const size_t buf_size = args->get_int_opt_or_else("read-size", 18*1024);
1544 
1545       Botan::ChaCha_RNG rng(Botan::secure_vector<uint8_t>(64));
1546       Botan::TLS::Session_Manager_In_Memory session_manager(rng, 1024);
1547       Shim_Credentials creds(*args);
1548 
1549       for(size_t i = 0; i != resume_count+1; ++i)
1550          {
1551          Shim_Socket socket("localhost", port);
1552 
1553          shim_log("Connection " + std::to_string(i+1) + "/" + std::to_string(resume_count+1));
1554 
1555          Shim_Policy policy(*args);
1556          Shim_Callbacks callbacks(*args, socket, policy);
1557 
1558          std::unique_ptr<Botan::TLS::Channel> chan;
1559 
1560          if(is_server)
1561             {
1562             chan.reset(new Botan::TLS::Server(callbacks, session_manager, creds, policy, rng, is_datagram));
1563             }
1564          else
1565             {
1566             Botan::TLS::Protocol_Version offer_version = policy.latest_supported_version(is_datagram);
1567             shim_log("Offering " + offer_version.to_string());
1568 
1569             std::string host_name = args->get_string_opt_or_else("host-name", "localhost");
1570             if(args->test_name().find("UnsolicitedServerNameAck-TLS1") == 0)
1571                host_name = ""; // avoid sending SNI for this test
1572 
1573             Botan::TLS::Server_Information server_info(host_name, port);
1574             const std::vector<std::string> next_protocols = args->get_alpn_string_vec_opt("advertise-alpn");
1575             chan.reset(new Botan::TLS::Client(callbacks, session_manager, creds, policy, rng,
1576                                               server_info, offer_version, next_protocols));
1577             }
1578 
1579          callbacks.set_channel(chan.get());
1580 
1581          std::vector<uint8_t> buf(buf_size);
1582 
1583          for(;;)
1584             {
1585             if(is_datagram)
1586                {
1587                uint8_t opcode;
1588                size_t got = socket.read(&opcode, 1);
1589                if(got == 0)
1590                   {
1591                   shim_log("EOF on socket");
1592                   break;
1593                   }
1594 
1595                if(opcode == 'P')
1596                   {
1597                   uint8_t len_bytes[4];
1598                   socket.read_exactly(len_bytes, sizeof(len_bytes));
1599 
1600                   size_t packet_len = Botan::load_be<uint32_t>(len_bytes, 0);
1601 
1602                   if(buf.size() < packet_len)
1603                      buf.resize(packet_len);
1604                   socket.read_exactly(buf.data(), packet_len);
1605 
1606                   chan->received_data(buf.data(), packet_len);
1607                   }
1608                else if(opcode == 'T')
1609                   {
1610                   uint8_t timeout_ack = 't';
1611 
1612                   uint8_t timeout_bytes[8];
1613                   socket.read_exactly(timeout_bytes, sizeof(timeout_bytes));
1614 
1615                   const uint64_t nsec = Botan::load_be<uint64_t>(timeout_bytes, 0);
1616 
1617                   shim_log("Timeout nsec " + std::to_string(nsec));
1618 
1619                   // FIXME handle this!
1620 
1621                   socket.write(&timeout_ack, 1); // ack it anyway
1622                   }
1623                else
1624                   shim_exit_with_error("Unknown opcode " + std::to_string(opcode));
1625                }
1626             else
1627                {
1628                size_t got = socket.read(buf.data(), buf.size());
1629                if(got == 0)
1630                   {
1631                   shim_log("EOF on socket");
1632                   break;
1633                   }
1634 
1635                shim_log("Got packet of " + std::to_string(got));
1636 
1637                if(args->flag_set("use-exporter-between-reads") && chan->is_active())
1638                   {
1639                   chan->key_material_export("some label", "some context", 42);
1640                   }
1641                const size_t needed = chan->received_data(buf.data(), got);
1642 
1643                if(needed)
1644                   shim_log("Short read still need " + std::to_string(needed));
1645                }
1646             }
1647 
1648          if(args->flag_set("check-close-notify"))
1649             {
1650             if(!callbacks.saw_close_notify())
1651                throw Shim_Exception("Unexpected SSL_shutdown result: -1 != 1");
1652             }
1653 
1654          if(args->option_used("expect-total-renegotiations"))
1655             {
1656             const size_t exp = args->get_int_opt("expect-total-renegotiations");
1657 
1658             if(exp != callbacks.sessions_established() - 1)
1659                throw Shim_Exception("Unexpected number of renegotiations: saw " +
1660                                     std::to_string(callbacks.sessions_established() - 1) +
1661                                     " exp " + std::to_string(exp));
1662             }
1663          shim_log("End of resume loop");
1664          }
1665 
1666       }
1667    catch(Shim_Exception& e)
1668       {
1669       shim_exit_with_error(e.what(), e.rc());
1670       }
1671    catch(std::exception& e)
1672       {
1673       shim_exit_with_error(map_to_bogo_error(e.what()));
1674       }
1675    catch(...)
1676       {
1677       shim_exit_with_error("Unknown exception", 3);
1678       }
1679    return 0;
1680    }
1681