• 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 <vector>
29 #include <mutex>
30 #include <iostream>
31 
32 #include <openssl/crypto.h>
33 #include <openssl/conf.h>
34 
35 #include "ssl_compat.h"
36 
37 namespace nghttp2 {
38 
39 namespace tls {
40 
41 #if OPENSSL_1_1_API
42 
43 // CRYPTO_LOCK is deprecated as of OpenSSL 1.1.0
LibsslGlobalLock()44 LibsslGlobalLock::LibsslGlobalLock() {}
45 
46 #else // !OPENSSL_1_1_API
47 
48 namespace {
49 std::mutex *ssl_global_locks;
50 } // namespace
51 
52 namespace {
53 void ssl_locking_cb(int mode, int type, const char *file, int line) {
54   if (mode & CRYPTO_LOCK) {
55     ssl_global_locks[type].lock();
56   } else {
57     ssl_global_locks[type].unlock();
58   }
59 }
60 } // namespace
61 
62 LibsslGlobalLock::LibsslGlobalLock() {
63   if (ssl_global_locks) {
64     std::cerr << "OpenSSL global lock has been already set" << std::endl;
65     assert(0);
66   }
67   ssl_global_locks = new std::mutex[CRYPTO_num_locks()];
68   // CRYPTO_set_id_callback(ssl_thread_id); OpenSSL manual says that
69   // if threadid_func is not specified using
70   // CRYPTO_THREADID_set_callback(), then default implementation is
71   // used. We use this default one.
72   CRYPTO_set_locking_callback(ssl_locking_cb);
73 }
74 
75 #endif // !OPENSSL_1_1_API
76 
get_tls_protocol(SSL * ssl)77 const char *get_tls_protocol(SSL *ssl) {
78   switch (SSL_version(ssl)) {
79   case SSL2_VERSION:
80     return "SSLv2";
81   case SSL3_VERSION:
82     return "SSLv3";
83 #ifdef TLS1_3_VERSION
84   case TLS1_3_VERSION:
85     return "TLSv1.3";
86 #endif // TLS1_3_VERSION
87   case TLS1_2_VERSION:
88     return "TLSv1.2";
89   case TLS1_1_VERSION:
90     return "TLSv1.1";
91   case TLS1_VERSION:
92     return "TLSv1";
93   default:
94     return "unknown";
95   }
96 }
97 
get_tls_session_info(TLSSessionInfo * tls_info,SSL * ssl)98 TLSSessionInfo *get_tls_session_info(TLSSessionInfo *tls_info, SSL *ssl) {
99   if (!ssl) {
100     return nullptr;
101   }
102 
103   auto session = SSL_get_session(ssl);
104   if (!session) {
105     return nullptr;
106   }
107 
108   tls_info->cipher = SSL_get_cipher_name(ssl);
109   tls_info->protocol = get_tls_protocol(ssl);
110   tls_info->session_reused = SSL_session_reused(ssl);
111 
112   unsigned int session_id_length;
113   tls_info->session_id = SSL_SESSION_get_id(session, &session_id_length);
114   tls_info->session_id_length = session_id_length;
115 
116   return tls_info;
117 }
118 
119 /* Conditional logic w/ lookup tables to check if id is one of the
120    the black listed cipher suites for HTTP/2 described in RFC 7540.
121    https://github.com/jay/http2_blacklisted_ciphers
122 */
123 #define IS_CIPHER_BANNED_METHOD2(id)                                           \
124   ((0x0000 <= id && id <= 0x00FF &&                                            \
125     "\xFF\xFF\xFF\xCF\xFF\xFF\xFF\xFF\x7F\x00\x00\x00\x80\x3F\x00\x00"         \
126     "\xF0\xFF\xFF\x3F\xF3\xF3\xFF\xFF\x3F\x00\x00\x00\x00\x00\x00\x80"         \
127             [(id & 0xFF) / 8] &                                                \
128         (1 << (id % 8))) ||                                                    \
129    (0xC000 <= id && id <= 0xC0FF &&                                            \
130     "\xFE\xFF\xFF\xFF\xFF\x67\xFE\xFF\xFF\xFF\x33\xCF\xFC\xCF\xFF\xCF"         \
131     "\x3C\xF3\xFC\x3F\x33\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"         \
132             [(id & 0xFF) / 8] &                                                \
133         (1 << (id % 8))))
134 
check_http2_cipher_black_list(SSL * ssl)135 bool check_http2_cipher_black_list(SSL *ssl) {
136   int id = SSL_CIPHER_get_id(SSL_get_current_cipher(ssl)) & 0xFFFFFF;
137 
138   return IS_CIPHER_BANNED_METHOD2(id);
139 }
140 
check_http2_tls_version(SSL * ssl)141 bool check_http2_tls_version(SSL *ssl) {
142   auto tls_ver = SSL_version(ssl);
143 
144   return tls_ver >= TLS1_2_VERSION;
145 }
146 
check_http2_requirement(SSL * ssl)147 bool check_http2_requirement(SSL *ssl) {
148   return check_http2_tls_version(ssl) && !check_http2_cipher_black_list(ssl);
149 }
150 
libssl_init()151 void libssl_init() {
152 #if OPENSSL_1_1_API
153 // No explicit initialization is required.
154 #elif defined(OPENSSL_IS_BORINGSSL)
155   CRYPTO_library_init();
156 #else  // !OPENSSL_1_1_API && !defined(OPENSSL_IS_BORINGSSL)
157   OPENSSL_config(nullptr);
158   SSL_load_error_strings();
159   SSL_library_init();
160   OpenSSL_add_all_algorithms();
161 #endif // !OPENSSL_1_1_API && !defined(OPENSSL_IS_BORINGSSL)
162 }
163 
ssl_ctx_set_proto_versions(SSL_CTX * ssl_ctx,int min,int max)164 int ssl_ctx_set_proto_versions(SSL_CTX *ssl_ctx, int min, int max) {
165 #if OPENSSL_1_1_API || defined(OPENSSL_IS_BORINGSSL)
166   if (SSL_CTX_set_min_proto_version(ssl_ctx, min) != 1 ||
167       SSL_CTX_set_max_proto_version(ssl_ctx, max) != 1) {
168     return -1;
169   }
170   return 0;
171 #else  // !OPENSSL_1_1_API && !defined(OPENSSL_IS_BORINGSSL)
172   long int opts = 0;
173 
174   // TODO We depends on the ordering of protocol version macro in
175   // OpenSSL.
176   if (min > TLS1_VERSION) {
177     opts |= SSL_OP_NO_TLSv1;
178   }
179   if (min > TLS1_1_VERSION) {
180     opts |= SSL_OP_NO_TLSv1_1;
181   }
182   if (min > TLS1_2_VERSION) {
183     opts |= SSL_OP_NO_TLSv1_2;
184   }
185 
186   if (max < TLS1_2_VERSION) {
187     opts |= SSL_OP_NO_TLSv1_2;
188   }
189   if (max < TLS1_1_VERSION) {
190     opts |= SSL_OP_NO_TLSv1_1;
191   }
192 
193   SSL_CTX_set_options(ssl_ctx, opts);
194 
195   return 0;
196 #endif // !OPENSSL_1_1_API && !defined(OPENSSL_IS_BORINGSSL)
197 }
198 
199 } // namespace tls
200 
201 } // namespace nghttp2
202