From cd3d8b6f4c16680100acc89db5b955e2aa399daa Mon Sep 17 00:00:00 2001 From: jsing <> Date: Thu, 26 Jan 2017 05:51:54 +0000 Subject: Rename s3_{both,clnt,pkt_srvr}.c to have an ssl_ prefix since they are no longer SSLv3 code. ok beck@ --- src/lib/libssl/Makefile | 4 +- src/lib/libssl/s3_both.c | 748 ------------ src/lib/libssl/s3_clnt.c | 2795 ------------------------------------------- src/lib/libssl/s3_pkt.c | 1446 ---------------------- src/lib/libssl/s3_srvr.c | 2923 --------------------------------------------- src/lib/libssl/ssl_both.c | 748 ++++++++++++ src/lib/libssl/ssl_clnt.c | 2795 +++++++++++++++++++++++++++++++++++++++++++ src/lib/libssl/ssl_pkt.c | 1446 ++++++++++++++++++++++ src/lib/libssl/ssl_srvr.c | 2923 +++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 7914 insertions(+), 7914 deletions(-) delete mode 100644 src/lib/libssl/s3_both.c delete mode 100644 src/lib/libssl/s3_clnt.c delete mode 100644 src/lib/libssl/s3_pkt.c delete mode 100644 src/lib/libssl/s3_srvr.c create mode 100644 src/lib/libssl/ssl_both.c create mode 100644 src/lib/libssl/ssl_clnt.c create mode 100644 src/lib/libssl/ssl_pkt.c create mode 100644 src/lib/libssl/ssl_srvr.c (limited to 'src/lib') diff --git a/src/lib/libssl/Makefile b/src/lib/libssl/Makefile index 7321c0d114..24606d1862 100644 --- a/src/lib/libssl/Makefile +++ b/src/lib/libssl/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.28 2017/01/26 05:31:25 jsing Exp $ +# $OpenBSD: Makefile,v 1.29 2017/01/26 05:51:54 jsing Exp $ .include .ifndef NOMAN @@ -24,7 +24,7 @@ VERSION_SCRIPT= Symbols.map SYMBOL_LIST= ${.CURDIR}/Symbols.list SRCS= \ - s3_srvr.c s3_clnt.c s3_lib.c s3_pkt.c s3_both.c \ + ssl_srvr.c ssl_clnt.c s3_lib.c ssl_pkt.c ssl_both.c \ t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c \ d1_meth.c d1_srvr.c d1_clnt.c d1_lib.c d1_pkt.c \ d1_both.c d1_enc.c d1_srtp.c \ diff --git a/src/lib/libssl/s3_both.c b/src/lib/libssl/s3_both.c deleted file mode 100644 index 41b35e5de6..0000000000 --- a/src/lib/libssl/s3_both.c +++ /dev/null @@ -1,748 +0,0 @@ -/* $OpenBSD: s3_both.c,v 1.57 2017/01/26 05:31:25 jsing Exp $ */ -/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] - */ -/* ==================================================================== - * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" - * - * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * openssl-core@openssl.org. - * - * 5. Products derived from this software may not be called "OpenSSL" - * nor may "OpenSSL" appear in their names without prior written - * permission of the OpenSSL Project. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit (http://www.openssl.org/)" - * - * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This product includes cryptographic software written by Eric Young - * (eay@cryptsoft.com). This product includes software written by Tim - * Hudson (tjh@cryptsoft.com). - * - */ -/* ==================================================================== - * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. - * ECC cipher suite support in OpenSSL originally developed by - * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. - */ - -#include -#include -#include - -#include "ssl_locl.h" - -#include -#include -#include -#include - -#include "bytestring.h" - -/* - * Send s->internal->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or - * SSL3_RT_CHANGE_CIPHER_SPEC). - */ -int -ssl3_do_write(SSL *s, int type) -{ - int ret; - - ret = ssl3_write_bytes(s, type, &s->internal->init_buf->data[s->internal->init_off], - s->internal->init_num); - if (ret < 0) - return (-1); - - if (type == SSL3_RT_HANDSHAKE) - /* - * Should not be done for 'Hello Request's, but in that case - * we'll ignore the result anyway. - */ - tls1_finish_mac(s, - (unsigned char *)&s->internal->init_buf->data[s->internal->init_off], ret); - - if (ret == s->internal->init_num) { - if (s->internal->msg_callback) - s->internal->msg_callback(1, s->version, type, s->internal->init_buf->data, - (size_t)(s->internal->init_off + s->internal->init_num), s, - s->internal->msg_callback_arg); - return (1); - } - - s->internal->init_off += ret; - s->internal->init_num -= ret; - - return (0); -} - -int -ssl3_send_finished(SSL *s, int a, int b, const char *sender, int slen) -{ - unsigned char *p; - int md_len; - - if (s->internal->state == a) { - md_len = s->method->internal->ssl3_enc->finish_mac_length; - OPENSSL_assert(md_len <= EVP_MAX_MD_SIZE); - - if (s->method->internal->ssl3_enc->final_finish_mac(s, sender, slen, - S3I(s)->tmp.finish_md) != md_len) - return (0); - S3I(s)->tmp.finish_md_len = md_len; - - /* Copy finished so we can use it for renegotiation checks. */ - if (s->internal->type == SSL_ST_CONNECT) { - memcpy(S3I(s)->previous_client_finished, - S3I(s)->tmp.finish_md, md_len); - S3I(s)->previous_client_finished_len = md_len; - } else { - memcpy(S3I(s)->previous_server_finished, - S3I(s)->tmp.finish_md, md_len); - S3I(s)->previous_server_finished_len = md_len; - } - - p = ssl3_handshake_msg_start(s, SSL3_MT_FINISHED); - memcpy(p, S3I(s)->tmp.finish_md, md_len); - ssl3_handshake_msg_finish(s, md_len); - - s->internal->state = b; - } - - return (ssl3_handshake_write(s)); -} - -/* - * ssl3_take_mac calculates the Finished MAC for the handshakes messages seen - * so far. - */ -static void -ssl3_take_mac(SSL *s) -{ - const char *sender; - int slen; - - /* - * If no new cipher setup return immediately: other functions will - * set the appropriate error. - */ - if (S3I(s)->tmp.new_cipher == NULL) - return; - - if (s->internal->state & SSL_ST_CONNECT) { - sender = s->method->internal->ssl3_enc->server_finished_label; - slen = s->method->internal->ssl3_enc->server_finished_label_len; - } else { - sender = s->method->internal->ssl3_enc->client_finished_label; - slen = s->method->internal->ssl3_enc->client_finished_label_len; - } - - S3I(s)->tmp.peer_finish_md_len = - s->method->internal->ssl3_enc->final_finish_mac(s, sender, slen, - S3I(s)->tmp.peer_finish_md); -} - -int -ssl3_get_finished(SSL *s, int a, int b) -{ - int al, ok, md_len; - long n; - CBS cbs; - - /* should actually be 36+4 :-) */ - n = s->method->internal->ssl_get_message(s, a, b, SSL3_MT_FINISHED, 64, &ok); - if (!ok) - return ((int)n); - - /* If this occurs, we have missed a message */ - if (!S3I(s)->change_cipher_spec) { - al = SSL_AD_UNEXPECTED_MESSAGE; - SSLerr(SSL_F_SSL3_GET_FINISHED, SSL_R_GOT_A_FIN_BEFORE_A_CCS); - goto f_err; - } - S3I(s)->change_cipher_spec = 0; - - md_len = s->method->internal->ssl3_enc->finish_mac_length; - - if (n < 0) { - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_FINISHED, SSL_R_BAD_DIGEST_LENGTH); - goto f_err; - } - - CBS_init(&cbs, s->internal->init_msg, n); - - if (S3I(s)->tmp.peer_finish_md_len != md_len || - CBS_len(&cbs) != md_len) { - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_FINISHED, SSL_R_BAD_DIGEST_LENGTH); - goto f_err; - } - - if (!CBS_mem_equal(&cbs, S3I(s)->tmp.peer_finish_md, CBS_len(&cbs))) { - al = SSL_AD_DECRYPT_ERROR; - SSLerr(SSL_F_SSL3_GET_FINISHED, SSL_R_DIGEST_CHECK_FAILED); - goto f_err; - } - - /* Copy finished so we can use it for renegotiation checks. */ - OPENSSL_assert(md_len <= EVP_MAX_MD_SIZE); - if (s->internal->type == SSL_ST_ACCEPT) { - memcpy(S3I(s)->previous_client_finished, - S3I(s)->tmp.peer_finish_md, md_len); - S3I(s)->previous_client_finished_len = md_len; - } else { - memcpy(S3I(s)->previous_server_finished, - S3I(s)->tmp.peer_finish_md, md_len); - S3I(s)->previous_server_finished_len = md_len; - } - - return (1); -f_err: - ssl3_send_alert(s, SSL3_AL_FATAL, al); - return (0); -} - -/* for these 2 messages, we need to - * ssl->enc_read_ctx re-init - * ssl->s3->internal->read_sequence zero - * ssl->s3->internal->read_mac_secret re-init - * ssl->session->read_sym_enc assign - * ssl->session->read_hash assign - */ -int -ssl3_send_change_cipher_spec(SSL *s, int a, int b) -{ - unsigned char *p; - - if (s->internal->state == a) { - p = (unsigned char *)s->internal->init_buf->data; - *p = SSL3_MT_CCS; - s->internal->init_num = 1; - s->internal->init_off = 0; - - s->internal->state = b; - } - - /* SSL3_ST_CW_CHANGE_B */ - return (ssl3_do_write(s, SSL3_RT_CHANGE_CIPHER_SPEC)); -} - -static int -ssl3_add_cert(CBB *cbb, X509 *x) -{ - unsigned char *data; - int cert_len; - int ret = 0; - CBB cert; - - if ((cert_len = i2d_X509(x, NULL)) < 0) - goto err; - - if (!CBB_add_u24_length_prefixed(cbb, &cert)) - goto err; - if (!CBB_add_space(&cert, &data, cert_len)) - goto err; - if (i2d_X509(x, &data) < 0) - goto err; - if (!CBB_flush(cbb)) - goto err; - - ret = 1; - - err: - return (ret); -} - -int -ssl3_output_cert_chain(SSL *s, CBB *cbb, X509 *x) -{ - int no_chain = 0; - CBB cert_list; - int ret = 0; - int i; - - if (!CBB_add_u24_length_prefixed(cbb, &cert_list)) - goto err; - - if ((s->internal->mode & SSL_MODE_NO_AUTO_CHAIN) || s->ctx->extra_certs) - no_chain = 1; - - /* TLSv1 sends a chain with nothing in it, instead of an alert. */ - if (x != NULL) { - if (no_chain) { - if (!ssl3_add_cert(&cert_list, x)) - goto err; - } else { - X509_STORE_CTX xs_ctx; - - if (!X509_STORE_CTX_init(&xs_ctx, s->ctx->cert_store, - x, NULL)) { - SSLerr(SSL_F_SSL3_OUTPUT_CERT_CHAIN, - ERR_R_X509_LIB); - goto err; - } - X509_verify_cert(&xs_ctx); - - /* Don't leave errors in the queue. */ - ERR_clear_error(); - for (i = 0; i < sk_X509_num(xs_ctx.chain); i++) { - x = sk_X509_value(xs_ctx.chain, i); - if (!ssl3_add_cert(&cert_list, x)) { - X509_STORE_CTX_cleanup(&xs_ctx); - goto err; - } - } - X509_STORE_CTX_cleanup(&xs_ctx); - } - } - - /* Thawte special :-) */ - for (i = 0; i < sk_X509_num(s->ctx->extra_certs); i++) { - x = sk_X509_value(s->ctx->extra_certs, i); - if (!ssl3_add_cert(&cert_list, x)) - goto err; - } - - if (!CBB_flush(cbb)) - goto err; - - ret = 1; - - err: - return (ret); -} - -/* - * Obtain handshake message of message type 'mt' (any if mt == -1), - * maximum acceptable body length 'max'. - * The first four bytes (msg_type and length) are read in state 'st1', - * the body is read in state 'stn'. - */ -long -ssl3_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok) -{ - unsigned char *p; - uint32_t l; - long n; - int i, al; - CBS cbs; - uint8_t u8; - - if (S3I(s)->tmp.reuse_message) { - S3I(s)->tmp.reuse_message = 0; - if ((mt >= 0) && (S3I(s)->tmp.message_type != mt)) { - al = SSL_AD_UNEXPECTED_MESSAGE; - SSLerr(SSL_F_SSL3_GET_MESSAGE, - SSL_R_UNEXPECTED_MESSAGE); - goto f_err; - } - *ok = 1; - s->internal->init_msg = s->internal->init_buf->data + 4; - s->internal->init_num = (int)S3I(s)->tmp.message_size; - return s->internal->init_num; - } - - p = (unsigned char *)s->internal->init_buf->data; - - /* s->internal->init_num < 4 */ - if (s->internal->state == st1) { - int skip_message; - - do { - while (s->internal->init_num < 4) { - i = s->method->internal->ssl_read_bytes(s, - SSL3_RT_HANDSHAKE, &p[s->internal->init_num], - 4 - s->internal->init_num, 0); - if (i <= 0) { - s->internal->rwstate = SSL_READING; - *ok = 0; - return i; - } - s->internal->init_num += i; - } - - skip_message = 0; - if (!s->server && p[0] == SSL3_MT_HELLO_REQUEST) { - /* - * The server may always send 'Hello Request' - * messages -- we are doing a handshake anyway - * now, so ignore them if their format is - * correct. Does not count for 'Finished' MAC. - */ - if (p[1] == 0 && p[2] == 0 &&p[3] == 0) { - s->internal->init_num = 0; - skip_message = 1; - - if (s->internal->msg_callback) - s->internal->msg_callback(0, s->version, - SSL3_RT_HANDSHAKE, p, 4, s, - s->internal->msg_callback_arg); - } - } - } while (skip_message); - - /* s->internal->init_num == 4 */ - - if ((mt >= 0) && (*p != mt)) { - al = SSL_AD_UNEXPECTED_MESSAGE; - SSLerr(SSL_F_SSL3_GET_MESSAGE, - SSL_R_UNEXPECTED_MESSAGE); - goto f_err; - } - - CBS_init(&cbs, p, 4); - if (!CBS_get_u8(&cbs, &u8) || - !CBS_get_u24(&cbs, &l)) { - SSLerr(SSL_F_SSL3_GET_MESSAGE, ERR_R_BUF_LIB); - goto err; - } - S3I(s)->tmp.message_type = u8; - - if (l > (unsigned long)max) { - al = SSL_AD_ILLEGAL_PARAMETER; - SSLerr(SSL_F_SSL3_GET_MESSAGE, - SSL_R_EXCESSIVE_MESSAGE_SIZE); - goto f_err; - } - if (l && !BUF_MEM_grow_clean(s->internal->init_buf, l + 4)) { - SSLerr(SSL_F_SSL3_GET_MESSAGE, ERR_R_BUF_LIB); - goto err; - } - S3I(s)->tmp.message_size = l; - s->internal->state = stn; - - s->internal->init_msg = s->internal->init_buf->data + 4; - s->internal->init_num = 0; - } - - /* next state (stn) */ - p = s->internal->init_msg; - n = S3I(s)->tmp.message_size - s->internal->init_num; - while (n > 0) { - i = s->method->internal->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, - &p[s->internal->init_num], n, 0); - if (i <= 0) { - s->internal->rwstate = SSL_READING; - *ok = 0; - return i; - } - s->internal->init_num += i; - n -= i; - } - - /* If receiving Finished, record MAC of prior handshake messages for - * Finished verification. */ - if (*s->internal->init_buf->data == SSL3_MT_FINISHED) - ssl3_take_mac(s); - - /* Feed this message into MAC computation. */ - if (s->internal->mac_packet) { - tls1_finish_mac(s, (unsigned char *)s->internal->init_buf->data, - s->internal->init_num + 4); - s->internal->mac_packet = 0; - - if (s->internal->msg_callback) - s->internal->msg_callback(0, s->version, - SSL3_RT_HANDSHAKE, s->internal->init_buf->data, - (size_t)s->internal->init_num + 4, s, - s->internal->msg_callback_arg); - } - - *ok = 1; - return (s->internal->init_num); - -f_err: - ssl3_send_alert(s, SSL3_AL_FATAL, al); -err: - *ok = 0; - return (-1); -} - -int -ssl_cert_type(X509 *x, EVP_PKEY *pkey) -{ - EVP_PKEY *pk; - int ret = -1, i; - - if (pkey == NULL) - pk = X509_get_pubkey(x); - else - pk = pkey; - if (pk == NULL) - goto err; - - i = pk->type; - if (i == EVP_PKEY_RSA) { - ret = SSL_PKEY_RSA_ENC; - } else if (i == EVP_PKEY_DSA) { - ret = SSL_PKEY_DSA_SIGN; - } else if (i == EVP_PKEY_EC) { - ret = SSL_PKEY_ECC; - } else if (i == NID_id_GostR3410_2001 || - i == NID_id_GostR3410_2001_cc) { - ret = SSL_PKEY_GOST01; - } - -err: - if (!pkey) - EVP_PKEY_free(pk); - return (ret); -} - -int -ssl_verify_alarm_type(long type) -{ - int al; - - switch (type) { - case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: - case X509_V_ERR_UNABLE_TO_GET_CRL: - case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: - al = SSL_AD_UNKNOWN_CA; - break; - case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: - case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: - case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: - case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: - case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: - case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: - case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: - case X509_V_ERR_CERT_NOT_YET_VALID: - case X509_V_ERR_CRL_NOT_YET_VALID: - case X509_V_ERR_CERT_UNTRUSTED: - case X509_V_ERR_CERT_REJECTED: - al = SSL_AD_BAD_CERTIFICATE; - break; - case X509_V_ERR_CERT_SIGNATURE_FAILURE: - case X509_V_ERR_CRL_SIGNATURE_FAILURE: - al = SSL_AD_DECRYPT_ERROR; - break; - case X509_V_ERR_CERT_HAS_EXPIRED: - case X509_V_ERR_CRL_HAS_EXPIRED: - al = SSL_AD_CERTIFICATE_EXPIRED; - break; - case X509_V_ERR_CERT_REVOKED: - al = SSL_AD_CERTIFICATE_REVOKED; - break; - case X509_V_ERR_OUT_OF_MEM: - al = SSL_AD_INTERNAL_ERROR; - break; - case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: - case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: - case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: - case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: - case X509_V_ERR_CERT_CHAIN_TOO_LONG: - case X509_V_ERR_PATH_LENGTH_EXCEEDED: - case X509_V_ERR_INVALID_CA: - al = SSL_AD_UNKNOWN_CA; - break; - case X509_V_ERR_APPLICATION_VERIFICATION: - al = SSL_AD_HANDSHAKE_FAILURE; - break; - case X509_V_ERR_INVALID_PURPOSE: - al = SSL_AD_UNSUPPORTED_CERTIFICATE; - break; - default: - al = SSL_AD_CERTIFICATE_UNKNOWN; - break; - } - return (al); -} - -int -ssl3_setup_init_buffer(SSL *s) -{ - BUF_MEM *buf = NULL; - - if (s->internal->init_buf != NULL) - return (1); - - if ((buf = BUF_MEM_new()) == NULL) - goto err; - if (!BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) - goto err; - - s->internal->init_buf = buf; - return (1); - -err: - BUF_MEM_free(buf); - return (0); -} - -int -ssl3_setup_read_buffer(SSL *s) -{ - unsigned char *p; - size_t len, align, headerlen; - - if (SSL_IS_DTLS(s)) - headerlen = DTLS1_RT_HEADER_LENGTH; - else - headerlen = SSL3_RT_HEADER_LENGTH; - - align = (-SSL3_RT_HEADER_LENGTH) & (SSL3_ALIGN_PAYLOAD - 1); - - if (s->s3->rbuf.buf == NULL) { - len = SSL3_RT_MAX_PLAIN_LENGTH + - SSL3_RT_MAX_ENCRYPTED_OVERHEAD + headerlen + align; - if ((p = malloc(len)) == NULL) - goto err; - s->s3->rbuf.buf = p; - s->s3->rbuf.len = len; - } - - s->internal->packet = &(s->s3->rbuf.buf[0]); - return 1; - -err: - SSLerr(SSL_F_SSL3_SETUP_READ_BUFFER, ERR_R_MALLOC_FAILURE); - return 0; -} - -int -ssl3_setup_write_buffer(SSL *s) -{ - unsigned char *p; - size_t len, align, headerlen; - - if (SSL_IS_DTLS(s)) - headerlen = DTLS1_RT_HEADER_LENGTH + 1; - else - headerlen = SSL3_RT_HEADER_LENGTH; - - align = (-SSL3_RT_HEADER_LENGTH) & (SSL3_ALIGN_PAYLOAD - 1); - - if (s->s3->wbuf.buf == NULL) { - len = s->max_send_fragment + - SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD + headerlen + align; - if (!(s->internal->options & SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS)) - len += headerlen + align + - SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD; - - if ((p = malloc(len)) == NULL) - goto err; - s->s3->wbuf.buf = p; - s->s3->wbuf.len = len; - } - - return 1; - -err: - SSLerr(SSL_F_SSL3_SETUP_WRITE_BUFFER, ERR_R_MALLOC_FAILURE); - return 0; -} - -int -ssl3_setup_buffers(SSL *s) -{ - if (!ssl3_setup_read_buffer(s)) - return 0; - if (!ssl3_setup_write_buffer(s)) - return 0; - return 1; -} - -int -ssl3_release_write_buffer(SSL *s) -{ - free(s->s3->wbuf.buf); - s->s3->wbuf.buf = NULL; - return 1; -} - -int -ssl3_release_read_buffer(SSL *s) -{ - free(s->s3->rbuf.buf); - s->s3->rbuf.buf = NULL; - return 1; -} diff --git a/src/lib/libssl/s3_clnt.c b/src/lib/libssl/s3_clnt.c deleted file mode 100644 index 13915c2439..0000000000 --- a/src/lib/libssl/s3_clnt.c +++ /dev/null @@ -1,2795 +0,0 @@ -/* $OpenBSD: s3_clnt.c,v 1.175 2017/01/26 05:31:25 jsing Exp $ */ -/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] - */ -/* ==================================================================== - * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" - * - * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * openssl-core@openssl.org. - * - * 5. Products derived from this software may not be called "OpenSSL" - * nor may "OpenSSL" appear in their names without prior written - * permission of the OpenSSL Project. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit (http://www.openssl.org/)" - * - * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This product includes cryptographic software written by Eric Young - * (eay@cryptsoft.com). This product includes software written by Tim - * Hudson (tjh@cryptsoft.com). - * - */ -/* ==================================================================== - * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. - * - * Portions of the attached software ("Contribution") are developed by - * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. - * - * The Contribution is licensed pursuant to the OpenSSL open source - * license provided above. - * - * ECC cipher suite support in OpenSSL originally written by - * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories. - * - */ -/* ==================================================================== - * Copyright 2005 Nokia. All rights reserved. - * - * The portions of the attached software ("Contribution") is developed by - * Nokia Corporation and is licensed pursuant to the OpenSSL open source - * license. - * - * The Contribution, originally written by Mika Kousa and Pasi Eronen of - * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites - * support (see RFC 4279) to OpenSSL. - * - * No patent licenses or other rights except those expressly stated in - * the OpenSSL open source license shall be deemed granted or received - * expressly, by implication, estoppel, or otherwise. - * - * No assurances are provided by Nokia that the Contribution does not - * infringe the patent or other intellectual property rights of any third - * party or that the license provides you with all the necessary rights - * to make use of the Contribution. - * - * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN - * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA - * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY - * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR - * OTHERWISE. - */ - -#include -#include -#include - -#include "ssl_locl.h" - -#include -#include -#include -#include -#include -#include -#include - -#ifndef OPENSSL_NO_ENGINE -#include -#endif -#ifndef OPENSSL_NO_GOST -#include -#endif - -#include "bytestring.h" - -static int ca_dn_cmp(const X509_NAME * const *a, const X509_NAME * const *b); - -int -ssl3_connect(SSL *s) -{ - void (*cb)(const SSL *ssl, int type, int val) = NULL; - int ret = -1; - int new_state, state, skip = 0; - - ERR_clear_error(); - errno = 0; - - if (s->internal->info_callback != NULL) - cb = s->internal->info_callback; - else if (s->ctx->internal->info_callback != NULL) - cb = s->ctx->internal->info_callback; - - s->internal->in_handshake++; - if (!SSL_in_init(s) || SSL_in_before(s)) - SSL_clear(s); - - for (;;) { - state = s->internal->state; - - switch (s->internal->state) { - case SSL_ST_RENEGOTIATE: - s->internal->renegotiate = 1; - s->internal->state = SSL_ST_CONNECT; - s->ctx->internal->stats.sess_connect_renegotiate++; - /* break */ - case SSL_ST_BEFORE: - case SSL_ST_CONNECT: - case SSL_ST_BEFORE|SSL_ST_CONNECT: - case SSL_ST_OK|SSL_ST_CONNECT: - - s->server = 0; - if (cb != NULL) - cb(s, SSL_CB_HANDSHAKE_START, 1); - - if ((s->version & 0xff00 ) != 0x0300) { - SSLerr(SSL_F_SSL3_CONNECT, - ERR_R_INTERNAL_ERROR); - ret = -1; - goto end; - } - - /* s->version=SSL3_VERSION; */ - s->internal->type = SSL_ST_CONNECT; - - if (!ssl3_setup_init_buffer(s)) { - ret = -1; - goto end; - } - if (!ssl3_setup_buffers(s)) { - ret = -1; - goto end; - } - if (!ssl_init_wbio_buffer(s, 0)) { - ret = -1; - goto end; - } - - /* don't push the buffering BIO quite yet */ - - if (!tls1_init_finished_mac(s)) { - ret = -1; - goto end; - } - - s->internal->state = SSL3_ST_CW_CLNT_HELLO_A; - s->ctx->internal->stats.sess_connect++; - s->internal->init_num = 0; - break; - - case SSL3_ST_CW_CLNT_HELLO_A: - case SSL3_ST_CW_CLNT_HELLO_B: - - s->internal->shutdown = 0; - ret = ssl3_client_hello(s); - if (ret <= 0) - goto end; - s->internal->state = SSL3_ST_CR_SRVR_HELLO_A; - s->internal->init_num = 0; - - /* turn on buffering for the next lot of output */ - if (s->bbio != s->wbio) - s->wbio = BIO_push(s->bbio, s->wbio); - - break; - - case SSL3_ST_CR_SRVR_HELLO_A: - case SSL3_ST_CR_SRVR_HELLO_B: - ret = ssl3_get_server_hello(s); - if (ret <= 0) - goto end; - - if (s->internal->hit) { - s->internal->state = SSL3_ST_CR_FINISHED_A; - if (s->internal->tlsext_ticket_expected) { - /* receive renewed session ticket */ - s->internal->state = SSL3_ST_CR_SESSION_TICKET_A; - } - } else - s->internal->state = SSL3_ST_CR_CERT_A; - s->internal->init_num = 0; - break; - - case SSL3_ST_CR_CERT_A: - case SSL3_ST_CR_CERT_B: - ret = ssl3_check_finished(s); - if (ret <= 0) - goto end; - if (ret == 2) { - s->internal->hit = 1; - if (s->internal->tlsext_ticket_expected) - s->internal->state = SSL3_ST_CR_SESSION_TICKET_A; - else - s->internal->state = SSL3_ST_CR_FINISHED_A; - s->internal->init_num = 0; - break; - } - /* Check if it is anon DH/ECDH. */ - if (!(S3I(s)->tmp.new_cipher->algorithm_auth & - SSL_aNULL)) { - ret = ssl3_get_server_certificate(s); - if (ret <= 0) - goto end; - if (s->internal->tlsext_status_expected) - s->internal->state = SSL3_ST_CR_CERT_STATUS_A; - else - s->internal->state = SSL3_ST_CR_KEY_EXCH_A; - } else { - skip = 1; - s->internal->state = SSL3_ST_CR_KEY_EXCH_A; - } - s->internal->init_num = 0; - break; - - case SSL3_ST_CR_KEY_EXCH_A: - case SSL3_ST_CR_KEY_EXCH_B: - ret = ssl3_get_server_key_exchange(s); - if (ret <= 0) - goto end; - s->internal->state = SSL3_ST_CR_CERT_REQ_A; - s->internal->init_num = 0; - - /* - * At this point we check that we have the - * required stuff from the server. - */ - if (!ssl3_check_cert_and_algorithm(s)) { - ret = -1; - goto end; - } - break; - - case SSL3_ST_CR_CERT_REQ_A: - case SSL3_ST_CR_CERT_REQ_B: - ret = ssl3_get_certificate_request(s); - if (ret <= 0) - goto end; - s->internal->state = SSL3_ST_CR_SRVR_DONE_A; - s->internal->init_num = 0; - break; - - case SSL3_ST_CR_SRVR_DONE_A: - case SSL3_ST_CR_SRVR_DONE_B: - ret = ssl3_get_server_done(s); - if (ret <= 0) - goto end; - if (S3I(s)->tmp.cert_req) - s->internal->state = SSL3_ST_CW_CERT_A; - else - s->internal->state = SSL3_ST_CW_KEY_EXCH_A; - s->internal->init_num = 0; - - break; - - case SSL3_ST_CW_CERT_A: - case SSL3_ST_CW_CERT_B: - case SSL3_ST_CW_CERT_C: - case SSL3_ST_CW_CERT_D: - ret = ssl3_send_client_certificate(s); - if (ret <= 0) - goto end; - s->internal->state = SSL3_ST_CW_KEY_EXCH_A; - s->internal->init_num = 0; - break; - - case SSL3_ST_CW_KEY_EXCH_A: - case SSL3_ST_CW_KEY_EXCH_B: - ret = ssl3_send_client_key_exchange(s); - if (ret <= 0) - goto end; - /* - * EAY EAY EAY need to check for DH fix cert - * sent back - */ - /* - * For TLS, cert_req is set to 2, so a cert chain - * of nothing is sent, but no verify packet is sent - */ - /* - * XXX: For now, we do not support client - * authentication in ECDH cipher suites with - * ECDH (rather than ECDSA) certificates. - * We need to skip the certificate verify - * message when client's ECDH public key is sent - * inside the client certificate. - */ - if (S3I(s)->tmp.cert_req == 1) { - s->internal->state = SSL3_ST_CW_CERT_VRFY_A; - } else { - s->internal->state = SSL3_ST_CW_CHANGE_A; - S3I(s)->change_cipher_spec = 0; - } - if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY) { - s->internal->state = SSL3_ST_CW_CHANGE_A; - S3I(s)->change_cipher_spec = 0; - } - - s->internal->init_num = 0; - break; - - case SSL3_ST_CW_CERT_VRFY_A: - case SSL3_ST_CW_CERT_VRFY_B: - ret = ssl3_send_client_verify(s); - if (ret <= 0) - goto end; - s->internal->state = SSL3_ST_CW_CHANGE_A; - s->internal->init_num = 0; - S3I(s)->change_cipher_spec = 0; - break; - - case SSL3_ST_CW_CHANGE_A: - case SSL3_ST_CW_CHANGE_B: - ret = ssl3_send_change_cipher_spec(s, - SSL3_ST_CW_CHANGE_A, SSL3_ST_CW_CHANGE_B); - if (ret <= 0) - goto end; - - if (S3I(s)->next_proto_neg_seen) - s->internal->state = SSL3_ST_CW_NEXT_PROTO_A; - else - s->internal->state = SSL3_ST_CW_FINISHED_A; - s->internal->init_num = 0; - - s->session->cipher = S3I(s)->tmp.new_cipher; - if (!s->method->internal->ssl3_enc->setup_key_block(s)) { - ret = -1; - goto end; - } - - if (!s->method->internal->ssl3_enc->change_cipher_state(s, - SSL3_CHANGE_CIPHER_CLIENT_WRITE)) { - ret = -1; - goto end; - } - - break; - - case SSL3_ST_CW_NEXT_PROTO_A: - case SSL3_ST_CW_NEXT_PROTO_B: - ret = ssl3_send_next_proto(s); - if (ret <= 0) - goto end; - s->internal->state = SSL3_ST_CW_FINISHED_A; - break; - - case SSL3_ST_CW_FINISHED_A: - case SSL3_ST_CW_FINISHED_B: - ret = ssl3_send_finished(s, SSL3_ST_CW_FINISHED_A, - SSL3_ST_CW_FINISHED_B, - s->method->internal->ssl3_enc->client_finished_label, - s->method->internal->ssl3_enc->client_finished_label_len); - if (ret <= 0) - goto end; - s->s3->flags |= SSL3_FLAGS_CCS_OK; - s->internal->state = SSL3_ST_CW_FLUSH; - - /* clear flags */ - s->s3->flags &= ~SSL3_FLAGS_POP_BUFFER; - if (s->internal->hit) { - S3I(s)->tmp.next_state = SSL_ST_OK; - if (s->s3->flags & - SSL3_FLAGS_DELAY_CLIENT_FINISHED) { - s->internal->state = SSL_ST_OK; - s->s3->flags|=SSL3_FLAGS_POP_BUFFER; - S3I(s)->delay_buf_pop_ret = 0; - } - } else { - /* Allow NewSessionTicket if ticket expected */ - if (s->internal->tlsext_ticket_expected) - S3I(s)->tmp.next_state = - SSL3_ST_CR_SESSION_TICKET_A; - else - - S3I(s)->tmp.next_state = SSL3_ST_CR_FINISHED_A; - } - s->internal->init_num = 0; - break; - - case SSL3_ST_CR_SESSION_TICKET_A: - case SSL3_ST_CR_SESSION_TICKET_B: - ret = ssl3_get_new_session_ticket(s); - if (ret <= 0) - goto end; - s->internal->state = SSL3_ST_CR_FINISHED_A; - s->internal->init_num = 0; - break; - - case SSL3_ST_CR_CERT_STATUS_A: - case SSL3_ST_CR_CERT_STATUS_B: - ret = ssl3_get_cert_status(s); - if (ret <= 0) - goto end; - s->internal->state = SSL3_ST_CR_KEY_EXCH_A; - s->internal->init_num = 0; - break; - - case SSL3_ST_CR_FINISHED_A: - case SSL3_ST_CR_FINISHED_B: - s->s3->flags |= SSL3_FLAGS_CCS_OK; - ret = ssl3_get_finished(s, SSL3_ST_CR_FINISHED_A, - SSL3_ST_CR_FINISHED_B); - if (ret <= 0) - goto end; - - if (s->internal->hit) - s->internal->state = SSL3_ST_CW_CHANGE_A; - else - s->internal->state = SSL_ST_OK; - s->internal->init_num = 0; - break; - - case SSL3_ST_CW_FLUSH: - s->internal->rwstate = SSL_WRITING; - if (BIO_flush(s->wbio) <= 0) { - ret = -1; - goto end; - } - s->internal->rwstate = SSL_NOTHING; - s->internal->state = S3I(s)->tmp.next_state; - break; - - case SSL_ST_OK: - /* clean a few things up */ - tls1_cleanup_key_block(s); - - BUF_MEM_free(s->internal->init_buf); - s->internal->init_buf = NULL; - - /* - * If we are not 'joining' the last two packets, - * remove the buffering now - */ - if (!(s->s3->flags & SSL3_FLAGS_POP_BUFFER)) - ssl_free_wbio_buffer(s); - /* else do it later in ssl3_write */ - - s->internal->init_num = 0; - s->internal->renegotiate = 0; - s->internal->new_session = 0; - - ssl_update_cache(s, SSL_SESS_CACHE_CLIENT); - if (s->internal->hit) - s->ctx->internal->stats.sess_hit++; - - ret = 1; - /* s->server=0; */ - s->internal->handshake_func = ssl3_connect; - s->ctx->internal->stats.sess_connect_good++; - - if (cb != NULL) - cb(s, SSL_CB_HANDSHAKE_DONE, 1); - - goto end; - /* break; */ - - default: - SSLerr(SSL_F_SSL3_CONNECT, - SSL_R_UNKNOWN_STATE); - ret = -1; - goto end; - /* break; */ - } - - /* did we do anything */ - if (!S3I(s)->tmp.reuse_message && !skip) { - if (s->internal->debug) { - if ((ret = BIO_flush(s->wbio)) <= 0) - goto end; - } - - if ((cb != NULL) && (s->internal->state != state)) { - new_state = s->internal->state; - s->internal->state = state; - cb(s, SSL_CB_CONNECT_LOOP, 1); - s->internal->state = new_state; - } - } - skip = 0; - } - -end: - s->internal->in_handshake--; - if (cb != NULL) - cb(s, SSL_CB_CONNECT_EXIT, ret); - - return (ret); -} - -int -ssl3_client_hello(SSL *s) -{ - unsigned char *bufend, *p, *d; - uint16_t max_version; - size_t outlen; - int i; - - bufend = (unsigned char *)s->internal->init_buf->data + SSL3_RT_MAX_PLAIN_LENGTH; - - if (s->internal->state == SSL3_ST_CW_CLNT_HELLO_A) { - SSL_SESSION *sess = s->session; - - if (ssl_supported_version_range(s, NULL, &max_version) != 1) { - SSLerr(SSL_F_SSL3_CLIENT_HELLO, - SSL_R_NO_PROTOCOLS_AVAILABLE); - return (-1); - } - s->client_version = s->version = max_version; - - if ((sess == NULL) || - (sess->ssl_version != s->version) || - (!sess->session_id_length && !sess->tlsext_tick) || - (sess->internal->not_resumable)) { - if (!ssl_get_new_session(s, 0)) - goto err; - } - /* else use the pre-loaded session */ - - /* - * If a DTLS ClientHello message is being resent after a - * HelloVerifyRequest, we must retain the original client - * random value. - */ - if (!SSL_IS_DTLS(s) || D1I(s)->send_cookie == 0) - arc4random_buf(s->s3->client_random, SSL3_RANDOM_SIZE); - - d = p = ssl3_handshake_msg_start(s, SSL3_MT_CLIENT_HELLO); - - /* - * Version indicates the negotiated version: for example from - * an SSLv2/v3 compatible client hello). The client_version - * field is the maximum version we permit and it is also - * used in RSA encrypted premaster secrets. Some servers can - * choke if we initially report a higher version then - * renegotiate to a lower one in the premaster secret. This - * didn't happen with TLS 1.0 as most servers supported it - * but it can with TLS 1.1 or later if the server only supports - * 1.0. - * - * Possible scenario with previous logic: - * 1. Client hello indicates TLS 1.2 - * 2. Server hello says TLS 1.0 - * 3. RSA encrypted premaster secret uses 1.2. - * 4. Handhaked proceeds using TLS 1.0. - * 5. Server sends hello request to renegotiate. - * 6. Client hello indicates TLS v1.0 as we now - * know that is maximum server supports. - * 7. Server chokes on RSA encrypted premaster secret - * containing version 1.0. - * - * For interoperability it should be OK to always use the - * maximum version we support in client hello and then rely - * on the checking of version to ensure the servers isn't - * being inconsistent: for example initially negotiating with - * TLS 1.0 and renegotiating with TLS 1.2. We do this by using - * client_version in client hello and not resetting it to - * the negotiated version. - */ - - *(p++) = s->client_version >> 8; - *(p++) = s->client_version & 0xff; - - /* Random stuff */ - memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE); - p += SSL3_RANDOM_SIZE; - - /* Session ID */ - if (s->internal->new_session) - i = 0; - else - i = s->session->session_id_length; - *(p++) = i; - if (i != 0) { - if (i > (int)sizeof(s->session->session_id)) { - SSLerr(SSL_F_SSL3_CLIENT_HELLO, - ERR_R_INTERNAL_ERROR); - goto err; - } - memcpy(p, s->session->session_id, i); - p += i; - } - - /* DTLS Cookie. */ - if (SSL_IS_DTLS(s)) { - if (D1I(s)->cookie_len > sizeof(D1I(s)->cookie)) { - SSLerr(SSL_F_DTLS1_CLIENT_HELLO, - ERR_R_INTERNAL_ERROR); - goto err; - } - *(p++) = D1I(s)->cookie_len; - memcpy(p, D1I(s)->cookie, D1I(s)->cookie_len); - p += D1I(s)->cookie_len; - } - - /* Ciphers supported */ - if (!ssl_cipher_list_to_bytes(s, SSL_get_ciphers(s), &p[2], - bufend - &p[2], &outlen)) - goto err; - if (outlen == 0) { - SSLerr(SSL_F_SSL3_CLIENT_HELLO, - SSL_R_NO_CIPHERS_AVAILABLE); - goto err; - } - s2n(outlen, p); - p += outlen; - - /* add in (no) COMPRESSION */ - *(p++) = 1; - *(p++) = 0; /* Add the NULL method */ - - /* TLS extensions*/ - if ((p = ssl_add_clienthello_tlsext(s, p, bufend)) == NULL) { - SSLerr(SSL_F_SSL3_CLIENT_HELLO, - ERR_R_INTERNAL_ERROR); - goto err; - } - - ssl3_handshake_msg_finish(s, p - d); - - s->internal->state = SSL3_ST_CW_CLNT_HELLO_B; - } - - /* SSL3_ST_CW_CLNT_HELLO_B */ - return (ssl3_handshake_write(s)); - -err: - return (-1); -} - -int -ssl3_get_server_hello(SSL *s) -{ - CBS cbs, server_random, session_id; - uint16_t server_version, cipher_suite; - uint16_t min_version, max_version; - uint8_t compression_method; - STACK_OF(SSL_CIPHER) *sk; - const SSL_CIPHER *cipher; - const SSL_METHOD *method; - unsigned char *p; - unsigned long alg_k; - size_t outlen; - int i, al, ok; - long n; - - s->internal->first_packet = 1; - n = s->method->internal->ssl_get_message(s, SSL3_ST_CR_SRVR_HELLO_A, - SSL3_ST_CR_SRVR_HELLO_B, -1, 20000, /* ?? */ &ok); - if (!ok) - return ((int)n); - s->internal->first_packet = 0; - - if (n < 0) - goto truncated; - - CBS_init(&cbs, s->internal->init_msg, n); - - if (SSL_IS_DTLS(s)) { - if (S3I(s)->tmp.message_type == DTLS1_MT_HELLO_VERIFY_REQUEST) { - if (D1I(s)->send_cookie == 0) { - S3I(s)->tmp.reuse_message = 1; - return (1); - } else { - /* Already sent a cookie. */ - al = SSL_AD_UNEXPECTED_MESSAGE; - SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, - SSL_R_BAD_MESSAGE_TYPE); - goto f_err; - } - } - } - - if (S3I(s)->tmp.message_type != SSL3_MT_SERVER_HELLO) { - al = SSL_AD_UNEXPECTED_MESSAGE; - SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, - SSL_R_BAD_MESSAGE_TYPE); - goto f_err; - } - - if (!CBS_get_u16(&cbs, &server_version)) - goto truncated; - - if (ssl_supported_version_range(s, &min_version, &max_version) != 1) { - SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, - SSL_R_NO_PROTOCOLS_AVAILABLE); - goto err; - } - - if (server_version < min_version || server_version > max_version) { - SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_WRONG_SSL_VERSION); - s->version = (s->version & 0xff00) | (server_version & 0xff); - al = SSL_AD_PROTOCOL_VERSION; - goto f_err; - } - s->version = server_version; - - if ((method = tls1_get_client_method(server_version)) == NULL) - method = dtls1_get_client_method(server_version); - if (method == NULL) { - SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, ERR_R_INTERNAL_ERROR); - goto err; - } - s->method = method; - - /* Server random. */ - if (!CBS_get_bytes(&cbs, &server_random, SSL3_RANDOM_SIZE)) - goto truncated; - if (!CBS_write_bytes(&server_random, s->s3->server_random, - sizeof(s->s3->server_random), NULL)) - goto err; - - /* Session ID. */ - if (!CBS_get_u8_length_prefixed(&cbs, &session_id)) - goto truncated; - - if ((CBS_len(&session_id) > sizeof(s->session->session_id)) || - (CBS_len(&session_id) > SSL3_SESSION_ID_SIZE)) { - al = SSL_AD_ILLEGAL_PARAMETER; - SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, - SSL_R_SSL3_SESSION_ID_TOO_LONG); - goto f_err; - } - - /* Cipher suite. */ - if (!CBS_get_u16(&cbs, &cipher_suite)) - goto truncated; - - /* - * Check if we want to resume the session based on external - * pre-shared secret. - */ - if (s->internal->tls_session_secret_cb) { - SSL_CIPHER *pref_cipher = NULL; - s->session->master_key_length = sizeof(s->session->master_key); - if (s->internal->tls_session_secret_cb(s, s->session->master_key, - &s->session->master_key_length, NULL, &pref_cipher, - s->internal->tls_session_secret_cb_arg)) { - s->session->cipher = pref_cipher ? pref_cipher : - ssl3_get_cipher_by_value(cipher_suite); - s->s3->flags |= SSL3_FLAGS_CCS_OK; - } - } - - if (s->session->session_id_length != 0 && - CBS_mem_equal(&session_id, s->session->session_id, - s->session->session_id_length)) { - if (s->sid_ctx_length != s->session->sid_ctx_length || - timingsafe_memcmp(s->session->sid_ctx, - s->sid_ctx, s->sid_ctx_length) != 0) { - /* actually a client application bug */ - al = SSL_AD_ILLEGAL_PARAMETER; - SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, - SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT); - goto f_err; - } - s->s3->flags |= SSL3_FLAGS_CCS_OK; - s->internal->hit = 1; - } else { - /* a miss or crap from the other end */ - - /* If we were trying for session-id reuse, make a new - * SSL_SESSION so we don't stuff up other people */ - s->internal->hit = 0; - if (s->session->session_id_length > 0) { - if (!ssl_get_new_session(s, 0)) { - al = SSL_AD_INTERNAL_ERROR; - goto f_err; - } - } - - /* - * XXX - improve the handling for the case where there is a - * zero length session identifier. - */ - if (!CBS_write_bytes(&session_id, s->session->session_id, - sizeof(s->session->session_id), &outlen)) - goto err; - s->session->session_id_length = outlen; - - s->session->ssl_version = s->version; - } - - if ((cipher = ssl3_get_cipher_by_value(cipher_suite)) == NULL) { - al = SSL_AD_ILLEGAL_PARAMETER; - SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, - SSL_R_UNKNOWN_CIPHER_RETURNED); - goto f_err; - } - - /* TLS v1.2 only ciphersuites require v1.2 or later. */ - if ((cipher->algorithm_ssl & SSL_TLSV1_2) && - (TLS1_get_version(s) < TLS1_2_VERSION)) { - al = SSL_AD_ILLEGAL_PARAMETER; - SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, - SSL_R_WRONG_CIPHER_RETURNED); - goto f_err; - } - - sk = ssl_get_ciphers_by_id(s); - i = sk_SSL_CIPHER_find(sk, cipher); - if (i < 0) { - /* we did not say we would use this cipher */ - al = SSL_AD_ILLEGAL_PARAMETER; - SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, - SSL_R_WRONG_CIPHER_RETURNED); - goto f_err; - } - - /* - * Depending on the session caching (internal/external), the cipher - * and/or cipher_id values may not be set. Make sure that - * cipher_id is set and use it for comparison. - */ - if (s->session->cipher) - s->session->cipher_id = s->session->cipher->id; - if (s->internal->hit && (s->session->cipher_id != cipher->id)) { - al = SSL_AD_ILLEGAL_PARAMETER; - SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, - SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED); - goto f_err; - } - S3I(s)->tmp.new_cipher = cipher; - - /* - * Don't digest cached records if no sigalgs: we may need them for - * client authentication. - */ - alg_k = S3I(s)->tmp.new_cipher->algorithm_mkey; - if (!(SSL_USE_SIGALGS(s) || (alg_k & SSL_kGOST)) && - !tls1_digest_cached_records(s)) { - al = SSL_AD_INTERNAL_ERROR; - goto f_err; - } - - if (!CBS_get_u8(&cbs, &compression_method)) - goto truncated; - - if (compression_method != 0) { - al = SSL_AD_ILLEGAL_PARAMETER; - SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, - SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM); - goto f_err; - } - - /* TLS extensions. */ - p = (unsigned char *)CBS_data(&cbs); - if (!ssl_parse_serverhello_tlsext(s, &p, CBS_len(&cbs), &al)) { - /* 'al' set by ssl_parse_serverhello_tlsext */ - SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_PARSE_TLSEXT); - goto f_err; - } - if (ssl_check_serverhello_tlsext(s) <= 0) { - SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_SERVERHELLO_TLSEXT); - goto err; - } - - /* See if any data remains... */ - if (p - CBS_data(&cbs) != CBS_len(&cbs)) - goto truncated; - - return (1); - -truncated: - /* wrong packet length */ - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_BAD_PACKET_LENGTH); -f_err: - ssl3_send_alert(s, SSL3_AL_FATAL, al); -err: - return (-1); -} - -int -ssl3_get_server_certificate(SSL *s) -{ - int al, i, ok, ret = -1; - long n; - CBS cbs, cert_list; - X509 *x = NULL; - const unsigned char *q; - STACK_OF(X509) *sk = NULL; - SESS_CERT *sc; - EVP_PKEY *pkey = NULL; - - n = s->method->internal->ssl_get_message(s, SSL3_ST_CR_CERT_A, - SSL3_ST_CR_CERT_B, -1, s->internal->max_cert_list, &ok); - - if (!ok) - return ((int)n); - - if (S3I(s)->tmp.message_type == SSL3_MT_SERVER_KEY_EXCHANGE) { - S3I(s)->tmp.reuse_message = 1; - return (1); - } - - if (S3I(s)->tmp.message_type != SSL3_MT_CERTIFICATE) { - al = SSL_AD_UNEXPECTED_MESSAGE; - SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, - SSL_R_BAD_MESSAGE_TYPE); - goto f_err; - } - - - if ((sk = sk_X509_new_null()) == NULL) { - SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, - ERR_R_MALLOC_FAILURE); - goto err; - } - - if (n < 0) - goto truncated; - - CBS_init(&cbs, s->internal->init_msg, n); - if (CBS_len(&cbs) < 3) - goto truncated; - - if (!CBS_get_u24_length_prefixed(&cbs, &cert_list) || - CBS_len(&cbs) != 0) { - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, - SSL_R_LENGTH_MISMATCH); - goto f_err; - } - - while (CBS_len(&cert_list) > 0) { - CBS cert; - - if (CBS_len(&cert_list) < 3) - goto truncated; - if (!CBS_get_u24_length_prefixed(&cert_list, &cert)) { - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, - SSL_R_CERT_LENGTH_MISMATCH); - goto f_err; - } - - q = CBS_data(&cert); - x = d2i_X509(NULL, &q, CBS_len(&cert)); - if (x == NULL) { - al = SSL_AD_BAD_CERTIFICATE; - SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, - ERR_R_ASN1_LIB); - goto f_err; - } - if (q != CBS_data(&cert) + CBS_len(&cert)) { - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, - SSL_R_CERT_LENGTH_MISMATCH); - goto f_err; - } - if (!sk_X509_push(sk, x)) { - SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, - ERR_R_MALLOC_FAILURE); - goto err; - } - x = NULL; - } - - i = ssl_verify_cert_chain(s, sk); - if ((s->verify_mode != SSL_VERIFY_NONE) && (i <= 0)) { - al = ssl_verify_alarm_type(s->verify_result); - SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, - SSL_R_CERTIFICATE_VERIFY_FAILED); - goto f_err; - - } - ERR_clear_error(); /* but we keep s->verify_result */ - - sc = ssl_sess_cert_new(); - if (sc == NULL) - goto err; - ssl_sess_cert_free(SSI(s)->sess_cert); - SSI(s)->sess_cert = sc; - - sc->cert_chain = sk; - /* - * Inconsistency alert: cert_chain does include the peer's - * certificate, which we don't include in s3_srvr.c - */ - x = sk_X509_value(sk, 0); - sk = NULL; - /* VRS 19990621: possible memory leak; sk=null ==> !sk_pop_free() @end*/ - - pkey = X509_get_pubkey(x); - - if (pkey == NULL || EVP_PKEY_missing_parameters(pkey)) { - x = NULL; - al = SSL3_AL_FATAL; - SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, - SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS); - goto f_err; - } - - i = ssl_cert_type(x, pkey); - if (i < 0) { - x = NULL; - al = SSL3_AL_FATAL; - SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, - SSL_R_UNKNOWN_CERTIFICATE_TYPE); - goto f_err; - } - - sc->peer_cert_type = i; - CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); - /* - * Why would the following ever happen? - * We just created sc a couple of lines ago. - */ - X509_free(sc->peer_pkeys[i].x509); - sc->peer_pkeys[i].x509 = x; - sc->peer_key = &(sc->peer_pkeys[i]); - - X509_free(s->session->peer); - CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); - s->session->peer = x; - s->session->verify_result = s->verify_result; - - x = NULL; - ret = 1; - - if (0) { -truncated: - /* wrong packet length */ - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, - SSL_R_BAD_PACKET_LENGTH); -f_err: - ssl3_send_alert(s, SSL3_AL_FATAL, al); - } -err: - EVP_PKEY_free(pkey); - X509_free(x); - sk_X509_pop_free(sk, X509_free); - - return (ret); -} - -static int -ssl3_get_server_kex_dhe(SSL *s, EVP_PKEY **pkey, unsigned char **pp, long *nn) -{ - CBS cbs, dhp, dhg, dhpk; - BN_CTX *bn_ctx = NULL; - SESS_CERT *sc = NULL; - DH *dh = NULL; - long alg_a; - int al; - - alg_a = S3I(s)->tmp.new_cipher->algorithm_auth; - sc = SSI(s)->sess_cert; - - if (*nn < 0) - goto err; - - CBS_init(&cbs, *pp, *nn); - - if ((dh = DH_new()) == NULL) { - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_DH_LIB); - goto err; - } - - if (!CBS_get_u16_length_prefixed(&cbs, &dhp)) - goto truncated; - if ((dh->p = BN_bin2bn(CBS_data(&dhp), CBS_len(&dhp), NULL)) == NULL) { - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_BN_LIB); - goto err; - } - - if (!CBS_get_u16_length_prefixed(&cbs, &dhg)) - goto truncated; - if ((dh->g = BN_bin2bn(CBS_data(&dhg), CBS_len(&dhg), NULL)) == NULL) { - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_BN_LIB); - goto err; - } - - if (!CBS_get_u16_length_prefixed(&cbs, &dhpk)) - goto truncated; - if ((dh->pub_key = BN_bin2bn(CBS_data(&dhpk), CBS_len(&dhpk), - NULL)) == NULL) { - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_BN_LIB); - goto err; - } - - /* - * Check the strength of the DH key just constructed. - * Discard keys weaker than 1024 bits. - */ - if (DH_size(dh) < 1024 / 8) { - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_DH_P_LENGTH); - goto err; - } - - if (alg_a & SSL_aRSA) - *pkey = X509_get_pubkey(sc->peer_pkeys[SSL_PKEY_RSA_ENC].x509); - else if (alg_a & SSL_aDSS) - *pkey = X509_get_pubkey(sc->peer_pkeys[SSL_PKEY_DSA_SIGN].x509); - else - /* XXX - Anonymous DH, so no certificate or pkey. */ - *pkey = NULL; - - sc->peer_dh_tmp = dh; - - *nn = CBS_len(&cbs); - *pp = (unsigned char *)CBS_data(&cbs); - - return (1); - - truncated: - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_PACKET_LENGTH); - ssl3_send_alert(s, SSL3_AL_FATAL, al); - - err: - DH_free(dh); - BN_CTX_free(bn_ctx); - - return (-1); -} - -static int -ssl3_get_server_kex_ecdhe_ecp(SSL *s, SESS_CERT *sc, int nid, CBS *public) -{ - const EC_GROUP *group; - EC_GROUP *ngroup = NULL; - EC_POINT *point = NULL; - BN_CTX *bn_ctx = NULL; - EC_KEY *ecdh = NULL; - int ret = -1; - - /* - * Extract the server's ephemeral ECDH public key. - */ - - if ((ecdh = EC_KEY_new()) == NULL) { - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE); - goto err; - } - - if ((ngroup = EC_GROUP_new_by_curve_name(nid)) == NULL) { - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_EC_LIB); - goto err; - } - if (EC_KEY_set_group(ecdh, ngroup) == 0) { - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_EC_LIB); - goto err; - } - - group = EC_KEY_get0_group(ecdh); - - if ((point = EC_POINT_new(group)) == NULL || - (bn_ctx = BN_CTX_new()) == NULL) { - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE); - goto err; - } - - if (EC_POINT_oct2point(group, point, CBS_data(public), - CBS_len(public), bn_ctx) == 0) { - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_ECPOINT); - ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - goto err; - } - - EC_KEY_set_public_key(ecdh, point); - sc->peer_ecdh_tmp = ecdh; - ecdh = NULL; - - ret = 1; - - err: - BN_CTX_free(bn_ctx); - EC_GROUP_free(ngroup); - EC_POINT_free(point); - EC_KEY_free(ecdh); - - return (ret); -} - -static int -ssl3_get_server_kex_ecdhe_ecx(SSL *s, SESS_CERT *sc, int nid, CBS *public) -{ - size_t outlen; - - if (nid != NID_X25519) { - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR); - goto err; - } - - if (CBS_len(public) != X25519_KEY_LENGTH) { - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_ECPOINT); - ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - goto err; - } - - if (!CBS_stow(public, &sc->peer_x25519_tmp, &outlen)) { - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE); - goto err; - } - - return (1); - - err: - return (-1); -} - -static int -ssl3_get_server_kex_ecdhe(SSL *s, EVP_PKEY **pkey, unsigned char **pp, long *nn) -{ - CBS cbs, public; - uint8_t curve_type; - uint16_t curve_id; - SESS_CERT *sc; - long alg_a; - int nid; - int al; - - alg_a = S3I(s)->tmp.new_cipher->algorithm_auth; - sc = SSI(s)->sess_cert; - - if (*nn < 0) - goto err; - - CBS_init(&cbs, *pp, *nn); - - /* Only named curves are supported. */ - if (!CBS_get_u8(&cbs, &curve_type) || - curve_type != NAMED_CURVE_TYPE || - !CBS_get_u16(&cbs, &curve_id)) { - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_TOO_SHORT); - goto f_err; - } - - /* - * Check that the curve is one of our preferences - if it is not, - * the server has sent us an invalid curve. - */ - if (tls1_check_curve(s, curve_id) != 1) { - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_WRONG_CURVE); - goto f_err; - } - - if ((nid = tls1_ec_curve_id2nid(curve_id)) == 0) { - al = SSL_AD_INTERNAL_ERROR; - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, - SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS); - goto f_err; - } - - if (!CBS_get_u8_length_prefixed(&cbs, &public)) - goto truncated; - - if (nid == NID_X25519) { - if (ssl3_get_server_kex_ecdhe_ecx(s, sc, nid, &public) != 1) - goto err; - } else { - if (ssl3_get_server_kex_ecdhe_ecp(s, sc, nid, &public) != 1) - goto err; - } - - /* - * The ECC/TLS specification does not mention the use of DSA to sign - * ECParameters in the server key exchange message. We do support RSA - * and ECDSA. - */ - if (alg_a & SSL_aRSA) - *pkey = X509_get_pubkey(sc->peer_pkeys[SSL_PKEY_RSA_ENC].x509); - else if (alg_a & SSL_aECDSA) - *pkey = X509_get_pubkey(sc->peer_pkeys[SSL_PKEY_ECC].x509); - else - /* XXX - Anonymous ECDH, so no certificate or pkey. */ - *pkey = NULL; - - *nn = CBS_len(&cbs); - *pp = (unsigned char *)CBS_data(&cbs); - - return (1); - - truncated: - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_PACKET_LENGTH); - - f_err: - ssl3_send_alert(s, SSL3_AL_FATAL, al); - - err: - return (-1); -} - -int -ssl3_get_server_key_exchange(SSL *s) -{ - unsigned char *q, md_buf[EVP_MAX_MD_SIZE*2]; - EVP_MD_CTX md_ctx; - unsigned char *param, *p; - int al, i, j, param_len, ok; - long n, alg_k, alg_a; - EVP_PKEY *pkey = NULL; - const EVP_MD *md = NULL; - RSA *rsa = NULL; - - alg_k = S3I(s)->tmp.new_cipher->algorithm_mkey; - alg_a = S3I(s)->tmp.new_cipher->algorithm_auth; - - /* - * Use same message size as in ssl3_get_certificate_request() - * as ServerKeyExchange message may be skipped. - */ - n = s->method->internal->ssl_get_message(s, SSL3_ST_CR_KEY_EXCH_A, - SSL3_ST_CR_KEY_EXCH_B, -1, s->internal->max_cert_list, &ok); - if (!ok) - return ((int)n); - - EVP_MD_CTX_init(&md_ctx); - - if (S3I(s)->tmp.message_type != SSL3_MT_SERVER_KEY_EXCHANGE) { - /* - * Do not skip server key exchange if this cipher suite uses - * ephemeral keys. - */ - if (alg_k & (SSL_kDHE|SSL_kECDHE)) { - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, - SSL_R_UNEXPECTED_MESSAGE); - al = SSL_AD_UNEXPECTED_MESSAGE; - goto f_err; - } - - S3I(s)->tmp.reuse_message = 1; - EVP_MD_CTX_cleanup(&md_ctx); - return (1); - } - - if (SSI(s)->sess_cert != NULL) { - DH_free(SSI(s)->sess_cert->peer_dh_tmp); - SSI(s)->sess_cert->peer_dh_tmp = NULL; - - EC_KEY_free(SSI(s)->sess_cert->peer_ecdh_tmp); - SSI(s)->sess_cert->peer_ecdh_tmp = NULL; - - free(SSI(s)->sess_cert->peer_x25519_tmp); - SSI(s)->sess_cert->peer_x25519_tmp = NULL; - } else { - SSI(s)->sess_cert = ssl_sess_cert_new(); - if (SSI(s)->sess_cert == NULL) - goto err; - } - - param = p = (unsigned char *)s->internal->init_msg; - param_len = n; - - if (alg_k & SSL_kDHE) { - if (ssl3_get_server_kex_dhe(s, &pkey, &p, &n) != 1) - goto err; - } else if (alg_k & SSL_kECDHE) { - if (ssl3_get_server_kex_ecdhe(s, &pkey, &p, &n) != 1) - goto err; - } else if (alg_k != 0) { - al = SSL_AD_UNEXPECTED_MESSAGE; - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_UNEXPECTED_MESSAGE); - goto f_err; - } - - param_len = param_len - n; - - /* if it was signed, check the signature */ - if (pkey != NULL) { - if (SSL_USE_SIGALGS(s)) { - int sigalg = tls12_get_sigid(pkey); - /* Should never happen */ - if (sigalg == -1) { - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, - ERR_R_INTERNAL_ERROR); - goto err; - } - /* - * Check key type is consistent - * with signature - */ - if (2 > n) - goto truncated; - if (sigalg != (int)p[1]) { - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, - SSL_R_WRONG_SIGNATURE_TYPE); - al = SSL_AD_DECODE_ERROR; - goto f_err; - } - md = tls12_get_hash(p[0]); - if (md == NULL) { - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, - SSL_R_UNKNOWN_DIGEST); - al = SSL_AD_DECODE_ERROR; - goto f_err; - } - p += 2; - n -= 2; - } else - md = EVP_sha1(); - - if (2 > n) - goto truncated; - n2s(p, i); - n -= 2; - j = EVP_PKEY_size(pkey); - - if (i != n || n > j) { - /* wrong packet length */ - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, - SSL_R_WRONG_SIGNATURE_LENGTH); - goto f_err; - } - - if (pkey->type == EVP_PKEY_RSA && !SSL_USE_SIGALGS(s)) { - int num; - - j = 0; - q = md_buf; - for (num = 2; num > 0; num--) { - if (!EVP_DigestInit_ex(&md_ctx, - (num == 2) ? s->ctx->internal->md5 : - s->ctx->internal->sha1, NULL)) { - al = SSL_AD_INTERNAL_ERROR; - goto f_err; - } - EVP_DigestUpdate(&md_ctx, - s->s3->client_random, - SSL3_RANDOM_SIZE); - EVP_DigestUpdate(&md_ctx, - s->s3->server_random, - SSL3_RANDOM_SIZE); - EVP_DigestUpdate(&md_ctx, param, param_len); - EVP_DigestFinal_ex(&md_ctx, q, - (unsigned int *)&i); - q += i; - j += i; - } - i = RSA_verify(NID_md5_sha1, md_buf, j, - p, n, pkey->pkey.rsa); - if (i < 0) { - al = SSL_AD_DECRYPT_ERROR; - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, - SSL_R_BAD_RSA_DECRYPT); - goto f_err; - } - if (i == 0) { - /* bad signature */ - al = SSL_AD_DECRYPT_ERROR; - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, - SSL_R_BAD_SIGNATURE); - goto f_err; - } - } else { - EVP_VerifyInit_ex(&md_ctx, md, NULL); - EVP_VerifyUpdate(&md_ctx, s->s3->client_random, - SSL3_RANDOM_SIZE); - EVP_VerifyUpdate(&md_ctx, s->s3->server_random, - SSL3_RANDOM_SIZE); - EVP_VerifyUpdate(&md_ctx, param, param_len); - if (EVP_VerifyFinal(&md_ctx, p,(int)n, pkey) <= 0) { - /* bad signature */ - al = SSL_AD_DECRYPT_ERROR; - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, - SSL_R_BAD_SIGNATURE); - goto f_err; - } - } - } else { - /* aNULL does not need public keys. */ - if (!(alg_a & SSL_aNULL)) { - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, - ERR_R_INTERNAL_ERROR); - goto err; - } - /* still data left over */ - if (n != 0) { - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, - SSL_R_EXTRA_DATA_IN_MESSAGE); - goto f_err; - } - } - - EVP_PKEY_free(pkey); - EVP_MD_CTX_cleanup(&md_ctx); - - return (1); - - truncated: - /* wrong packet length */ - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_PACKET_LENGTH); - - f_err: - ssl3_send_alert(s, SSL3_AL_FATAL, al); - - err: - EVP_PKEY_free(pkey); - RSA_free(rsa); - EVP_MD_CTX_cleanup(&md_ctx); - - return (-1); -} - -int -ssl3_get_certificate_request(SSL *s) -{ - int ok, ret = 0; - long n; - uint8_t ctype_num; - CBS cert_request, ctypes, rdn_list; - X509_NAME *xn = NULL; - const unsigned char *q; - STACK_OF(X509_NAME) *ca_sk = NULL; - - n = s->method->internal->ssl_get_message(s, SSL3_ST_CR_CERT_REQ_A, - SSL3_ST_CR_CERT_REQ_B, -1, s->internal->max_cert_list, &ok); - - if (!ok) - return ((int)n); - - S3I(s)->tmp.cert_req = 0; - - if (S3I(s)->tmp.message_type == SSL3_MT_SERVER_DONE) { - S3I(s)->tmp.reuse_message = 1; - /* - * If we get here we don't need any cached handshake records - * as we wont be doing client auth. - */ - if (S3I(s)->handshake_buffer) { - if (!tls1_digest_cached_records(s)) - goto err; - } - return (1); - } - - if (S3I(s)->tmp.message_type != SSL3_MT_CERTIFICATE_REQUEST) { - ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); - SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, - SSL_R_WRONG_MESSAGE_TYPE); - goto err; - } - - /* TLS does not like anon-DH with client cert */ - if (S3I(s)->tmp.new_cipher->algorithm_auth & SSL_aNULL) { - ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); - SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, - SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER); - goto err; - } - - if (n < 0) - goto truncated; - CBS_init(&cert_request, s->internal->init_msg, n); - - if ((ca_sk = sk_X509_NAME_new(ca_dn_cmp)) == NULL) { - SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, - ERR_R_MALLOC_FAILURE); - goto err; - } - - /* get the certificate types */ - if (!CBS_get_u8(&cert_request, &ctype_num)) - goto truncated; - - if (ctype_num > SSL3_CT_NUMBER) - ctype_num = SSL3_CT_NUMBER; - if (!CBS_get_bytes(&cert_request, &ctypes, ctype_num) || - !CBS_write_bytes(&ctypes, (uint8_t *)S3I(s)->tmp.ctype, - sizeof(S3I(s)->tmp.ctype), NULL)) { - SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, - SSL_R_DATA_LENGTH_TOO_LONG); - goto err; - } - - if (SSL_USE_SIGALGS(s)) { - CBS sigalgs; - - if (CBS_len(&cert_request) < 2) { - SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, - SSL_R_DATA_LENGTH_TOO_LONG); - goto err; - } - - /* Check we have enough room for signature algorithms and - * following length value. - */ - if (!CBS_get_u16_length_prefixed(&cert_request, &sigalgs)) { - ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, - SSL_R_DATA_LENGTH_TOO_LONG); - goto err; - } - if ((CBS_len(&sigalgs) & 1) || - !tls1_process_sigalgs(s, CBS_data(&sigalgs), - CBS_len(&sigalgs))) { - ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, - SSL_R_SIGNATURE_ALGORITHMS_ERROR); - goto err; - } - } - - /* get the CA RDNs */ - if (CBS_len(&cert_request) < 2) { - SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, - SSL_R_DATA_LENGTH_TOO_LONG); - goto err; - } - - if (!CBS_get_u16_length_prefixed(&cert_request, &rdn_list) || - CBS_len(&cert_request) != 0) { - ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, - SSL_R_LENGTH_MISMATCH); - goto err; - } - - while (CBS_len(&rdn_list) > 0) { - CBS rdn; - - if (CBS_len(&rdn_list) < 2) { - SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, - SSL_R_DATA_LENGTH_TOO_LONG); - goto err; - } - - if (!CBS_get_u16_length_prefixed(&rdn_list, &rdn)) { - ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, - SSL_R_CA_DN_TOO_LONG); - goto err; - } - - q = CBS_data(&rdn); - if ((xn = d2i_X509_NAME(NULL, &q, CBS_len(&rdn))) == NULL) { - ssl3_send_alert(s, SSL3_AL_FATAL, - SSL_AD_DECODE_ERROR); - SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, - ERR_R_ASN1_LIB); - goto err; - } - - if (q != CBS_data(&rdn) + CBS_len(&rdn)) { - ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, - SSL_R_CA_DN_LENGTH_MISMATCH); - goto err; - } - if (!sk_X509_NAME_push(ca_sk, xn)) { - SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, - ERR_R_MALLOC_FAILURE); - goto err; - } - xn = NULL; /* avoid free in err block */ - } - - /* we should setup a certificate to return.... */ - S3I(s)->tmp.cert_req = 1; - S3I(s)->tmp.ctype_num = ctype_num; - sk_X509_NAME_pop_free(S3I(s)->tmp.ca_names, X509_NAME_free); - S3I(s)->tmp.ca_names = ca_sk; - ca_sk = NULL; - - ret = 1; - if (0) { -truncated: - SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, - SSL_R_BAD_PACKET_LENGTH); - } -err: - X509_NAME_free(xn); - sk_X509_NAME_pop_free(ca_sk, X509_NAME_free); - return (ret); -} - -static int -ca_dn_cmp(const X509_NAME * const *a, const X509_NAME * const *b) -{ - return (X509_NAME_cmp(*a, *b)); -} - -int -ssl3_get_new_session_ticket(SSL *s) -{ - int ok, al, ret = 0; - uint32_t lifetime_hint; - long n; - CBS cbs, session_ticket; - - n = s->method->internal->ssl_get_message(s, SSL3_ST_CR_SESSION_TICKET_A, - SSL3_ST_CR_SESSION_TICKET_B, -1, 16384, &ok); - if (!ok) - return ((int)n); - - if (S3I(s)->tmp.message_type == SSL3_MT_FINISHED) { - S3I(s)->tmp.reuse_message = 1; - return (1); - } - if (S3I(s)->tmp.message_type != SSL3_MT_NEWSESSION_TICKET) { - al = SSL_AD_UNEXPECTED_MESSAGE; - SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET, - SSL_R_BAD_MESSAGE_TYPE); - goto f_err; - } - - if (n < 0) { - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET, - SSL_R_LENGTH_MISMATCH); - goto f_err; - } - - CBS_init(&cbs, s->internal->init_msg, n); - if (!CBS_get_u32(&cbs, &lifetime_hint) || -#if UINT32_MAX > LONG_MAX - lifetime_hint > LONG_MAX || -#endif - !CBS_get_u16_length_prefixed(&cbs, &session_ticket) || - CBS_len(&cbs) != 0) { - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET, - SSL_R_LENGTH_MISMATCH); - goto f_err; - } - s->session->tlsext_tick_lifetime_hint = (long)lifetime_hint; - - if (!CBS_stow(&session_ticket, &s->session->tlsext_tick, - &s->session->tlsext_ticklen)) { - SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET, - ERR_R_MALLOC_FAILURE); - goto err; - } - - /* - * There are two ways to detect a resumed ticket sesion. - * One is to set an appropriate session ID and then the server - * must return a match in ServerHello. This allows the normal - * client session ID matching to work and we know much - * earlier that the ticket has been accepted. - * - * The other way is to set zero length session ID when the - * ticket is presented and rely on the handshake to determine - * session resumption. - * - * We choose the former approach because this fits in with - * assumptions elsewhere in OpenSSL. The session ID is set - * to the SHA256 (or SHA1 is SHA256 is disabled) hash of the - * ticket. - */ - EVP_Digest(CBS_data(&session_ticket), CBS_len(&session_ticket), - s->session->session_id, &s->session->session_id_length, - EVP_sha256(), NULL); - ret = 1; - return (ret); -f_err: - ssl3_send_alert(s, SSL3_AL_FATAL, al); -err: - return (-1); -} - -int -ssl3_get_cert_status(SSL *s) -{ - CBS cert_status, response; - size_t stow_len; - int ok, al; - long n; - uint8_t status_type; - - n = s->method->internal->ssl_get_message(s, SSL3_ST_CR_CERT_STATUS_A, - SSL3_ST_CR_CERT_STATUS_B, SSL3_MT_CERTIFICATE_STATUS, - 16384, &ok); - - if (!ok) - return ((int)n); - - if (n < 0) { - /* need at least status type + length */ - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_CERT_STATUS, - SSL_R_LENGTH_MISMATCH); - goto f_err; - } - - CBS_init(&cert_status, s->internal->init_msg, n); - if (!CBS_get_u8(&cert_status, &status_type) || - CBS_len(&cert_status) < 3) { - /* need at least status type + length */ - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_CERT_STATUS, - SSL_R_LENGTH_MISMATCH); - goto f_err; - } - - if (status_type != TLSEXT_STATUSTYPE_ocsp) { - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_CERT_STATUS, - SSL_R_UNSUPPORTED_STATUS_TYPE); - goto f_err; - } - - if (!CBS_get_u24_length_prefixed(&cert_status, &response) || - CBS_len(&cert_status) != 0) { - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_CERT_STATUS, - SSL_R_LENGTH_MISMATCH); - goto f_err; - } - - if (!CBS_stow(&response, &s->internal->tlsext_ocsp_resp, - &stow_len) || stow_len > INT_MAX) { - s->internal->tlsext_ocsp_resplen = 0; - al = SSL_AD_INTERNAL_ERROR; - SSLerr(SSL_F_SSL3_GET_CERT_STATUS, - ERR_R_MALLOC_FAILURE); - goto f_err; - } - s->internal->tlsext_ocsp_resplen = (int)stow_len; - - if (s->ctx->internal->tlsext_status_cb) { - int ret; - ret = s->ctx->internal->tlsext_status_cb(s, - s->ctx->internal->tlsext_status_arg); - if (ret == 0) { - al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE; - SSLerr(SSL_F_SSL3_GET_CERT_STATUS, - SSL_R_INVALID_STATUS_RESPONSE); - goto f_err; - } - if (ret < 0) { - al = SSL_AD_INTERNAL_ERROR; - SSLerr(SSL_F_SSL3_GET_CERT_STATUS, - ERR_R_MALLOC_FAILURE); - goto f_err; - } - } - return (1); -f_err: - ssl3_send_alert(s, SSL3_AL_FATAL, al); - return (-1); -} - -int -ssl3_get_server_done(SSL *s) -{ - int ok, ret = 0; - long n; - - n = s->method->internal->ssl_get_message(s, SSL3_ST_CR_SRVR_DONE_A, - SSL3_ST_CR_SRVR_DONE_B, SSL3_MT_SERVER_DONE, - 30, /* should be very small, like 0 :-) */ &ok); - - if (!ok) - return ((int)n); - if (n > 0) { - /* should contain no data */ - ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - SSLerr(SSL_F_SSL3_GET_SERVER_DONE, SSL_R_LENGTH_MISMATCH); - return (-1); - } - ret = 1; - return (ret); -} - -static int -ssl3_send_client_kex_rsa(SSL *s, SESS_CERT *sess_cert, CBB *cbb) -{ - unsigned char pms[SSL_MAX_MASTER_KEY_LENGTH]; - unsigned char *enc_pms = NULL; - EVP_PKEY *pkey = NULL; - int ret = -1; - int enc_len; - CBB epms; - - /* - * RSA-Encrypted Premaster Secret Message - RFC 5246 section 7.4.7.1. - */ - - pkey = X509_get_pubkey(sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509); - if (pkey == NULL || pkey->type != EVP_PKEY_RSA || - pkey->pkey.rsa == NULL) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - ERR_R_INTERNAL_ERROR); - goto err; - } - - pms[0] = s->client_version >> 8; - pms[1] = s->client_version & 0xff; - arc4random_buf(&pms[2], sizeof(pms) - 2); - - if ((enc_pms = malloc(RSA_size(pkey->pkey.rsa))) == NULL) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - ERR_R_MALLOC_FAILURE); - goto err; - } - - enc_len = RSA_public_encrypt(sizeof(pms), pms, enc_pms, pkey->pkey.rsa, - RSA_PKCS1_PADDING); - if (enc_len <= 0) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - SSL_R_BAD_RSA_ENCRYPT); - goto err; - } - - if (!CBB_add_u16_length_prefixed(cbb, &epms)) - goto err; - if (!CBB_add_bytes(&epms, enc_pms, enc_len)) - goto err; - if (!CBB_flush(cbb)) - goto err; - - s->session->master_key_length = - s->method->internal->ssl3_enc->generate_master_secret(s, - s->session->master_key, pms, sizeof(pms)); - - ret = 1; - -err: - explicit_bzero(pms, sizeof(pms)); - EVP_PKEY_free(pkey); - free(enc_pms); - - return (ret); -} - -static int -ssl3_send_client_kex_dhe(SSL *s, SESS_CERT *sess_cert, CBB *cbb) -{ - DH *dh_srvr = NULL, *dh_clnt = NULL; - unsigned char *key = NULL; - int key_size = 0, key_len; - unsigned char *data; - int ret = -1; - CBB dh_Yc; - - /* Ensure that we have an ephemeral key for DHE. */ - if (sess_cert->peer_dh_tmp == NULL) { - ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - SSL_R_UNABLE_TO_FIND_DH_PARAMETERS); - goto err; - } - dh_srvr = sess_cert->peer_dh_tmp; - - /* Generate a new random key. */ - if ((dh_clnt = DHparams_dup(dh_srvr)) == NULL) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB); - goto err; - } - if (!DH_generate_key(dh_clnt)) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB); - goto err; - } - key_size = DH_size(dh_clnt); - if ((key = malloc(key_size)) == NULL) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - ERR_R_MALLOC_FAILURE); - goto err; - } - key_len = DH_compute_key(key, dh_srvr->pub_key, dh_clnt); - if (key_len <= 0) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB); - goto err; - } - - /* Generate master key from the result. */ - s->session->master_key_length = - s->method->internal->ssl3_enc->generate_master_secret(s, - s->session->master_key, key, key_len); - - if (!CBB_add_u16_length_prefixed(cbb, &dh_Yc)) - goto err; - if (!CBB_add_space(&dh_Yc, &data, BN_num_bytes(dh_clnt->pub_key))) - goto err; - BN_bn2bin(dh_clnt->pub_key, data); - if (!CBB_flush(cbb)) - goto err; - - ret = 1; - -err: - DH_free(dh_clnt); - if (key != NULL) - explicit_bzero(key, key_size); - free(key); - - return (ret); -} - -static int -ssl3_send_client_kex_ecdhe_ecp(SSL *s, SESS_CERT *sc, CBB *cbb) -{ - const EC_GROUP *group = NULL; - const EC_POINT *point = NULL; - EC_KEY *ecdh = NULL; - BN_CTX *bn_ctx = NULL; - unsigned char *key = NULL; - unsigned char *data; - size_t encoded_len; - int key_size = 0, key_len; - int ret = -1; - CBB ecpoint; - - if ((group = EC_KEY_get0_group(sc->peer_ecdh_tmp)) == NULL || - (point = EC_KEY_get0_public_key(sc->peer_ecdh_tmp)) == NULL) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - ERR_R_INTERNAL_ERROR); - goto err; - } - - if ((ecdh = EC_KEY_new()) == NULL) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - ERR_R_MALLOC_FAILURE); - goto err; - } - - if (!EC_KEY_set_group(ecdh, group)) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB); - goto err; - } - - /* Generate a new ECDH key pair. */ - if (!(EC_KEY_generate_key(ecdh))) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB); - goto err; - } - if ((key_size = ECDH_size(ecdh)) <= 0) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB); - goto err; - } - if ((key = malloc(key_size)) == NULL) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - ERR_R_MALLOC_FAILURE); - } - key_len = ECDH_compute_key(key, key_size, point, ecdh, NULL); - if (key_len <= 0) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB); - goto err; - } - - /* Generate master key from the result. */ - s->session->master_key_length = - s->method->internal->ssl3_enc->generate_master_secret(s, - s->session->master_key, key, key_len); - - encoded_len = EC_POINT_point2oct(group, EC_KEY_get0_public_key(ecdh), - POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL); - if (encoded_len == 0) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB); - goto err; - } - - if ((bn_ctx = BN_CTX_new()) == NULL) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - ERR_R_MALLOC_FAILURE); - goto err; - } - - /* Encode the public key. */ - if (!CBB_add_u8_length_prefixed(cbb, &ecpoint)) - goto err; - if (!CBB_add_space(&ecpoint, &data, encoded_len)) - goto err; - if (EC_POINT_point2oct(group, EC_KEY_get0_public_key(ecdh), - POINT_CONVERSION_UNCOMPRESSED, data, encoded_len, - bn_ctx) == 0) - goto err; - if (!CBB_flush(cbb)) - goto err; - - ret = 1; - - err: - if (key != NULL) - explicit_bzero(key, key_size); - free(key); - - BN_CTX_free(bn_ctx); - EC_KEY_free(ecdh); - - return (ret); -} - -static int -ssl3_send_client_kex_ecdhe_ecx(SSL *s, SESS_CERT *sc, CBB *cbb) -{ - uint8_t *public_key = NULL, *private_key = NULL, *shared_key = NULL; - int ret = -1; - CBB ecpoint; - - /* Generate X25519 key pair and derive shared key. */ - if ((public_key = malloc(X25519_KEY_LENGTH)) == NULL) - goto err; - if ((private_key = malloc(X25519_KEY_LENGTH)) == NULL) - goto err; - if ((shared_key = malloc(X25519_KEY_LENGTH)) == NULL) - goto err; - X25519_keypair(public_key, private_key); - if (!X25519(shared_key, private_key, sc->peer_x25519_tmp)) - goto err; - - /* Serialize the public key. */ - if (!CBB_add_u8_length_prefixed(cbb, &ecpoint)) - goto err; - if (!CBB_add_bytes(&ecpoint, public_key, X25519_KEY_LENGTH)) - goto err; - if (!CBB_flush(cbb)) - goto err; - - /* Generate master key from the result. */ - s->session->master_key_length = - s->method->internal->ssl3_enc->generate_master_secret(s, - s->session->master_key, shared_key, X25519_KEY_LENGTH); - - ret = 1; - - err: - if (private_key != NULL) - explicit_bzero(private_key, X25519_KEY_LENGTH); - if (shared_key != NULL) - explicit_bzero(shared_key, X25519_KEY_LENGTH); - - free(public_key); - free(private_key); - free(shared_key); - - return (ret); -} - -static int -ssl3_send_client_kex_ecdhe(SSL *s, SESS_CERT *sc, CBB *cbb) -{ - if (sc->peer_x25519_tmp != NULL) { - if (ssl3_send_client_kex_ecdhe_ecx(s, sc, cbb) != 1) - goto err; - } else if (sc->peer_ecdh_tmp != NULL) { - if (ssl3_send_client_kex_ecdhe_ecp(s, sc, cbb) != 1) - goto err; - } else { - ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - ERR_R_INTERNAL_ERROR); - goto err; - } - - return (1); - - err: - return (-1); -} - -static int -ssl3_send_client_kex_gost(SSL *s, SESS_CERT *sess_cert, CBB *cbb) -{ - unsigned char premaster_secret[32], shared_ukm[32], tmp[256]; - EVP_PKEY *pub_key = NULL; - EVP_PKEY_CTX *pkey_ctx; - X509 *peer_cert; - size_t msglen; - unsigned int md_len; - EVP_MD_CTX *ukm_hash; - int ret = -1; - int nid; - CBB gostblob; - - /* Get server sertificate PKEY and create ctx from it */ - peer_cert = sess_cert->peer_pkeys[SSL_PKEY_GOST01].x509; - if (peer_cert == NULL) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER); - goto err; - } - - pub_key = X509_get_pubkey(peer_cert); - pkey_ctx = EVP_PKEY_CTX_new(pub_key, NULL); - - /* - * If we have send a certificate, and certificate key parameters match - * those of server certificate, use certificate key for key exchange. - * Otherwise, generate ephemeral key pair. - */ - EVP_PKEY_encrypt_init(pkey_ctx); - - /* Generate session key. */ - arc4random_buf(premaster_secret, 32); - - /* - * If we have client certificate, use its secret as peer key. - */ - if (S3I(s)->tmp.cert_req && s->cert->key->privatekey) { - if (EVP_PKEY_derive_set_peer(pkey_ctx, - s->cert->key->privatekey) <=0) { - /* - * If there was an error - just ignore it. - * Ephemeral key would be used. - */ - ERR_clear_error(); - } - } - - /* - * Compute shared IV and store it in algorithm-specific context data. - */ - ukm_hash = EVP_MD_CTX_create(); - if (ukm_hash == NULL) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - ERR_R_MALLOC_FAILURE); - goto err; - } - - if (ssl_get_algorithm2(s) & SSL_HANDSHAKE_MAC_GOST94) - nid = NID_id_GostR3411_94; - else - nid = NID_id_tc26_gost3411_2012_256; - if (!EVP_DigestInit(ukm_hash, EVP_get_digestbynid(nid))) - goto err; - EVP_DigestUpdate(ukm_hash, s->s3->client_random, SSL3_RANDOM_SIZE); - EVP_DigestUpdate(ukm_hash, s->s3->server_random, SSL3_RANDOM_SIZE); - EVP_DigestFinal_ex(ukm_hash, shared_ukm, &md_len); - EVP_MD_CTX_destroy(ukm_hash); - if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, EVP_PKEY_OP_ENCRYPT, - EVP_PKEY_CTRL_SET_IV, 8, shared_ukm) < 0) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, SSL_R_LIBRARY_BUG); - goto err; - } - - /* - * Make GOST keytransport blob message, encapsulate it into sequence. - */ - msglen = 255; - if (EVP_PKEY_encrypt(pkey_ctx, tmp, &msglen, premaster_secret, - 32) < 0) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, SSL_R_LIBRARY_BUG); - goto err; - } - - if (!CBB_add_asn1(cbb, &gostblob, CBS_ASN1_SEQUENCE)) - goto err; - if (!CBB_add_bytes(&gostblob, tmp, msglen)) - goto err; - if (!CBB_flush(cbb)) - goto err; - - /* Check if pubkey from client certificate was used. */ - if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 2, - NULL) > 0) { - /* Set flag "skip certificate verify". */ - s->s3->flags |= TLS1_FLAGS_SKIP_CERT_VERIFY; - } - EVP_PKEY_CTX_free(pkey_ctx); - s->session->master_key_length = - s->method->internal->ssl3_enc->generate_master_secret(s, - s->session->master_key, premaster_secret, 32); - - ret = 1; - - err: - explicit_bzero(premaster_secret, sizeof(premaster_secret)); - EVP_PKEY_free(pub_key); - - return (ret); -} - -int -ssl3_send_client_key_exchange(SSL *s) -{ - SESS_CERT *sess_cert; - unsigned long alg_k; - CBB cbb, kex; - - memset(&cbb, 0, sizeof(cbb)); - - if (s->internal->state == SSL3_ST_CW_KEY_EXCH_A) { - alg_k = S3I(s)->tmp.new_cipher->algorithm_mkey; - - if ((sess_cert = SSI(s)->sess_cert) == NULL) { - ssl3_send_alert(s, SSL3_AL_FATAL, - SSL_AD_UNEXPECTED_MESSAGE); - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - ERR_R_INTERNAL_ERROR); - goto err; - } - - if (!ssl3_handshake_msg_start_cbb(s, &cbb, &kex, - SSL3_MT_CLIENT_KEY_EXCHANGE)) - goto err; - - if (alg_k & SSL_kRSA) { - if (ssl3_send_client_kex_rsa(s, sess_cert, &kex) != 1) - goto err; - } else if (alg_k & SSL_kDHE) { - if (ssl3_send_client_kex_dhe(s, sess_cert, &kex) != 1) - goto err; - } else if (alg_k & SSL_kECDHE) { - if (ssl3_send_client_kex_ecdhe(s, sess_cert, &kex) != 1) - goto err; - } else if (alg_k & SSL_kGOST) { - if (ssl3_send_client_kex_gost(s, sess_cert, &kex) != 1) - goto err; - } else { - ssl3_send_alert(s, SSL3_AL_FATAL, - SSL_AD_HANDSHAKE_FAILURE); - SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, - ERR_R_INTERNAL_ERROR); - goto err; - } - - if (!ssl3_handshake_msg_finish_cbb(s, &cbb)) - goto err; - - s->internal->state = SSL3_ST_CW_KEY_EXCH_B; - } - - /* SSL3_ST_CW_KEY_EXCH_B */ - return (ssl3_handshake_write(s)); - -err: - CBB_cleanup(&cbb); - - return (-1); -} - -int -ssl3_send_client_verify(SSL *s) -{ - unsigned char *p; - unsigned char data[MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH]; - EVP_PKEY *pkey; - EVP_PKEY_CTX *pctx = NULL; - EVP_MD_CTX mctx; - unsigned u = 0; - unsigned long n; - int j; - - EVP_MD_CTX_init(&mctx); - - if (s->internal->state == SSL3_ST_CW_CERT_VRFY_A) { - p = ssl3_handshake_msg_start(s, SSL3_MT_CERTIFICATE_VERIFY); - - /* - * Create context from key and test if sha1 is allowed as - * digest. - */ - pkey = s->cert->key->privatekey; - pctx = EVP_PKEY_CTX_new(pkey, NULL); - EVP_PKEY_sign_init(pctx); - if (EVP_PKEY_CTX_set_signature_md(pctx, EVP_sha1()) > 0) { - if (!SSL_USE_SIGALGS(s)) - s->method->internal->ssl3_enc->cert_verify_mac(s, - NID_sha1, &(data[MD5_DIGEST_LENGTH])); - } else { - ERR_clear_error(); - } - /* - * For TLS v1.2 send signature algorithm and signature - * using agreed digest and cached handshake records. - */ - if (SSL_USE_SIGALGS(s)) { - long hdatalen = 0; - void *hdata; - const EVP_MD *md = s->cert->key->digest; - hdatalen = BIO_get_mem_data(S3I(s)->handshake_buffer, - &hdata); - if (hdatalen <= 0 || - !tls12_get_sigandhash(p, pkey, md)) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, - ERR_R_INTERNAL_ERROR); - goto err; - } - p += 2; - if (!EVP_SignInit_ex(&mctx, md, NULL) || - !EVP_SignUpdate(&mctx, hdata, hdatalen) || - !EVP_SignFinal(&mctx, p + 2, &u, pkey)) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, - ERR_R_EVP_LIB); - goto err; - } - s2n(u, p); - n = u + 4; - if (!tls1_digest_cached_records(s)) - goto err; - } else if (pkey->type == EVP_PKEY_RSA) { - s->method->internal->ssl3_enc->cert_verify_mac( - s, NID_md5, &(data[0])); - if (RSA_sign(NID_md5_sha1, data, - MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH, &(p[2]), - &u, pkey->pkey.rsa) <= 0 ) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, - ERR_R_RSA_LIB); - goto err; - } - s2n(u, p); - n = u + 2; - } else if (pkey->type == EVP_PKEY_DSA) { - if (!DSA_sign(pkey->save_type, - &(data[MD5_DIGEST_LENGTH]), - SHA_DIGEST_LENGTH, &(p[2]), - (unsigned int *)&j, pkey->pkey.dsa)) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, - ERR_R_DSA_LIB); - goto err; - } - s2n(j, p); - n = j + 2; - } else if (pkey->type == EVP_PKEY_EC) { - if (!ECDSA_sign(pkey->save_type, - &(data[MD5_DIGEST_LENGTH]), - SHA_DIGEST_LENGTH, &(p[2]), - (unsigned int *)&j, pkey->pkey.ec)) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, - ERR_R_ECDSA_LIB); - goto err; - } - s2n(j, p); - n = j + 2; -#ifndef OPENSSL_NO_GOST - } else if (pkey->type == NID_id_GostR3410_94 || - pkey->type == NID_id_GostR3410_2001) { - unsigned char signbuf[128]; - long hdatalen = 0; - void *hdata; - const EVP_MD *md; - int nid; - size_t sigsize; - - hdatalen = BIO_get_mem_data(S3I(s)->handshake_buffer, &hdata); - if (hdatalen <= 0) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, - ERR_R_INTERNAL_ERROR); - goto err; - } - if (!EVP_PKEY_get_default_digest_nid(pkey, &nid) || - !(md = EVP_get_digestbynid(nid))) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, - ERR_R_EVP_LIB); - goto err; - } - if (!EVP_DigestInit_ex(&mctx, md, NULL) || - !EVP_DigestUpdate(&mctx, hdata, hdatalen) || - !EVP_DigestFinal(&mctx, signbuf, &u) || - (EVP_PKEY_CTX_set_signature_md(pctx, md) <= 0) || - (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN, - EVP_PKEY_CTRL_GOST_SIG_FORMAT, - GOST_SIG_FORMAT_RS_LE, - NULL) <= 0) || - (EVP_PKEY_sign(pctx, &(p[2]), &sigsize, - signbuf, u) <= 0)) { - SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, - ERR_R_EVP_LIB); - goto err; - } - if (!tls1_digest_cached_records(s)) - goto err; - j = sigsize; - s2n(j, p); - n = j + 2; -#endif - } else { - SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, - ERR_R_INTERNAL_ERROR); - goto err; - } - - s->internal->state = SSL3_ST_CW_CERT_VRFY_B; - - ssl3_handshake_msg_finish(s, n); - } - - EVP_MD_CTX_cleanup(&mctx); - EVP_PKEY_CTX_free(pctx); - - return (ssl3_handshake_write(s)); - -err: - EVP_MD_CTX_cleanup(&mctx); - EVP_PKEY_CTX_free(pctx); - return (-1); -} - -int -ssl3_send_client_certificate(SSL *s) -{ - EVP_PKEY *pkey = NULL; - X509 *x509 = NULL; - CBB cbb, client_cert; - int i; - - memset(&cbb, 0, sizeof(cbb)); - - if (s->internal->state == SSL3_ST_CW_CERT_A) { - if ((s->cert == NULL) || (s->cert->key->x509 == NULL) || - (s->cert->key->privatekey == NULL)) - s->internal->state = SSL3_ST_CW_CERT_B; - else - s->internal->state = SSL3_ST_CW_CERT_C; - } - - /* We need to get a client cert */ - if (s->internal->state == SSL3_ST_CW_CERT_B) { - /* - * If we get an error, we need to - * ssl->rwstate=SSL_X509_LOOKUP; return(-1); - * We then get retied later - */ - i = ssl_do_client_cert_cb(s, &x509, &pkey); - if (i < 0) { - s->internal->rwstate = SSL_X509_LOOKUP; - return (-1); - } - s->internal->rwstate = SSL_NOTHING; - if ((i == 1) && (pkey != NULL) && (x509 != NULL)) { - s->internal->state = SSL3_ST_CW_CERT_B; - if (!SSL_use_certificate(s, x509) || - !SSL_use_PrivateKey(s, pkey)) - i = 0; - } else if (i == 1) { - i = 0; - SSLerr(SSL_F_SSL3_SEND_CLIENT_CERTIFICATE, - SSL_R_BAD_DATA_RETURNED_BY_CALLBACK); - } - - X509_free(x509); - EVP_PKEY_free(pkey); - if (i == 0) - S3I(s)->tmp.cert_req = 2; - - /* Ok, we have a cert */ - s->internal->state = SSL3_ST_CW_CERT_C; - } - - if (s->internal->state == SSL3_ST_CW_CERT_C) { - if (!ssl3_handshake_msg_start_cbb(s, &cbb, &client_cert, - SSL3_MT_CERTIFICATE)) - goto err; - if (!ssl3_output_cert_chain(s, &client_cert, - (S3I(s)->tmp.cert_req == 2) ? NULL : s->cert->key->x509)) - goto err; - if (!ssl3_handshake_msg_finish_cbb(s, &cbb)) - goto err; - - s->internal->state = SSL3_ST_CW_CERT_D; - } - - /* SSL3_ST_CW_CERT_D */ - return (ssl3_do_write(s, SSL3_RT_HANDSHAKE)); - - err: - CBB_cleanup(&cbb); - - return (0); -} - -#define has_bits(i,m) (((i)&(m)) == (m)) - -int -ssl3_check_cert_and_algorithm(SSL *s) -{ - int i, idx; - long alg_k, alg_a; - EVP_PKEY *pkey = NULL; - SESS_CERT *sc; - DH *dh; - - alg_k = S3I(s)->tmp.new_cipher->algorithm_mkey; - alg_a = S3I(s)->tmp.new_cipher->algorithm_auth; - - /* We don't have a certificate. */ - if (alg_a & SSL_aNULL) - return (1); - - sc = SSI(s)->sess_cert; - if (sc == NULL) { - SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, - ERR_R_INTERNAL_ERROR); - goto err; - } - dh = SSI(s)->sess_cert->peer_dh_tmp; - - /* This is the passed certificate. */ - - idx = sc->peer_cert_type; - if (idx == SSL_PKEY_ECC) { - if (ssl_check_srvr_ecc_cert_and_alg( - sc->peer_pkeys[idx].x509, s) == 0) { - /* check failed */ - SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, - SSL_R_BAD_ECC_CERT); - goto f_err; - } else { - return (1); - } - } - pkey = X509_get_pubkey(sc->peer_pkeys[idx].x509); - i = X509_certificate_type(sc->peer_pkeys[idx].x509, pkey); - EVP_PKEY_free(pkey); - - /* Check that we have a certificate if we require one. */ - if ((alg_a & SSL_aRSA) && !has_bits(i, EVP_PK_RSA|EVP_PKT_SIGN)) { - SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, - SSL_R_MISSING_RSA_SIGNING_CERT); - goto f_err; - } else if ((alg_a & SSL_aDSS) && - !has_bits(i, EVP_PK_DSA|EVP_PKT_SIGN)) { - SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, - SSL_R_MISSING_DSA_SIGNING_CERT); - goto f_err; - } - if ((alg_k & SSL_kRSA) && - !has_bits(i, EVP_PK_RSA|EVP_PKT_ENC)) { - SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, - SSL_R_MISSING_RSA_ENCRYPTING_CERT); - goto f_err; - } - if ((alg_k & SSL_kDHE) && - !(has_bits(i, EVP_PK_DH|EVP_PKT_EXCH) || (dh != NULL))) { - SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, - SSL_R_MISSING_DH_KEY); - goto f_err; - } - - return (1); -f_err: - ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); -err: - return (0); -} - -int -ssl3_send_next_proto(SSL *s) -{ - unsigned int len, padding_len; - unsigned char *d, *p; - - if (s->internal->state == SSL3_ST_CW_NEXT_PROTO_A) { - d = p = ssl3_handshake_msg_start(s, SSL3_MT_NEXT_PROTO); - - len = s->internal->next_proto_negotiated_len; - padding_len = 32 - ((len + 2) % 32); - *(p++) = len; - memcpy(p, s->internal->next_proto_negotiated, len); - p += len; - *(p++) = padding_len; - memset(p, 0, padding_len); - p += padding_len; - - ssl3_handshake_msg_finish(s, p - d); - - s->internal->state = SSL3_ST_CW_NEXT_PROTO_B; - } - - return (ssl3_handshake_write(s)); -} - -/* - * Check to see if handshake is full or resumed. Usually this is just a - * case of checking to see if a cache hit has occurred. In the case of - * session tickets we have to check the next message to be sure. - */ - -int -ssl3_check_finished(SSL *s) -{ - int ok; - long n; - - /* If we have no ticket it cannot be a resumed session. */ - if (!s->session->tlsext_tick) - return (1); - /* this function is called when we really expect a Certificate - * message, so permit appropriate message length */ - n = s->method->internal->ssl_get_message(s, SSL3_ST_CR_CERT_A, - SSL3_ST_CR_CERT_B, -1, s->internal->max_cert_list, &ok); - if (!ok) - return ((int)n); - S3I(s)->tmp.reuse_message = 1; - if ((S3I(s)->tmp.message_type == SSL3_MT_FINISHED) || - (S3I(s)->tmp.message_type == SSL3_MT_NEWSESSION_TICKET)) - return (2); - - return (1); -} - -int -ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey) -{ - int i = 0; - -#ifndef OPENSSL_NO_ENGINE - if (s->ctx->internal->client_cert_engine) { - i = ENGINE_load_ssl_client_cert( - s->ctx->internal->client_cert_engine, s, - SSL_get_client_CA_list(s), px509, ppkey, NULL, NULL, NULL); - if (i != 0) - return (i); - } -#endif - if (s->ctx->internal->client_cert_cb) - i = s->ctx->internal->client_cert_cb(s, px509, ppkey); - return (i); -} diff --git a/src/lib/libssl/s3_pkt.c b/src/lib/libssl/s3_pkt.c deleted file mode 100644 index 5dadc0654e..0000000000 --- a/src/lib/libssl/s3_pkt.c +++ /dev/null @@ -1,1446 +0,0 @@ -/* $OpenBSD: s3_pkt.c,v 1.70 2017/01/26 05:31:25 jsing Exp $ */ -/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] - */ -/* ==================================================================== - * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" - * - * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * openssl-core@openssl.org. - * - * 5. Products derived from this software may not be called "OpenSSL" - * nor may "OpenSSL" appear in their names without prior written - * permission of the OpenSSL Project. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit (http://www.openssl.org/)" - * - * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This product includes cryptographic software written by Eric Young - * (eay@cryptsoft.com). This product includes software written by Tim - * Hudson (tjh@cryptsoft.com). - * - */ - -#include -#include - -#include "ssl_locl.h" - -#include -#include - -#include "bytestring.h" - -static int do_ssl3_write(SSL *s, int type, const unsigned char *buf, - unsigned int len, int create_empty_fragment); -static int ssl3_get_record(SSL *s); - -/* If extend == 0, obtain new n-byte packet; if extend == 1, increase - * packet by another n bytes. - * The packet will be in the sub-array of s->s3->rbuf.buf specified - * by s->internal->packet and s->internal->packet_length. - * (If s->internal->read_ahead is set, 'max' bytes may be stored in rbuf - * [plus s->internal->packet_length bytes if extend == 1].) - */ -static int -ssl3_read_n(SSL *s, int n, int max, int extend) -{ - int i, len, left; - size_t align; - unsigned char *pkt; - SSL3_BUFFER *rb; - - if (n <= 0) - return n; - - rb = &(s->s3->rbuf); - if (rb->buf == NULL) - if (!ssl3_setup_read_buffer(s)) - return -1; - - left = rb->left; - align = (size_t)rb->buf + SSL3_RT_HEADER_LENGTH; - align = (-align) & (SSL3_ALIGN_PAYLOAD - 1); - - if (!extend) { - /* start with empty packet ... */ - if (left == 0) - rb->offset = align; - else if (align != 0 && left >= SSL3_RT_HEADER_LENGTH) { - /* check if next packet length is large - * enough to justify payload alignment... */ - pkt = rb->buf + rb->offset; - if (pkt[0] == SSL3_RT_APPLICATION_DATA && - (pkt[3]<<8|pkt[4]) >= 128) { - /* Note that even if packet is corrupted - * and its length field is insane, we can - * only be led to wrong decision about - * whether memmove will occur or not. - * Header values has no effect on memmove - * arguments and therefore no buffer - * overrun can be triggered. */ - memmove(rb->buf + align, pkt, left); - rb->offset = align; - } - } - s->internal->packet = rb->buf + rb->offset; - s->internal->packet_length = 0; - /* ... now we can act as if 'extend' was set */ - } - - /* For DTLS/UDP reads should not span multiple packets - * because the read operation returns the whole packet - * at once (as long as it fits into the buffer). */ - if (SSL_IS_DTLS(s)) { - if (left > 0 && n > left) - n = left; - } - - /* if there is enough in the buffer from a previous read, take some */ - if (left >= n) { - s->internal->packet_length += n; - rb->left = left - n; - rb->offset += n; - return (n); - } - - /* else we need to read more data */ - - len = s->internal->packet_length; - pkt = rb->buf + align; - /* Move any available bytes to front of buffer: - * 'len' bytes already pointed to by 'packet', - * 'left' extra ones at the end */ - if (s->internal->packet != pkt) { - /* len > 0 */ - memmove(pkt, s->internal->packet, len + left); - s->internal->packet = pkt; - rb->offset = len + align; - } - - if (n > (int)(rb->len - rb->offset)) { - /* does not happen */ - SSLerr(SSL_F_SSL3_READ_N, ERR_R_INTERNAL_ERROR); - return -1; - } - - if (!s->internal->read_ahead) { - /* ignore max parameter */ - max = n; - } else { - if (max < n) - max = n; - if (max > (int)(rb->len - rb->offset)) - max = rb->len - rb->offset; - } - - while (left < n) { - /* Now we have len+left bytes at the front of s->s3->rbuf.buf - * and need to read in more until we have len+n (up to - * len+max if possible) */ - - errno = 0; - if (s->rbio != NULL) { - s->internal->rwstate = SSL_READING; - i = BIO_read(s->rbio, pkt + len + left, max - left); - } else { - SSLerr(SSL_F_SSL3_READ_N, SSL_R_READ_BIO_NOT_SET); - i = -1; - } - - if (i <= 0) { - rb->left = left; - if (s->internal->mode & SSL_MODE_RELEASE_BUFFERS && - !SSL_IS_DTLS(s)) { - if (len + left == 0) - ssl3_release_read_buffer(s); - } - return (i); - } - left += i; - - /* - * reads should *never* span multiple packets for DTLS because - * the underlying transport protocol is message oriented as - * opposed to byte oriented as in the TLS case. - */ - if (SSL_IS_DTLS(s)) { - if (n > left) - n = left; /* makes the while condition false */ - } - } - - /* done reading, now the book-keeping */ - rb->offset += n; - rb->left = left - n; - s->internal->packet_length += n; - s->internal->rwstate = SSL_NOTHING; - - return (n); -} - -int -ssl3_packet_read(SSL *s, int plen) -{ - int n; - - n = ssl3_read_n(s, plen, s->s3->rbuf.len, 0); - if (n <= 0) - return n; - if (s->internal->packet_length < plen) - return s->internal->packet_length; - - return plen; -} - -int -ssl3_packet_extend(SSL *s, int plen) -{ - int rlen, n; - - if (s->internal->packet_length >= plen) - return plen; - rlen = plen - s->internal->packet_length; - - n = ssl3_read_n(s, rlen, rlen, 1); - if (n <= 0) - return n; - if (s->internal->packet_length < plen) - return s->internal->packet_length; - - return plen; -} - -/* Call this to get a new input record. - * It will return <= 0 if more data is needed, normally due to an error - * or non-blocking IO. - * When it finishes, one packet has been decoded and can be found in - * ssl->s3->internal->rrec.type - is the type of record - * ssl->s3->internal->rrec.data, - data - * ssl->s3->internal->rrec.length, - number of bytes - */ -/* used only by ssl3_read_bytes */ -static int -ssl3_get_record(SSL *s) -{ - int al; - int enc_err, n, i, ret = -1; - SSL3_RECORD *rr; - SSL_SESSION *sess; - unsigned char md[EVP_MAX_MD_SIZE]; - unsigned mac_size, orig_len; - - rr = &(S3I(s)->rrec); - sess = s->session; - -again: - /* check if we have the header */ - if ((s->internal->rstate != SSL_ST_READ_BODY) || - (s->internal->packet_length < SSL3_RT_HEADER_LENGTH)) { - CBS header; - uint16_t len, ssl_version; - uint8_t type; - - n = ssl3_packet_read(s, SSL3_RT_HEADER_LENGTH); - if (n <= 0) - return (n); - - s->internal->mac_packet = 1; - s->internal->rstate = SSL_ST_READ_BODY; - - if (s->server && s->internal->first_packet) { - if ((ret = ssl_server_legacy_first_packet(s)) != 1) - return (ret); - ret = -1; - } - - CBS_init(&header, s->internal->packet, SSL3_RT_HEADER_LENGTH); - - /* Pull apart the header into the SSL3_RECORD */ - if (!CBS_get_u8(&header, &type) || - !CBS_get_u16(&header, &ssl_version) || - !CBS_get_u16(&header, &len)) { - SSLerr(SSL_F_SSL3_GET_RECORD, - SSL_R_BAD_PACKET_LENGTH); - goto err; - } - - rr->type = type; - rr->length = len; - - /* Lets check version */ - if (!s->internal->first_packet && ssl_version != s->version) { - SSLerr(SSL_F_SSL3_GET_RECORD, - SSL_R_WRONG_VERSION_NUMBER); - if ((s->version & 0xFF00) == (ssl_version & 0xFF00) && - !s->internal->enc_write_ctx && !s->internal->write_hash) - /* Send back error using their minor version number :-) */ - s->version = ssl_version; - al = SSL_AD_PROTOCOL_VERSION; - goto f_err; - } - - if ((ssl_version >> 8) != SSL3_VERSION_MAJOR) { - SSLerr(SSL_F_SSL3_GET_RECORD, - SSL_R_WRONG_VERSION_NUMBER); - goto err; - } - - if (rr->length > s->s3->rbuf.len - SSL3_RT_HEADER_LENGTH) { - al = SSL_AD_RECORD_OVERFLOW; - SSLerr(SSL_F_SSL3_GET_RECORD, - SSL_R_PACKET_LENGTH_TOO_LONG); - goto f_err; - } - - /* now s->internal->rstate == SSL_ST_READ_BODY */ - } - - /* s->internal->rstate == SSL_ST_READ_BODY, get and decode the data */ - - n = ssl3_packet_extend(s, SSL3_RT_HEADER_LENGTH + rr->length); - if (n <= 0) - return (n); - if (n != SSL3_RT_HEADER_LENGTH + rr->length) - return (n); - - s->internal->rstate = SSL_ST_READ_HEADER; /* set state for later operations */ - - /* At this point, s->internal->packet_length == SSL3_RT_HEADER_LNGTH + rr->length, - * and we have that many bytes in s->internal->packet - */ - rr->input = &(s->internal->packet[SSL3_RT_HEADER_LENGTH]); - - /* ok, we can now read from 's->internal->packet' data into 'rr' - * rr->input points at rr->length bytes, which - * need to be copied into rr->data by either - * the decryption or by the decompression - * When the data is 'copied' into the rr->data buffer, - * rr->input will be pointed at the new buffer */ - - /* We now have - encrypted [ MAC [ compressed [ plain ] ] ] - * rr->length bytes of encrypted compressed stuff. */ - - /* check is not needed I believe */ - if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH) { - al = SSL_AD_RECORD_OVERFLOW; - SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_ENCRYPTED_LENGTH_TOO_LONG); - goto f_err; - } - - /* decrypt in place in 'rr->input' */ - rr->data = rr->input; - - enc_err = s->method->internal->ssl3_enc->enc(s, 0); - /* enc_err is: - * 0: (in non-constant time) if the record is publically invalid. - * 1: if the padding is valid - * -1: if the padding is invalid */ - if (enc_err == 0) { - al = SSL_AD_DECRYPTION_FAILED; - SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_BLOCK_CIPHER_PAD_IS_WRONG); - goto f_err; - } - - - /* r->length is now the compressed data plus mac */ - if ((sess != NULL) && (s->enc_read_ctx != NULL) && - (EVP_MD_CTX_md(s->read_hash) != NULL)) { - /* s->read_hash != NULL => mac_size != -1 */ - unsigned char *mac = NULL; - unsigned char mac_tmp[EVP_MAX_MD_SIZE]; - - mac_size = EVP_MD_CTX_size(s->read_hash); - OPENSSL_assert(mac_size <= EVP_MAX_MD_SIZE); - - /* kludge: *_cbc_remove_padding passes padding length in rr->type */ - orig_len = rr->length + ((unsigned int)rr->type >> 8); - - /* orig_len is the length of the record before any padding was - * removed. This is public information, as is the MAC in use, - * therefore we can safely process the record in a different - * amount of time if it's too short to possibly contain a MAC. - */ - if (orig_len < mac_size || - /* CBC records must have a padding length byte too. */ - (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE && - orig_len < mac_size + 1)) { - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_LENGTH_TOO_SHORT); - goto f_err; - } - - if (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE) { - /* We update the length so that the TLS header bytes - * can be constructed correctly but we need to extract - * the MAC in constant time from within the record, - * without leaking the contents of the padding bytes. - * */ - mac = mac_tmp; - ssl3_cbc_copy_mac(mac_tmp, rr, mac_size, orig_len); - rr->length -= mac_size; - } else { - /* In this case there's no padding, so |orig_len| - * equals |rec->length| and we checked that there's - * enough bytes for |mac_size| above. */ - rr->length -= mac_size; - mac = &rr->data[rr->length]; - } - - i = s->method->internal->ssl3_enc->mac(s,md,0 /* not send */); - if (i < 0 || mac == NULL || - timingsafe_memcmp(md, mac, (size_t)mac_size) != 0) - enc_err = -1; - if (rr->length > - SSL3_RT_MAX_COMPRESSED_LENGTH + mac_size) - enc_err = -1; - } - - if (enc_err < 0) { - /* - * A separate 'decryption_failed' alert was introduced with - * TLS 1.0, SSL 3.0 only has 'bad_record_mac'. But unless a - * decryption failure is directly visible from the ciphertext - * anyway, we should not reveal which kind of error - * occurred -- this might become visible to an attacker - * (e.g. via a logfile) - */ - al = SSL_AD_BAD_RECORD_MAC; - SSLerr(SSL_F_SSL3_GET_RECORD, - SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC); - goto f_err; - } - - if (rr->length > SSL3_RT_MAX_PLAIN_LENGTH) { - al = SSL_AD_RECORD_OVERFLOW; - SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_DATA_LENGTH_TOO_LONG); - goto f_err; - } - - rr->off = 0; - /* - * So at this point the following is true - * - * ssl->s3->internal->rrec.type is the type of record - * ssl->s3->internal->rrec.length == number of bytes in record - * ssl->s3->internal->rrec.off == offset to first valid byte - * ssl->s3->internal->rrec.data == where to take bytes from, increment - * after use :-). - */ - - /* we have pulled in a full packet so zero things */ - s->internal->packet_length = 0; - - /* just read a 0 length packet */ - if (rr->length == 0) - goto again; - - return (1); - -f_err: - ssl3_send_alert(s, SSL3_AL_FATAL, al); -err: - return (ret); -} - -/* Call this to write data in records of type 'type' - * It will return <= 0 if not all data has been sent or non-blocking IO. - */ -int -ssl3_write_bytes(SSL *s, int type, const void *buf_, int len) -{ - const unsigned char *buf = buf_; - unsigned int tot, n, nw; - int i; - - if (len < 0) { - SSLerr(SSL_F_SSL3_WRITE_BYTES, ERR_R_INTERNAL_ERROR); - return -1; - } - - s->internal->rwstate = SSL_NOTHING; - tot = S3I(s)->wnum; - S3I(s)->wnum = 0; - - if (SSL_in_init(s) && !s->internal->in_handshake) { - i = s->internal->handshake_func(s); - if (i < 0) - return (i); - if (i == 0) { - SSLerr(SSL_F_SSL3_WRITE_BYTES, - SSL_R_SSL_HANDSHAKE_FAILURE); - return -1; - } - } - - if (len < tot) - len = tot; - n = (len - tot); - for (;;) { - if (n > s->max_send_fragment) - nw = s->max_send_fragment; - else - nw = n; - - i = do_ssl3_write(s, type, &(buf[tot]), nw, 0); - if (i <= 0) { - S3I(s)->wnum = tot; - return i; - } - - if ((i == (int)n) || (type == SSL3_RT_APPLICATION_DATA && - (s->internal->mode & SSL_MODE_ENABLE_PARTIAL_WRITE))) { - /* - * Next chunk of data should get another prepended - * empty fragment in ciphersuites with known-IV - * weakness. - */ - S3I(s)->empty_fragment_done = 0; - - return tot + i; - } - - n -= i; - tot += i; - } -} - -static int -do_ssl3_write(SSL *s, int type, const unsigned char *buf, - unsigned int len, int create_empty_fragment) -{ - unsigned char *p, *plen; - int i, mac_size, clear = 0; - int prefix_len = 0; - int eivlen; - size_t align; - SSL3_RECORD *wr; - SSL3_BUFFER *wb = &(s->s3->wbuf); - SSL_SESSION *sess; - - if (wb->buf == NULL) - if (!ssl3_setup_write_buffer(s)) - return -1; - - /* first check if there is a SSL3_BUFFER still being written - * out. This will happen with non blocking IO */ - if (wb->left != 0) - return (ssl3_write_pending(s, type, buf, len)); - - /* If we have an alert to send, lets send it */ - if (s->s3->alert_dispatch) { - i = s->method->ssl_dispatch_alert(s); - if (i <= 0) - return (i); - /* if it went, fall through and send more stuff */ - /* we may have released our buffer, so get it again */ - if (wb->buf == NULL) - if (!ssl3_setup_write_buffer(s)) - return -1; - } - - if (len == 0 && !create_empty_fragment) - return 0; - - wr = &(S3I(s)->wrec); - sess = s->session; - - if ((sess == NULL) || (s->internal->enc_write_ctx == NULL) || - (EVP_MD_CTX_md(s->internal->write_hash) == NULL)) { - clear = s->internal->enc_write_ctx ? 0 : 1; /* must be AEAD cipher */ - mac_size = 0; - } else { - mac_size = EVP_MD_CTX_size(s->internal->write_hash); - if (mac_size < 0) - goto err; - } - - /* - * 'create_empty_fragment' is true only when this function calls - * itself. - */ - if (!clear && !create_empty_fragment && !S3I(s)->empty_fragment_done) { - /* - * Countermeasure against known-IV weakness in CBC ciphersuites - * (see http://www.openssl.org/~bodo/tls-cbc.txt) - */ - if (S3I(s)->need_empty_fragments && - type == SSL3_RT_APPLICATION_DATA) { - /* recursive function call with 'create_empty_fragment' set; - * this prepares and buffers the data for an empty fragment - * (these 'prefix_len' bytes are sent out later - * together with the actual payload) */ - prefix_len = do_ssl3_write(s, type, buf, 0, 1); - if (prefix_len <= 0) - goto err; - - if (prefix_len > - (SSL3_RT_HEADER_LENGTH + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD)) { - /* insufficient space */ - SSLerr(SSL_F_DO_SSL3_WRITE, - ERR_R_INTERNAL_ERROR); - goto err; - } - } - - S3I(s)->empty_fragment_done = 1; - } - - if (create_empty_fragment) { - /* extra fragment would be couple of cipher blocks, - * which would be multiple of SSL3_ALIGN_PAYLOAD, so - * if we want to align the real payload, then we can - * just pretent we simply have two headers. */ - align = (size_t)wb->buf + 2 * SSL3_RT_HEADER_LENGTH; - align = (-align) & (SSL3_ALIGN_PAYLOAD - 1); - - p = wb->buf + align; - wb->offset = align; - } else if (prefix_len) { - p = wb->buf + wb->offset + prefix_len; - } else { - align = (size_t)wb->buf + SSL3_RT_HEADER_LENGTH; - align = (-align) & (SSL3_ALIGN_PAYLOAD - 1); - - p = wb->buf + align; - wb->offset = align; - } - - /* write the header */ - - *(p++) = type&0xff; - wr->type = type; - - *(p++) = (s->version >> 8); - /* Some servers hang if iniatial client hello is larger than 256 - * bytes and record version number > TLS 1.0 - */ - if (s->internal->state == SSL3_ST_CW_CLNT_HELLO_B && !s->internal->renegotiate && - TLS1_get_version(s) > TLS1_VERSION) - *(p++) = 0x1; - else - *(p++) = s->version&0xff; - - /* field where we are to write out packet length */ - plen = p; - p += 2; - - /* Explicit IV length. */ - if (s->internal->enc_write_ctx && SSL_USE_EXPLICIT_IV(s)) { - int mode = EVP_CIPHER_CTX_mode(s->internal->enc_write_ctx); - if (mode == EVP_CIPH_CBC_MODE) { - eivlen = EVP_CIPHER_CTX_iv_length(s->internal->enc_write_ctx); - if (eivlen <= 1) - eivlen = 0; - } - /* Need explicit part of IV for GCM mode */ - else if (mode == EVP_CIPH_GCM_MODE) - eivlen = EVP_GCM_TLS_EXPLICIT_IV_LEN; - else - eivlen = 0; - } else if (s->internal->aead_write_ctx != NULL && - s->internal->aead_write_ctx->variable_nonce_in_record) { - eivlen = s->internal->aead_write_ctx->variable_nonce_len; - } else - eivlen = 0; - - /* lets setup the record stuff. */ - wr->data = p + eivlen; - wr->length = (int)len; - wr->input = (unsigned char *)buf; - - /* we now 'read' from wr->input, wr->length bytes into wr->data */ - - memcpy(wr->data, wr->input, wr->length); - wr->input = wr->data; - - /* we should still have the output to wr->data and the input - * from wr->input. Length should be wr->length. - * wr->data still points in the wb->buf */ - - if (mac_size != 0) { - if (s->method->internal->ssl3_enc->mac(s, - &(p[wr->length + eivlen]), 1) < 0) - goto err; - wr->length += mac_size; - } - - wr->input = p; - wr->data = p; - - if (eivlen) { - /* if (RAND_pseudo_bytes(p, eivlen) <= 0) - goto err; - */ - wr->length += eivlen; - } - - /* ssl3_enc can only have an error on read */ - s->method->internal->ssl3_enc->enc(s, 1); - - /* record length after mac and block padding */ - s2n(wr->length, plen); - - /* we should now have - * wr->data pointing to the encrypted data, which is - * wr->length long */ - wr->type=type; /* not needed but helps for debugging */ - wr->length += SSL3_RT_HEADER_LENGTH; - - if (create_empty_fragment) { - /* we are in a recursive call; - * just return the length, don't write out anything here - */ - return wr->length; - } - - /* now let's set up wb */ - wb->left = prefix_len + wr->length; - - /* memorize arguments so that ssl3_write_pending can detect - * bad write retries later */ - S3I(s)->wpend_tot = len; - S3I(s)->wpend_buf = buf; - S3I(s)->wpend_type = type; - S3I(s)->wpend_ret = len; - - /* we now just need to write the buffer */ - return ssl3_write_pending(s, type, buf, len); -err: - return -1; -} - -/* if s->s3->wbuf.left != 0, we need to call this */ -int -ssl3_write_pending(SSL *s, int type, const unsigned char *buf, unsigned int len) -{ - int i; - SSL3_BUFFER *wb = &(s->s3->wbuf); - - /* XXXX */ - if ((S3I(s)->wpend_tot > (int)len) || ((S3I(s)->wpend_buf != buf) && - !(s->internal->mode & SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER)) || - (S3I(s)->wpend_type != type)) { - SSLerr(SSL_F_SSL3_WRITE_PENDING, SSL_R_BAD_WRITE_RETRY); - return (-1); - } - - for (;;) { - errno = 0; - if (s->wbio != NULL) { - s->internal->rwstate = SSL_WRITING; - i = BIO_write(s->wbio, - (char *)&(wb->buf[wb->offset]), - (unsigned int)wb->left); - } else { - SSLerr(SSL_F_SSL3_WRITE_PENDING, SSL_R_BIO_NOT_SET); - i = -1; - } - if (i == wb->left) { - wb->left = 0; - wb->offset += i; - if (s->internal->mode & SSL_MODE_RELEASE_BUFFERS && - !SSL_IS_DTLS(s)) - ssl3_release_write_buffer(s); - s->internal->rwstate = SSL_NOTHING; - return (S3I(s)->wpend_ret); - } else if (i <= 0) { - /* - * For DTLS, just drop it. That's kind of the - * whole point in using a datagram service. - */ - if (SSL_IS_DTLS(s)) - wb->left = 0; - return (i); - } - wb->offset += i; - wb->left -= i; - } -} - -/* Return up to 'len' payload bytes received in 'type' records. - * 'type' is one of the following: - * - * - SSL3_RT_HANDSHAKE (when ssl3_get_message calls us) - * - SSL3_RT_APPLICATION_DATA (when ssl3_read calls us) - * - 0 (during a shutdown, no data has to be returned) - * - * If we don't have stored data to work from, read a SSL/TLS record first - * (possibly multiple records if we still don't have anything to return). - * - * This function must handle any surprises the peer may have for us, such as - * Alert records (e.g. close_notify), ChangeCipherSpec records (not really - * a surprise, but handled as if it were), or renegotiation requests. - * Also if record payloads contain fragments too small to process, we store - * them until there is enough for the respective protocol (the record protocol - * may use arbitrary fragmentation and even interleaving): - * Change cipher spec protocol - * just 1 byte needed, no need for keeping anything stored - * Alert protocol - * 2 bytes needed (AlertLevel, AlertDescription) - * Handshake protocol - * 4 bytes needed (HandshakeType, uint24 length) -- we just have - * to detect unexpected Client Hello and Hello Request messages - * here, anything else is handled by higher layers - * Application data protocol - * none of our business - */ -int -ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek) -{ - void (*cb)(const SSL *ssl, int type2, int val) = NULL; - int al, i, j, ret, rrcount = 0; - unsigned int n; - SSL3_RECORD *rr; - BIO *bio; - - if (s->s3->rbuf.buf == NULL) /* Not initialized yet */ - if (!ssl3_setup_read_buffer(s)) - return (-1); - - if (len < 0) { - SSLerr(SSL_F_SSL3_READ_BYTES, ERR_R_INTERNAL_ERROR); - return -1; - } - - if ((type && type != SSL3_RT_APPLICATION_DATA && - type != SSL3_RT_HANDSHAKE) || - (peek && (type != SSL3_RT_APPLICATION_DATA))) { - SSLerr(SSL_F_SSL3_READ_BYTES, ERR_R_INTERNAL_ERROR); - return -1; - } - - if ((type == SSL3_RT_HANDSHAKE) && - (S3I(s)->handshake_fragment_len > 0)) { - /* (partially) satisfy request from storage */ - unsigned char *src = S3I(s)->handshake_fragment; - unsigned char *dst = buf; - unsigned int k; - - /* peek == 0 */ - n = 0; - while ((len > 0) && (S3I(s)->handshake_fragment_len > 0)) { - *dst++ = *src++; - len--; - S3I(s)->handshake_fragment_len--; - n++; - } - /* move any remaining fragment bytes: */ - for (k = 0; k < S3I(s)->handshake_fragment_len; k++) - S3I(s)->handshake_fragment[k] = *src++; - return n; - } - - /* - * Now S3I(s)->handshake_fragment_len == 0 if - * type == SSL3_RT_HANDSHAKE. - */ - if (!s->internal->in_handshake && SSL_in_init(s)) { - /* type == SSL3_RT_APPLICATION_DATA */ - i = s->internal->handshake_func(s); - if (i < 0) - return (i); - if (i == 0) { - SSLerr(SSL_F_SSL3_READ_BYTES, - SSL_R_SSL_HANDSHAKE_FAILURE); - return (-1); - } - } - -start: - /* - * Do not process more than three consecutive records, otherwise the - * peer can cause us to loop indefinitely. Instead, return with an - * SSL_ERROR_WANT_READ so the caller can choose when to handle further - * processing. In the future, the total number of non-handshake and - * non-application data records per connection should probably also be - * limited... - */ - if (rrcount++ >= 3) { - if ((bio = SSL_get_rbio(s)) == NULL) { - SSLerr(SSL_F_SSL3_READ_BYTES, ERR_R_INTERNAL_ERROR); - return -1; - } - BIO_clear_retry_flags(bio); - BIO_set_retry_read(bio); - s->internal->rwstate = SSL_READING; - return -1; - } - - s->internal->rwstate = SSL_NOTHING; - - /* - * S3I(s)->rrec.type - is the type of record - * S3I(s)->rrec.data, - data - * S3I(s)->rrec.off, - offset into 'data' for next read - * S3I(s)->rrec.length, - number of bytes. - */ - rr = &(S3I(s)->rrec); - - /* get new packet if necessary */ - if ((rr->length == 0) || (s->internal->rstate == SSL_ST_READ_BODY)) { - ret = ssl3_get_record(s); - if (ret <= 0) - return (ret); - } - - /* we now have a packet which can be read and processed */ - - if (S3I(s)->change_cipher_spec /* set when we receive ChangeCipherSpec, - * reset by ssl3_get_finished */ - && (rr->type != SSL3_RT_HANDSHAKE)) { - al = SSL_AD_UNEXPECTED_MESSAGE; - SSLerr(SSL_F_SSL3_READ_BYTES, - SSL_R_DATA_BETWEEN_CCS_AND_FINISHED); - goto f_err; - } - - /* If the other end has shut down, throw anything we read away - * (even in 'peek' mode) */ - if (s->internal->shutdown & SSL_RECEIVED_SHUTDOWN) { - rr->length = 0; - s->internal->rwstate = SSL_NOTHING; - return (0); - } - - - /* SSL3_RT_APPLICATION_DATA or SSL3_RT_HANDSHAKE */ - if (type == rr->type) { - /* make sure that we are not getting application data when we - * are doing a handshake for the first time */ - if (SSL_in_init(s) && (type == SSL3_RT_APPLICATION_DATA) && - (s->enc_read_ctx == NULL)) { - al = SSL_AD_UNEXPECTED_MESSAGE; - SSLerr(SSL_F_SSL3_READ_BYTES, - SSL_R_APP_DATA_IN_HANDSHAKE); - goto f_err; - } - - if (len <= 0) - return (len); - - if ((unsigned int)len > rr->length) - n = rr->length; - else - n = (unsigned int)len; - - memcpy(buf, &(rr->data[rr->off]), n); - if (!peek) { - memset(&(rr->data[rr->off]), 0, n); - rr->length -= n; - rr->off += n; - if (rr->length == 0) { - s->internal->rstate = SSL_ST_READ_HEADER; - rr->off = 0; - if (s->internal->mode & SSL_MODE_RELEASE_BUFFERS && - s->s3->rbuf.left == 0) - ssl3_release_read_buffer(s); - } - } - return (n); - } - - - /* If we get here, then type != rr->type; if we have a handshake - * message, then it was unexpected (Hello Request or Client Hello). */ - - { - /* - * In case of record types for which we have 'fragment' - * storage, * fill that so that we can process the data - * at a fixed place. - */ - unsigned int dest_maxlen = 0; - unsigned char *dest = NULL; - unsigned int *dest_len = NULL; - - if (rr->type == SSL3_RT_HANDSHAKE) { - dest_maxlen = sizeof S3I(s)->handshake_fragment; - dest = S3I(s)->handshake_fragment; - dest_len = &S3I(s)->handshake_fragment_len; - } else if (rr->type == SSL3_RT_ALERT) { - dest_maxlen = sizeof S3I(s)->alert_fragment; - dest = S3I(s)->alert_fragment; - dest_len = &S3I(s)->alert_fragment_len; - } - if (dest_maxlen > 0) { - /* available space in 'dest' */ - n = dest_maxlen - *dest_len; - if (rr->length < n) - n = rr->length; /* available bytes */ - - /* now move 'n' bytes: */ - while (n-- > 0) { - dest[(*dest_len)++] = rr->data[rr->off++]; - rr->length--; - } - - if (*dest_len < dest_maxlen) - goto start; /* fragment was too small */ - } - } - - /* S3I(s)->handshake_fragment_len == 4 iff rr->type == SSL3_RT_HANDSHAKE; - * S3I(s)->alert_fragment_len == 2 iff rr->type == SSL3_RT_ALERT. - * (Possibly rr is 'empty' now, i.e. rr->length may be 0.) */ - - /* If we are a client, check for an incoming 'Hello Request': */ - if ((!s->server) && (S3I(s)->handshake_fragment_len >= 4) && - (S3I(s)->handshake_fragment[0] == SSL3_MT_HELLO_REQUEST) && - (s->session != NULL) && (s->session->cipher != NULL)) { - S3I(s)->handshake_fragment_len = 0; - - if ((S3I(s)->handshake_fragment[1] != 0) || - (S3I(s)->handshake_fragment[2] != 0) || - (S3I(s)->handshake_fragment[3] != 0)) { - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_BAD_HELLO_REQUEST); - goto f_err; - } - - if (s->internal->msg_callback) - s->internal->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, - S3I(s)->handshake_fragment, 4, s, - s->internal->msg_callback_arg); - - if (SSL_is_init_finished(s) && - !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) && - !S3I(s)->renegotiate) { - ssl3_renegotiate(s); - if (ssl3_renegotiate_check(s)) { - i = s->internal->handshake_func(s); - if (i < 0) - return (i); - if (i == 0) { - SSLerr(SSL_F_SSL3_READ_BYTES, - SSL_R_SSL_HANDSHAKE_FAILURE); - return (-1); - } - - if (!(s->internal->mode & SSL_MODE_AUTO_RETRY)) { - if (s->s3->rbuf.left == 0) { - /* no read-ahead left? */ - /* In the case where we try to read application data, - * but we trigger an SSL handshake, we return -1 with - * the retry option set. Otherwise renegotiation may - * cause nasty problems in the blocking world */ - s->internal->rwstate = SSL_READING; - bio = SSL_get_rbio(s); - BIO_clear_retry_flags(bio); - BIO_set_retry_read(bio); - return (-1); - } - } - } - } - /* we either finished a handshake or ignored the request, - * now try again to obtain the (application) data we were asked for */ - goto start; - } - /* If we are a server and get a client hello when renegotiation isn't - * allowed send back a no renegotiation alert and carry on. - * WARNING: experimental code, needs reviewing (steve) - */ - if (s->server && - SSL_is_init_finished(s) && - !S3I(s)->send_connection_binding && - (S3I(s)->handshake_fragment_len >= 4) && - (S3I(s)->handshake_fragment[0] == SSL3_MT_CLIENT_HELLO) && - (s->session != NULL) && (s->session->cipher != NULL)) { - /*S3I(s)->handshake_fragment_len = 0;*/ - rr->length = 0; - ssl3_send_alert(s, SSL3_AL_WARNING, SSL_AD_NO_RENEGOTIATION); - goto start; - } - if (S3I(s)->alert_fragment_len >= 2) { - int alert_level = S3I(s)->alert_fragment[0]; - int alert_descr = S3I(s)->alert_fragment[1]; - - S3I(s)->alert_fragment_len = 0; - - if (s->internal->msg_callback) - s->internal->msg_callback(0, s->version, SSL3_RT_ALERT, - S3I(s)->alert_fragment, 2, s, s->internal->msg_callback_arg); - - if (s->internal->info_callback != NULL) - cb = s->internal->info_callback; - else if (s->ctx->internal->info_callback != NULL) - cb = s->ctx->internal->info_callback; - - if (cb != NULL) { - j = (alert_level << 8) | alert_descr; - cb(s, SSL_CB_READ_ALERT, j); - } - - if (alert_level == SSL3_AL_WARNING) { - S3I(s)->warn_alert = alert_descr; - if (alert_descr == SSL_AD_CLOSE_NOTIFY) { - s->internal->shutdown |= SSL_RECEIVED_SHUTDOWN; - return (0); - } - /* This is a warning but we receive it if we requested - * renegotiation and the peer denied it. Terminate with - * a fatal alert because if application tried to - * renegotiatie it presumably had a good reason and - * expects it to succeed. - * - * In future we might have a renegotiation where we - * don't care if the peer refused it where we carry on. - */ - else if (alert_descr == SSL_AD_NO_RENEGOTIATION) { - al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_SSL3_READ_BYTES, - SSL_R_NO_RENEGOTIATION); - goto f_err; - } - } else if (alert_level == SSL3_AL_FATAL) { - s->internal->rwstate = SSL_NOTHING; - S3I(s)->fatal_alert = alert_descr; - SSLerr(SSL_F_SSL3_READ_BYTES, - SSL_AD_REASON_OFFSET + alert_descr); - ERR_asprintf_error_data("SSL alert number %d", - alert_descr); - s->internal->shutdown |= SSL_RECEIVED_SHUTDOWN; - SSL_CTX_remove_session(s->ctx, s->session); - return (0); - } else { - al = SSL_AD_ILLEGAL_PARAMETER; - SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_UNKNOWN_ALERT_TYPE); - goto f_err; - } - - goto start; - } - - if (s->internal->shutdown & SSL_SENT_SHUTDOWN) { - /* but we have not received a shutdown */ - s->internal->rwstate = SSL_NOTHING; - rr->length = 0; - return (0); - } - - if (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC) { - /* 'Change Cipher Spec' is just a single byte, so we know - * exactly what the record payload has to look like */ - if ((rr->length != 1) || (rr->off != 0) || - (rr->data[0] != SSL3_MT_CCS)) { - al = SSL_AD_ILLEGAL_PARAMETER; - SSLerr(SSL_F_SSL3_READ_BYTES, - SSL_R_BAD_CHANGE_CIPHER_SPEC); - goto f_err; - } - - /* Check we have a cipher to change to */ - if (S3I(s)->tmp.new_cipher == NULL) { - al = SSL_AD_UNEXPECTED_MESSAGE; - SSLerr(SSL_F_SSL3_READ_BYTES, - SSL_R_CCS_RECEIVED_EARLY); - goto f_err; - } - - /* Check that we should be receiving a Change Cipher Spec. */ - if (!(s->s3->flags & SSL3_FLAGS_CCS_OK)) { - al = SSL_AD_UNEXPECTED_MESSAGE; - SSLerr(SSL_F_SSL3_READ_BYTES, - SSL_R_CCS_RECEIVED_EARLY); - goto f_err; - } - s->s3->flags &= ~SSL3_FLAGS_CCS_OK; - - rr->length = 0; - - if (s->internal->msg_callback) { - s->internal->msg_callback(0, s->version, - SSL3_RT_CHANGE_CIPHER_SPEC, rr->data, 1, s, - s->internal->msg_callback_arg); - } - - S3I(s)->change_cipher_spec = 1; - if (!ssl3_do_change_cipher_spec(s)) - goto err; - else - goto start; - } - - /* Unexpected handshake message (Client Hello, or protocol violation) */ - if ((S3I(s)->handshake_fragment_len >= 4) && !s->internal->in_handshake) { - if (((s->internal->state&SSL_ST_MASK) == SSL_ST_OK) && - !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS)) { - s->internal->state = s->server ? SSL_ST_ACCEPT : SSL_ST_CONNECT; - s->internal->renegotiate = 1; - s->internal->new_session = 1; - } - i = s->internal->handshake_func(s); - if (i < 0) - return (i); - if (i == 0) { - SSLerr(SSL_F_SSL3_READ_BYTES, - SSL_R_SSL_HANDSHAKE_FAILURE); - return (-1); - } - - if (!(s->internal->mode & SSL_MODE_AUTO_RETRY)) { - if (s->s3->rbuf.left == 0) { /* no read-ahead left? */ - BIO *bio; - /* In the case where we try to read application data, - * but we trigger an SSL handshake, we return -1 with - * the retry option set. Otherwise renegotiation may - * cause nasty problems in the blocking world */ - s->internal->rwstate = SSL_READING; - bio = SSL_get_rbio(s); - BIO_clear_retry_flags(bio); - BIO_set_retry_read(bio); - return (-1); - } - } - goto start; - } - - switch (rr->type) { - default: - /* - * TLS up to v1.1 just ignores unknown message types: - * TLS v1.2 give an unexpected message alert. - */ - if (s->version >= TLS1_VERSION && - s->version <= TLS1_1_VERSION) { - rr->length = 0; - goto start; - } - al = SSL_AD_UNEXPECTED_MESSAGE; - SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_UNEXPECTED_RECORD); - goto f_err; - case SSL3_RT_CHANGE_CIPHER_SPEC: - case SSL3_RT_ALERT: - case SSL3_RT_HANDSHAKE: - /* we already handled all of these, with the possible exception - * of SSL3_RT_HANDSHAKE when s->internal->in_handshake is set, but that - * should not happen when type != rr->type */ - al = SSL_AD_UNEXPECTED_MESSAGE; - SSLerr(SSL_F_SSL3_READ_BYTES, ERR_R_INTERNAL_ERROR); - goto f_err; - case SSL3_RT_APPLICATION_DATA: - /* At this point, we were expecting handshake data, - * but have application data. If the library was - * running inside ssl3_read() (i.e. in_read_app_data - * is set) and it makes sense to read application data - * at this point (session renegotiation not yet started), - * we will indulge it. - */ - if (S3I(s)->in_read_app_data && - (S3I(s)->total_renegotiations != 0) && - (((s->internal->state & SSL_ST_CONNECT) && - (s->internal->state >= SSL3_ST_CW_CLNT_HELLO_A) && - (s->internal->state <= SSL3_ST_CR_SRVR_HELLO_A)) || - ((s->internal->state & SSL_ST_ACCEPT) && - (s->internal->state <= SSL3_ST_SW_HELLO_REQ_A) && - (s->internal->state >= SSL3_ST_SR_CLNT_HELLO_A)))) { - S3I(s)->in_read_app_data = 2; - return (-1); - } else { - al = SSL_AD_UNEXPECTED_MESSAGE; - SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_UNEXPECTED_RECORD); - goto f_err; - } - } - /* not reached */ - -f_err: - ssl3_send_alert(s, SSL3_AL_FATAL, al); -err: - return (-1); -} - -int -ssl3_do_change_cipher_spec(SSL *s) -{ - int i; - const char *sender; - int slen; - - if (s->internal->state & SSL_ST_ACCEPT) - i = SSL3_CHANGE_CIPHER_SERVER_READ; - else - i = SSL3_CHANGE_CIPHER_CLIENT_READ; - - if (S3I(s)->tmp.key_block == NULL) { - if (s->session == NULL || s->session->master_key_length == 0) { - /* might happen if dtls1_read_bytes() calls this */ - SSLerr(SSL_F_SSL3_DO_CHANGE_CIPHER_SPEC, - SSL_R_CCS_RECEIVED_EARLY); - return (0); - } - - s->session->cipher = S3I(s)->tmp.new_cipher; - if (!s->method->internal->ssl3_enc->setup_key_block(s)) - return (0); - } - - if (!s->method->internal->ssl3_enc->change_cipher_state(s, i)) - return (0); - - /* we have to record the message digest at - * this point so we can get it before we read - * the finished message */ - if (s->internal->state & SSL_ST_CONNECT) { - sender = s->method->internal->ssl3_enc->server_finished_label; - slen = s->method->internal->ssl3_enc->server_finished_label_len; - } else { - sender = s->method->internal->ssl3_enc->client_finished_label; - slen = s->method->internal->ssl3_enc->client_finished_label_len; - } - - i = s->method->internal->ssl3_enc->final_finish_mac(s, sender, slen, - S3I(s)->tmp.peer_finish_md); - if (i == 0) { - SSLerr(SSL_F_SSL3_DO_CHANGE_CIPHER_SPEC, ERR_R_INTERNAL_ERROR); - return 0; - } - S3I(s)->tmp.peer_finish_md_len = i; - - return (1); -} - -int -ssl3_send_alert(SSL *s, int level, int desc) -{ - /* Map tls/ssl alert value to correct one */ - desc = s->method->internal->ssl3_enc->alert_value(desc); - if (desc < 0) - return -1; - /* If a fatal one, remove from cache */ - if ((level == 2) && (s->session != NULL)) - SSL_CTX_remove_session(s->ctx, s->session); - - s->s3->alert_dispatch = 1; - s->s3->send_alert[0] = level; - s->s3->send_alert[1] = desc; - if (s->s3->wbuf.left == 0) /* data still being written out? */ - return s->method->ssl_dispatch_alert(s); - - /* else data is still being written out, we will get written - * some time in the future */ - return -1; -} - -int -ssl3_dispatch_alert(SSL *s) -{ - int i, j; - void (*cb)(const SSL *ssl, int type, int val) = NULL; - - s->s3->alert_dispatch = 0; - i = do_ssl3_write(s, SSL3_RT_ALERT, &s->s3->send_alert[0], 2, 0); - if (i <= 0) { - s->s3->alert_dispatch = 1; - } else { - /* Alert sent to BIO. If it is important, flush it now. - * If the message does not get sent due to non-blocking IO, - * we will not worry too much. */ - if (s->s3->send_alert[0] == SSL3_AL_FATAL) - (void)BIO_flush(s->wbio); - - if (s->internal->msg_callback) - s->internal->msg_callback(1, s->version, SSL3_RT_ALERT, - s->s3->send_alert, 2, s, s->internal->msg_callback_arg); - - if (s->internal->info_callback != NULL) - cb = s->internal->info_callback; - else if (s->ctx->internal->info_callback != NULL) - cb = s->ctx->internal->info_callback; - - if (cb != NULL) { - j = (s->s3->send_alert[0]<<8)|s->s3->send_alert[1]; - cb(s, SSL_CB_WRITE_ALERT, j); - } - } - return (i); -} diff --git a/src/lib/libssl/s3_srvr.c b/src/lib/libssl/s3_srvr.c deleted file mode 100644 index 28f0fc486a..0000000000 --- a/src/lib/libssl/s3_srvr.c +++ /dev/null @@ -1,2923 +0,0 @@ -/* $OpenBSD: s3_srvr.c,v 1.154 2017/01/26 05:31:25 jsing Exp $ */ -/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] - */ -/* ==================================================================== - * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" - * - * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * openssl-core@openssl.org. - * - * 5. Products derived from this software may not be called "OpenSSL" - * nor may "OpenSSL" appear in their names without prior written - * permission of the OpenSSL Project. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit (http://www.openssl.org/)" - * - * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This product includes cryptographic software written by Eric Young - * (eay@cryptsoft.com). This product includes software written by Tim - * Hudson (tjh@cryptsoft.com). - * - */ -/* ==================================================================== - * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. - * - * Portions of the attached software ("Contribution") are developed by - * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. - * - * The Contribution is licensed pursuant to the OpenSSL open source - * license provided above. - * - * ECC cipher suite support in OpenSSL originally written by - * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories. - * - */ -/* ==================================================================== - * Copyright 2005 Nokia. All rights reserved. - * - * The portions of the attached software ("Contribution") is developed by - * Nokia Corporation and is licensed pursuant to the OpenSSL open source - * license. - * - * The Contribution, originally written by Mika Kousa and Pasi Eronen of - * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites - * support (see RFC 4279) to OpenSSL. - * - * No patent licenses or other rights except those expressly stated in - * the OpenSSL open source license shall be deemed granted or received - * expressly, by implication, estoppel, or otherwise. - * - * No assurances are provided by Nokia that the Contribution does not - * infringe the patent or other intellectual property rights of any third - * party or that the license provides you with all the necessary rights - * to make use of the Contribution. - * - * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN - * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA - * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY - * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR - * OTHERWISE. - */ - -#include - -#include "ssl_locl.h" - -#include -#include -#include -#include -#include -#ifndef OPENSSL_NO_GOST -#include -#endif -#include -#include -#include -#include - -#include "bytestring.h" - -int -ssl3_accept(SSL *s) -{ - unsigned long alg_k; - void (*cb)(const SSL *ssl, int type, int val) = NULL; - int ret = -1; - int new_state, state, skip = 0; - - ERR_clear_error(); - errno = 0; - - if (s->internal->info_callback != NULL) - cb = s->internal->info_callback; - else if (s->ctx->internal->info_callback != NULL) - cb = s->ctx->internal->info_callback; - - /* init things to blank */ - s->internal->in_handshake++; - if (!SSL_in_init(s) || SSL_in_before(s)) - SSL_clear(s); - - if (s->cert == NULL) { - SSLerr(SSL_F_SSL3_ACCEPT, SSL_R_NO_CERTIFICATE_SET); - ret = -1; - goto end; - } - - for (;;) { - state = s->internal->state; - - switch (s->internal->state) { - case SSL_ST_RENEGOTIATE: - s->internal->renegotiate = 1; - /* s->internal->state=SSL_ST_ACCEPT; */ - - case SSL_ST_BEFORE: - case SSL_ST_ACCEPT: - case SSL_ST_BEFORE|SSL_ST_ACCEPT: - case SSL_ST_OK|SSL_ST_ACCEPT: - - s->server = 1; - if (cb != NULL) - cb(s, SSL_CB_HANDSHAKE_START, 1); - - if ((s->version >> 8) != 3) { - SSLerr(SSL_F_SSL3_ACCEPT, ERR_R_INTERNAL_ERROR); - ret = -1; - goto end; - } - s->internal->type = SSL_ST_ACCEPT; - - if (!ssl3_setup_init_buffer(s)) { - ret = -1; - goto end; - } - if (!ssl3_setup_buffers(s)) { - ret = -1; - goto end; - } - - s->internal->init_num = 0; - - if (s->internal->state != SSL_ST_RENEGOTIATE) { - /* - * Ok, we now need to push on a buffering BIO - * so that the output is sent in a way that - * TCP likes :-) - */ - if (!ssl_init_wbio_buffer(s, 1)) { - ret = -1; - goto end; - } - - if (!tls1_init_finished_mac(s)) { - ret = -1; - goto end; - } - - s->internal->state = SSL3_ST_SR_CLNT_HELLO_A; - s->ctx->internal->stats.sess_accept++; - } else if (!S3I(s)->send_connection_binding) { - /* - * Server attempting to renegotiate with - * client that doesn't support secure - * renegotiation. - */ - SSLerr(SSL_F_SSL3_ACCEPT, - SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED); - ssl3_send_alert(s, SSL3_AL_FATAL, - SSL_AD_HANDSHAKE_FAILURE); - ret = -1; - goto end; - } else { - /* - * s->internal->state == SSL_ST_RENEGOTIATE, - * we will just send a HelloRequest - */ - s->ctx->internal->stats.sess_accept_renegotiate++; - s->internal->state = SSL3_ST_SW_HELLO_REQ_A; - } - break; - - case SSL3_ST_SW_HELLO_REQ_A: - case SSL3_ST_SW_HELLO_REQ_B: - - s->internal->shutdown = 0; - ret = ssl3_send_hello_request(s); - if (ret <= 0) - goto end; - S3I(s)->tmp.next_state = SSL3_ST_SW_HELLO_REQ_C; - s->internal->state = SSL3_ST_SW_FLUSH; - s->internal->init_num = 0; - - if (!tls1_init_finished_mac(s)) { - ret = -1; - goto end; - } - break; - - case SSL3_ST_SW_HELLO_REQ_C: - s->internal->state = SSL_ST_OK; - break; - - case SSL3_ST_SR_CLNT_HELLO_A: - case SSL3_ST_SR_CLNT_HELLO_B: - case SSL3_ST_SR_CLNT_HELLO_C: - - s->internal->shutdown = 0; - if (s->internal->rwstate != SSL_X509_LOOKUP) { - ret = ssl3_get_client_hello(s); - if (ret <= 0) - goto end; - } - - s->internal->renegotiate = 2; - s->internal->state = SSL3_ST_SW_SRVR_HELLO_A; - s->internal->init_num = 0; - break; - - case SSL3_ST_SW_SRVR_HELLO_A: - case SSL3_ST_SW_SRVR_HELLO_B: - ret = ssl3_send_server_hello(s); - if (ret <= 0) - goto end; - if (s->internal->hit) { - if (s->internal->tlsext_ticket_expected) - s->internal->state = SSL3_ST_SW_SESSION_TICKET_A; - else - s->internal->state = SSL3_ST_SW_CHANGE_A; - } - else - s->internal->state = SSL3_ST_SW_CERT_A; - s->internal->init_num = 0; - break; - - case SSL3_ST_SW_CERT_A: - case SSL3_ST_SW_CERT_B: - /* Check if it is anon DH or anon ECDH. */ - if (!(S3I(s)->tmp.new_cipher->algorithm_auth & - SSL_aNULL)) { - ret = ssl3_send_server_certificate(s); - if (ret <= 0) - goto end; - if (s->internal->tlsext_status_expected) - s->internal->state = SSL3_ST_SW_CERT_STATUS_A; - else - s->internal->state = SSL3_ST_SW_KEY_EXCH_A; - } else { - skip = 1; - s->internal->state = SSL3_ST_SW_KEY_EXCH_A; - } - s->internal->init_num = 0; - break; - - case SSL3_ST_SW_KEY_EXCH_A: - case SSL3_ST_SW_KEY_EXCH_B: - alg_k = S3I(s)->tmp.new_cipher->algorithm_mkey; - - /* - * Only send if using a DH key exchange. - * - * For ECC ciphersuites, we send a ServerKeyExchange - * message only if the cipher suite is ECDHE. In other - * cases, the server certificate contains the server's - * public key for key exchange. - */ - if (alg_k & (SSL_kDHE|SSL_kECDHE)) { - ret = ssl3_send_server_key_exchange(s); - if (ret <= 0) - goto end; - } else - skip = 1; - - s->internal->state = SSL3_ST_SW_CERT_REQ_A; - s->internal->init_num = 0; - break; - - case SSL3_ST_SW_CERT_REQ_A: - case SSL3_ST_SW_CERT_REQ_B: - /* - * Determine whether or not we need to request a - * certificate. - * - * Do not request a certificate if: - * - * - We did not ask for it (SSL_VERIFY_PEER is unset). - * - * - SSL_VERIFY_CLIENT_ONCE is set and we are - * renegotiating. - * - * - We are using an anonymous ciphersuites - * (see section "Certificate request" in SSL 3 drafts - * and in RFC 2246) ... except when the application - * insists on verification (against the specs, but - * s3_clnt.c accepts this for SSL 3). - */ - if (!(s->verify_mode & SSL_VERIFY_PEER) || - ((s->session->peer != NULL) && - (s->verify_mode & SSL_VERIFY_CLIENT_ONCE)) || - ((S3I(s)->tmp.new_cipher->algorithm_auth & - SSL_aNULL) && !(s->verify_mode & - SSL_VERIFY_FAIL_IF_NO_PEER_CERT))) { - /* No cert request */ - skip = 1; - S3I(s)->tmp.cert_request = 0; - s->internal->state = SSL3_ST_SW_SRVR_DONE_A; - if (S3I(s)->handshake_buffer) { - if (!tls1_digest_cached_records(s)) { - ret = -1; - goto end; - } - } - } else { - S3I(s)->tmp.cert_request = 1; - ret = ssl3_send_certificate_request(s); - if (ret <= 0) - goto end; - s->internal->state = SSL3_ST_SW_SRVR_DONE_A; - s->internal->init_num = 0; - } - break; - - case SSL3_ST_SW_SRVR_DONE_A: - case SSL3_ST_SW_SRVR_DONE_B: - ret = ssl3_send_server_done(s); - if (ret <= 0) - goto end; - S3I(s)->tmp.next_state = SSL3_ST_SR_CERT_A; - s->internal->state = SSL3_ST_SW_FLUSH; - s->internal->init_num = 0; - break; - - case SSL3_ST_SW_FLUSH: - - /* - * This code originally checked to see if - * any data was pending using BIO_CTRL_INFO - * and then flushed. This caused problems - * as documented in PR#1939. The proposed - * fix doesn't completely resolve this issue - * as buggy implementations of BIO_CTRL_PENDING - * still exist. So instead we just flush - * unconditionally. - */ - - s->internal->rwstate = SSL_WRITING; - if (BIO_flush(s->wbio) <= 0) { - ret = -1; - goto end; - } - s->internal->rwstate = SSL_NOTHING; - - s->internal->state = S3I(s)->tmp.next_state; - break; - - case SSL3_ST_SR_CERT_A: - case SSL3_ST_SR_CERT_B: - if (S3I(s)->tmp.cert_request) { - ret = ssl3_get_client_certificate(s); - if (ret <= 0) - goto end; - } - s->internal->init_num = 0; - s->internal->state = SSL3_ST_SR_KEY_EXCH_A; - break; - - case SSL3_ST_SR_KEY_EXCH_A: - case SSL3_ST_SR_KEY_EXCH_B: - ret = ssl3_get_client_key_exchange(s); - if (ret <= 0) - goto end; - alg_k = S3I(s)->tmp.new_cipher->algorithm_mkey; - if (ret == 2) { - /* - * For the ECDH ciphersuites when - * the client sends its ECDH pub key in - * a certificate, the CertificateVerify - * message is not sent. - * Also for GOST ciphersuites when - * the client uses its key from the certificate - * for key exchange. - */ - if (S3I(s)->next_proto_neg_seen) - s->internal->state = SSL3_ST_SR_NEXT_PROTO_A; - else - s->internal->state = SSL3_ST_SR_FINISHED_A; - s->internal->init_num = 0; - } else if (SSL_USE_SIGALGS(s) || (alg_k & SSL_kGOST)) { - s->internal->state = SSL3_ST_SR_CERT_VRFY_A; - s->internal->init_num = 0; - if (!s->session->peer) - break; - /* - * For sigalgs freeze the handshake buffer - * at this point and digest cached records. - */ - if (!S3I(s)->handshake_buffer) { - SSLerr(SSL_F_SSL3_ACCEPT, - ERR_R_INTERNAL_ERROR); - ret = -1; - goto end; - } - s->s3->flags |= TLS1_FLAGS_KEEP_HANDSHAKE; - if (!tls1_digest_cached_records(s)) { - ret = -1; - goto end; - } - } else { - int offset = 0; - int dgst_num; - - s->internal->state = SSL3_ST_SR_CERT_VRFY_A; - s->internal->init_num = 0; - - /* - * We need to get hashes here so if there is - * a client cert, it can be verified - * FIXME - digest processing for - * CertificateVerify should be generalized. - * But it is next step - */ - if (S3I(s)->handshake_buffer) { - if (!tls1_digest_cached_records(s)) { - ret = -1; - goto end; - } - } - for (dgst_num = 0; dgst_num < SSL_MAX_DIGEST; - dgst_num++) - if (S3I(s)->handshake_dgst[dgst_num]) { - int dgst_size; - - s->method->internal->ssl3_enc->cert_verify_mac(s, - EVP_MD_CTX_type( - S3I(s)->handshake_dgst[dgst_num]), - &(S3I(s)->tmp.cert_verify_md[offset])); - dgst_size = EVP_MD_CTX_size( - S3I(s)->handshake_dgst[dgst_num]); - if (dgst_size < 0) { - ret = -1; - goto end; - } - offset += dgst_size; - } - } - break; - - case SSL3_ST_SR_CERT_VRFY_A: - case SSL3_ST_SR_CERT_VRFY_B: - s->s3->flags |= SSL3_FLAGS_CCS_OK; - - /* we should decide if we expected this one */ - ret = ssl3_get_cert_verify(s); - if (ret <= 0) - goto end; - - if (S3I(s)->next_proto_neg_seen) - s->internal->state = SSL3_ST_SR_NEXT_PROTO_A; - else - s->internal->state = SSL3_ST_SR_FINISHED_A; - s->internal->init_num = 0; - break; - - case SSL3_ST_SR_NEXT_PROTO_A: - case SSL3_ST_SR_NEXT_PROTO_B: - ret = ssl3_get_next_proto(s); - if (ret <= 0) - goto end; - s->internal->init_num = 0; - s->internal->state = SSL3_ST_SR_FINISHED_A; - break; - - case SSL3_ST_SR_FINISHED_A: - case SSL3_ST_SR_FINISHED_B: - s->s3->flags |= SSL3_FLAGS_CCS_OK; - ret = ssl3_get_finished(s, SSL3_ST_SR_FINISHED_A, - SSL3_ST_SR_FINISHED_B); - if (ret <= 0) - goto end; - if (s->internal->hit) - s->internal->state = SSL_ST_OK; - else if (s->internal->tlsext_ticket_expected) - s->internal->state = SSL3_ST_SW_SESSION_TICKET_A; - else - s->internal->state = SSL3_ST_SW_CHANGE_A; - s->internal->init_num = 0; - break; - - case SSL3_ST_SW_SESSION_TICKET_A: - case SSL3_ST_SW_SESSION_TICKET_B: - ret = ssl3_send_newsession_ticket(s); - if (ret <= 0) - goto end; - s->internal->state = SSL3_ST_SW_CHANGE_A; - s->internal->init_num = 0; - break; - - case SSL3_ST_SW_CERT_STATUS_A: - case SSL3_ST_SW_CERT_STATUS_B: - ret = ssl3_send_cert_status(s); - if (ret <= 0) - goto end; - s->internal->state = SSL3_ST_SW_KEY_EXCH_A; - s->internal->init_num = 0; - break; - - - case SSL3_ST_SW_CHANGE_A: - case SSL3_ST_SW_CHANGE_B: - - s->session->cipher = S3I(s)->tmp.new_cipher; - if (!s->method->internal->ssl3_enc->setup_key_block(s)) { - ret = -1; - goto end; - } - - ret = ssl3_send_change_cipher_spec(s, - SSL3_ST_SW_CHANGE_A, SSL3_ST_SW_CHANGE_B); - - if (ret <= 0) - goto end; - s->internal->state = SSL3_ST_SW_FINISHED_A; - s->internal->init_num = 0; - - if (!s->method->internal->ssl3_enc->change_cipher_state( - s, SSL3_CHANGE_CIPHER_SERVER_WRITE)) { - ret = -1; - goto end; - } - - break; - - case SSL3_ST_SW_FINISHED_A: - case SSL3_ST_SW_FINISHED_B: - ret = ssl3_send_finished(s, - SSL3_ST_SW_FINISHED_A, SSL3_ST_SW_FINISHED_B, - s->method->internal->ssl3_enc->server_finished_label, - s->method->internal->ssl3_enc->server_finished_label_len); - if (ret <= 0) - goto end; - s->internal->state = SSL3_ST_SW_FLUSH; - if (s->internal->hit) { - if (S3I(s)->next_proto_neg_seen) { - s->s3->flags |= SSL3_FLAGS_CCS_OK; - S3I(s)->tmp.next_state = - SSL3_ST_SR_NEXT_PROTO_A; - } else - S3I(s)->tmp.next_state = - SSL3_ST_SR_FINISHED_A; - } else - S3I(s)->tmp.next_state = SSL_ST_OK; - s->internal->init_num = 0; - break; - - case SSL_ST_OK: - /* clean a few things up */ - tls1_cleanup_key_block(s); - - BUF_MEM_free(s->internal->init_buf); - s->internal->init_buf = NULL; - - /* remove buffering on output */ - ssl_free_wbio_buffer(s); - - s->internal->init_num = 0; - - /* skipped if we just sent a HelloRequest */ - if (s->internal->renegotiate == 2) { - s->internal->renegotiate = 0; - s->internal->new_session = 0; - - ssl_update_cache(s, SSL_SESS_CACHE_SERVER); - - s->ctx->internal->stats.sess_accept_good++; - /* s->server=1; */ - s->internal->handshake_func = ssl3_accept; - - if (cb != NULL) - cb(s, SSL_CB_HANDSHAKE_DONE, 1); - } - - ret = 1; - goto end; - /* break; */ - - default: - SSLerr(SSL_F_SSL3_ACCEPT, - SSL_R_UNKNOWN_STATE); - ret = -1; - goto end; - /* break; */ - } - - if (!S3I(s)->tmp.reuse_message && !skip) { - if (s->internal->debug) { - if ((ret = BIO_flush(s->wbio)) <= 0) - goto end; - } - - - if ((cb != NULL) && (s->internal->state != state)) { - new_state = s->internal->state; - s->internal->state = state; - cb(s, SSL_CB_ACCEPT_LOOP, 1); - s->internal->state = new_state; - } - } - skip = 0; - } -end: - /* BIO_flush(s->wbio); */ - - s->internal->in_handshake--; - if (cb != NULL) - cb(s, SSL_CB_ACCEPT_EXIT, ret); - return (ret); -} - -int -ssl3_send_hello_request(SSL *s) -{ - if (s->internal->state == SSL3_ST_SW_HELLO_REQ_A) { - ssl3_handshake_msg_start(s, SSL3_MT_HELLO_REQUEST); - ssl3_handshake_msg_finish(s, 0); - - s->internal->state = SSL3_ST_SW_HELLO_REQ_B; - } - - /* SSL3_ST_SW_HELLO_REQ_B */ - return (ssl3_handshake_write(s)); -} - -int -ssl3_get_client_hello(SSL *s) -{ - int i, j, ok, al, ret = -1; - unsigned int cookie_len; - long n; - unsigned long id; - unsigned char *p, *d; - SSL_CIPHER *c; - STACK_OF(SSL_CIPHER) *ciphers = NULL; - unsigned long alg_k; - const SSL_METHOD *method; - uint16_t shared_version; - - /* - * We do this so that we will respond with our native type. - * If we are TLSv1 and we get SSLv3, we will respond with TLSv1, - * This down switching should be handled by a different method. - * If we are SSLv3, we will respond with SSLv3, even if prompted with - * TLSv1. - */ - if (s->internal->state == SSL3_ST_SR_CLNT_HELLO_A) { - s->internal->state = SSL3_ST_SR_CLNT_HELLO_B; - } - - s->internal->first_packet = 1; - n = s->method->internal->ssl_get_message(s, SSL3_ST_SR_CLNT_HELLO_B, - SSL3_ST_SR_CLNT_HELLO_C, SSL3_MT_CLIENT_HELLO, - SSL3_RT_MAX_PLAIN_LENGTH, &ok); - - if (!ok) - return ((int)n); - s->internal->first_packet = 0; - - d = p = (unsigned char *)s->internal->init_msg; - - if (2 > n) - goto truncated; - /* - * Use version from inside client hello, not from record header. - * (may differ: see RFC 2246, Appendix E, second paragraph) - */ - s->client_version = (((int)p[0]) << 8)|(int)p[1]; - p += 2; - - if (ssl_max_shared_version(s, s->client_version, &shared_version) != 1) { - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_WRONG_VERSION_NUMBER); - if ((s->client_version >> 8) == SSL3_VERSION_MAJOR && - !s->internal->enc_write_ctx && !s->internal->write_hash) { - /* - * Similar to ssl3_get_record, send alert using remote - * version number. - */ - s->version = s->client_version; - } - al = SSL_AD_PROTOCOL_VERSION; - goto f_err; - } - s->version = shared_version; - - if ((method = tls1_get_server_method(shared_version)) == NULL) - method = dtls1_get_server_method(shared_version); - if (method == NULL) { - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); - goto err; - } - s->method = method; - - /* - * If we require cookies (DTLS) and this ClientHello doesn't - * contain one, just return since we do not want to - * allocate any memory yet. So check cookie length... - */ - if (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) { - unsigned int session_length, cookie_length; - - if (p - d + SSL3_RANDOM_SIZE + 1 >= n) - goto truncated; - session_length = *(p + SSL3_RANDOM_SIZE); - - if (p - d + SSL3_RANDOM_SIZE + session_length + 1 >= n) - goto truncated; - cookie_length = p[SSL3_RANDOM_SIZE + session_length + 1]; - - if (cookie_length == 0) - return (1); - } - - if (p - d + SSL3_RANDOM_SIZE + 1 > n) - goto truncated; - - /* load the client random */ - memcpy(s->s3->client_random, p, SSL3_RANDOM_SIZE); - p += SSL3_RANDOM_SIZE; - - /* get the session-id */ - j= *(p++); - if (p - d + j > n) - goto truncated; - - s->internal->hit = 0; - /* - * Versions before 0.9.7 always allow clients to resume sessions in - * renegotiation. 0.9.7 and later allow this by default, but optionally - * ignore resumption requests with flag - * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION (it's a new flag - * rather than a change to default behavior so that applications - * relying on this for security won't even compile against older - * library versions). - * - * 1.0.1 and later also have a function SSL_renegotiate_abbreviated() - * to request renegotiation but not a new session (s->internal->new_session - * remains unset): for servers, this essentially just means that the - * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION setting will be - * ignored. - */ - if ((s->internal->new_session && (s->internal->options & - SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION))) { - if (!ssl_get_new_session(s, 1)) - goto err; - } else { - i = ssl_get_prev_session(s, p, j, d + n); - if (i == 1) { /* previous session */ - s->internal->hit = 1; - } else if (i == -1) - goto err; - else { - /* i == 0 */ - if (!ssl_get_new_session(s, 1)) - goto err; - } - } - - p += j; - - if (SSL_IS_DTLS(s)) { - /* cookie stuff */ - if (p - d + 1 > n) - goto truncated; - cookie_len = *(p++); - - /* - * The ClientHello may contain a cookie even if the - * HelloVerify message has not been sent--make sure that it - * does not cause an overflow. - */ - if (cookie_len > sizeof(D1I(s)->rcvd_cookie)) { - /* too much data */ - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, - SSL_R_COOKIE_MISMATCH); - goto f_err; - } - - if (p - d + cookie_len > n) - goto truncated; - - /* verify the cookie if appropriate option is set. */ - if ((SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) && - cookie_len > 0) { - memcpy(D1I(s)->rcvd_cookie, p, cookie_len); - - if (s->ctx->internal->app_verify_cookie_cb != NULL) { - if (s->ctx->internal->app_verify_cookie_cb(s, - D1I(s)->rcvd_cookie, cookie_len) == 0) { - al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, - SSL_R_COOKIE_MISMATCH); - goto f_err; - } - /* else cookie verification succeeded */ - } else if (timingsafe_memcmp(D1I(s)->rcvd_cookie, D1I(s)->cookie, - D1I(s)->cookie_len) != 0) { - /* default verification */ - al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, - SSL_R_COOKIE_MISMATCH); - goto f_err; - } - - ret = 2; - } - - p += cookie_len; - } - - if (p - d + 2 > n) - goto truncated; - n2s(p, i); - if ((i == 0) && (j != 0)) { - /* we need a cipher if we are not resuming a session */ - al = SSL_AD_ILLEGAL_PARAMETER; - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, - SSL_R_NO_CIPHERS_SPECIFIED); - goto f_err; - } - if (p - d + i > n) - goto truncated; - if (i > 0) { - if ((ciphers = ssl_bytes_to_cipher_list(s, p, i)) == NULL) - goto err; - } - p += i; - - /* If it is a hit, check that the cipher is in the list */ - if ((s->internal->hit) && (i > 0)) { - j = 0; - id = s->session->cipher->id; - - for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) { - c = sk_SSL_CIPHER_value(ciphers, i); - if (c->id == id) { - j = 1; - break; - } - } - if (j == 0) { - /* - * We need to have the cipher in the cipher - * list if we are asked to reuse it - */ - al = SSL_AD_ILLEGAL_PARAMETER; - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, - SSL_R_REQUIRED_CIPHER_MISSING); - goto f_err; - } - } - - /* compression */ - if (p - d + 1 > n) - goto truncated; - i= *(p++); - if (p - d + i > n) - goto truncated; - for (j = 0; j < i; j++) { - if (p[j] == 0) - break; - } - - p += i; - if (j >= i) { - /* no compress */ - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, - SSL_R_NO_COMPRESSION_SPECIFIED); - goto f_err; - } - - /* TLS extensions*/ - if (!ssl_parse_clienthello_tlsext(s, &p, d, n, &al)) { - /* 'al' set by ssl_parse_clienthello_tlsext */ - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_PARSE_TLSEXT); - goto f_err; - } - if (ssl_check_clienthello_tlsext_early(s) <= 0) { - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, - SSL_R_CLIENTHELLO_TLSEXT); - goto err; - } - - /* - * Check if we want to use external pre-shared secret for this - * handshake for not reused session only. We need to generate - * server_random before calling tls_session_secret_cb in order to allow - * SessionTicket processing to use it in key derivation. - */ - arc4random_buf(s->s3->server_random, SSL3_RANDOM_SIZE); - - if (!s->internal->hit && s->internal->tls_session_secret_cb) { - SSL_CIPHER *pref_cipher = NULL; - - s->session->master_key_length = sizeof(s->session->master_key); - if (s->internal->tls_session_secret_cb(s, s->session->master_key, - &s->session->master_key_length, ciphers, &pref_cipher, - s->internal->tls_session_secret_cb_arg)) { - s->internal->hit = 1; - s->session->ciphers = ciphers; - s->session->verify_result = X509_V_OK; - - ciphers = NULL; - - /* check if some cipher was preferred by call back */ - pref_cipher = pref_cipher ? pref_cipher : - ssl3_choose_cipher(s, s->session->ciphers, - SSL_get_ciphers(s)); - if (pref_cipher == NULL) { - al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, - SSL_R_NO_SHARED_CIPHER); - goto f_err; - } - - s->session->cipher = pref_cipher; - - sk_SSL_CIPHER_free(s->cipher_list); - sk_SSL_CIPHER_free(s->internal->cipher_list_by_id); - - s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers); - s->internal->cipher_list_by_id = - sk_SSL_CIPHER_dup(s->session->ciphers); - } - } - - /* - * Given s->session->ciphers and SSL_get_ciphers, we must - * pick a cipher - */ - - if (!s->internal->hit) { - sk_SSL_CIPHER_free(s->session->ciphers); - s->session->ciphers = ciphers; - if (ciphers == NULL) { - al = SSL_AD_ILLEGAL_PARAMETER; - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, - SSL_R_NO_CIPHERS_PASSED); - goto f_err; - } - ciphers = NULL; - c = ssl3_choose_cipher(s, s->session->ciphers, - SSL_get_ciphers(s)); - - if (c == NULL) { - al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, - SSL_R_NO_SHARED_CIPHER); - goto f_err; - } - S3I(s)->tmp.new_cipher = c; - } else { - S3I(s)->tmp.new_cipher = s->session->cipher; - } - - alg_k = S3I(s)->tmp.new_cipher->algorithm_mkey; - if (!(SSL_USE_SIGALGS(s) || (alg_k & SSL_kGOST)) || - !(s->verify_mode & SSL_VERIFY_PEER)) { - if (!tls1_digest_cached_records(s)) { - al = SSL_AD_INTERNAL_ERROR; - goto f_err; - } - } - - /* - * We now have the following setup. - * client_random - * cipher_list - our prefered list of ciphers - * ciphers - the clients prefered list of ciphers - * compression - basically ignored right now - * ssl version is set - sslv3 - * s->session - The ssl session has been setup. - * s->internal->hit - session reuse flag - * s->tmp.new_cipher - the new cipher to use. - */ - - /* Handles TLS extensions that we couldn't check earlier */ - if (ssl_check_clienthello_tlsext_late(s) <= 0) { - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT); - goto err; - } - - if (ret < 0) - ret = 1; - if (0) { -truncated: - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_BAD_PACKET_LENGTH); -f_err: - ssl3_send_alert(s, SSL3_AL_FATAL, al); - } -err: - sk_SSL_CIPHER_free(ciphers); - - return (ret); -} - -int -ssl3_send_server_hello(SSL *s) -{ - unsigned char *bufend; - unsigned char *p, *d; - CBB cbb, session_id; - size_t outlen; - int sl; - - memset(&cbb, 0, sizeof(cbb)); - - bufend = (unsigned char *)s->internal->init_buf->data + SSL3_RT_MAX_PLAIN_LENGTH; - - if (s->internal->state == SSL3_ST_SW_SRVR_HELLO_A) { - d = p = ssl3_handshake_msg_start(s, SSL3_MT_SERVER_HELLO); - - if (!CBB_init_fixed(&cbb, p, bufend - p)) - goto err; - - if (!CBB_add_u16(&cbb, s->version)) - goto err; - if (!CBB_add_bytes(&cbb, s->s3->server_random, - sizeof(s->s3->server_random))) - goto err; - - /* - * There are several cases for the session ID to send - * back in the server hello: - * - * - For session reuse from the session cache, - * we send back the old session ID. - * - If stateless session reuse (using a session ticket) - * is successful, we send back the client's "session ID" - * (which doesn't actually identify the session). - * - If it is a new session, we send back the new - * session ID. - * - However, if we want the new session to be single-use, - * we send back a 0-length session ID. - * - * s->internal->hit is non-zero in either case of session reuse, - * so the following won't overwrite an ID that we're supposed - * to send back. - */ - if (!(s->ctx->internal->session_cache_mode & SSL_SESS_CACHE_SERVER) - && !s->internal->hit) - s->session->session_id_length = 0; - - sl = s->session->session_id_length; - if (sl > (int)sizeof(s->session->session_id)) { - SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO, - ERR_R_INTERNAL_ERROR); - goto err; - } - - if (!CBB_add_u8_length_prefixed(&cbb, &session_id)) - goto err; - if (!CBB_add_bytes(&session_id, s->session->session_id, sl)) - goto err; - - /* Cipher suite. */ - if (!CBB_add_u16(&cbb, - ssl3_cipher_get_value(S3I(s)->tmp.new_cipher))) - goto err; - - /* Compression method. */ - if (!CBB_add_u8(&cbb, 0)) - goto err; - - if (!CBB_finish(&cbb, NULL, &outlen)) - goto err; - - if ((p = ssl_add_serverhello_tlsext(s, p + outlen, - bufend)) == NULL) { - SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO, - ERR_R_INTERNAL_ERROR); - goto err; - } - - ssl3_handshake_msg_finish(s, p - d); - } - - /* SSL3_ST_SW_SRVR_HELLO_B */ - return (ssl3_handshake_write(s)); - - err: - CBB_cleanup(&cbb); - - return (-1); -} - -int -ssl3_send_server_done(SSL *s) -{ - if (s->internal->state == SSL3_ST_SW_SRVR_DONE_A) { - ssl3_handshake_msg_start(s, SSL3_MT_SERVER_DONE); - ssl3_handshake_msg_finish(s, 0); - - s->internal->state = SSL3_ST_SW_SRVR_DONE_B; - } - - /* SSL3_ST_SW_SRVR_DONE_B */ - return (ssl3_handshake_write(s)); -} - -int -ssl3_send_server_kex_dhe(SSL *s, CBB *cbb) -{ - CBB dh_p, dh_g, dh_Ys; - DH *dh = NULL, *dhp; - unsigned char *data; - int al; - - if (s->cert->dh_tmp_auto != 0) { - if ((dhp = ssl_get_auto_dh(s)) == NULL) { - al = SSL_AD_INTERNAL_ERROR; - SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, - ERR_R_INTERNAL_ERROR); - goto f_err; - } - } else - dhp = s->cert->dh_tmp; - - if (dhp == NULL && s->cert->dh_tmp_cb != NULL) - dhp = s->cert->dh_tmp_cb(s, 0, - SSL_C_PKEYLENGTH(S3I(s)->tmp.new_cipher)); - - if (dhp == NULL) { - al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, - SSL_R_MISSING_TMP_DH_KEY); - goto f_err; - } - - if (S3I(s)->tmp.dh != NULL) { - SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, - ERR_R_INTERNAL_ERROR); - goto err; - } - - if (s->cert->dh_tmp_auto != 0) { - dh = dhp; - } else if ((dh = DHparams_dup(dhp)) == NULL) { - SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_DH_LIB); - goto err; - } - S3I(s)->tmp.dh = dh; - if (!DH_generate_key(dh)) { - SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_DH_LIB); - goto err; - } - - /* - * Serialize the DH parameters and public key. - */ - if (!CBB_add_u16_length_prefixed(cbb, &dh_p)) - goto err; - if (!CBB_add_space(&dh_p, &data, BN_num_bytes(dh->p))) - goto err; - BN_bn2bin(dh->p, data); - - if (!CBB_add_u16_length_prefixed(cbb, &dh_g)) - goto err; - if (!CBB_add_space(&dh_g, &data, BN_num_bytes(dh->g))) - goto err; - BN_bn2bin(dh->g, data); - - if (!CBB_add_u16_length_prefixed(cbb, &dh_Ys)) - goto err; - if (!CBB_add_space(&dh_Ys, &data, BN_num_bytes(dh->pub_key))) - goto err; - BN_bn2bin(dh->pub_key, data); - - if (!CBB_flush(cbb)) - goto err; - - return (1); - - f_err: - ssl3_send_alert(s, SSL3_AL_FATAL, al); - err: - return (-1); -} - -static int -ssl3_send_server_kex_ecdhe_ecp(SSL *s, int nid, CBB *cbb) -{ - CBB ecpoint; - unsigned char *data; - EC_KEY *ecdh = NULL, *ecdhp; - const EC_GROUP *group; - unsigned char *encodedPoint = NULL; - int encodedlen = 0; - int curve_id = 0; - BN_CTX *bn_ctx = NULL; - int al; - - ecdhp = s->cert->ecdh_tmp; - if (s->cert->ecdh_tmp_auto != 0) { - if (nid != NID_undef) - ecdhp = EC_KEY_new_by_curve_name(nid); - } else if (ecdhp == NULL && s->cert->ecdh_tmp_cb != NULL) { - ecdhp = s->cert->ecdh_tmp_cb(s, 0, - SSL_C_PKEYLENGTH(S3I(s)->tmp.new_cipher)); - } - if (ecdhp == NULL) { - al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, - SSL_R_MISSING_TMP_ECDH_KEY); - goto f_err; - } - - if (S3I(s)->tmp.ecdh != NULL) { - SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, - ERR_R_INTERNAL_ERROR); - goto err; - } - - /* Duplicate the ECDH structure. */ - if (s->cert->ecdh_tmp_auto != 0) { - ecdh = ecdhp; - } else if ((ecdh = EC_KEY_dup(ecdhp)) == NULL) { - SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, - ERR_R_ECDH_LIB); - goto err; - } - S3I(s)->tmp.ecdh = ecdh; - - if ((EC_KEY_get0_public_key(ecdh) == NULL) || - (EC_KEY_get0_private_key(ecdh) == NULL) || - (s->internal->options & SSL_OP_SINGLE_ECDH_USE)) { - if (!EC_KEY_generate_key(ecdh)) { - SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, - ERR_R_ECDH_LIB); - goto err; - } - } - - if (((group = EC_KEY_get0_group(ecdh)) == NULL) || - (EC_KEY_get0_public_key(ecdh) == NULL) || - (EC_KEY_get0_private_key(ecdh) == NULL)) { - SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, - ERR_R_ECDH_LIB); - goto err; - } - - /* - * Only named curves are supported in ECDH ephemeral key exchanges. - * For supported named curves, curve_id is non-zero. - */ - if ((curve_id = tls1_ec_nid2curve_id( - EC_GROUP_get_curve_name(group))) == 0) { - SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, - SSL_R_UNSUPPORTED_ELLIPTIC_CURVE); - goto err; - } - - /* - * Encode the public key. First check the size of encoding and - * allocate memory accordingly. - */ - encodedlen = EC_POINT_point2oct(group, EC_KEY_get0_public_key(ecdh), - POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL); - - encodedPoint = malloc(encodedlen); - - bn_ctx = BN_CTX_new(); - if ((encodedPoint == NULL) || (bn_ctx == NULL)) { - SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, - ERR_R_MALLOC_FAILURE); - goto err; - } - - encodedlen = EC_POINT_point2oct(group, EC_KEY_get0_public_key(ecdh), - POINT_CONVERSION_UNCOMPRESSED, encodedPoint, encodedlen, bn_ctx); - - if (encodedlen == 0) { - SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_ECDH_LIB); - goto err; - } - - BN_CTX_free(bn_ctx); - bn_ctx = NULL; - - /* - * Only named curves are supported in ECDH ephemeral key exchanges. - * In this case the ServerKeyExchange message has: - * [1 byte CurveType], [2 byte CurveName] - * [1 byte length of encoded point], followed by - * the actual encoded point itself. - */ - if (!CBB_add_u8(cbb, NAMED_CURVE_TYPE)) - goto err; - if (!CBB_add_u16(cbb, curve_id)) - goto err; - if (!CBB_add_u8_length_prefixed(cbb, &ecpoint)) - goto err; - if (!CBB_add_space(&ecpoint, &data, encodedlen)) - goto err; - - memcpy(data, encodedPoint, encodedlen); - - free(encodedPoint); - encodedPoint = NULL; - - if (!CBB_flush(cbb)) - goto err; - - return (1); - - f_err: - ssl3_send_alert(s, SSL3_AL_FATAL, al); - err: - free(encodedPoint); - BN_CTX_free(bn_ctx); - - return (-1); -} - -static int -ssl3_send_server_kex_ecdhe_ecx(SSL *s, int nid, CBB *cbb) -{ - uint8_t *public_key = NULL; - int curve_id; - CBB ecpoint; - int ret = -1; - - /* Generate an X25519 key pair. */ - if (S3I(s)->tmp.x25519 != NULL) { - SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, - ERR_R_INTERNAL_ERROR); - goto err; - } - if ((S3I(s)->tmp.x25519 = malloc(X25519_KEY_LENGTH)) == NULL) - goto err; - if ((public_key = malloc(X25519_KEY_LENGTH)) == NULL) - goto err; - X25519_keypair(public_key, S3I(s)->tmp.x25519); - - /* Serialize public key. */ - if ((curve_id = tls1_ec_nid2curve_id(nid)) == 0) { - SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, - SSL_R_UNSUPPORTED_ELLIPTIC_CURVE); - goto err; - } - - if (!CBB_add_u8(cbb, NAMED_CURVE_TYPE)) - goto err; - if (!CBB_add_u16(cbb, curve_id)) - goto err; - if (!CBB_add_u8_length_prefixed(cbb, &ecpoint)) - goto err; - if (!CBB_add_bytes(&ecpoint, public_key, X25519_KEY_LENGTH)) - goto err; - if (!CBB_flush(cbb)) - goto err; - - ret = 1; - - err: - free(public_key); - - return (ret); -} - -static int -ssl3_send_server_kex_ecdhe(SSL *s, CBB *cbb) -{ - int nid; - - nid = tls1_get_shared_curve(s); - - if (s->cert->ecdh_tmp_auto != 0 && nid == NID_X25519) - return ssl3_send_server_kex_ecdhe_ecx(s, nid, cbb); - - return ssl3_send_server_kex_ecdhe_ecp(s, nid, cbb); -} - -int -ssl3_send_server_key_exchange(SSL *s) -{ - CBB cbb; - unsigned char *params = NULL; - size_t params_len; - unsigned char *q; - int j, num; - unsigned char md_buf[MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH]; - unsigned int u; - EVP_PKEY *pkey; - const EVP_MD *md = NULL; - unsigned char *p, *d; - int al, i; - unsigned long type; - int n; - int kn; - BUF_MEM *buf; - EVP_MD_CTX md_ctx; - - memset(&cbb, 0, sizeof(cbb)); - - EVP_MD_CTX_init(&md_ctx); - if (s->internal->state == SSL3_ST_SW_KEY_EXCH_A) { - type = S3I(s)->tmp.new_cipher->algorithm_mkey; - - buf = s->internal->init_buf; - - if (!CBB_init(&cbb, 0)) - goto err; - - if (type & SSL_kDHE) { - if (ssl3_send_server_kex_dhe(s, &cbb) != 1) - goto err; - } else if (type & SSL_kECDHE) { - if (ssl3_send_server_kex_ecdhe(s, &cbb) != 1) - goto err; - } else { - al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, - SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE); - goto f_err; - } - - if (!CBB_finish(&cbb, ¶ms, ¶ms_len)) - goto err; - - if (!(S3I(s)->tmp.new_cipher->algorithm_auth & SSL_aNULL)) { - if ((pkey = ssl_get_sign_pkey( - s, S3I(s)->tmp.new_cipher, &md)) == NULL) { - al = SSL_AD_DECODE_ERROR; - goto f_err; - } - kn = EVP_PKEY_size(pkey); - } else { - pkey = NULL; - kn = 0; - } - - if (!BUF_MEM_grow_clean(buf, ssl3_handshake_msg_hdr_len(s) + - params_len + kn)) { - SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, - ERR_LIB_BUF); - goto err; - } - - d = p = ssl3_handshake_msg_start(s, - SSL3_MT_SERVER_KEY_EXCHANGE); - - memcpy(p, params, params_len); - - free(params); - params = NULL; - - n = params_len; - p += params_len; - - /* not anonymous */ - if (pkey != NULL) { - /* - * n is the length of the params, they start at &(d[4]) - * and p points to the space at the end. - */ - if (pkey->type == EVP_PKEY_RSA && !SSL_USE_SIGALGS(s)) { - q = md_buf; - j = 0; - for (num = 2; num > 0; num--) { - if (!EVP_DigestInit_ex(&md_ctx, - (num == 2) ? s->ctx->internal->md5 : - s->ctx->internal->sha1, NULL)) - goto err; - EVP_DigestUpdate(&md_ctx, - s->s3->client_random, - SSL3_RANDOM_SIZE); - EVP_DigestUpdate(&md_ctx, - s->s3->server_random, - SSL3_RANDOM_SIZE); - EVP_DigestUpdate(&md_ctx, d, n); - EVP_DigestFinal_ex(&md_ctx, q, - (unsigned int *)&i); - q += i; - j += i; - } - if (RSA_sign(NID_md5_sha1, md_buf, j, - &(p[2]), &u, pkey->pkey.rsa) <= 0) { - SSLerr( - SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, - ERR_LIB_RSA); - goto err; - } - s2n(u, p); - n += u + 2; - } else if (md) { - /* Send signature algorithm. */ - if (SSL_USE_SIGALGS(s)) { - if (!tls12_get_sigandhash(p, pkey, md)) { - /* Should never happen */ - al = SSL_AD_INTERNAL_ERROR; - SSLerr( - SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, - ERR_R_INTERNAL_ERROR); - goto f_err; - } - p += 2; - } - EVP_SignInit_ex(&md_ctx, md, NULL); - EVP_SignUpdate(&md_ctx, - s->s3->client_random, - SSL3_RANDOM_SIZE); - EVP_SignUpdate(&md_ctx, - s->s3->server_random, - SSL3_RANDOM_SIZE); - EVP_SignUpdate(&md_ctx, d, n); - if (!EVP_SignFinal(&md_ctx, &p[2], - (unsigned int *)&i, pkey)) { - SSLerr( - SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, - ERR_LIB_EVP); - goto err; - } - s2n(i, p); - n += i + 2; - if (SSL_USE_SIGALGS(s)) - n += 2; - } else { - /* Is this error check actually needed? */ - al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, - SSL_R_UNKNOWN_PKEY_TYPE); - goto f_err; - } - } - - ssl3_handshake_msg_finish(s, n); - } - - s->internal->state = SSL3_ST_SW_KEY_EXCH_B; - - EVP_MD_CTX_cleanup(&md_ctx); - - return (ssl3_handshake_write(s)); - - f_err: - ssl3_send_alert(s, SSL3_AL_FATAL, al); - err: - free(params); - EVP_MD_CTX_cleanup(&md_ctx); - CBB_cleanup(&cbb); - - return (-1); -} - -int -ssl3_send_certificate_request(SSL *s) -{ - unsigned char *p, *d; - int i, j, nl, off, n; - STACK_OF(X509_NAME) *sk = NULL; - X509_NAME *name; - BUF_MEM *buf; - - if (s->internal->state == SSL3_ST_SW_CERT_REQ_A) { - buf = s->internal->init_buf; - - d = p = ssl3_handshake_msg_start(s, - SSL3_MT_CERTIFICATE_REQUEST); - - /* get the list of acceptable cert types */ - p++; - n = ssl3_get_req_cert_type(s, p); - d[0] = n; - p += n; - n++; - - if (SSL_USE_SIGALGS(s)) { - nl = tls12_get_req_sig_algs(s, p + 2); - s2n(nl, p); - p += nl + 2; - n += nl + 2; - } - - off = n; - p += 2; - n += 2; - - sk = SSL_get_client_CA_list(s); - nl = 0; - if (sk != NULL) { - for (i = 0; i < sk_X509_NAME_num(sk); i++) { - name = sk_X509_NAME_value(sk, i); - j = i2d_X509_NAME(name, NULL); - if (!BUF_MEM_grow_clean(buf, - ssl3_handshake_msg_hdr_len(s) + n + j - + 2)) { - SSLerr( - SSL_F_SSL3_SEND_CERTIFICATE_REQUEST, - ERR_R_BUF_LIB); - goto err; - } - p = ssl3_handshake_msg_start(s, - SSL3_MT_CERTIFICATE_REQUEST) + n; - s2n(j, p); - i2d_X509_NAME(name, &p); - n += 2 + j; - nl += 2 + j; - } - } - /* else no CA names */ - p = ssl3_handshake_msg_start(s, - SSL3_MT_CERTIFICATE_REQUEST) + off; - s2n(nl, p); - - ssl3_handshake_msg_finish(s, n); - - s->internal->state = SSL3_ST_SW_CERT_REQ_B; - } - - /* SSL3_ST_SW_CERT_REQ_B */ - return (ssl3_handshake_write(s)); -err: - return (-1); -} - -static int -ssl3_get_client_kex_rsa(SSL *s, unsigned char *p, long n) -{ - unsigned char fakekey[SSL_MAX_MASTER_KEY_LENGTH]; - unsigned char *d; - RSA *rsa = NULL; - EVP_PKEY *pkey = NULL; - int i, al; - - d = p; - - arc4random_buf(fakekey, sizeof(fakekey)); - fakekey[0] = s->client_version >> 8; - fakekey[1] = s->client_version & 0xff; - - pkey = s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey; - if ((pkey == NULL) || (pkey->type != EVP_PKEY_RSA) || - (pkey->pkey.rsa == NULL)) { - al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - SSL_R_MISSING_RSA_CERTIFICATE); - goto f_err; - } - rsa = pkey->pkey.rsa; - - if (2 > n) - goto truncated; - n2s(p, i); - if (n != i + 2) { - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG); - goto err; - } else - n = i; - - i = RSA_private_decrypt((int)n, p, p, rsa, RSA_PKCS1_PADDING); - - ERR_clear_error(); - - al = -1; - - if (i != SSL_MAX_MASTER_KEY_LENGTH) { - al = SSL_AD_DECODE_ERROR; - /* SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_RSA_DECRYPT); */ - } - - if (p - d + 2 > n) /* needed in the SSL3 case */ - goto truncated; - if ((al == -1) && !((p[0] == (s->client_version >> 8)) && - (p[1] == (s->client_version & 0xff)))) { - /* - * The premaster secret must contain the same version - * number as the ClientHello to detect version rollback - * attacks (strangely, the protocol does not offer such - * protection for DH ciphersuites). - * However, buggy clients exist that send the negotiated - * protocol version instead if the server does not - * support the requested protocol version. - * If SSL_OP_TLS_ROLLBACK_BUG is set, tolerate such - * clients. - */ - if (!((s->internal->options & SSL_OP_TLS_ROLLBACK_BUG) && - (p[0] == (s->version >> 8)) && - (p[1] == (s->version & 0xff)))) { - al = SSL_AD_DECODE_ERROR; - /* SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_PROTOCOL_VERSION_NUMBER); */ - - /* - * The Klima-Pokorny-Rosa extension of - * Bleichenbacher's attack - * (http://eprint.iacr.org/2003/052/) exploits - * the version number check as a "bad version - * oracle" -- an alert would reveal that the - * plaintext corresponding to some ciphertext - * made up by the adversary is properly - * formatted except that the version number is - * wrong. - * To avoid such attacks, we should treat this - * just like any other decryption error. - */ - } - } - - if (al != -1) { - /* - * Some decryption failure -- use random value instead - * as countermeasure against Bleichenbacher's attack - * on PKCS #1 v1.5 RSA padding (see RFC 2246, - * section 7.4.7.1). - */ - i = SSL_MAX_MASTER_KEY_LENGTH; - p = fakekey; - } - - s->session->master_key_length = - s->method->internal->ssl3_enc->generate_master_secret(s, - s->session->master_key, p, i); - - explicit_bzero(p, i); - - return (1); -truncated: - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_BAD_PACKET_LENGTH); -f_err: - ssl3_send_alert(s, SSL3_AL_FATAL, al); -err: - return (-1); -} - -static int -ssl3_get_client_kex_dhe(SSL *s, unsigned char *p, long n) -{ - BIGNUM *bn = NULL; - int key_size, al; - CBS cbs, dh_Yc; - DH *dh; - - if (n < 0) - goto err; - - CBS_init(&cbs, p, n); - - if (!CBS_get_u16_length_prefixed(&cbs, &dh_Yc)) - goto truncated; - - if (CBS_len(&cbs) != 0) - goto truncated; - - if (S3I(s)->tmp.dh == NULL) { - al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - SSL_R_MISSING_TMP_DH_KEY); - goto f_err; - } - dh = S3I(s)->tmp.dh; - - if ((bn = BN_bin2bn(CBS_data(&dh_Yc), CBS_len(&dh_Yc), NULL)) == NULL) { - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - SSL_R_BN_LIB); - goto err; - } - - key_size = DH_compute_key(p, bn, dh); - if (key_size <= 0) { - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB); - BN_clear_free(bn); - goto err; - } - - s->session->master_key_length = - s->method->internal->ssl3_enc->generate_master_secret( - s, s->session->master_key, p, key_size); - - explicit_bzero(p, key_size); - - DH_free(S3I(s)->tmp.dh); - S3I(s)->tmp.dh = NULL; - - BN_clear_free(bn); - - return (1); - - truncated: - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_BAD_PACKET_LENGTH); - f_err: - ssl3_send_alert(s, SSL3_AL_FATAL, al); - err: - return (-1); -} - -static int -ssl3_get_client_kex_ecdhe_ecp(SSL *s, unsigned char *p, long n) -{ - EC_KEY *srvr_ecdh = NULL; - EVP_PKEY *clnt_pub_pkey = NULL; - EC_POINT *clnt_ecpoint = NULL; - BN_CTX *bn_ctx = NULL; - int i, al; - - int ret = 1; - int key_size; - const EC_KEY *tkey; - const EC_GROUP *group; - const BIGNUM *priv_key; - - /* Initialize structures for server's ECDH key pair. */ - if ((srvr_ecdh = EC_KEY_new()) == NULL) { - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - ERR_R_MALLOC_FAILURE); - goto err; - } - - /* - * Use the ephemeral values we saved when - * generating the ServerKeyExchange message. - */ - tkey = S3I(s)->tmp.ecdh; - - group = EC_KEY_get0_group(tkey); - priv_key = EC_KEY_get0_private_key(tkey); - - if (!EC_KEY_set_group(srvr_ecdh, group) || - !EC_KEY_set_private_key(srvr_ecdh, priv_key)) { - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - ERR_R_EC_LIB); - goto err; - } - - /* Let's get client's public key */ - if ((clnt_ecpoint = EC_POINT_new(group)) == NULL) { - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - ERR_R_MALLOC_FAILURE); - goto err; - } - - if (n == 0L) { - /* Client Publickey was in Client Certificate */ - if (((clnt_pub_pkey = X509_get_pubkey( - s->session->peer)) == NULL) || - (clnt_pub_pkey->type != EVP_PKEY_EC)) { - /* - * XXX: For now, we do not support client - * authentication using ECDH certificates - * so this branch (n == 0L) of the code is - * never executed. When that support is - * added, we ought to ensure the key - * received in the certificate is - * authorized for key agreement. - * ECDH_compute_key implicitly checks that - * the two ECDH shares are for the same - * group. - */ - al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - SSL_R_UNABLE_TO_DECODE_ECDH_CERTS); - goto f_err; - } - - if (EC_POINT_copy(clnt_ecpoint, - EC_KEY_get0_public_key(clnt_pub_pkey->pkey.ec)) - == 0) { - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - ERR_R_EC_LIB); - goto err; - } - ret = 2; /* Skip certificate verify processing */ - } else { - /* - * Get client's public key from encoded point - * in the ClientKeyExchange message. - */ - if ((bn_ctx = BN_CTX_new()) == NULL) { - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - ERR_R_MALLOC_FAILURE); - goto err; - } - - /* Get encoded point length */ - i = *p; - - p += 1; - if (n != 1 + i) { - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - ERR_R_EC_LIB); - goto err; - } - if (EC_POINT_oct2point(group, - clnt_ecpoint, p, i, bn_ctx) == 0) { - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - ERR_R_EC_LIB); - goto err; - } - /* - * p is pointing to somewhere in the buffer - * currently, so set it to the start. - */ - p = (unsigned char *)s->internal->init_buf->data; - } - - /* Compute the shared pre-master secret */ - key_size = ECDH_size(srvr_ecdh); - if (key_size <= 0) { - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - ERR_R_ECDH_LIB); - goto err; - } - i = ECDH_compute_key(p, key_size, clnt_ecpoint, srvr_ecdh, - NULL); - if (i <= 0) { - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - ERR_R_ECDH_LIB); - goto err; - } - - EVP_PKEY_free(clnt_pub_pkey); - EC_POINT_free(clnt_ecpoint); - EC_KEY_free(srvr_ecdh); - BN_CTX_free(bn_ctx); - EC_KEY_free(S3I(s)->tmp.ecdh); - S3I(s)->tmp.ecdh = NULL; - - /* Compute the master secret */ - s->session->master_key_length = - s->method->internal->ssl3_enc->generate_master_secret( - s, s->session->master_key, p, i); - - explicit_bzero(p, i); - return (ret); - - f_err: - ssl3_send_alert(s, SSL3_AL_FATAL, al); - err: - EVP_PKEY_free(clnt_pub_pkey); - EC_POINT_free(clnt_ecpoint); - EC_KEY_free(srvr_ecdh); - BN_CTX_free(bn_ctx); - return (-1); -} - -static int -ssl3_get_client_kex_ecdhe_ecx(SSL *s, unsigned char *p, long n) -{ - uint8_t *shared_key = NULL; - CBS cbs, ecpoint; - int ret = -1; - - if (n < 0) - goto err; - - CBS_init(&cbs, p, n); - if (!CBS_get_u8_length_prefixed(&cbs, &ecpoint)) - goto err; - if (CBS_len(&ecpoint) != X25519_KEY_LENGTH) - goto err; - - if ((shared_key = malloc(X25519_KEY_LENGTH)) == NULL) - goto err; - if (!X25519(shared_key, S3I(s)->tmp.x25519, CBS_data(&ecpoint))) - goto err; - - explicit_bzero(S3I(s)->tmp.x25519, X25519_KEY_LENGTH); - free(S3I(s)->tmp.x25519); - S3I(s)->tmp.x25519 = NULL; - - s->session->master_key_length = - s->method->internal->ssl3_enc->generate_master_secret( - s, s->session->master_key, shared_key, X25519_KEY_LENGTH); - - ret = 1; - - err: - if (shared_key != NULL) - explicit_bzero(shared_key, X25519_KEY_LENGTH); - free(shared_key); - - return (ret); -} - -static int -ssl3_get_client_kex_ecdhe(SSL *s, unsigned char *p, long n) -{ - if (S3I(s)->tmp.x25519 != NULL) - return ssl3_get_client_kex_ecdhe_ecx(s, p, n); - - return ssl3_get_client_kex_ecdhe_ecp(s, p, n); -} - -static int -ssl3_get_client_kex_gost(SSL *s, unsigned char *p, long n) -{ - - EVP_PKEY_CTX *pkey_ctx; - EVP_PKEY *client_pub_pkey = NULL, *pk = NULL; - unsigned char premaster_secret[32], *start; - size_t outlen = 32, inlen; - unsigned long alg_a; - int Ttag, Tclass; - long Tlen; - int al; - int ret = 0; - - /* Get our certificate private key*/ - alg_a = S3I(s)->tmp.new_cipher->algorithm_auth; - if (alg_a & SSL_aGOST01) - pk = s->cert->pkeys[SSL_PKEY_GOST01].privatekey; - - pkey_ctx = EVP_PKEY_CTX_new(pk, NULL); - EVP_PKEY_decrypt_init(pkey_ctx); - /* - * If client certificate is present and is of the same type, - * maybe use it for key exchange. - * Don't mind errors from EVP_PKEY_derive_set_peer, because - * it is completely valid to use a client certificate for - * authorization only. - */ - client_pub_pkey = X509_get_pubkey(s->session->peer); - if (client_pub_pkey) { - if (EVP_PKEY_derive_set_peer(pkey_ctx, - client_pub_pkey) <= 0) - ERR_clear_error(); - } - if (2 > n) - goto truncated; - /* Decrypt session key */ - if (ASN1_get_object((const unsigned char **)&p, &Tlen, &Ttag, - &Tclass, n) != V_ASN1_CONSTRUCTED || - Ttag != V_ASN1_SEQUENCE || Tclass != V_ASN1_UNIVERSAL) { - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - SSL_R_DECRYPTION_FAILED); - goto gerr; - } - start = p; - inlen = Tlen; - if (EVP_PKEY_decrypt(pkey_ctx, premaster_secret, &outlen, - start, inlen) <=0) { - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - SSL_R_DECRYPTION_FAILED); - goto gerr; - } - /* Generate master secret */ - s->session->master_key_length = - s->method->internal->ssl3_enc->generate_master_secret( - s, s->session->master_key, premaster_secret, 32); - /* Check if pubkey from client certificate was used */ - if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, -1, - EVP_PKEY_CTRL_PEER_KEY, 2, NULL) > 0) - ret = 2; - else - ret = 1; - gerr: - EVP_PKEY_free(client_pub_pkey); - EVP_PKEY_CTX_free(pkey_ctx); - if (ret) - return (ret); - else - goto err; - - truncated: - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_BAD_PACKET_LENGTH); - ssl3_send_alert(s, SSL3_AL_FATAL, al); - err: - return (-1); -} - -int -ssl3_get_client_key_exchange(SSL *s) -{ - unsigned long alg_k; - unsigned char *p; - int al, ok; - long n; - - /* 2048 maxlen is a guess. How long a key does that permit? */ - n = s->method->internal->ssl_get_message(s, SSL3_ST_SR_KEY_EXCH_A, - SSL3_ST_SR_KEY_EXCH_B, SSL3_MT_CLIENT_KEY_EXCHANGE, 2048, &ok); - if (!ok) - return ((int)n); - - p = (unsigned char *)s->internal->init_msg; - - alg_k = S3I(s)->tmp.new_cipher->algorithm_mkey; - - if (alg_k & SSL_kRSA) { - if (ssl3_get_client_kex_rsa(s, p, n) != 1) - goto err; - } else if (alg_k & SSL_kDHE) { - if (ssl3_get_client_kex_dhe(s, p, n) != 1) - goto err; - } else if (alg_k & SSL_kECDHE) { - if (ssl3_get_client_kex_ecdhe(s, p, n) != 1) - goto err; - } else if (alg_k & SSL_kGOST) { - if (ssl3_get_client_kex_gost(s, p, n) != 1) - goto err; - } else { - al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, - SSL_R_UNKNOWN_CIPHER_TYPE); - goto f_err; - } - - return (1); - - f_err: - ssl3_send_alert(s, SSL3_AL_FATAL, al); - err: - return (-1); -} - -int -ssl3_get_cert_verify(SSL *s) -{ - EVP_PKEY *pkey = NULL; - unsigned char *p; - int al, ok, ret = 0; - long n; - int type = 0, i, j; - X509 *peer; - const EVP_MD *md = NULL; - EVP_MD_CTX mctx; - EVP_MD_CTX_init(&mctx); - - n = s->method->internal->ssl_get_message(s, SSL3_ST_SR_CERT_VRFY_A, - SSL3_ST_SR_CERT_VRFY_B, -1, SSL3_RT_MAX_PLAIN_LENGTH, &ok); - if (!ok) - return ((int)n); - - if (s->session->peer != NULL) { - peer = s->session->peer; - pkey = X509_get_pubkey(peer); - type = X509_certificate_type(peer, pkey); - } else { - peer = NULL; - pkey = NULL; - } - - if (S3I(s)->tmp.message_type != SSL3_MT_CERTIFICATE_VERIFY) { - S3I(s)->tmp.reuse_message = 1; - if (peer != NULL) { - al = SSL_AD_UNEXPECTED_MESSAGE; - SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, - SSL_R_MISSING_VERIFY_MESSAGE); - goto f_err; - } - ret = 1; - goto end; - } - - if (peer == NULL) { - SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, - SSL_R_NO_CLIENT_CERT_RECEIVED); - al = SSL_AD_UNEXPECTED_MESSAGE; - goto f_err; - } - - if (!(type & EVP_PKT_SIGN)) { - SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, - SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE); - al = SSL_AD_ILLEGAL_PARAMETER; - goto f_err; - } - - if (S3I(s)->change_cipher_spec) { - SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, - SSL_R_CCS_RECEIVED_EARLY); - al = SSL_AD_UNEXPECTED_MESSAGE; - goto f_err; - } - - /* we now have a signature that we need to verify */ - p = (unsigned char *)s->internal->init_msg; - /* - * Check for broken implementations of GOST ciphersuites. - * - * If key is GOST and n is exactly 64, it is a bare - * signature without length field. - */ - if (n == 64 && (pkey->type == NID_id_GostR3410_94 || - pkey->type == NID_id_GostR3410_2001) ) { - i = 64; - } else { - if (SSL_USE_SIGALGS(s)) { - int sigalg = tls12_get_sigid(pkey); - /* Should never happen */ - if (sigalg == -1) { - SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, - ERR_R_INTERNAL_ERROR); - al = SSL_AD_INTERNAL_ERROR; - goto f_err; - } - if (2 > n) - goto truncated; - /* Check key type is consistent with signature */ - if (sigalg != (int)p[1]) { - SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, - SSL_R_WRONG_SIGNATURE_TYPE); - al = SSL_AD_DECODE_ERROR; - goto f_err; - } - md = tls12_get_hash(p[0]); - if (md == NULL) { - SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, - SSL_R_UNKNOWN_DIGEST); - al = SSL_AD_DECODE_ERROR; - goto f_err; - } - p += 2; - n -= 2; - } - if (2 > n) - goto truncated; - n2s(p, i); - n -= 2; - if (i > n) - goto truncated; - } - j = EVP_PKEY_size(pkey); - if ((i > j) || (n > j) || (n <= 0)) { - SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, - SSL_R_WRONG_SIGNATURE_SIZE); - al = SSL_AD_DECODE_ERROR; - goto f_err; - } - - if (SSL_USE_SIGALGS(s)) { - long hdatalen = 0; - void *hdata; - hdatalen = BIO_get_mem_data(S3I(s)->handshake_buffer, &hdata); - if (hdatalen <= 0) { - SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, - ERR_R_INTERNAL_ERROR); - al = SSL_AD_INTERNAL_ERROR; - goto f_err; - } - if (!EVP_VerifyInit_ex(&mctx, md, NULL) || - !EVP_VerifyUpdate(&mctx, hdata, hdatalen)) { - SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, - ERR_R_EVP_LIB); - al = SSL_AD_INTERNAL_ERROR; - goto f_err; - } - - if (EVP_VerifyFinal(&mctx, p, i, pkey) <= 0) { - al = SSL_AD_DECRYPT_ERROR; - SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, - SSL_R_BAD_SIGNATURE); - goto f_err; - } - } else - if (pkey->type == EVP_PKEY_RSA) { - i = RSA_verify(NID_md5_sha1, S3I(s)->tmp.cert_verify_md, - MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH, p, i, - pkey->pkey.rsa); - if (i < 0) { - al = SSL_AD_DECRYPT_ERROR; - SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, - SSL_R_BAD_RSA_DECRYPT); - goto f_err; - } - if (i == 0) { - al = SSL_AD_DECRYPT_ERROR; - SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, - SSL_R_BAD_RSA_SIGNATURE); - goto f_err; - } - } else - if (pkey->type == EVP_PKEY_DSA) { - j = DSA_verify(pkey->save_type, - &(S3I(s)->tmp.cert_verify_md[MD5_DIGEST_LENGTH]), - SHA_DIGEST_LENGTH, p, i, pkey->pkey.dsa); - if (j <= 0) { - /* bad signature */ - al = SSL_AD_DECRYPT_ERROR; - SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, - SSL_R_BAD_DSA_SIGNATURE); - goto f_err; - } - } else - if (pkey->type == EVP_PKEY_EC) { - j = ECDSA_verify(pkey->save_type, - &(S3I(s)->tmp.cert_verify_md[MD5_DIGEST_LENGTH]), - SHA_DIGEST_LENGTH, p, i, pkey->pkey.ec); - if (j <= 0) { - /* bad signature */ - al = SSL_AD_DECRYPT_ERROR; - SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, - SSL_R_BAD_ECDSA_SIGNATURE); - goto f_err; - } - } else -#ifndef OPENSSL_NO_GOST - if (pkey->type == NID_id_GostR3410_94 || - pkey->type == NID_id_GostR3410_2001) { - long hdatalen = 0; - void *hdata; - unsigned char signature[128]; - unsigned int siglen = sizeof(signature); - int nid; - EVP_PKEY_CTX *pctx; - - hdatalen = BIO_get_mem_data(S3I(s)->handshake_buffer, &hdata); - if (hdatalen <= 0) { - SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, - ERR_R_INTERNAL_ERROR); - al = SSL_AD_INTERNAL_ERROR; - goto f_err; - } - if (!EVP_PKEY_get_default_digest_nid(pkey, &nid) || - !(md = EVP_get_digestbynid(nid))) { - SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, - ERR_R_EVP_LIB); - al = SSL_AD_INTERNAL_ERROR; - goto f_err; - } - pctx = EVP_PKEY_CTX_new(pkey, NULL); - if (!pctx) { - SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, - ERR_R_EVP_LIB); - al = SSL_AD_INTERNAL_ERROR; - goto f_err; - } - if (!EVP_DigestInit_ex(&mctx, md, NULL) || - !EVP_DigestUpdate(&mctx, hdata, hdatalen) || - !EVP_DigestFinal(&mctx, signature, &siglen) || - (EVP_PKEY_verify_init(pctx) <= 0) || - (EVP_PKEY_CTX_set_signature_md(pctx, md) <= 0) || - (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_VERIFY, - EVP_PKEY_CTRL_GOST_SIG_FORMAT, - GOST_SIG_FORMAT_RS_LE, - NULL) <= 0)) { - SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, - ERR_R_EVP_LIB); - al = SSL_AD_INTERNAL_ERROR; - EVP_PKEY_CTX_free(pctx); - goto f_err; - } - - if (EVP_PKEY_verify(pctx, p, i, signature, siglen) <= 0) { - al = SSL_AD_DECRYPT_ERROR; - SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, - SSL_R_BAD_SIGNATURE); - EVP_PKEY_CTX_free(pctx); - goto f_err; - } - - EVP_PKEY_CTX_free(pctx); - } else -#endif - { - SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, - ERR_R_INTERNAL_ERROR); - al = SSL_AD_UNSUPPORTED_CERTIFICATE; - goto f_err; - } - - - ret = 1; - if (0) { -truncated: - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, SSL_R_BAD_PACKET_LENGTH); -f_err: - ssl3_send_alert(s, SSL3_AL_FATAL, al); - } -end: - if (S3I(s)->handshake_buffer) { - BIO_free(S3I(s)->handshake_buffer); - S3I(s)->handshake_buffer = NULL; - s->s3->flags &= ~TLS1_FLAGS_KEEP_HANDSHAKE; - } - EVP_MD_CTX_cleanup(&mctx); - EVP_PKEY_free(pkey); - return (ret); -} - -int -ssl3_get_client_certificate(SSL *s) -{ - CBS cbs, client_certs; - int i, ok, al, ret = -1; - X509 *x = NULL; - long n; - const unsigned char *q; - STACK_OF(X509) *sk = NULL; - - n = s->method->internal->ssl_get_message(s, SSL3_ST_SR_CERT_A, SSL3_ST_SR_CERT_B, - -1, s->internal->max_cert_list, &ok); - - if (!ok) - return ((int)n); - - if (S3I(s)->tmp.message_type == SSL3_MT_CLIENT_KEY_EXCHANGE) { - if ((s->verify_mode & SSL_VERIFY_PEER) && - (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) { - SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, - SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE); - al = SSL_AD_HANDSHAKE_FAILURE; - goto f_err; - } - /* - * If tls asked for a client cert, - * the client must return a 0 list. - */ - if (S3I(s)->tmp.cert_request) { - SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, - SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST - ); - al = SSL_AD_UNEXPECTED_MESSAGE; - goto f_err; - } - S3I(s)->tmp.reuse_message = 1; - return (1); - } - - if (S3I(s)->tmp.message_type != SSL3_MT_CERTIFICATE) { - al = SSL_AD_UNEXPECTED_MESSAGE; - SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, - SSL_R_WRONG_MESSAGE_TYPE); - goto f_err; - } - - if (n < 0) - goto truncated; - - CBS_init(&cbs, s->internal->init_msg, n); - - if ((sk = sk_X509_new_null()) == NULL) { - SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, - ERR_R_MALLOC_FAILURE); - goto err; - } - - if (!CBS_get_u24_length_prefixed(&cbs, &client_certs) || - CBS_len(&cbs) != 0) - goto truncated; - - while (CBS_len(&client_certs) > 0) { - CBS cert; - - if (!CBS_get_u24_length_prefixed(&client_certs, &cert)) { - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, - SSL_R_CERT_LENGTH_MISMATCH); - goto f_err; - } - - q = CBS_data(&cert); - x = d2i_X509(NULL, &q, CBS_len(&cert)); - if (x == NULL) { - SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, - ERR_R_ASN1_LIB); - goto err; - } - if (q != CBS_data(&cert) + CBS_len(&cert)) { - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, - SSL_R_CERT_LENGTH_MISMATCH); - goto f_err; - } - if (!sk_X509_push(sk, x)) { - SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, - ERR_R_MALLOC_FAILURE); - goto err; - } - x = NULL; - } - - if (sk_X509_num(sk) <= 0) { - /* - * TLS does not mind 0 certs returned. - * Fail for TLS only if we required a certificate. - */ - if ((s->verify_mode & SSL_VERIFY_PEER) && - (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) { - SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, - SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE); - al = SSL_AD_HANDSHAKE_FAILURE; - goto f_err; - } - /* No client certificate so digest cached records */ - if (S3I(s)->handshake_buffer && !tls1_digest_cached_records(s)) { - al = SSL_AD_INTERNAL_ERROR; - goto f_err; - } - } else { - i = ssl_verify_cert_chain(s, sk); - if (i <= 0) { - al = ssl_verify_alarm_type(s->verify_result); - SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, - SSL_R_NO_CERTIFICATE_RETURNED); - goto f_err; - } - } - - X509_free(s->session->peer); - s->session->peer = sk_X509_shift(sk); - s->session->verify_result = s->verify_result; - - /* - * With the current implementation, sess_cert will always be NULL - * when we arrive here - */ - if (SSI(s)->sess_cert == NULL) { - SSI(s)->sess_cert = ssl_sess_cert_new(); - if (SSI(s)->sess_cert == NULL) { - SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, - ERR_R_MALLOC_FAILURE); - goto err; - } - } - sk_X509_pop_free(SSI(s)->sess_cert->cert_chain, X509_free); - SSI(s)->sess_cert->cert_chain = sk; - - /* - * Inconsistency alert: cert_chain does *not* include the - * peer's own certificate, while we do include it in s3_clnt.c - */ - - sk = NULL; - - ret = 1; - if (0) { -truncated: - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, - SSL_R_BAD_PACKET_LENGTH); -f_err: - ssl3_send_alert(s, SSL3_AL_FATAL, al); - } -err: - X509_free(x); - sk_X509_pop_free(sk, X509_free); - - return (ret); -} - -int -ssl3_send_server_certificate(SSL *s) -{ - CBB cbb, server_cert; - X509 *x; - - /* - * Server Certificate - RFC 5246, section 7.4.2. - */ - - memset(&cbb, 0, sizeof(cbb)); - - if (s->internal->state == SSL3_ST_SW_CERT_A) { - if ((x = ssl_get_server_send_cert(s)) == NULL) { - SSLerr(SSL_F_SSL3_SEND_SERVER_CERTIFICATE, - ERR_R_INTERNAL_ERROR); - return (0); - } - - if (!ssl3_handshake_msg_start_cbb(s, &cbb, &server_cert, - SSL3_MT_CERTIFICATE)) - goto err; - if (!ssl3_output_cert_chain(s, &server_cert, x)) - goto err; - if (!ssl3_handshake_msg_finish_cbb(s, &cbb)) - goto err; - - s->internal->state = SSL3_ST_SW_CERT_B; - } - - /* SSL3_ST_SW_CERT_B */ - return (ssl3_handshake_write(s)); - - err: - CBB_cleanup(&cbb); - - return (0); -} - -/* send a new session ticket (not necessarily for a new session) */ -int -ssl3_send_newsession_ticket(SSL *s) -{ - unsigned char *d, *p, *macstart; - unsigned char *senc = NULL; - const unsigned char *const_p; - int len, slen_full, slen; - SSL_SESSION *sess; - unsigned int hlen; - EVP_CIPHER_CTX ctx; - HMAC_CTX hctx; - SSL_CTX *tctx = s->initial_ctx; - unsigned char iv[EVP_MAX_IV_LENGTH]; - unsigned char key_name[16]; - - if (s->internal->state == SSL3_ST_SW_SESSION_TICKET_A) { - /* get session encoding length */ - slen_full = i2d_SSL_SESSION(s->session, NULL); - /* - * Some length values are 16 bits, so forget it if session is - * too long - */ - if (slen_full > 0xFF00) - goto err; - senc = malloc(slen_full); - if (!senc) - goto err; - p = senc; - i2d_SSL_SESSION(s->session, &p); - - /* - * Create a fresh copy (not shared with other threads) to - * clean up - */ - const_p = senc; - sess = d2i_SSL_SESSION(NULL, &const_p, slen_full); - if (sess == NULL) - goto err; - - /* ID is irrelevant for the ticket */ - sess->session_id_length = 0; - - slen = i2d_SSL_SESSION(sess, NULL); - if (slen > slen_full) { - /* shouldn't ever happen */ - goto err; - } - p = senc; - i2d_SSL_SESSION(sess, &p); - SSL_SESSION_free(sess); - - /* - * Grow buffer if need be: the length calculation is as - * follows 1 (size of message name) + 3 (message length - * bytes) + 4 (ticket lifetime hint) + 2 (ticket length) + - * 16 (key name) + max_iv_len (iv length) + - * session_length + max_enc_block_size (max encrypted session - * length) + max_md_size (HMAC). - */ - if (!BUF_MEM_grow(s->internal->init_buf, ssl3_handshake_msg_hdr_len(s) + - 22 + EVP_MAX_IV_LENGTH + EVP_MAX_BLOCK_LENGTH + - EVP_MAX_MD_SIZE + slen)) - goto err; - - d = p = ssl3_handshake_msg_start(s, SSL3_MT_NEWSESSION_TICKET); - - EVP_CIPHER_CTX_init(&ctx); - HMAC_CTX_init(&hctx); - - /* - * Initialize HMAC and cipher contexts. If callback present - * it does all the work otherwise use generated values - * from parent ctx. - */ - if (tctx->internal->tlsext_ticket_key_cb) { - if (tctx->internal->tlsext_ticket_key_cb(s, - key_name, iv, &ctx, &hctx, 1) < 0) { - EVP_CIPHER_CTX_cleanup(&ctx); - goto err; - } - } else { - arc4random_buf(iv, 16); - EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, - tctx->internal->tlsext_tick_aes_key, iv); - HMAC_Init_ex(&hctx, tctx->internal->tlsext_tick_hmac_key, - 16, tlsext_tick_md(), NULL); - memcpy(key_name, tctx->internal->tlsext_tick_key_name, 16); - } - - /* - * Ticket lifetime hint (advisory only): - * We leave this unspecified for resumed session - * (for simplicity), and guess that tickets for new - * sessions will live as long as their sessions. - */ - l2n(s->internal->hit ? 0 : s->session->timeout, p); - - /* Skip ticket length for now */ - p += 2; - /* Output key name */ - macstart = p; - memcpy(p, key_name, 16); - p += 16; - /* output IV */ - memcpy(p, iv, EVP_CIPHER_CTX_iv_length(&ctx)); - p += EVP_CIPHER_CTX_iv_length(&ctx); - /* Encrypt session data */ - EVP_EncryptUpdate(&ctx, p, &len, senc, slen); - p += len; - EVP_EncryptFinal_ex(&ctx, p, &len); - p += len; - EVP_CIPHER_CTX_cleanup(&ctx); - - HMAC_Update(&hctx, macstart, p - macstart); - HMAC_Final(&hctx, p, &hlen); - HMAC_CTX_cleanup(&hctx); - p += hlen; - - /* Now write out lengths: p points to end of data written */ - /* Total length */ - len = p - d; - - /* Skip ticket lifetime hint. */ - p = d + 4; - s2n(len - 6, p); /* Message length */ - - ssl3_handshake_msg_finish(s, len); - - s->internal->state = SSL3_ST_SW_SESSION_TICKET_B; - - explicit_bzero(senc, slen_full); - free(senc); - } - - /* SSL3_ST_SW_SESSION_TICKET_B */ - return (ssl3_handshake_write(s)); - - err: - if (senc != NULL) - explicit_bzero(senc, slen_full); - free(senc); - - return (-1); -} - -int -ssl3_send_cert_status(SSL *s) -{ - unsigned char *p; - - if (s->internal->state == SSL3_ST_SW_CERT_STATUS_A) { - /* - * Grow buffer if need be: the length calculation is as - * follows 1 (message type) + 3 (message length) + - * 1 (ocsp response type) + 3 (ocsp response length) - * + (ocsp response) - */ - if (!BUF_MEM_grow(s->internal->init_buf, SSL3_HM_HEADER_LENGTH + 4 + - s->internal->tlsext_ocsp_resplen)) - return (-1); - - p = ssl3_handshake_msg_start(s, SSL3_MT_CERTIFICATE_STATUS); - - *(p++) = s->tlsext_status_type; - l2n3(s->internal->tlsext_ocsp_resplen, p); - memcpy(p, s->internal->tlsext_ocsp_resp, s->internal->tlsext_ocsp_resplen); - - ssl3_handshake_msg_finish(s, s->internal->tlsext_ocsp_resplen + 4); - - s->internal->state = SSL3_ST_SW_CERT_STATUS_B; - } - - /* SSL3_ST_SW_CERT_STATUS_B */ - return (ssl3_handshake_write(s)); -} - -/* - * ssl3_get_next_proto reads a Next Protocol Negotiation handshake message. - * It sets the next_proto member in s if found - */ -int -ssl3_get_next_proto(SSL *s) -{ - CBS cbs, proto, padding; - int ok; - long n; - size_t len; - - /* - * Clients cannot send a NextProtocol message if we didn't see the - * extension in their ClientHello - */ - if (!S3I(s)->next_proto_neg_seen) { - SSLerr(SSL_F_SSL3_GET_NEXT_PROTO, - SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION); - return (-1); - } - - /* 514 maxlen is enough for the payload format below */ - n = s->method->internal->ssl_get_message(s, SSL3_ST_SR_NEXT_PROTO_A, - SSL3_ST_SR_NEXT_PROTO_B, SSL3_MT_NEXT_PROTO, 514, &ok); - if (!ok) - return ((int)n); - - /* - * s->internal->state doesn't reflect whether ChangeCipherSpec has been received - * in this handshake, but S3I(s)->change_cipher_spec does (will be reset - * by ssl3_get_finished). - */ - if (!S3I(s)->change_cipher_spec) { - SSLerr(SSL_F_SSL3_GET_NEXT_PROTO, - SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS); - return (-1); - } - - if (n < 2) - return (0); - /* The body must be > 1 bytes long */ - - CBS_init(&cbs, s->internal->init_msg, s->internal->init_num); - - /* - * The payload looks like: - * uint8 proto_len; - * uint8 proto[proto_len]; - * uint8 padding_len; - * uint8 padding[padding_len]; - */ - if (!CBS_get_u8_length_prefixed(&cbs, &proto) || - !CBS_get_u8_length_prefixed(&cbs, &padding) || - CBS_len(&cbs) != 0) - return 0; - - /* - * XXX We should not NULL it, but this matches old behavior of not - * freeing before malloc. - */ - s->internal->next_proto_negotiated = NULL; - s->internal->next_proto_negotiated_len = 0; - - if (!CBS_stow(&proto, &s->internal->next_proto_negotiated, &len)) { - SSLerr(SSL_F_SSL3_GET_NEXT_PROTO, - ERR_R_MALLOC_FAILURE); - return (0); - } - s->internal->next_proto_negotiated_len = (uint8_t)len; - - return (1); -} diff --git a/src/lib/libssl/ssl_both.c b/src/lib/libssl/ssl_both.c new file mode 100644 index 0000000000..e556e336ed --- /dev/null +++ b/src/lib/libssl/ssl_both.c @@ -0,0 +1,748 @@ +/* $OpenBSD: ssl_both.c,v 1.1 2017/01/26 05:51:54 jsing Exp $ */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * ECC cipher suite support in OpenSSL originally developed by + * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. + */ + +#include +#include +#include + +#include "ssl_locl.h" + +#include +#include +#include +#include + +#include "bytestring.h" + +/* + * Send s->internal->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or + * SSL3_RT_CHANGE_CIPHER_SPEC). + */ +int +ssl3_do_write(SSL *s, int type) +{ + int ret; + + ret = ssl3_write_bytes(s, type, &s->internal->init_buf->data[s->internal->init_off], + s->internal->init_num); + if (ret < 0) + return (-1); + + if (type == SSL3_RT_HANDSHAKE) + /* + * Should not be done for 'Hello Request's, but in that case + * we'll ignore the result anyway. + */ + tls1_finish_mac(s, + (unsigned char *)&s->internal->init_buf->data[s->internal->init_off], ret); + + if (ret == s->internal->init_num) { + if (s->internal->msg_callback) + s->internal->msg_callback(1, s->version, type, s->internal->init_buf->data, + (size_t)(s->internal->init_off + s->internal->init_num), s, + s->internal->msg_callback_arg); + return (1); + } + + s->internal->init_off += ret; + s->internal->init_num -= ret; + + return (0); +} + +int +ssl3_send_finished(SSL *s, int a, int b, const char *sender, int slen) +{ + unsigned char *p; + int md_len; + + if (s->internal->state == a) { + md_len = s->method->internal->ssl3_enc->finish_mac_length; + OPENSSL_assert(md_len <= EVP_MAX_MD_SIZE); + + if (s->method->internal->ssl3_enc->final_finish_mac(s, sender, slen, + S3I(s)->tmp.finish_md) != md_len) + return (0); + S3I(s)->tmp.finish_md_len = md_len; + + /* Copy finished so we can use it for renegotiation checks. */ + if (s->internal->type == SSL_ST_CONNECT) { + memcpy(S3I(s)->previous_client_finished, + S3I(s)->tmp.finish_md, md_len); + S3I(s)->previous_client_finished_len = md_len; + } else { + memcpy(S3I(s)->previous_server_finished, + S3I(s)->tmp.finish_md, md_len); + S3I(s)->previous_server_finished_len = md_len; + } + + p = ssl3_handshake_msg_start(s, SSL3_MT_FINISHED); + memcpy(p, S3I(s)->tmp.finish_md, md_len); + ssl3_handshake_msg_finish(s, md_len); + + s->internal->state = b; + } + + return (ssl3_handshake_write(s)); +} + +/* + * ssl3_take_mac calculates the Finished MAC for the handshakes messages seen + * so far. + */ +static void +ssl3_take_mac(SSL *s) +{ + const char *sender; + int slen; + + /* + * If no new cipher setup return immediately: other functions will + * set the appropriate error. + */ + if (S3I(s)->tmp.new_cipher == NULL) + return; + + if (s->internal->state & SSL_ST_CONNECT) { + sender = s->method->internal->ssl3_enc->server_finished_label; + slen = s->method->internal->ssl3_enc->server_finished_label_len; + } else { + sender = s->method->internal->ssl3_enc->client_finished_label; + slen = s->method->internal->ssl3_enc->client_finished_label_len; + } + + S3I(s)->tmp.peer_finish_md_len = + s->method->internal->ssl3_enc->final_finish_mac(s, sender, slen, + S3I(s)->tmp.peer_finish_md); +} + +int +ssl3_get_finished(SSL *s, int a, int b) +{ + int al, ok, md_len; + long n; + CBS cbs; + + /* should actually be 36+4 :-) */ + n = s->method->internal->ssl_get_message(s, a, b, SSL3_MT_FINISHED, 64, &ok); + if (!ok) + return ((int)n); + + /* If this occurs, we have missed a message */ + if (!S3I(s)->change_cipher_spec) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_SSL3_GET_FINISHED, SSL_R_GOT_A_FIN_BEFORE_A_CCS); + goto f_err; + } + S3I(s)->change_cipher_spec = 0; + + md_len = s->method->internal->ssl3_enc->finish_mac_length; + + if (n < 0) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_FINISHED, SSL_R_BAD_DIGEST_LENGTH); + goto f_err; + } + + CBS_init(&cbs, s->internal->init_msg, n); + + if (S3I(s)->tmp.peer_finish_md_len != md_len || + CBS_len(&cbs) != md_len) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_FINISHED, SSL_R_BAD_DIGEST_LENGTH); + goto f_err; + } + + if (!CBS_mem_equal(&cbs, S3I(s)->tmp.peer_finish_md, CBS_len(&cbs))) { + al = SSL_AD_DECRYPT_ERROR; + SSLerr(SSL_F_SSL3_GET_FINISHED, SSL_R_DIGEST_CHECK_FAILED); + goto f_err; + } + + /* Copy finished so we can use it for renegotiation checks. */ + OPENSSL_assert(md_len <= EVP_MAX_MD_SIZE); + if (s->internal->type == SSL_ST_ACCEPT) { + memcpy(S3I(s)->previous_client_finished, + S3I(s)->tmp.peer_finish_md, md_len); + S3I(s)->previous_client_finished_len = md_len; + } else { + memcpy(S3I(s)->previous_server_finished, + S3I(s)->tmp.peer_finish_md, md_len); + S3I(s)->previous_server_finished_len = md_len; + } + + return (1); +f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + return (0); +} + +/* for these 2 messages, we need to + * ssl->enc_read_ctx re-init + * ssl->s3->internal->read_sequence zero + * ssl->s3->internal->read_mac_secret re-init + * ssl->session->read_sym_enc assign + * ssl->session->read_hash assign + */ +int +ssl3_send_change_cipher_spec(SSL *s, int a, int b) +{ + unsigned char *p; + + if (s->internal->state == a) { + p = (unsigned char *)s->internal->init_buf->data; + *p = SSL3_MT_CCS; + s->internal->init_num = 1; + s->internal->init_off = 0; + + s->internal->state = b; + } + + /* SSL3_ST_CW_CHANGE_B */ + return (ssl3_do_write(s, SSL3_RT_CHANGE_CIPHER_SPEC)); +} + +static int +ssl3_add_cert(CBB *cbb, X509 *x) +{ + unsigned char *data; + int cert_len; + int ret = 0; + CBB cert; + + if ((cert_len = i2d_X509(x, NULL)) < 0) + goto err; + + if (!CBB_add_u24_length_prefixed(cbb, &cert)) + goto err; + if (!CBB_add_space(&cert, &data, cert_len)) + goto err; + if (i2d_X509(x, &data) < 0) + goto err; + if (!CBB_flush(cbb)) + goto err; + + ret = 1; + + err: + return (ret); +} + +int +ssl3_output_cert_chain(SSL *s, CBB *cbb, X509 *x) +{ + int no_chain = 0; + CBB cert_list; + int ret = 0; + int i; + + if (!CBB_add_u24_length_prefixed(cbb, &cert_list)) + goto err; + + if ((s->internal->mode & SSL_MODE_NO_AUTO_CHAIN) || s->ctx->extra_certs) + no_chain = 1; + + /* TLSv1 sends a chain with nothing in it, instead of an alert. */ + if (x != NULL) { + if (no_chain) { + if (!ssl3_add_cert(&cert_list, x)) + goto err; + } else { + X509_STORE_CTX xs_ctx; + + if (!X509_STORE_CTX_init(&xs_ctx, s->ctx->cert_store, + x, NULL)) { + SSLerr(SSL_F_SSL3_OUTPUT_CERT_CHAIN, + ERR_R_X509_LIB); + goto err; + } + X509_verify_cert(&xs_ctx); + + /* Don't leave errors in the queue. */ + ERR_clear_error(); + for (i = 0; i < sk_X509_num(xs_ctx.chain); i++) { + x = sk_X509_value(xs_ctx.chain, i); + if (!ssl3_add_cert(&cert_list, x)) { + X509_STORE_CTX_cleanup(&xs_ctx); + goto err; + } + } + X509_STORE_CTX_cleanup(&xs_ctx); + } + } + + /* Thawte special :-) */ + for (i = 0; i < sk_X509_num(s->ctx->extra_certs); i++) { + x = sk_X509_value(s->ctx->extra_certs, i); + if (!ssl3_add_cert(&cert_list, x)) + goto err; + } + + if (!CBB_flush(cbb)) + goto err; + + ret = 1; + + err: + return (ret); +} + +/* + * Obtain handshake message of message type 'mt' (any if mt == -1), + * maximum acceptable body length 'max'. + * The first four bytes (msg_type and length) are read in state 'st1', + * the body is read in state 'stn'. + */ +long +ssl3_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok) +{ + unsigned char *p; + uint32_t l; + long n; + int i, al; + CBS cbs; + uint8_t u8; + + if (S3I(s)->tmp.reuse_message) { + S3I(s)->tmp.reuse_message = 0; + if ((mt >= 0) && (S3I(s)->tmp.message_type != mt)) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_SSL3_GET_MESSAGE, + SSL_R_UNEXPECTED_MESSAGE); + goto f_err; + } + *ok = 1; + s->internal->init_msg = s->internal->init_buf->data + 4; + s->internal->init_num = (int)S3I(s)->tmp.message_size; + return s->internal->init_num; + } + + p = (unsigned char *)s->internal->init_buf->data; + + /* s->internal->init_num < 4 */ + if (s->internal->state == st1) { + int skip_message; + + do { + while (s->internal->init_num < 4) { + i = s->method->internal->ssl_read_bytes(s, + SSL3_RT_HANDSHAKE, &p[s->internal->init_num], + 4 - s->internal->init_num, 0); + if (i <= 0) { + s->internal->rwstate = SSL_READING; + *ok = 0; + return i; + } + s->internal->init_num += i; + } + + skip_message = 0; + if (!s->server && p[0] == SSL3_MT_HELLO_REQUEST) { + /* + * The server may always send 'Hello Request' + * messages -- we are doing a handshake anyway + * now, so ignore them if their format is + * correct. Does not count for 'Finished' MAC. + */ + if (p[1] == 0 && p[2] == 0 &&p[3] == 0) { + s->internal->init_num = 0; + skip_message = 1; + + if (s->internal->msg_callback) + s->internal->msg_callback(0, s->version, + SSL3_RT_HANDSHAKE, p, 4, s, + s->internal->msg_callback_arg); + } + } + } while (skip_message); + + /* s->internal->init_num == 4 */ + + if ((mt >= 0) && (*p != mt)) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_SSL3_GET_MESSAGE, + SSL_R_UNEXPECTED_MESSAGE); + goto f_err; + } + + CBS_init(&cbs, p, 4); + if (!CBS_get_u8(&cbs, &u8) || + !CBS_get_u24(&cbs, &l)) { + SSLerr(SSL_F_SSL3_GET_MESSAGE, ERR_R_BUF_LIB); + goto err; + } + S3I(s)->tmp.message_type = u8; + + if (l > (unsigned long)max) { + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_MESSAGE, + SSL_R_EXCESSIVE_MESSAGE_SIZE); + goto f_err; + } + if (l && !BUF_MEM_grow_clean(s->internal->init_buf, l + 4)) { + SSLerr(SSL_F_SSL3_GET_MESSAGE, ERR_R_BUF_LIB); + goto err; + } + S3I(s)->tmp.message_size = l; + s->internal->state = stn; + + s->internal->init_msg = s->internal->init_buf->data + 4; + s->internal->init_num = 0; + } + + /* next state (stn) */ + p = s->internal->init_msg; + n = S3I(s)->tmp.message_size - s->internal->init_num; + while (n > 0) { + i = s->method->internal->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, + &p[s->internal->init_num], n, 0); + if (i <= 0) { + s->internal->rwstate = SSL_READING; + *ok = 0; + return i; + } + s->internal->init_num += i; + n -= i; + } + + /* If receiving Finished, record MAC of prior handshake messages for + * Finished verification. */ + if (*s->internal->init_buf->data == SSL3_MT_FINISHED) + ssl3_take_mac(s); + + /* Feed this message into MAC computation. */ + if (s->internal->mac_packet) { + tls1_finish_mac(s, (unsigned char *)s->internal->init_buf->data, + s->internal->init_num + 4); + s->internal->mac_packet = 0; + + if (s->internal->msg_callback) + s->internal->msg_callback(0, s->version, + SSL3_RT_HANDSHAKE, s->internal->init_buf->data, + (size_t)s->internal->init_num + 4, s, + s->internal->msg_callback_arg); + } + + *ok = 1; + return (s->internal->init_num); + +f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); +err: + *ok = 0; + return (-1); +} + +int +ssl_cert_type(X509 *x, EVP_PKEY *pkey) +{ + EVP_PKEY *pk; + int ret = -1, i; + + if (pkey == NULL) + pk = X509_get_pubkey(x); + else + pk = pkey; + if (pk == NULL) + goto err; + + i = pk->type; + if (i == EVP_PKEY_RSA) { + ret = SSL_PKEY_RSA_ENC; + } else if (i == EVP_PKEY_DSA) { + ret = SSL_PKEY_DSA_SIGN; + } else if (i == EVP_PKEY_EC) { + ret = SSL_PKEY_ECC; + } else if (i == NID_id_GostR3410_2001 || + i == NID_id_GostR3410_2001_cc) { + ret = SSL_PKEY_GOST01; + } + +err: + if (!pkey) + EVP_PKEY_free(pk); + return (ret); +} + +int +ssl_verify_alarm_type(long type) +{ + int al; + + switch (type) { + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: + case X509_V_ERR_UNABLE_TO_GET_CRL: + case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: + al = SSL_AD_UNKNOWN_CA; + break; + case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: + case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: + case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: + case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: + case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: + case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: + case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: + case X509_V_ERR_CERT_NOT_YET_VALID: + case X509_V_ERR_CRL_NOT_YET_VALID: + case X509_V_ERR_CERT_UNTRUSTED: + case X509_V_ERR_CERT_REJECTED: + al = SSL_AD_BAD_CERTIFICATE; + break; + case X509_V_ERR_CERT_SIGNATURE_FAILURE: + case X509_V_ERR_CRL_SIGNATURE_FAILURE: + al = SSL_AD_DECRYPT_ERROR; + break; + case X509_V_ERR_CERT_HAS_EXPIRED: + case X509_V_ERR_CRL_HAS_EXPIRED: + al = SSL_AD_CERTIFICATE_EXPIRED; + break; + case X509_V_ERR_CERT_REVOKED: + al = SSL_AD_CERTIFICATE_REVOKED; + break; + case X509_V_ERR_OUT_OF_MEM: + al = SSL_AD_INTERNAL_ERROR; + break; + case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: + case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: + case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: + case X509_V_ERR_CERT_CHAIN_TOO_LONG: + case X509_V_ERR_PATH_LENGTH_EXCEEDED: + case X509_V_ERR_INVALID_CA: + al = SSL_AD_UNKNOWN_CA; + break; + case X509_V_ERR_APPLICATION_VERIFICATION: + al = SSL_AD_HANDSHAKE_FAILURE; + break; + case X509_V_ERR_INVALID_PURPOSE: + al = SSL_AD_UNSUPPORTED_CERTIFICATE; + break; + default: + al = SSL_AD_CERTIFICATE_UNKNOWN; + break; + } + return (al); +} + +int +ssl3_setup_init_buffer(SSL *s) +{ + BUF_MEM *buf = NULL; + + if (s->internal->init_buf != NULL) + return (1); + + if ((buf = BUF_MEM_new()) == NULL) + goto err; + if (!BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) + goto err; + + s->internal->init_buf = buf; + return (1); + +err: + BUF_MEM_free(buf); + return (0); +} + +int +ssl3_setup_read_buffer(SSL *s) +{ + unsigned char *p; + size_t len, align, headerlen; + + if (SSL_IS_DTLS(s)) + headerlen = DTLS1_RT_HEADER_LENGTH; + else + headerlen = SSL3_RT_HEADER_LENGTH; + + align = (-SSL3_RT_HEADER_LENGTH) & (SSL3_ALIGN_PAYLOAD - 1); + + if (s->s3->rbuf.buf == NULL) { + len = SSL3_RT_MAX_PLAIN_LENGTH + + SSL3_RT_MAX_ENCRYPTED_OVERHEAD + headerlen + align; + if ((p = malloc(len)) == NULL) + goto err; + s->s3->rbuf.buf = p; + s->s3->rbuf.len = len; + } + + s->internal->packet = &(s->s3->rbuf.buf[0]); + return 1; + +err: + SSLerr(SSL_F_SSL3_SETUP_READ_BUFFER, ERR_R_MALLOC_FAILURE); + return 0; +} + +int +ssl3_setup_write_buffer(SSL *s) +{ + unsigned char *p; + size_t len, align, headerlen; + + if (SSL_IS_DTLS(s)) + headerlen = DTLS1_RT_HEADER_LENGTH + 1; + else + headerlen = SSL3_RT_HEADER_LENGTH; + + align = (-SSL3_RT_HEADER_LENGTH) & (SSL3_ALIGN_PAYLOAD - 1); + + if (s->s3->wbuf.buf == NULL) { + len = s->max_send_fragment + + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD + headerlen + align; + if (!(s->internal->options & SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS)) + len += headerlen + align + + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD; + + if ((p = malloc(len)) == NULL) + goto err; + s->s3->wbuf.buf = p; + s->s3->wbuf.len = len; + } + + return 1; + +err: + SSLerr(SSL_F_SSL3_SETUP_WRITE_BUFFER, ERR_R_MALLOC_FAILURE); + return 0; +} + +int +ssl3_setup_buffers(SSL *s) +{ + if (!ssl3_setup_read_buffer(s)) + return 0; + if (!ssl3_setup_write_buffer(s)) + return 0; + return 1; +} + +int +ssl3_release_write_buffer(SSL *s) +{ + free(s->s3->wbuf.buf); + s->s3->wbuf.buf = NULL; + return 1; +} + +int +ssl3_release_read_buffer(SSL *s) +{ + free(s->s3->rbuf.buf); + s->s3->rbuf.buf = NULL; + return 1; +} diff --git a/src/lib/libssl/ssl_clnt.c b/src/lib/libssl/ssl_clnt.c new file mode 100644 index 0000000000..e7c78b139b --- /dev/null +++ b/src/lib/libssl/ssl_clnt.c @@ -0,0 +1,2795 @@ +/* $OpenBSD: ssl_clnt.c,v 1.1 2017/01/26 05:51:54 jsing Exp $ */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * ECC cipher suite support in OpenSSL originally written by + * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories. + * + */ +/* ==================================================================== + * Copyright 2005 Nokia. All rights reserved. + * + * The portions of the attached software ("Contribution") is developed by + * Nokia Corporation and is licensed pursuant to the OpenSSL open source + * license. + * + * The Contribution, originally written by Mika Kousa and Pasi Eronen of + * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites + * support (see RFC 4279) to OpenSSL. + * + * No patent licenses or other rights except those expressly stated in + * the OpenSSL open source license shall be deemed granted or received + * expressly, by implication, estoppel, or otherwise. + * + * No assurances are provided by Nokia that the Contribution does not + * infringe the patent or other intellectual property rights of any third + * party or that the license provides you with all the necessary rights + * to make use of the Contribution. + * + * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN + * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA + * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY + * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR + * OTHERWISE. + */ + +#include +#include +#include + +#include "ssl_locl.h" + +#include +#include +#include +#include +#include +#include +#include + +#ifndef OPENSSL_NO_ENGINE +#include +#endif +#ifndef OPENSSL_NO_GOST +#include +#endif + +#include "bytestring.h" + +static int ca_dn_cmp(const X509_NAME * const *a, const X509_NAME * const *b); + +int +ssl3_connect(SSL *s) +{ + void (*cb)(const SSL *ssl, int type, int val) = NULL; + int ret = -1; + int new_state, state, skip = 0; + + ERR_clear_error(); + errno = 0; + + if (s->internal->info_callback != NULL) + cb = s->internal->info_callback; + else if (s->ctx->internal->info_callback != NULL) + cb = s->ctx->internal->info_callback; + + s->internal->in_handshake++; + if (!SSL_in_init(s) || SSL_in_before(s)) + SSL_clear(s); + + for (;;) { + state = s->internal->state; + + switch (s->internal->state) { + case SSL_ST_RENEGOTIATE: + s->internal->renegotiate = 1; + s->internal->state = SSL_ST_CONNECT; + s->ctx->internal->stats.sess_connect_renegotiate++; + /* break */ + case SSL_ST_BEFORE: + case SSL_ST_CONNECT: + case SSL_ST_BEFORE|SSL_ST_CONNECT: + case SSL_ST_OK|SSL_ST_CONNECT: + + s->server = 0; + if (cb != NULL) + cb(s, SSL_CB_HANDSHAKE_START, 1); + + if ((s->version & 0xff00 ) != 0x0300) { + SSLerr(SSL_F_SSL3_CONNECT, + ERR_R_INTERNAL_ERROR); + ret = -1; + goto end; + } + + /* s->version=SSL3_VERSION; */ + s->internal->type = SSL_ST_CONNECT; + + if (!ssl3_setup_init_buffer(s)) { + ret = -1; + goto end; + } + if (!ssl3_setup_buffers(s)) { + ret = -1; + goto end; + } + if (!ssl_init_wbio_buffer(s, 0)) { + ret = -1; + goto end; + } + + /* don't push the buffering BIO quite yet */ + + if (!tls1_init_finished_mac(s)) { + ret = -1; + goto end; + } + + s->internal->state = SSL3_ST_CW_CLNT_HELLO_A; + s->ctx->internal->stats.sess_connect++; + s->internal->init_num = 0; + break; + + case SSL3_ST_CW_CLNT_HELLO_A: + case SSL3_ST_CW_CLNT_HELLO_B: + + s->internal->shutdown = 0; + ret = ssl3_client_hello(s); + if (ret <= 0) + goto end; + s->internal->state = SSL3_ST_CR_SRVR_HELLO_A; + s->internal->init_num = 0; + + /* turn on buffering for the next lot of output */ + if (s->bbio != s->wbio) + s->wbio = BIO_push(s->bbio, s->wbio); + + break; + + case SSL3_ST_CR_SRVR_HELLO_A: + case SSL3_ST_CR_SRVR_HELLO_B: + ret = ssl3_get_server_hello(s); + if (ret <= 0) + goto end; + + if (s->internal->hit) { + s->internal->state = SSL3_ST_CR_FINISHED_A; + if (s->internal->tlsext_ticket_expected) { + /* receive renewed session ticket */ + s->internal->state = SSL3_ST_CR_SESSION_TICKET_A; + } + } else + s->internal->state = SSL3_ST_CR_CERT_A; + s->internal->init_num = 0; + break; + + case SSL3_ST_CR_CERT_A: + case SSL3_ST_CR_CERT_B: + ret = ssl3_check_finished(s); + if (ret <= 0) + goto end; + if (ret == 2) { + s->internal->hit = 1; + if (s->internal->tlsext_ticket_expected) + s->internal->state = SSL3_ST_CR_SESSION_TICKET_A; + else + s->internal->state = SSL3_ST_CR_FINISHED_A; + s->internal->init_num = 0; + break; + } + /* Check if it is anon DH/ECDH. */ + if (!(S3I(s)->tmp.new_cipher->algorithm_auth & + SSL_aNULL)) { + ret = ssl3_get_server_certificate(s); + if (ret <= 0) + goto end; + if (s->internal->tlsext_status_expected) + s->internal->state = SSL3_ST_CR_CERT_STATUS_A; + else + s->internal->state = SSL3_ST_CR_KEY_EXCH_A; + } else { + skip = 1; + s->internal->state = SSL3_ST_CR_KEY_EXCH_A; + } + s->internal->init_num = 0; + break; + + case SSL3_ST_CR_KEY_EXCH_A: + case SSL3_ST_CR_KEY_EXCH_B: + ret = ssl3_get_server_key_exchange(s); + if (ret <= 0) + goto end; + s->internal->state = SSL3_ST_CR_CERT_REQ_A; + s->internal->init_num = 0; + + /* + * At this point we check that we have the + * required stuff from the server. + */ + if (!ssl3_check_cert_and_algorithm(s)) { + ret = -1; + goto end; + } + break; + + case SSL3_ST_CR_CERT_REQ_A: + case SSL3_ST_CR_CERT_REQ_B: + ret = ssl3_get_certificate_request(s); + if (ret <= 0) + goto end; + s->internal->state = SSL3_ST_CR_SRVR_DONE_A; + s->internal->init_num = 0; + break; + + case SSL3_ST_CR_SRVR_DONE_A: + case SSL3_ST_CR_SRVR_DONE_B: + ret = ssl3_get_server_done(s); + if (ret <= 0) + goto end; + if (S3I(s)->tmp.cert_req) + s->internal->state = SSL3_ST_CW_CERT_A; + else + s->internal->state = SSL3_ST_CW_KEY_EXCH_A; + s->internal->init_num = 0; + + break; + + case SSL3_ST_CW_CERT_A: + case SSL3_ST_CW_CERT_B: + case SSL3_ST_CW_CERT_C: + case SSL3_ST_CW_CERT_D: + ret = ssl3_send_client_certificate(s); + if (ret <= 0) + goto end; + s->internal->state = SSL3_ST_CW_KEY_EXCH_A; + s->internal->init_num = 0; + break; + + case SSL3_ST_CW_KEY_EXCH_A: + case SSL3_ST_CW_KEY_EXCH_B: + ret = ssl3_send_client_key_exchange(s); + if (ret <= 0) + goto end; + /* + * EAY EAY EAY need to check for DH fix cert + * sent back + */ + /* + * For TLS, cert_req is set to 2, so a cert chain + * of nothing is sent, but no verify packet is sent + */ + /* + * XXX: For now, we do not support client + * authentication in ECDH cipher suites with + * ECDH (rather than ECDSA) certificates. + * We need to skip the certificate verify + * message when client's ECDH public key is sent + * inside the client certificate. + */ + if (S3I(s)->tmp.cert_req == 1) { + s->internal->state = SSL3_ST_CW_CERT_VRFY_A; + } else { + s->internal->state = SSL3_ST_CW_CHANGE_A; + S3I(s)->change_cipher_spec = 0; + } + if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY) { + s->internal->state = SSL3_ST_CW_CHANGE_A; + S3I(s)->change_cipher_spec = 0; + } + + s->internal->init_num = 0; + break; + + case SSL3_ST_CW_CERT_VRFY_A: + case SSL3_ST_CW_CERT_VRFY_B: + ret = ssl3_send_client_verify(s); + if (ret <= 0) + goto end; + s->internal->state = SSL3_ST_CW_CHANGE_A; + s->internal->init_num = 0; + S3I(s)->change_cipher_spec = 0; + break; + + case SSL3_ST_CW_CHANGE_A: + case SSL3_ST_CW_CHANGE_B: + ret = ssl3_send_change_cipher_spec(s, + SSL3_ST_CW_CHANGE_A, SSL3_ST_CW_CHANGE_B); + if (ret <= 0) + goto end; + + if (S3I(s)->next_proto_neg_seen) + s->internal->state = SSL3_ST_CW_NEXT_PROTO_A; + else + s->internal->state = SSL3_ST_CW_FINISHED_A; + s->internal->init_num = 0; + + s->session->cipher = S3I(s)->tmp.new_cipher; + if (!s->method->internal->ssl3_enc->setup_key_block(s)) { + ret = -1; + goto end; + } + + if (!s->method->internal->ssl3_enc->change_cipher_state(s, + SSL3_CHANGE_CIPHER_CLIENT_WRITE)) { + ret = -1; + goto end; + } + + break; + + case SSL3_ST_CW_NEXT_PROTO_A: + case SSL3_ST_CW_NEXT_PROTO_B: + ret = ssl3_send_next_proto(s); + if (ret <= 0) + goto end; + s->internal->state = SSL3_ST_CW_FINISHED_A; + break; + + case SSL3_ST_CW_FINISHED_A: + case SSL3_ST_CW_FINISHED_B: + ret = ssl3_send_finished(s, SSL3_ST_CW_FINISHED_A, + SSL3_ST_CW_FINISHED_B, + s->method->internal->ssl3_enc->client_finished_label, + s->method->internal->ssl3_enc->client_finished_label_len); + if (ret <= 0) + goto end; + s->s3->flags |= SSL3_FLAGS_CCS_OK; + s->internal->state = SSL3_ST_CW_FLUSH; + + /* clear flags */ + s->s3->flags &= ~SSL3_FLAGS_POP_BUFFER; + if (s->internal->hit) { + S3I(s)->tmp.next_state = SSL_ST_OK; + if (s->s3->flags & + SSL3_FLAGS_DELAY_CLIENT_FINISHED) { + s->internal->state = SSL_ST_OK; + s->s3->flags|=SSL3_FLAGS_POP_BUFFER; + S3I(s)->delay_buf_pop_ret = 0; + } + } else { + /* Allow NewSessionTicket if ticket expected */ + if (s->internal->tlsext_ticket_expected) + S3I(s)->tmp.next_state = + SSL3_ST_CR_SESSION_TICKET_A; + else + + S3I(s)->tmp.next_state = SSL3_ST_CR_FINISHED_A; + } + s->internal->init_num = 0; + break; + + case SSL3_ST_CR_SESSION_TICKET_A: + case SSL3_ST_CR_SESSION_TICKET_B: + ret = ssl3_get_new_session_ticket(s); + if (ret <= 0) + goto end; + s->internal->state = SSL3_ST_CR_FINISHED_A; + s->internal->init_num = 0; + break; + + case SSL3_ST_CR_CERT_STATUS_A: + case SSL3_ST_CR_CERT_STATUS_B: + ret = ssl3_get_cert_status(s); + if (ret <= 0) + goto end; + s->internal->state = SSL3_ST_CR_KEY_EXCH_A; + s->internal->init_num = 0; + break; + + case SSL3_ST_CR_FINISHED_A: + case SSL3_ST_CR_FINISHED_B: + s->s3->flags |= SSL3_FLAGS_CCS_OK; + ret = ssl3_get_finished(s, SSL3_ST_CR_FINISHED_A, + SSL3_ST_CR_FINISHED_B); + if (ret <= 0) + goto end; + + if (s->internal->hit) + s->internal->state = SSL3_ST_CW_CHANGE_A; + else + s->internal->state = SSL_ST_OK; + s->internal->init_num = 0; + break; + + case SSL3_ST_CW_FLUSH: + s->internal->rwstate = SSL_WRITING; + if (BIO_flush(s->wbio) <= 0) { + ret = -1; + goto end; + } + s->internal->rwstate = SSL_NOTHING; + s->internal->state = S3I(s)->tmp.next_state; + break; + + case SSL_ST_OK: + /* clean a few things up */ + tls1_cleanup_key_block(s); + + BUF_MEM_free(s->internal->init_buf); + s->internal->init_buf = NULL; + + /* + * If we are not 'joining' the last two packets, + * remove the buffering now + */ + if (!(s->s3->flags & SSL3_FLAGS_POP_BUFFER)) + ssl_free_wbio_buffer(s); + /* else do it later in ssl3_write */ + + s->internal->init_num = 0; + s->internal->renegotiate = 0; + s->internal->new_session = 0; + + ssl_update_cache(s, SSL_SESS_CACHE_CLIENT); + if (s->internal->hit) + s->ctx->internal->stats.sess_hit++; + + ret = 1; + /* s->server=0; */ + s->internal->handshake_func = ssl3_connect; + s->ctx->internal->stats.sess_connect_good++; + + if (cb != NULL) + cb(s, SSL_CB_HANDSHAKE_DONE, 1); + + goto end; + /* break; */ + + default: + SSLerr(SSL_F_SSL3_CONNECT, + SSL_R_UNKNOWN_STATE); + ret = -1; + goto end; + /* break; */ + } + + /* did we do anything */ + if (!S3I(s)->tmp.reuse_message && !skip) { + if (s->internal->debug) { + if ((ret = BIO_flush(s->wbio)) <= 0) + goto end; + } + + if ((cb != NULL) && (s->internal->state != state)) { + new_state = s->internal->state; + s->internal->state = state; + cb(s, SSL_CB_CONNECT_LOOP, 1); + s->internal->state = new_state; + } + } + skip = 0; + } + +end: + s->internal->in_handshake--; + if (cb != NULL) + cb(s, SSL_CB_CONNECT_EXIT, ret); + + return (ret); +} + +int +ssl3_client_hello(SSL *s) +{ + unsigned char *bufend, *p, *d; + uint16_t max_version; + size_t outlen; + int i; + + bufend = (unsigned char *)s->internal->init_buf->data + SSL3_RT_MAX_PLAIN_LENGTH; + + if (s->internal->state == SSL3_ST_CW_CLNT_HELLO_A) { + SSL_SESSION *sess = s->session; + + if (ssl_supported_version_range(s, NULL, &max_version) != 1) { + SSLerr(SSL_F_SSL3_CLIENT_HELLO, + SSL_R_NO_PROTOCOLS_AVAILABLE); + return (-1); + } + s->client_version = s->version = max_version; + + if ((sess == NULL) || + (sess->ssl_version != s->version) || + (!sess->session_id_length && !sess->tlsext_tick) || + (sess->internal->not_resumable)) { + if (!ssl_get_new_session(s, 0)) + goto err; + } + /* else use the pre-loaded session */ + + /* + * If a DTLS ClientHello message is being resent after a + * HelloVerifyRequest, we must retain the original client + * random value. + */ + if (!SSL_IS_DTLS(s) || D1I(s)->send_cookie == 0) + arc4random_buf(s->s3->client_random, SSL3_RANDOM_SIZE); + + d = p = ssl3_handshake_msg_start(s, SSL3_MT_CLIENT_HELLO); + + /* + * Version indicates the negotiated version: for example from + * an SSLv2/v3 compatible client hello). The client_version + * field is the maximum version we permit and it is also + * used in RSA encrypted premaster secrets. Some servers can + * choke if we initially report a higher version then + * renegotiate to a lower one in the premaster secret. This + * didn't happen with TLS 1.0 as most servers supported it + * but it can with TLS 1.1 or later if the server only supports + * 1.0. + * + * Possible scenario with previous logic: + * 1. Client hello indicates TLS 1.2 + * 2. Server hello says TLS 1.0 + * 3. RSA encrypted premaster secret uses 1.2. + * 4. Handhaked proceeds using TLS 1.0. + * 5. Server sends hello request to renegotiate. + * 6. Client hello indicates TLS v1.0 as we now + * know that is maximum server supports. + * 7. Server chokes on RSA encrypted premaster secret + * containing version 1.0. + * + * For interoperability it should be OK to always use the + * maximum version we support in client hello and then rely + * on the checking of version to ensure the servers isn't + * being inconsistent: for example initially negotiating with + * TLS 1.0 and renegotiating with TLS 1.2. We do this by using + * client_version in client hello and not resetting it to + * the negotiated version. + */ + + *(p++) = s->client_version >> 8; + *(p++) = s->client_version & 0xff; + + /* Random stuff */ + memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE); + p += SSL3_RANDOM_SIZE; + + /* Session ID */ + if (s->internal->new_session) + i = 0; + else + i = s->session->session_id_length; + *(p++) = i; + if (i != 0) { + if (i > (int)sizeof(s->session->session_id)) { + SSLerr(SSL_F_SSL3_CLIENT_HELLO, + ERR_R_INTERNAL_ERROR); + goto err; + } + memcpy(p, s->session->session_id, i); + p += i; + } + + /* DTLS Cookie. */ + if (SSL_IS_DTLS(s)) { + if (D1I(s)->cookie_len > sizeof(D1I(s)->cookie)) { + SSLerr(SSL_F_DTLS1_CLIENT_HELLO, + ERR_R_INTERNAL_ERROR); + goto err; + } + *(p++) = D1I(s)->cookie_len; + memcpy(p, D1I(s)->cookie, D1I(s)->cookie_len); + p += D1I(s)->cookie_len; + } + + /* Ciphers supported */ + if (!ssl_cipher_list_to_bytes(s, SSL_get_ciphers(s), &p[2], + bufend - &p[2], &outlen)) + goto err; + if (outlen == 0) { + SSLerr(SSL_F_SSL3_CLIENT_HELLO, + SSL_R_NO_CIPHERS_AVAILABLE); + goto err; + } + s2n(outlen, p); + p += outlen; + + /* add in (no) COMPRESSION */ + *(p++) = 1; + *(p++) = 0; /* Add the NULL method */ + + /* TLS extensions*/ + if ((p = ssl_add_clienthello_tlsext(s, p, bufend)) == NULL) { + SSLerr(SSL_F_SSL3_CLIENT_HELLO, + ERR_R_INTERNAL_ERROR); + goto err; + } + + ssl3_handshake_msg_finish(s, p - d); + + s->internal->state = SSL3_ST_CW_CLNT_HELLO_B; + } + + /* SSL3_ST_CW_CLNT_HELLO_B */ + return (ssl3_handshake_write(s)); + +err: + return (-1); +} + +int +ssl3_get_server_hello(SSL *s) +{ + CBS cbs, server_random, session_id; + uint16_t server_version, cipher_suite; + uint16_t min_version, max_version; + uint8_t compression_method; + STACK_OF(SSL_CIPHER) *sk; + const SSL_CIPHER *cipher; + const SSL_METHOD *method; + unsigned char *p; + unsigned long alg_k; + size_t outlen; + int i, al, ok; + long n; + + s->internal->first_packet = 1; + n = s->method->internal->ssl_get_message(s, SSL3_ST_CR_SRVR_HELLO_A, + SSL3_ST_CR_SRVR_HELLO_B, -1, 20000, /* ?? */ &ok); + if (!ok) + return ((int)n); + s->internal->first_packet = 0; + + if (n < 0) + goto truncated; + + CBS_init(&cbs, s->internal->init_msg, n); + + if (SSL_IS_DTLS(s)) { + if (S3I(s)->tmp.message_type == DTLS1_MT_HELLO_VERIFY_REQUEST) { + if (D1I(s)->send_cookie == 0) { + S3I(s)->tmp.reuse_message = 1; + return (1); + } else { + /* Already sent a cookie. */ + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, + SSL_R_BAD_MESSAGE_TYPE); + goto f_err; + } + } + } + + if (S3I(s)->tmp.message_type != SSL3_MT_SERVER_HELLO) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, + SSL_R_BAD_MESSAGE_TYPE); + goto f_err; + } + + if (!CBS_get_u16(&cbs, &server_version)) + goto truncated; + + if (ssl_supported_version_range(s, &min_version, &max_version) != 1) { + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, + SSL_R_NO_PROTOCOLS_AVAILABLE); + goto err; + } + + if (server_version < min_version || server_version > max_version) { + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_WRONG_SSL_VERSION); + s->version = (s->version & 0xff00) | (server_version & 0xff); + al = SSL_AD_PROTOCOL_VERSION; + goto f_err; + } + s->version = server_version; + + if ((method = tls1_get_client_method(server_version)) == NULL) + method = dtls1_get_client_method(server_version); + if (method == NULL) { + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, ERR_R_INTERNAL_ERROR); + goto err; + } + s->method = method; + + /* Server random. */ + if (!CBS_get_bytes(&cbs, &server_random, SSL3_RANDOM_SIZE)) + goto truncated; + if (!CBS_write_bytes(&server_random, s->s3->server_random, + sizeof(s->s3->server_random), NULL)) + goto err; + + /* Session ID. */ + if (!CBS_get_u8_length_prefixed(&cbs, &session_id)) + goto truncated; + + if ((CBS_len(&session_id) > sizeof(s->session->session_id)) || + (CBS_len(&session_id) > SSL3_SESSION_ID_SIZE)) { + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, + SSL_R_SSL3_SESSION_ID_TOO_LONG); + goto f_err; + } + + /* Cipher suite. */ + if (!CBS_get_u16(&cbs, &cipher_suite)) + goto truncated; + + /* + * Check if we want to resume the session based on external + * pre-shared secret. + */ + if (s->internal->tls_session_secret_cb) { + SSL_CIPHER *pref_cipher = NULL; + s->session->master_key_length = sizeof(s->session->master_key); + if (s->internal->tls_session_secret_cb(s, s->session->master_key, + &s->session->master_key_length, NULL, &pref_cipher, + s->internal->tls_session_secret_cb_arg)) { + s->session->cipher = pref_cipher ? pref_cipher : + ssl3_get_cipher_by_value(cipher_suite); + s->s3->flags |= SSL3_FLAGS_CCS_OK; + } + } + + if (s->session->session_id_length != 0 && + CBS_mem_equal(&session_id, s->session->session_id, + s->session->session_id_length)) { + if (s->sid_ctx_length != s->session->sid_ctx_length || + timingsafe_memcmp(s->session->sid_ctx, + s->sid_ctx, s->sid_ctx_length) != 0) { + /* actually a client application bug */ + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, + SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT); + goto f_err; + } + s->s3->flags |= SSL3_FLAGS_CCS_OK; + s->internal->hit = 1; + } else { + /* a miss or crap from the other end */ + + /* If we were trying for session-id reuse, make a new + * SSL_SESSION so we don't stuff up other people */ + s->internal->hit = 0; + if (s->session->session_id_length > 0) { + if (!ssl_get_new_session(s, 0)) { + al = SSL_AD_INTERNAL_ERROR; + goto f_err; + } + } + + /* + * XXX - improve the handling for the case where there is a + * zero length session identifier. + */ + if (!CBS_write_bytes(&session_id, s->session->session_id, + sizeof(s->session->session_id), &outlen)) + goto err; + s->session->session_id_length = outlen; + + s->session->ssl_version = s->version; + } + + if ((cipher = ssl3_get_cipher_by_value(cipher_suite)) == NULL) { + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, + SSL_R_UNKNOWN_CIPHER_RETURNED); + goto f_err; + } + + /* TLS v1.2 only ciphersuites require v1.2 or later. */ + if ((cipher->algorithm_ssl & SSL_TLSV1_2) && + (TLS1_get_version(s) < TLS1_2_VERSION)) { + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, + SSL_R_WRONG_CIPHER_RETURNED); + goto f_err; + } + + sk = ssl_get_ciphers_by_id(s); + i = sk_SSL_CIPHER_find(sk, cipher); + if (i < 0) { + /* we did not say we would use this cipher */ + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, + SSL_R_WRONG_CIPHER_RETURNED); + goto f_err; + } + + /* + * Depending on the session caching (internal/external), the cipher + * and/or cipher_id values may not be set. Make sure that + * cipher_id is set and use it for comparison. + */ + if (s->session->cipher) + s->session->cipher_id = s->session->cipher->id; + if (s->internal->hit && (s->session->cipher_id != cipher->id)) { + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, + SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED); + goto f_err; + } + S3I(s)->tmp.new_cipher = cipher; + + /* + * Don't digest cached records if no sigalgs: we may need them for + * client authentication. + */ + alg_k = S3I(s)->tmp.new_cipher->algorithm_mkey; + if (!(SSL_USE_SIGALGS(s) || (alg_k & SSL_kGOST)) && + !tls1_digest_cached_records(s)) { + al = SSL_AD_INTERNAL_ERROR; + goto f_err; + } + + if (!CBS_get_u8(&cbs, &compression_method)) + goto truncated; + + if (compression_method != 0) { + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, + SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM); + goto f_err; + } + + /* TLS extensions. */ + p = (unsigned char *)CBS_data(&cbs); + if (!ssl_parse_serverhello_tlsext(s, &p, CBS_len(&cbs), &al)) { + /* 'al' set by ssl_parse_serverhello_tlsext */ + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_PARSE_TLSEXT); + goto f_err; + } + if (ssl_check_serverhello_tlsext(s) <= 0) { + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_SERVERHELLO_TLSEXT); + goto err; + } + + /* See if any data remains... */ + if (p - CBS_data(&cbs) != CBS_len(&cbs)) + goto truncated; + + return (1); + +truncated: + /* wrong packet length */ + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_BAD_PACKET_LENGTH); +f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); +err: + return (-1); +} + +int +ssl3_get_server_certificate(SSL *s) +{ + int al, i, ok, ret = -1; + long n; + CBS cbs, cert_list; + X509 *x = NULL; + const unsigned char *q; + STACK_OF(X509) *sk = NULL; + SESS_CERT *sc; + EVP_PKEY *pkey = NULL; + + n = s->method->internal->ssl_get_message(s, SSL3_ST_CR_CERT_A, + SSL3_ST_CR_CERT_B, -1, s->internal->max_cert_list, &ok); + + if (!ok) + return ((int)n); + + if (S3I(s)->tmp.message_type == SSL3_MT_SERVER_KEY_EXCHANGE) { + S3I(s)->tmp.reuse_message = 1; + return (1); + } + + if (S3I(s)->tmp.message_type != SSL3_MT_CERTIFICATE) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, + SSL_R_BAD_MESSAGE_TYPE); + goto f_err; + } + + + if ((sk = sk_X509_new_null()) == NULL) { + SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, + ERR_R_MALLOC_FAILURE); + goto err; + } + + if (n < 0) + goto truncated; + + CBS_init(&cbs, s->internal->init_msg, n); + if (CBS_len(&cbs) < 3) + goto truncated; + + if (!CBS_get_u24_length_prefixed(&cbs, &cert_list) || + CBS_len(&cbs) != 0) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, + SSL_R_LENGTH_MISMATCH); + goto f_err; + } + + while (CBS_len(&cert_list) > 0) { + CBS cert; + + if (CBS_len(&cert_list) < 3) + goto truncated; + if (!CBS_get_u24_length_prefixed(&cert_list, &cert)) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, + SSL_R_CERT_LENGTH_MISMATCH); + goto f_err; + } + + q = CBS_data(&cert); + x = d2i_X509(NULL, &q, CBS_len(&cert)); + if (x == NULL) { + al = SSL_AD_BAD_CERTIFICATE; + SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, + ERR_R_ASN1_LIB); + goto f_err; + } + if (q != CBS_data(&cert) + CBS_len(&cert)) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, + SSL_R_CERT_LENGTH_MISMATCH); + goto f_err; + } + if (!sk_X509_push(sk, x)) { + SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, + ERR_R_MALLOC_FAILURE); + goto err; + } + x = NULL; + } + + i = ssl_verify_cert_chain(s, sk); + if ((s->verify_mode != SSL_VERIFY_NONE) && (i <= 0)) { + al = ssl_verify_alarm_type(s->verify_result); + SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, + SSL_R_CERTIFICATE_VERIFY_FAILED); + goto f_err; + + } + ERR_clear_error(); /* but we keep s->verify_result */ + + sc = ssl_sess_cert_new(); + if (sc == NULL) + goto err; + ssl_sess_cert_free(SSI(s)->sess_cert); + SSI(s)->sess_cert = sc; + + sc->cert_chain = sk; + /* + * Inconsistency alert: cert_chain does include the peer's + * certificate, which we don't include in s3_srvr.c + */ + x = sk_X509_value(sk, 0); + sk = NULL; + /* VRS 19990621: possible memory leak; sk=null ==> !sk_pop_free() @end*/ + + pkey = X509_get_pubkey(x); + + if (pkey == NULL || EVP_PKEY_missing_parameters(pkey)) { + x = NULL; + al = SSL3_AL_FATAL; + SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, + SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS); + goto f_err; + } + + i = ssl_cert_type(x, pkey); + if (i < 0) { + x = NULL; + al = SSL3_AL_FATAL; + SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, + SSL_R_UNKNOWN_CERTIFICATE_TYPE); + goto f_err; + } + + sc->peer_cert_type = i; + CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); + /* + * Why would the following ever happen? + * We just created sc a couple of lines ago. + */ + X509_free(sc->peer_pkeys[i].x509); + sc->peer_pkeys[i].x509 = x; + sc->peer_key = &(sc->peer_pkeys[i]); + + X509_free(s->session->peer); + CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); + s->session->peer = x; + s->session->verify_result = s->verify_result; + + x = NULL; + ret = 1; + + if (0) { +truncated: + /* wrong packet length */ + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, + SSL_R_BAD_PACKET_LENGTH); +f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + } +err: + EVP_PKEY_free(pkey); + X509_free(x); + sk_X509_pop_free(sk, X509_free); + + return (ret); +} + +static int +ssl3_get_server_kex_dhe(SSL *s, EVP_PKEY **pkey, unsigned char **pp, long *nn) +{ + CBS cbs, dhp, dhg, dhpk; + BN_CTX *bn_ctx = NULL; + SESS_CERT *sc = NULL; + DH *dh = NULL; + long alg_a; + int al; + + alg_a = S3I(s)->tmp.new_cipher->algorithm_auth; + sc = SSI(s)->sess_cert; + + if (*nn < 0) + goto err; + + CBS_init(&cbs, *pp, *nn); + + if ((dh = DH_new()) == NULL) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_DH_LIB); + goto err; + } + + if (!CBS_get_u16_length_prefixed(&cbs, &dhp)) + goto truncated; + if ((dh->p = BN_bin2bn(CBS_data(&dhp), CBS_len(&dhp), NULL)) == NULL) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_BN_LIB); + goto err; + } + + if (!CBS_get_u16_length_prefixed(&cbs, &dhg)) + goto truncated; + if ((dh->g = BN_bin2bn(CBS_data(&dhg), CBS_len(&dhg), NULL)) == NULL) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_BN_LIB); + goto err; + } + + if (!CBS_get_u16_length_prefixed(&cbs, &dhpk)) + goto truncated; + if ((dh->pub_key = BN_bin2bn(CBS_data(&dhpk), CBS_len(&dhpk), + NULL)) == NULL) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_BN_LIB); + goto err; + } + + /* + * Check the strength of the DH key just constructed. + * Discard keys weaker than 1024 bits. + */ + if (DH_size(dh) < 1024 / 8) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_DH_P_LENGTH); + goto err; + } + + if (alg_a & SSL_aRSA) + *pkey = X509_get_pubkey(sc->peer_pkeys[SSL_PKEY_RSA_ENC].x509); + else if (alg_a & SSL_aDSS) + *pkey = X509_get_pubkey(sc->peer_pkeys[SSL_PKEY_DSA_SIGN].x509); + else + /* XXX - Anonymous DH, so no certificate or pkey. */ + *pkey = NULL; + + sc->peer_dh_tmp = dh; + + *nn = CBS_len(&cbs); + *pp = (unsigned char *)CBS_data(&cbs); + + return (1); + + truncated: + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_PACKET_LENGTH); + ssl3_send_alert(s, SSL3_AL_FATAL, al); + + err: + DH_free(dh); + BN_CTX_free(bn_ctx); + + return (-1); +} + +static int +ssl3_get_server_kex_ecdhe_ecp(SSL *s, SESS_CERT *sc, int nid, CBS *public) +{ + const EC_GROUP *group; + EC_GROUP *ngroup = NULL; + EC_POINT *point = NULL; + BN_CTX *bn_ctx = NULL; + EC_KEY *ecdh = NULL; + int ret = -1; + + /* + * Extract the server's ephemeral ECDH public key. + */ + + if ((ecdh = EC_KEY_new()) == NULL) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE); + goto err; + } + + if ((ngroup = EC_GROUP_new_by_curve_name(nid)) == NULL) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_EC_LIB); + goto err; + } + if (EC_KEY_set_group(ecdh, ngroup) == 0) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_EC_LIB); + goto err; + } + + group = EC_KEY_get0_group(ecdh); + + if ((point = EC_POINT_new(group)) == NULL || + (bn_ctx = BN_CTX_new()) == NULL) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (EC_POINT_oct2point(group, point, CBS_data(public), + CBS_len(public), bn_ctx) == 0) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_ECPOINT); + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + goto err; + } + + EC_KEY_set_public_key(ecdh, point); + sc->peer_ecdh_tmp = ecdh; + ecdh = NULL; + + ret = 1; + + err: + BN_CTX_free(bn_ctx); + EC_GROUP_free(ngroup); + EC_POINT_free(point); + EC_KEY_free(ecdh); + + return (ret); +} + +static int +ssl3_get_server_kex_ecdhe_ecx(SSL *s, SESS_CERT *sc, int nid, CBS *public) +{ + size_t outlen; + + if (nid != NID_X25519) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR); + goto err; + } + + if (CBS_len(public) != X25519_KEY_LENGTH) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_ECPOINT); + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + goto err; + } + + if (!CBS_stow(public, &sc->peer_x25519_tmp, &outlen)) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE); + goto err; + } + + return (1); + + err: + return (-1); +} + +static int +ssl3_get_server_kex_ecdhe(SSL *s, EVP_PKEY **pkey, unsigned char **pp, long *nn) +{ + CBS cbs, public; + uint8_t curve_type; + uint16_t curve_id; + SESS_CERT *sc; + long alg_a; + int nid; + int al; + + alg_a = S3I(s)->tmp.new_cipher->algorithm_auth; + sc = SSI(s)->sess_cert; + + if (*nn < 0) + goto err; + + CBS_init(&cbs, *pp, *nn); + + /* Only named curves are supported. */ + if (!CBS_get_u8(&cbs, &curve_type) || + curve_type != NAMED_CURVE_TYPE || + !CBS_get_u16(&cbs, &curve_id)) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_TOO_SHORT); + goto f_err; + } + + /* + * Check that the curve is one of our preferences - if it is not, + * the server has sent us an invalid curve. + */ + if (tls1_check_curve(s, curve_id) != 1) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_WRONG_CURVE); + goto f_err; + } + + if ((nid = tls1_ec_curve_id2nid(curve_id)) == 0) { + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, + SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS); + goto f_err; + } + + if (!CBS_get_u8_length_prefixed(&cbs, &public)) + goto truncated; + + if (nid == NID_X25519) { + if (ssl3_get_server_kex_ecdhe_ecx(s, sc, nid, &public) != 1) + goto err; + } else { + if (ssl3_get_server_kex_ecdhe_ecp(s, sc, nid, &public) != 1) + goto err; + } + + /* + * The ECC/TLS specification does not mention the use of DSA to sign + * ECParameters in the server key exchange message. We do support RSA + * and ECDSA. + */ + if (alg_a & SSL_aRSA) + *pkey = X509_get_pubkey(sc->peer_pkeys[SSL_PKEY_RSA_ENC].x509); + else if (alg_a & SSL_aECDSA) + *pkey = X509_get_pubkey(sc->peer_pkeys[SSL_PKEY_ECC].x509); + else + /* XXX - Anonymous ECDH, so no certificate or pkey. */ + *pkey = NULL; + + *nn = CBS_len(&cbs); + *pp = (unsigned char *)CBS_data(&cbs); + + return (1); + + truncated: + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_PACKET_LENGTH); + + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + + err: + return (-1); +} + +int +ssl3_get_server_key_exchange(SSL *s) +{ + unsigned char *q, md_buf[EVP_MAX_MD_SIZE*2]; + EVP_MD_CTX md_ctx; + unsigned char *param, *p; + int al, i, j, param_len, ok; + long n, alg_k, alg_a; + EVP_PKEY *pkey = NULL; + const EVP_MD *md = NULL; + RSA *rsa = NULL; + + alg_k = S3I(s)->tmp.new_cipher->algorithm_mkey; + alg_a = S3I(s)->tmp.new_cipher->algorithm_auth; + + /* + * Use same message size as in ssl3_get_certificate_request() + * as ServerKeyExchange message may be skipped. + */ + n = s->method->internal->ssl_get_message(s, SSL3_ST_CR_KEY_EXCH_A, + SSL3_ST_CR_KEY_EXCH_B, -1, s->internal->max_cert_list, &ok); + if (!ok) + return ((int)n); + + EVP_MD_CTX_init(&md_ctx); + + if (S3I(s)->tmp.message_type != SSL3_MT_SERVER_KEY_EXCHANGE) { + /* + * Do not skip server key exchange if this cipher suite uses + * ephemeral keys. + */ + if (alg_k & (SSL_kDHE|SSL_kECDHE)) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, + SSL_R_UNEXPECTED_MESSAGE); + al = SSL_AD_UNEXPECTED_MESSAGE; + goto f_err; + } + + S3I(s)->tmp.reuse_message = 1; + EVP_MD_CTX_cleanup(&md_ctx); + return (1); + } + + if (SSI(s)->sess_cert != NULL) { + DH_free(SSI(s)->sess_cert->peer_dh_tmp); + SSI(s)->sess_cert->peer_dh_tmp = NULL; + + EC_KEY_free(SSI(s)->sess_cert->peer_ecdh_tmp); + SSI(s)->sess_cert->peer_ecdh_tmp = NULL; + + free(SSI(s)->sess_cert->peer_x25519_tmp); + SSI(s)->sess_cert->peer_x25519_tmp = NULL; + } else { + SSI(s)->sess_cert = ssl_sess_cert_new(); + if (SSI(s)->sess_cert == NULL) + goto err; + } + + param = p = (unsigned char *)s->internal->init_msg; + param_len = n; + + if (alg_k & SSL_kDHE) { + if (ssl3_get_server_kex_dhe(s, &pkey, &p, &n) != 1) + goto err; + } else if (alg_k & SSL_kECDHE) { + if (ssl3_get_server_kex_ecdhe(s, &pkey, &p, &n) != 1) + goto err; + } else if (alg_k != 0) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_UNEXPECTED_MESSAGE); + goto f_err; + } + + param_len = param_len - n; + + /* if it was signed, check the signature */ + if (pkey != NULL) { + if (SSL_USE_SIGALGS(s)) { + int sigalg = tls12_get_sigid(pkey); + /* Should never happen */ + if (sigalg == -1) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } + /* + * Check key type is consistent + * with signature + */ + if (2 > n) + goto truncated; + if (sigalg != (int)p[1]) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, + SSL_R_WRONG_SIGNATURE_TYPE); + al = SSL_AD_DECODE_ERROR; + goto f_err; + } + md = tls12_get_hash(p[0]); + if (md == NULL) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, + SSL_R_UNKNOWN_DIGEST); + al = SSL_AD_DECODE_ERROR; + goto f_err; + } + p += 2; + n -= 2; + } else + md = EVP_sha1(); + + if (2 > n) + goto truncated; + n2s(p, i); + n -= 2; + j = EVP_PKEY_size(pkey); + + if (i != n || n > j) { + /* wrong packet length */ + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, + SSL_R_WRONG_SIGNATURE_LENGTH); + goto f_err; + } + + if (pkey->type == EVP_PKEY_RSA && !SSL_USE_SIGALGS(s)) { + int num; + + j = 0; + q = md_buf; + for (num = 2; num > 0; num--) { + if (!EVP_DigestInit_ex(&md_ctx, + (num == 2) ? s->ctx->internal->md5 : + s->ctx->internal->sha1, NULL)) { + al = SSL_AD_INTERNAL_ERROR; + goto f_err; + } + EVP_DigestUpdate(&md_ctx, + s->s3->client_random, + SSL3_RANDOM_SIZE); + EVP_DigestUpdate(&md_ctx, + s->s3->server_random, + SSL3_RANDOM_SIZE); + EVP_DigestUpdate(&md_ctx, param, param_len); + EVP_DigestFinal_ex(&md_ctx, q, + (unsigned int *)&i); + q += i; + j += i; + } + i = RSA_verify(NID_md5_sha1, md_buf, j, + p, n, pkey->pkey.rsa); + if (i < 0) { + al = SSL_AD_DECRYPT_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, + SSL_R_BAD_RSA_DECRYPT); + goto f_err; + } + if (i == 0) { + /* bad signature */ + al = SSL_AD_DECRYPT_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, + SSL_R_BAD_SIGNATURE); + goto f_err; + } + } else { + EVP_VerifyInit_ex(&md_ctx, md, NULL); + EVP_VerifyUpdate(&md_ctx, s->s3->client_random, + SSL3_RANDOM_SIZE); + EVP_VerifyUpdate(&md_ctx, s->s3->server_random, + SSL3_RANDOM_SIZE); + EVP_VerifyUpdate(&md_ctx, param, param_len); + if (EVP_VerifyFinal(&md_ctx, p,(int)n, pkey) <= 0) { + /* bad signature */ + al = SSL_AD_DECRYPT_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, + SSL_R_BAD_SIGNATURE); + goto f_err; + } + } + } else { + /* aNULL does not need public keys. */ + if (!(alg_a & SSL_aNULL)) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } + /* still data left over */ + if (n != 0) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, + SSL_R_EXTRA_DATA_IN_MESSAGE); + goto f_err; + } + } + + EVP_PKEY_free(pkey); + EVP_MD_CTX_cleanup(&md_ctx); + + return (1); + + truncated: + /* wrong packet length */ + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_PACKET_LENGTH); + + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + + err: + EVP_PKEY_free(pkey); + RSA_free(rsa); + EVP_MD_CTX_cleanup(&md_ctx); + + return (-1); +} + +int +ssl3_get_certificate_request(SSL *s) +{ + int ok, ret = 0; + long n; + uint8_t ctype_num; + CBS cert_request, ctypes, rdn_list; + X509_NAME *xn = NULL; + const unsigned char *q; + STACK_OF(X509_NAME) *ca_sk = NULL; + + n = s->method->internal->ssl_get_message(s, SSL3_ST_CR_CERT_REQ_A, + SSL3_ST_CR_CERT_REQ_B, -1, s->internal->max_cert_list, &ok); + + if (!ok) + return ((int)n); + + S3I(s)->tmp.cert_req = 0; + + if (S3I(s)->tmp.message_type == SSL3_MT_SERVER_DONE) { + S3I(s)->tmp.reuse_message = 1; + /* + * If we get here we don't need any cached handshake records + * as we wont be doing client auth. + */ + if (S3I(s)->handshake_buffer) { + if (!tls1_digest_cached_records(s)) + goto err; + } + return (1); + } + + if (S3I(s)->tmp.message_type != SSL3_MT_CERTIFICATE_REQUEST) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); + SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, + SSL_R_WRONG_MESSAGE_TYPE); + goto err; + } + + /* TLS does not like anon-DH with client cert */ + if (S3I(s)->tmp.new_cipher->algorithm_auth & SSL_aNULL) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); + SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, + SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER); + goto err; + } + + if (n < 0) + goto truncated; + CBS_init(&cert_request, s->internal->init_msg, n); + + if ((ca_sk = sk_X509_NAME_new(ca_dn_cmp)) == NULL) { + SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, + ERR_R_MALLOC_FAILURE); + goto err; + } + + /* get the certificate types */ + if (!CBS_get_u8(&cert_request, &ctype_num)) + goto truncated; + + if (ctype_num > SSL3_CT_NUMBER) + ctype_num = SSL3_CT_NUMBER; + if (!CBS_get_bytes(&cert_request, &ctypes, ctype_num) || + !CBS_write_bytes(&ctypes, (uint8_t *)S3I(s)->tmp.ctype, + sizeof(S3I(s)->tmp.ctype), NULL)) { + SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, + SSL_R_DATA_LENGTH_TOO_LONG); + goto err; + } + + if (SSL_USE_SIGALGS(s)) { + CBS sigalgs; + + if (CBS_len(&cert_request) < 2) { + SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, + SSL_R_DATA_LENGTH_TOO_LONG); + goto err; + } + + /* Check we have enough room for signature algorithms and + * following length value. + */ + if (!CBS_get_u16_length_prefixed(&cert_request, &sigalgs)) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, + SSL_R_DATA_LENGTH_TOO_LONG); + goto err; + } + if ((CBS_len(&sigalgs) & 1) || + !tls1_process_sigalgs(s, CBS_data(&sigalgs), + CBS_len(&sigalgs))) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, + SSL_R_SIGNATURE_ALGORITHMS_ERROR); + goto err; + } + } + + /* get the CA RDNs */ + if (CBS_len(&cert_request) < 2) { + SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, + SSL_R_DATA_LENGTH_TOO_LONG); + goto err; + } + + if (!CBS_get_u16_length_prefixed(&cert_request, &rdn_list) || + CBS_len(&cert_request) != 0) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, + SSL_R_LENGTH_MISMATCH); + goto err; + } + + while (CBS_len(&rdn_list) > 0) { + CBS rdn; + + if (CBS_len(&rdn_list) < 2) { + SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, + SSL_R_DATA_LENGTH_TOO_LONG); + goto err; + } + + if (!CBS_get_u16_length_prefixed(&rdn_list, &rdn)) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, + SSL_R_CA_DN_TOO_LONG); + goto err; + } + + q = CBS_data(&rdn); + if ((xn = d2i_X509_NAME(NULL, &q, CBS_len(&rdn))) == NULL) { + ssl3_send_alert(s, SSL3_AL_FATAL, + SSL_AD_DECODE_ERROR); + SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, + ERR_R_ASN1_LIB); + goto err; + } + + if (q != CBS_data(&rdn) + CBS_len(&rdn)) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, + SSL_R_CA_DN_LENGTH_MISMATCH); + goto err; + } + if (!sk_X509_NAME_push(ca_sk, xn)) { + SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, + ERR_R_MALLOC_FAILURE); + goto err; + } + xn = NULL; /* avoid free in err block */ + } + + /* we should setup a certificate to return.... */ + S3I(s)->tmp.cert_req = 1; + S3I(s)->tmp.ctype_num = ctype_num; + sk_X509_NAME_pop_free(S3I(s)->tmp.ca_names, X509_NAME_free); + S3I(s)->tmp.ca_names = ca_sk; + ca_sk = NULL; + + ret = 1; + if (0) { +truncated: + SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, + SSL_R_BAD_PACKET_LENGTH); + } +err: + X509_NAME_free(xn); + sk_X509_NAME_pop_free(ca_sk, X509_NAME_free); + return (ret); +} + +static int +ca_dn_cmp(const X509_NAME * const *a, const X509_NAME * const *b) +{ + return (X509_NAME_cmp(*a, *b)); +} + +int +ssl3_get_new_session_ticket(SSL *s) +{ + int ok, al, ret = 0; + uint32_t lifetime_hint; + long n; + CBS cbs, session_ticket; + + n = s->method->internal->ssl_get_message(s, SSL3_ST_CR_SESSION_TICKET_A, + SSL3_ST_CR_SESSION_TICKET_B, -1, 16384, &ok); + if (!ok) + return ((int)n); + + if (S3I(s)->tmp.message_type == SSL3_MT_FINISHED) { + S3I(s)->tmp.reuse_message = 1; + return (1); + } + if (S3I(s)->tmp.message_type != SSL3_MT_NEWSESSION_TICKET) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET, + SSL_R_BAD_MESSAGE_TYPE); + goto f_err; + } + + if (n < 0) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET, + SSL_R_LENGTH_MISMATCH); + goto f_err; + } + + CBS_init(&cbs, s->internal->init_msg, n); + if (!CBS_get_u32(&cbs, &lifetime_hint) || +#if UINT32_MAX > LONG_MAX + lifetime_hint > LONG_MAX || +#endif + !CBS_get_u16_length_prefixed(&cbs, &session_ticket) || + CBS_len(&cbs) != 0) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET, + SSL_R_LENGTH_MISMATCH); + goto f_err; + } + s->session->tlsext_tick_lifetime_hint = (long)lifetime_hint; + + if (!CBS_stow(&session_ticket, &s->session->tlsext_tick, + &s->session->tlsext_ticklen)) { + SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET, + ERR_R_MALLOC_FAILURE); + goto err; + } + + /* + * There are two ways to detect a resumed ticket sesion. + * One is to set an appropriate session ID and then the server + * must return a match in ServerHello. This allows the normal + * client session ID matching to work and we know much + * earlier that the ticket has been accepted. + * + * The other way is to set zero length session ID when the + * ticket is presented and rely on the handshake to determine + * session resumption. + * + * We choose the former approach because this fits in with + * assumptions elsewhere in OpenSSL. The session ID is set + * to the SHA256 (or SHA1 is SHA256 is disabled) hash of the + * ticket. + */ + EVP_Digest(CBS_data(&session_ticket), CBS_len(&session_ticket), + s->session->session_id, &s->session->session_id_length, + EVP_sha256(), NULL); + ret = 1; + return (ret); +f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); +err: + return (-1); +} + +int +ssl3_get_cert_status(SSL *s) +{ + CBS cert_status, response; + size_t stow_len; + int ok, al; + long n; + uint8_t status_type; + + n = s->method->internal->ssl_get_message(s, SSL3_ST_CR_CERT_STATUS_A, + SSL3_ST_CR_CERT_STATUS_B, SSL3_MT_CERTIFICATE_STATUS, + 16384, &ok); + + if (!ok) + return ((int)n); + + if (n < 0) { + /* need at least status type + length */ + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CERT_STATUS, + SSL_R_LENGTH_MISMATCH); + goto f_err; + } + + CBS_init(&cert_status, s->internal->init_msg, n); + if (!CBS_get_u8(&cert_status, &status_type) || + CBS_len(&cert_status) < 3) { + /* need at least status type + length */ + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CERT_STATUS, + SSL_R_LENGTH_MISMATCH); + goto f_err; + } + + if (status_type != TLSEXT_STATUSTYPE_ocsp) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CERT_STATUS, + SSL_R_UNSUPPORTED_STATUS_TYPE); + goto f_err; + } + + if (!CBS_get_u24_length_prefixed(&cert_status, &response) || + CBS_len(&cert_status) != 0) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CERT_STATUS, + SSL_R_LENGTH_MISMATCH); + goto f_err; + } + + if (!CBS_stow(&response, &s->internal->tlsext_ocsp_resp, + &stow_len) || stow_len > INT_MAX) { + s->internal->tlsext_ocsp_resplen = 0; + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL3_GET_CERT_STATUS, + ERR_R_MALLOC_FAILURE); + goto f_err; + } + s->internal->tlsext_ocsp_resplen = (int)stow_len; + + if (s->ctx->internal->tlsext_status_cb) { + int ret; + ret = s->ctx->internal->tlsext_status_cb(s, + s->ctx->internal->tlsext_status_arg); + if (ret == 0) { + al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE; + SSLerr(SSL_F_SSL3_GET_CERT_STATUS, + SSL_R_INVALID_STATUS_RESPONSE); + goto f_err; + } + if (ret < 0) { + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL3_GET_CERT_STATUS, + ERR_R_MALLOC_FAILURE); + goto f_err; + } + } + return (1); +f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + return (-1); +} + +int +ssl3_get_server_done(SSL *s) +{ + int ok, ret = 0; + long n; + + n = s->method->internal->ssl_get_message(s, SSL3_ST_CR_SRVR_DONE_A, + SSL3_ST_CR_SRVR_DONE_B, SSL3_MT_SERVER_DONE, + 30, /* should be very small, like 0 :-) */ &ok); + + if (!ok) + return ((int)n); + if (n > 0) { + /* should contain no data */ + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + SSLerr(SSL_F_SSL3_GET_SERVER_DONE, SSL_R_LENGTH_MISMATCH); + return (-1); + } + ret = 1; + return (ret); +} + +static int +ssl3_send_client_kex_rsa(SSL *s, SESS_CERT *sess_cert, CBB *cbb) +{ + unsigned char pms[SSL_MAX_MASTER_KEY_LENGTH]; + unsigned char *enc_pms = NULL; + EVP_PKEY *pkey = NULL; + int ret = -1; + int enc_len; + CBB epms; + + /* + * RSA-Encrypted Premaster Secret Message - RFC 5246 section 7.4.7.1. + */ + + pkey = X509_get_pubkey(sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509); + if (pkey == NULL || pkey->type != EVP_PKEY_RSA || + pkey->pkey.rsa == NULL) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + pms[0] = s->client_version >> 8; + pms[1] = s->client_version & 0xff; + arc4random_buf(&pms[2], sizeof(pms) - 2); + + if ((enc_pms = malloc(RSA_size(pkey->pkey.rsa))) == NULL) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_MALLOC_FAILURE); + goto err; + } + + enc_len = RSA_public_encrypt(sizeof(pms), pms, enc_pms, pkey->pkey.rsa, + RSA_PKCS1_PADDING); + if (enc_len <= 0) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + SSL_R_BAD_RSA_ENCRYPT); + goto err; + } + + if (!CBB_add_u16_length_prefixed(cbb, &epms)) + goto err; + if (!CBB_add_bytes(&epms, enc_pms, enc_len)) + goto err; + if (!CBB_flush(cbb)) + goto err; + + s->session->master_key_length = + s->method->internal->ssl3_enc->generate_master_secret(s, + s->session->master_key, pms, sizeof(pms)); + + ret = 1; + +err: + explicit_bzero(pms, sizeof(pms)); + EVP_PKEY_free(pkey); + free(enc_pms); + + return (ret); +} + +static int +ssl3_send_client_kex_dhe(SSL *s, SESS_CERT *sess_cert, CBB *cbb) +{ + DH *dh_srvr = NULL, *dh_clnt = NULL; + unsigned char *key = NULL; + int key_size = 0, key_len; + unsigned char *data; + int ret = -1; + CBB dh_Yc; + + /* Ensure that we have an ephemeral key for DHE. */ + if (sess_cert->peer_dh_tmp == NULL) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + SSL_R_UNABLE_TO_FIND_DH_PARAMETERS); + goto err; + } + dh_srvr = sess_cert->peer_dh_tmp; + + /* Generate a new random key. */ + if ((dh_clnt = DHparams_dup(dh_srvr)) == NULL) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB); + goto err; + } + if (!DH_generate_key(dh_clnt)) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB); + goto err; + } + key_size = DH_size(dh_clnt); + if ((key = malloc(key_size)) == NULL) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_MALLOC_FAILURE); + goto err; + } + key_len = DH_compute_key(key, dh_srvr->pub_key, dh_clnt); + if (key_len <= 0) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB); + goto err; + } + + /* Generate master key from the result. */ + s->session->master_key_length = + s->method->internal->ssl3_enc->generate_master_secret(s, + s->session->master_key, key, key_len); + + if (!CBB_add_u16_length_prefixed(cbb, &dh_Yc)) + goto err; + if (!CBB_add_space(&dh_Yc, &data, BN_num_bytes(dh_clnt->pub_key))) + goto err; + BN_bn2bin(dh_clnt->pub_key, data); + if (!CBB_flush(cbb)) + goto err; + + ret = 1; + +err: + DH_free(dh_clnt); + if (key != NULL) + explicit_bzero(key, key_size); + free(key); + + return (ret); +} + +static int +ssl3_send_client_kex_ecdhe_ecp(SSL *s, SESS_CERT *sc, CBB *cbb) +{ + const EC_GROUP *group = NULL; + const EC_POINT *point = NULL; + EC_KEY *ecdh = NULL; + BN_CTX *bn_ctx = NULL; + unsigned char *key = NULL; + unsigned char *data; + size_t encoded_len; + int key_size = 0, key_len; + int ret = -1; + CBB ecpoint; + + if ((group = EC_KEY_get0_group(sc->peer_ecdh_tmp)) == NULL || + (point = EC_KEY_get0_public_key(sc->peer_ecdh_tmp)) == NULL) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + if ((ecdh = EC_KEY_new()) == NULL) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!EC_KEY_set_group(ecdh, group)) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB); + goto err; + } + + /* Generate a new ECDH key pair. */ + if (!(EC_KEY_generate_key(ecdh))) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB); + goto err; + } + if ((key_size = ECDH_size(ecdh)) <= 0) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB); + goto err; + } + if ((key = malloc(key_size)) == NULL) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_MALLOC_FAILURE); + } + key_len = ECDH_compute_key(key, key_size, point, ecdh, NULL); + if (key_len <= 0) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB); + goto err; + } + + /* Generate master key from the result. */ + s->session->master_key_length = + s->method->internal->ssl3_enc->generate_master_secret(s, + s->session->master_key, key, key_len); + + encoded_len = EC_POINT_point2oct(group, EC_KEY_get0_public_key(ecdh), + POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL); + if (encoded_len == 0) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB); + goto err; + } + + if ((bn_ctx = BN_CTX_new()) == NULL) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_MALLOC_FAILURE); + goto err; + } + + /* Encode the public key. */ + if (!CBB_add_u8_length_prefixed(cbb, &ecpoint)) + goto err; + if (!CBB_add_space(&ecpoint, &data, encoded_len)) + goto err; + if (EC_POINT_point2oct(group, EC_KEY_get0_public_key(ecdh), + POINT_CONVERSION_UNCOMPRESSED, data, encoded_len, + bn_ctx) == 0) + goto err; + if (!CBB_flush(cbb)) + goto err; + + ret = 1; + + err: + if (key != NULL) + explicit_bzero(key, key_size); + free(key); + + BN_CTX_free(bn_ctx); + EC_KEY_free(ecdh); + + return (ret); +} + +static int +ssl3_send_client_kex_ecdhe_ecx(SSL *s, SESS_CERT *sc, CBB *cbb) +{ + uint8_t *public_key = NULL, *private_key = NULL, *shared_key = NULL; + int ret = -1; + CBB ecpoint; + + /* Generate X25519 key pair and derive shared key. */ + if ((public_key = malloc(X25519_KEY_LENGTH)) == NULL) + goto err; + if ((private_key = malloc(X25519_KEY_LENGTH)) == NULL) + goto err; + if ((shared_key = malloc(X25519_KEY_LENGTH)) == NULL) + goto err; + X25519_keypair(public_key, private_key); + if (!X25519(shared_key, private_key, sc->peer_x25519_tmp)) + goto err; + + /* Serialize the public key. */ + if (!CBB_add_u8_length_prefixed(cbb, &ecpoint)) + goto err; + if (!CBB_add_bytes(&ecpoint, public_key, X25519_KEY_LENGTH)) + goto err; + if (!CBB_flush(cbb)) + goto err; + + /* Generate master key from the result. */ + s->session->master_key_length = + s->method->internal->ssl3_enc->generate_master_secret(s, + s->session->master_key, shared_key, X25519_KEY_LENGTH); + + ret = 1; + + err: + if (private_key != NULL) + explicit_bzero(private_key, X25519_KEY_LENGTH); + if (shared_key != NULL) + explicit_bzero(shared_key, X25519_KEY_LENGTH); + + free(public_key); + free(private_key); + free(shared_key); + + return (ret); +} + +static int +ssl3_send_client_kex_ecdhe(SSL *s, SESS_CERT *sc, CBB *cbb) +{ + if (sc->peer_x25519_tmp != NULL) { + if (ssl3_send_client_kex_ecdhe_ecx(s, sc, cbb) != 1) + goto err; + } else if (sc->peer_ecdh_tmp != NULL) { + if (ssl3_send_client_kex_ecdhe_ecp(s, sc, cbb) != 1) + goto err; + } else { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + return (1); + + err: + return (-1); +} + +static int +ssl3_send_client_kex_gost(SSL *s, SESS_CERT *sess_cert, CBB *cbb) +{ + unsigned char premaster_secret[32], shared_ukm[32], tmp[256]; + EVP_PKEY *pub_key = NULL; + EVP_PKEY_CTX *pkey_ctx; + X509 *peer_cert; + size_t msglen; + unsigned int md_len; + EVP_MD_CTX *ukm_hash; + int ret = -1; + int nid; + CBB gostblob; + + /* Get server sertificate PKEY and create ctx from it */ + peer_cert = sess_cert->peer_pkeys[SSL_PKEY_GOST01].x509; + if (peer_cert == NULL) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER); + goto err; + } + + pub_key = X509_get_pubkey(peer_cert); + pkey_ctx = EVP_PKEY_CTX_new(pub_key, NULL); + + /* + * If we have send a certificate, and certificate key parameters match + * those of server certificate, use certificate key for key exchange. + * Otherwise, generate ephemeral key pair. + */ + EVP_PKEY_encrypt_init(pkey_ctx); + + /* Generate session key. */ + arc4random_buf(premaster_secret, 32); + + /* + * If we have client certificate, use its secret as peer key. + */ + if (S3I(s)->tmp.cert_req && s->cert->key->privatekey) { + if (EVP_PKEY_derive_set_peer(pkey_ctx, + s->cert->key->privatekey) <=0) { + /* + * If there was an error - just ignore it. + * Ephemeral key would be used. + */ + ERR_clear_error(); + } + } + + /* + * Compute shared IV and store it in algorithm-specific context data. + */ + ukm_hash = EVP_MD_CTX_create(); + if (ukm_hash == NULL) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_MALLOC_FAILURE); + goto err; + } + + if (ssl_get_algorithm2(s) & SSL_HANDSHAKE_MAC_GOST94) + nid = NID_id_GostR3411_94; + else + nid = NID_id_tc26_gost3411_2012_256; + if (!EVP_DigestInit(ukm_hash, EVP_get_digestbynid(nid))) + goto err; + EVP_DigestUpdate(ukm_hash, s->s3->client_random, SSL3_RANDOM_SIZE); + EVP_DigestUpdate(ukm_hash, s->s3->server_random, SSL3_RANDOM_SIZE); + EVP_DigestFinal_ex(ukm_hash, shared_ukm, &md_len); + EVP_MD_CTX_destroy(ukm_hash); + if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, EVP_PKEY_OP_ENCRYPT, + EVP_PKEY_CTRL_SET_IV, 8, shared_ukm) < 0) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, SSL_R_LIBRARY_BUG); + goto err; + } + + /* + * Make GOST keytransport blob message, encapsulate it into sequence. + */ + msglen = 255; + if (EVP_PKEY_encrypt(pkey_ctx, tmp, &msglen, premaster_secret, + 32) < 0) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, SSL_R_LIBRARY_BUG); + goto err; + } + + if (!CBB_add_asn1(cbb, &gostblob, CBS_ASN1_SEQUENCE)) + goto err; + if (!CBB_add_bytes(&gostblob, tmp, msglen)) + goto err; + if (!CBB_flush(cbb)) + goto err; + + /* Check if pubkey from client certificate was used. */ + if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 2, + NULL) > 0) { + /* Set flag "skip certificate verify". */ + s->s3->flags |= TLS1_FLAGS_SKIP_CERT_VERIFY; + } + EVP_PKEY_CTX_free(pkey_ctx); + s->session->master_key_length = + s->method->internal->ssl3_enc->generate_master_secret(s, + s->session->master_key, premaster_secret, 32); + + ret = 1; + + err: + explicit_bzero(premaster_secret, sizeof(premaster_secret)); + EVP_PKEY_free(pub_key); + + return (ret); +} + +int +ssl3_send_client_key_exchange(SSL *s) +{ + SESS_CERT *sess_cert; + unsigned long alg_k; + CBB cbb, kex; + + memset(&cbb, 0, sizeof(cbb)); + + if (s->internal->state == SSL3_ST_CW_KEY_EXCH_A) { + alg_k = S3I(s)->tmp.new_cipher->algorithm_mkey; + + if ((sess_cert = SSI(s)->sess_cert) == NULL) { + ssl3_send_alert(s, SSL3_AL_FATAL, + SSL_AD_UNEXPECTED_MESSAGE); + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + if (!ssl3_handshake_msg_start_cbb(s, &cbb, &kex, + SSL3_MT_CLIENT_KEY_EXCHANGE)) + goto err; + + if (alg_k & SSL_kRSA) { + if (ssl3_send_client_kex_rsa(s, sess_cert, &kex) != 1) + goto err; + } else if (alg_k & SSL_kDHE) { + if (ssl3_send_client_kex_dhe(s, sess_cert, &kex) != 1) + goto err; + } else if (alg_k & SSL_kECDHE) { + if (ssl3_send_client_kex_ecdhe(s, sess_cert, &kex) != 1) + goto err; + } else if (alg_k & SSL_kGOST) { + if (ssl3_send_client_kex_gost(s, sess_cert, &kex) != 1) + goto err; + } else { + ssl3_send_alert(s, SSL3_AL_FATAL, + SSL_AD_HANDSHAKE_FAILURE); + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + if (!ssl3_handshake_msg_finish_cbb(s, &cbb)) + goto err; + + s->internal->state = SSL3_ST_CW_KEY_EXCH_B; + } + + /* SSL3_ST_CW_KEY_EXCH_B */ + return (ssl3_handshake_write(s)); + +err: + CBB_cleanup(&cbb); + + return (-1); +} + +int +ssl3_send_client_verify(SSL *s) +{ + unsigned char *p; + unsigned char data[MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH]; + EVP_PKEY *pkey; + EVP_PKEY_CTX *pctx = NULL; + EVP_MD_CTX mctx; + unsigned u = 0; + unsigned long n; + int j; + + EVP_MD_CTX_init(&mctx); + + if (s->internal->state == SSL3_ST_CW_CERT_VRFY_A) { + p = ssl3_handshake_msg_start(s, SSL3_MT_CERTIFICATE_VERIFY); + + /* + * Create context from key and test if sha1 is allowed as + * digest. + */ + pkey = s->cert->key->privatekey; + pctx = EVP_PKEY_CTX_new(pkey, NULL); + EVP_PKEY_sign_init(pctx); + if (EVP_PKEY_CTX_set_signature_md(pctx, EVP_sha1()) > 0) { + if (!SSL_USE_SIGALGS(s)) + s->method->internal->ssl3_enc->cert_verify_mac(s, + NID_sha1, &(data[MD5_DIGEST_LENGTH])); + } else { + ERR_clear_error(); + } + /* + * For TLS v1.2 send signature algorithm and signature + * using agreed digest and cached handshake records. + */ + if (SSL_USE_SIGALGS(s)) { + long hdatalen = 0; + void *hdata; + const EVP_MD *md = s->cert->key->digest; + hdatalen = BIO_get_mem_data(S3I(s)->handshake_buffer, + &hdata); + if (hdatalen <= 0 || + !tls12_get_sigandhash(p, pkey, md)) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, + ERR_R_INTERNAL_ERROR); + goto err; + } + p += 2; + if (!EVP_SignInit_ex(&mctx, md, NULL) || + !EVP_SignUpdate(&mctx, hdata, hdatalen) || + !EVP_SignFinal(&mctx, p + 2, &u, pkey)) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, + ERR_R_EVP_LIB); + goto err; + } + s2n(u, p); + n = u + 4; + if (!tls1_digest_cached_records(s)) + goto err; + } else if (pkey->type == EVP_PKEY_RSA) { + s->method->internal->ssl3_enc->cert_verify_mac( + s, NID_md5, &(data[0])); + if (RSA_sign(NID_md5_sha1, data, + MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH, &(p[2]), + &u, pkey->pkey.rsa) <= 0 ) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, + ERR_R_RSA_LIB); + goto err; + } + s2n(u, p); + n = u + 2; + } else if (pkey->type == EVP_PKEY_DSA) { + if (!DSA_sign(pkey->save_type, + &(data[MD5_DIGEST_LENGTH]), + SHA_DIGEST_LENGTH, &(p[2]), + (unsigned int *)&j, pkey->pkey.dsa)) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, + ERR_R_DSA_LIB); + goto err; + } + s2n(j, p); + n = j + 2; + } else if (pkey->type == EVP_PKEY_EC) { + if (!ECDSA_sign(pkey->save_type, + &(data[MD5_DIGEST_LENGTH]), + SHA_DIGEST_LENGTH, &(p[2]), + (unsigned int *)&j, pkey->pkey.ec)) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, + ERR_R_ECDSA_LIB); + goto err; + } + s2n(j, p); + n = j + 2; +#ifndef OPENSSL_NO_GOST + } else if (pkey->type == NID_id_GostR3410_94 || + pkey->type == NID_id_GostR3410_2001) { + unsigned char signbuf[128]; + long hdatalen = 0; + void *hdata; + const EVP_MD *md; + int nid; + size_t sigsize; + + hdatalen = BIO_get_mem_data(S3I(s)->handshake_buffer, &hdata); + if (hdatalen <= 0) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, + ERR_R_INTERNAL_ERROR); + goto err; + } + if (!EVP_PKEY_get_default_digest_nid(pkey, &nid) || + !(md = EVP_get_digestbynid(nid))) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, + ERR_R_EVP_LIB); + goto err; + } + if (!EVP_DigestInit_ex(&mctx, md, NULL) || + !EVP_DigestUpdate(&mctx, hdata, hdatalen) || + !EVP_DigestFinal(&mctx, signbuf, &u) || + (EVP_PKEY_CTX_set_signature_md(pctx, md) <= 0) || + (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_SIGN, + EVP_PKEY_CTRL_GOST_SIG_FORMAT, + GOST_SIG_FORMAT_RS_LE, + NULL) <= 0) || + (EVP_PKEY_sign(pctx, &(p[2]), &sigsize, + signbuf, u) <= 0)) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, + ERR_R_EVP_LIB); + goto err; + } + if (!tls1_digest_cached_records(s)) + goto err; + j = sigsize; + s2n(j, p); + n = j + 2; +#endif + } else { + SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, + ERR_R_INTERNAL_ERROR); + goto err; + } + + s->internal->state = SSL3_ST_CW_CERT_VRFY_B; + + ssl3_handshake_msg_finish(s, n); + } + + EVP_MD_CTX_cleanup(&mctx); + EVP_PKEY_CTX_free(pctx); + + return (ssl3_handshake_write(s)); + +err: + EVP_MD_CTX_cleanup(&mctx); + EVP_PKEY_CTX_free(pctx); + return (-1); +} + +int +ssl3_send_client_certificate(SSL *s) +{ + EVP_PKEY *pkey = NULL; + X509 *x509 = NULL; + CBB cbb, client_cert; + int i; + + memset(&cbb, 0, sizeof(cbb)); + + if (s->internal->state == SSL3_ST_CW_CERT_A) { + if ((s->cert == NULL) || (s->cert->key->x509 == NULL) || + (s->cert->key->privatekey == NULL)) + s->internal->state = SSL3_ST_CW_CERT_B; + else + s->internal->state = SSL3_ST_CW_CERT_C; + } + + /* We need to get a client cert */ + if (s->internal->state == SSL3_ST_CW_CERT_B) { + /* + * If we get an error, we need to + * ssl->rwstate=SSL_X509_LOOKUP; return(-1); + * We then get retied later + */ + i = ssl_do_client_cert_cb(s, &x509, &pkey); + if (i < 0) { + s->internal->rwstate = SSL_X509_LOOKUP; + return (-1); + } + s->internal->rwstate = SSL_NOTHING; + if ((i == 1) && (pkey != NULL) && (x509 != NULL)) { + s->internal->state = SSL3_ST_CW_CERT_B; + if (!SSL_use_certificate(s, x509) || + !SSL_use_PrivateKey(s, pkey)) + i = 0; + } else if (i == 1) { + i = 0; + SSLerr(SSL_F_SSL3_SEND_CLIENT_CERTIFICATE, + SSL_R_BAD_DATA_RETURNED_BY_CALLBACK); + } + + X509_free(x509); + EVP_PKEY_free(pkey); + if (i == 0) + S3I(s)->tmp.cert_req = 2; + + /* Ok, we have a cert */ + s->internal->state = SSL3_ST_CW_CERT_C; + } + + if (s->internal->state == SSL3_ST_CW_CERT_C) { + if (!ssl3_handshake_msg_start_cbb(s, &cbb, &client_cert, + SSL3_MT_CERTIFICATE)) + goto err; + if (!ssl3_output_cert_chain(s, &client_cert, + (S3I(s)->tmp.cert_req == 2) ? NULL : s->cert->key->x509)) + goto err; + if (!ssl3_handshake_msg_finish_cbb(s, &cbb)) + goto err; + + s->internal->state = SSL3_ST_CW_CERT_D; + } + + /* SSL3_ST_CW_CERT_D */ + return (ssl3_do_write(s, SSL3_RT_HANDSHAKE)); + + err: + CBB_cleanup(&cbb); + + return (0); +} + +#define has_bits(i,m) (((i)&(m)) == (m)) + +int +ssl3_check_cert_and_algorithm(SSL *s) +{ + int i, idx; + long alg_k, alg_a; + EVP_PKEY *pkey = NULL; + SESS_CERT *sc; + DH *dh; + + alg_k = S3I(s)->tmp.new_cipher->algorithm_mkey; + alg_a = S3I(s)->tmp.new_cipher->algorithm_auth; + + /* We don't have a certificate. */ + if (alg_a & SSL_aNULL) + return (1); + + sc = SSI(s)->sess_cert; + if (sc == NULL) { + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, + ERR_R_INTERNAL_ERROR); + goto err; + } + dh = SSI(s)->sess_cert->peer_dh_tmp; + + /* This is the passed certificate. */ + + idx = sc->peer_cert_type; + if (idx == SSL_PKEY_ECC) { + if (ssl_check_srvr_ecc_cert_and_alg( + sc->peer_pkeys[idx].x509, s) == 0) { + /* check failed */ + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, + SSL_R_BAD_ECC_CERT); + goto f_err; + } else { + return (1); + } + } + pkey = X509_get_pubkey(sc->peer_pkeys[idx].x509); + i = X509_certificate_type(sc->peer_pkeys[idx].x509, pkey); + EVP_PKEY_free(pkey); + + /* Check that we have a certificate if we require one. */ + if ((alg_a & SSL_aRSA) && !has_bits(i, EVP_PK_RSA|EVP_PKT_SIGN)) { + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, + SSL_R_MISSING_RSA_SIGNING_CERT); + goto f_err; + } else if ((alg_a & SSL_aDSS) && + !has_bits(i, EVP_PK_DSA|EVP_PKT_SIGN)) { + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, + SSL_R_MISSING_DSA_SIGNING_CERT); + goto f_err; + } + if ((alg_k & SSL_kRSA) && + !has_bits(i, EVP_PK_RSA|EVP_PKT_ENC)) { + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, + SSL_R_MISSING_RSA_ENCRYPTING_CERT); + goto f_err; + } + if ((alg_k & SSL_kDHE) && + !(has_bits(i, EVP_PK_DH|EVP_PKT_EXCH) || (dh != NULL))) { + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, + SSL_R_MISSING_DH_KEY); + goto f_err; + } + + return (1); +f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); +err: + return (0); +} + +int +ssl3_send_next_proto(SSL *s) +{ + unsigned int len, padding_len; + unsigned char *d, *p; + + if (s->internal->state == SSL3_ST_CW_NEXT_PROTO_A) { + d = p = ssl3_handshake_msg_start(s, SSL3_MT_NEXT_PROTO); + + len = s->internal->next_proto_negotiated_len; + padding_len = 32 - ((len + 2) % 32); + *(p++) = len; + memcpy(p, s->internal->next_proto_negotiated, len); + p += len; + *(p++) = padding_len; + memset(p, 0, padding_len); + p += padding_len; + + ssl3_handshake_msg_finish(s, p - d); + + s->internal->state = SSL3_ST_CW_NEXT_PROTO_B; + } + + return (ssl3_handshake_write(s)); +} + +/* + * Check to see if handshake is full or resumed. Usually this is just a + * case of checking to see if a cache hit has occurred. In the case of + * session tickets we have to check the next message to be sure. + */ + +int +ssl3_check_finished(SSL *s) +{ + int ok; + long n; + + /* If we have no ticket it cannot be a resumed session. */ + if (!s->session->tlsext_tick) + return (1); + /* this function is called when we really expect a Certificate + * message, so permit appropriate message length */ + n = s->method->internal->ssl_get_message(s, SSL3_ST_CR_CERT_A, + SSL3_ST_CR_CERT_B, -1, s->internal->max_cert_list, &ok); + if (!ok) + return ((int)n); + S3I(s)->tmp.reuse_message = 1; + if ((S3I(s)->tmp.message_type == SSL3_MT_FINISHED) || + (S3I(s)->tmp.message_type == SSL3_MT_NEWSESSION_TICKET)) + return (2); + + return (1); +} + +int +ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey) +{ + int i = 0; + +#ifndef OPENSSL_NO_ENGINE + if (s->ctx->internal->client_cert_engine) { + i = ENGINE_load_ssl_client_cert( + s->ctx->internal->client_cert_engine, s, + SSL_get_client_CA_list(s), px509, ppkey, NULL, NULL, NULL); + if (i != 0) + return (i); + } +#endif + if (s->ctx->internal->client_cert_cb) + i = s->ctx->internal->client_cert_cb(s, px509, ppkey); + return (i); +} diff --git a/src/lib/libssl/ssl_pkt.c b/src/lib/libssl/ssl_pkt.c new file mode 100644 index 0000000000..2ab264f33f --- /dev/null +++ b/src/lib/libssl/ssl_pkt.c @@ -0,0 +1,1446 @@ +/* $OpenBSD: ssl_pkt.c,v 1.1 2017/01/26 05:51:54 jsing Exp $ */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include +#include + +#include "ssl_locl.h" + +#include +#include + +#include "bytestring.h" + +static int do_ssl3_write(SSL *s, int type, const unsigned char *buf, + unsigned int len, int create_empty_fragment); +static int ssl3_get_record(SSL *s); + +/* If extend == 0, obtain new n-byte packet; if extend == 1, increase + * packet by another n bytes. + * The packet will be in the sub-array of s->s3->rbuf.buf specified + * by s->internal->packet and s->internal->packet_length. + * (If s->internal->read_ahead is set, 'max' bytes may be stored in rbuf + * [plus s->internal->packet_length bytes if extend == 1].) + */ +static int +ssl3_read_n(SSL *s, int n, int max, int extend) +{ + int i, len, left; + size_t align; + unsigned char *pkt; + SSL3_BUFFER *rb; + + if (n <= 0) + return n; + + rb = &(s->s3->rbuf); + if (rb->buf == NULL) + if (!ssl3_setup_read_buffer(s)) + return -1; + + left = rb->left; + align = (size_t)rb->buf + SSL3_RT_HEADER_LENGTH; + align = (-align) & (SSL3_ALIGN_PAYLOAD - 1); + + if (!extend) { + /* start with empty packet ... */ + if (left == 0) + rb->offset = align; + else if (align != 0 && left >= SSL3_RT_HEADER_LENGTH) { + /* check if next packet length is large + * enough to justify payload alignment... */ + pkt = rb->buf + rb->offset; + if (pkt[0] == SSL3_RT_APPLICATION_DATA && + (pkt[3]<<8|pkt[4]) >= 128) { + /* Note that even if packet is corrupted + * and its length field is insane, we can + * only be led to wrong decision about + * whether memmove will occur or not. + * Header values has no effect on memmove + * arguments and therefore no buffer + * overrun can be triggered. */ + memmove(rb->buf + align, pkt, left); + rb->offset = align; + } + } + s->internal->packet = rb->buf + rb->offset; + s->internal->packet_length = 0; + /* ... now we can act as if 'extend' was set */ + } + + /* For DTLS/UDP reads should not span multiple packets + * because the read operation returns the whole packet + * at once (as long as it fits into the buffer). */ + if (SSL_IS_DTLS(s)) { + if (left > 0 && n > left) + n = left; + } + + /* if there is enough in the buffer from a previous read, take some */ + if (left >= n) { + s->internal->packet_length += n; + rb->left = left - n; + rb->offset += n; + return (n); + } + + /* else we need to read more data */ + + len = s->internal->packet_length; + pkt = rb->buf + align; + /* Move any available bytes to front of buffer: + * 'len' bytes already pointed to by 'packet', + * 'left' extra ones at the end */ + if (s->internal->packet != pkt) { + /* len > 0 */ + memmove(pkt, s->internal->packet, len + left); + s->internal->packet = pkt; + rb->offset = len + align; + } + + if (n > (int)(rb->len - rb->offset)) { + /* does not happen */ + SSLerr(SSL_F_SSL3_READ_N, ERR_R_INTERNAL_ERROR); + return -1; + } + + if (!s->internal->read_ahead) { + /* ignore max parameter */ + max = n; + } else { + if (max < n) + max = n; + if (max > (int)(rb->len - rb->offset)) + max = rb->len - rb->offset; + } + + while (left < n) { + /* Now we have len+left bytes at the front of s->s3->rbuf.buf + * and need to read in more until we have len+n (up to + * len+max if possible) */ + + errno = 0; + if (s->rbio != NULL) { + s->internal->rwstate = SSL_READING; + i = BIO_read(s->rbio, pkt + len + left, max - left); + } else { + SSLerr(SSL_F_SSL3_READ_N, SSL_R_READ_BIO_NOT_SET); + i = -1; + } + + if (i <= 0) { + rb->left = left; + if (s->internal->mode & SSL_MODE_RELEASE_BUFFERS && + !SSL_IS_DTLS(s)) { + if (len + left == 0) + ssl3_release_read_buffer(s); + } + return (i); + } + left += i; + + /* + * reads should *never* span multiple packets for DTLS because + * the underlying transport protocol is message oriented as + * opposed to byte oriented as in the TLS case. + */ + if (SSL_IS_DTLS(s)) { + if (n > left) + n = left; /* makes the while condition false */ + } + } + + /* done reading, now the book-keeping */ + rb->offset += n; + rb->left = left - n; + s->internal->packet_length += n; + s->internal->rwstate = SSL_NOTHING; + + return (n); +} + +int +ssl3_packet_read(SSL *s, int plen) +{ + int n; + + n = ssl3_read_n(s, plen, s->s3->rbuf.len, 0); + if (n <= 0) + return n; + if (s->internal->packet_length < plen) + return s->internal->packet_length; + + return plen; +} + +int +ssl3_packet_extend(SSL *s, int plen) +{ + int rlen, n; + + if (s->internal->packet_length >= plen) + return plen; + rlen = plen - s->internal->packet_length; + + n = ssl3_read_n(s, rlen, rlen, 1); + if (n <= 0) + return n; + if (s->internal->packet_length < plen) + return s->internal->packet_length; + + return plen; +} + +/* Call this to get a new input record. + * It will return <= 0 if more data is needed, normally due to an error + * or non-blocking IO. + * When it finishes, one packet has been decoded and can be found in + * ssl->s3->internal->rrec.type - is the type of record + * ssl->s3->internal->rrec.data, - data + * ssl->s3->internal->rrec.length, - number of bytes + */ +/* used only by ssl3_read_bytes */ +static int +ssl3_get_record(SSL *s) +{ + int al; + int enc_err, n, i, ret = -1; + SSL3_RECORD *rr; + SSL_SESSION *sess; + unsigned char md[EVP_MAX_MD_SIZE]; + unsigned mac_size, orig_len; + + rr = &(S3I(s)->rrec); + sess = s->session; + +again: + /* check if we have the header */ + if ((s->internal->rstate != SSL_ST_READ_BODY) || + (s->internal->packet_length < SSL3_RT_HEADER_LENGTH)) { + CBS header; + uint16_t len, ssl_version; + uint8_t type; + + n = ssl3_packet_read(s, SSL3_RT_HEADER_LENGTH); + if (n <= 0) + return (n); + + s->internal->mac_packet = 1; + s->internal->rstate = SSL_ST_READ_BODY; + + if (s->server && s->internal->first_packet) { + if ((ret = ssl_server_legacy_first_packet(s)) != 1) + return (ret); + ret = -1; + } + + CBS_init(&header, s->internal->packet, SSL3_RT_HEADER_LENGTH); + + /* Pull apart the header into the SSL3_RECORD */ + if (!CBS_get_u8(&header, &type) || + !CBS_get_u16(&header, &ssl_version) || + !CBS_get_u16(&header, &len)) { + SSLerr(SSL_F_SSL3_GET_RECORD, + SSL_R_BAD_PACKET_LENGTH); + goto err; + } + + rr->type = type; + rr->length = len; + + /* Lets check version */ + if (!s->internal->first_packet && ssl_version != s->version) { + SSLerr(SSL_F_SSL3_GET_RECORD, + SSL_R_WRONG_VERSION_NUMBER); + if ((s->version & 0xFF00) == (ssl_version & 0xFF00) && + !s->internal->enc_write_ctx && !s->internal->write_hash) + /* Send back error using their minor version number :-) */ + s->version = ssl_version; + al = SSL_AD_PROTOCOL_VERSION; + goto f_err; + } + + if ((ssl_version >> 8) != SSL3_VERSION_MAJOR) { + SSLerr(SSL_F_SSL3_GET_RECORD, + SSL_R_WRONG_VERSION_NUMBER); + goto err; + } + + if (rr->length > s->s3->rbuf.len - SSL3_RT_HEADER_LENGTH) { + al = SSL_AD_RECORD_OVERFLOW; + SSLerr(SSL_F_SSL3_GET_RECORD, + SSL_R_PACKET_LENGTH_TOO_LONG); + goto f_err; + } + + /* now s->internal->rstate == SSL_ST_READ_BODY */ + } + + /* s->internal->rstate == SSL_ST_READ_BODY, get and decode the data */ + + n = ssl3_packet_extend(s, SSL3_RT_HEADER_LENGTH + rr->length); + if (n <= 0) + return (n); + if (n != SSL3_RT_HEADER_LENGTH + rr->length) + return (n); + + s->internal->rstate = SSL_ST_READ_HEADER; /* set state for later operations */ + + /* At this point, s->internal->packet_length == SSL3_RT_HEADER_LNGTH + rr->length, + * and we have that many bytes in s->internal->packet + */ + rr->input = &(s->internal->packet[SSL3_RT_HEADER_LENGTH]); + + /* ok, we can now read from 's->internal->packet' data into 'rr' + * rr->input points at rr->length bytes, which + * need to be copied into rr->data by either + * the decryption or by the decompression + * When the data is 'copied' into the rr->data buffer, + * rr->input will be pointed at the new buffer */ + + /* We now have - encrypted [ MAC [ compressed [ plain ] ] ] + * rr->length bytes of encrypted compressed stuff. */ + + /* check is not needed I believe */ + if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH) { + al = SSL_AD_RECORD_OVERFLOW; + SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_ENCRYPTED_LENGTH_TOO_LONG); + goto f_err; + } + + /* decrypt in place in 'rr->input' */ + rr->data = rr->input; + + enc_err = s->method->internal->ssl3_enc->enc(s, 0); + /* enc_err is: + * 0: (in non-constant time) if the record is publically invalid. + * 1: if the padding is valid + * -1: if the padding is invalid */ + if (enc_err == 0) { + al = SSL_AD_DECRYPTION_FAILED; + SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_BLOCK_CIPHER_PAD_IS_WRONG); + goto f_err; + } + + + /* r->length is now the compressed data plus mac */ + if ((sess != NULL) && (s->enc_read_ctx != NULL) && + (EVP_MD_CTX_md(s->read_hash) != NULL)) { + /* s->read_hash != NULL => mac_size != -1 */ + unsigned char *mac = NULL; + unsigned char mac_tmp[EVP_MAX_MD_SIZE]; + + mac_size = EVP_MD_CTX_size(s->read_hash); + OPENSSL_assert(mac_size <= EVP_MAX_MD_SIZE); + + /* kludge: *_cbc_remove_padding passes padding length in rr->type */ + orig_len = rr->length + ((unsigned int)rr->type >> 8); + + /* orig_len is the length of the record before any padding was + * removed. This is public information, as is the MAC in use, + * therefore we can safely process the record in a different + * amount of time if it's too short to possibly contain a MAC. + */ + if (orig_len < mac_size || + /* CBC records must have a padding length byte too. */ + (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE && + orig_len < mac_size + 1)) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_LENGTH_TOO_SHORT); + goto f_err; + } + + if (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE) { + /* We update the length so that the TLS header bytes + * can be constructed correctly but we need to extract + * the MAC in constant time from within the record, + * without leaking the contents of the padding bytes. + * */ + mac = mac_tmp; + ssl3_cbc_copy_mac(mac_tmp, rr, mac_size, orig_len); + rr->length -= mac_size; + } else { + /* In this case there's no padding, so |orig_len| + * equals |rec->length| and we checked that there's + * enough bytes for |mac_size| above. */ + rr->length -= mac_size; + mac = &rr->data[rr->length]; + } + + i = s->method->internal->ssl3_enc->mac(s,md,0 /* not send */); + if (i < 0 || mac == NULL || + timingsafe_memcmp(md, mac, (size_t)mac_size) != 0) + enc_err = -1; + if (rr->length > + SSL3_RT_MAX_COMPRESSED_LENGTH + mac_size) + enc_err = -1; + } + + if (enc_err < 0) { + /* + * A separate 'decryption_failed' alert was introduced with + * TLS 1.0, SSL 3.0 only has 'bad_record_mac'. But unless a + * decryption failure is directly visible from the ciphertext + * anyway, we should not reveal which kind of error + * occurred -- this might become visible to an attacker + * (e.g. via a logfile) + */ + al = SSL_AD_BAD_RECORD_MAC; + SSLerr(SSL_F_SSL3_GET_RECORD, + SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC); + goto f_err; + } + + if (rr->length > SSL3_RT_MAX_PLAIN_LENGTH) { + al = SSL_AD_RECORD_OVERFLOW; + SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_DATA_LENGTH_TOO_LONG); + goto f_err; + } + + rr->off = 0; + /* + * So at this point the following is true + * + * ssl->s3->internal->rrec.type is the type of record + * ssl->s3->internal->rrec.length == number of bytes in record + * ssl->s3->internal->rrec.off == offset to first valid byte + * ssl->s3->internal->rrec.data == where to take bytes from, increment + * after use :-). + */ + + /* we have pulled in a full packet so zero things */ + s->internal->packet_length = 0; + + /* just read a 0 length packet */ + if (rr->length == 0) + goto again; + + return (1); + +f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); +err: + return (ret); +} + +/* Call this to write data in records of type 'type' + * It will return <= 0 if not all data has been sent or non-blocking IO. + */ +int +ssl3_write_bytes(SSL *s, int type, const void *buf_, int len) +{ + const unsigned char *buf = buf_; + unsigned int tot, n, nw; + int i; + + if (len < 0) { + SSLerr(SSL_F_SSL3_WRITE_BYTES, ERR_R_INTERNAL_ERROR); + return -1; + } + + s->internal->rwstate = SSL_NOTHING; + tot = S3I(s)->wnum; + S3I(s)->wnum = 0; + + if (SSL_in_init(s) && !s->internal->in_handshake) { + i = s->internal->handshake_func(s); + if (i < 0) + return (i); + if (i == 0) { + SSLerr(SSL_F_SSL3_WRITE_BYTES, + SSL_R_SSL_HANDSHAKE_FAILURE); + return -1; + } + } + + if (len < tot) + len = tot; + n = (len - tot); + for (;;) { + if (n > s->max_send_fragment) + nw = s->max_send_fragment; + else + nw = n; + + i = do_ssl3_write(s, type, &(buf[tot]), nw, 0); + if (i <= 0) { + S3I(s)->wnum = tot; + return i; + } + + if ((i == (int)n) || (type == SSL3_RT_APPLICATION_DATA && + (s->internal->mode & SSL_MODE_ENABLE_PARTIAL_WRITE))) { + /* + * Next chunk of data should get another prepended + * empty fragment in ciphersuites with known-IV + * weakness. + */ + S3I(s)->empty_fragment_done = 0; + + return tot + i; + } + + n -= i; + tot += i; + } +} + +static int +do_ssl3_write(SSL *s, int type, const unsigned char *buf, + unsigned int len, int create_empty_fragment) +{ + unsigned char *p, *plen; + int i, mac_size, clear = 0; + int prefix_len = 0; + int eivlen; + size_t align; + SSL3_RECORD *wr; + SSL3_BUFFER *wb = &(s->s3->wbuf); + SSL_SESSION *sess; + + if (wb->buf == NULL) + if (!ssl3_setup_write_buffer(s)) + return -1; + + /* first check if there is a SSL3_BUFFER still being written + * out. This will happen with non blocking IO */ + if (wb->left != 0) + return (ssl3_write_pending(s, type, buf, len)); + + /* If we have an alert to send, lets send it */ + if (s->s3->alert_dispatch) { + i = s->method->ssl_dispatch_alert(s); + if (i <= 0) + return (i); + /* if it went, fall through and send more stuff */ + /* we may have released our buffer, so get it again */ + if (wb->buf == NULL) + if (!ssl3_setup_write_buffer(s)) + return -1; + } + + if (len == 0 && !create_empty_fragment) + return 0; + + wr = &(S3I(s)->wrec); + sess = s->session; + + if ((sess == NULL) || (s->internal->enc_write_ctx == NULL) || + (EVP_MD_CTX_md(s->internal->write_hash) == NULL)) { + clear = s->internal->enc_write_ctx ? 0 : 1; /* must be AEAD cipher */ + mac_size = 0; + } else { + mac_size = EVP_MD_CTX_size(s->internal->write_hash); + if (mac_size < 0) + goto err; + } + + /* + * 'create_empty_fragment' is true only when this function calls + * itself. + */ + if (!clear && !create_empty_fragment && !S3I(s)->empty_fragment_done) { + /* + * Countermeasure against known-IV weakness in CBC ciphersuites + * (see http://www.openssl.org/~bodo/tls-cbc.txt) + */ + if (S3I(s)->need_empty_fragments && + type == SSL3_RT_APPLICATION_DATA) { + /* recursive function call with 'create_empty_fragment' set; + * this prepares and buffers the data for an empty fragment + * (these 'prefix_len' bytes are sent out later + * together with the actual payload) */ + prefix_len = do_ssl3_write(s, type, buf, 0, 1); + if (prefix_len <= 0) + goto err; + + if (prefix_len > + (SSL3_RT_HEADER_LENGTH + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD)) { + /* insufficient space */ + SSLerr(SSL_F_DO_SSL3_WRITE, + ERR_R_INTERNAL_ERROR); + goto err; + } + } + + S3I(s)->empty_fragment_done = 1; + } + + if (create_empty_fragment) { + /* extra fragment would be couple of cipher blocks, + * which would be multiple of SSL3_ALIGN_PAYLOAD, so + * if we want to align the real payload, then we can + * just pretent we simply have two headers. */ + align = (size_t)wb->buf + 2 * SSL3_RT_HEADER_LENGTH; + align = (-align) & (SSL3_ALIGN_PAYLOAD - 1); + + p = wb->buf + align; + wb->offset = align; + } else if (prefix_len) { + p = wb->buf + wb->offset + prefix_len; + } else { + align = (size_t)wb->buf + SSL3_RT_HEADER_LENGTH; + align = (-align) & (SSL3_ALIGN_PAYLOAD - 1); + + p = wb->buf + align; + wb->offset = align; + } + + /* write the header */ + + *(p++) = type&0xff; + wr->type = type; + + *(p++) = (s->version >> 8); + /* Some servers hang if iniatial client hello is larger than 256 + * bytes and record version number > TLS 1.0 + */ + if (s->internal->state == SSL3_ST_CW_CLNT_HELLO_B && !s->internal->renegotiate && + TLS1_get_version(s) > TLS1_VERSION) + *(p++) = 0x1; + else + *(p++) = s->version&0xff; + + /* field where we are to write out packet length */ + plen = p; + p += 2; + + /* Explicit IV length. */ + if (s->internal->enc_write_ctx && SSL_USE_EXPLICIT_IV(s)) { + int mode = EVP_CIPHER_CTX_mode(s->internal->enc_write_ctx); + if (mode == EVP_CIPH_CBC_MODE) { + eivlen = EVP_CIPHER_CTX_iv_length(s->internal->enc_write_ctx); + if (eivlen <= 1) + eivlen = 0; + } + /* Need explicit part of IV for GCM mode */ + else if (mode == EVP_CIPH_GCM_MODE) + eivlen = EVP_GCM_TLS_EXPLICIT_IV_LEN; + else + eivlen = 0; + } else if (s->internal->aead_write_ctx != NULL && + s->internal->aead_write_ctx->variable_nonce_in_record) { + eivlen = s->internal->aead_write_ctx->variable_nonce_len; + } else + eivlen = 0; + + /* lets setup the record stuff. */ + wr->data = p + eivlen; + wr->length = (int)len; + wr->input = (unsigned char *)buf; + + /* we now 'read' from wr->input, wr->length bytes into wr->data */ + + memcpy(wr->data, wr->input, wr->length); + wr->input = wr->data; + + /* we should still have the output to wr->data and the input + * from wr->input. Length should be wr->length. + * wr->data still points in the wb->buf */ + + if (mac_size != 0) { + if (s->method->internal->ssl3_enc->mac(s, + &(p[wr->length + eivlen]), 1) < 0) + goto err; + wr->length += mac_size; + } + + wr->input = p; + wr->data = p; + + if (eivlen) { + /* if (RAND_pseudo_bytes(p, eivlen) <= 0) + goto err; + */ + wr->length += eivlen; + } + + /* ssl3_enc can only have an error on read */ + s->method->internal->ssl3_enc->enc(s, 1); + + /* record length after mac and block padding */ + s2n(wr->length, plen); + + /* we should now have + * wr->data pointing to the encrypted data, which is + * wr->length long */ + wr->type=type; /* not needed but helps for debugging */ + wr->length += SSL3_RT_HEADER_LENGTH; + + if (create_empty_fragment) { + /* we are in a recursive call; + * just return the length, don't write out anything here + */ + return wr->length; + } + + /* now let's set up wb */ + wb->left = prefix_len + wr->length; + + /* memorize arguments so that ssl3_write_pending can detect + * bad write retries later */ + S3I(s)->wpend_tot = len; + S3I(s)->wpend_buf = buf; + S3I(s)->wpend_type = type; + S3I(s)->wpend_ret = len; + + /* we now just need to write the buffer */ + return ssl3_write_pending(s, type, buf, len); +err: + return -1; +} + +/* if s->s3->wbuf.left != 0, we need to call this */ +int +ssl3_write_pending(SSL *s, int type, const unsigned char *buf, unsigned int len) +{ + int i; + SSL3_BUFFER *wb = &(s->s3->wbuf); + + /* XXXX */ + if ((S3I(s)->wpend_tot > (int)len) || ((S3I(s)->wpend_buf != buf) && + !(s->internal->mode & SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER)) || + (S3I(s)->wpend_type != type)) { + SSLerr(SSL_F_SSL3_WRITE_PENDING, SSL_R_BAD_WRITE_RETRY); + return (-1); + } + + for (;;) { + errno = 0; + if (s->wbio != NULL) { + s->internal->rwstate = SSL_WRITING; + i = BIO_write(s->wbio, + (char *)&(wb->buf[wb->offset]), + (unsigned int)wb->left); + } else { + SSLerr(SSL_F_SSL3_WRITE_PENDING, SSL_R_BIO_NOT_SET); + i = -1; + } + if (i == wb->left) { + wb->left = 0; + wb->offset += i; + if (s->internal->mode & SSL_MODE_RELEASE_BUFFERS && + !SSL_IS_DTLS(s)) + ssl3_release_write_buffer(s); + s->internal->rwstate = SSL_NOTHING; + return (S3I(s)->wpend_ret); + } else if (i <= 0) { + /* + * For DTLS, just drop it. That's kind of the + * whole point in using a datagram service. + */ + if (SSL_IS_DTLS(s)) + wb->left = 0; + return (i); + } + wb->offset += i; + wb->left -= i; + } +} + +/* Return up to 'len' payload bytes received in 'type' records. + * 'type' is one of the following: + * + * - SSL3_RT_HANDSHAKE (when ssl3_get_message calls us) + * - SSL3_RT_APPLICATION_DATA (when ssl3_read calls us) + * - 0 (during a shutdown, no data has to be returned) + * + * If we don't have stored data to work from, read a SSL/TLS record first + * (possibly multiple records if we still don't have anything to return). + * + * This function must handle any surprises the peer may have for us, such as + * Alert records (e.g. close_notify), ChangeCipherSpec records (not really + * a surprise, but handled as if it were), or renegotiation requests. + * Also if record payloads contain fragments too small to process, we store + * them until there is enough for the respective protocol (the record protocol + * may use arbitrary fragmentation and even interleaving): + * Change cipher spec protocol + * just 1 byte needed, no need for keeping anything stored + * Alert protocol + * 2 bytes needed (AlertLevel, AlertDescription) + * Handshake protocol + * 4 bytes needed (HandshakeType, uint24 length) -- we just have + * to detect unexpected Client Hello and Hello Request messages + * here, anything else is handled by higher layers + * Application data protocol + * none of our business + */ +int +ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek) +{ + void (*cb)(const SSL *ssl, int type2, int val) = NULL; + int al, i, j, ret, rrcount = 0; + unsigned int n; + SSL3_RECORD *rr; + BIO *bio; + + if (s->s3->rbuf.buf == NULL) /* Not initialized yet */ + if (!ssl3_setup_read_buffer(s)) + return (-1); + + if (len < 0) { + SSLerr(SSL_F_SSL3_READ_BYTES, ERR_R_INTERNAL_ERROR); + return -1; + } + + if ((type && type != SSL3_RT_APPLICATION_DATA && + type != SSL3_RT_HANDSHAKE) || + (peek && (type != SSL3_RT_APPLICATION_DATA))) { + SSLerr(SSL_F_SSL3_READ_BYTES, ERR_R_INTERNAL_ERROR); + return -1; + } + + if ((type == SSL3_RT_HANDSHAKE) && + (S3I(s)->handshake_fragment_len > 0)) { + /* (partially) satisfy request from storage */ + unsigned char *src = S3I(s)->handshake_fragment; + unsigned char *dst = buf; + unsigned int k; + + /* peek == 0 */ + n = 0; + while ((len > 0) && (S3I(s)->handshake_fragment_len > 0)) { + *dst++ = *src++; + len--; + S3I(s)->handshake_fragment_len--; + n++; + } + /* move any remaining fragment bytes: */ + for (k = 0; k < S3I(s)->handshake_fragment_len; k++) + S3I(s)->handshake_fragment[k] = *src++; + return n; + } + + /* + * Now S3I(s)->handshake_fragment_len == 0 if + * type == SSL3_RT_HANDSHAKE. + */ + if (!s->internal->in_handshake && SSL_in_init(s)) { + /* type == SSL3_RT_APPLICATION_DATA */ + i = s->internal->handshake_func(s); + if (i < 0) + return (i); + if (i == 0) { + SSLerr(SSL_F_SSL3_READ_BYTES, + SSL_R_SSL_HANDSHAKE_FAILURE); + return (-1); + } + } + +start: + /* + * Do not process more than three consecutive records, otherwise the + * peer can cause us to loop indefinitely. Instead, return with an + * SSL_ERROR_WANT_READ so the caller can choose when to handle further + * processing. In the future, the total number of non-handshake and + * non-application data records per connection should probably also be + * limited... + */ + if (rrcount++ >= 3) { + if ((bio = SSL_get_rbio(s)) == NULL) { + SSLerr(SSL_F_SSL3_READ_BYTES, ERR_R_INTERNAL_ERROR); + return -1; + } + BIO_clear_retry_flags(bio); + BIO_set_retry_read(bio); + s->internal->rwstate = SSL_READING; + return -1; + } + + s->internal->rwstate = SSL_NOTHING; + + /* + * S3I(s)->rrec.type - is the type of record + * S3I(s)->rrec.data, - data + * S3I(s)->rrec.off, - offset into 'data' for next read + * S3I(s)->rrec.length, - number of bytes. + */ + rr = &(S3I(s)->rrec); + + /* get new packet if necessary */ + if ((rr->length == 0) || (s->internal->rstate == SSL_ST_READ_BODY)) { + ret = ssl3_get_record(s); + if (ret <= 0) + return (ret); + } + + /* we now have a packet which can be read and processed */ + + if (S3I(s)->change_cipher_spec /* set when we receive ChangeCipherSpec, + * reset by ssl3_get_finished */ + && (rr->type != SSL3_RT_HANDSHAKE)) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_SSL3_READ_BYTES, + SSL_R_DATA_BETWEEN_CCS_AND_FINISHED); + goto f_err; + } + + /* If the other end has shut down, throw anything we read away + * (even in 'peek' mode) */ + if (s->internal->shutdown & SSL_RECEIVED_SHUTDOWN) { + rr->length = 0; + s->internal->rwstate = SSL_NOTHING; + return (0); + } + + + /* SSL3_RT_APPLICATION_DATA or SSL3_RT_HANDSHAKE */ + if (type == rr->type) { + /* make sure that we are not getting application data when we + * are doing a handshake for the first time */ + if (SSL_in_init(s) && (type == SSL3_RT_APPLICATION_DATA) && + (s->enc_read_ctx == NULL)) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_SSL3_READ_BYTES, + SSL_R_APP_DATA_IN_HANDSHAKE); + goto f_err; + } + + if (len <= 0) + return (len); + + if ((unsigned int)len > rr->length) + n = rr->length; + else + n = (unsigned int)len; + + memcpy(buf, &(rr->data[rr->off]), n); + if (!peek) { + memset(&(rr->data[rr->off]), 0, n); + rr->length -= n; + rr->off += n; + if (rr->length == 0) { + s->internal->rstate = SSL_ST_READ_HEADER; + rr->off = 0; + if (s->internal->mode & SSL_MODE_RELEASE_BUFFERS && + s->s3->rbuf.left == 0) + ssl3_release_read_buffer(s); + } + } + return (n); + } + + + /* If we get here, then type != rr->type; if we have a handshake + * message, then it was unexpected (Hello Request or Client Hello). */ + + { + /* + * In case of record types for which we have 'fragment' + * storage, * fill that so that we can process the data + * at a fixed place. + */ + unsigned int dest_maxlen = 0; + unsigned char *dest = NULL; + unsigned int *dest_len = NULL; + + if (rr->type == SSL3_RT_HANDSHAKE) { + dest_maxlen = sizeof S3I(s)->handshake_fragment; + dest = S3I(s)->handshake_fragment; + dest_len = &S3I(s)->handshake_fragment_len; + } else if (rr->type == SSL3_RT_ALERT) { + dest_maxlen = sizeof S3I(s)->alert_fragment; + dest = S3I(s)->alert_fragment; + dest_len = &S3I(s)->alert_fragment_len; + } + if (dest_maxlen > 0) { + /* available space in 'dest' */ + n = dest_maxlen - *dest_len; + if (rr->length < n) + n = rr->length; /* available bytes */ + + /* now move 'n' bytes: */ + while (n-- > 0) { + dest[(*dest_len)++] = rr->data[rr->off++]; + rr->length--; + } + + if (*dest_len < dest_maxlen) + goto start; /* fragment was too small */ + } + } + + /* S3I(s)->handshake_fragment_len == 4 iff rr->type == SSL3_RT_HANDSHAKE; + * S3I(s)->alert_fragment_len == 2 iff rr->type == SSL3_RT_ALERT. + * (Possibly rr is 'empty' now, i.e. rr->length may be 0.) */ + + /* If we are a client, check for an incoming 'Hello Request': */ + if ((!s->server) && (S3I(s)->handshake_fragment_len >= 4) && + (S3I(s)->handshake_fragment[0] == SSL3_MT_HELLO_REQUEST) && + (s->session != NULL) && (s->session->cipher != NULL)) { + S3I(s)->handshake_fragment_len = 0; + + if ((S3I(s)->handshake_fragment[1] != 0) || + (S3I(s)->handshake_fragment[2] != 0) || + (S3I(s)->handshake_fragment[3] != 0)) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_BAD_HELLO_REQUEST); + goto f_err; + } + + if (s->internal->msg_callback) + s->internal->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, + S3I(s)->handshake_fragment, 4, s, + s->internal->msg_callback_arg); + + if (SSL_is_init_finished(s) && + !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) && + !S3I(s)->renegotiate) { + ssl3_renegotiate(s); + if (ssl3_renegotiate_check(s)) { + i = s->internal->handshake_func(s); + if (i < 0) + return (i); + if (i == 0) { + SSLerr(SSL_F_SSL3_READ_BYTES, + SSL_R_SSL_HANDSHAKE_FAILURE); + return (-1); + } + + if (!(s->internal->mode & SSL_MODE_AUTO_RETRY)) { + if (s->s3->rbuf.left == 0) { + /* no read-ahead left? */ + /* In the case where we try to read application data, + * but we trigger an SSL handshake, we return -1 with + * the retry option set. Otherwise renegotiation may + * cause nasty problems in the blocking world */ + s->internal->rwstate = SSL_READING; + bio = SSL_get_rbio(s); + BIO_clear_retry_flags(bio); + BIO_set_retry_read(bio); + return (-1); + } + } + } + } + /* we either finished a handshake or ignored the request, + * now try again to obtain the (application) data we were asked for */ + goto start; + } + /* If we are a server and get a client hello when renegotiation isn't + * allowed send back a no renegotiation alert and carry on. + * WARNING: experimental code, needs reviewing (steve) + */ + if (s->server && + SSL_is_init_finished(s) && + !S3I(s)->send_connection_binding && + (S3I(s)->handshake_fragment_len >= 4) && + (S3I(s)->handshake_fragment[0] == SSL3_MT_CLIENT_HELLO) && + (s->session != NULL) && (s->session->cipher != NULL)) { + /*S3I(s)->handshake_fragment_len = 0;*/ + rr->length = 0; + ssl3_send_alert(s, SSL3_AL_WARNING, SSL_AD_NO_RENEGOTIATION); + goto start; + } + if (S3I(s)->alert_fragment_len >= 2) { + int alert_level = S3I(s)->alert_fragment[0]; + int alert_descr = S3I(s)->alert_fragment[1]; + + S3I(s)->alert_fragment_len = 0; + + if (s->internal->msg_callback) + s->internal->msg_callback(0, s->version, SSL3_RT_ALERT, + S3I(s)->alert_fragment, 2, s, s->internal->msg_callback_arg); + + if (s->internal->info_callback != NULL) + cb = s->internal->info_callback; + else if (s->ctx->internal->info_callback != NULL) + cb = s->ctx->internal->info_callback; + + if (cb != NULL) { + j = (alert_level << 8) | alert_descr; + cb(s, SSL_CB_READ_ALERT, j); + } + + if (alert_level == SSL3_AL_WARNING) { + S3I(s)->warn_alert = alert_descr; + if (alert_descr == SSL_AD_CLOSE_NOTIFY) { + s->internal->shutdown |= SSL_RECEIVED_SHUTDOWN; + return (0); + } + /* This is a warning but we receive it if we requested + * renegotiation and the peer denied it. Terminate with + * a fatal alert because if application tried to + * renegotiatie it presumably had a good reason and + * expects it to succeed. + * + * In future we might have a renegotiation where we + * don't care if the peer refused it where we carry on. + */ + else if (alert_descr == SSL_AD_NO_RENEGOTIATION) { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_READ_BYTES, + SSL_R_NO_RENEGOTIATION); + goto f_err; + } + } else if (alert_level == SSL3_AL_FATAL) { + s->internal->rwstate = SSL_NOTHING; + S3I(s)->fatal_alert = alert_descr; + SSLerr(SSL_F_SSL3_READ_BYTES, + SSL_AD_REASON_OFFSET + alert_descr); + ERR_asprintf_error_data("SSL alert number %d", + alert_descr); + s->internal->shutdown |= SSL_RECEIVED_SHUTDOWN; + SSL_CTX_remove_session(s->ctx, s->session); + return (0); + } else { + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_UNKNOWN_ALERT_TYPE); + goto f_err; + } + + goto start; + } + + if (s->internal->shutdown & SSL_SENT_SHUTDOWN) { + /* but we have not received a shutdown */ + s->internal->rwstate = SSL_NOTHING; + rr->length = 0; + return (0); + } + + if (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC) { + /* 'Change Cipher Spec' is just a single byte, so we know + * exactly what the record payload has to look like */ + if ((rr->length != 1) || (rr->off != 0) || + (rr->data[0] != SSL3_MT_CCS)) { + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_READ_BYTES, + SSL_R_BAD_CHANGE_CIPHER_SPEC); + goto f_err; + } + + /* Check we have a cipher to change to */ + if (S3I(s)->tmp.new_cipher == NULL) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_SSL3_READ_BYTES, + SSL_R_CCS_RECEIVED_EARLY); + goto f_err; + } + + /* Check that we should be receiving a Change Cipher Spec. */ + if (!(s->s3->flags & SSL3_FLAGS_CCS_OK)) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_SSL3_READ_BYTES, + SSL_R_CCS_RECEIVED_EARLY); + goto f_err; + } + s->s3->flags &= ~SSL3_FLAGS_CCS_OK; + + rr->length = 0; + + if (s->internal->msg_callback) { + s->internal->msg_callback(0, s->version, + SSL3_RT_CHANGE_CIPHER_SPEC, rr->data, 1, s, + s->internal->msg_callback_arg); + } + + S3I(s)->change_cipher_spec = 1; + if (!ssl3_do_change_cipher_spec(s)) + goto err; + else + goto start; + } + + /* Unexpected handshake message (Client Hello, or protocol violation) */ + if ((S3I(s)->handshake_fragment_len >= 4) && !s->internal->in_handshake) { + if (((s->internal->state&SSL_ST_MASK) == SSL_ST_OK) && + !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS)) { + s->internal->state = s->server ? SSL_ST_ACCEPT : SSL_ST_CONNECT; + s->internal->renegotiate = 1; + s->internal->new_session = 1; + } + i = s->internal->handshake_func(s); + if (i < 0) + return (i); + if (i == 0) { + SSLerr(SSL_F_SSL3_READ_BYTES, + SSL_R_SSL_HANDSHAKE_FAILURE); + return (-1); + } + + if (!(s->internal->mode & SSL_MODE_AUTO_RETRY)) { + if (s->s3->rbuf.left == 0) { /* no read-ahead left? */ + BIO *bio; + /* In the case where we try to read application data, + * but we trigger an SSL handshake, we return -1 with + * the retry option set. Otherwise renegotiation may + * cause nasty problems in the blocking world */ + s->internal->rwstate = SSL_READING; + bio = SSL_get_rbio(s); + BIO_clear_retry_flags(bio); + BIO_set_retry_read(bio); + return (-1); + } + } + goto start; + } + + switch (rr->type) { + default: + /* + * TLS up to v1.1 just ignores unknown message types: + * TLS v1.2 give an unexpected message alert. + */ + if (s->version >= TLS1_VERSION && + s->version <= TLS1_1_VERSION) { + rr->length = 0; + goto start; + } + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_UNEXPECTED_RECORD); + goto f_err; + case SSL3_RT_CHANGE_CIPHER_SPEC: + case SSL3_RT_ALERT: + case SSL3_RT_HANDSHAKE: + /* we already handled all of these, with the possible exception + * of SSL3_RT_HANDSHAKE when s->internal->in_handshake is set, but that + * should not happen when type != rr->type */ + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_SSL3_READ_BYTES, ERR_R_INTERNAL_ERROR); + goto f_err; + case SSL3_RT_APPLICATION_DATA: + /* At this point, we were expecting handshake data, + * but have application data. If the library was + * running inside ssl3_read() (i.e. in_read_app_data + * is set) and it makes sense to read application data + * at this point (session renegotiation not yet started), + * we will indulge it. + */ + if (S3I(s)->in_read_app_data && + (S3I(s)->total_renegotiations != 0) && + (((s->internal->state & SSL_ST_CONNECT) && + (s->internal->state >= SSL3_ST_CW_CLNT_HELLO_A) && + (s->internal->state <= SSL3_ST_CR_SRVR_HELLO_A)) || + ((s->internal->state & SSL_ST_ACCEPT) && + (s->internal->state <= SSL3_ST_SW_HELLO_REQ_A) && + (s->internal->state >= SSL3_ST_SR_CLNT_HELLO_A)))) { + S3I(s)->in_read_app_data = 2; + return (-1); + } else { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_UNEXPECTED_RECORD); + goto f_err; + } + } + /* not reached */ + +f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); +err: + return (-1); +} + +int +ssl3_do_change_cipher_spec(SSL *s) +{ + int i; + const char *sender; + int slen; + + if (s->internal->state & SSL_ST_ACCEPT) + i = SSL3_CHANGE_CIPHER_SERVER_READ; + else + i = SSL3_CHANGE_CIPHER_CLIENT_READ; + + if (S3I(s)->tmp.key_block == NULL) { + if (s->session == NULL || s->session->master_key_length == 0) { + /* might happen if dtls1_read_bytes() calls this */ + SSLerr(SSL_F_SSL3_DO_CHANGE_CIPHER_SPEC, + SSL_R_CCS_RECEIVED_EARLY); + return (0); + } + + s->session->cipher = S3I(s)->tmp.new_cipher; + if (!s->method->internal->ssl3_enc->setup_key_block(s)) + return (0); + } + + if (!s->method->internal->ssl3_enc->change_cipher_state(s, i)) + return (0); + + /* we have to record the message digest at + * this point so we can get it before we read + * the finished message */ + if (s->internal->state & SSL_ST_CONNECT) { + sender = s->method->internal->ssl3_enc->server_finished_label; + slen = s->method->internal->ssl3_enc->server_finished_label_len; + } else { + sender = s->method->internal->ssl3_enc->client_finished_label; + slen = s->method->internal->ssl3_enc->client_finished_label_len; + } + + i = s->method->internal->ssl3_enc->final_finish_mac(s, sender, slen, + S3I(s)->tmp.peer_finish_md); + if (i == 0) { + SSLerr(SSL_F_SSL3_DO_CHANGE_CIPHER_SPEC, ERR_R_INTERNAL_ERROR); + return 0; + } + S3I(s)->tmp.peer_finish_md_len = i; + + return (1); +} + +int +ssl3_send_alert(SSL *s, int level, int desc) +{ + /* Map tls/ssl alert value to correct one */ + desc = s->method->internal->ssl3_enc->alert_value(desc); + if (desc < 0) + return -1; + /* If a fatal one, remove from cache */ + if ((level == 2) && (s->session != NULL)) + SSL_CTX_remove_session(s->ctx, s->session); + + s->s3->alert_dispatch = 1; + s->s3->send_alert[0] = level; + s->s3->send_alert[1] = desc; + if (s->s3->wbuf.left == 0) /* data still being written out? */ + return s->method->ssl_dispatch_alert(s); + + /* else data is still being written out, we will get written + * some time in the future */ + return -1; +} + +int +ssl3_dispatch_alert(SSL *s) +{ + int i, j; + void (*cb)(const SSL *ssl, int type, int val) = NULL; + + s->s3->alert_dispatch = 0; + i = do_ssl3_write(s, SSL3_RT_ALERT, &s->s3->send_alert[0], 2, 0); + if (i <= 0) { + s->s3->alert_dispatch = 1; + } else { + /* Alert sent to BIO. If it is important, flush it now. + * If the message does not get sent due to non-blocking IO, + * we will not worry too much. */ + if (s->s3->send_alert[0] == SSL3_AL_FATAL) + (void)BIO_flush(s->wbio); + + if (s->internal->msg_callback) + s->internal->msg_callback(1, s->version, SSL3_RT_ALERT, + s->s3->send_alert, 2, s, s->internal->msg_callback_arg); + + if (s->internal->info_callback != NULL) + cb = s->internal->info_callback; + else if (s->ctx->internal->info_callback != NULL) + cb = s->ctx->internal->info_callback; + + if (cb != NULL) { + j = (s->s3->send_alert[0]<<8)|s->s3->send_alert[1]; + cb(s, SSL_CB_WRITE_ALERT, j); + } + } + return (i); +} diff --git a/src/lib/libssl/ssl_srvr.c b/src/lib/libssl/ssl_srvr.c new file mode 100644 index 0000000000..dfc6ee67b6 --- /dev/null +++ b/src/lib/libssl/ssl_srvr.c @@ -0,0 +1,2923 @@ +/* $OpenBSD: ssl_srvr.c,v 1.1 2017/01/26 05:51:54 jsing Exp $ */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2007 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * ECC cipher suite support in OpenSSL originally written by + * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories. + * + */ +/* ==================================================================== + * Copyright 2005 Nokia. All rights reserved. + * + * The portions of the attached software ("Contribution") is developed by + * Nokia Corporation and is licensed pursuant to the OpenSSL open source + * license. + * + * The Contribution, originally written by Mika Kousa and Pasi Eronen of + * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites + * support (see RFC 4279) to OpenSSL. + * + * No patent licenses or other rights except those expressly stated in + * the OpenSSL open source license shall be deemed granted or received + * expressly, by implication, estoppel, or otherwise. + * + * No assurances are provided by Nokia that the Contribution does not + * infringe the patent or other intellectual property rights of any third + * party or that the license provides you with all the necessary rights + * to make use of the Contribution. + * + * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN + * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA + * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY + * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR + * OTHERWISE. + */ + +#include + +#include "ssl_locl.h" + +#include +#include +#include +#include +#include +#ifndef OPENSSL_NO_GOST +#include +#endif +#include +#include +#include +#include + +#include "bytestring.h" + +int +ssl3_accept(SSL *s) +{ + unsigned long alg_k; + void (*cb)(const SSL *ssl, int type, int val) = NULL; + int ret = -1; + int new_state, state, skip = 0; + + ERR_clear_error(); + errno = 0; + + if (s->internal->info_callback != NULL) + cb = s->internal->info_callback; + else if (s->ctx->internal->info_callback != NULL) + cb = s->ctx->internal->info_callback; + + /* init things to blank */ + s->internal->in_handshake++; + if (!SSL_in_init(s) || SSL_in_before(s)) + SSL_clear(s); + + if (s->cert == NULL) { + SSLerr(SSL_F_SSL3_ACCEPT, SSL_R_NO_CERTIFICATE_SET); + ret = -1; + goto end; + } + + for (;;) { + state = s->internal->state; + + switch (s->internal->state) { + case SSL_ST_RENEGOTIATE: + s->internal->renegotiate = 1; + /* s->internal->state=SSL_ST_ACCEPT; */ + + case SSL_ST_BEFORE: + case SSL_ST_ACCEPT: + case SSL_ST_BEFORE|SSL_ST_ACCEPT: + case SSL_ST_OK|SSL_ST_ACCEPT: + + s->server = 1; + if (cb != NULL) + cb(s, SSL_CB_HANDSHAKE_START, 1); + + if ((s->version >> 8) != 3) { + SSLerr(SSL_F_SSL3_ACCEPT, ERR_R_INTERNAL_ERROR); + ret = -1; + goto end; + } + s->internal->type = SSL_ST_ACCEPT; + + if (!ssl3_setup_init_buffer(s)) { + ret = -1; + goto end; + } + if (!ssl3_setup_buffers(s)) { + ret = -1; + goto end; + } + + s->internal->init_num = 0; + + if (s->internal->state != SSL_ST_RENEGOTIATE) { + /* + * Ok, we now need to push on a buffering BIO + * so that the output is sent in a way that + * TCP likes :-) + */ + if (!ssl_init_wbio_buffer(s, 1)) { + ret = -1; + goto end; + } + + if (!tls1_init_finished_mac(s)) { + ret = -1; + goto end; + } + + s->internal->state = SSL3_ST_SR_CLNT_HELLO_A; + s->ctx->internal->stats.sess_accept++; + } else if (!S3I(s)->send_connection_binding) { + /* + * Server attempting to renegotiate with + * client that doesn't support secure + * renegotiation. + */ + SSLerr(SSL_F_SSL3_ACCEPT, + SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED); + ssl3_send_alert(s, SSL3_AL_FATAL, + SSL_AD_HANDSHAKE_FAILURE); + ret = -1; + goto end; + } else { + /* + * s->internal->state == SSL_ST_RENEGOTIATE, + * we will just send a HelloRequest + */ + s->ctx->internal->stats.sess_accept_renegotiate++; + s->internal->state = SSL3_ST_SW_HELLO_REQ_A; + } + break; + + case SSL3_ST_SW_HELLO_REQ_A: + case SSL3_ST_SW_HELLO_REQ_B: + + s->internal->shutdown = 0; + ret = ssl3_send_hello_request(s); + if (ret <= 0) + goto end; + S3I(s)->tmp.next_state = SSL3_ST_SW_HELLO_REQ_C; + s->internal->state = SSL3_ST_SW_FLUSH; + s->internal->init_num = 0; + + if (!tls1_init_finished_mac(s)) { + ret = -1; + goto end; + } + break; + + case SSL3_ST_SW_HELLO_REQ_C: + s->internal->state = SSL_ST_OK; + break; + + case SSL3_ST_SR_CLNT_HELLO_A: + case SSL3_ST_SR_CLNT_HELLO_B: + case SSL3_ST_SR_CLNT_HELLO_C: + + s->internal->shutdown = 0; + if (s->internal->rwstate != SSL_X509_LOOKUP) { + ret = ssl3_get_client_hello(s); + if (ret <= 0) + goto end; + } + + s->internal->renegotiate = 2; + s->internal->state = SSL3_ST_SW_SRVR_HELLO_A; + s->internal->init_num = 0; + break; + + case SSL3_ST_SW_SRVR_HELLO_A: + case SSL3_ST_SW_SRVR_HELLO_B: + ret = ssl3_send_server_hello(s); + if (ret <= 0) + goto end; + if (s->internal->hit) { + if (s->internal->tlsext_ticket_expected) + s->internal->state = SSL3_ST_SW_SESSION_TICKET_A; + else + s->internal->state = SSL3_ST_SW_CHANGE_A; + } + else + s->internal->state = SSL3_ST_SW_CERT_A; + s->internal->init_num = 0; + break; + + case SSL3_ST_SW_CERT_A: + case SSL3_ST_SW_CERT_B: + /* Check if it is anon DH or anon ECDH. */ + if (!(S3I(s)->tmp.new_cipher->algorithm_auth & + SSL_aNULL)) { + ret = ssl3_send_server_certificate(s); + if (ret <= 0) + goto end; + if (s->internal->tlsext_status_expected) + s->internal->state = SSL3_ST_SW_CERT_STATUS_A; + else + s->internal->state = SSL3_ST_SW_KEY_EXCH_A; + } else { + skip = 1; + s->internal->state = SSL3_ST_SW_KEY_EXCH_A; + } + s->internal->init_num = 0; + break; + + case SSL3_ST_SW_KEY_EXCH_A: + case SSL3_ST_SW_KEY_EXCH_B: + alg_k = S3I(s)->tmp.new_cipher->algorithm_mkey; + + /* + * Only send if using a DH key exchange. + * + * For ECC ciphersuites, we send a ServerKeyExchange + * message only if the cipher suite is ECDHE. In other + * cases, the server certificate contains the server's + * public key for key exchange. + */ + if (alg_k & (SSL_kDHE|SSL_kECDHE)) { + ret = ssl3_send_server_key_exchange(s); + if (ret <= 0) + goto end; + } else + skip = 1; + + s->internal->state = SSL3_ST_SW_CERT_REQ_A; + s->internal->init_num = 0; + break; + + case SSL3_ST_SW_CERT_REQ_A: + case SSL3_ST_SW_CERT_REQ_B: + /* + * Determine whether or not we need to request a + * certificate. + * + * Do not request a certificate if: + * + * - We did not ask for it (SSL_VERIFY_PEER is unset). + * + * - SSL_VERIFY_CLIENT_ONCE is set and we are + * renegotiating. + * + * - We are using an anonymous ciphersuites + * (see section "Certificate request" in SSL 3 drafts + * and in RFC 2246) ... except when the application + * insists on verification (against the specs, but + * s3_clnt.c accepts this for SSL 3). + */ + if (!(s->verify_mode & SSL_VERIFY_PEER) || + ((s->session->peer != NULL) && + (s->verify_mode & SSL_VERIFY_CLIENT_ONCE)) || + ((S3I(s)->tmp.new_cipher->algorithm_auth & + SSL_aNULL) && !(s->verify_mode & + SSL_VERIFY_FAIL_IF_NO_PEER_CERT))) { + /* No cert request */ + skip = 1; + S3I(s)->tmp.cert_request = 0; + s->internal->state = SSL3_ST_SW_SRVR_DONE_A; + if (S3I(s)->handshake_buffer) { + if (!tls1_digest_cached_records(s)) { + ret = -1; + goto end; + } + } + } else { + S3I(s)->tmp.cert_request = 1; + ret = ssl3_send_certificate_request(s); + if (ret <= 0) + goto end; + s->internal->state = SSL3_ST_SW_SRVR_DONE_A; + s->internal->init_num = 0; + } + break; + + case SSL3_ST_SW_SRVR_DONE_A: + case SSL3_ST_SW_SRVR_DONE_B: + ret = ssl3_send_server_done(s); + if (ret <= 0) + goto end; + S3I(s)->tmp.next_state = SSL3_ST_SR_CERT_A; + s->internal->state = SSL3_ST_SW_FLUSH; + s->internal->init_num = 0; + break; + + case SSL3_ST_SW_FLUSH: + + /* + * This code originally checked to see if + * any data was pending using BIO_CTRL_INFO + * and then flushed. This caused problems + * as documented in PR#1939. The proposed + * fix doesn't completely resolve this issue + * as buggy implementations of BIO_CTRL_PENDING + * still exist. So instead we just flush + * unconditionally. + */ + + s->internal->rwstate = SSL_WRITING; + if (BIO_flush(s->wbio) <= 0) { + ret = -1; + goto end; + } + s->internal->rwstate = SSL_NOTHING; + + s->internal->state = S3I(s)->tmp.next_state; + break; + + case SSL3_ST_SR_CERT_A: + case SSL3_ST_SR_CERT_B: + if (S3I(s)->tmp.cert_request) { + ret = ssl3_get_client_certificate(s); + if (ret <= 0) + goto end; + } + s->internal->init_num = 0; + s->internal->state = SSL3_ST_SR_KEY_EXCH_A; + break; + + case SSL3_ST_SR_KEY_EXCH_A: + case SSL3_ST_SR_KEY_EXCH_B: + ret = ssl3_get_client_key_exchange(s); + if (ret <= 0) + goto end; + alg_k = S3I(s)->tmp.new_cipher->algorithm_mkey; + if (ret == 2) { + /* + * For the ECDH ciphersuites when + * the client sends its ECDH pub key in + * a certificate, the CertificateVerify + * message is not sent. + * Also for GOST ciphersuites when + * the client uses its key from the certificate + * for key exchange. + */ + if (S3I(s)->next_proto_neg_seen) + s->internal->state = SSL3_ST_SR_NEXT_PROTO_A; + else + s->internal->state = SSL3_ST_SR_FINISHED_A; + s->internal->init_num = 0; + } else if (SSL_USE_SIGALGS(s) || (alg_k & SSL_kGOST)) { + s->internal->state = SSL3_ST_SR_CERT_VRFY_A; + s->internal->init_num = 0; + if (!s->session->peer) + break; + /* + * For sigalgs freeze the handshake buffer + * at this point and digest cached records. + */ + if (!S3I(s)->handshake_buffer) { + SSLerr(SSL_F_SSL3_ACCEPT, + ERR_R_INTERNAL_ERROR); + ret = -1; + goto end; + } + s->s3->flags |= TLS1_FLAGS_KEEP_HANDSHAKE; + if (!tls1_digest_cached_records(s)) { + ret = -1; + goto end; + } + } else { + int offset = 0; + int dgst_num; + + s->internal->state = SSL3_ST_SR_CERT_VRFY_A; + s->internal->init_num = 0; + + /* + * We need to get hashes here so if there is + * a client cert, it can be verified + * FIXME - digest processing for + * CertificateVerify should be generalized. + * But it is next step + */ + if (S3I(s)->handshake_buffer) { + if (!tls1_digest_cached_records(s)) { + ret = -1; + goto end; + } + } + for (dgst_num = 0; dgst_num < SSL_MAX_DIGEST; + dgst_num++) + if (S3I(s)->handshake_dgst[dgst_num]) { + int dgst_size; + + s->method->internal->ssl3_enc->cert_verify_mac(s, + EVP_MD_CTX_type( + S3I(s)->handshake_dgst[dgst_num]), + &(S3I(s)->tmp.cert_verify_md[offset])); + dgst_size = EVP_MD_CTX_size( + S3I(s)->handshake_dgst[dgst_num]); + if (dgst_size < 0) { + ret = -1; + goto end; + } + offset += dgst_size; + } + } + break; + + case SSL3_ST_SR_CERT_VRFY_A: + case SSL3_ST_SR_CERT_VRFY_B: + s->s3->flags |= SSL3_FLAGS_CCS_OK; + + /* we should decide if we expected this one */ + ret = ssl3_get_cert_verify(s); + if (ret <= 0) + goto end; + + if (S3I(s)->next_proto_neg_seen) + s->internal->state = SSL3_ST_SR_NEXT_PROTO_A; + else + s->internal->state = SSL3_ST_SR_FINISHED_A; + s->internal->init_num = 0; + break; + + case SSL3_ST_SR_NEXT_PROTO_A: + case SSL3_ST_SR_NEXT_PROTO_B: + ret = ssl3_get_next_proto(s); + if (ret <= 0) + goto end; + s->internal->init_num = 0; + s->internal->state = SSL3_ST_SR_FINISHED_A; + break; + + case SSL3_ST_SR_FINISHED_A: + case SSL3_ST_SR_FINISHED_B: + s->s3->flags |= SSL3_FLAGS_CCS_OK; + ret = ssl3_get_finished(s, SSL3_ST_SR_FINISHED_A, + SSL3_ST_SR_FINISHED_B); + if (ret <= 0) + goto end; + if (s->internal->hit) + s->internal->state = SSL_ST_OK; + else if (s->internal->tlsext_ticket_expected) + s->internal->state = SSL3_ST_SW_SESSION_TICKET_A; + else + s->internal->state = SSL3_ST_SW_CHANGE_A; + s->internal->init_num = 0; + break; + + case SSL3_ST_SW_SESSION_TICKET_A: + case SSL3_ST_SW_SESSION_TICKET_B: + ret = ssl3_send_newsession_ticket(s); + if (ret <= 0) + goto end; + s->internal->state = SSL3_ST_SW_CHANGE_A; + s->internal->init_num = 0; + break; + + case SSL3_ST_SW_CERT_STATUS_A: + case SSL3_ST_SW_CERT_STATUS_B: + ret = ssl3_send_cert_status(s); + if (ret <= 0) + goto end; + s->internal->state = SSL3_ST_SW_KEY_EXCH_A; + s->internal->init_num = 0; + break; + + + case SSL3_ST_SW_CHANGE_A: + case SSL3_ST_SW_CHANGE_B: + + s->session->cipher = S3I(s)->tmp.new_cipher; + if (!s->method->internal->ssl3_enc->setup_key_block(s)) { + ret = -1; + goto end; + } + + ret = ssl3_send_change_cipher_spec(s, + SSL3_ST_SW_CHANGE_A, SSL3_ST_SW_CHANGE_B); + + if (ret <= 0) + goto end; + s->internal->state = SSL3_ST_SW_FINISHED_A; + s->internal->init_num = 0; + + if (!s->method->internal->ssl3_enc->change_cipher_state( + s, SSL3_CHANGE_CIPHER_SERVER_WRITE)) { + ret = -1; + goto end; + } + + break; + + case SSL3_ST_SW_FINISHED_A: + case SSL3_ST_SW_FINISHED_B: + ret = ssl3_send_finished(s, + SSL3_ST_SW_FINISHED_A, SSL3_ST_SW_FINISHED_B, + s->method->internal->ssl3_enc->server_finished_label, + s->method->internal->ssl3_enc->server_finished_label_len); + if (ret <= 0) + goto end; + s->internal->state = SSL3_ST_SW_FLUSH; + if (s->internal->hit) { + if (S3I(s)->next_proto_neg_seen) { + s->s3->flags |= SSL3_FLAGS_CCS_OK; + S3I(s)->tmp.next_state = + SSL3_ST_SR_NEXT_PROTO_A; + } else + S3I(s)->tmp.next_state = + SSL3_ST_SR_FINISHED_A; + } else + S3I(s)->tmp.next_state = SSL_ST_OK; + s->internal->init_num = 0; + break; + + case SSL_ST_OK: + /* clean a few things up */ + tls1_cleanup_key_block(s); + + BUF_MEM_free(s->internal->init_buf); + s->internal->init_buf = NULL; + + /* remove buffering on output */ + ssl_free_wbio_buffer(s); + + s->internal->init_num = 0; + + /* skipped if we just sent a HelloRequest */ + if (s->internal->renegotiate == 2) { + s->internal->renegotiate = 0; + s->internal->new_session = 0; + + ssl_update_cache(s, SSL_SESS_CACHE_SERVER); + + s->ctx->internal->stats.sess_accept_good++; + /* s->server=1; */ + s->internal->handshake_func = ssl3_accept; + + if (cb != NULL) + cb(s, SSL_CB_HANDSHAKE_DONE, 1); + } + + ret = 1; + goto end; + /* break; */ + + default: + SSLerr(SSL_F_SSL3_ACCEPT, + SSL_R_UNKNOWN_STATE); + ret = -1; + goto end; + /* break; */ + } + + if (!S3I(s)->tmp.reuse_message && !skip) { + if (s->internal->debug) { + if ((ret = BIO_flush(s->wbio)) <= 0) + goto end; + } + + + if ((cb != NULL) && (s->internal->state != state)) { + new_state = s->internal->state; + s->internal->state = state; + cb(s, SSL_CB_ACCEPT_LOOP, 1); + s->internal->state = new_state; + } + } + skip = 0; + } +end: + /* BIO_flush(s->wbio); */ + + s->internal->in_handshake--; + if (cb != NULL) + cb(s, SSL_CB_ACCEPT_EXIT, ret); + return (ret); +} + +int +ssl3_send_hello_request(SSL *s) +{ + if (s->internal->state == SSL3_ST_SW_HELLO_REQ_A) { + ssl3_handshake_msg_start(s, SSL3_MT_HELLO_REQUEST); + ssl3_handshake_msg_finish(s, 0); + + s->internal->state = SSL3_ST_SW_HELLO_REQ_B; + } + + /* SSL3_ST_SW_HELLO_REQ_B */ + return (ssl3_handshake_write(s)); +} + +int +ssl3_get_client_hello(SSL *s) +{ + int i, j, ok, al, ret = -1; + unsigned int cookie_len; + long n; + unsigned long id; + unsigned char *p, *d; + SSL_CIPHER *c; + STACK_OF(SSL_CIPHER) *ciphers = NULL; + unsigned long alg_k; + const SSL_METHOD *method; + uint16_t shared_version; + + /* + * We do this so that we will respond with our native type. + * If we are TLSv1 and we get SSLv3, we will respond with TLSv1, + * This down switching should be handled by a different method. + * If we are SSLv3, we will respond with SSLv3, even if prompted with + * TLSv1. + */ + if (s->internal->state == SSL3_ST_SR_CLNT_HELLO_A) { + s->internal->state = SSL3_ST_SR_CLNT_HELLO_B; + } + + s->internal->first_packet = 1; + n = s->method->internal->ssl_get_message(s, SSL3_ST_SR_CLNT_HELLO_B, + SSL3_ST_SR_CLNT_HELLO_C, SSL3_MT_CLIENT_HELLO, + SSL3_RT_MAX_PLAIN_LENGTH, &ok); + + if (!ok) + return ((int)n); + s->internal->first_packet = 0; + + d = p = (unsigned char *)s->internal->init_msg; + + if (2 > n) + goto truncated; + /* + * Use version from inside client hello, not from record header. + * (may differ: see RFC 2246, Appendix E, second paragraph) + */ + s->client_version = (((int)p[0]) << 8)|(int)p[1]; + p += 2; + + if (ssl_max_shared_version(s, s->client_version, &shared_version) != 1) { + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_WRONG_VERSION_NUMBER); + if ((s->client_version >> 8) == SSL3_VERSION_MAJOR && + !s->internal->enc_write_ctx && !s->internal->write_hash) { + /* + * Similar to ssl3_get_record, send alert using remote + * version number. + */ + s->version = s->client_version; + } + al = SSL_AD_PROTOCOL_VERSION; + goto f_err; + } + s->version = shared_version; + + if ((method = tls1_get_server_method(shared_version)) == NULL) + method = dtls1_get_server_method(shared_version); + if (method == NULL) { + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); + goto err; + } + s->method = method; + + /* + * If we require cookies (DTLS) and this ClientHello doesn't + * contain one, just return since we do not want to + * allocate any memory yet. So check cookie length... + */ + if (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) { + unsigned int session_length, cookie_length; + + if (p - d + SSL3_RANDOM_SIZE + 1 >= n) + goto truncated; + session_length = *(p + SSL3_RANDOM_SIZE); + + if (p - d + SSL3_RANDOM_SIZE + session_length + 1 >= n) + goto truncated; + cookie_length = p[SSL3_RANDOM_SIZE + session_length + 1]; + + if (cookie_length == 0) + return (1); + } + + if (p - d + SSL3_RANDOM_SIZE + 1 > n) + goto truncated; + + /* load the client random */ + memcpy(s->s3->client_random, p, SSL3_RANDOM_SIZE); + p += SSL3_RANDOM_SIZE; + + /* get the session-id */ + j= *(p++); + if (p - d + j > n) + goto truncated; + + s->internal->hit = 0; + /* + * Versions before 0.9.7 always allow clients to resume sessions in + * renegotiation. 0.9.7 and later allow this by default, but optionally + * ignore resumption requests with flag + * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION (it's a new flag + * rather than a change to default behavior so that applications + * relying on this for security won't even compile against older + * library versions). + * + * 1.0.1 and later also have a function SSL_renegotiate_abbreviated() + * to request renegotiation but not a new session (s->internal->new_session + * remains unset): for servers, this essentially just means that the + * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION setting will be + * ignored. + */ + if ((s->internal->new_session && (s->internal->options & + SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION))) { + if (!ssl_get_new_session(s, 1)) + goto err; + } else { + i = ssl_get_prev_session(s, p, j, d + n); + if (i == 1) { /* previous session */ + s->internal->hit = 1; + } else if (i == -1) + goto err; + else { + /* i == 0 */ + if (!ssl_get_new_session(s, 1)) + goto err; + } + } + + p += j; + + if (SSL_IS_DTLS(s)) { + /* cookie stuff */ + if (p - d + 1 > n) + goto truncated; + cookie_len = *(p++); + + /* + * The ClientHello may contain a cookie even if the + * HelloVerify message has not been sent--make sure that it + * does not cause an overflow. + */ + if (cookie_len > sizeof(D1I(s)->rcvd_cookie)) { + /* too much data */ + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, + SSL_R_COOKIE_MISMATCH); + goto f_err; + } + + if (p - d + cookie_len > n) + goto truncated; + + /* verify the cookie if appropriate option is set. */ + if ((SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) && + cookie_len > 0) { + memcpy(D1I(s)->rcvd_cookie, p, cookie_len); + + if (s->ctx->internal->app_verify_cookie_cb != NULL) { + if (s->ctx->internal->app_verify_cookie_cb(s, + D1I(s)->rcvd_cookie, cookie_len) == 0) { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, + SSL_R_COOKIE_MISMATCH); + goto f_err; + } + /* else cookie verification succeeded */ + } else if (timingsafe_memcmp(D1I(s)->rcvd_cookie, D1I(s)->cookie, + D1I(s)->cookie_len) != 0) { + /* default verification */ + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, + SSL_R_COOKIE_MISMATCH); + goto f_err; + } + + ret = 2; + } + + p += cookie_len; + } + + if (p - d + 2 > n) + goto truncated; + n2s(p, i); + if ((i == 0) && (j != 0)) { + /* we need a cipher if we are not resuming a session */ + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, + SSL_R_NO_CIPHERS_SPECIFIED); + goto f_err; + } + if (p - d + i > n) + goto truncated; + if (i > 0) { + if ((ciphers = ssl_bytes_to_cipher_list(s, p, i)) == NULL) + goto err; + } + p += i; + + /* If it is a hit, check that the cipher is in the list */ + if ((s->internal->hit) && (i > 0)) { + j = 0; + id = s->session->cipher->id; + + for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) { + c = sk_SSL_CIPHER_value(ciphers, i); + if (c->id == id) { + j = 1; + break; + } + } + if (j == 0) { + /* + * We need to have the cipher in the cipher + * list if we are asked to reuse it + */ + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, + SSL_R_REQUIRED_CIPHER_MISSING); + goto f_err; + } + } + + /* compression */ + if (p - d + 1 > n) + goto truncated; + i= *(p++); + if (p - d + i > n) + goto truncated; + for (j = 0; j < i; j++) { + if (p[j] == 0) + break; + } + + p += i; + if (j >= i) { + /* no compress */ + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, + SSL_R_NO_COMPRESSION_SPECIFIED); + goto f_err; + } + + /* TLS extensions*/ + if (!ssl_parse_clienthello_tlsext(s, &p, d, n, &al)) { + /* 'al' set by ssl_parse_clienthello_tlsext */ + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_PARSE_TLSEXT); + goto f_err; + } + if (ssl_check_clienthello_tlsext_early(s) <= 0) { + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, + SSL_R_CLIENTHELLO_TLSEXT); + goto err; + } + + /* + * Check if we want to use external pre-shared secret for this + * handshake for not reused session only. We need to generate + * server_random before calling tls_session_secret_cb in order to allow + * SessionTicket processing to use it in key derivation. + */ + arc4random_buf(s->s3->server_random, SSL3_RANDOM_SIZE); + + if (!s->internal->hit && s->internal->tls_session_secret_cb) { + SSL_CIPHER *pref_cipher = NULL; + + s->session->master_key_length = sizeof(s->session->master_key); + if (s->internal->tls_session_secret_cb(s, s->session->master_key, + &s->session->master_key_length, ciphers, &pref_cipher, + s->internal->tls_session_secret_cb_arg)) { + s->internal->hit = 1; + s->session->ciphers = ciphers; + s->session->verify_result = X509_V_OK; + + ciphers = NULL; + + /* check if some cipher was preferred by call back */ + pref_cipher = pref_cipher ? pref_cipher : + ssl3_choose_cipher(s, s->session->ciphers, + SSL_get_ciphers(s)); + if (pref_cipher == NULL) { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, + SSL_R_NO_SHARED_CIPHER); + goto f_err; + } + + s->session->cipher = pref_cipher; + + sk_SSL_CIPHER_free(s->cipher_list); + sk_SSL_CIPHER_free(s->internal->cipher_list_by_id); + + s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers); + s->internal->cipher_list_by_id = + sk_SSL_CIPHER_dup(s->session->ciphers); + } + } + + /* + * Given s->session->ciphers and SSL_get_ciphers, we must + * pick a cipher + */ + + if (!s->internal->hit) { + sk_SSL_CIPHER_free(s->session->ciphers); + s->session->ciphers = ciphers; + if (ciphers == NULL) { + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, + SSL_R_NO_CIPHERS_PASSED); + goto f_err; + } + ciphers = NULL; + c = ssl3_choose_cipher(s, s->session->ciphers, + SSL_get_ciphers(s)); + + if (c == NULL) { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, + SSL_R_NO_SHARED_CIPHER); + goto f_err; + } + S3I(s)->tmp.new_cipher = c; + } else { + S3I(s)->tmp.new_cipher = s->session->cipher; + } + + alg_k = S3I(s)->tmp.new_cipher->algorithm_mkey; + if (!(SSL_USE_SIGALGS(s) || (alg_k & SSL_kGOST)) || + !(s->verify_mode & SSL_VERIFY_PEER)) { + if (!tls1_digest_cached_records(s)) { + al = SSL_AD_INTERNAL_ERROR; + goto f_err; + } + } + + /* + * We now have the following setup. + * client_random + * cipher_list - our prefered list of ciphers + * ciphers - the clients prefered list of ciphers + * compression - basically ignored right now + * ssl version is set - sslv3 + * s->session - The ssl session has been setup. + * s->internal->hit - session reuse flag + * s->tmp.new_cipher - the new cipher to use. + */ + + /* Handles TLS extensions that we couldn't check earlier */ + if (ssl_check_clienthello_tlsext_late(s) <= 0) { + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT); + goto err; + } + + if (ret < 0) + ret = 1; + if (0) { +truncated: + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_BAD_PACKET_LENGTH); +f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + } +err: + sk_SSL_CIPHER_free(ciphers); + + return (ret); +} + +int +ssl3_send_server_hello(SSL *s) +{ + unsigned char *bufend; + unsigned char *p, *d; + CBB cbb, session_id; + size_t outlen; + int sl; + + memset(&cbb, 0, sizeof(cbb)); + + bufend = (unsigned char *)s->internal->init_buf->data + SSL3_RT_MAX_PLAIN_LENGTH; + + if (s->internal->state == SSL3_ST_SW_SRVR_HELLO_A) { + d = p = ssl3_handshake_msg_start(s, SSL3_MT_SERVER_HELLO); + + if (!CBB_init_fixed(&cbb, p, bufend - p)) + goto err; + + if (!CBB_add_u16(&cbb, s->version)) + goto err; + if (!CBB_add_bytes(&cbb, s->s3->server_random, + sizeof(s->s3->server_random))) + goto err; + + /* + * There are several cases for the session ID to send + * back in the server hello: + * + * - For session reuse from the session cache, + * we send back the old session ID. + * - If stateless session reuse (using a session ticket) + * is successful, we send back the client's "session ID" + * (which doesn't actually identify the session). + * - If it is a new session, we send back the new + * session ID. + * - However, if we want the new session to be single-use, + * we send back a 0-length session ID. + * + * s->internal->hit is non-zero in either case of session reuse, + * so the following won't overwrite an ID that we're supposed + * to send back. + */ + if (!(s->ctx->internal->session_cache_mode & SSL_SESS_CACHE_SERVER) + && !s->internal->hit) + s->session->session_id_length = 0; + + sl = s->session->session_id_length; + if (sl > (int)sizeof(s->session->session_id)) { + SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO, + ERR_R_INTERNAL_ERROR); + goto err; + } + + if (!CBB_add_u8_length_prefixed(&cbb, &session_id)) + goto err; + if (!CBB_add_bytes(&session_id, s->session->session_id, sl)) + goto err; + + /* Cipher suite. */ + if (!CBB_add_u16(&cbb, + ssl3_cipher_get_value(S3I(s)->tmp.new_cipher))) + goto err; + + /* Compression method. */ + if (!CBB_add_u8(&cbb, 0)) + goto err; + + if (!CBB_finish(&cbb, NULL, &outlen)) + goto err; + + if ((p = ssl_add_serverhello_tlsext(s, p + outlen, + bufend)) == NULL) { + SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO, + ERR_R_INTERNAL_ERROR); + goto err; + } + + ssl3_handshake_msg_finish(s, p - d); + } + + /* SSL3_ST_SW_SRVR_HELLO_B */ + return (ssl3_handshake_write(s)); + + err: + CBB_cleanup(&cbb); + + return (-1); +} + +int +ssl3_send_server_done(SSL *s) +{ + if (s->internal->state == SSL3_ST_SW_SRVR_DONE_A) { + ssl3_handshake_msg_start(s, SSL3_MT_SERVER_DONE); + ssl3_handshake_msg_finish(s, 0); + + s->internal->state = SSL3_ST_SW_SRVR_DONE_B; + } + + /* SSL3_ST_SW_SRVR_DONE_B */ + return (ssl3_handshake_write(s)); +} + +int +ssl3_send_server_kex_dhe(SSL *s, CBB *cbb) +{ + CBB dh_p, dh_g, dh_Ys; + DH *dh = NULL, *dhp; + unsigned char *data; + int al; + + if (s->cert->dh_tmp_auto != 0) { + if ((dhp = ssl_get_auto_dh(s)) == NULL) { + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto f_err; + } + } else + dhp = s->cert->dh_tmp; + + if (dhp == NULL && s->cert->dh_tmp_cb != NULL) + dhp = s->cert->dh_tmp_cb(s, 0, + SSL_C_PKEYLENGTH(S3I(s)->tmp.new_cipher)); + + if (dhp == NULL) { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, + SSL_R_MISSING_TMP_DH_KEY); + goto f_err; + } + + if (S3I(s)->tmp.dh != NULL) { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + if (s->cert->dh_tmp_auto != 0) { + dh = dhp; + } else if ((dh = DHparams_dup(dhp)) == NULL) { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_DH_LIB); + goto err; + } + S3I(s)->tmp.dh = dh; + if (!DH_generate_key(dh)) { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_DH_LIB); + goto err; + } + + /* + * Serialize the DH parameters and public key. + */ + if (!CBB_add_u16_length_prefixed(cbb, &dh_p)) + goto err; + if (!CBB_add_space(&dh_p, &data, BN_num_bytes(dh->p))) + goto err; + BN_bn2bin(dh->p, data); + + if (!CBB_add_u16_length_prefixed(cbb, &dh_g)) + goto err; + if (!CBB_add_space(&dh_g, &data, BN_num_bytes(dh->g))) + goto err; + BN_bn2bin(dh->g, data); + + if (!CBB_add_u16_length_prefixed(cbb, &dh_Ys)) + goto err; + if (!CBB_add_space(&dh_Ys, &data, BN_num_bytes(dh->pub_key))) + goto err; + BN_bn2bin(dh->pub_key, data); + + if (!CBB_flush(cbb)) + goto err; + + return (1); + + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + err: + return (-1); +} + +static int +ssl3_send_server_kex_ecdhe_ecp(SSL *s, int nid, CBB *cbb) +{ + CBB ecpoint; + unsigned char *data; + EC_KEY *ecdh = NULL, *ecdhp; + const EC_GROUP *group; + unsigned char *encodedPoint = NULL; + int encodedlen = 0; + int curve_id = 0; + BN_CTX *bn_ctx = NULL; + int al; + + ecdhp = s->cert->ecdh_tmp; + if (s->cert->ecdh_tmp_auto != 0) { + if (nid != NID_undef) + ecdhp = EC_KEY_new_by_curve_name(nid); + } else if (ecdhp == NULL && s->cert->ecdh_tmp_cb != NULL) { + ecdhp = s->cert->ecdh_tmp_cb(s, 0, + SSL_C_PKEYLENGTH(S3I(s)->tmp.new_cipher)); + } + if (ecdhp == NULL) { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, + SSL_R_MISSING_TMP_ECDH_KEY); + goto f_err; + } + + if (S3I(s)->tmp.ecdh != NULL) { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + /* Duplicate the ECDH structure. */ + if (s->cert->ecdh_tmp_auto != 0) { + ecdh = ecdhp; + } else if ((ecdh = EC_KEY_dup(ecdhp)) == NULL) { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, + ERR_R_ECDH_LIB); + goto err; + } + S3I(s)->tmp.ecdh = ecdh; + + if ((EC_KEY_get0_public_key(ecdh) == NULL) || + (EC_KEY_get0_private_key(ecdh) == NULL) || + (s->internal->options & SSL_OP_SINGLE_ECDH_USE)) { + if (!EC_KEY_generate_key(ecdh)) { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, + ERR_R_ECDH_LIB); + goto err; + } + } + + if (((group = EC_KEY_get0_group(ecdh)) == NULL) || + (EC_KEY_get0_public_key(ecdh) == NULL) || + (EC_KEY_get0_private_key(ecdh) == NULL)) { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, + ERR_R_ECDH_LIB); + goto err; + } + + /* + * Only named curves are supported in ECDH ephemeral key exchanges. + * For supported named curves, curve_id is non-zero. + */ + if ((curve_id = tls1_ec_nid2curve_id( + EC_GROUP_get_curve_name(group))) == 0) { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, + SSL_R_UNSUPPORTED_ELLIPTIC_CURVE); + goto err; + } + + /* + * Encode the public key. First check the size of encoding and + * allocate memory accordingly. + */ + encodedlen = EC_POINT_point2oct(group, EC_KEY_get0_public_key(ecdh), + POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL); + + encodedPoint = malloc(encodedlen); + + bn_ctx = BN_CTX_new(); + if ((encodedPoint == NULL) || (bn_ctx == NULL)) { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, + ERR_R_MALLOC_FAILURE); + goto err; + } + + encodedlen = EC_POINT_point2oct(group, EC_KEY_get0_public_key(ecdh), + POINT_CONVERSION_UNCOMPRESSED, encodedPoint, encodedlen, bn_ctx); + + if (encodedlen == 0) { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_ECDH_LIB); + goto err; + } + + BN_CTX_free(bn_ctx); + bn_ctx = NULL; + + /* + * Only named curves are supported in ECDH ephemeral key exchanges. + * In this case the ServerKeyExchange message has: + * [1 byte CurveType], [2 byte CurveName] + * [1 byte length of encoded point], followed by + * the actual encoded point itself. + */ + if (!CBB_add_u8(cbb, NAMED_CURVE_TYPE)) + goto err; + if (!CBB_add_u16(cbb, curve_id)) + goto err; + if (!CBB_add_u8_length_prefixed(cbb, &ecpoint)) + goto err; + if (!CBB_add_space(&ecpoint, &data, encodedlen)) + goto err; + + memcpy(data, encodedPoint, encodedlen); + + free(encodedPoint); + encodedPoint = NULL; + + if (!CBB_flush(cbb)) + goto err; + + return (1); + + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + err: + free(encodedPoint); + BN_CTX_free(bn_ctx); + + return (-1); +} + +static int +ssl3_send_server_kex_ecdhe_ecx(SSL *s, int nid, CBB *cbb) +{ + uint8_t *public_key = NULL; + int curve_id; + CBB ecpoint; + int ret = -1; + + /* Generate an X25519 key pair. */ + if (S3I(s)->tmp.x25519 != NULL) { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } + if ((S3I(s)->tmp.x25519 = malloc(X25519_KEY_LENGTH)) == NULL) + goto err; + if ((public_key = malloc(X25519_KEY_LENGTH)) == NULL) + goto err; + X25519_keypair(public_key, S3I(s)->tmp.x25519); + + /* Serialize public key. */ + if ((curve_id = tls1_ec_nid2curve_id(nid)) == 0) { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, + SSL_R_UNSUPPORTED_ELLIPTIC_CURVE); + goto err; + } + + if (!CBB_add_u8(cbb, NAMED_CURVE_TYPE)) + goto err; + if (!CBB_add_u16(cbb, curve_id)) + goto err; + if (!CBB_add_u8_length_prefixed(cbb, &ecpoint)) + goto err; + if (!CBB_add_bytes(&ecpoint, public_key, X25519_KEY_LENGTH)) + goto err; + if (!CBB_flush(cbb)) + goto err; + + ret = 1; + + err: + free(public_key); + + return (ret); +} + +static int +ssl3_send_server_kex_ecdhe(SSL *s, CBB *cbb) +{ + int nid; + + nid = tls1_get_shared_curve(s); + + if (s->cert->ecdh_tmp_auto != 0 && nid == NID_X25519) + return ssl3_send_server_kex_ecdhe_ecx(s, nid, cbb); + + return ssl3_send_server_kex_ecdhe_ecp(s, nid, cbb); +} + +int +ssl3_send_server_key_exchange(SSL *s) +{ + CBB cbb; + unsigned char *params = NULL; + size_t params_len; + unsigned char *q; + int j, num; + unsigned char md_buf[MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH]; + unsigned int u; + EVP_PKEY *pkey; + const EVP_MD *md = NULL; + unsigned char *p, *d; + int al, i; + unsigned long type; + int n; + int kn; + BUF_MEM *buf; + EVP_MD_CTX md_ctx; + + memset(&cbb, 0, sizeof(cbb)); + + EVP_MD_CTX_init(&md_ctx); + if (s->internal->state == SSL3_ST_SW_KEY_EXCH_A) { + type = S3I(s)->tmp.new_cipher->algorithm_mkey; + + buf = s->internal->init_buf; + + if (!CBB_init(&cbb, 0)) + goto err; + + if (type & SSL_kDHE) { + if (ssl3_send_server_kex_dhe(s, &cbb) != 1) + goto err; + } else if (type & SSL_kECDHE) { + if (ssl3_send_server_kex_ecdhe(s, &cbb) != 1) + goto err; + } else { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, + SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE); + goto f_err; + } + + if (!CBB_finish(&cbb, ¶ms, ¶ms_len)) + goto err; + + if (!(S3I(s)->tmp.new_cipher->algorithm_auth & SSL_aNULL)) { + if ((pkey = ssl_get_sign_pkey( + s, S3I(s)->tmp.new_cipher, &md)) == NULL) { + al = SSL_AD_DECODE_ERROR; + goto f_err; + } + kn = EVP_PKEY_size(pkey); + } else { + pkey = NULL; + kn = 0; + } + + if (!BUF_MEM_grow_clean(buf, ssl3_handshake_msg_hdr_len(s) + + params_len + kn)) { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, + ERR_LIB_BUF); + goto err; + } + + d = p = ssl3_handshake_msg_start(s, + SSL3_MT_SERVER_KEY_EXCHANGE); + + memcpy(p, params, params_len); + + free(params); + params = NULL; + + n = params_len; + p += params_len; + + /* not anonymous */ + if (pkey != NULL) { + /* + * n is the length of the params, they start at &(d[4]) + * and p points to the space at the end. + */ + if (pkey->type == EVP_PKEY_RSA && !SSL_USE_SIGALGS(s)) { + q = md_buf; + j = 0; + for (num = 2; num > 0; num--) { + if (!EVP_DigestInit_ex(&md_ctx, + (num == 2) ? s->ctx->internal->md5 : + s->ctx->internal->sha1, NULL)) + goto err; + EVP_DigestUpdate(&md_ctx, + s->s3->client_random, + SSL3_RANDOM_SIZE); + EVP_DigestUpdate(&md_ctx, + s->s3->server_random, + SSL3_RANDOM_SIZE); + EVP_DigestUpdate(&md_ctx, d, n); + EVP_DigestFinal_ex(&md_ctx, q, + (unsigned int *)&i); + q += i; + j += i; + } + if (RSA_sign(NID_md5_sha1, md_buf, j, + &(p[2]), &u, pkey->pkey.rsa) <= 0) { + SSLerr( + SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, + ERR_LIB_RSA); + goto err; + } + s2n(u, p); + n += u + 2; + } else if (md) { + /* Send signature algorithm. */ + if (SSL_USE_SIGALGS(s)) { + if (!tls12_get_sigandhash(p, pkey, md)) { + /* Should never happen */ + al = SSL_AD_INTERNAL_ERROR; + SSLerr( + SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto f_err; + } + p += 2; + } + EVP_SignInit_ex(&md_ctx, md, NULL); + EVP_SignUpdate(&md_ctx, + s->s3->client_random, + SSL3_RANDOM_SIZE); + EVP_SignUpdate(&md_ctx, + s->s3->server_random, + SSL3_RANDOM_SIZE); + EVP_SignUpdate(&md_ctx, d, n); + if (!EVP_SignFinal(&md_ctx, &p[2], + (unsigned int *)&i, pkey)) { + SSLerr( + SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, + ERR_LIB_EVP); + goto err; + } + s2n(i, p); + n += i + 2; + if (SSL_USE_SIGALGS(s)) + n += 2; + } else { + /* Is this error check actually needed? */ + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, + SSL_R_UNKNOWN_PKEY_TYPE); + goto f_err; + } + } + + ssl3_handshake_msg_finish(s, n); + } + + s->internal->state = SSL3_ST_SW_KEY_EXCH_B; + + EVP_MD_CTX_cleanup(&md_ctx); + + return (ssl3_handshake_write(s)); + + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + err: + free(params); + EVP_MD_CTX_cleanup(&md_ctx); + CBB_cleanup(&cbb); + + return (-1); +} + +int +ssl3_send_certificate_request(SSL *s) +{ + unsigned char *p, *d; + int i, j, nl, off, n; + STACK_OF(X509_NAME) *sk = NULL; + X509_NAME *name; + BUF_MEM *buf; + + if (s->internal->state == SSL3_ST_SW_CERT_REQ_A) { + buf = s->internal->init_buf; + + d = p = ssl3_handshake_msg_start(s, + SSL3_MT_CERTIFICATE_REQUEST); + + /* get the list of acceptable cert types */ + p++; + n = ssl3_get_req_cert_type(s, p); + d[0] = n; + p += n; + n++; + + if (SSL_USE_SIGALGS(s)) { + nl = tls12_get_req_sig_algs(s, p + 2); + s2n(nl, p); + p += nl + 2; + n += nl + 2; + } + + off = n; + p += 2; + n += 2; + + sk = SSL_get_client_CA_list(s); + nl = 0; + if (sk != NULL) { + for (i = 0; i < sk_X509_NAME_num(sk); i++) { + name = sk_X509_NAME_value(sk, i); + j = i2d_X509_NAME(name, NULL); + if (!BUF_MEM_grow_clean(buf, + ssl3_handshake_msg_hdr_len(s) + n + j + + 2)) { + SSLerr( + SSL_F_SSL3_SEND_CERTIFICATE_REQUEST, + ERR_R_BUF_LIB); + goto err; + } + p = ssl3_handshake_msg_start(s, + SSL3_MT_CERTIFICATE_REQUEST) + n; + s2n(j, p); + i2d_X509_NAME(name, &p); + n += 2 + j; + nl += 2 + j; + } + } + /* else no CA names */ + p = ssl3_handshake_msg_start(s, + SSL3_MT_CERTIFICATE_REQUEST) + off; + s2n(nl, p); + + ssl3_handshake_msg_finish(s, n); + + s->internal->state = SSL3_ST_SW_CERT_REQ_B; + } + + /* SSL3_ST_SW_CERT_REQ_B */ + return (ssl3_handshake_write(s)); +err: + return (-1); +} + +static int +ssl3_get_client_kex_rsa(SSL *s, unsigned char *p, long n) +{ + unsigned char fakekey[SSL_MAX_MASTER_KEY_LENGTH]; + unsigned char *d; + RSA *rsa = NULL; + EVP_PKEY *pkey = NULL; + int i, al; + + d = p; + + arc4random_buf(fakekey, sizeof(fakekey)); + fakekey[0] = s->client_version >> 8; + fakekey[1] = s->client_version & 0xff; + + pkey = s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey; + if ((pkey == NULL) || (pkey->type != EVP_PKEY_RSA) || + (pkey->pkey.rsa == NULL)) { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_MISSING_RSA_CERTIFICATE); + goto f_err; + } + rsa = pkey->pkey.rsa; + + if (2 > n) + goto truncated; + n2s(p, i); + if (n != i + 2) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG); + goto err; + } else + n = i; + + i = RSA_private_decrypt((int)n, p, p, rsa, RSA_PKCS1_PADDING); + + ERR_clear_error(); + + al = -1; + + if (i != SSL_MAX_MASTER_KEY_LENGTH) { + al = SSL_AD_DECODE_ERROR; + /* SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_RSA_DECRYPT); */ + } + + if (p - d + 2 > n) /* needed in the SSL3 case */ + goto truncated; + if ((al == -1) && !((p[0] == (s->client_version >> 8)) && + (p[1] == (s->client_version & 0xff)))) { + /* + * The premaster secret must contain the same version + * number as the ClientHello to detect version rollback + * attacks (strangely, the protocol does not offer such + * protection for DH ciphersuites). + * However, buggy clients exist that send the negotiated + * protocol version instead if the server does not + * support the requested protocol version. + * If SSL_OP_TLS_ROLLBACK_BUG is set, tolerate such + * clients. + */ + if (!((s->internal->options & SSL_OP_TLS_ROLLBACK_BUG) && + (p[0] == (s->version >> 8)) && + (p[1] == (s->version & 0xff)))) { + al = SSL_AD_DECODE_ERROR; + /* SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_PROTOCOL_VERSION_NUMBER); */ + + /* + * The Klima-Pokorny-Rosa extension of + * Bleichenbacher's attack + * (http://eprint.iacr.org/2003/052/) exploits + * the version number check as a "bad version + * oracle" -- an alert would reveal that the + * plaintext corresponding to some ciphertext + * made up by the adversary is properly + * formatted except that the version number is + * wrong. + * To avoid such attacks, we should treat this + * just like any other decryption error. + */ + } + } + + if (al != -1) { + /* + * Some decryption failure -- use random value instead + * as countermeasure against Bleichenbacher's attack + * on PKCS #1 v1.5 RSA padding (see RFC 2246, + * section 7.4.7.1). + */ + i = SSL_MAX_MASTER_KEY_LENGTH; + p = fakekey; + } + + s->session->master_key_length = + s->method->internal->ssl3_enc->generate_master_secret(s, + s->session->master_key, p, i); + + explicit_bzero(p, i); + + return (1); +truncated: + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_BAD_PACKET_LENGTH); +f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); +err: + return (-1); +} + +static int +ssl3_get_client_kex_dhe(SSL *s, unsigned char *p, long n) +{ + BIGNUM *bn = NULL; + int key_size, al; + CBS cbs, dh_Yc; + DH *dh; + + if (n < 0) + goto err; + + CBS_init(&cbs, p, n); + + if (!CBS_get_u16_length_prefixed(&cbs, &dh_Yc)) + goto truncated; + + if (CBS_len(&cbs) != 0) + goto truncated; + + if (S3I(s)->tmp.dh == NULL) { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_MISSING_TMP_DH_KEY); + goto f_err; + } + dh = S3I(s)->tmp.dh; + + if ((bn = BN_bin2bn(CBS_data(&dh_Yc), CBS_len(&dh_Yc), NULL)) == NULL) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_BN_LIB); + goto err; + } + + key_size = DH_compute_key(p, bn, dh); + if (key_size <= 0) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB); + BN_clear_free(bn); + goto err; + } + + s->session->master_key_length = + s->method->internal->ssl3_enc->generate_master_secret( + s, s->session->master_key, p, key_size); + + explicit_bzero(p, key_size); + + DH_free(S3I(s)->tmp.dh); + S3I(s)->tmp.dh = NULL; + + BN_clear_free(bn); + + return (1); + + truncated: + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_BAD_PACKET_LENGTH); + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + err: + return (-1); +} + +static int +ssl3_get_client_kex_ecdhe_ecp(SSL *s, unsigned char *p, long n) +{ + EC_KEY *srvr_ecdh = NULL; + EVP_PKEY *clnt_pub_pkey = NULL; + EC_POINT *clnt_ecpoint = NULL; + BN_CTX *bn_ctx = NULL; + int i, al; + + int ret = 1; + int key_size; + const EC_KEY *tkey; + const EC_GROUP *group; + const BIGNUM *priv_key; + + /* Initialize structures for server's ECDH key pair. */ + if ((srvr_ecdh = EC_KEY_new()) == NULL) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + ERR_R_MALLOC_FAILURE); + goto err; + } + + /* + * Use the ephemeral values we saved when + * generating the ServerKeyExchange message. + */ + tkey = S3I(s)->tmp.ecdh; + + group = EC_KEY_get0_group(tkey); + priv_key = EC_KEY_get0_private_key(tkey); + + if (!EC_KEY_set_group(srvr_ecdh, group) || + !EC_KEY_set_private_key(srvr_ecdh, priv_key)) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + ERR_R_EC_LIB); + goto err; + } + + /* Let's get client's public key */ + if ((clnt_ecpoint = EC_POINT_new(group)) == NULL) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + ERR_R_MALLOC_FAILURE); + goto err; + } + + if (n == 0L) { + /* Client Publickey was in Client Certificate */ + if (((clnt_pub_pkey = X509_get_pubkey( + s->session->peer)) == NULL) || + (clnt_pub_pkey->type != EVP_PKEY_EC)) { + /* + * XXX: For now, we do not support client + * authentication using ECDH certificates + * so this branch (n == 0L) of the code is + * never executed. When that support is + * added, we ought to ensure the key + * received in the certificate is + * authorized for key agreement. + * ECDH_compute_key implicitly checks that + * the two ECDH shares are for the same + * group. + */ + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_UNABLE_TO_DECODE_ECDH_CERTS); + goto f_err; + } + + if (EC_POINT_copy(clnt_ecpoint, + EC_KEY_get0_public_key(clnt_pub_pkey->pkey.ec)) + == 0) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + ERR_R_EC_LIB); + goto err; + } + ret = 2; /* Skip certificate verify processing */ + } else { + /* + * Get client's public key from encoded point + * in the ClientKeyExchange message. + */ + if ((bn_ctx = BN_CTX_new()) == NULL) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + ERR_R_MALLOC_FAILURE); + goto err; + } + + /* Get encoded point length */ + i = *p; + + p += 1; + if (n != 1 + i) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + ERR_R_EC_LIB); + goto err; + } + if (EC_POINT_oct2point(group, + clnt_ecpoint, p, i, bn_ctx) == 0) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + ERR_R_EC_LIB); + goto err; + } + /* + * p is pointing to somewhere in the buffer + * currently, so set it to the start. + */ + p = (unsigned char *)s->internal->init_buf->data; + } + + /* Compute the shared pre-master secret */ + key_size = ECDH_size(srvr_ecdh); + if (key_size <= 0) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + ERR_R_ECDH_LIB); + goto err; + } + i = ECDH_compute_key(p, key_size, clnt_ecpoint, srvr_ecdh, + NULL); + if (i <= 0) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + ERR_R_ECDH_LIB); + goto err; + } + + EVP_PKEY_free(clnt_pub_pkey); + EC_POINT_free(clnt_ecpoint); + EC_KEY_free(srvr_ecdh); + BN_CTX_free(bn_ctx); + EC_KEY_free(S3I(s)->tmp.ecdh); + S3I(s)->tmp.ecdh = NULL; + + /* Compute the master secret */ + s->session->master_key_length = + s->method->internal->ssl3_enc->generate_master_secret( + s, s->session->master_key, p, i); + + explicit_bzero(p, i); + return (ret); + + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + err: + EVP_PKEY_free(clnt_pub_pkey); + EC_POINT_free(clnt_ecpoint); + EC_KEY_free(srvr_ecdh); + BN_CTX_free(bn_ctx); + return (-1); +} + +static int +ssl3_get_client_kex_ecdhe_ecx(SSL *s, unsigned char *p, long n) +{ + uint8_t *shared_key = NULL; + CBS cbs, ecpoint; + int ret = -1; + + if (n < 0) + goto err; + + CBS_init(&cbs, p, n); + if (!CBS_get_u8_length_prefixed(&cbs, &ecpoint)) + goto err; + if (CBS_len(&ecpoint) != X25519_KEY_LENGTH) + goto err; + + if ((shared_key = malloc(X25519_KEY_LENGTH)) == NULL) + goto err; + if (!X25519(shared_key, S3I(s)->tmp.x25519, CBS_data(&ecpoint))) + goto err; + + explicit_bzero(S3I(s)->tmp.x25519, X25519_KEY_LENGTH); + free(S3I(s)->tmp.x25519); + S3I(s)->tmp.x25519 = NULL; + + s->session->master_key_length = + s->method->internal->ssl3_enc->generate_master_secret( + s, s->session->master_key, shared_key, X25519_KEY_LENGTH); + + ret = 1; + + err: + if (shared_key != NULL) + explicit_bzero(shared_key, X25519_KEY_LENGTH); + free(shared_key); + + return (ret); +} + +static int +ssl3_get_client_kex_ecdhe(SSL *s, unsigned char *p, long n) +{ + if (S3I(s)->tmp.x25519 != NULL) + return ssl3_get_client_kex_ecdhe_ecx(s, p, n); + + return ssl3_get_client_kex_ecdhe_ecp(s, p, n); +} + +static int +ssl3_get_client_kex_gost(SSL *s, unsigned char *p, long n) +{ + + EVP_PKEY_CTX *pkey_ctx; + EVP_PKEY *client_pub_pkey = NULL, *pk = NULL; + unsigned char premaster_secret[32], *start; + size_t outlen = 32, inlen; + unsigned long alg_a; + int Ttag, Tclass; + long Tlen; + int al; + int ret = 0; + + /* Get our certificate private key*/ + alg_a = S3I(s)->tmp.new_cipher->algorithm_auth; + if (alg_a & SSL_aGOST01) + pk = s->cert->pkeys[SSL_PKEY_GOST01].privatekey; + + pkey_ctx = EVP_PKEY_CTX_new(pk, NULL); + EVP_PKEY_decrypt_init(pkey_ctx); + /* + * If client certificate is present and is of the same type, + * maybe use it for key exchange. + * Don't mind errors from EVP_PKEY_derive_set_peer, because + * it is completely valid to use a client certificate for + * authorization only. + */ + client_pub_pkey = X509_get_pubkey(s->session->peer); + if (client_pub_pkey) { + if (EVP_PKEY_derive_set_peer(pkey_ctx, + client_pub_pkey) <= 0) + ERR_clear_error(); + } + if (2 > n) + goto truncated; + /* Decrypt session key */ + if (ASN1_get_object((const unsigned char **)&p, &Tlen, &Ttag, + &Tclass, n) != V_ASN1_CONSTRUCTED || + Ttag != V_ASN1_SEQUENCE || Tclass != V_ASN1_UNIVERSAL) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_DECRYPTION_FAILED); + goto gerr; + } + start = p; + inlen = Tlen; + if (EVP_PKEY_decrypt(pkey_ctx, premaster_secret, &outlen, + start, inlen) <=0) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_DECRYPTION_FAILED); + goto gerr; + } + /* Generate master secret */ + s->session->master_key_length = + s->method->internal->ssl3_enc->generate_master_secret( + s, s->session->master_key, premaster_secret, 32); + /* Check if pubkey from client certificate was used */ + if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, -1, + EVP_PKEY_CTRL_PEER_KEY, 2, NULL) > 0) + ret = 2; + else + ret = 1; + gerr: + EVP_PKEY_free(client_pub_pkey); + EVP_PKEY_CTX_free(pkey_ctx); + if (ret) + return (ret); + else + goto err; + + truncated: + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_BAD_PACKET_LENGTH); + ssl3_send_alert(s, SSL3_AL_FATAL, al); + err: + return (-1); +} + +int +ssl3_get_client_key_exchange(SSL *s) +{ + unsigned long alg_k; + unsigned char *p; + int al, ok; + long n; + + /* 2048 maxlen is a guess. How long a key does that permit? */ + n = s->method->internal->ssl_get_message(s, SSL3_ST_SR_KEY_EXCH_A, + SSL3_ST_SR_KEY_EXCH_B, SSL3_MT_CLIENT_KEY_EXCHANGE, 2048, &ok); + if (!ok) + return ((int)n); + + p = (unsigned char *)s->internal->init_msg; + + alg_k = S3I(s)->tmp.new_cipher->algorithm_mkey; + + if (alg_k & SSL_kRSA) { + if (ssl3_get_client_kex_rsa(s, p, n) != 1) + goto err; + } else if (alg_k & SSL_kDHE) { + if (ssl3_get_client_kex_dhe(s, p, n) != 1) + goto err; + } else if (alg_k & SSL_kECDHE) { + if (ssl3_get_client_kex_ecdhe(s, p, n) != 1) + goto err; + } else if (alg_k & SSL_kGOST) { + if (ssl3_get_client_kex_gost(s, p, n) != 1) + goto err; + } else { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_UNKNOWN_CIPHER_TYPE); + goto f_err; + } + + return (1); + + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + err: + return (-1); +} + +int +ssl3_get_cert_verify(SSL *s) +{ + EVP_PKEY *pkey = NULL; + unsigned char *p; + int al, ok, ret = 0; + long n; + int type = 0, i, j; + X509 *peer; + const EVP_MD *md = NULL; + EVP_MD_CTX mctx; + EVP_MD_CTX_init(&mctx); + + n = s->method->internal->ssl_get_message(s, SSL3_ST_SR_CERT_VRFY_A, + SSL3_ST_SR_CERT_VRFY_B, -1, SSL3_RT_MAX_PLAIN_LENGTH, &ok); + if (!ok) + return ((int)n); + + if (s->session->peer != NULL) { + peer = s->session->peer; + pkey = X509_get_pubkey(peer); + type = X509_certificate_type(peer, pkey); + } else { + peer = NULL; + pkey = NULL; + } + + if (S3I(s)->tmp.message_type != SSL3_MT_CERTIFICATE_VERIFY) { + S3I(s)->tmp.reuse_message = 1; + if (peer != NULL) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, + SSL_R_MISSING_VERIFY_MESSAGE); + goto f_err; + } + ret = 1; + goto end; + } + + if (peer == NULL) { + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, + SSL_R_NO_CLIENT_CERT_RECEIVED); + al = SSL_AD_UNEXPECTED_MESSAGE; + goto f_err; + } + + if (!(type & EVP_PKT_SIGN)) { + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, + SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE); + al = SSL_AD_ILLEGAL_PARAMETER; + goto f_err; + } + + if (S3I(s)->change_cipher_spec) { + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, + SSL_R_CCS_RECEIVED_EARLY); + al = SSL_AD_UNEXPECTED_MESSAGE; + goto f_err; + } + + /* we now have a signature that we need to verify */ + p = (unsigned char *)s->internal->init_msg; + /* + * Check for broken implementations of GOST ciphersuites. + * + * If key is GOST and n is exactly 64, it is a bare + * signature without length field. + */ + if (n == 64 && (pkey->type == NID_id_GostR3410_94 || + pkey->type == NID_id_GostR3410_2001) ) { + i = 64; + } else { + if (SSL_USE_SIGALGS(s)) { + int sigalg = tls12_get_sigid(pkey); + /* Should never happen */ + if (sigalg == -1) { + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, + ERR_R_INTERNAL_ERROR); + al = SSL_AD_INTERNAL_ERROR; + goto f_err; + } + if (2 > n) + goto truncated; + /* Check key type is consistent with signature */ + if (sigalg != (int)p[1]) { + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, + SSL_R_WRONG_SIGNATURE_TYPE); + al = SSL_AD_DECODE_ERROR; + goto f_err; + } + md = tls12_get_hash(p[0]); + if (md == NULL) { + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, + SSL_R_UNKNOWN_DIGEST); + al = SSL_AD_DECODE_ERROR; + goto f_err; + } + p += 2; + n -= 2; + } + if (2 > n) + goto truncated; + n2s(p, i); + n -= 2; + if (i > n) + goto truncated; + } + j = EVP_PKEY_size(pkey); + if ((i > j) || (n > j) || (n <= 0)) { + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, + SSL_R_WRONG_SIGNATURE_SIZE); + al = SSL_AD_DECODE_ERROR; + goto f_err; + } + + if (SSL_USE_SIGALGS(s)) { + long hdatalen = 0; + void *hdata; + hdatalen = BIO_get_mem_data(S3I(s)->handshake_buffer, &hdata); + if (hdatalen <= 0) { + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, + ERR_R_INTERNAL_ERROR); + al = SSL_AD_INTERNAL_ERROR; + goto f_err; + } + if (!EVP_VerifyInit_ex(&mctx, md, NULL) || + !EVP_VerifyUpdate(&mctx, hdata, hdatalen)) { + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, + ERR_R_EVP_LIB); + al = SSL_AD_INTERNAL_ERROR; + goto f_err; + } + + if (EVP_VerifyFinal(&mctx, p, i, pkey) <= 0) { + al = SSL_AD_DECRYPT_ERROR; + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, + SSL_R_BAD_SIGNATURE); + goto f_err; + } + } else + if (pkey->type == EVP_PKEY_RSA) { + i = RSA_verify(NID_md5_sha1, S3I(s)->tmp.cert_verify_md, + MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH, p, i, + pkey->pkey.rsa); + if (i < 0) { + al = SSL_AD_DECRYPT_ERROR; + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, + SSL_R_BAD_RSA_DECRYPT); + goto f_err; + } + if (i == 0) { + al = SSL_AD_DECRYPT_ERROR; + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, + SSL_R_BAD_RSA_SIGNATURE); + goto f_err; + } + } else + if (pkey->type == EVP_PKEY_DSA) { + j = DSA_verify(pkey->save_type, + &(S3I(s)->tmp.cert_verify_md[MD5_DIGEST_LENGTH]), + SHA_DIGEST_LENGTH, p, i, pkey->pkey.dsa); + if (j <= 0) { + /* bad signature */ + al = SSL_AD_DECRYPT_ERROR; + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, + SSL_R_BAD_DSA_SIGNATURE); + goto f_err; + } + } else + if (pkey->type == EVP_PKEY_EC) { + j = ECDSA_verify(pkey->save_type, + &(S3I(s)->tmp.cert_verify_md[MD5_DIGEST_LENGTH]), + SHA_DIGEST_LENGTH, p, i, pkey->pkey.ec); + if (j <= 0) { + /* bad signature */ + al = SSL_AD_DECRYPT_ERROR; + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, + SSL_R_BAD_ECDSA_SIGNATURE); + goto f_err; + } + } else +#ifndef OPENSSL_NO_GOST + if (pkey->type == NID_id_GostR3410_94 || + pkey->type == NID_id_GostR3410_2001) { + long hdatalen = 0; + void *hdata; + unsigned char signature[128]; + unsigned int siglen = sizeof(signature); + int nid; + EVP_PKEY_CTX *pctx; + + hdatalen = BIO_get_mem_data(S3I(s)->handshake_buffer, &hdata); + if (hdatalen <= 0) { + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, + ERR_R_INTERNAL_ERROR); + al = SSL_AD_INTERNAL_ERROR; + goto f_err; + } + if (!EVP_PKEY_get_default_digest_nid(pkey, &nid) || + !(md = EVP_get_digestbynid(nid))) { + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, + ERR_R_EVP_LIB); + al = SSL_AD_INTERNAL_ERROR; + goto f_err; + } + pctx = EVP_PKEY_CTX_new(pkey, NULL); + if (!pctx) { + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, + ERR_R_EVP_LIB); + al = SSL_AD_INTERNAL_ERROR; + goto f_err; + } + if (!EVP_DigestInit_ex(&mctx, md, NULL) || + !EVP_DigestUpdate(&mctx, hdata, hdatalen) || + !EVP_DigestFinal(&mctx, signature, &siglen) || + (EVP_PKEY_verify_init(pctx) <= 0) || + (EVP_PKEY_CTX_set_signature_md(pctx, md) <= 0) || + (EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_VERIFY, + EVP_PKEY_CTRL_GOST_SIG_FORMAT, + GOST_SIG_FORMAT_RS_LE, + NULL) <= 0)) { + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, + ERR_R_EVP_LIB); + al = SSL_AD_INTERNAL_ERROR; + EVP_PKEY_CTX_free(pctx); + goto f_err; + } + + if (EVP_PKEY_verify(pctx, p, i, signature, siglen) <= 0) { + al = SSL_AD_DECRYPT_ERROR; + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, + SSL_R_BAD_SIGNATURE); + EVP_PKEY_CTX_free(pctx); + goto f_err; + } + + EVP_PKEY_CTX_free(pctx); + } else +#endif + { + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, + ERR_R_INTERNAL_ERROR); + al = SSL_AD_UNSUPPORTED_CERTIFICATE; + goto f_err; + } + + + ret = 1; + if (0) { +truncated: + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, SSL_R_BAD_PACKET_LENGTH); +f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + } +end: + if (S3I(s)->handshake_buffer) { + BIO_free(S3I(s)->handshake_buffer); + S3I(s)->handshake_buffer = NULL; + s->s3->flags &= ~TLS1_FLAGS_KEEP_HANDSHAKE; + } + EVP_MD_CTX_cleanup(&mctx); + EVP_PKEY_free(pkey); + return (ret); +} + +int +ssl3_get_client_certificate(SSL *s) +{ + CBS cbs, client_certs; + int i, ok, al, ret = -1; + X509 *x = NULL; + long n; + const unsigned char *q; + STACK_OF(X509) *sk = NULL; + + n = s->method->internal->ssl_get_message(s, SSL3_ST_SR_CERT_A, SSL3_ST_SR_CERT_B, + -1, s->internal->max_cert_list, &ok); + + if (!ok) + return ((int)n); + + if (S3I(s)->tmp.message_type == SSL3_MT_CLIENT_KEY_EXCHANGE) { + if ((s->verify_mode & SSL_VERIFY_PEER) && + (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) { + SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, + SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE); + al = SSL_AD_HANDSHAKE_FAILURE; + goto f_err; + } + /* + * If tls asked for a client cert, + * the client must return a 0 list. + */ + if (S3I(s)->tmp.cert_request) { + SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, + SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST + ); + al = SSL_AD_UNEXPECTED_MESSAGE; + goto f_err; + } + S3I(s)->tmp.reuse_message = 1; + return (1); + } + + if (S3I(s)->tmp.message_type != SSL3_MT_CERTIFICATE) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, + SSL_R_WRONG_MESSAGE_TYPE); + goto f_err; + } + + if (n < 0) + goto truncated; + + CBS_init(&cbs, s->internal->init_msg, n); + + if ((sk = sk_X509_new_null()) == NULL) { + SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, + ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!CBS_get_u24_length_prefixed(&cbs, &client_certs) || + CBS_len(&cbs) != 0) + goto truncated; + + while (CBS_len(&client_certs) > 0) { + CBS cert; + + if (!CBS_get_u24_length_prefixed(&client_certs, &cert)) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, + SSL_R_CERT_LENGTH_MISMATCH); + goto f_err; + } + + q = CBS_data(&cert); + x = d2i_X509(NULL, &q, CBS_len(&cert)); + if (x == NULL) { + SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, + ERR_R_ASN1_LIB); + goto err; + } + if (q != CBS_data(&cert) + CBS_len(&cert)) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, + SSL_R_CERT_LENGTH_MISMATCH); + goto f_err; + } + if (!sk_X509_push(sk, x)) { + SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, + ERR_R_MALLOC_FAILURE); + goto err; + } + x = NULL; + } + + if (sk_X509_num(sk) <= 0) { + /* + * TLS does not mind 0 certs returned. + * Fail for TLS only if we required a certificate. + */ + if ((s->verify_mode & SSL_VERIFY_PEER) && + (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) { + SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, + SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE); + al = SSL_AD_HANDSHAKE_FAILURE; + goto f_err; + } + /* No client certificate so digest cached records */ + if (S3I(s)->handshake_buffer && !tls1_digest_cached_records(s)) { + al = SSL_AD_INTERNAL_ERROR; + goto f_err; + } + } else { + i = ssl_verify_cert_chain(s, sk); + if (i <= 0) { + al = ssl_verify_alarm_type(s->verify_result); + SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, + SSL_R_NO_CERTIFICATE_RETURNED); + goto f_err; + } + } + + X509_free(s->session->peer); + s->session->peer = sk_X509_shift(sk); + s->session->verify_result = s->verify_result; + + /* + * With the current implementation, sess_cert will always be NULL + * when we arrive here + */ + if (SSI(s)->sess_cert == NULL) { + SSI(s)->sess_cert = ssl_sess_cert_new(); + if (SSI(s)->sess_cert == NULL) { + SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, + ERR_R_MALLOC_FAILURE); + goto err; + } + } + sk_X509_pop_free(SSI(s)->sess_cert->cert_chain, X509_free); + SSI(s)->sess_cert->cert_chain = sk; + + /* + * Inconsistency alert: cert_chain does *not* include the + * peer's own certificate, while we do include it in s3_clnt.c + */ + + sk = NULL; + + ret = 1; + if (0) { +truncated: + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, + SSL_R_BAD_PACKET_LENGTH); +f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + } +err: + X509_free(x); + sk_X509_pop_free(sk, X509_free); + + return (ret); +} + +int +ssl3_send_server_certificate(SSL *s) +{ + CBB cbb, server_cert; + X509 *x; + + /* + * Server Certificate - RFC 5246, section 7.4.2. + */ + + memset(&cbb, 0, sizeof(cbb)); + + if (s->internal->state == SSL3_ST_SW_CERT_A) { + if ((x = ssl_get_server_send_cert(s)) == NULL) { + SSLerr(SSL_F_SSL3_SEND_SERVER_CERTIFICATE, + ERR_R_INTERNAL_ERROR); + return (0); + } + + if (!ssl3_handshake_msg_start_cbb(s, &cbb, &server_cert, + SSL3_MT_CERTIFICATE)) + goto err; + if (!ssl3_output_cert_chain(s, &server_cert, x)) + goto err; + if (!ssl3_handshake_msg_finish_cbb(s, &cbb)) + goto err; + + s->internal->state = SSL3_ST_SW_CERT_B; + } + + /* SSL3_ST_SW_CERT_B */ + return (ssl3_handshake_write(s)); + + err: + CBB_cleanup(&cbb); + + return (0); +} + +/* send a new session ticket (not necessarily for a new session) */ +int +ssl3_send_newsession_ticket(SSL *s) +{ + unsigned char *d, *p, *macstart; + unsigned char *senc = NULL; + const unsigned char *const_p; + int len, slen_full, slen; + SSL_SESSION *sess; + unsigned int hlen; + EVP_CIPHER_CTX ctx; + HMAC_CTX hctx; + SSL_CTX *tctx = s->initial_ctx; + unsigned char iv[EVP_MAX_IV_LENGTH]; + unsigned char key_name[16]; + + if (s->internal->state == SSL3_ST_SW_SESSION_TICKET_A) { + /* get session encoding length */ + slen_full = i2d_SSL_SESSION(s->session, NULL); + /* + * Some length values are 16 bits, so forget it if session is + * too long + */ + if (slen_full > 0xFF00) + goto err; + senc = malloc(slen_full); + if (!senc) + goto err; + p = senc; + i2d_SSL_SESSION(s->session, &p); + + /* + * Create a fresh copy (not shared with other threads) to + * clean up + */ + const_p = senc; + sess = d2i_SSL_SESSION(NULL, &const_p, slen_full); + if (sess == NULL) + goto err; + + /* ID is irrelevant for the ticket */ + sess->session_id_length = 0; + + slen = i2d_SSL_SESSION(sess, NULL); + if (slen > slen_full) { + /* shouldn't ever happen */ + goto err; + } + p = senc; + i2d_SSL_SESSION(sess, &p); + SSL_SESSION_free(sess); + + /* + * Grow buffer if need be: the length calculation is as + * follows 1 (size of message name) + 3 (message length + * bytes) + 4 (ticket lifetime hint) + 2 (ticket length) + + * 16 (key name) + max_iv_len (iv length) + + * session_length + max_enc_block_size (max encrypted session + * length) + max_md_size (HMAC). + */ + if (!BUF_MEM_grow(s->internal->init_buf, ssl3_handshake_msg_hdr_len(s) + + 22 + EVP_MAX_IV_LENGTH + EVP_MAX_BLOCK_LENGTH + + EVP_MAX_MD_SIZE + slen)) + goto err; + + d = p = ssl3_handshake_msg_start(s, SSL3_MT_NEWSESSION_TICKET); + + EVP_CIPHER_CTX_init(&ctx); + HMAC_CTX_init(&hctx); + + /* + * Initialize HMAC and cipher contexts. If callback present + * it does all the work otherwise use generated values + * from parent ctx. + */ + if (tctx->internal->tlsext_ticket_key_cb) { + if (tctx->internal->tlsext_ticket_key_cb(s, + key_name, iv, &ctx, &hctx, 1) < 0) { + EVP_CIPHER_CTX_cleanup(&ctx); + goto err; + } + } else { + arc4random_buf(iv, 16); + EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, + tctx->internal->tlsext_tick_aes_key, iv); + HMAC_Init_ex(&hctx, tctx->internal->tlsext_tick_hmac_key, + 16, tlsext_tick_md(), NULL); + memcpy(key_name, tctx->internal->tlsext_tick_key_name, 16); + } + + /* + * Ticket lifetime hint (advisory only): + * We leave this unspecified for resumed session + * (for simplicity), and guess that tickets for new + * sessions will live as long as their sessions. + */ + l2n(s->internal->hit ? 0 : s->session->timeout, p); + + /* Skip ticket length for now */ + p += 2; + /* Output key name */ + macstart = p; + memcpy(p, key_name, 16); + p += 16; + /* output IV */ + memcpy(p, iv, EVP_CIPHER_CTX_iv_length(&ctx)); + p += EVP_CIPHER_CTX_iv_length(&ctx); + /* Encrypt session data */ + EVP_EncryptUpdate(&ctx, p, &len, senc, slen); + p += len; + EVP_EncryptFinal_ex(&ctx, p, &len); + p += len; + EVP_CIPHER_CTX_cleanup(&ctx); + + HMAC_Update(&hctx, macstart, p - macstart); + HMAC_Final(&hctx, p, &hlen); + HMAC_CTX_cleanup(&hctx); + p += hlen; + + /* Now write out lengths: p points to end of data written */ + /* Total length */ + len = p - d; + + /* Skip ticket lifetime hint. */ + p = d + 4; + s2n(len - 6, p); /* Message length */ + + ssl3_handshake_msg_finish(s, len); + + s->internal->state = SSL3_ST_SW_SESSION_TICKET_B; + + explicit_bzero(senc, slen_full); + free(senc); + } + + /* SSL3_ST_SW_SESSION_TICKET_B */ + return (ssl3_handshake_write(s)); + + err: + if (senc != NULL) + explicit_bzero(senc, slen_full); + free(senc); + + return (-1); +} + +int +ssl3_send_cert_status(SSL *s) +{ + unsigned char *p; + + if (s->internal->state == SSL3_ST_SW_CERT_STATUS_A) { + /* + * Grow buffer if need be: the length calculation is as + * follows 1 (message type) + 3 (message length) + + * 1 (ocsp response type) + 3 (ocsp response length) + * + (ocsp response) + */ + if (!BUF_MEM_grow(s->internal->init_buf, SSL3_HM_HEADER_LENGTH + 4 + + s->internal->tlsext_ocsp_resplen)) + return (-1); + + p = ssl3_handshake_msg_start(s, SSL3_MT_CERTIFICATE_STATUS); + + *(p++) = s->tlsext_status_type; + l2n3(s->internal->tlsext_ocsp_resplen, p); + memcpy(p, s->internal->tlsext_ocsp_resp, s->internal->tlsext_ocsp_resplen); + + ssl3_handshake_msg_finish(s, s->internal->tlsext_ocsp_resplen + 4); + + s->internal->state = SSL3_ST_SW_CERT_STATUS_B; + } + + /* SSL3_ST_SW_CERT_STATUS_B */ + return (ssl3_handshake_write(s)); +} + +/* + * ssl3_get_next_proto reads a Next Protocol Negotiation handshake message. + * It sets the next_proto member in s if found + */ +int +ssl3_get_next_proto(SSL *s) +{ + CBS cbs, proto, padding; + int ok; + long n; + size_t len; + + /* + * Clients cannot send a NextProtocol message if we didn't see the + * extension in their ClientHello + */ + if (!S3I(s)->next_proto_neg_seen) { + SSLerr(SSL_F_SSL3_GET_NEXT_PROTO, + SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION); + return (-1); + } + + /* 514 maxlen is enough for the payload format below */ + n = s->method->internal->ssl_get_message(s, SSL3_ST_SR_NEXT_PROTO_A, + SSL3_ST_SR_NEXT_PROTO_B, SSL3_MT_NEXT_PROTO, 514, &ok); + if (!ok) + return ((int)n); + + /* + * s->internal->state doesn't reflect whether ChangeCipherSpec has been received + * in this handshake, but S3I(s)->change_cipher_spec does (will be reset + * by ssl3_get_finished). + */ + if (!S3I(s)->change_cipher_spec) { + SSLerr(SSL_F_SSL3_GET_NEXT_PROTO, + SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS); + return (-1); + } + + if (n < 2) + return (0); + /* The body must be > 1 bytes long */ + + CBS_init(&cbs, s->internal->init_msg, s->internal->init_num); + + /* + * The payload looks like: + * uint8 proto_len; + * uint8 proto[proto_len]; + * uint8 padding_len; + * uint8 padding[padding_len]; + */ + if (!CBS_get_u8_length_prefixed(&cbs, &proto) || + !CBS_get_u8_length_prefixed(&cbs, &padding) || + CBS_len(&cbs) != 0) + return 0; + + /* + * XXX We should not NULL it, but this matches old behavior of not + * freeing before malloc. + */ + s->internal->next_proto_negotiated = NULL; + s->internal->next_proto_negotiated_len = 0; + + if (!CBS_stow(&proto, &s->internal->next_proto_negotiated, &len)) { + SSLerr(SSL_F_SSL3_GET_NEXT_PROTO, + ERR_R_MALLOC_FAILURE); + return (0); + } + s->internal->next_proto_negotiated_len = (uint8_t)len; + + return (1); +} -- cgit v1.2.3-55-g6feb