Mercurial > projects > hoofbaby
comparison deps/Platinum/ThirdParty/Neptune/ThirdParty/axTLS/ssl/tls1_clnt.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 <time.h> | |
34 #include <stdio.h> | |
35 | |
36 #include "ssl.h" | |
37 | |
38 #ifdef CONFIG_SSL_ENABLE_CLIENT /* all commented out if no client */ | |
39 | |
40 static int send_client_hello(SSL *ssl); | |
41 static int process_server_hello(SSL *ssl); | |
42 static int process_server_hello_done(SSL *ssl); | |
43 static int send_client_key_xchg(SSL *ssl); | |
44 static int process_cert_req(SSL *ssl); | |
45 static int send_cert_verify(SSL *ssl); | |
46 | |
47 /* | |
48 * Establish a new SSL connection to an SSL server. | |
49 */ | |
50 EXP_FUNC SSL * STDCALL ssl_client_new(SSL_CTX *ssl_ctx, SSL_SOCKET* client_fd, const | |
51 uint8_t *session_id, uint8_t sess_id_size) | |
52 { | |
53 SSL *ssl; | |
54 int ret; | |
55 | |
56 SOCKET_BLOCK(client_fd); /* ensure blocking mode */ | |
57 ssl = ssl_new(ssl_ctx, client_fd); | |
58 | |
59 if (session_id && ssl_ctx->num_sessions) | |
60 { | |
61 if (sess_id_size > SSL_SESSION_ID_SIZE) /* validity check */ | |
62 { | |
63 ssl_free(ssl); | |
64 return NULL; | |
65 } | |
66 | |
67 memcpy(ssl->session_id, session_id, sess_id_size); | |
68 ssl->sess_id_size = sess_id_size; | |
69 SET_SSL_FLAG(SSL_SESSION_RESUME); /* just flag for later */ | |
70 } | |
71 | |
72 SET_SSL_FLAG(SSL_IS_CLIENT); | |
73 ret = do_client_connect(ssl); | |
74 return ssl; | |
75 } | |
76 | |
77 /* | |
78 * Process the handshake record. | |
79 */ | |
80 int do_clnt_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len) | |
81 { | |
82 int ret = SSL_OK; | |
83 | |
84 /* To get here the state must be valid */ | |
85 switch (handshake_type) | |
86 { | |
87 case HS_SERVER_HELLO: | |
88 ret = process_server_hello(ssl); | |
89 break; | |
90 | |
91 case HS_CERTIFICATE: | |
92 ret = process_certificate(ssl, &ssl->x509_ctx); | |
93 break; | |
94 | |
95 case HS_SERVER_HELLO_DONE: | |
96 if ((ret = process_server_hello_done(ssl)) == SSL_OK) | |
97 { | |
98 if (IS_SET_SSL_FLAG(SSL_HAS_CERT_REQ)) | |
99 { | |
100 if ((ret = send_certificate(ssl)) == SSL_OK && | |
101 (ret = send_client_key_xchg(ssl)) == SSL_OK) | |
102 { | |
103 send_cert_verify(ssl); | |
104 } | |
105 } | |
106 else | |
107 { | |
108 ret = send_client_key_xchg(ssl); | |
109 } | |
110 | |
111 if (ret == SSL_OK && | |
112 (ret = send_change_cipher_spec(ssl)) == SSL_OK) | |
113 { | |
114 ret = send_finished(ssl); | |
115 } | |
116 } | |
117 break; | |
118 | |
119 case HS_CERT_REQ: | |
120 ret = process_cert_req(ssl); | |
121 break; | |
122 | |
123 case HS_FINISHED: | |
124 ret = process_finished(ssl, hs_len); | |
125 disposable_free(ssl); /* free up some memory */ | |
126 break; | |
127 | |
128 case HS_HELLO_REQUEST: | |
129 disposable_new(ssl); | |
130 ret = do_client_connect(ssl); | |
131 break; | |
132 } | |
133 | |
134 return ret; | |
135 } | |
136 | |
137 /* | |
138 * Do the handshaking from the beginning. | |
139 */ | |
140 int do_client_connect(SSL *ssl) | |
141 { | |
142 int ret = SSL_OK; | |
143 | |
144 send_client_hello(ssl); /* send the client hello */ | |
145 ssl->bm_read_index = 0; | |
146 ssl->next_state = HS_SERVER_HELLO; | |
147 ssl->hs_status = SSL_NOT_OK; /* not connected */ | |
148 x509_free(ssl->x509_ctx); | |
149 | |
150 /* sit in a loop until it all looks good */ | |
151 while (ssl->hs_status != SSL_OK) | |
152 { | |
153 ret = basic_read(ssl, NULL); | |
154 | |
155 if (ret < SSL_OK) | |
156 { | |
157 if (ret != SSL_ERROR_CONN_LOST && | |
158 ret != SSL_ERROR_TIMEOUT && /* GBG */ | |
159 ret != SSL_ERROR_EOS /* GBG */) | |
160 { | |
161 /* let the server know we are dying and why */ | |
162 if (send_alert(ssl, ret)) | |
163 { | |
164 /* something nasty happened, so get rid of it */ | |
165 kill_ssl_session(ssl->ssl_ctx->ssl_sessions, ssl); | |
166 } | |
167 } | |
168 | |
169 break; | |
170 } | |
171 } | |
172 | |
173 ssl->hs_status = ret; /* connected? */ | |
174 return ret; | |
175 } | |
176 | |
177 /* | |
178 * Send the initial client hello. | |
179 */ | |
180 static int send_client_hello(SSL *ssl) | |
181 { | |
182 uint8_t *buf = ssl->bm_data; | |
183 time_t tm = time(NULL); | |
184 uint8_t *tm_ptr = &buf[6]; /* time will go here */ | |
185 int i, offset; | |
186 | |
187 buf[0] = HS_CLIENT_HELLO; | |
188 buf[1] = 0; | |
189 buf[2] = 0; | |
190 /* byte 3 is calculated later */ | |
191 buf[4] = 0x03; | |
192 buf[5] = 0x01; | |
193 | |
194 /* client random value - spec says that 1st 4 bytes are big endian time */ | |
195 *tm_ptr++ = (uint8_t)(((long)tm & 0xff000000) >> 24); | |
196 *tm_ptr++ = (uint8_t)(((long)tm & 0x00ff0000) >> 16); | |
197 *tm_ptr++ = (uint8_t)(((long)tm & 0x0000ff00) >> 8); | |
198 *tm_ptr++ = (uint8_t)(((long)tm & 0x000000ff)); | |
199 get_random(SSL_RANDOM_SIZE-4, &buf[10]); | |
200 memcpy(ssl->dc->client_random, &buf[6], SSL_RANDOM_SIZE); | |
201 offset = 6 + SSL_RANDOM_SIZE; | |
202 | |
203 /* give session resumption a go */ | |
204 if (IS_SET_SSL_FLAG(SSL_SESSION_RESUME)) /* set initially by user */ | |
205 { | |
206 buf[offset++] = ssl->sess_id_size; | |
207 memcpy(&buf[offset], ssl->session_id, ssl->sess_id_size); | |
208 offset += ssl->sess_id_size; | |
209 CLR_SSL_FLAG(SSL_SESSION_RESUME); /* clear so we can set later */ | |
210 } | |
211 else | |
212 { | |
213 /* no session id - because no session resumption just yet */ | |
214 buf[offset++] = 0; | |
215 } | |
216 | |
217 buf[offset++] = 0; /* number of ciphers */ | |
218 buf[offset++] = NUM_PROTOCOLS*2;/* number of ciphers */ | |
219 | |
220 /* put all our supported protocols in our request */ | |
221 for (i = 0; i < NUM_PROTOCOLS; i++) | |
222 { | |
223 buf[offset++] = 0; /* cipher we are using */ | |
224 buf[offset++] = ssl_prot_prefs[i]; | |
225 } | |
226 | |
227 buf[offset++] = 1; /* no compression */ | |
228 buf[offset++] = 0; | |
229 buf[3] = offset - 4; /* handshake size */ | |
230 | |
231 return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, offset); | |
232 } | |
233 | |
234 /* | |
235 * Process the server hello. | |
236 */ | |
237 static int process_server_hello(SSL *ssl) | |
238 { | |
239 uint8_t *buf = ssl->bm_data; | |
240 int pkt_size = ssl->bm_index; | |
241 int version = (buf[4] << 4) + buf[5]; | |
242 int num_sessions = ssl->ssl_ctx->num_sessions; | |
243 uint8_t sess_id_size; | |
244 int offset, ret = SSL_OK; | |
245 | |
246 /* check that we are talking to a TLSv1 server */ | |
247 if (version != 0x31) | |
248 return SSL_ERROR_INVALID_VERSION; | |
249 | |
250 /* get the server random value */ | |
251 memcpy(ssl->dc->server_random, &buf[6], SSL_RANDOM_SIZE); | |
252 offset = 6 + SSL_RANDOM_SIZE; /* skip of session id size */ | |
253 sess_id_size = buf[offset++]; | |
254 | |
255 if (num_sessions) | |
256 { | |
257 ssl->session = ssl_session_update(num_sessions, | |
258 ssl->ssl_ctx->ssl_sessions, ssl, &buf[offset]); | |
259 memcpy(ssl->session->session_id, &buf[offset], sess_id_size); | |
260 | |
261 /* pad the rest with 0's */ | |
262 if (sess_id_size < SSL_SESSION_ID_SIZE) | |
263 { | |
264 memset(&ssl->session->session_id[sess_id_size], 0, | |
265 SSL_SESSION_ID_SIZE-sess_id_size); | |
266 } | |
267 } | |
268 | |
269 memcpy(ssl->session_id, &buf[offset], sess_id_size); | |
270 ssl->sess_id_size = sess_id_size; | |
271 offset += sess_id_size; | |
272 | |
273 /* get the real cipher we are using */ | |
274 ssl->cipher = buf[++offset]; | |
275 ssl->next_state = IS_SET_SSL_FLAG(SSL_SESSION_RESUME) ? | |
276 HS_FINISHED : HS_CERTIFICATE; | |
277 | |
278 offset++; // skip the compr | |
279 PARANOIA_CHECK(pkt_size, offset); | |
280 ssl->dc->bm_proc_index = offset+1; | |
281 | |
282 error: | |
283 return ret; | |
284 } | |
285 | |
286 /** | |
287 * Process the server hello done message. | |
288 */ | |
289 static int process_server_hello_done(SSL *ssl) | |
290 { | |
291 ssl->next_state = HS_FINISHED; | |
292 return SSL_OK; | |
293 } | |
294 | |
295 /* | |
296 * Send a client key exchange message. | |
297 */ | |
298 static int send_client_key_xchg(SSL *ssl) | |
299 { | |
300 uint8_t *buf = ssl->bm_data; | |
301 uint8_t premaster_secret[SSL_SECRET_SIZE]; | |
302 int enc_secret_size = -1; | |
303 | |
304 buf[0] = HS_CLIENT_KEY_XCHG; | |
305 buf[1] = 0; | |
306 | |
307 premaster_secret[0] = 0x03; /* encode the version number */ | |
308 premaster_secret[1] = 0x01; | |
309 get_random(SSL_SECRET_SIZE-2, &premaster_secret[2]); | |
310 DISPLAY_RSA(ssl, ssl->x509_ctx->rsa_ctx); | |
311 | |
312 /* rsa_ctx->bi_ctx is not thread-safe */ | |
313 SSL_CTX_LOCK(ssl->ssl_ctx->mutex); | |
314 enc_secret_size = RSA_encrypt(ssl->x509_ctx->rsa_ctx, premaster_secret, | |
315 SSL_SECRET_SIZE, &buf[6], 0); | |
316 SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); | |
317 | |
318 buf[2] = (enc_secret_size + 2) >> 8; | |
319 buf[3] = (enc_secret_size + 2) & 0xff; | |
320 buf[4] = enc_secret_size >> 8; | |
321 buf[5] = enc_secret_size & 0xff; | |
322 | |
323 generate_master_secret(ssl, premaster_secret); | |
324 return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, enc_secret_size+6); | |
325 } | |
326 | |
327 /* | |
328 * Process the certificate request. | |
329 */ | |
330 static int process_cert_req(SSL *ssl) | |
331 { | |
332 uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index]; | |
333 int ret = SSL_OK; | |
334 int offset = (buf[2] << 4) + buf[3]; | |
335 int pkt_size = ssl->bm_index; | |
336 | |
337 /* don't do any processing - we will send back an RSA certificate anyway */ | |
338 ssl->next_state = HS_SERVER_HELLO_DONE; | |
339 SET_SSL_FLAG(SSL_HAS_CERT_REQ); | |
340 ssl->dc->bm_proc_index += offset; | |
341 PARANOIA_CHECK(pkt_size, offset); | |
342 error: | |
343 return ret; | |
344 } | |
345 | |
346 /* | |
347 * Send a certificate verify message. | |
348 */ | |
349 static int send_cert_verify(SSL *ssl) | |
350 { | |
351 uint8_t *buf = ssl->bm_data; | |
352 uint8_t dgst[MD5_SIZE+SHA1_SIZE]; | |
353 RSA_CTX *rsa_ctx = ssl->ssl_ctx->rsa_ctx; | |
354 int n = 0, ret; | |
355 | |
356 DISPLAY_RSA(ssl, rsa_ctx); | |
357 | |
358 buf[0] = HS_CERT_VERIFY; | |
359 buf[1] = 0; | |
360 | |
361 finished_digest(ssl, NULL, dgst); /* calculate the digest */ | |
362 | |
363 /* rsa_ctx->bi_ctx is not thread-safe */ | |
364 if (rsa_ctx) | |
365 { | |
366 SSL_CTX_LOCK(ssl->ssl_ctx->mutex); | |
367 n = RSA_encrypt(rsa_ctx, dgst, sizeof(dgst), &buf[6], 1); | |
368 SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); | |
369 | |
370 if (n == 0) | |
371 { | |
372 ret = SSL_ERROR_INVALID_KEY; | |
373 goto error; | |
374 } | |
375 } | |
376 | |
377 buf[4] = n >> 8; /* add the RSA size (not officially documented) */ | |
378 buf[5] = n & 0xff; | |
379 n += 2; | |
380 buf[2] = n >> 8; | |
381 buf[3] = n & 0xff; | |
382 ret = send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, n+4); | |
383 | |
384 error: | |
385 return ret; | |
386 } | |
387 | |
388 #endif /* CONFIG_SSL_ENABLE_CLIENT */ |