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