diff options
Diffstat (limited to 'src/microspdy/io_openssl.c')
-rw-r--r-- | src/microspdy/io_openssl.c | 280 |
1 files changed, 0 insertions, 280 deletions
diff --git a/src/microspdy/io_openssl.c b/src/microspdy/io_openssl.c deleted file mode 100644 index f71a9230..00000000 --- a/src/microspdy/io_openssl.c +++ /dev/null | |||
@@ -1,280 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of libmicrospdy | ||
3 | Copyright Copyright (C) 2012 Andrey Uzunov | ||
4 | |||
5 | This program is free software: you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation, either version 3 of the License, or | ||
8 | (at your option) any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | /** | ||
20 | * @file io_openssl.c | ||
21 | * @brief TLS handling using libssl. The current code assumes that | ||
22 | * blocking I/O is in use. | ||
23 | * @author Andrey Uzunov | ||
24 | */ | ||
25 | |||
26 | #include "platform.h" | ||
27 | #include "internal.h" | ||
28 | #include "session.h" | ||
29 | #include "io_openssl.h" | ||
30 | |||
31 | |||
32 | /** | ||
33 | * Callback to advertise spdy ver. 3 in Next Protocol Negotiation | ||
34 | * | ||
35 | * @param ssl openssl context for a connection | ||
36 | * @param out must be set to the raw data that is advertised in NPN | ||
37 | * @param outlen must be set to size of out | ||
38 | * @param arg | ||
39 | * @return SSL_TLSEXT_ERR_OK to do advertising | ||
40 | */ | ||
41 | static int | ||
42 | spdyf_next_protos_advertised_cb (SSL *ssl, const unsigned char **out, unsigned int *outlen, void *arg) | ||
43 | { | ||
44 | (void)ssl; | ||
45 | (void)arg; | ||
46 | static unsigned char npn_spdy3[] = {0x06, // length of "spdy/3" | ||
47 | 0x73,0x70,0x64,0x79,0x2f,0x33};// spdy/3 | ||
48 | |||
49 | *out = npn_spdy3; | ||
50 | *outlen = 7; // total length of npn_spdy3 | ||
51 | return SSL_TLSEXT_ERR_OK; | ||
52 | } | ||
53 | |||
54 | |||
55 | void | ||
56 | SPDYF_openssl_global_init() | ||
57 | { | ||
58 | //error strings are now not used by the lib | ||
59 | //SSL_load_error_strings(); | ||
60 | //init libssl | ||
61 | SSL_library_init(); //always returns 1 | ||
62 | //the table for looking up algos is not used now by the lib | ||
63 | //OpenSSL_add_all_algorithms(); | ||
64 | } | ||
65 | |||
66 | |||
67 | void | ||
68 | SPDYF_openssl_global_deinit() | ||
69 | { | ||
70 | //if SSL_load_error_strings was called | ||
71 | //ERR_free_strings(); | ||
72 | //if OpenSSL_add_all_algorithms was called | ||
73 | //EVP_cleanup(); | ||
74 | } | ||
75 | |||
76 | |||
77 | int | ||
78 | SPDYF_openssl_init(struct SPDY_Daemon *daemon) | ||
79 | { | ||
80 | int options; | ||
81 | //create ssl context. TLSv1 used | ||
82 | if(NULL == (daemon->io_context = SSL_CTX_new(TLSv1_server_method()))) | ||
83 | { | ||
84 | SPDYF_DEBUG("Couldn't create ssl context"); | ||
85 | return SPDY_NO; | ||
86 | } | ||
87 | //set options for tls | ||
88 | //TODO DH is not enabled for easier debugging | ||
89 | //SSL_CTX_set_options(daemon->io_context, SSL_OP_SINGLE_DH_USE); | ||
90 | |||
91 | //TODO here session tickets are disabled for easier debuging with | ||
92 | //wireshark when using Chrome | ||
93 | // SSL_OP_NO_COMPRESSION disables TLS compression to avoid CRIME attack | ||
94 | options = SSL_OP_NO_TICKET; | ||
95 | #ifdef SSL_OP_NO_COMPRESSION | ||
96 | options |= SSL_OP_NO_COMPRESSION; | ||
97 | #elif OPENSSL_VERSION_NUMBER >= 0x00908000L /* workaround for OpenSSL 0.9.8 */ | ||
98 | sk_SSL_COMP_zero(SSL_COMP_get_compression_methods()); | ||
99 | #endif | ||
100 | |||
101 | SSL_CTX_set_options(daemon->io_context, options); | ||
102 | if(1 != SSL_CTX_use_certificate_file(daemon->io_context, daemon->certfile , SSL_FILETYPE_PEM)) | ||
103 | { | ||
104 | SPDYF_DEBUG("Couldn't load the cert file"); | ||
105 | SSL_CTX_free(daemon->io_context); | ||
106 | return SPDY_NO; | ||
107 | } | ||
108 | if(1 != SSL_CTX_use_PrivateKey_file(daemon->io_context, daemon->keyfile, SSL_FILETYPE_PEM)) | ||
109 | { | ||
110 | SPDYF_DEBUG("Couldn't load the name file"); | ||
111 | SSL_CTX_free(daemon->io_context); | ||
112 | return SPDY_NO; | ||
113 | } | ||
114 | SSL_CTX_set_next_protos_advertised_cb(daemon->io_context, &spdyf_next_protos_advertised_cb, NULL); | ||
115 | if (1 != SSL_CTX_set_cipher_list(daemon->io_context, "HIGH")) | ||
116 | { | ||
117 | SPDYF_DEBUG("Couldn't set the desired cipher list"); | ||
118 | SSL_CTX_free(daemon->io_context); | ||
119 | return SPDY_NO; | ||
120 | } | ||
121 | |||
122 | return SPDY_YES; | ||
123 | } | ||
124 | |||
125 | |||
126 | void | ||
127 | SPDYF_openssl_deinit(struct SPDY_Daemon *daemon) | ||
128 | { | ||
129 | SSL_CTX_free(daemon->io_context); | ||
130 | } | ||
131 | |||
132 | |||
133 | int | ||
134 | SPDYF_openssl_new_session(struct SPDY_Session *session) | ||
135 | { | ||
136 | int ret; | ||
137 | |||
138 | if(NULL == (session->io_context = SSL_new(session->daemon->io_context))) | ||
139 | { | ||
140 | SPDYF_DEBUG("Couldn't create ssl structure"); | ||
141 | return SPDY_NO; | ||
142 | } | ||
143 | if(1 != (ret = SSL_set_fd(session->io_context, session->socket_fd))) | ||
144 | { | ||
145 | SPDYF_DEBUG("SSL_set_fd %i",ret); | ||
146 | SSL_free(session->io_context); | ||
147 | session->io_context = NULL; | ||
148 | return SPDY_NO; | ||
149 | } | ||
150 | |||
151 | //for non-blocking I/O SSL_accept may return -1 | ||
152 | //and this function won't work | ||
153 | if(1 != (ret = SSL_accept(session->io_context))) | ||
154 | { | ||
155 | SPDYF_DEBUG("SSL_accept %i",ret); | ||
156 | SSL_free(session->io_context); | ||
157 | session->io_context = NULL; | ||
158 | return SPDY_NO; | ||
159 | } | ||
160 | /* alternatively | ||
161 | SSL_set_accept_state(session->io_context); | ||
162 | * may be called and then the negotiation will be done on reading | ||
163 | */ | ||
164 | |||
165 | return SPDY_YES; | ||
166 | } | ||
167 | |||
168 | |||
169 | void | ||
170 | SPDYF_openssl_close_session(struct SPDY_Session *session) | ||
171 | { | ||
172 | //SSL_shutdown sends TLS "close notify" as in TLS standard. | ||
173 | //The function may fail as it waits for the other party to also close | ||
174 | //the TLS session. The lib just sends it and will close the socket | ||
175 | //after that because the browsers don't seem to care much about | ||
176 | //"close notify" | ||
177 | SSL_shutdown(session->io_context); | ||
178 | |||
179 | SSL_free(session->io_context); | ||
180 | } | ||
181 | |||
182 | |||
183 | int | ||
184 | SPDYF_openssl_recv(struct SPDY_Session *session, | ||
185 | void * buffer, | ||
186 | size_t size) | ||
187 | { | ||
188 | int ret; | ||
189 | int n = SSL_read(session->io_context, | ||
190 | buffer, | ||
191 | size); | ||
192 | //if(n > 0) SPDYF_DEBUG("recvd: %i",n); | ||
193 | if (n <= 0) | ||
194 | { | ||
195 | ret = SSL_get_error(session->io_context, n); | ||
196 | switch(ret) | ||
197 | { | ||
198 | case SSL_ERROR_ZERO_RETURN: | ||
199 | return 0; | ||
200 | |||
201 | case SSL_ERROR_WANT_READ: | ||
202 | case SSL_ERROR_WANT_WRITE: | ||
203 | return SPDY_IO_ERROR_AGAIN; | ||
204 | |||
205 | case SSL_ERROR_SYSCALL: | ||
206 | if(EINTR == errno) | ||
207 | return SPDY_IO_ERROR_AGAIN; | ||
208 | return SPDY_IO_ERROR_ERROR; | ||
209 | default: | ||
210 | return SPDY_IO_ERROR_ERROR; | ||
211 | } | ||
212 | } | ||
213 | |||
214 | return n; | ||
215 | } | ||
216 | |||
217 | |||
218 | int | ||
219 | SPDYF_openssl_send(struct SPDY_Session *session, | ||
220 | const void * buffer, | ||
221 | size_t size) | ||
222 | { | ||
223 | int ret; | ||
224 | |||
225 | int n = SSL_write(session->io_context, | ||
226 | buffer, | ||
227 | size); | ||
228 | //if(n > 0) SPDYF_DEBUG("sent: %i",n); | ||
229 | if (n <= 0) | ||
230 | { | ||
231 | ret = SSL_get_error(session->io_context, n); | ||
232 | switch(ret) | ||
233 | { | ||
234 | case SSL_ERROR_ZERO_RETURN: | ||
235 | return 0; | ||
236 | |||
237 | case SSL_ERROR_WANT_READ: | ||
238 | case SSL_ERROR_WANT_WRITE: | ||
239 | return SPDY_IO_ERROR_AGAIN; | ||
240 | |||
241 | case SSL_ERROR_SYSCALL: | ||
242 | if(EINTR == errno) | ||
243 | return SPDY_IO_ERROR_AGAIN; | ||
244 | return SPDY_IO_ERROR_ERROR; | ||
245 | default: | ||
246 | return SPDY_IO_ERROR_ERROR; | ||
247 | } | ||
248 | } | ||
249 | |||
250 | return n; | ||
251 | } | ||
252 | |||
253 | |||
254 | int | ||
255 | SPDYF_openssl_is_pending(struct SPDY_Session *session) | ||
256 | { | ||
257 | /* From openssl docs: | ||
258 | * BUGS | ||
259 | SSL_pending() takes into account only bytes from the TLS/SSL record that is currently being processed (if any). If the SSL object's read_ahead flag is set, additional protocol bytes may have been read containing more TLS/SSL records; these are ignored by SSL_pending(). | ||
260 | */ | ||
261 | return SSL_pending(session->io_context) > 0 ? SPDY_YES : SPDY_NO; | ||
262 | } | ||
263 | |||
264 | |||
265 | int | ||
266 | SPDYF_openssl_before_write(struct SPDY_Session *session) | ||
267 | { | ||
268 | (void)session; | ||
269 | |||
270 | return SPDY_YES; | ||
271 | } | ||
272 | |||
273 | |||
274 | int | ||
275 | SPDYF_openssl_after_write(struct SPDY_Session *session, int was_written) | ||
276 | { | ||
277 | (void)session; | ||
278 | |||
279 | return was_written; | ||
280 | } | ||