Rough and ready port of axTLS

Committer:
ashleymills
Date:
Mon May 13 18:15:18 2013 +0000
Revision:
0:5a29fd060ac8
initial commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ashleymills 0:5a29fd060ac8 1 /*
ashleymills 0:5a29fd060ac8 2 * Copyright (c) 2007, Cameron Rich
ashleymills 0:5a29fd060ac8 3 *
ashleymills 0:5a29fd060ac8 4 * All rights reserved.
ashleymills 0:5a29fd060ac8 5 *
ashleymills 0:5a29fd060ac8 6 * Redistribution and use in source and binary forms, with or without
ashleymills 0:5a29fd060ac8 7 * modification, are permitted provided that the following conditions are met:
ashleymills 0:5a29fd060ac8 8 *
ashleymills 0:5a29fd060ac8 9 * * Redistributions of source code must retain the above copyright notice,
ashleymills 0:5a29fd060ac8 10 * this list of conditions and the following disclaimer.
ashleymills 0:5a29fd060ac8 11 * * Redistributions in binary form must reproduce the above copyright notice,
ashleymills 0:5a29fd060ac8 12 * this list of conditions and the following disclaimer in the documentation
ashleymills 0:5a29fd060ac8 13 * and/or other materials provided with the distribution.
ashleymills 0:5a29fd060ac8 14 * * Neither the name of the axTLS project nor the names of its contributors
ashleymills 0:5a29fd060ac8 15 * may be used to endorse or promote products derived from this software
ashleymills 0:5a29fd060ac8 16 * without specific prior written permission.
ashleymills 0:5a29fd060ac8 17 *
ashleymills 0:5a29fd060ac8 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
ashleymills 0:5a29fd060ac8 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
ashleymills 0:5a29fd060ac8 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
ashleymills 0:5a29fd060ac8 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
ashleymills 0:5a29fd060ac8 22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
ashleymills 0:5a29fd060ac8 23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
ashleymills 0:5a29fd060ac8 24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
ashleymills 0:5a29fd060ac8 25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
ashleymills 0:5a29fd060ac8 26 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
ashleymills 0:5a29fd060ac8 27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
ashleymills 0:5a29fd060ac8 28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
ashleymills 0:5a29fd060ac8 29 */
ashleymills 0:5a29fd060ac8 30
ashleymills 0:5a29fd060ac8 31 #include <stdlib.h>
ashleymills 0:5a29fd060ac8 32 #include <string.h>
ashleymills 0:5a29fd060ac8 33 #include <time.h>
ashleymills 0:5a29fd060ac8 34 #include <stdio.h>
ashleymills 0:5a29fd060ac8 35 #include "os_port.h"
ashleymills 0:5a29fd060ac8 36 #include "ssl.h"
ashleymills 0:5a29fd060ac8 37
ashleymills 0:5a29fd060ac8 38 #ifdef CONFIG_SSL_ENABLE_CLIENT /* all commented out if no client */
ashleymills 0:5a29fd060ac8 39
ashleymills 0:5a29fd060ac8 40 static int send_client_hello(SSL *ssl);
ashleymills 0:5a29fd060ac8 41 static int process_server_hello(SSL *ssl);
ashleymills 0:5a29fd060ac8 42 static int process_server_hello_done(SSL *ssl);
ashleymills 0:5a29fd060ac8 43 static int send_client_key_xchg(SSL *ssl);
ashleymills 0:5a29fd060ac8 44 static int process_cert_req(SSL *ssl);
ashleymills 0:5a29fd060ac8 45 static int send_cert_verify(SSL *ssl);
ashleymills 0:5a29fd060ac8 46
ashleymills 0:5a29fd060ac8 47 /*
ashleymills 0:5a29fd060ac8 48 * Establish a new SSL connection to an SSL server.
ashleymills 0:5a29fd060ac8 49 */
ashleymills 0:5a29fd060ac8 50 EXP_FUNC SSL * STDCALL ssl_client_new(SSL_CTX *ssl_ctx, int client_fd, const
ashleymills 0:5a29fd060ac8 51 uint8_t *session_id, uint8_t sess_id_size)
ashleymills 0:5a29fd060ac8 52 {
ashleymills 0:5a29fd060ac8 53 SSL *ssl = ssl_new(ssl_ctx, client_fd);
ashleymills 0:5a29fd060ac8 54 ssl->version = SSL_PROTOCOL_VERSION_MAX; /* try top version first */
ashleymills 0:5a29fd060ac8 55
ashleymills 0:5a29fd060ac8 56 if (session_id && ssl_ctx->num_sessions)
ashleymills 0:5a29fd060ac8 57 {
ashleymills 0:5a29fd060ac8 58 if (sess_id_size > SSL_SESSION_ID_SIZE) /* validity check */
ashleymills 0:5a29fd060ac8 59 {
ashleymills 0:5a29fd060ac8 60 ssl_free(ssl);
ashleymills 0:5a29fd060ac8 61 return NULL;
ashleymills 0:5a29fd060ac8 62 }
ashleymills 0:5a29fd060ac8 63
ashleymills 0:5a29fd060ac8 64 memcpy(ssl->session_id, session_id, sess_id_size);
ashleymills 0:5a29fd060ac8 65 ssl->sess_id_size = sess_id_size;
ashleymills 0:5a29fd060ac8 66 SET_SSL_FLAG(SSL_SESSION_RESUME); /* just flag for later */
ashleymills 0:5a29fd060ac8 67 }
ashleymills 0:5a29fd060ac8 68
ashleymills 0:5a29fd060ac8 69 SET_SSL_FLAG(SSL_IS_CLIENT);
ashleymills 0:5a29fd060ac8 70 do_client_connect(ssl);
ashleymills 0:5a29fd060ac8 71 return ssl;
ashleymills 0:5a29fd060ac8 72 }
ashleymills 0:5a29fd060ac8 73
ashleymills 0:5a29fd060ac8 74 /*
ashleymills 0:5a29fd060ac8 75 * Process the handshake record.
ashleymills 0:5a29fd060ac8 76 */
ashleymills 0:5a29fd060ac8 77 int do_clnt_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len)
ashleymills 0:5a29fd060ac8 78 {
ashleymills 0:5a29fd060ac8 79 int ret;
ashleymills 0:5a29fd060ac8 80
ashleymills 0:5a29fd060ac8 81 /* To get here the state must be valid */
ashleymills 0:5a29fd060ac8 82 switch (handshake_type)
ashleymills 0:5a29fd060ac8 83 {
ashleymills 0:5a29fd060ac8 84 case HS_SERVER_HELLO:
ashleymills 0:5a29fd060ac8 85 ret = process_server_hello(ssl);
ashleymills 0:5a29fd060ac8 86 break;
ashleymills 0:5a29fd060ac8 87
ashleymills 0:5a29fd060ac8 88 case HS_CERTIFICATE:
ashleymills 0:5a29fd060ac8 89 ret = process_certificate(ssl, &ssl->x509_ctx);
ashleymills 0:5a29fd060ac8 90 break;
ashleymills 0:5a29fd060ac8 91
ashleymills 0:5a29fd060ac8 92 case HS_SERVER_HELLO_DONE:
ashleymills 0:5a29fd060ac8 93 if ((ret = process_server_hello_done(ssl)) == SSL_OK)
ashleymills 0:5a29fd060ac8 94 {
ashleymills 0:5a29fd060ac8 95 if (IS_SET_SSL_FLAG(SSL_HAS_CERT_REQ))
ashleymills 0:5a29fd060ac8 96 {
ashleymills 0:5a29fd060ac8 97 if ((ret = send_certificate(ssl)) == SSL_OK &&
ashleymills 0:5a29fd060ac8 98 (ret = send_client_key_xchg(ssl)) == SSL_OK)
ashleymills 0:5a29fd060ac8 99 {
ashleymills 0:5a29fd060ac8 100 send_cert_verify(ssl);
ashleymills 0:5a29fd060ac8 101 }
ashleymills 0:5a29fd060ac8 102 }
ashleymills 0:5a29fd060ac8 103 else
ashleymills 0:5a29fd060ac8 104 {
ashleymills 0:5a29fd060ac8 105 ret = send_client_key_xchg(ssl);
ashleymills 0:5a29fd060ac8 106 }
ashleymills 0:5a29fd060ac8 107
ashleymills 0:5a29fd060ac8 108 if (ret == SSL_OK &&
ashleymills 0:5a29fd060ac8 109 (ret = send_change_cipher_spec(ssl)) == SSL_OK)
ashleymills 0:5a29fd060ac8 110 {
ashleymills 0:5a29fd060ac8 111 ret = send_finished(ssl);
ashleymills 0:5a29fd060ac8 112 }
ashleymills 0:5a29fd060ac8 113 }
ashleymills 0:5a29fd060ac8 114 break;
ashleymills 0:5a29fd060ac8 115
ashleymills 0:5a29fd060ac8 116 case HS_CERT_REQ:
ashleymills 0:5a29fd060ac8 117 ret = process_cert_req(ssl);
ashleymills 0:5a29fd060ac8 118 break;
ashleymills 0:5a29fd060ac8 119
ashleymills 0:5a29fd060ac8 120 case HS_FINISHED:
ashleymills 0:5a29fd060ac8 121 ret = process_finished(ssl, buf, hs_len);
ashleymills 0:5a29fd060ac8 122 disposable_free(ssl); /* free up some memory */
ashleymills 0:5a29fd060ac8 123 /* note: client renegotiation is not allowed after this */
ashleymills 0:5a29fd060ac8 124 break;
ashleymills 0:5a29fd060ac8 125
ashleymills 0:5a29fd060ac8 126 case HS_HELLO_REQUEST:
ashleymills 0:5a29fd060ac8 127 disposable_new(ssl);
ashleymills 0:5a29fd060ac8 128 ret = do_client_connect(ssl);
ashleymills 0:5a29fd060ac8 129 break;
ashleymills 0:5a29fd060ac8 130
ashleymills 0:5a29fd060ac8 131 default:
ashleymills 0:5a29fd060ac8 132 ret = SSL_ERROR_INVALID_HANDSHAKE;
ashleymills 0:5a29fd060ac8 133 break;
ashleymills 0:5a29fd060ac8 134 }
ashleymills 0:5a29fd060ac8 135
ashleymills 0:5a29fd060ac8 136 return ret;
ashleymills 0:5a29fd060ac8 137 }
ashleymills 0:5a29fd060ac8 138
ashleymills 0:5a29fd060ac8 139 /*
ashleymills 0:5a29fd060ac8 140 * Do the handshaking from the beginning.
ashleymills 0:5a29fd060ac8 141 */
ashleymills 0:5a29fd060ac8 142 int do_client_connect(SSL *ssl)
ashleymills 0:5a29fd060ac8 143 {
ashleymills 0:5a29fd060ac8 144 int ret = SSL_OK;
ashleymills 0:5a29fd060ac8 145
ashleymills 0:5a29fd060ac8 146 send_client_hello(ssl); /* send the client hello */
ashleymills 0:5a29fd060ac8 147 ssl->bm_read_index = 0;
ashleymills 0:5a29fd060ac8 148 ssl->next_state = HS_SERVER_HELLO;
ashleymills 0:5a29fd060ac8 149 ssl->hs_status = SSL_NOT_OK; /* not connected */
ashleymills 0:5a29fd060ac8 150
ashleymills 0:5a29fd060ac8 151 /* sit in a loop until it all looks good */
ashleymills 0:5a29fd060ac8 152 if (!IS_SET_SSL_FLAG(SSL_CONNECT_IN_PARTS))
ashleymills 0:5a29fd060ac8 153 {
ashleymills 0:5a29fd060ac8 154 while (ssl->hs_status != SSL_OK)
ashleymills 0:5a29fd060ac8 155 {
ashleymills 0:5a29fd060ac8 156 ret = ssl_read(ssl, NULL);
ashleymills 0:5a29fd060ac8 157
ashleymills 0:5a29fd060ac8 158 if (ret < SSL_OK)
ashleymills 0:5a29fd060ac8 159 break;
ashleymills 0:5a29fd060ac8 160 }
ashleymills 0:5a29fd060ac8 161
ashleymills 0:5a29fd060ac8 162 ssl->hs_status = ret; /* connected? */
ashleymills 0:5a29fd060ac8 163 }
ashleymills 0:5a29fd060ac8 164
ashleymills 0:5a29fd060ac8 165 return ret;
ashleymills 0:5a29fd060ac8 166 }
ashleymills 0:5a29fd060ac8 167
ashleymills 0:5a29fd060ac8 168 /*
ashleymills 0:5a29fd060ac8 169 * Send the initial client hello.
ashleymills 0:5a29fd060ac8 170 */
ashleymills 0:5a29fd060ac8 171 static int send_client_hello(SSL *ssl)
ashleymills 0:5a29fd060ac8 172 {
ashleymills 0:5a29fd060ac8 173 uint8_t *buf = ssl->bm_data;
ashleymills 0:5a29fd060ac8 174 time_t tm = time(NULL);
ashleymills 0:5a29fd060ac8 175 uint8_t *tm_ptr = &buf[6]; /* time will go here */
ashleymills 0:5a29fd060ac8 176 int i, offset;
ashleymills 0:5a29fd060ac8 177
ashleymills 0:5a29fd060ac8 178 buf[0] = HS_CLIENT_HELLO;
ashleymills 0:5a29fd060ac8 179 buf[1] = 0;
ashleymills 0:5a29fd060ac8 180 buf[2] = 0;
ashleymills 0:5a29fd060ac8 181 /* byte 3 is calculated later */
ashleymills 0:5a29fd060ac8 182 buf[4] = 0x03;
ashleymills 0:5a29fd060ac8 183 buf[5] = ssl->version & 0x0f;
ashleymills 0:5a29fd060ac8 184
ashleymills 0:5a29fd060ac8 185 /* client random value - spec says that 1st 4 bytes are big endian time */
ashleymills 0:5a29fd060ac8 186 *tm_ptr++ = (uint8_t)(((long)tm & 0xff000000) >> 24);
ashleymills 0:5a29fd060ac8 187 *tm_ptr++ = (uint8_t)(((long)tm & 0x00ff0000) >> 16);
ashleymills 0:5a29fd060ac8 188 *tm_ptr++ = (uint8_t)(((long)tm & 0x0000ff00) >> 8);
ashleymills 0:5a29fd060ac8 189 *tm_ptr++ = (uint8_t)(((long)tm & 0x000000ff));
ashleymills 0:5a29fd060ac8 190 get_random(SSL_RANDOM_SIZE-4, &buf[10]);
ashleymills 0:5a29fd060ac8 191 memcpy(ssl->dc->client_random, &buf[6], SSL_RANDOM_SIZE);
ashleymills 0:5a29fd060ac8 192 offset = 6 + SSL_RANDOM_SIZE;
ashleymills 0:5a29fd060ac8 193
ashleymills 0:5a29fd060ac8 194 /* give session resumption a go */
ashleymills 0:5a29fd060ac8 195 if (IS_SET_SSL_FLAG(SSL_SESSION_RESUME)) /* set initially by user */
ashleymills 0:5a29fd060ac8 196 {
ashleymills 0:5a29fd060ac8 197 buf[offset++] = ssl->sess_id_size;
ashleymills 0:5a29fd060ac8 198 memcpy(&buf[offset], ssl->session_id, ssl->sess_id_size);
ashleymills 0:5a29fd060ac8 199 offset += ssl->sess_id_size;
ashleymills 0:5a29fd060ac8 200 CLR_SSL_FLAG(SSL_SESSION_RESUME); /* clear so we can set later */
ashleymills 0:5a29fd060ac8 201 }
ashleymills 0:5a29fd060ac8 202 else
ashleymills 0:5a29fd060ac8 203 {
ashleymills 0:5a29fd060ac8 204 /* no session id - because no session resumption just yet */
ashleymills 0:5a29fd060ac8 205 buf[offset++] = 0;
ashleymills 0:5a29fd060ac8 206 }
ashleymills 0:5a29fd060ac8 207
ashleymills 0:5a29fd060ac8 208 buf[offset++] = 0; /* number of ciphers */
ashleymills 0:5a29fd060ac8 209 buf[offset++] = NUM_PROTOCOLS*2;/* number of ciphers */
ashleymills 0:5a29fd060ac8 210
ashleymills 0:5a29fd060ac8 211 /* put all our supported protocols in our request */
ashleymills 0:5a29fd060ac8 212 for (i = 0; i < NUM_PROTOCOLS; i++)
ashleymills 0:5a29fd060ac8 213 {
ashleymills 0:5a29fd060ac8 214 buf[offset++] = 0; /* cipher we are using */
ashleymills 0:5a29fd060ac8 215 buf[offset++] = ssl_prot_prefs[i];
ashleymills 0:5a29fd060ac8 216 }
ashleymills 0:5a29fd060ac8 217
ashleymills 0:5a29fd060ac8 218 buf[offset++] = 1; /* no compression */
ashleymills 0:5a29fd060ac8 219 buf[offset++] = 0;
ashleymills 0:5a29fd060ac8 220 buf[3] = offset - 4; /* handshake size */
ashleymills 0:5a29fd060ac8 221
ashleymills 0:5a29fd060ac8 222 return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, offset);
ashleymills 0:5a29fd060ac8 223 }
ashleymills 0:5a29fd060ac8 224
ashleymills 0:5a29fd060ac8 225 /*
ashleymills 0:5a29fd060ac8 226 * Process the server hello.
ashleymills 0:5a29fd060ac8 227 */
ashleymills 0:5a29fd060ac8 228 static int process_server_hello(SSL *ssl)
ashleymills 0:5a29fd060ac8 229 {
ashleymills 0:5a29fd060ac8 230 uint8_t *buf = ssl->bm_data;
ashleymills 0:5a29fd060ac8 231 int pkt_size = ssl->bm_index;
ashleymills 0:5a29fd060ac8 232 int num_sessions = ssl->ssl_ctx->num_sessions;
ashleymills 0:5a29fd060ac8 233 uint8_t sess_id_size;
ashleymills 0:5a29fd060ac8 234 int offset, ret = SSL_OK;
ashleymills 0:5a29fd060ac8 235
ashleymills 0:5a29fd060ac8 236 /* check that we are talking to a TLSv1 server */
ashleymills 0:5a29fd060ac8 237 uint8_t version = (buf[4] << 4) + buf[5];
ashleymills 0:5a29fd060ac8 238 if (version > SSL_PROTOCOL_VERSION_MAX)
ashleymills 0:5a29fd060ac8 239 {
ashleymills 0:5a29fd060ac8 240 version = SSL_PROTOCOL_VERSION_MAX;
ashleymills 0:5a29fd060ac8 241 }
ashleymills 0:5a29fd060ac8 242 else if (ssl->version < SSL_PROTOCOL_MIN_VERSION)
ashleymills 0:5a29fd060ac8 243 {
ashleymills 0:5a29fd060ac8 244 ret = SSL_ERROR_INVALID_VERSION;
ashleymills 0:5a29fd060ac8 245 ssl_display_error(ret);
ashleymills 0:5a29fd060ac8 246 goto error;
ashleymills 0:5a29fd060ac8 247 }
ashleymills 0:5a29fd060ac8 248
ashleymills 0:5a29fd060ac8 249 ssl->version = version;
ashleymills 0:5a29fd060ac8 250
ashleymills 0:5a29fd060ac8 251 /* get the server random value */
ashleymills 0:5a29fd060ac8 252 memcpy(ssl->dc->server_random, &buf[6], SSL_RANDOM_SIZE);
ashleymills 0:5a29fd060ac8 253 offset = 6 + SSL_RANDOM_SIZE; /* skip of session id size */
ashleymills 0:5a29fd060ac8 254 sess_id_size = buf[offset++];
ashleymills 0:5a29fd060ac8 255
ashleymills 0:5a29fd060ac8 256 if (sess_id_size > SSL_SESSION_ID_SIZE)
ashleymills 0:5a29fd060ac8 257 {
ashleymills 0:5a29fd060ac8 258 ret = SSL_ERROR_INVALID_SESSION;
ashleymills 0:5a29fd060ac8 259 goto error;
ashleymills 0:5a29fd060ac8 260 }
ashleymills 0:5a29fd060ac8 261
ashleymills 0:5a29fd060ac8 262 if (num_sessions)
ashleymills 0:5a29fd060ac8 263 {
ashleymills 0:5a29fd060ac8 264 ssl->session = ssl_session_update(num_sessions,
ashleymills 0:5a29fd060ac8 265 ssl->ssl_ctx->ssl_sessions, ssl, &buf[offset]);
ashleymills 0:5a29fd060ac8 266 memcpy(ssl->session->session_id, &buf[offset], sess_id_size);
ashleymills 0:5a29fd060ac8 267
ashleymills 0:5a29fd060ac8 268 /* pad the rest with 0's */
ashleymills 0:5a29fd060ac8 269 if (sess_id_size < SSL_SESSION_ID_SIZE)
ashleymills 0:5a29fd060ac8 270 {
ashleymills 0:5a29fd060ac8 271 memset(&ssl->session->session_id[sess_id_size], 0,
ashleymills 0:5a29fd060ac8 272 SSL_SESSION_ID_SIZE-sess_id_size);
ashleymills 0:5a29fd060ac8 273 }
ashleymills 0:5a29fd060ac8 274 }
ashleymills 0:5a29fd060ac8 275
ashleymills 0:5a29fd060ac8 276 memcpy(ssl->session_id, &buf[offset], sess_id_size);
ashleymills 0:5a29fd060ac8 277 ssl->sess_id_size = sess_id_size;
ashleymills 0:5a29fd060ac8 278 offset += sess_id_size;
ashleymills 0:5a29fd060ac8 279
ashleymills 0:5a29fd060ac8 280 /* get the real cipher we are using */
ashleymills 0:5a29fd060ac8 281 ssl->cipher = buf[++offset];
ashleymills 0:5a29fd060ac8 282 ssl->next_state = IS_SET_SSL_FLAG(SSL_SESSION_RESUME) ?
ashleymills 0:5a29fd060ac8 283 HS_FINISHED : HS_CERTIFICATE;
ashleymills 0:5a29fd060ac8 284
ashleymills 0:5a29fd060ac8 285 offset++; // skip the compr
ashleymills 0:5a29fd060ac8 286 PARANOIA_CHECK(pkt_size, offset);
ashleymills 0:5a29fd060ac8 287 ssl->dc->bm_proc_index = offset+1;
ashleymills 0:5a29fd060ac8 288
ashleymills 0:5a29fd060ac8 289 error:
ashleymills 0:5a29fd060ac8 290 return ret;
ashleymills 0:5a29fd060ac8 291 }
ashleymills 0:5a29fd060ac8 292
ashleymills 0:5a29fd060ac8 293 /**
ashleymills 0:5a29fd060ac8 294 * Process the server hello done message.
ashleymills 0:5a29fd060ac8 295 */
ashleymills 0:5a29fd060ac8 296 static int process_server_hello_done(SSL *ssl)
ashleymills 0:5a29fd060ac8 297 {
ashleymills 0:5a29fd060ac8 298 ssl->next_state = HS_FINISHED;
ashleymills 0:5a29fd060ac8 299 return SSL_OK;
ashleymills 0:5a29fd060ac8 300 }
ashleymills 0:5a29fd060ac8 301
ashleymills 0:5a29fd060ac8 302 /*
ashleymills 0:5a29fd060ac8 303 * Send a client key exchange message.
ashleymills 0:5a29fd060ac8 304 */
ashleymills 0:5a29fd060ac8 305 static int send_client_key_xchg(SSL *ssl)
ashleymills 0:5a29fd060ac8 306 {
ashleymills 0:5a29fd060ac8 307 uint8_t *buf = ssl->bm_data;
ashleymills 0:5a29fd060ac8 308 uint8_t premaster_secret[SSL_SECRET_SIZE];
ashleymills 0:5a29fd060ac8 309 int enc_secret_size = -1;
ashleymills 0:5a29fd060ac8 310
ashleymills 0:5a29fd060ac8 311 buf[0] = HS_CLIENT_KEY_XCHG;
ashleymills 0:5a29fd060ac8 312 buf[1] = 0;
ashleymills 0:5a29fd060ac8 313
ashleymills 0:5a29fd060ac8 314 premaster_secret[0] = 0x03; /* encode the version number */
ashleymills 0:5a29fd060ac8 315 premaster_secret[1] = SSL_PROTOCOL_MINOR_VERSION; /* must be TLS 1.1 */
ashleymills 0:5a29fd060ac8 316 get_random(SSL_SECRET_SIZE-2, &premaster_secret[2]);
ashleymills 0:5a29fd060ac8 317 DISPLAY_RSA(ssl, ssl->x509_ctx->rsa_ctx);
ashleymills 0:5a29fd060ac8 318
ashleymills 0:5a29fd060ac8 319 /* rsa_ctx->bi_ctx is not thread-safe */
ashleymills 0:5a29fd060ac8 320 SSL_CTX_LOCK(ssl->ssl_ctx->mutex);
ashleymills 0:5a29fd060ac8 321 enc_secret_size = RSA_encrypt(ssl->x509_ctx->rsa_ctx, premaster_secret,
ashleymills 0:5a29fd060ac8 322 SSL_SECRET_SIZE, &buf[6], 0);
ashleymills 0:5a29fd060ac8 323 SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
ashleymills 0:5a29fd060ac8 324
ashleymills 0:5a29fd060ac8 325 buf[2] = (enc_secret_size + 2) >> 8;
ashleymills 0:5a29fd060ac8 326 buf[3] = (enc_secret_size + 2) & 0xff;
ashleymills 0:5a29fd060ac8 327 buf[4] = enc_secret_size >> 8;
ashleymills 0:5a29fd060ac8 328 buf[5] = enc_secret_size & 0xff;
ashleymills 0:5a29fd060ac8 329
ashleymills 0:5a29fd060ac8 330 generate_master_secret(ssl, premaster_secret);
ashleymills 0:5a29fd060ac8 331 return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, enc_secret_size+6);
ashleymills 0:5a29fd060ac8 332 }
ashleymills 0:5a29fd060ac8 333
ashleymills 0:5a29fd060ac8 334 /*
ashleymills 0:5a29fd060ac8 335 * Process the certificate request.
ashleymills 0:5a29fd060ac8 336 */
ashleymills 0:5a29fd060ac8 337 static int process_cert_req(SSL *ssl)
ashleymills 0:5a29fd060ac8 338 {
ashleymills 0:5a29fd060ac8 339 uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index];
ashleymills 0:5a29fd060ac8 340 int ret = SSL_OK;
ashleymills 0:5a29fd060ac8 341 int offset = (buf[2] << 4) + buf[3];
ashleymills 0:5a29fd060ac8 342 int pkt_size = ssl->bm_index;
ashleymills 0:5a29fd060ac8 343
ashleymills 0:5a29fd060ac8 344 /* don't do any processing - we will send back an RSA certificate anyway */
ashleymills 0:5a29fd060ac8 345 ssl->next_state = HS_SERVER_HELLO_DONE;
ashleymills 0:5a29fd060ac8 346 SET_SSL_FLAG(SSL_HAS_CERT_REQ);
ashleymills 0:5a29fd060ac8 347 ssl->dc->bm_proc_index += offset;
ashleymills 0:5a29fd060ac8 348 PARANOIA_CHECK(pkt_size, offset);
ashleymills 0:5a29fd060ac8 349 error:
ashleymills 0:5a29fd060ac8 350 return ret;
ashleymills 0:5a29fd060ac8 351 }
ashleymills 0:5a29fd060ac8 352
ashleymills 0:5a29fd060ac8 353 /*
ashleymills 0:5a29fd060ac8 354 * Send a certificate verify message.
ashleymills 0:5a29fd060ac8 355 */
ashleymills 0:5a29fd060ac8 356 static int send_cert_verify(SSL *ssl)
ashleymills 0:5a29fd060ac8 357 {
ashleymills 0:5a29fd060ac8 358 uint8_t *buf = ssl->bm_data;
ashleymills 0:5a29fd060ac8 359 uint8_t dgst[MD5_SIZE+SHA1_SIZE];
ashleymills 0:5a29fd060ac8 360 RSA_CTX *rsa_ctx = ssl->ssl_ctx->rsa_ctx;
ashleymills 0:5a29fd060ac8 361 int n = 0, ret;
ashleymills 0:5a29fd060ac8 362
ashleymills 0:5a29fd060ac8 363 DISPLAY_RSA(ssl, rsa_ctx);
ashleymills 0:5a29fd060ac8 364
ashleymills 0:5a29fd060ac8 365 buf[0] = HS_CERT_VERIFY;
ashleymills 0:5a29fd060ac8 366 buf[1] = 0;
ashleymills 0:5a29fd060ac8 367
ashleymills 0:5a29fd060ac8 368 finished_digest(ssl, NULL, dgst); /* calculate the digest */
ashleymills 0:5a29fd060ac8 369
ashleymills 0:5a29fd060ac8 370 /* rsa_ctx->bi_ctx is not thread-safe */
ashleymills 0:5a29fd060ac8 371 if (rsa_ctx)
ashleymills 0:5a29fd060ac8 372 {
ashleymills 0:5a29fd060ac8 373 SSL_CTX_LOCK(ssl->ssl_ctx->mutex);
ashleymills 0:5a29fd060ac8 374 n = RSA_encrypt(rsa_ctx, dgst, sizeof(dgst), &buf[6], 1);
ashleymills 0:5a29fd060ac8 375 SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);
ashleymills 0:5a29fd060ac8 376
ashleymills 0:5a29fd060ac8 377 if (n == 0)
ashleymills 0:5a29fd060ac8 378 {
ashleymills 0:5a29fd060ac8 379 ret = SSL_ERROR_INVALID_KEY;
ashleymills 0:5a29fd060ac8 380 goto error;
ashleymills 0:5a29fd060ac8 381 }
ashleymills 0:5a29fd060ac8 382 }
ashleymills 0:5a29fd060ac8 383
ashleymills 0:5a29fd060ac8 384 buf[4] = n >> 8; /* add the RSA size (not officially documented) */
ashleymills 0:5a29fd060ac8 385 buf[5] = n & 0xff;
ashleymills 0:5a29fd060ac8 386 n += 2;
ashleymills 0:5a29fd060ac8 387 buf[2] = n >> 8;
ashleymills 0:5a29fd060ac8 388 buf[3] = n & 0xff;
ashleymills 0:5a29fd060ac8 389 ret = send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, n+4);
ashleymills 0:5a29fd060ac8 390
ashleymills 0:5a29fd060ac8 391 error:
ashleymills 0:5a29fd060ac8 392 return ret;
ashleymills 0:5a29fd060ac8 393 }
ashleymills 0:5a29fd060ac8 394
ashleymills 0:5a29fd060ac8 395 #endif /* CONFIG_SSL_ENABLE_CLIENT */