• 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 #include <openssl/crypto.h>
35 #include <openssl/conf.h>
36 
37 #ifdef HAVE_LIBBROTLI
38 #  include <brotli/encode.h>
39 #  include <brotli/decode.h>
40 #endif // HAVE_LIBBROTLI
41 
42 #include "ssl_compat.h"
43 
44 namespace nghttp2 {
45 
46 namespace tls {
47 
get_tls_protocol(SSL * ssl)48 const char *get_tls_protocol(SSL *ssl) {
49   switch (SSL_version(ssl)) {
50   case SSL2_VERSION:
51     return "SSLv2";
52   case SSL3_VERSION:
53     return "SSLv3";
54 #ifdef TLS1_3_VERSION
55   case TLS1_3_VERSION:
56     return "TLSv1.3";
57 #endif // TLS1_3_VERSION
58   case TLS1_2_VERSION:
59     return "TLSv1.2";
60   case TLS1_1_VERSION:
61     return "TLSv1.1";
62   case TLS1_VERSION:
63     return "TLSv1";
64   default:
65     return "unknown";
66   }
67 }
68 
get_tls_session_info(TLSSessionInfo * tls_info,SSL * ssl)69 TLSSessionInfo *get_tls_session_info(TLSSessionInfo *tls_info, SSL *ssl) {
70   if (!ssl) {
71     return nullptr;
72   }
73 
74   auto session = SSL_get_session(ssl);
75   if (!session) {
76     return nullptr;
77   }
78 
79   tls_info->cipher = SSL_get_cipher_name(ssl);
80   tls_info->protocol = get_tls_protocol(ssl);
81   tls_info->session_reused = SSL_session_reused(ssl);
82 
83   unsigned int session_id_length;
84   tls_info->session_id = SSL_SESSION_get_id(session, &session_id_length);
85   tls_info->session_id_length = session_id_length;
86 
87   return tls_info;
88 }
89 
90 /* Conditional logic w/ lookup tables to check if id is one of the
91    the block listed cipher suites for HTTP/2 described in RFC 7540.
92    https://github.com/jay/http2_blacklisted_ciphers
93 */
94 #define IS_CIPHER_BANNED_METHOD2(id)                                           \
95   ((0x0000 <= id && id <= 0x00FF &&                                            \
96     "\xFF\xFF\xFF\xCF\xFF\xFF\xFF\xFF\x7F\x00\x00\x00\x80\x3F\x00\x00"         \
97     "\xF0\xFF\xFF\x3F\xF3\xF3\xFF\xFF\x3F\x00\x00\x00\x00\x00\x00\x80"         \
98             [(id & 0xFF) / 8] &                                                \
99         (1 << (id % 8))) ||                                                    \
100    (0xC000 <= id && id <= 0xC0FF &&                                            \
101     "\xFE\xFF\xFF\xFF\xFF\x67\xFE\xFF\xFF\xFF\x33\xCF\xFC\xCF\xFF\xCF"         \
102     "\x3C\xF3\xFC\x3F\x33\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"         \
103             [(id & 0xFF) / 8] &                                                \
104         (1 << (id % 8))))
105 
check_http2_cipher_block_list(SSL * ssl)106 bool check_http2_cipher_block_list(SSL *ssl) {
107   int id = SSL_CIPHER_get_id(SSL_get_current_cipher(ssl)) & 0xFFFFFF;
108 
109   return IS_CIPHER_BANNED_METHOD2(id);
110 }
111 
check_http2_tls_version(SSL * ssl)112 bool check_http2_tls_version(SSL *ssl) {
113   auto tls_ver = SSL_version(ssl);
114 
115   return tls_ver >= TLS1_2_VERSION;
116 }
117 
check_http2_requirement(SSL * ssl)118 bool check_http2_requirement(SSL *ssl) {
119   return check_http2_tls_version(ssl) && !check_http2_cipher_block_list(ssl);
120 }
121 
ssl_ctx_set_proto_versions(SSL_CTX * ssl_ctx,int min,int max)122 int ssl_ctx_set_proto_versions(SSL_CTX *ssl_ctx, int min, int max) {
123   if (SSL_CTX_set_min_proto_version(ssl_ctx, min) != 1 ||
124       SSL_CTX_set_max_proto_version(ssl_ctx, max) != 1) {
125     return -1;
126   }
127   return 0;
128 }
129 
130 #if defined(NGHTTP2_OPENSSL_IS_BORINGSSL) && defined(HAVE_LIBBROTLI)
cert_compress(SSL * ssl,CBB * out,const uint8_t * in,size_t in_len)131 int cert_compress(SSL *ssl, CBB *out, const uint8_t *in, size_t in_len) {
132   uint8_t *dest;
133 
134   auto compressed_size = BrotliEncoderMaxCompressedSize(in_len);
135   if (compressed_size == 0) {
136     return 0;
137   }
138 
139   if (!CBB_reserve(out, &dest, compressed_size)) {
140     return 0;
141   }
142 
143   if (BrotliEncoderCompress(BROTLI_MAX_QUALITY, BROTLI_DEFAULT_WINDOW,
144                             BROTLI_MODE_GENERIC, in_len, in, &compressed_size,
145                             dest) != BROTLI_TRUE) {
146     return 0;
147   }
148 
149   if (!CBB_did_write(out, compressed_size)) {
150     return 0;
151   }
152 
153   return 1;
154 }
155 
cert_decompress(SSL * ssl,CRYPTO_BUFFER ** out,size_t uncompressed_len,const uint8_t * in,size_t in_len)156 int cert_decompress(SSL *ssl, CRYPTO_BUFFER **out, size_t uncompressed_len,
157                     const uint8_t *in, size_t in_len) {
158   uint8_t *dest;
159   auto buf = CRYPTO_BUFFER_alloc(&dest, uncompressed_len);
160   auto len = uncompressed_len;
161 
162   if (BrotliDecoderDecompress(in_len, in, &len, dest) !=
163       BROTLI_DECODER_RESULT_SUCCESS) {
164     CRYPTO_BUFFER_free(buf);
165 
166     return 0;
167   }
168 
169   if (uncompressed_len != len) {
170     CRYPTO_BUFFER_free(buf);
171 
172     return 0;
173   }
174 
175   *out = buf;
176 
177   return 1;
178 }
179 #endif // NGHTTP2_OPENSSL_IS_BORINGSSL && HAVE_LIBBROTLI
180 
181 namespace {
182 std::ofstream keylog_file;
183 
keylog_callback(const SSL * ssl,const char * line)184 void keylog_callback(const SSL *ssl, const char *line) {
185   keylog_file.write(line, strlen(line));
186   keylog_file.put('\n');
187   keylog_file.flush();
188 }
189 } // namespace
190 
setup_keylog_callback(SSL_CTX * ssl_ctx)191 int setup_keylog_callback(SSL_CTX *ssl_ctx) {
192   auto keylog_filename = getenv("SSLKEYLOGFILE");
193   if (!keylog_filename) {
194     return 0;
195   }
196 
197   keylog_file.open(keylog_filename, std::ios_base::app);
198   if (!keylog_file) {
199     return -1;
200   }
201 
202   SSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback);
203 
204   return 0;
205 }
206 
207 } // namespace tls
208 
209 } // namespace nghttp2
210