Mercurial > projects > hoofbaby
comparison deps/Platinum/ThirdParty/Neptune/ThirdParty/axTLS/ssl/tls1_svr.c @ 0:3425707ddbf6
Initial import (hopefully this mercurial stuff works...)
author | fraserofthenight |
---|---|
date | Mon, 06 Jul 2009 08:06:28 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:3425707ddbf6 |
---|---|
1 /* | |
2 * Copyright (c) 2007, Cameron Rich | |
3 * | |
4 * All rights reserved. | |
5 * | |
6 * Redistribution and use in source and binary forms, with or without | |
7 * modification, are permitted provided that the following conditions are met: | |
8 * | |
9 * * Redistributions of source code must retain the above copyright notice, | |
10 * this list of conditions and the following disclaimer. | |
11 * * Redistributions in binary form must reproduce the above copyright notice, | |
12 * this list of conditions and the following disclaimer in the documentation | |
13 * and/or other materials provided with the distribution. | |
14 * * Neither the name of the axTLS project nor the names of its contributors | |
15 * may be used to endorse or promote products derived from this software | |
16 * without specific prior written permission. | |
17 * | |
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | |
22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
26 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
29 */ | |
30 | |
31 #include <stdlib.h> | |
32 #include <string.h> | |
33 #include <stdio.h> | |
34 | |
35 #include "ssl.h" | |
36 | |
37 static const uint8_t g_hello_done[] = { HS_SERVER_HELLO_DONE, 0, 0, 0 }; | |
38 | |
39 static int process_client_hello(SSL *ssl); | |
40 static int send_server_hello_sequence(SSL *ssl); | |
41 static int send_server_hello(SSL *ssl); | |
42 static int send_server_hello_done(SSL *ssl); | |
43 static int process_client_key_xchg(SSL *ssl); | |
44 #ifdef CONFIG_SSL_CERT_VERIFICATION | |
45 static int send_certificate_request(SSL *ssl); | |
46 static int process_cert_verify(SSL *ssl); | |
47 #endif | |
48 | |
49 /* | |
50 * Establish a new SSL connection to an SSL client. | |
51 */ | |
52 EXP_FUNC SSL * STDCALL ssl_server_new(SSL_CTX *ssl_ctx, SSL_SOCKET* client_fd) | |
53 { | |
54 SSL *ssl; | |
55 | |
56 ssl = ssl_new(ssl_ctx, client_fd); | |
57 ssl->next_state = HS_CLIENT_HELLO; | |
58 | |
59 #ifdef CONFIG_SSL_FULL_MODE | |
60 if (ssl_ctx->chain_length == 0) | |
61 printf("Warning - no server certificate defined\n"); TTY_FLUSH(); | |
62 #endif | |
63 | |
64 return ssl; | |
65 } | |
66 | |
67 /* | |
68 * Process the handshake record. | |
69 */ | |
70 int do_svr_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len) | |
71 { | |
72 int ret = SSL_OK; | |
73 ssl->hs_status = SSL_NOT_OK; /* not connected */ | |
74 | |
75 /* To get here the state must be valid */ | |
76 switch (handshake_type) | |
77 { | |
78 case HS_CLIENT_HELLO: | |
79 if ((ret = process_client_hello(ssl)) == SSL_OK) | |
80 ret = send_server_hello_sequence(ssl); | |
81 break; | |
82 | |
83 #ifdef CONFIG_SSL_CERT_VERIFICATION | |
84 case HS_CERTIFICATE:/* the client sends its cert */ | |
85 ret = process_certificate(ssl, &ssl->x509_ctx); | |
86 | |
87 if (ret == SSL_OK) /* verify the cert */ | |
88 { | |
89 int cert_res; | |
90 cert_res = x509_verify( | |
91 ssl->ssl_ctx->ca_cert_ctx, ssl->x509_ctx); | |
92 ret = (cert_res == 0) ? SSL_OK : SSL_X509_ERROR(cert_res); | |
93 } | |
94 break; | |
95 | |
96 case HS_CERT_VERIFY: | |
97 ret = process_cert_verify(ssl); | |
98 add_packet(ssl, buf, hs_len); /* needs to be done after */ | |
99 break; | |
100 #endif | |
101 case HS_CLIENT_KEY_XCHG: | |
102 ret = process_client_key_xchg(ssl); | |
103 break; | |
104 | |
105 case HS_FINISHED: | |
106 ret = process_finished(ssl, hs_len); | |
107 disposable_free(ssl); /* free up some memory */ | |
108 break; | |
109 } | |
110 | |
111 return ret; | |
112 } | |
113 | |
114 /* | |
115 * Process a client hello message. | |
116 */ | |
117 static int process_client_hello(SSL *ssl) | |
118 { | |
119 uint8_t *buf = ssl->bm_data; | |
120 uint8_t *record_buf = ssl->hmac_header; | |
121 int pkt_size = ssl->bm_index; | |
122 int i, j, cs_len, id_len, offset = 6 + SSL_RANDOM_SIZE; | |
123 int version = (record_buf[1] << 4) + record_buf[2]; | |
124 int ret = SSL_OK; | |
125 | |
126 /* should be v3.1 (TLSv1) or better - we'll send in v3.1 mode anyway */ | |
127 if (version < 0x31) | |
128 { | |
129 ret = SSL_ERROR_INVALID_VERSION; | |
130 ssl_display_error(ret); | |
131 goto error; | |
132 } | |
133 | |
134 memcpy(ssl->dc->client_random, &buf[6], SSL_RANDOM_SIZE); | |
135 | |
136 /* process the session id */ | |
137 id_len = buf[offset++]; | |
138 if (id_len > SSL_SESSION_ID_SIZE) | |
139 { | |
140 return SSL_ERROR_INVALID_SESSION; | |
141 } | |
142 | |
143 #ifndef CONFIG_SSL_SKELETON_MODE | |
144 ssl->session = ssl_session_update(ssl->ssl_ctx->num_sessions, | |
145 ssl->ssl_ctx->ssl_sessions, ssl, id_len ? &buf[offset] : NULL); | |
146 #endif | |
147 | |
148 offset += id_len; | |
149 cs_len = (buf[offset]<<8) + buf[offset+1]; | |
150 offset += 3; /* add 1 due to all cipher suites being 8 bit */ | |
151 | |
152 PARANOIA_CHECK(pkt_size, offset); | |
153 | |
154 /* work out what cipher suite we are going to use */ | |
155 for (j = 0; j < NUM_PROTOCOLS; j++) | |
156 { | |
157 for (i = 0; i < cs_len; i += 2) | |
158 { | |
159 if (ssl_prot_prefs[j] == buf[offset+i]) /* got a match? */ | |
160 { | |
161 ssl->cipher = ssl_prot_prefs[j]; | |
162 goto do_state; | |
163 } | |
164 } | |
165 } | |
166 | |
167 /* ouch! protocol is not supported */ | |
168 ret = SSL_ERROR_NO_CIPHER; | |
169 | |
170 do_state: | |
171 error: | |
172 return ret; | |
173 } | |
174 | |
175 #ifdef CONFIG_SSL_ENABLE_V23_HANDSHAKE | |
176 /* | |
177 * Some browsers use a hybrid SSLv2 "client hello" | |
178 */ | |
179 int process_sslv23_client_hello(SSL *ssl) | |
180 { | |
181 uint8_t *buf = ssl->bm_data; | |
182 int bytes_needed = ((buf[0] & 0x7f) << 8) + buf[1]; | |
183 int version = (buf[3] << 4) + buf[4]; | |
184 int ret = SSL_OK; | |
185 | |
186 /* we have already read 3 extra bytes so far */ | |
187 int read_len = SOCKET_READ(ssl->client_fd, buf, bytes_needed-3); | |
188 int cs_len = buf[1]; | |
189 int id_len = buf[3]; | |
190 int ch_len = buf[5]; | |
191 int i, j, offset = 8; /* start at first cipher */ | |
192 int random_offset = 0; | |
193 | |
194 DISPLAY_BYTES(ssl, "received %d bytes", buf, read_len, read_len); | |
195 | |
196 /* should be v3.1 (TLSv1) or better - we'll send in v3.1 mode anyway */ | |
197 if (version < 0x31) | |
198 { | |
199 return SSL_ERROR_INVALID_VERSION; | |
200 } | |
201 | |
202 add_packet(ssl, buf, read_len); | |
203 | |
204 /* connection has gone, so die */ | |
205 if (bytes_needed < 0) | |
206 { | |
207 return SSL_ERROR_CONN_LOST; | |
208 } | |
209 | |
210 /* now work out what cipher suite we are going to use */ | |
211 for (j = 0; j < NUM_PROTOCOLS; j++) | |
212 { | |
213 for (i = 0; i < cs_len; i += 3) | |
214 { | |
215 if (ssl_prot_prefs[j] == buf[offset+i]) | |
216 { | |
217 ssl->cipher = ssl_prot_prefs[j]; | |
218 goto server_hello; | |
219 } | |
220 } | |
221 } | |
222 | |
223 /* ouch! protocol is not supported */ | |
224 ret = SSL_ERROR_NO_CIPHER; | |
225 goto error; | |
226 | |
227 server_hello: | |
228 /* get the session id */ | |
229 offset += cs_len - 2; /* we've gone 2 bytes past the end */ | |
230 #ifndef CONFIG_SSL_SKELETON_MODE | |
231 ssl->session = ssl_session_update(ssl->ssl_ctx->num_sessions, | |
232 ssl->ssl_ctx->ssl_sessions, ssl, id_len ? &buf[offset] : NULL); | |
233 #endif | |
234 | |
235 /* get the client random data */ | |
236 offset += id_len; | |
237 | |
238 /* random can be anywhere between 16 and 32 bytes long - so it is padded | |
239 * with 0's to the left */ | |
240 if (ch_len == 0x10) | |
241 { | |
242 random_offset += 0x10; | |
243 } | |
244 | |
245 memcpy(&ssl->dc->client_random[random_offset], &buf[offset], ch_len); | |
246 ret = send_server_hello_sequence(ssl); | |
247 | |
248 error: | |
249 return ret; | |
250 } | |
251 #endif | |
252 | |
253 /* | |
254 * Send the entire server hello sequence | |
255 */ | |
256 static int send_server_hello_sequence(SSL *ssl) | |
257 { | |
258 int ret; | |
259 | |
260 if ((ret = send_server_hello(ssl)) == SSL_OK) | |
261 { | |
262 #ifndef CONFIG_SSL_SKELETON_MODE | |
263 /* resume handshake? */ | |
264 if (IS_SET_SSL_FLAG(SSL_SESSION_RESUME)) | |
265 { | |
266 if ((ret = send_change_cipher_spec(ssl)) == SSL_OK) | |
267 { | |
268 ret = send_finished(ssl); | |
269 ssl->next_state = HS_FINISHED; | |
270 } | |
271 } | |
272 else | |
273 #endif | |
274 if ((ret = send_certificate(ssl)) == SSL_OK) | |
275 { | |
276 #ifdef CONFIG_SSL_CERT_VERIFICATION | |
277 /* ask the client for its certificate */ | |
278 if (IS_SET_SSL_FLAG(SSL_CLIENT_AUTHENTICATION)) | |
279 { | |
280 if ((ret = send_certificate_request(ssl)) == SSL_OK) | |
281 { | |
282 ret = send_server_hello_done(ssl); | |
283 ssl->next_state = HS_CERTIFICATE; | |
284 } | |
285 } | |
286 else | |
287 #endif | |
288 { | |
289 ret = send_server_hello_done(ssl); | |
290 ssl->next_state = HS_CLIENT_KEY_XCHG; | |
291 } | |
292 } | |
293 } | |
294 | |
295 return ret; | |
296 } | |
297 | |
298 /* | |
299 * Send a server hello message. | |
300 */ | |
301 static int send_server_hello(SSL *ssl) | |
302 { | |
303 uint8_t *buf = ssl->bm_data; | |
304 int offset = 0; | |
305 | |
306 buf[0] = HS_SERVER_HELLO; | |
307 buf[1] = 0; | |
308 buf[2] = 0; | |
309 /* byte 3 is calculated later */ | |
310 buf[4] = 0x03; | |
311 buf[5] = 0x01; | |
312 | |
313 /* server random value */ | |
314 get_random(SSL_RANDOM_SIZE, &buf[6]); | |
315 memcpy(ssl->dc->server_random, &buf[6], SSL_RANDOM_SIZE); | |
316 offset = 6 + SSL_RANDOM_SIZE; | |
317 | |
318 #ifndef CONFIG_SSL_SKELETON_MODE | |
319 if (IS_SET_SSL_FLAG(SSL_SESSION_RESUME)) | |
320 { | |
321 /* retrieve id from session cache */ | |
322 buf[offset++] = SSL_SESSION_ID_SIZE; | |
323 memcpy(&buf[offset], ssl->session->session_id, SSL_SESSION_ID_SIZE); | |
324 memcpy(ssl->session_id, ssl->session->session_id, SSL_SESSION_ID_SIZE); | |
325 ssl->sess_id_size = SSL_SESSION_ID_SIZE; | |
326 offset += SSL_SESSION_ID_SIZE; | |
327 } | |
328 else /* generate our own session id */ | |
329 #endif | |
330 { | |
331 #ifndef CONFIG_SSL_SKELETON_MODE | |
332 buf[offset++] = SSL_SESSION_ID_SIZE; | |
333 get_random(SSL_SESSION_ID_SIZE, &buf[offset]); | |
334 memcpy(ssl->session_id, &buf[offset], SSL_SESSION_ID_SIZE); | |
335 ssl->sess_id_size = SSL_SESSION_ID_SIZE; | |
336 | |
337 /* store id in session cache */ | |
338 if (ssl->ssl_ctx->num_sessions) | |
339 { | |
340 memcpy(ssl->session->session_id, | |
341 ssl->session_id, SSL_SESSION_ID_SIZE); | |
342 } | |
343 | |
344 offset += SSL_SESSION_ID_SIZE; | |
345 #else | |
346 buf[offset++] = 0; /* don't bother with session id in skelton mode */ | |
347 #endif | |
348 } | |
349 | |
350 buf[offset++] = 0; /* cipher we are using */ | |
351 buf[offset++] = ssl->cipher; | |
352 buf[offset++] = 0; /* no compression */ | |
353 buf[3] = offset - 4; /* handshake size */ | |
354 return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, offset); | |
355 } | |
356 | |
357 /* | |
358 * Send the server hello done message. | |
359 */ | |
360 static int send_server_hello_done(SSL *ssl) | |
361 { | |
362 return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, | |
363 g_hello_done, sizeof(g_hello_done)); | |
364 } | |
365 | |
366 /* | |
367 * Pull apart a client key exchange message. Decrypt the pre-master key (using | |
368 * our RSA private key) and then work out the master key. Initialise the | |
369 * ciphers. | |
370 */ | |
371 static int process_client_key_xchg(SSL *ssl) | |
372 { | |
373 uint8_t *buf = ssl->bm_data; | |
374 int pkt_size = ssl->bm_index; | |
375 int premaster_size, secret_length = (buf[2] << 8) + buf[3]; | |
376 uint8_t premaster_secret[MAX_KEY_BYTE_SIZE]; | |
377 RSA_CTX *rsa_ctx = ssl->ssl_ctx->rsa_ctx; | |
378 int offset = 4; | |
379 int ret = SSL_OK; | |
380 | |
381 DISPLAY_RSA(ssl, rsa_ctx); | |
382 | |
383 /* is there an extra size field? */ | |
384 if ((secret_length - 2) == rsa_ctx->num_octets) | |
385 offset += 2; | |
386 | |
387 PARANOIA_CHECK(pkt_size, rsa_ctx->num_octets+offset); | |
388 | |
389 /* rsa_ctx->bi_ctx is not thread-safe */ | |
390 SSL_CTX_LOCK(ssl->ssl_ctx->mutex); | |
391 premaster_size = RSA_decrypt(rsa_ctx, &buf[offset], premaster_secret, 1); | |
392 SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); | |
393 | |
394 if (premaster_size != SSL_SECRET_SIZE || | |
395 premaster_secret[0] != 0x03 || /* check version is 3.1 (TLS) */ | |
396 premaster_secret[1] != 0x01) | |
397 { | |
398 /* guard against a Bleichenbacher attack */ | |
399 memset(premaster_secret, 0, SSL_SECRET_SIZE); | |
400 /* and continue - will die eventually when checking the mac */ | |
401 } | |
402 | |
403 #if 0 | |
404 print_blob("pre-master", premaster_secret, SSL_SECRET_SIZE); | |
405 #endif | |
406 | |
407 generate_master_secret(ssl, premaster_secret); | |
408 | |
409 #ifdef CONFIG_SSL_CERT_VERIFICATION | |
410 ssl->next_state = IS_SET_SSL_FLAG(SSL_CLIENT_AUTHENTICATION) ? | |
411 HS_CERT_VERIFY : HS_FINISHED; | |
412 #else | |
413 ssl->next_state = HS_FINISHED; | |
414 #endif | |
415 error: | |
416 return ret; | |
417 } | |
418 | |
419 #ifdef CONFIG_SSL_CERT_VERIFICATION | |
420 static const uint8_t g_cert_request[] = { HS_CERT_REQ, 0, 0, 4, 1, 0, 0, 0 }; | |
421 | |
422 /* | |
423 * Send the certificate request message. | |
424 */ | |
425 static int send_certificate_request(SSL *ssl) | |
426 { | |
427 return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, | |
428 g_cert_request, sizeof(g_cert_request)); | |
429 } | |
430 | |
431 /* | |
432 * Ensure the client has the private key by first decrypting the packet and | |
433 * then checking the packet digests. | |
434 */ | |
435 static int process_cert_verify(SSL *ssl) | |
436 { | |
437 uint8_t *buf = ssl->bm_data; | |
438 int pkt_size = ssl->bm_index; | |
439 uint8_t dgst_buf[MAX_KEY_BYTE_SIZE]; | |
440 uint8_t dgst[MD5_SIZE+SHA1_SIZE]; | |
441 X509_CTX *x509_ctx = ssl->x509_ctx; | |
442 int ret = SSL_OK; | |
443 int n; | |
444 | |
445 PARANOIA_CHECK(pkt_size, x509_ctx->rsa_ctx->num_octets+6); | |
446 | |
447 DISPLAY_RSA(ssl, x509_ctx->rsa_ctx); | |
448 | |
449 /* rsa_ctx->bi_ctx is not thread-safe */ | |
450 SSL_CTX_LOCK(ssl->ssl_ctx->mutex); | |
451 n = RSA_decrypt(x509_ctx->rsa_ctx, &buf[6], dgst_buf, 0); | |
452 SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); | |
453 | |
454 if (n != SHA1_SIZE + MD5_SIZE) | |
455 { | |
456 ret = SSL_ERROR_INVALID_KEY; | |
457 goto end_cert_vfy; | |
458 } | |
459 | |
460 finished_digest(ssl, NULL, dgst); /* calculate the digest */ | |
461 if (memcmp(dgst_buf, dgst, MD5_SIZE + SHA1_SIZE)) | |
462 { | |
463 ret = SSL_ERROR_INVALID_KEY; | |
464 } | |
465 | |
466 end_cert_vfy: | |
467 ssl->next_state = HS_FINISHED; | |
468 error: | |
469 return ret; | |
470 } | |
471 | |
472 #endif |