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