• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * nghttp2 - HTTP/2 C Library
3  *
4  * Copyright (c) 2014 Tatsuhiro Tsujikawa
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25 #include "tls.h"
26 
27 #include <cassert>
28 #include <cstring>
29 #include <vector>
30 #include <mutex>
31 #include <iostream>
32 #include <fstream>
33 
34 #ifdef HAVE_LIBBROTLI
35 #  include <brotli/encode.h>
36 #  include <brotli/decode.h>
37 #endif // HAVE_LIBBROTLI
38 
39 #include "ssl_compat.h"
40 
41 #ifdef NGHTTP2_OPENSSL_IS_WOLFSSL
42 #  include <wolfssl/options.h>
43 #  include <wolfssl/openssl/crypto.h>
44 #  include <wolfssl/openssl/conf.h>
45 #else // !NGHTTP2_OPENSSL_IS_WOLFSSL
46 #  include <openssl/crypto.h>
47 #  include <openssl/conf.h>
48 #endif // !NGHTTP2_OPENSSL_IS_WOLFSSL
49 
50 namespace nghttp2 {
51 
52 namespace tls {
53 
get_tls_protocol(SSL * ssl)54 const char *get_tls_protocol(SSL *ssl) {
55   switch (SSL_version(ssl)) {
56   case SSL2_VERSION:
57     return "SSLv2";
58   case SSL3_VERSION:
59     return "SSLv3";
60 #ifdef TLS1_3_VERSION
61   case TLS1_3_VERSION:
62     return "TLSv1.3";
63 #endif // TLS1_3_VERSION
64   case TLS1_2_VERSION:
65     return "TLSv1.2";
66   case TLS1_1_VERSION:
67     return "TLSv1.1";
68   case TLS1_VERSION:
69     return "TLSv1";
70   default:
71     return "unknown";
72   }
73 }
74 
get_tls_session_info(TLSSessionInfo * tls_info,SSL * ssl)75 TLSSessionInfo *get_tls_session_info(TLSSessionInfo *tls_info, SSL *ssl) {
76   if (!ssl) {
77     return nullptr;
78   }
79 
80   auto session = SSL_get_session(ssl);
81   if (!session) {
82     return nullptr;
83   }
84 
85   tls_info->cipher = SSL_get_cipher_name(ssl);
86   tls_info->protocol = get_tls_protocol(ssl);
87   tls_info->session_reused = SSL_session_reused(ssl);
88 
89   unsigned int session_id_length;
90   tls_info->session_id = SSL_SESSION_get_id(session, &session_id_length);
91   tls_info->session_id_length = session_id_length;
92 
93   return tls_info;
94 }
95 
96 /* Conditional logic w/ lookup tables to check if id is one of the
97    the block listed cipher suites for HTTP/2 described in RFC 7540.
98    https://github.com/jay/http2_blacklisted_ciphers
99 */
100 #define IS_CIPHER_BANNED_METHOD2(id)                                           \
101   ((0x0000 <= id && id <= 0x00FF &&                                            \
102     "\xFF\xFF\xFF\xCF\xFF\xFF\xFF\xFF\x7F\x00\x00\x00\x80\x3F\x00\x00"         \
103     "\xF0\xFF\xFF\x3F\xF3\xF3\xFF\xFF\x3F\x00\x00\x00\x00\x00\x00\x80"         \
104         [(id & 0xFF) / 8] &                                                    \
105       (1 << (id % 8))) ||                                                      \
106    (0xC000 <= id && id <= 0xC0FF &&                                            \
107     "\xFE\xFF\xFF\xFF\xFF\x67\xFE\xFF\xFF\xFF\x33\xCF\xFC\xCF\xFF\xCF"         \
108     "\x3C\xF3\xFC\x3F\x33\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"         \
109         [(id & 0xFF) / 8] &                                                    \
110       (1 << (id % 8))))
111 
check_http2_cipher_block_list(SSL * ssl)112 bool check_http2_cipher_block_list(SSL *ssl) {
113   int id = SSL_CIPHER_get_id(SSL_get_current_cipher(ssl)) & 0xFFFFFF;
114 
115   return IS_CIPHER_BANNED_METHOD2(id);
116 }
117 
check_http2_tls_version(SSL * ssl)118 bool check_http2_tls_version(SSL *ssl) {
119   auto tls_ver = SSL_version(ssl);
120 
121   return tls_ver >= TLS1_2_VERSION;
122 }
123 
check_http2_requirement(SSL * ssl)124 bool check_http2_requirement(SSL *ssl) {
125   return check_http2_tls_version(ssl) && !check_http2_cipher_block_list(ssl);
126 }
127 
ssl_ctx_set_proto_versions(SSL_CTX * ssl_ctx,int min,int max)128 int ssl_ctx_set_proto_versions(SSL_CTX *ssl_ctx, int min, int max) {
129   if (SSL_CTX_set_min_proto_version(ssl_ctx, min) != 1 ||
130       SSL_CTX_set_max_proto_version(ssl_ctx, max) != 1) {
131     return -1;
132   }
133   return 0;
134 }
135 
136 #if defined(NGHTTP2_OPENSSL_IS_BORINGSSL) && defined(HAVE_LIBBROTLI)
cert_compress(SSL * ssl,CBB * out,const uint8_t * in,size_t in_len)137 int cert_compress(SSL *ssl, CBB *out, const uint8_t *in, size_t in_len) {
138   uint8_t *dest;
139 
140   auto compressed_size = BrotliEncoderMaxCompressedSize(in_len);
141   if (compressed_size == 0) {
142     return 0;
143   }
144 
145   if (!CBB_reserve(out, &dest, compressed_size)) {
146     return 0;
147   }
148 
149   if (BrotliEncoderCompress(BROTLI_MAX_QUALITY, BROTLI_DEFAULT_WINDOW,
150                             BROTLI_MODE_GENERIC, in_len, in, &compressed_size,
151                             dest) != BROTLI_TRUE) {
152     return 0;
153   }
154 
155   if (!CBB_did_write(out, compressed_size)) {
156     return 0;
157   }
158 
159   return 1;
160 }
161 
cert_decompress(SSL * ssl,CRYPTO_BUFFER ** out,size_t uncompressed_len,const uint8_t * in,size_t in_len)162 int cert_decompress(SSL *ssl, CRYPTO_BUFFER **out, size_t uncompressed_len,
163                     const uint8_t *in, size_t in_len) {
164   uint8_t *dest;
165   auto buf = CRYPTO_BUFFER_alloc(&dest, uncompressed_len);
166   auto len = uncompressed_len;
167 
168   if (BrotliDecoderDecompress(in_len, in, &len, dest) !=
169       BROTLI_DECODER_RESULT_SUCCESS) {
170     CRYPTO_BUFFER_free(buf);
171 
172     return 0;
173   }
174 
175   if (uncompressed_len != len) {
176     CRYPTO_BUFFER_free(buf);
177 
178     return 0;
179   }
180 
181   *out = buf;
182 
183   return 1;
184 }
185 #endif // NGHTTP2_OPENSSL_IS_BORINGSSL && HAVE_LIBBROTLI
186 
187 #if defined(NGHTTP2_GENUINE_OPENSSL) ||                                        \
188   defined(NGHTTP2_OPENSSL_IS_BORINGSSL) ||                                     \
189   defined(NGHTTP2_OPENSSL_IS_LIBRESSL) ||                                      \
190   (defined(NGHTTP2_OPENSSL_IS_WOLFSSL) && defined(HAVE_SECRET_CALLBACK))
191 namespace {
192 std::ofstream keylog_file;
193 
keylog_callback(const SSL * ssl,const char * line)194 void keylog_callback(const SSL *ssl, const char *line) {
195   keylog_file.write(line, strlen(line));
196   keylog_file.put('\n');
197   keylog_file.flush();
198 }
199 } // namespace
200 
setup_keylog_callback(SSL_CTX * ssl_ctx)201 int setup_keylog_callback(SSL_CTX *ssl_ctx) {
202   auto keylog_filename = getenv("SSLKEYLOGFILE");
203   if (!keylog_filename) {
204     return 0;
205   }
206 
207   keylog_file.open(keylog_filename, std::ios_base::app);
208   if (!keylog_file) {
209     return -1;
210   }
211 
212   SSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback);
213 
214   return 0;
215 }
216 #else  // !NGHTTP2_GENUINE_OPENSSL && !NGHTTP2_OPENSSL_IS_BORINGSSL &&
217        // !NGHTTP2_OPENSSL_IS_LIBRESSL && !(NGHTTP2_OPENSSL_IS_WOLFSSL &&
218        // HAVE_SECRET_CALLBACK)
setup_keylog_callback(SSL_CTX * ssl_ctx)219 int setup_keylog_callback(SSL_CTX *ssl_ctx) { return 0; }
220 #endif // !NGHTTP2_GENUINE_OPENSSL && !NGHTTP2_OPENSSL_IS_BORINGSSL &&
221        // !NGHTTP2_OPENSSL_IS_LIBRESSL && !(NGHTTP2_OPENSSL_IS_WOLFSSL &&
222        // HAVE_SECRET_CALLBACK)
223 
224 } // namespace tls
225 
226 } // namespace nghttp2
227