1 /*
2   +----------------------------------------------------------------------+
3   | Swoole                                                               |
4   +----------------------------------------------------------------------+
5   | This source file is subject to version 2.0 of the Apache license,    |
6   | that is bundled with this package in the file LICENSE, and is        |
7   | available through the world-wide-web at the following url:           |
8   | http://www.apache.org/licenses/LICENSE-2.0.html                      |
9   | If you did not receive a copy of the Apache2.0 license and are unable|
10   | to obtain it through the world-wide-web, please send a note to       |
11   | license@php.net so we can mail you a copy immediately.               |
12   +----------------------------------------------------------------------+
13   | Author: Tianfeng Han  <mikan.tenny@gmail.com>                        |
14   +----------------------------------------------------------------------+
15 */
16 
17 #pragma once
18 
19 #include "swoole.h"
20 
21 #ifdef SW_USE_OPENSSL
22 
23 #include <unordered_map>
24 #include <string>
25 #include <array>
26 
27 #include <openssl/ssl.h>
28 #include <openssl/bio.h>
29 #include <openssl/err.h>
30 #include <openssl/conf.h>
31 #include <openssl/ossl_typ.h>
32 #include <openssl/crypto.h>
33 #include <openssl/x509.h>
34 #include <openssl/x509v3.h>
35 #include <openssl/rand.h>
36 #include <openssl/opensslv.h>
37 
38 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
39 #define SW_SUPPORT_DTLS
40 #endif
41 
42 #if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3000000fL
43 #undef SW_SUPPORT_DTLS
44 #endif
45 
46 #ifdef OPENSSL_IS_BORINGSSL
47 #define BIO_CTRL_DGRAM_SET_CONNECTED 32
48 #define BIO_CTRL_DGRAM_SET_PEER 44
49 #define BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT 45
50 #define BIO_dgram_get_peer(b,peer) \
51          (int)BIO_ctrl(b, BIO_CTRL_DGRAM_GET_PEER, 0, (char *)(peer))
52 #define OPENSSL_assert(x)       assert(x)
53 #endif
54 
55 enum swSSLCreateFlag {
56     SW_SSL_SERVER = 1,
57     SW_SSL_CLIENT = 2,
58 };
59 
60 enum swSSLState {
61     SW_SSL_STATE_HANDSHAKE = 0,
62     SW_SSL_STATE_READY = 1,
63     SW_SSL_STATE_WAIT_STREAM = 2,
64 };
65 
66 enum swSSLVersion {
67     SW_SSL_SSLv2 = 1u << 1,
68     SW_SSL_SSLv3 = 1u << 2,
69     SW_SSL_TLSv1 = 1u << 3,
70     SW_SSL_TLSv1_1 = 1u << 4,
71     SW_SSL_TLSv1_2 = 1u << 5,
72     SW_SSL_TLSv1_3 = 1u << 6,
73     SW_SSL_DTLS = 1u << 7,
74 };
75 
76 #define SW_SSL_ALL (SW_SSL_SSLv2 | SW_SSL_SSLv3 | SW_SSL_TLSv1 | SW_SSL_TLSv1_1 | SW_SSL_TLSv1_2 | SW_SSL_TLSv1_3)
77 
78 enum swSSLMethod {
79     SW_SSLv23_METHOD = 0,
80     SW_SSLv3_METHOD,
81     SW_SSLv3_SERVER_METHOD,
82     SW_SSLv3_CLIENT_METHOD,
83     SW_SSLv23_SERVER_METHOD,
84     SW_SSLv23_CLIENT_METHOD,
85     SW_TLSv1_METHOD,
86     SW_TLSv1_SERVER_METHOD,
87     SW_TLSv1_CLIENT_METHOD,
88 #ifdef TLS1_1_VERSION
89     SW_TLSv1_1_METHOD,
90     SW_TLSv1_1_SERVER_METHOD,
91     SW_TLSv1_1_CLIENT_METHOD,
92 #endif
93 #ifdef TLS1_2_VERSION
94     SW_TLSv1_2_METHOD,
95     SW_TLSv1_2_SERVER_METHOD,
96     SW_TLSv1_2_CLIENT_METHOD,
97 #endif
98 #ifdef SW_SUPPORT_DTLS
99     SW_DTLS_CLIENT_METHOD,
100     SW_DTLS_SERVER_METHOD,
101 #endif
102 };
103 
104 namespace swoole {
105 
106 struct SSLContext {
107     uchar http : 1;
108     uchar http_v2 : 1;
109     uchar prefer_server_ciphers : 1;
110     uchar session_tickets : 1;
111     uchar stapling : 1;
112     uchar stapling_verify : 1;
113     std::string ciphers;
114     std::string ecdh_curve;
115     std::string session_cache;
116     std::string dhparam;
117     std::string cert_file;
118     std::string key_file;
119     std::string passphrase;
120     std::string client_cert_file;
121 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
122     uchar disable_tls_host_name : 1;
123     std::string tls_host_name;
124 #endif
125 
126 #ifdef OPENSSL_IS_BORINGSSL
127     uint8_t grease;
128 #endif
129 
130     std::string cafile;
131     std::string capath;
132     uint8_t verify_depth;
133     uchar disable_compress : 1;
134     uchar verify_peer : 1;
135     uchar allow_self_signed : 1;
136     uint32_t protocols;
137     uint8_t create_flag;
138     SSL_CTX *context;
139 
get_contextSSLContext140     SSL_CTX *get_context() {
141         return context;
142     }
143 
readySSLContext144     bool ready() {
145         return context != nullptr;
146     }
147 
set_protocolsSSLContext148     void set_protocols(uint32_t _protocols) {
149         protocols = _protocols;
150     }
151 
set_cert_fileSSLContext152     bool set_cert_file(const std::string &_cert_file) {
153         if (access(_cert_file.c_str(), R_OK) < 0) {
154             swoole_warning("ssl cert file[%s] not found", _cert_file.c_str());
155             return false;
156         }
157         cert_file = _cert_file;
158         return true;
159     }
160 
set_key_fileSSLContext161     bool set_key_file(const std::string &_key_file) {
162         if (access(_key_file.c_str(), R_OK) < 0) {
163             swoole_warning("ssl key file[%s] not found", _key_file.c_str());
164             return false;
165         }
166         key_file = _key_file;
167         return true;
168     }
169 
170     bool create();
171     bool set_capath();
172     bool set_ciphers();
173     bool set_client_certificate();
174     bool set_ecdh_curve();
175     bool set_dhparam();
176     ~SSLContext();
177 };
178 }
179 
180 void swoole_ssl_init(void);
181 void swoole_ssl_init_thread_safety();
182 bool swoole_ssl_is_thread_safety();
183 void swoole_ssl_server_http_advise(swoole::SSLContext &);
184 const char *swoole_ssl_get_error();
185 int swoole_ssl_get_ex_connection_index();
186 int swoole_ssl_get_ex_port_index();
187 std::string swoole_ssl_get_version_message();
188 
189 #endif
190