diff options
Diffstat (limited to 'thirdparty/openssl/ssl')
55 files changed, 56115 insertions, 0 deletions
diff --git a/thirdparty/openssl/ssl/bio_ssl.c b/thirdparty/openssl/ssl/bio_ssl.c new file mode 100644 index 0000000000..d2d4d2ea2d --- /dev/null +++ b/thirdparty/openssl/ssl/bio_ssl.c @@ -0,0 +1,591 @@ +/* ssl/bio_ssl.c */ +/* 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.] + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <openssl/crypto.h> +#include <openssl/bio.h> +#include <openssl/err.h> +#include <openssl/ssl.h> + +static int ssl_write(BIO *h, const char *buf, int num); +static int ssl_read(BIO *h, char *buf, int size); +static int ssl_puts(BIO *h, const char *str); +static long ssl_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static int ssl_new(BIO *h); +static int ssl_free(BIO *data); +static long ssl_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp); +typedef struct bio_ssl_st { + SSL *ssl; /* The ssl handle :-) */ + /* re-negotiate every time the total number of bytes is this size */ + int num_renegotiates; + unsigned long renegotiate_count; + unsigned long byte_count; + unsigned long renegotiate_timeout; + unsigned long last_time; +} BIO_SSL; + +static BIO_METHOD methods_sslp = { + BIO_TYPE_SSL, "ssl", + ssl_write, + ssl_read, + ssl_puts, + NULL, /* ssl_gets, */ + ssl_ctrl, + ssl_new, + ssl_free, + ssl_callback_ctrl, +}; + +BIO_METHOD *BIO_f_ssl(void) +{ + return (&methods_sslp); +} + +static int ssl_new(BIO *bi) +{ + BIO_SSL *bs; + + bs = (BIO_SSL *)OPENSSL_malloc(sizeof(BIO_SSL)); + if (bs == NULL) { + BIOerr(BIO_F_SSL_NEW, ERR_R_MALLOC_FAILURE); + return (0); + } + memset(bs, 0, sizeof(BIO_SSL)); + bi->init = 0; + bi->ptr = (char *)bs; + bi->flags = 0; + return (1); +} + +static int ssl_free(BIO *a) +{ + BIO_SSL *bs; + + if (a == NULL) + return (0); + bs = (BIO_SSL *)a->ptr; + if (bs->ssl != NULL) + SSL_shutdown(bs->ssl); + if (a->shutdown) { + if (a->init && (bs->ssl != NULL)) + SSL_free(bs->ssl); + a->init = 0; + a->flags = 0; + } + if (a->ptr != NULL) + OPENSSL_free(a->ptr); + return (1); +} + +static int ssl_read(BIO *b, char *out, int outl) +{ + int ret = 1; + BIO_SSL *sb; + SSL *ssl; + int retry_reason = 0; + int r = 0; + + if (out == NULL) + return (0); + sb = (BIO_SSL *)b->ptr; + ssl = sb->ssl; + + BIO_clear_retry_flags(b); + +#if 0 + if (!SSL_is_init_finished(ssl)) { +/* ret=SSL_do_handshake(ssl); */ + if (ret > 0) { + + outflags = (BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY); + ret = -1; + goto end; + } + } +#endif +/* if (ret > 0) */ + ret = SSL_read(ssl, out, outl); + + switch (SSL_get_error(ssl, ret)) { + case SSL_ERROR_NONE: + if (ret <= 0) + break; + if (sb->renegotiate_count > 0) { + sb->byte_count += ret; + if (sb->byte_count > sb->renegotiate_count) { + sb->byte_count = 0; + sb->num_renegotiates++; + SSL_renegotiate(ssl); + r = 1; + } + } + if ((sb->renegotiate_timeout > 0) && (!r)) { + unsigned long tm; + + tm = (unsigned long)time(NULL); + if (tm > sb->last_time + sb->renegotiate_timeout) { + sb->last_time = tm; + sb->num_renegotiates++; + SSL_renegotiate(ssl); + } + } + + break; + case SSL_ERROR_WANT_READ: + BIO_set_retry_read(b); + break; + case SSL_ERROR_WANT_WRITE: + BIO_set_retry_write(b); + break; + case SSL_ERROR_WANT_X509_LOOKUP: + BIO_set_retry_special(b); + retry_reason = BIO_RR_SSL_X509_LOOKUP; + break; + case SSL_ERROR_WANT_ACCEPT: + BIO_set_retry_special(b); + retry_reason = BIO_RR_ACCEPT; + break; + case SSL_ERROR_WANT_CONNECT: + BIO_set_retry_special(b); + retry_reason = BIO_RR_CONNECT; + break; + case SSL_ERROR_SYSCALL: + case SSL_ERROR_SSL: + case SSL_ERROR_ZERO_RETURN: + default: + break; + } + + b->retry_reason = retry_reason; + return (ret); +} + +static int ssl_write(BIO *b, const char *out, int outl) +{ + int ret, r = 0; + int retry_reason = 0; + SSL *ssl; + BIO_SSL *bs; + + if (out == NULL) + return (0); + bs = (BIO_SSL *)b->ptr; + ssl = bs->ssl; + + BIO_clear_retry_flags(b); + + /* + * ret=SSL_do_handshake(ssl); if (ret > 0) + */ + ret = SSL_write(ssl, out, outl); + + switch (SSL_get_error(ssl, ret)) { + case SSL_ERROR_NONE: + if (ret <= 0) + break; + if (bs->renegotiate_count > 0) { + bs->byte_count += ret; + if (bs->byte_count > bs->renegotiate_count) { + bs->byte_count = 0; + bs->num_renegotiates++; + SSL_renegotiate(ssl); + r = 1; + } + } + if ((bs->renegotiate_timeout > 0) && (!r)) { + unsigned long tm; + + tm = (unsigned long)time(NULL); + if (tm > bs->last_time + bs->renegotiate_timeout) { + bs->last_time = tm; + bs->num_renegotiates++; + SSL_renegotiate(ssl); + } + } + break; + case SSL_ERROR_WANT_WRITE: + BIO_set_retry_write(b); + break; + case SSL_ERROR_WANT_READ: + BIO_set_retry_read(b); + break; + case SSL_ERROR_WANT_X509_LOOKUP: + BIO_set_retry_special(b); + retry_reason = BIO_RR_SSL_X509_LOOKUP; + break; + case SSL_ERROR_WANT_CONNECT: + BIO_set_retry_special(b); + retry_reason = BIO_RR_CONNECT; + case SSL_ERROR_SYSCALL: + case SSL_ERROR_SSL: + default: + break; + } + + b->retry_reason = retry_reason; + return (ret); +} + +static long ssl_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + SSL **sslp, *ssl; + BIO_SSL *bs; + BIO *dbio, *bio; + long ret = 1; + + bs = (BIO_SSL *)b->ptr; + ssl = bs->ssl; + if ((ssl == NULL) && (cmd != BIO_C_SET_SSL)) + return (0); + switch (cmd) { + case BIO_CTRL_RESET: + SSL_shutdown(ssl); + + if (ssl->handshake_func == ssl->method->ssl_connect) + SSL_set_connect_state(ssl); + else if (ssl->handshake_func == ssl->method->ssl_accept) + SSL_set_accept_state(ssl); + + SSL_clear(ssl); + + if (b->next_bio != NULL) + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + else if (ssl->rbio != NULL) + ret = BIO_ctrl(ssl->rbio, cmd, num, ptr); + else + ret = 1; + break; + case BIO_CTRL_INFO: + ret = 0; + break; + case BIO_C_SSL_MODE: + if (num) /* client mode */ + SSL_set_connect_state(ssl); + else + SSL_set_accept_state(ssl); + break; + case BIO_C_SET_SSL_RENEGOTIATE_TIMEOUT: + ret = bs->renegotiate_timeout; + if (num < 60) + num = 5; + bs->renegotiate_timeout = (unsigned long)num; + bs->last_time = (unsigned long)time(NULL); + break; + case BIO_C_SET_SSL_RENEGOTIATE_BYTES: + ret = bs->renegotiate_count; + if ((long)num >= 512) + bs->renegotiate_count = (unsigned long)num; + break; + case BIO_C_GET_SSL_NUM_RENEGOTIATES: + ret = bs->num_renegotiates; + break; + case BIO_C_SET_SSL: + if (ssl != NULL) { + ssl_free(b); + if (!ssl_new(b)) + return 0; + } + b->shutdown = (int)num; + ssl = (SSL *)ptr; + ((BIO_SSL *)b->ptr)->ssl = ssl; + bio = SSL_get_rbio(ssl); + if (bio != NULL) { + if (b->next_bio != NULL) + BIO_push(bio, b->next_bio); + b->next_bio = bio; + CRYPTO_add(&bio->references, 1, CRYPTO_LOCK_BIO); + } + b->init = 1; + break; + case BIO_C_GET_SSL: + if (ptr != NULL) { + sslp = (SSL **)ptr; + *sslp = ssl; + } else + ret = 0; + break; + case BIO_CTRL_GET_CLOSE: + ret = b->shutdown; + break; + case BIO_CTRL_SET_CLOSE: + b->shutdown = (int)num; + break; + case BIO_CTRL_WPENDING: + ret = BIO_ctrl(ssl->wbio, cmd, num, ptr); + break; + case BIO_CTRL_PENDING: + ret = SSL_pending(ssl); + if (ret == 0) + ret = BIO_pending(ssl->rbio); + break; + case BIO_CTRL_FLUSH: + BIO_clear_retry_flags(b); + ret = BIO_ctrl(ssl->wbio, cmd, num, ptr); + BIO_copy_next_retry(b); + break; + case BIO_CTRL_PUSH: + if ((b->next_bio != NULL) && (b->next_bio != ssl->rbio)) { + SSL_set_bio(ssl, b->next_bio, b->next_bio); + CRYPTO_add(&b->next_bio->references, 1, CRYPTO_LOCK_BIO); + } + break; + case BIO_CTRL_POP: + /* Only detach if we are the BIO explicitly being popped */ + if (b == ptr) { + /* + * Shouldn't happen in practice because the rbio and wbio are the + * same when pushed. + */ + if (ssl->rbio != ssl->wbio) + BIO_free_all(ssl->wbio); + if (b->next_bio != NULL) + CRYPTO_add(&b->next_bio->references, -1, CRYPTO_LOCK_BIO); + ssl->wbio = NULL; + ssl->rbio = NULL; + } + break; + case BIO_C_DO_STATE_MACHINE: + BIO_clear_retry_flags(b); + + b->retry_reason = 0; + ret = (int)SSL_do_handshake(ssl); + + switch (SSL_get_error(ssl, (int)ret)) { + case SSL_ERROR_WANT_READ: + BIO_set_flags(b, BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY); + break; + case SSL_ERROR_WANT_WRITE: + BIO_set_flags(b, BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY); + break; + case SSL_ERROR_WANT_CONNECT: + BIO_set_flags(b, BIO_FLAGS_IO_SPECIAL | BIO_FLAGS_SHOULD_RETRY); + b->retry_reason = b->next_bio->retry_reason; + break; + case SSL_ERROR_WANT_X509_LOOKUP: + BIO_set_retry_special(b); + b->retry_reason = BIO_RR_SSL_X509_LOOKUP; + break; + default: + break; + } + break; + case BIO_CTRL_DUP: + dbio = (BIO *)ptr; + if (((BIO_SSL *)dbio->ptr)->ssl != NULL) + SSL_free(((BIO_SSL *)dbio->ptr)->ssl); + ((BIO_SSL *)dbio->ptr)->ssl = SSL_dup(ssl); + ((BIO_SSL *)dbio->ptr)->renegotiate_count = + ((BIO_SSL *)b->ptr)->renegotiate_count; + ((BIO_SSL *)dbio->ptr)->byte_count = ((BIO_SSL *)b->ptr)->byte_count; + ((BIO_SSL *)dbio->ptr)->renegotiate_timeout = + ((BIO_SSL *)b->ptr)->renegotiate_timeout; + ((BIO_SSL *)dbio->ptr)->last_time = ((BIO_SSL *)b->ptr)->last_time; + ret = (((BIO_SSL *)dbio->ptr)->ssl != NULL); + break; + case BIO_C_GET_FD: + ret = BIO_ctrl(ssl->rbio, cmd, num, ptr); + break; + case BIO_CTRL_SET_CALLBACK: + { +#if 0 /* FIXME: Should this be used? -- Richard + * Levitte */ + SSLerr(SSL_F_SSL_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + ret = -1; +#else + ret = 0; +#endif + } + break; + case BIO_CTRL_GET_CALLBACK: + { + void (**fptr) (const SSL *xssl, int type, int val); + + fptr = (void (**)(const SSL *xssl, int type, int val))ptr; + *fptr = SSL_get_info_callback(ssl); + } + break; + default: + ret = BIO_ctrl(ssl->rbio, cmd, num, ptr); + break; + } + return (ret); +} + +static long ssl_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) +{ + SSL *ssl; + BIO_SSL *bs; + long ret = 1; + + bs = (BIO_SSL *)b->ptr; + ssl = bs->ssl; + switch (cmd) { + case BIO_CTRL_SET_CALLBACK: + { + /* + * FIXME: setting this via a completely different prototype seems + * like a crap idea + */ + SSL_set_info_callback(ssl, (void (*)(const SSL *, int, int))fp); + } + break; + default: + ret = BIO_callback_ctrl(ssl->rbio, cmd, fp); + break; + } + return (ret); +} + +static int ssl_puts(BIO *bp, const char *str) +{ + int n, ret; + + n = strlen(str); + ret = BIO_write(bp, str, n); + return (ret); +} + +BIO *BIO_new_buffer_ssl_connect(SSL_CTX *ctx) +{ +#ifndef OPENSSL_NO_SOCK + BIO *ret = NULL, *buf = NULL, *ssl = NULL; + + if ((buf = BIO_new(BIO_f_buffer())) == NULL) + return (NULL); + if ((ssl = BIO_new_ssl_connect(ctx)) == NULL) + goto err; + if ((ret = BIO_push(buf, ssl)) == NULL) + goto err; + return (ret); + err: + if (buf != NULL) + BIO_free(buf); + if (ssl != NULL) + BIO_free(ssl); +#endif + return (NULL); +} + +BIO *BIO_new_ssl_connect(SSL_CTX *ctx) +{ +#ifndef OPENSSL_NO_SOCK + BIO *ret = NULL, *con = NULL, *ssl = NULL; + + if ((con = BIO_new(BIO_s_connect())) == NULL) + return (NULL); + if ((ssl = BIO_new_ssl(ctx, 1)) == NULL) + goto err; + if ((ret = BIO_push(ssl, con)) == NULL) + goto err; + return (ret); + err: + if (con != NULL) + BIO_free(con); +#endif + return (NULL); +} + +BIO *BIO_new_ssl(SSL_CTX *ctx, int client) +{ + BIO *ret; + SSL *ssl; + + if ((ret = BIO_new(BIO_f_ssl())) == NULL) + return (NULL); + if ((ssl = SSL_new(ctx)) == NULL) { + BIO_free(ret); + return (NULL); + } + if (client) + SSL_set_connect_state(ssl); + else + SSL_set_accept_state(ssl); + + BIO_set_ssl(ret, ssl, BIO_CLOSE); + return (ret); +} + +int BIO_ssl_copy_session_id(BIO *t, BIO *f) +{ + t = BIO_find_type(t, BIO_TYPE_SSL); + f = BIO_find_type(f, BIO_TYPE_SSL); + if ((t == NULL) || (f == NULL)) + return (0); + if ((((BIO_SSL *)t->ptr)->ssl == NULL) || + (((BIO_SSL *)f->ptr)->ssl == NULL)) + return (0); + SSL_copy_session_id(((BIO_SSL *)t->ptr)->ssl, ((BIO_SSL *)f->ptr)->ssl); + return (1); +} + +void BIO_ssl_shutdown(BIO *b) +{ + SSL *s; + + while (b != NULL) { + if (b->method->type == BIO_TYPE_SSL) { + s = ((BIO_SSL *)b->ptr)->ssl; + SSL_shutdown(s); + break; + } + b = b->next_bio; + } +} diff --git a/thirdparty/openssl/ssl/d1_both.c b/thirdparty/openssl/ssl/d1_both.c new file mode 100644 index 0000000000..5d26c94926 --- /dev/null +++ b/thirdparty/openssl/ssl/d1_both.c @@ -0,0 +1,1580 @@ +/* ssl/d1_both.c */ +/* + * DTLS implementation written by Nagendra Modadugu + * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. + */ +/* ==================================================================== + * Copyright (c) 1998-2005 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 (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.] + */ + +#include <limits.h> +#include <string.h> +#include <stdio.h> +#include "ssl_locl.h" +#include <openssl/buffer.h> +#include <openssl/rand.h> +#include <openssl/objects.h> +#include <openssl/evp.h> +#include <openssl/x509.h> + +#define RSMBLY_BITMASK_SIZE(msg_len) (((msg_len) + 7) / 8) + +#define RSMBLY_BITMASK_MARK(bitmask, start, end) { \ + if ((end) - (start) <= 8) { \ + long ii; \ + for (ii = (start); ii < (end); ii++) bitmask[((ii) >> 3)] |= (1 << ((ii) & 7)); \ + } else { \ + long ii; \ + bitmask[((start) >> 3)] |= bitmask_start_values[((start) & 7)]; \ + for (ii = (((start) >> 3) + 1); ii < ((((end) - 1)) >> 3); ii++) bitmask[ii] = 0xff; \ + bitmask[(((end) - 1) >> 3)] |= bitmask_end_values[((end) & 7)]; \ + } } + +#define RSMBLY_BITMASK_IS_COMPLETE(bitmask, msg_len, is_complete) { \ + long ii; \ + OPENSSL_assert((msg_len) > 0); \ + is_complete = 1; \ + if (bitmask[(((msg_len) - 1) >> 3)] != bitmask_end_values[((msg_len) & 7)]) is_complete = 0; \ + if (is_complete) for (ii = (((msg_len) - 1) >> 3) - 1; ii >= 0 ; ii--) \ + if (bitmask[ii] != 0xff) { is_complete = 0; break; } } + +#if 0 +# define RSMBLY_BITMASK_PRINT(bitmask, msg_len) { \ + long ii; \ + printf("bitmask: "); for (ii = 0; ii < (msg_len); ii++) \ + printf("%d ", (bitmask[ii >> 3] & (1 << (ii & 7))) >> (ii & 7)); \ + printf("\n"); } +#endif + +static unsigned char bitmask_start_values[] = + { 0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80 }; +static unsigned char bitmask_end_values[] = + { 0xff, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f }; + +/* XDTLS: figure out the right values */ +static const unsigned int g_probable_mtu[] = { 1500, 512, 256 }; + +static void dtls1_fix_message_header(SSL *s, unsigned long frag_off, + unsigned long frag_len); +static unsigned char *dtls1_write_message_header(SSL *s, unsigned char *p); +static void dtls1_set_message_header_int(SSL *s, unsigned char mt, + unsigned long len, + unsigned short seq_num, + unsigned long frag_off, + unsigned long frag_len); +static long dtls1_get_message_fragment(SSL *s, int st1, int stn, long max, + int *ok); + +static hm_fragment *dtls1_hm_fragment_new(unsigned long frag_len, + int reassembly) +{ + hm_fragment *frag = NULL; + unsigned char *buf = NULL; + unsigned char *bitmask = NULL; + + frag = (hm_fragment *)OPENSSL_malloc(sizeof(hm_fragment)); + if (frag == NULL) + return NULL; + + if (frag_len) { + buf = (unsigned char *)OPENSSL_malloc(frag_len); + if (buf == NULL) { + OPENSSL_free(frag); + return NULL; + } + } + + /* zero length fragment gets zero frag->fragment */ + frag->fragment = buf; + + /* Initialize reassembly bitmask if necessary */ + if (reassembly) { + bitmask = + (unsigned char *)OPENSSL_malloc(RSMBLY_BITMASK_SIZE(frag_len)); + if (bitmask == NULL) { + if (buf != NULL) + OPENSSL_free(buf); + OPENSSL_free(frag); + return NULL; + } + memset(bitmask, 0, RSMBLY_BITMASK_SIZE(frag_len)); + } + + frag->reassembly = bitmask; + + return frag; +} + +void dtls1_hm_fragment_free(hm_fragment *frag) +{ + + if (frag->msg_header.is_ccs) { + EVP_CIPHER_CTX_free(frag->msg_header. + saved_retransmit_state.enc_write_ctx); + EVP_MD_CTX_destroy(frag->msg_header. + saved_retransmit_state.write_hash); + } + if (frag->fragment) + OPENSSL_free(frag->fragment); + if (frag->reassembly) + OPENSSL_free(frag->reassembly); + OPENSSL_free(frag); +} + +static int dtls1_query_mtu(SSL *s) +{ + if (s->d1->link_mtu) { + s->d1->mtu = + s->d1->link_mtu - BIO_dgram_get_mtu_overhead(SSL_get_wbio(s)); + s->d1->link_mtu = 0; + } + + /* AHA! Figure out the MTU, and stick to the right size */ + if (s->d1->mtu < dtls1_min_mtu(s)) { + if (!(SSL_get_options(s) & SSL_OP_NO_QUERY_MTU)) { + s->d1->mtu = + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL); + + /* + * I've seen the kernel return bogus numbers when it doesn't know + * (initial write), so just make sure we have a reasonable number + */ + if (s->d1->mtu < dtls1_min_mtu(s)) { + /* Set to min mtu */ + s->d1->mtu = dtls1_min_mtu(s); + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SET_MTU, + s->d1->mtu, NULL); + } + } else + return 0; + } + return 1; +} + +/* + * send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or + * SSL3_RT_CHANGE_CIPHER_SPEC) + */ +int dtls1_do_write(SSL *s, int type) +{ + int ret; + unsigned int curr_mtu; + int retry = 1; + unsigned int len, frag_off, mac_size, blocksize, used_len; + + if (!dtls1_query_mtu(s)) + return -1; + + OPENSSL_assert(s->d1->mtu >= dtls1_min_mtu(s)); /* should have something + * reasonable now */ + + if (s->init_off == 0 && type == SSL3_RT_HANDSHAKE) + OPENSSL_assert(s->init_num == + (int)s->d1->w_msg_hdr.msg_len + + DTLS1_HM_HEADER_LENGTH); + + if (s->write_hash) { + if (s->enc_write_ctx + && EVP_CIPHER_CTX_mode(s->enc_write_ctx) == EVP_CIPH_GCM_MODE) + mac_size = 0; + else + mac_size = EVP_MD_CTX_size(s->write_hash); + } else + mac_size = 0; + + if (s->enc_write_ctx && + (EVP_CIPHER_CTX_mode(s->enc_write_ctx) == EVP_CIPH_CBC_MODE)) + blocksize = 2 * EVP_CIPHER_block_size(s->enc_write_ctx->cipher); + else + blocksize = 0; + + frag_off = 0; + s->rwstate = SSL_NOTHING; + + /* s->init_num shouldn't ever be < 0...but just in case */ + while (s->init_num > 0) { + if (type == SSL3_RT_HANDSHAKE && s->init_off != 0) { + /* We must be writing a fragment other than the first one */ + + if (frag_off > 0) { + /* This is the first attempt at writing out this fragment */ + + if (s->init_off <= DTLS1_HM_HEADER_LENGTH) { + /* + * Each fragment that was already sent must at least have + * contained the message header plus one other byte. + * Therefore |init_off| must have progressed by at least + * |DTLS1_HM_HEADER_LENGTH + 1| bytes. If not something went + * wrong. + */ + return -1; + } + + /* + * Adjust |init_off| and |init_num| to allow room for a new + * message header for this fragment. + */ + s->init_off -= DTLS1_HM_HEADER_LENGTH; + s->init_num += DTLS1_HM_HEADER_LENGTH; + } else { + /* + * We must have been called again after a retry so use the + * fragment offset from our last attempt. We do not need + * to adjust |init_off| and |init_num| as above, because + * that should already have been done before the retry. + */ + frag_off = s->d1->w_msg_hdr.frag_off; + } + } + + used_len = BIO_wpending(SSL_get_wbio(s)) + DTLS1_RT_HEADER_LENGTH + + mac_size + blocksize; + if (s->d1->mtu > used_len) + curr_mtu = s->d1->mtu - used_len; + else + curr_mtu = 0; + + if (curr_mtu <= DTLS1_HM_HEADER_LENGTH) { + /* + * grr.. we could get an error if MTU picked was wrong + */ + ret = BIO_flush(SSL_get_wbio(s)); + if (ret <= 0) { + s->rwstate = SSL_WRITING; + return ret; + } + used_len = DTLS1_RT_HEADER_LENGTH + mac_size + blocksize; + if (s->d1->mtu > used_len + DTLS1_HM_HEADER_LENGTH) { + curr_mtu = s->d1->mtu - used_len; + } else { + /* Shouldn't happen */ + return -1; + } + } + + /* + * We just checked that s->init_num > 0 so this cast should be safe + */ + if (((unsigned int)s->init_num) > curr_mtu) + len = curr_mtu; + else + len = s->init_num; + + /* Shouldn't ever happen */ + if (len > INT_MAX) + len = INT_MAX; + + /* + * XDTLS: this function is too long. split out the CCS part + */ + if (type == SSL3_RT_HANDSHAKE) { + if (len < DTLS1_HM_HEADER_LENGTH) { + /* + * len is so small that we really can't do anything sensible + * so fail + */ + return -1; + } + dtls1_fix_message_header(s, frag_off, + len - DTLS1_HM_HEADER_LENGTH); + + dtls1_write_message_header(s, + (unsigned char *)&s->init_buf-> + data[s->init_off]); + } + + ret = dtls1_write_bytes(s, type, &s->init_buf->data[s->init_off], + len); + if (ret < 0) { + /* + * might need to update MTU here, but we don't know which + * previous packet caused the failure -- so can't really + * retransmit anything. continue as if everything is fine and + * wait for an alert to handle the retransmit + */ + if (retry && BIO_ctrl(SSL_get_wbio(s), + BIO_CTRL_DGRAM_MTU_EXCEEDED, 0, NULL) > 0) { + if (!(SSL_get_options(s) & SSL_OP_NO_QUERY_MTU)) { + if (!dtls1_query_mtu(s)) + return -1; + /* Have one more go */ + retry = 0; + } else + return -1; + } else { + return (-1); + } + } else { + + /* + * bad if this assert fails, only part of the handshake message + * got sent. but why would this happen? + */ + OPENSSL_assert(len == (unsigned int)ret); + + if (type == SSL3_RT_HANDSHAKE && !s->d1->retransmitting) { + /* + * should not be done for 'Hello Request's, but in that case + * we'll ignore the result anyway + */ + unsigned char *p = + (unsigned char *)&s->init_buf->data[s->init_off]; + const struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr; + int xlen; + + if (frag_off == 0 && s->version != DTLS1_BAD_VER) { + /* + * reconstruct message header is if it is being sent in + * single fragment + */ + *p++ = msg_hdr->type; + l2n3(msg_hdr->msg_len, p); + s2n(msg_hdr->seq, p); + l2n3(0, p); + l2n3(msg_hdr->msg_len, p); + p -= DTLS1_HM_HEADER_LENGTH; + xlen = ret; + } else { + p += DTLS1_HM_HEADER_LENGTH; + xlen = ret - DTLS1_HM_HEADER_LENGTH; + } + + ssl3_finish_mac(s, p, xlen); + } + + if (ret == s->init_num) { + if (s->msg_callback) + s->msg_callback(1, s->version, type, s->init_buf->data, + (size_t)(s->init_off + s->init_num), s, + s->msg_callback_arg); + + s->init_off = 0; /* done writing this message */ + s->init_num = 0; + + return (1); + } + s->init_off += ret; + s->init_num -= ret; + ret -= DTLS1_HM_HEADER_LENGTH; + frag_off += ret; + + /* + * We save the fragment offset for the next fragment so we have it + * available in case of an IO retry. We don't know the length of the + * next fragment yet so just set that to 0 for now. It will be + * updated again later. + */ + dtls1_fix_message_header(s, frag_off, 0); + } + } + return (0); +} + +/* + * Obtain handshake message of message type 'mt' (any if mt == -1), maximum + * acceptable body length 'max'. Read an entire handshake message. Handshake + * messages arrive in fragments. + */ +long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok) +{ + int i, al; + struct hm_header_st *msg_hdr; + unsigned char *p; + unsigned long msg_len; + + /* + * s3->tmp is used to store messages that are unexpected, caused by the + * absence of an optional handshake message + */ + if (s->s3->tmp.reuse_message) { + s->s3->tmp.reuse_message = 0; + if ((mt >= 0) && (s->s3->tmp.message_type != mt)) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_DTLS1_GET_MESSAGE, SSL_R_UNEXPECTED_MESSAGE); + goto f_err; + } + *ok = 1; + s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH; + s->init_num = (int)s->s3->tmp.message_size; + return s->init_num; + } + + msg_hdr = &s->d1->r_msg_hdr; + memset(msg_hdr, 0x00, sizeof(struct hm_header_st)); + + again: + i = dtls1_get_message_fragment(s, st1, stn, max, ok); + if (i == DTLS1_HM_BAD_FRAGMENT || i == DTLS1_HM_FRAGMENT_RETRY) { + /* bad fragment received */ + goto again; + } else if (i <= 0 && !*ok) { + return i; + } + + if (mt >= 0 && s->s3->tmp.message_type != mt) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_DTLS1_GET_MESSAGE, SSL_R_UNEXPECTED_MESSAGE); + goto f_err; + } + + p = (unsigned char *)s->init_buf->data; + msg_len = msg_hdr->msg_len; + + /* reconstruct message header */ + *(p++) = msg_hdr->type; + l2n3(msg_len, p); + s2n(msg_hdr->seq, p); + l2n3(0, p); + l2n3(msg_len, p); + if (s->version != DTLS1_BAD_VER) { + p -= DTLS1_HM_HEADER_LENGTH; + msg_len += DTLS1_HM_HEADER_LENGTH; + } + + ssl3_finish_mac(s, p, msg_len); + if (s->msg_callback) + s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, + p, msg_len, s, s->msg_callback_arg); + + memset(msg_hdr, 0x00, sizeof(struct hm_header_st)); + + /* Don't change sequence numbers while listening */ + if (!s->d1->listen) + s->d1->handshake_read_seq++; + + s->init_msg = s->init_buf->data + DTLS1_HM_HEADER_LENGTH; + return s->init_num; + + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + *ok = 0; + return -1; +} + +static int dtls1_preprocess_fragment(SSL *s, struct hm_header_st *msg_hdr, + int max) +{ + size_t frag_off, frag_len, msg_len; + + msg_len = msg_hdr->msg_len; + frag_off = msg_hdr->frag_off; + frag_len = msg_hdr->frag_len; + + /* sanity checking */ + if ((frag_off + frag_len) > msg_len) { + SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT, SSL_R_EXCESSIVE_MESSAGE_SIZE); + return SSL_AD_ILLEGAL_PARAMETER; + } + + if ((frag_off + frag_len) > (unsigned long)max) { + SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT, SSL_R_EXCESSIVE_MESSAGE_SIZE); + return SSL_AD_ILLEGAL_PARAMETER; + } + + if (s->d1->r_msg_hdr.frag_off == 0) { /* first fragment */ + /* + * msg_len is limited to 2^24, but is effectively checked against max + * above + */ + if (!BUF_MEM_grow_clean + (s->init_buf, msg_len + DTLS1_HM_HEADER_LENGTH)) { + SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT, ERR_R_BUF_LIB); + return SSL_AD_INTERNAL_ERROR; + } + + s->s3->tmp.message_size = msg_len; + s->d1->r_msg_hdr.msg_len = msg_len; + s->s3->tmp.message_type = msg_hdr->type; + s->d1->r_msg_hdr.type = msg_hdr->type; + s->d1->r_msg_hdr.seq = msg_hdr->seq; + } else if (msg_len != s->d1->r_msg_hdr.msg_len) { + /* + * They must be playing with us! BTW, failure to enforce upper limit + * would open possibility for buffer overrun. + */ + SSLerr(SSL_F_DTLS1_PREPROCESS_FRAGMENT, SSL_R_EXCESSIVE_MESSAGE_SIZE); + return SSL_AD_ILLEGAL_PARAMETER; + } + + return 0; /* no error */ +} + +static int dtls1_retrieve_buffered_fragment(SSL *s, long max, int *ok) +{ + /*- + * (0) check whether the desired fragment is available + * if so: + * (1) copy over the fragment to s->init_buf->data[] + * (2) update s->init_num + */ + pitem *item; + hm_fragment *frag; + int al; + + *ok = 0; + item = pqueue_peek(s->d1->buffered_messages); + if (item == NULL) + return 0; + + frag = (hm_fragment *)item->data; + + /* Don't return if reassembly still in progress */ + if (frag->reassembly != NULL) + return 0; + + if (s->d1->handshake_read_seq == frag->msg_header.seq) { + unsigned long frag_len = frag->msg_header.frag_len; + pqueue_pop(s->d1->buffered_messages); + + al = dtls1_preprocess_fragment(s, &frag->msg_header, max); + + if (al == 0) { /* no alert */ + unsigned char *p = + (unsigned char *)s->init_buf->data + DTLS1_HM_HEADER_LENGTH; + memcpy(&p[frag->msg_header.frag_off], frag->fragment, + frag->msg_header.frag_len); + } + + dtls1_hm_fragment_free(frag); + pitem_free(item); + + if (al == 0) { + *ok = 1; + return frag_len; + } + + ssl3_send_alert(s, SSL3_AL_FATAL, al); + s->init_num = 0; + *ok = 0; + return -1; + } else + return 0; +} + +/* + * dtls1_max_handshake_message_len returns the maximum number of bytes + * permitted in a DTLS handshake message for |s|. The minimum is 16KB, but + * may be greater if the maximum certificate list size requires it. + */ +static unsigned long dtls1_max_handshake_message_len(const SSL *s) +{ + unsigned long max_len = + DTLS1_HM_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH; + if (max_len < (unsigned long)s->max_cert_list) + return s->max_cert_list; + return max_len; +} + +static int +dtls1_reassemble_fragment(SSL *s, const struct hm_header_st *msg_hdr, int *ok) +{ + hm_fragment *frag = NULL; + pitem *item = NULL; + int i = -1, is_complete; + unsigned char seq64be[8]; + unsigned long frag_len = msg_hdr->frag_len; + + if ((msg_hdr->frag_off + frag_len) > msg_hdr->msg_len || + msg_hdr->msg_len > dtls1_max_handshake_message_len(s)) + goto err; + + if (frag_len == 0) + return DTLS1_HM_FRAGMENT_RETRY; + + /* Try to find item in queue */ + memset(seq64be, 0, sizeof(seq64be)); + seq64be[6] = (unsigned char)(msg_hdr->seq >> 8); + seq64be[7] = (unsigned char)msg_hdr->seq; + item = pqueue_find(s->d1->buffered_messages, seq64be); + + if (item == NULL) { + frag = dtls1_hm_fragment_new(msg_hdr->msg_len, 1); + if (frag == NULL) + goto err; + memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr)); + frag->msg_header.frag_len = frag->msg_header.msg_len; + frag->msg_header.frag_off = 0; + } else { + frag = (hm_fragment *)item->data; + if (frag->msg_header.msg_len != msg_hdr->msg_len) { + item = NULL; + frag = NULL; + goto err; + } + } + + /* + * If message is already reassembled, this must be a retransmit and can + * be dropped. In this case item != NULL and so frag does not need to be + * freed. + */ + if (frag->reassembly == NULL) { + unsigned char devnull[256]; + + while (frag_len) { + i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, + devnull, + frag_len > + sizeof(devnull) ? sizeof(devnull) : + frag_len, 0); + if (i <= 0) + goto err; + frag_len -= i; + } + return DTLS1_HM_FRAGMENT_RETRY; + } + + /* read the body of the fragment (header has already been read */ + i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, + frag->fragment + msg_hdr->frag_off, + frag_len, 0); + if ((unsigned long)i != frag_len) + i = -1; + if (i <= 0) + goto err; + + RSMBLY_BITMASK_MARK(frag->reassembly, (long)msg_hdr->frag_off, + (long)(msg_hdr->frag_off + frag_len)); + + RSMBLY_BITMASK_IS_COMPLETE(frag->reassembly, (long)msg_hdr->msg_len, + is_complete); + + if (is_complete) { + OPENSSL_free(frag->reassembly); + frag->reassembly = NULL; + } + + if (item == NULL) { + item = pitem_new(seq64be, frag); + if (item == NULL) { + i = -1; + goto err; + } + + item = pqueue_insert(s->d1->buffered_messages, item); + /* + * pqueue_insert fails iff a duplicate item is inserted. However, + * |item| cannot be a duplicate. If it were, |pqueue_find|, above, + * would have returned it and control would never have reached this + * branch. + */ + OPENSSL_assert(item != NULL); + } + + return DTLS1_HM_FRAGMENT_RETRY; + + err: + if (frag != NULL && item == NULL) + dtls1_hm_fragment_free(frag); + *ok = 0; + return i; +} + +static int +dtls1_process_out_of_seq_message(SSL *s, const struct hm_header_st *msg_hdr, + int *ok) +{ + int i = -1; + hm_fragment *frag = NULL; + pitem *item = NULL; + unsigned char seq64be[8]; + unsigned long frag_len = msg_hdr->frag_len; + + if ((msg_hdr->frag_off + frag_len) > msg_hdr->msg_len) + goto err; + + /* Try to find item in queue, to prevent duplicate entries */ + memset(seq64be, 0, sizeof(seq64be)); + seq64be[6] = (unsigned char)(msg_hdr->seq >> 8); + seq64be[7] = (unsigned char)msg_hdr->seq; + item = pqueue_find(s->d1->buffered_messages, seq64be); + + /* + * If we already have an entry and this one is a fragment, don't discard + * it and rather try to reassemble it. + */ + if (item != NULL && frag_len != msg_hdr->msg_len) + item = NULL; + + /* + * Discard the message if sequence number was already there, is too far + * in the future, already in the queue or if we received a FINISHED + * before the SERVER_HELLO, which then must be a stale retransmit. + */ + if (msg_hdr->seq <= s->d1->handshake_read_seq || + msg_hdr->seq > s->d1->handshake_read_seq + 10 || item != NULL || + (s->d1->handshake_read_seq == 0 && msg_hdr->type == SSL3_MT_FINISHED)) + { + unsigned char devnull[256]; + + while (frag_len) { + i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, + devnull, + frag_len > + sizeof(devnull) ? sizeof(devnull) : + frag_len, 0); + if (i <= 0) + goto err; + frag_len -= i; + } + } else { + if (frag_len != msg_hdr->msg_len) + return dtls1_reassemble_fragment(s, msg_hdr, ok); + + if (frag_len > dtls1_max_handshake_message_len(s)) + goto err; + + frag = dtls1_hm_fragment_new(frag_len, 0); + if (frag == NULL) + goto err; + + memcpy(&(frag->msg_header), msg_hdr, sizeof(*msg_hdr)); + + if (frag_len) { + /* + * read the body of the fragment (header has already been read + */ + i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, + frag->fragment, frag_len, 0); + if ((unsigned long)i != frag_len) + i = -1; + if (i <= 0) + goto err; + } + + item = pitem_new(seq64be, frag); + if (item == NULL) + goto err; + + item = pqueue_insert(s->d1->buffered_messages, item); + /* + * pqueue_insert fails iff a duplicate item is inserted. However, + * |item| cannot be a duplicate. If it were, |pqueue_find|, above, + * would have returned it. Then, either |frag_len| != + * |msg_hdr->msg_len| in which case |item| is set to NULL and it will + * have been processed with |dtls1_reassemble_fragment|, above, or + * the record will have been discarded. + */ + OPENSSL_assert(item != NULL); + } + + return DTLS1_HM_FRAGMENT_RETRY; + + err: + if (frag != NULL && item == NULL) + dtls1_hm_fragment_free(frag); + *ok = 0; + return i; +} + +static long +dtls1_get_message_fragment(SSL *s, int st1, int stn, long max, int *ok) +{ + unsigned char wire[DTLS1_HM_HEADER_LENGTH]; + unsigned long len, frag_off, frag_len; + int i, al; + struct hm_header_st msg_hdr; + + redo: + /* see if we have the required fragment already */ + if ((frag_len = dtls1_retrieve_buffered_fragment(s, max, ok)) || *ok) { + if (*ok) + s->init_num = frag_len; + return frag_len; + } + + /* read handshake message header */ + i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, wire, + DTLS1_HM_HEADER_LENGTH, 0); + if (i <= 0) { /* nbio, or an error */ + s->rwstate = SSL_READING; + *ok = 0; + return i; + } + /* Handshake fails if message header is incomplete */ + if (i != DTLS1_HM_HEADER_LENGTH) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT, SSL_R_UNEXPECTED_MESSAGE); + goto f_err; + } + + /* parse the message fragment header */ + dtls1_get_message_header(wire, &msg_hdr); + + len = msg_hdr.msg_len; + frag_off = msg_hdr.frag_off; + frag_len = msg_hdr.frag_len; + + /* + * We must have at least frag_len bytes left in the record to be read. + * Fragments must not span records. + */ + if (frag_len > s->s3->rrec.length) { + al = SSL3_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT, SSL_R_BAD_LENGTH); + goto f_err; + } + + /* + * if this is a future (or stale) message it gets buffered + * (or dropped)--no further processing at this time + * While listening, we accept seq 1 (ClientHello with cookie) + * although we're still expecting seq 0 (ClientHello) + */ + if (msg_hdr.seq != s->d1->handshake_read_seq + && !(s->d1->listen && msg_hdr.seq == 1)) + return dtls1_process_out_of_seq_message(s, &msg_hdr, ok); + + if (frag_len && frag_len < len) + return dtls1_reassemble_fragment(s, &msg_hdr, ok); + + if (!s->server && s->d1->r_msg_hdr.frag_off == 0 && + wire[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 (wire[1] == 0 && wire[2] == 0 && wire[3] == 0) { + if (s->msg_callback) + s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, + wire, DTLS1_HM_HEADER_LENGTH, s, + s->msg_callback_arg); + + s->init_num = 0; + goto redo; + } else { /* Incorrectly formated Hello request */ + + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT, + SSL_R_UNEXPECTED_MESSAGE); + goto f_err; + } + } + + if ((al = dtls1_preprocess_fragment(s, &msg_hdr, max))) + goto f_err; + + if (frag_len > 0) { + unsigned char *p = + (unsigned char *)s->init_buf->data + DTLS1_HM_HEADER_LENGTH; + + i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, + &p[frag_off], frag_len, 0); + + /* + * This shouldn't ever fail due to NBIO because we already checked + * that we have enough data in the record + */ + if (i <= 0) { + s->rwstate = SSL_READING; + *ok = 0; + return i; + } + } else + i = 0; + + /* + * XDTLS: an incorrectly formatted fragment should cause the handshake + * to fail + */ + if (i != (int)frag_len) { + al = SSL3_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT, SSL3_AD_ILLEGAL_PARAMETER); + goto f_err; + } + + *ok = 1; + s->state = stn; + + /* + * Note that s->init_num is *not* used as current offset in + * s->init_buf->data, but as a counter summing up fragments' lengths: as + * soon as they sum up to handshake packet length, we assume we have got + * all the fragments. + */ + s->init_num = frag_len; + return frag_len; + + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + s->init_num = 0; + + *ok = 0; + return (-1); +} + +/*- + * for these 2 messages, we need to + * ssl->enc_read_ctx re-init + * ssl->s3->read_sequence zero + * ssl->s3->read_mac_secret re-init + * ssl->session->read_sym_enc assign + * ssl->session->read_compression assign + * ssl->session->read_hash assign + */ +int dtls1_send_change_cipher_spec(SSL *s, int a, int b) +{ + unsigned char *p; + + if (s->state == a) { + p = (unsigned char *)s->init_buf->data; + *p++ = SSL3_MT_CCS; + s->d1->handshake_write_seq = s->d1->next_handshake_write_seq; + s->init_num = DTLS1_CCS_HEADER_LENGTH; + + if (s->version == DTLS1_BAD_VER) { + s->d1->next_handshake_write_seq++; + s2n(s->d1->handshake_write_seq, p); + s->init_num += 2; + } + + s->init_off = 0; + + dtls1_set_message_header_int(s, SSL3_MT_CCS, 0, + s->d1->handshake_write_seq, 0, 0); + + /* buffer the message to handle re-xmits */ + dtls1_buffer_message(s, 1); + + s->state = b; + } + + /* SSL3_ST_CW_CHANGE_B */ + return (dtls1_do_write(s, SSL3_RT_CHANGE_CIPHER_SPEC)); +} + +int dtls1_read_failed(SSL *s, int code) +{ + if (code > 0) { + fprintf(stderr, "invalid state reached %s:%d", __FILE__, __LINE__); + return 1; + } + + if (!dtls1_is_timer_expired(s)) { + /* + * not a timeout, none of our business, let higher layers handle + * this. in fact it's probably an error + */ + return code; + } +#ifndef OPENSSL_NO_HEARTBEATS + /* done, no need to send a retransmit */ + if (!SSL_in_init(s) && !s->tlsext_hb_pending) +#else + /* done, no need to send a retransmit */ + if (!SSL_in_init(s)) +#endif + { + BIO_set_flags(SSL_get_rbio(s), BIO_FLAGS_READ); + return code; + } +#if 0 /* for now, each alert contains only one + * record number */ + item = pqueue_peek(state->rcvd_records); + if (item) { + /* send an alert immediately for all the missing records */ + } else +#endif + +#if 0 /* no more alert sending, just retransmit the + * last set of messages */ + if (state->timeout.read_timeouts >= DTLS1_TMO_READ_COUNT) + ssl3_send_alert(s, SSL3_AL_WARNING, + DTLS1_AD_MISSING_HANDSHAKE_MESSAGE); +#endif + + return dtls1_handle_timeout(s); +} + +int dtls1_get_queue_priority(unsigned short seq, int is_ccs) +{ + /* + * The index of the retransmission queue actually is the message sequence + * number, since the queue only contains messages of a single handshake. + * However, the ChangeCipherSpec has no message sequence number and so + * using only the sequence will result in the CCS and Finished having the + * same index. To prevent this, the sequence number is multiplied by 2. + * In case of a CCS 1 is subtracted. This does not only differ CSS and + * Finished, it also maintains the order of the index (important for + * priority queues) and fits in the unsigned short variable. + */ + return seq * 2 - is_ccs; +} + +int dtls1_retransmit_buffered_messages(SSL *s) +{ + pqueue sent = s->d1->sent_messages; + piterator iter; + pitem *item; + hm_fragment *frag; + int found = 0; + + iter = pqueue_iterator(sent); + + for (item = pqueue_next(&iter); item != NULL; item = pqueue_next(&iter)) { + frag = (hm_fragment *)item->data; + if (dtls1_retransmit_message(s, (unsigned short) + dtls1_get_queue_priority + (frag->msg_header.seq, + frag->msg_header.is_ccs), 0, + &found) <= 0 && found) { + fprintf(stderr, "dtls1_retransmit_message() failed\n"); + return -1; + } + } + + return 1; +} + +int dtls1_buffer_message(SSL *s, int is_ccs) +{ + pitem *item; + hm_fragment *frag; + unsigned char seq64be[8]; + + /* + * this function is called immediately after a message has been + * serialized + */ + OPENSSL_assert(s->init_off == 0); + + frag = dtls1_hm_fragment_new(s->init_num, 0); + if (!frag) + return 0; + + memcpy(frag->fragment, s->init_buf->data, s->init_num); + + if (is_ccs) { + /* For DTLS1_BAD_VER the header length is non-standard */ + OPENSSL_assert(s->d1->w_msg_hdr.msg_len + + ((s->version==DTLS1_BAD_VER)?3:DTLS1_CCS_HEADER_LENGTH) + == (unsigned int)s->init_num); + } else { + OPENSSL_assert(s->d1->w_msg_hdr.msg_len + + DTLS1_HM_HEADER_LENGTH == (unsigned int)s->init_num); + } + + frag->msg_header.msg_len = s->d1->w_msg_hdr.msg_len; + frag->msg_header.seq = s->d1->w_msg_hdr.seq; + frag->msg_header.type = s->d1->w_msg_hdr.type; + frag->msg_header.frag_off = 0; + frag->msg_header.frag_len = s->d1->w_msg_hdr.msg_len; + frag->msg_header.is_ccs = is_ccs; + + /* save current state */ + frag->msg_header.saved_retransmit_state.enc_write_ctx = s->enc_write_ctx; + frag->msg_header.saved_retransmit_state.write_hash = s->write_hash; + frag->msg_header.saved_retransmit_state.compress = s->compress; + frag->msg_header.saved_retransmit_state.session = s->session; + frag->msg_header.saved_retransmit_state.epoch = s->d1->w_epoch; + + memset(seq64be, 0, sizeof(seq64be)); + seq64be[6] = + (unsigned + char)(dtls1_get_queue_priority(frag->msg_header.seq, + frag->msg_header.is_ccs) >> 8); + seq64be[7] = + (unsigned + char)(dtls1_get_queue_priority(frag->msg_header.seq, + frag->msg_header.is_ccs)); + + item = pitem_new(seq64be, frag); + if (item == NULL) { + dtls1_hm_fragment_free(frag); + return 0; + } +#if 0 + fprintf(stderr, "buffered messge: \ttype = %xx\n", msg_buf->type); + fprintf(stderr, "\t\t\t\t\tlen = %d\n", msg_buf->len); + fprintf(stderr, "\t\t\t\t\tseq_num = %d\n", msg_buf->seq_num); +#endif + + pqueue_insert(s->d1->sent_messages, item); + return 1; +} + +int +dtls1_retransmit_message(SSL *s, unsigned short seq, unsigned long frag_off, + int *found) +{ + int ret; + /* XDTLS: for now assuming that read/writes are blocking */ + pitem *item; + hm_fragment *frag; + unsigned long header_length; + unsigned char seq64be[8]; + struct dtls1_retransmit_state saved_state; + unsigned char save_write_sequence[8]; + + /*- + OPENSSL_assert(s->init_num == 0); + OPENSSL_assert(s->init_off == 0); + */ + + /* XDTLS: the requested message ought to be found, otherwise error */ + memset(seq64be, 0, sizeof(seq64be)); + seq64be[6] = (unsigned char)(seq >> 8); + seq64be[7] = (unsigned char)seq; + + item = pqueue_find(s->d1->sent_messages, seq64be); + if (item == NULL) { + fprintf(stderr, "retransmit: message %d non-existant\n", seq); + *found = 0; + return 0; + } + + *found = 1; + frag = (hm_fragment *)item->data; + + if (frag->msg_header.is_ccs) + header_length = DTLS1_CCS_HEADER_LENGTH; + else + header_length = DTLS1_HM_HEADER_LENGTH; + + memcpy(s->init_buf->data, frag->fragment, + frag->msg_header.msg_len + header_length); + s->init_num = frag->msg_header.msg_len + header_length; + + dtls1_set_message_header_int(s, frag->msg_header.type, + frag->msg_header.msg_len, + frag->msg_header.seq, 0, + frag->msg_header.frag_len); + + /* save current state */ + saved_state.enc_write_ctx = s->enc_write_ctx; + saved_state.write_hash = s->write_hash; + saved_state.compress = s->compress; + saved_state.session = s->session; + saved_state.epoch = s->d1->w_epoch; + saved_state.epoch = s->d1->w_epoch; + + s->d1->retransmitting = 1; + + /* restore state in which the message was originally sent */ + s->enc_write_ctx = frag->msg_header.saved_retransmit_state.enc_write_ctx; + s->write_hash = frag->msg_header.saved_retransmit_state.write_hash; + s->compress = frag->msg_header.saved_retransmit_state.compress; + s->session = frag->msg_header.saved_retransmit_state.session; + s->d1->w_epoch = frag->msg_header.saved_retransmit_state.epoch; + + if (frag->msg_header.saved_retransmit_state.epoch == + saved_state.epoch - 1) { + memcpy(save_write_sequence, s->s3->write_sequence, + sizeof(s->s3->write_sequence)); + memcpy(s->s3->write_sequence, s->d1->last_write_sequence, + sizeof(s->s3->write_sequence)); + } + + ret = dtls1_do_write(s, frag->msg_header.is_ccs ? + SSL3_RT_CHANGE_CIPHER_SPEC : SSL3_RT_HANDSHAKE); + + /* restore current state */ + s->enc_write_ctx = saved_state.enc_write_ctx; + s->write_hash = saved_state.write_hash; + s->compress = saved_state.compress; + s->session = saved_state.session; + s->d1->w_epoch = saved_state.epoch; + + if (frag->msg_header.saved_retransmit_state.epoch == + saved_state.epoch - 1) { + memcpy(s->d1->last_write_sequence, s->s3->write_sequence, + sizeof(s->s3->write_sequence)); + memcpy(s->s3->write_sequence, save_write_sequence, + sizeof(s->s3->write_sequence)); + } + + s->d1->retransmitting = 0; + + (void)BIO_flush(SSL_get_wbio(s)); + return ret; +} + +/* call this function when the buffered messages are no longer needed */ +void dtls1_clear_record_buffer(SSL *s) +{ + pitem *item; + + for (item = pqueue_pop(s->d1->sent_messages); + item != NULL; item = pqueue_pop(s->d1->sent_messages)) { + dtls1_hm_fragment_free((hm_fragment *)item->data); + pitem_free(item); + } +} + +unsigned char *dtls1_set_message_header(SSL *s, unsigned char *p, + unsigned char mt, unsigned long len, + unsigned long frag_off, + unsigned long frag_len) +{ + /* Don't change sequence numbers while listening */ + if (frag_off == 0 && !s->d1->listen) { + s->d1->handshake_write_seq = s->d1->next_handshake_write_seq; + s->d1->next_handshake_write_seq++; + } + + dtls1_set_message_header_int(s, mt, len, s->d1->handshake_write_seq, + frag_off, frag_len); + + return p += DTLS1_HM_HEADER_LENGTH; +} + +/* don't actually do the writing, wait till the MTU has been retrieved */ +static void +dtls1_set_message_header_int(SSL *s, unsigned char mt, + unsigned long len, unsigned short seq_num, + unsigned long frag_off, unsigned long frag_len) +{ + struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr; + + msg_hdr->type = mt; + msg_hdr->msg_len = len; + msg_hdr->seq = seq_num; + msg_hdr->frag_off = frag_off; + msg_hdr->frag_len = frag_len; +} + +static void +dtls1_fix_message_header(SSL *s, unsigned long frag_off, + unsigned long frag_len) +{ + struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr; + + msg_hdr->frag_off = frag_off; + msg_hdr->frag_len = frag_len; +} + +static unsigned char *dtls1_write_message_header(SSL *s, unsigned char *p) +{ + struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr; + + *p++ = msg_hdr->type; + l2n3(msg_hdr->msg_len, p); + + s2n(msg_hdr->seq, p); + l2n3(msg_hdr->frag_off, p); + l2n3(msg_hdr->frag_len, p); + + return p; +} + +unsigned int dtls1_link_min_mtu(void) +{ + return (g_probable_mtu[(sizeof(g_probable_mtu) / + sizeof(g_probable_mtu[0])) - 1]); +} + +unsigned int dtls1_min_mtu(SSL *s) +{ + return dtls1_link_min_mtu() - BIO_dgram_get_mtu_overhead(SSL_get_wbio(s)); +} + +void +dtls1_get_message_header(unsigned char *data, struct hm_header_st *msg_hdr) +{ + memset(msg_hdr, 0x00, sizeof(struct hm_header_st)); + msg_hdr->type = *(data++); + n2l3(data, msg_hdr->msg_len); + + n2s(data, msg_hdr->seq); + n2l3(data, msg_hdr->frag_off); + n2l3(data, msg_hdr->frag_len); +} + +void dtls1_get_ccs_header(unsigned char *data, struct ccs_header_st *ccs_hdr) +{ + memset(ccs_hdr, 0x00, sizeof(struct ccs_header_st)); + + ccs_hdr->type = *(data++); +} + +int dtls1_shutdown(SSL *s) +{ + int ret; +#ifndef OPENSSL_NO_SCTP + BIO *wbio; + + wbio = SSL_get_wbio(s); + if (wbio != NULL && BIO_dgram_is_sctp(wbio) && + !(s->shutdown & SSL_SENT_SHUTDOWN)) { + ret = BIO_dgram_sctp_wait_for_dry(wbio); + if (ret < 0) + return -1; + + if (ret == 0) + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN, 1, + NULL); + } +#endif + ret = ssl3_shutdown(s); +#ifndef OPENSSL_NO_SCTP + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN, 0, NULL); +#endif + return ret; +} + +#ifndef OPENSSL_NO_HEARTBEATS +int dtls1_process_heartbeat(SSL *s) +{ + unsigned char *p = &s->s3->rrec.data[0], *pl; + unsigned short hbtype; + unsigned int payload; + unsigned int padding = 16; /* Use minimum padding */ + + if (s->msg_callback) + s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT, + &s->s3->rrec.data[0], s->s3->rrec.length, + s, s->msg_callback_arg); + + /* Read type and payload length first */ + if (1 + 2 + 16 > s->s3->rrec.length) + return 0; /* silently discard */ + if (s->s3->rrec.length > SSL3_RT_MAX_PLAIN_LENGTH) + return 0; /* silently discard per RFC 6520 sec. 4 */ + + hbtype = *p++; + n2s(p, payload); + if (1 + 2 + payload + 16 > s->s3->rrec.length) + return 0; /* silently discard per RFC 6520 sec. 4 */ + pl = p; + + if (hbtype == TLS1_HB_REQUEST) { + unsigned char *buffer, *bp; + unsigned int write_length = 1 /* heartbeat type */ + + 2 /* heartbeat length */ + + payload + padding; + int r; + + if (write_length > SSL3_RT_MAX_PLAIN_LENGTH) + return 0; + + /* + * Allocate memory for the response, size is 1 byte message type, + * plus 2 bytes payload length, plus payload, plus padding + */ + buffer = OPENSSL_malloc(write_length); + if (buffer == NULL) + return -1; + bp = buffer; + + /* Enter response type, length and copy payload */ + *bp++ = TLS1_HB_RESPONSE; + s2n(payload, bp); + memcpy(bp, pl, payload); + bp += payload; + /* Random padding */ + if (RAND_pseudo_bytes(bp, padding) < 0) { + OPENSSL_free(buffer); + return -1; + } + + r = dtls1_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, write_length); + + if (r >= 0 && s->msg_callback) + s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT, + buffer, write_length, s, s->msg_callback_arg); + + OPENSSL_free(buffer); + + if (r < 0) + return r; + } else if (hbtype == TLS1_HB_RESPONSE) { + unsigned int seq; + + /* + * We only send sequence numbers (2 bytes unsigned int), and 16 + * random bytes, so we just try to read the sequence number + */ + n2s(pl, seq); + + if (payload == 18 && seq == s->tlsext_hb_seq) { + dtls1_stop_timer(s); + s->tlsext_hb_seq++; + s->tlsext_hb_pending = 0; + } + } + + return 0; +} + +int dtls1_heartbeat(SSL *s) +{ + unsigned char *buf, *p; + int ret = -1; + unsigned int payload = 18; /* Sequence number + random bytes */ + unsigned int padding = 16; /* Use minimum padding */ + + /* Only send if peer supports and accepts HB requests... */ + if (!(s->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED) || + s->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_SEND_REQUESTS) { + SSLerr(SSL_F_DTLS1_HEARTBEAT, SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT); + return -1; + } + + /* ...and there is none in flight yet... */ + if (s->tlsext_hb_pending) { + SSLerr(SSL_F_DTLS1_HEARTBEAT, SSL_R_TLS_HEARTBEAT_PENDING); + return -1; + } + + /* ...and no handshake in progress. */ + if (SSL_in_init(s) || s->in_handshake) { + SSLerr(SSL_F_DTLS1_HEARTBEAT, SSL_R_UNEXPECTED_MESSAGE); + return -1; + } + + /* + * Check if padding is too long, payload and padding must not exceed 2^14 + * - 3 = 16381 bytes in total. + */ + OPENSSL_assert(payload + padding <= 16381); + + /*- + * Create HeartBeat message, we just use a sequence number + * as payload to distuingish different messages and add + * some random stuff. + * - Message Type, 1 byte + * - Payload Length, 2 bytes (unsigned int) + * - Payload, the sequence number (2 bytes uint) + * - Payload, random bytes (16 bytes uint) + * - Padding + */ + buf = OPENSSL_malloc(1 + 2 + payload + padding); + p = buf; + /* Message Type */ + *p++ = TLS1_HB_REQUEST; + /* Payload length (18 bytes here) */ + s2n(payload, p); + /* Sequence number */ + s2n(s->tlsext_hb_seq, p); + /* 16 random bytes */ + if (RAND_pseudo_bytes(p, 16) < 0) + goto err; + p += 16; + /* Random padding */ + if (RAND_pseudo_bytes(p, padding) < 0) + goto err; + + ret = dtls1_write_bytes(s, TLS1_RT_HEARTBEAT, buf, 3 + payload + padding); + if (ret >= 0) { + if (s->msg_callback) + s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT, + buf, 3 + payload + padding, + s, s->msg_callback_arg); + + dtls1_start_timer(s); + s->tlsext_hb_pending = 1; + } + +err: + OPENSSL_free(buf); + + return ret; +} +#endif diff --git a/thirdparty/openssl/ssl/d1_clnt.c b/thirdparty/openssl/ssl/d1_clnt.c new file mode 100644 index 0000000000..3ddfa7bca4 --- /dev/null +++ b/thirdparty/openssl/ssl/d1_clnt.c @@ -0,0 +1,869 @@ +/* ssl/d1_clnt.c */ +/* + * DTLS implementation written by Nagendra Modadugu + * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. + */ +/* ==================================================================== + * Copyright (c) 1999-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 (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.] + */ + +#include <stdio.h> +#include "ssl_locl.h" +#ifndef OPENSSL_NO_KRB5 +# include "kssl_lcl.h" +#endif +#include <openssl/buffer.h> +#include <openssl/rand.h> +#include <openssl/objects.h> +#include <openssl/evp.h> +#include <openssl/md5.h> +#include <openssl/bn.h> +#ifndef OPENSSL_NO_DH +# include <openssl/dh.h> +#endif + +static const SSL_METHOD *dtls1_get_client_method(int ver); +static int dtls1_get_hello_verify(SSL *s); + +static const SSL_METHOD *dtls1_get_client_method(int ver) +{ + if (ver == DTLS_ANY_VERSION) + return DTLS_client_method(); + else if (ver == DTLS1_VERSION || ver == DTLS1_BAD_VER) + return DTLSv1_client_method(); + else if (ver == DTLS1_2_VERSION) + return DTLSv1_2_client_method(); + else + return NULL; +} + +IMPLEMENT_dtls1_meth_func(DTLS1_VERSION, + DTLSv1_client_method, + ssl_undefined_function, + dtls1_connect, + dtls1_get_client_method, DTLSv1_enc_data) + +IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION, + DTLSv1_2_client_method, + ssl_undefined_function, + dtls1_connect, + dtls1_get_client_method, DTLSv1_2_enc_data) + +IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION, + DTLS_client_method, + ssl_undefined_function, + dtls1_connect, + dtls1_get_client_method, DTLSv1_2_enc_data) + +int dtls1_connect(SSL *s) +{ + BUF_MEM *buf = NULL; + unsigned long Time = (unsigned long)time(NULL); + void (*cb) (const SSL *ssl, int type, int val) = NULL; + int ret = -1; + int new_state, state, skip = 0; +#ifndef OPENSSL_NO_SCTP + unsigned char sctpauthkey[64]; + char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)]; +#endif + + RAND_add(&Time, sizeof(Time), 0); + ERR_clear_error(); + clear_sys_error(); + + if (s->info_callback != NULL) + cb = s->info_callback; + else if (s->ctx->info_callback != NULL) + cb = s->ctx->info_callback; + + s->in_handshake++; + if (!SSL_in_init(s) || SSL_in_before(s)) + SSL_clear(s); + +#ifndef OPENSSL_NO_SCTP + /* + * Notify SCTP BIO socket to enter handshake mode and prevent stream + * identifier other than 0. Will be ignored if no SCTP is used. + */ + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE, + s->in_handshake, NULL); +#endif + +#ifndef OPENSSL_NO_HEARTBEATS + /* + * If we're awaiting a HeartbeatResponse, pretend we already got and + * don't await it anymore, because Heartbeats don't make sense during + * handshakes anyway. + */ + if (s->tlsext_hb_pending) { + dtls1_stop_timer(s); + s->tlsext_hb_pending = 0; + s->tlsext_hb_seq++; + } +#endif + + for (;;) { + state = s->state; + + switch (s->state) { + case SSL_ST_RENEGOTIATE: + s->renegotiate = 1; + s->state = SSL_ST_CONNECT; + s->ctx->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) != (DTLS1_VERSION & 0xff00) && + (s->version & 0xff00) != (DTLS1_BAD_VER & 0xff00)) { + SSLerr(SSL_F_DTLS1_CONNECT, ERR_R_INTERNAL_ERROR); + ret = -1; + s->state = SSL_ST_ERR; + goto end; + } + + /* s->version=SSL3_VERSION; */ + s->type = SSL_ST_CONNECT; + + if (s->init_buf == NULL) { + if ((buf = BUF_MEM_new()) == NULL) { + ret = -1; + s->state = SSL_ST_ERR; + goto end; + } + if (!BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) { + ret = -1; + s->state = SSL_ST_ERR; + goto end; + } + s->init_buf = buf; + buf = NULL; + } + + if (!ssl3_setup_buffers(s)) { + ret = -1; + s->state = SSL_ST_ERR; + goto end; + } + + /* setup buffing BIO */ + if (!ssl_init_wbio_buffer(s, 0)) { + ret = -1; + s->state = SSL_ST_ERR; + goto end; + } + + /* don't push the buffering BIO quite yet */ + + s->state = SSL3_ST_CW_CLNT_HELLO_A; + s->ctx->stats.sess_connect++; + s->init_num = 0; + /* mark client_random uninitialized */ + memset(s->s3->client_random, 0, sizeof(s->s3->client_random)); + s->d1->send_cookie = 0; + s->hit = 0; + s->d1->change_cipher_spec_ok = 0; + /* + * Should have been reset by ssl3_get_finished, too. + */ + s->s3->change_cipher_spec = 0; + break; + +#ifndef OPENSSL_NO_SCTP + case DTLS1_SCTP_ST_CR_READ_SOCK: + + if (BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s))) { + s->s3->in_read_app_data = 2; + s->rwstate = SSL_READING; + BIO_clear_retry_flags(SSL_get_rbio(s)); + BIO_set_retry_read(SSL_get_rbio(s)); + ret = -1; + goto end; + } + + s->state = s->s3->tmp.next_state; + break; + + case DTLS1_SCTP_ST_CW_WRITE_SOCK: + /* read app data until dry event */ + + ret = BIO_dgram_sctp_wait_for_dry(SSL_get_wbio(s)); + if (ret < 0) + goto end; + + if (ret == 0) { + s->s3->in_read_app_data = 2; + s->rwstate = SSL_READING; + BIO_clear_retry_flags(SSL_get_rbio(s)); + BIO_set_retry_read(SSL_get_rbio(s)); + ret = -1; + goto end; + } + + s->state = s->d1->next_state; + break; +#endif + + case SSL3_ST_CW_CLNT_HELLO_A: + s->shutdown = 0; + + /* every DTLS ClientHello resets Finished MAC */ + ssl3_init_finished_mac(s); + + case SSL3_ST_CW_CLNT_HELLO_B: + dtls1_start_timer(s); + ret = ssl3_client_hello(s); + if (ret <= 0) + goto end; + + if (s->d1->send_cookie) { + s->state = SSL3_ST_CW_FLUSH; + s->s3->tmp.next_state = SSL3_ST_CR_SRVR_HELLO_A; + } else + s->state = SSL3_ST_CR_SRVR_HELLO_A; + + s->init_num = 0; + +#ifndef OPENSSL_NO_SCTP + /* Disable buffering for SCTP */ + if (!BIO_dgram_is_sctp(SSL_get_wbio(s))) { +#endif + /* + * turn on buffering for the next lot of output + */ + if (s->bbio != s->wbio) + s->wbio = BIO_push(s->bbio, s->wbio); +#ifndef OPENSSL_NO_SCTP + } +#endif + + 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; + else { + if (s->hit) { +#ifndef OPENSSL_NO_SCTP + /* + * Add new shared key for SCTP-Auth, will be ignored if + * no SCTP used. + */ + snprintf((char *)labelbuffer, + sizeof(DTLS1_SCTP_AUTH_LABEL), + DTLS1_SCTP_AUTH_LABEL); + + if (SSL_export_keying_material(s, sctpauthkey, + sizeof(sctpauthkey), + labelbuffer, + sizeof(labelbuffer), NULL, 0, + 0) <= 0) { + ret = -1; + s->state = SSL_ST_ERR; + goto end; + } + + BIO_ctrl(SSL_get_wbio(s), + BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY, + sizeof(sctpauthkey), sctpauthkey); +#endif + + s->state = SSL3_ST_CR_FINISHED_A; + if (s->tlsext_ticket_expected) { + /* receive renewed session ticket */ + s->state = SSL3_ST_CR_SESSION_TICKET_A; + } + } else + s->state = DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A; + } + s->init_num = 0; + break; + + case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A: + case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B: + + ret = dtls1_get_hello_verify(s); + if (ret <= 0) + goto end; + dtls1_stop_timer(s); + if (s->d1->send_cookie) /* start again, with a cookie */ + s->state = SSL3_ST_CW_CLNT_HELLO_A; + else + s->state = SSL3_ST_CR_CERT_A; + s->init_num = 0; + break; + + case SSL3_ST_CR_CERT_A: + case SSL3_ST_CR_CERT_B: + /* Check if it is anon DH or PSK */ + if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) && + !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) { + ret = ssl3_get_server_certificate(s); + if (ret <= 0) + goto end; +#ifndef OPENSSL_NO_TLSEXT + if (s->tlsext_status_expected) + s->state = SSL3_ST_CR_CERT_STATUS_A; + else + s->state = SSL3_ST_CR_KEY_EXCH_A; + } else { + skip = 1; + s->state = SSL3_ST_CR_KEY_EXCH_A; + } +#else + } else + skip = 1; + + s->state = SSL3_ST_CR_KEY_EXCH_A; +#endif + s->init_num = 0; + break; + + case SSL3_ST_CR_KEY_EXCH_A: + case SSL3_ST_CR_KEY_EXCH_B: + ret = ssl3_get_key_exchange(s); + if (ret <= 0) + goto end; + s->state = SSL3_ST_CR_CERT_REQ_A; + s->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; + s->state = SSL_ST_ERR; + 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->state = SSL3_ST_CR_SRVR_DONE_A; + s->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; + dtls1_stop_timer(s); + if (s->s3->tmp.cert_req) + s->s3->tmp.next_state = SSL3_ST_CW_CERT_A; + else + s->s3->tmp.next_state = SSL3_ST_CW_KEY_EXCH_A; + s->init_num = 0; + +#ifndef OPENSSL_NO_SCTP + if (BIO_dgram_is_sctp(SSL_get_wbio(s)) && + state == SSL_ST_RENEGOTIATE) + s->state = DTLS1_SCTP_ST_CR_READ_SOCK; + else +#endif + s->state = s->s3->tmp.next_state; + 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: + dtls1_start_timer(s); + ret = ssl3_send_client_certificate(s); + if (ret <= 0) + goto end; + s->state = SSL3_ST_CW_KEY_EXCH_A; + s->init_num = 0; + break; + + case SSL3_ST_CW_KEY_EXCH_A: + case SSL3_ST_CW_KEY_EXCH_B: + dtls1_start_timer(s); + ret = ssl3_send_client_key_exchange(s); + if (ret <= 0) + goto end; + +#ifndef OPENSSL_NO_SCTP + /* + * Add new shared key for SCTP-Auth, will be ignored if no SCTP + * used. + */ + snprintf((char *)labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL), + DTLS1_SCTP_AUTH_LABEL); + + if (SSL_export_keying_material(s, sctpauthkey, + sizeof(sctpauthkey), labelbuffer, + sizeof(labelbuffer), NULL, 0, 0) <= 0) { + ret = -1; + s->state = SSL_ST_ERR; + goto end; + } + + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY, + sizeof(sctpauthkey), sctpauthkey); +#endif + + /* + * 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 + */ + if (s->s3->tmp.cert_req == 1) { + s->state = SSL3_ST_CW_CERT_VRFY_A; + } else { +#ifndef OPENSSL_NO_SCTP + if (BIO_dgram_is_sctp(SSL_get_wbio(s))) { + s->d1->next_state = SSL3_ST_CW_CHANGE_A; + s->state = DTLS1_SCTP_ST_CW_WRITE_SOCK; + } else +#endif + s->state = SSL3_ST_CW_CHANGE_A; + } + + s->init_num = 0; + break; + + case SSL3_ST_CW_CERT_VRFY_A: + case SSL3_ST_CW_CERT_VRFY_B: + dtls1_start_timer(s); + ret = ssl3_send_client_verify(s); + if (ret <= 0) + goto end; +#ifndef OPENSSL_NO_SCTP + if (BIO_dgram_is_sctp(SSL_get_wbio(s))) { + s->d1->next_state = SSL3_ST_CW_CHANGE_A; + s->state = DTLS1_SCTP_ST_CW_WRITE_SOCK; + } else +#endif + s->state = SSL3_ST_CW_CHANGE_A; + s->init_num = 0; + break; + + case SSL3_ST_CW_CHANGE_A: + case SSL3_ST_CW_CHANGE_B: + if (!s->hit) + dtls1_start_timer(s); + ret = dtls1_send_change_cipher_spec(s, + SSL3_ST_CW_CHANGE_A, + SSL3_ST_CW_CHANGE_B); + if (ret <= 0) + goto end; + + s->state = SSL3_ST_CW_FINISHED_A; + s->init_num = 0; + + s->session->cipher = s->s3->tmp.new_cipher; +#ifdef OPENSSL_NO_COMP + s->session->compress_meth = 0; +#else + if (s->s3->tmp.new_compression == NULL) + s->session->compress_meth = 0; + else + s->session->compress_meth = s->s3->tmp.new_compression->id; +#endif + if (!s->method->ssl3_enc->setup_key_block(s)) { + ret = -1; + s->state = SSL_ST_ERR; + goto end; + } + + if (!s->method->ssl3_enc->change_cipher_state(s, + SSL3_CHANGE_CIPHER_CLIENT_WRITE)) + { + ret = -1; + s->state = SSL_ST_ERR; + goto end; + } +#ifndef OPENSSL_NO_SCTP + if (s->hit) { + /* + * Change to new shared key of SCTP-Auth, will be ignored if + * no SCTP used. + */ + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY, + 0, NULL); + } +#endif + + dtls1_reset_seq_numbers(s, SSL3_CC_WRITE); + break; + + case SSL3_ST_CW_FINISHED_A: + case SSL3_ST_CW_FINISHED_B: + if (!s->hit) + dtls1_start_timer(s); + ret = ssl3_send_finished(s, + SSL3_ST_CW_FINISHED_A, + SSL3_ST_CW_FINISHED_B, + s->method-> + ssl3_enc->client_finished_label, + s->method-> + ssl3_enc->client_finished_label_len); + if (ret <= 0) + goto end; + s->state = SSL3_ST_CW_FLUSH; + + /* clear flags */ + s->s3->flags &= ~SSL3_FLAGS_POP_BUFFER; + if (s->hit) { + s->s3->tmp.next_state = SSL_ST_OK; +#ifndef OPENSSL_NO_SCTP + if (BIO_dgram_is_sctp(SSL_get_wbio(s))) { + s->d1->next_state = s->s3->tmp.next_state; + s->s3->tmp.next_state = DTLS1_SCTP_ST_CW_WRITE_SOCK; + } +#endif + if (s->s3->flags & SSL3_FLAGS_DELAY_CLIENT_FINISHED) { + s->state = SSL_ST_OK; +#ifndef OPENSSL_NO_SCTP + if (BIO_dgram_is_sctp(SSL_get_wbio(s))) { + s->d1->next_state = SSL_ST_OK; + s->state = DTLS1_SCTP_ST_CW_WRITE_SOCK; + } +#endif + s->s3->flags |= SSL3_FLAGS_POP_BUFFER; + s->s3->delay_buf_pop_ret = 0; + } + } else { +#ifndef OPENSSL_NO_SCTP + /* + * Change to new shared key of SCTP-Auth, will be ignored if + * no SCTP used. + */ + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY, + 0, NULL); +#endif + +#ifndef OPENSSL_NO_TLSEXT + /* + * Allow NewSessionTicket if ticket expected + */ + if (s->tlsext_ticket_expected) + s->s3->tmp.next_state = SSL3_ST_CR_SESSION_TICKET_A; + else +#endif + + s->s3->tmp.next_state = SSL3_ST_CR_FINISHED_A; + } + s->init_num = 0; + break; + +#ifndef OPENSSL_NO_TLSEXT + 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->state = SSL3_ST_CR_FINISHED_A; + s->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->state = SSL3_ST_CR_KEY_EXCH_A; + s->init_num = 0; + break; +#endif + + case SSL3_ST_CR_FINISHED_A: + case SSL3_ST_CR_FINISHED_B: + s->d1->change_cipher_spec_ok = 1; + ret = ssl3_get_finished(s, SSL3_ST_CR_FINISHED_A, + SSL3_ST_CR_FINISHED_B); + if (ret <= 0) + goto end; + dtls1_stop_timer(s); + + if (s->hit) + s->state = SSL3_ST_CW_CHANGE_A; + else + s->state = SSL_ST_OK; + +#ifndef OPENSSL_NO_SCTP + if (BIO_dgram_is_sctp(SSL_get_wbio(s)) && + state == SSL_ST_RENEGOTIATE) { + s->d1->next_state = s->state; + s->state = DTLS1_SCTP_ST_CW_WRITE_SOCK; + } +#endif + + s->init_num = 0; + break; + + case SSL3_ST_CW_FLUSH: + s->rwstate = SSL_WRITING; + if (BIO_flush(s->wbio) <= 0) { + /* + * If the write error was fatal, stop trying + */ + if (!BIO_should_retry(s->wbio)) { + s->rwstate = SSL_NOTHING; + s->state = s->s3->tmp.next_state; + } + + ret = -1; + goto end; + } + s->rwstate = SSL_NOTHING; + s->state = s->s3->tmp.next_state; + break; + + case SSL_ST_OK: + /* clean a few things up */ + ssl3_cleanup_key_block(s); + +#if 0 + if (s->init_buf != NULL) { + BUF_MEM_free(s->init_buf); + s->init_buf = NULL; + } +#endif + + /* + * 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->init_num = 0; + s->renegotiate = 0; + s->new_session = 0; + + ssl_update_cache(s, SSL_SESS_CACHE_CLIENT); + if (s->hit) + s->ctx->stats.sess_hit++; + + ret = 1; + /* s->server=0; */ + s->handshake_func = dtls1_connect; + s->ctx->stats.sess_connect_good++; + + if (cb != NULL) + cb(s, SSL_CB_HANDSHAKE_DONE, 1); + + /* done with handshaking */ + s->d1->handshake_read_seq = 0; + s->d1->next_handshake_write_seq = 0; + goto end; + /* break; */ + + case SSL_ST_ERR: + default: + SSLerr(SSL_F_DTLS1_CONNECT, SSL_R_UNKNOWN_STATE); + ret = -1; + goto end; + /* break; */ + } + + /* did we do anything */ + if (!s->s3->tmp.reuse_message && !skip) { + if (s->debug) { + if ((ret = BIO_flush(s->wbio)) <= 0) + goto end; + } + + if ((cb != NULL) && (s->state != state)) { + new_state = s->state; + s->state = state; + cb(s, SSL_CB_CONNECT_LOOP, 1); + s->state = new_state; + } + } + skip = 0; + } + end: + s->in_handshake--; + +#ifndef OPENSSL_NO_SCTP + /* + * Notify SCTP BIO socket to leave handshake mode and allow stream + * identifier other than 0. Will be ignored if no SCTP is used. + */ + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE, + s->in_handshake, NULL); +#endif + + if (buf != NULL) + BUF_MEM_free(buf); + if (cb != NULL) + cb(s, SSL_CB_CONNECT_EXIT, ret); + return (ret); +} + +static int dtls1_get_hello_verify(SSL *s) +{ + int n, al, ok = 0; + unsigned char *data; + unsigned int cookie_len; + + s->first_packet = 1; + n = s->method->ssl_get_message(s, + DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A, + DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B, + -1, s->max_cert_list, &ok); + s->first_packet = 0; + + if (!ok) + return ((int)n); + + if (s->s3->tmp.message_type != DTLS1_MT_HELLO_VERIFY_REQUEST) { + s->d1->send_cookie = 0; + s->s3->tmp.reuse_message = 1; + return (1); + } + + data = (unsigned char *)s->init_msg; +#if 0 + if (s->method->version != DTLS_ANY_VERSION && + ((data[0] != (s->version >> 8)) || (data[1] != (s->version & 0xff)))) + { + SSLerr(SSL_F_DTLS1_GET_HELLO_VERIFY, SSL_R_WRONG_SSL_VERSION); + s->version = (s->version & 0xff00) | data[1]; + al = SSL_AD_PROTOCOL_VERSION; + goto f_err; + } +#endif + data += 2; + + cookie_len = *(data++); + if (cookie_len > sizeof(s->d1->cookie)) { + al = SSL_AD_ILLEGAL_PARAMETER; + goto f_err; + } + + memcpy(s->d1->cookie, data, cookie_len); + s->d1->cookie_len = cookie_len; + + s->d1->send_cookie = 1; + return 1; + + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + s->state = SSL_ST_ERR; + return -1; +} diff --git a/thirdparty/openssl/ssl/d1_lib.c b/thirdparty/openssl/ssl/d1_lib.c new file mode 100644 index 0000000000..ee78921ba8 --- /dev/null +++ b/thirdparty/openssl/ssl/d1_lib.c @@ -0,0 +1,573 @@ +/* ssl/d1_lib.c */ +/* + * DTLS implementation written by Nagendra Modadugu + * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. + */ +/* ==================================================================== + * Copyright (c) 1999-2005 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 <stdio.h> +#define USE_SOCKETS +#include <openssl/objects.h> +#include "ssl_locl.h" + +#if defined(OPENSSL_SYS_VMS) +# include <sys/timeb.h> +#endif + +static void get_current_time(struct timeval *t); +static void dtls1_set_handshake_header(SSL *s, int type, unsigned long len); +static int dtls1_handshake_write(SSL *s); +const char dtls1_version_str[] = "DTLSv1" OPENSSL_VERSION_PTEXT; +int dtls1_listen(SSL *s, struct sockaddr *client); + +SSL3_ENC_METHOD DTLSv1_enc_data = { + tls1_enc, + tls1_mac, + tls1_setup_key_block, + tls1_generate_master_secret, + tls1_change_cipher_state, + tls1_final_finish_mac, + TLS1_FINISH_MAC_LENGTH, + tls1_cert_verify_mac, + TLS_MD_CLIENT_FINISH_CONST, TLS_MD_CLIENT_FINISH_CONST_SIZE, + TLS_MD_SERVER_FINISH_CONST, TLS_MD_SERVER_FINISH_CONST_SIZE, + tls1_alert_code, + tls1_export_keying_material, + SSL_ENC_FLAG_DTLS | SSL_ENC_FLAG_EXPLICIT_IV, + DTLS1_HM_HEADER_LENGTH, + dtls1_set_handshake_header, + dtls1_handshake_write +}; + +SSL3_ENC_METHOD DTLSv1_2_enc_data = { + tls1_enc, + tls1_mac, + tls1_setup_key_block, + tls1_generate_master_secret, + tls1_change_cipher_state, + tls1_final_finish_mac, + TLS1_FINISH_MAC_LENGTH, + tls1_cert_verify_mac, + TLS_MD_CLIENT_FINISH_CONST, TLS_MD_CLIENT_FINISH_CONST_SIZE, + TLS_MD_SERVER_FINISH_CONST, TLS_MD_SERVER_FINISH_CONST_SIZE, + tls1_alert_code, + tls1_export_keying_material, + SSL_ENC_FLAG_DTLS | SSL_ENC_FLAG_EXPLICIT_IV | SSL_ENC_FLAG_SIGALGS + | SSL_ENC_FLAG_SHA256_PRF | SSL_ENC_FLAG_TLS1_2_CIPHERS, + DTLS1_HM_HEADER_LENGTH, + dtls1_set_handshake_header, + dtls1_handshake_write +}; + +long dtls1_default_timeout(void) +{ + /* + * 2 hours, the 24 hours mentioned in the DTLSv1 spec is way too long for + * http, the cache would over fill + */ + return (60 * 60 * 2); +} + +int dtls1_new(SSL *s) +{ + DTLS1_STATE *d1; + + if (!ssl3_new(s)) + return (0); + if ((d1 = OPENSSL_malloc(sizeof *d1)) == NULL) + return (0); + memset(d1, 0, sizeof *d1); + + /* d1->handshake_epoch=0; */ + + d1->unprocessed_rcds.q = pqueue_new(); + d1->processed_rcds.q = pqueue_new(); + d1->buffered_messages = pqueue_new(); + d1->sent_messages = pqueue_new(); + d1->buffered_app_data.q = pqueue_new(); + + if (s->server) { + d1->cookie_len = sizeof(s->d1->cookie); + } + + d1->link_mtu = 0; + d1->mtu = 0; + + if (!d1->unprocessed_rcds.q || !d1->processed_rcds.q + || !d1->buffered_messages || !d1->sent_messages + || !d1->buffered_app_data.q) { + if (d1->unprocessed_rcds.q) + pqueue_free(d1->unprocessed_rcds.q); + if (d1->processed_rcds.q) + pqueue_free(d1->processed_rcds.q); + if (d1->buffered_messages) + pqueue_free(d1->buffered_messages); + if (d1->sent_messages) + pqueue_free(d1->sent_messages); + if (d1->buffered_app_data.q) + pqueue_free(d1->buffered_app_data.q); + OPENSSL_free(d1); + return (0); + } + + s->d1 = d1; + s->method->ssl_clear(s); + return (1); +} + +static void dtls1_clear_queues(SSL *s) +{ + pitem *item = NULL; + hm_fragment *frag = NULL; + DTLS1_RECORD_DATA *rdata; + + while ((item = pqueue_pop(s->d1->unprocessed_rcds.q)) != NULL) { + rdata = (DTLS1_RECORD_DATA *)item->data; + if (rdata->rbuf.buf) { + OPENSSL_free(rdata->rbuf.buf); + } + OPENSSL_free(item->data); + pitem_free(item); + } + + while ((item = pqueue_pop(s->d1->processed_rcds.q)) != NULL) { + rdata = (DTLS1_RECORD_DATA *)item->data; + if (rdata->rbuf.buf) { + OPENSSL_free(rdata->rbuf.buf); + } + OPENSSL_free(item->data); + pitem_free(item); + } + + while ((item = pqueue_pop(s->d1->buffered_messages)) != NULL) { + frag = (hm_fragment *)item->data; + dtls1_hm_fragment_free(frag); + pitem_free(item); + } + + while ((item = pqueue_pop(s->d1->sent_messages)) != NULL) { + frag = (hm_fragment *)item->data; + dtls1_hm_fragment_free(frag); + pitem_free(item); + } + + while ((item = pqueue_pop(s->d1->buffered_app_data.q)) != NULL) { + rdata = (DTLS1_RECORD_DATA *)item->data; + if (rdata->rbuf.buf) { + OPENSSL_free(rdata->rbuf.buf); + } + OPENSSL_free(item->data); + pitem_free(item); + } +} + +void dtls1_free(SSL *s) +{ + ssl3_free(s); + + dtls1_clear_queues(s); + + pqueue_free(s->d1->unprocessed_rcds.q); + pqueue_free(s->d1->processed_rcds.q); + pqueue_free(s->d1->buffered_messages); + pqueue_free(s->d1->sent_messages); + pqueue_free(s->d1->buffered_app_data.q); + + OPENSSL_free(s->d1); + s->d1 = NULL; +} + +void dtls1_clear(SSL *s) +{ + pqueue unprocessed_rcds; + pqueue processed_rcds; + pqueue buffered_messages; + pqueue sent_messages; + pqueue buffered_app_data; + unsigned int mtu; + unsigned int link_mtu; + + if (s->d1) { + unprocessed_rcds = s->d1->unprocessed_rcds.q; + processed_rcds = s->d1->processed_rcds.q; + buffered_messages = s->d1->buffered_messages; + sent_messages = s->d1->sent_messages; + buffered_app_data = s->d1->buffered_app_data.q; + mtu = s->d1->mtu; + link_mtu = s->d1->link_mtu; + + dtls1_clear_queues(s); + + memset(s->d1, 0, sizeof(*(s->d1))); + + if (s->server) { + s->d1->cookie_len = sizeof(s->d1->cookie); + } + + if (SSL_get_options(s) & SSL_OP_NO_QUERY_MTU) { + s->d1->mtu = mtu; + s->d1->link_mtu = link_mtu; + } + + s->d1->unprocessed_rcds.q = unprocessed_rcds; + s->d1->processed_rcds.q = processed_rcds; + s->d1->buffered_messages = buffered_messages; + s->d1->sent_messages = sent_messages; + s->d1->buffered_app_data.q = buffered_app_data; + } + + ssl3_clear(s); + if (s->options & SSL_OP_CISCO_ANYCONNECT) + s->client_version = s->version = DTLS1_BAD_VER; + else if (s->method->version == DTLS_ANY_VERSION) + s->version = DTLS1_2_VERSION; + else + s->version = s->method->version; +} + +long dtls1_ctrl(SSL *s, int cmd, long larg, void *parg) +{ + int ret = 0; + + switch (cmd) { + case DTLS_CTRL_GET_TIMEOUT: + if (dtls1_get_timeout(s, (struct timeval *)parg) != NULL) { + ret = 1; + } + break; + case DTLS_CTRL_HANDLE_TIMEOUT: + ret = dtls1_handle_timeout(s); + break; + case DTLS_CTRL_LISTEN: + ret = dtls1_listen(s, parg); + break; + case SSL_CTRL_CHECK_PROTO_VERSION: + /* + * For library-internal use; checks that the current protocol is the + * highest enabled version (according to s->ctx->method, as version + * negotiation may have changed s->method). + */ + if (s->version == s->ctx->method->version) + return 1; + /* + * Apparently we're using a version-flexible SSL_METHOD (not at its + * highest protocol version). + */ + if (s->ctx->method->version == DTLS_method()->version) { +#if DTLS_MAX_VERSION != DTLS1_2_VERSION +# error Code needs update for DTLS_method() support beyond DTLS1_2_VERSION. +#endif + if (!(s->options & SSL_OP_NO_DTLSv1_2)) + return s->version == DTLS1_2_VERSION; + if (!(s->options & SSL_OP_NO_DTLSv1)) + return s->version == DTLS1_VERSION; + } + return 0; /* Unexpected state; fail closed. */ + case DTLS_CTRL_SET_LINK_MTU: + if (larg < (long)dtls1_link_min_mtu()) + return 0; + s->d1->link_mtu = larg; + return 1; + case DTLS_CTRL_GET_LINK_MIN_MTU: + return (long)dtls1_link_min_mtu(); + case SSL_CTRL_SET_MTU: + /* + * We may not have a BIO set yet so can't call dtls1_min_mtu() + * We'll have to make do with dtls1_link_min_mtu() and max overhead + */ + if (larg < (long)dtls1_link_min_mtu() - DTLS1_MAX_MTU_OVERHEAD) + return 0; + s->d1->mtu = larg; + return larg; + default: + ret = ssl3_ctrl(s, cmd, larg, parg); + break; + } + return (ret); +} + +/* + * As it's impossible to use stream ciphers in "datagram" mode, this + * simple filter is designed to disengage them in DTLS. Unfortunately + * there is no universal way to identify stream SSL_CIPHER, so we have + * to explicitly list their SSL_* codes. Currently RC4 is the only one + * available, but if new ones emerge, they will have to be added... + */ +const SSL_CIPHER *dtls1_get_cipher(unsigned int u) +{ + const SSL_CIPHER *ciph = ssl3_get_cipher(u); + + if (ciph != NULL) { + if (ciph->algorithm_enc == SSL_RC4) + return NULL; + } + + return ciph; +} + +void dtls1_start_timer(SSL *s) +{ +#ifndef OPENSSL_NO_SCTP + /* Disable timer for SCTP */ + if (BIO_dgram_is_sctp(SSL_get_wbio(s))) { + memset(&(s->d1->next_timeout), 0, sizeof(struct timeval)); + return; + } +#endif + + /* If timer is not set, initialize duration with 1 second */ + if (s->d1->next_timeout.tv_sec == 0 && s->d1->next_timeout.tv_usec == 0) { + s->d1->timeout_duration = 1; + } + + /* Set timeout to current time */ + get_current_time(&(s->d1->next_timeout)); + + /* Add duration to current time */ + s->d1->next_timeout.tv_sec += s->d1->timeout_duration; + BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0, + &(s->d1->next_timeout)); +} + +struct timeval *dtls1_get_timeout(SSL *s, struct timeval *timeleft) +{ + struct timeval timenow; + + /* If no timeout is set, just return NULL */ + if (s->d1->next_timeout.tv_sec == 0 && s->d1->next_timeout.tv_usec == 0) { + return NULL; + } + + /* Get current time */ + get_current_time(&timenow); + + /* If timer already expired, set remaining time to 0 */ + if (s->d1->next_timeout.tv_sec < timenow.tv_sec || + (s->d1->next_timeout.tv_sec == timenow.tv_sec && + s->d1->next_timeout.tv_usec <= timenow.tv_usec)) { + memset(timeleft, 0, sizeof(struct timeval)); + return timeleft; + } + + /* Calculate time left until timer expires */ + memcpy(timeleft, &(s->d1->next_timeout), sizeof(struct timeval)); + timeleft->tv_sec -= timenow.tv_sec; + timeleft->tv_usec -= timenow.tv_usec; + if (timeleft->tv_usec < 0) { + timeleft->tv_sec--; + timeleft->tv_usec += 1000000; + } + + /* + * If remaining time is less than 15 ms, set it to 0 to prevent issues + * because of small devergences with socket timeouts. + */ + if (timeleft->tv_sec == 0 && timeleft->tv_usec < 15000) { + memset(timeleft, 0, sizeof(struct timeval)); + } + + return timeleft; +} + +int dtls1_is_timer_expired(SSL *s) +{ + struct timeval timeleft; + + /* Get time left until timeout, return false if no timer running */ + if (dtls1_get_timeout(s, &timeleft) == NULL) { + return 0; + } + + /* Return false if timer is not expired yet */ + if (timeleft.tv_sec > 0 || timeleft.tv_usec > 0) { + return 0; + } + + /* Timer expired, so return true */ + return 1; +} + +void dtls1_double_timeout(SSL *s) +{ + s->d1->timeout_duration *= 2; + if (s->d1->timeout_duration > 60) + s->d1->timeout_duration = 60; + dtls1_start_timer(s); +} + +void dtls1_stop_timer(SSL *s) +{ + /* Reset everything */ + memset(&(s->d1->timeout), 0, sizeof(struct dtls1_timeout_st)); + memset(&(s->d1->next_timeout), 0, sizeof(struct timeval)); + s->d1->timeout_duration = 1; + BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0, + &(s->d1->next_timeout)); + /* Clear retransmission buffer */ + dtls1_clear_record_buffer(s); +} + +int dtls1_check_timeout_num(SSL *s) +{ + unsigned int mtu; + + s->d1->timeout.num_alerts++; + + /* Reduce MTU after 2 unsuccessful retransmissions */ + if (s->d1->timeout.num_alerts > 2 + && !(SSL_get_options(s) & SSL_OP_NO_QUERY_MTU)) { + mtu = + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_GET_FALLBACK_MTU, 0, + NULL); + if (mtu < s->d1->mtu) + s->d1->mtu = mtu; + } + + if (s->d1->timeout.num_alerts > DTLS1_TMO_ALERT_COUNT) { + /* fail the connection, enough alerts have been sent */ + SSLerr(SSL_F_DTLS1_CHECK_TIMEOUT_NUM, SSL_R_READ_TIMEOUT_EXPIRED); + return -1; + } + + return 0; +} + +int dtls1_handle_timeout(SSL *s) +{ + /* if no timer is expired, don't do anything */ + if (!dtls1_is_timer_expired(s)) { + return 0; + } + + dtls1_double_timeout(s); + + if (dtls1_check_timeout_num(s) < 0) + return -1; + + s->d1->timeout.read_timeouts++; + if (s->d1->timeout.read_timeouts > DTLS1_TMO_READ_COUNT) { + s->d1->timeout.read_timeouts = 1; + } +#ifndef OPENSSL_NO_HEARTBEATS + if (s->tlsext_hb_pending) { + s->tlsext_hb_pending = 0; + return dtls1_heartbeat(s); + } +#endif + + dtls1_start_timer(s); + return dtls1_retransmit_buffered_messages(s); +} + +static void get_current_time(struct timeval *t) +{ +#if defined(_WIN32) + SYSTEMTIME st; + union { + unsigned __int64 ul; + FILETIME ft; + } now; + + GetSystemTime(&st); + SystemTimeToFileTime(&st, &now.ft); +# ifdef __MINGW32__ + now.ul -= 116444736000000000ULL; +# else + now.ul -= 116444736000000000UI64; /* re-bias to 1/1/1970 */ +# endif + t->tv_sec = (long)(now.ul / 10000000); + t->tv_usec = ((int)(now.ul % 10000000)) / 10; +#elif defined(OPENSSL_SYS_VMS) + struct timeb tb; + ftime(&tb); + t->tv_sec = (long)tb.time; + t->tv_usec = (long)tb.millitm * 1000; +#else + gettimeofday(t, NULL); +#endif +} + +int dtls1_listen(SSL *s, struct sockaddr *client) +{ + int ret; + + /* Ensure there is no state left over from a previous invocation */ + SSL_clear(s); + + SSL_set_options(s, SSL_OP_COOKIE_EXCHANGE); + s->d1->listen = 1; + + ret = SSL_accept(s); + if (ret <= 0) + return ret; + + (void)BIO_dgram_get_peer(SSL_get_rbio(s), client); + return 1; +} + +static void dtls1_set_handshake_header(SSL *s, int htype, unsigned long len) +{ + unsigned char *p = (unsigned char *)s->init_buf->data; + dtls1_set_message_header(s, p, htype, len, 0, len); + s->init_num = (int)len + DTLS1_HM_HEADER_LENGTH; + s->init_off = 0; + /* Buffer the message to handle re-xmits */ + dtls1_buffer_message(s, 0); +} + +static int dtls1_handshake_write(SSL *s) +{ + return dtls1_do_write(s, SSL3_RT_HANDSHAKE); +} diff --git a/thirdparty/openssl/ssl/d1_meth.c b/thirdparty/openssl/ssl/d1_meth.c new file mode 100644 index 0000000000..899010e985 --- /dev/null +++ b/thirdparty/openssl/ssl/d1_meth.c @@ -0,0 +1,90 @@ +/* ssl/d1_meth.h */ +/* + * DTLS implementation written by Nagendra Modadugu + * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. + */ +/* ==================================================================== + * Copyright (c) 1999-2005 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 <stdio.h> +#include <openssl/objects.h> +#include "ssl_locl.h" + +static const SSL_METHOD *dtls1_get_method(int ver); +static const SSL_METHOD *dtls1_get_method(int ver) +{ + if (ver == DTLS_ANY_VERSION) + return DTLS_method(); + else if (ver == DTLS1_VERSION) + return DTLSv1_method(); + else if (ver == DTLS1_2_VERSION) + return DTLSv1_2_method(); + else + return NULL; +} + +IMPLEMENT_dtls1_meth_func(DTLS1_VERSION, + DTLSv1_method, + dtls1_accept, + dtls1_connect, dtls1_get_method, DTLSv1_enc_data) + +IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION, + DTLSv1_2_method, + dtls1_accept, + dtls1_connect, dtls1_get_method, DTLSv1_2_enc_data) + +IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION, + DTLS_method, + dtls1_accept, + dtls1_connect, dtls1_get_method, DTLSv1_2_enc_data) diff --git a/thirdparty/openssl/ssl/d1_pkt.c b/thirdparty/openssl/ssl/d1_pkt.c new file mode 100644 index 0000000000..fe30ec7d00 --- /dev/null +++ b/thirdparty/openssl/ssl/d1_pkt.c @@ -0,0 +1,1921 @@ +/* ssl/d1_pkt.c */ +/* + * DTLS implementation written by Nagendra Modadugu + * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. + */ +/* ==================================================================== + * Copyright (c) 1998-2005 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 (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.] + */ + +#include <stdio.h> +#include <errno.h> +#define USE_SOCKETS +#include "ssl_locl.h" +#include <openssl/evp.h> +#include <openssl/buffer.h> +#include <openssl/pqueue.h> +#include <openssl/rand.h> + +/* mod 128 saturating subtract of two 64-bit values in big-endian order */ +static int satsub64be(const unsigned char *v1, const unsigned char *v2) +{ + int ret, sat, brw, i; + + if (sizeof(long) == 8) + do { + const union { + long one; + char little; + } is_endian = { + 1 + }; + long l; + + if (is_endian.little) + break; + /* not reached on little-endians */ + /* + * following test is redundant, because input is always aligned, + * but I take no chances... + */ + if (((size_t)v1 | (size_t)v2) & 0x7) + break; + + l = *((long *)v1); + l -= *((long *)v2); + if (l > 128) + return 128; + else if (l < -128) + return -128; + else + return (int)l; + } while (0); + + ret = (int)v1[7] - (int)v2[7]; + sat = 0; + brw = ret >> 8; /* brw is either 0 or -1 */ + if (ret & 0x80) { + for (i = 6; i >= 0; i--) { + brw += (int)v1[i] - (int)v2[i]; + sat |= ~brw; + brw >>= 8; + } + } else { + for (i = 6; i >= 0; i--) { + brw += (int)v1[i] - (int)v2[i]; + sat |= brw; + brw >>= 8; + } + } + brw <<= 8; /* brw is either 0 or -256 */ + + if (sat & 0xff) + return brw | 0x80; + else + return brw + (ret & 0xFF); +} + +static int have_handshake_fragment(SSL *s, int type, unsigned char *buf, + int len, int peek); +static int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap); +static void dtls1_record_bitmap_update(SSL *s, DTLS1_BITMAP *bitmap); +static DTLS1_BITMAP *dtls1_get_bitmap(SSL *s, SSL3_RECORD *rr, + unsigned int *is_next_epoch); +#if 0 +static int dtls1_record_needs_buffering(SSL *s, SSL3_RECORD *rr, + unsigned short *priority, + unsigned long *offset); +#endif +static int dtls1_buffer_record(SSL *s, record_pqueue *q, + unsigned char *priority); +static int dtls1_process_record(SSL *s); + +/* copy buffered record into SSL structure */ +static int dtls1_copy_record(SSL *s, pitem *item) +{ + DTLS1_RECORD_DATA *rdata; + + rdata = (DTLS1_RECORD_DATA *)item->data; + + if (s->s3->rbuf.buf != NULL) + OPENSSL_free(s->s3->rbuf.buf); + + s->packet = rdata->packet; + s->packet_length = rdata->packet_length; + memcpy(&(s->s3->rbuf), &(rdata->rbuf), sizeof(SSL3_BUFFER)); + memcpy(&(s->s3->rrec), &(rdata->rrec), sizeof(SSL3_RECORD)); + + /* Set proper sequence number for mac calculation */ + memcpy(&(s->s3->read_sequence[2]), &(rdata->packet[5]), 6); + + return (1); +} + +static int +dtls1_buffer_record(SSL *s, record_pqueue *queue, unsigned char *priority) +{ + DTLS1_RECORD_DATA *rdata; + pitem *item; + + /* Limit the size of the queue to prevent DOS attacks */ + if (pqueue_size(queue->q) >= 100) + return 0; + + rdata = OPENSSL_malloc(sizeof(DTLS1_RECORD_DATA)); + item = pitem_new(priority, rdata); + if (rdata == NULL || item == NULL) { + if (rdata != NULL) + OPENSSL_free(rdata); + if (item != NULL) + pitem_free(item); + + SSLerr(SSL_F_DTLS1_BUFFER_RECORD, ERR_R_INTERNAL_ERROR); + return -1; + } + + rdata->packet = s->packet; + rdata->packet_length = s->packet_length; + memcpy(&(rdata->rbuf), &(s->s3->rbuf), sizeof(SSL3_BUFFER)); + memcpy(&(rdata->rrec), &(s->s3->rrec), sizeof(SSL3_RECORD)); + + item->data = rdata; + +#ifndef OPENSSL_NO_SCTP + /* Store bio_dgram_sctp_rcvinfo struct */ + if (BIO_dgram_is_sctp(SSL_get_rbio(s)) && + (s->state == SSL3_ST_SR_FINISHED_A + || s->state == SSL3_ST_CR_FINISHED_A)) { + BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SCTP_GET_RCVINFO, + sizeof(rdata->recordinfo), &rdata->recordinfo); + } +#endif + + s->packet = NULL; + s->packet_length = 0; + memset(&(s->s3->rbuf), 0, sizeof(SSL3_BUFFER)); + memset(&(s->s3->rrec), 0, sizeof(SSL3_RECORD)); + + if (!ssl3_setup_buffers(s)) { + SSLerr(SSL_F_DTLS1_BUFFER_RECORD, ERR_R_INTERNAL_ERROR); + if (rdata->rbuf.buf != NULL) + OPENSSL_free(rdata->rbuf.buf); + OPENSSL_free(rdata); + pitem_free(item); + return (-1); + } + + /* insert should not fail, since duplicates are dropped */ + if (pqueue_insert(queue->q, item) == NULL) { + SSLerr(SSL_F_DTLS1_BUFFER_RECORD, ERR_R_INTERNAL_ERROR); + if (rdata->rbuf.buf != NULL) + OPENSSL_free(rdata->rbuf.buf); + OPENSSL_free(rdata); + pitem_free(item); + return (-1); + } + + return (1); +} + +static int dtls1_retrieve_buffered_record(SSL *s, record_pqueue *queue) +{ + pitem *item; + + item = pqueue_pop(queue->q); + if (item) { + dtls1_copy_record(s, item); + + OPENSSL_free(item->data); + pitem_free(item); + + return (1); + } + + return (0); +} + +/* + * retrieve a buffered record that belongs to the new epoch, i.e., not + * processed yet + */ +#define dtls1_get_unprocessed_record(s) \ + dtls1_retrieve_buffered_record((s), \ + &((s)->d1->unprocessed_rcds)) + +/* + * retrieve a buffered record that belongs to the current epoch, ie, + * processed + */ +#define dtls1_get_processed_record(s) \ + dtls1_retrieve_buffered_record((s), \ + &((s)->d1->processed_rcds)) + +static int dtls1_process_buffered_records(SSL *s) +{ + pitem *item; + + item = pqueue_peek(s->d1->unprocessed_rcds.q); + if (item) { + /* Check if epoch is current. */ + if (s->d1->unprocessed_rcds.epoch != s->d1->r_epoch) + return (1); /* Nothing to do. */ + + /* Process all the records. */ + while (pqueue_peek(s->d1->unprocessed_rcds.q)) { + dtls1_get_unprocessed_record(s); + if (!dtls1_process_record(s)) + return (0); + if (dtls1_buffer_record(s, &(s->d1->processed_rcds), + s->s3->rrec.seq_num) < 0) + return -1; + } + } + + /* + * sync epoch numbers once all the unprocessed records have been + * processed + */ + s->d1->processed_rcds.epoch = s->d1->r_epoch; + s->d1->unprocessed_rcds.epoch = s->d1->r_epoch + 1; + + return (1); +} + +#if 0 + +static int dtls1_get_buffered_record(SSL *s) +{ + pitem *item; + PQ_64BIT priority = + (((PQ_64BIT) s->d1->handshake_read_seq) << 32) | + ((PQ_64BIT) s->d1->r_msg_hdr.frag_off); + + /* if we're not (re)negotiating, nothing buffered */ + if (!SSL_in_init(s)) + return 0; + + item = pqueue_peek(s->d1->rcvd_records); + if (item && item->priority == priority) { + /* + * Check if we've received the record of interest. It must be a + * handshake record, since data records as passed up without + * buffering + */ + DTLS1_RECORD_DATA *rdata; + item = pqueue_pop(s->d1->rcvd_records); + rdata = (DTLS1_RECORD_DATA *)item->data; + + if (s->s3->rbuf.buf != NULL) + OPENSSL_free(s->s3->rbuf.buf); + + s->packet = rdata->packet; + s->packet_length = rdata->packet_length; + memcpy(&(s->s3->rbuf), &(rdata->rbuf), sizeof(SSL3_BUFFER)); + memcpy(&(s->s3->rrec), &(rdata->rrec), sizeof(SSL3_RECORD)); + + OPENSSL_free(item->data); + pitem_free(item); + + /* s->d1->next_expected_seq_num++; */ + return (1); + } + + return 0; +} + +#endif + +static int dtls1_process_record(SSL *s) +{ + int i, al; + int enc_err; + SSL_SESSION *sess; + SSL3_RECORD *rr; + unsigned int mac_size, orig_len; + unsigned char md[EVP_MAX_MD_SIZE]; + + rr = &(s->s3->rrec); + sess = s->session; + + /* + * At this point, s->packet_length == SSL3_RT_HEADER_LNGTH + rr->length, + * and we have that many bytes in s->packet + */ + rr->input = &(s->packet[DTLS1_RT_HEADER_LENGTH]); + + /* + * ok, we can now read from 's->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_DTLS1_PROCESS_RECORD, SSL_R_ENCRYPTED_LENGTH_TOO_LONG); + goto f_err; + } + + /* decrypt in place in 'rr->input' */ + rr->data = rr->input; + + enc_err = s->method->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) { + /* For DTLS we simply ignore bad packets. */ + rr->length = 0; + s->packet_length = 0; + goto err; + } +#ifdef TLS_DEBUG + printf("dec %d\n", rr->length); + { + unsigned int z; + for (z = 0; z < rr->length; z++) + printf("%02X%c", rr->data[z], ((z + 1) % 16) ? ' ' : '\n'); + } + printf("\n"); +#endif + + /* 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_DTLS1_PROCESS_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->ssl3_enc->mac(s, md, 0 /* not send */ ); + if (i < 0 || mac == NULL + || CRYPTO_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) { + /* decryption failed, silently discard message */ + rr->length = 0; + s->packet_length = 0; + goto err; + } + + /* r->length is now just compressed */ + if (s->expand != NULL) { + if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH) { + al = SSL_AD_RECORD_OVERFLOW; + SSLerr(SSL_F_DTLS1_PROCESS_RECORD, + SSL_R_COMPRESSED_LENGTH_TOO_LONG); + goto f_err; + } + if (!ssl3_do_uncompress(s)) { + al = SSL_AD_DECOMPRESSION_FAILURE; + SSLerr(SSL_F_DTLS1_PROCESS_RECORD, SSL_R_BAD_DECOMPRESSION); + goto f_err; + } + } + + if (rr->length > SSL3_RT_MAX_PLAIN_LENGTH) { + al = SSL_AD_RECORD_OVERFLOW; + SSLerr(SSL_F_DTLS1_PROCESS_RECORD, SSL_R_DATA_LENGTH_TOO_LONG); + goto f_err; + } + + rr->off = 0; + /*- + * So at this point the following is true + * ssl->s3->rrec.type is the type of record + * ssl->s3->rrec.length == number of bytes in record + * ssl->s3->rrec.off == offset to first valid byte + * ssl->s3->rrec.data == where to take bytes from, increment + * after use :-). + */ + + /* we have pulled in a full packet so zero things */ + s->packet_length = 0; + return (1); + + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + err: + return (0); +} + +/*- + * 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->rrec.type - is the type of record + * ssl->s3->rrec.data, - data + * ssl->s3->rrec.length, - number of bytes + */ +/* used only by dtls1_read_bytes */ +int dtls1_get_record(SSL *s) +{ + int ssl_major, ssl_minor; + int i, n; + SSL3_RECORD *rr; + unsigned char *p = NULL; + unsigned short version; + DTLS1_BITMAP *bitmap; + unsigned int is_next_epoch; + + rr = &(s->s3->rrec); + + /* + * The epoch may have changed. If so, process all the pending records. + * This is a non-blocking operation. + */ + if (dtls1_process_buffered_records(s) < 0) + return -1; + + /* if we're renegotiating, then there may be buffered records */ + if (dtls1_get_processed_record(s)) + return 1; + + /* get something from the wire */ + again: + /* check if we have the header */ + if ((s->rstate != SSL_ST_READ_BODY) || + (s->packet_length < DTLS1_RT_HEADER_LENGTH)) { + n = ssl3_read_n(s, DTLS1_RT_HEADER_LENGTH, s->s3->rbuf.len, 0); + /* read timeout is handled by dtls1_read_bytes */ + if (n <= 0) + return (n); /* error or non-blocking */ + + /* this packet contained a partial record, dump it */ + if (s->packet_length != DTLS1_RT_HEADER_LENGTH) { + s->packet_length = 0; + goto again; + } + + s->rstate = SSL_ST_READ_BODY; + + p = s->packet; + + if (s->msg_callback) + s->msg_callback(0, 0, SSL3_RT_HEADER, p, DTLS1_RT_HEADER_LENGTH, + s, s->msg_callback_arg); + + /* Pull apart the header into the DTLS1_RECORD */ + rr->type = *(p++); + ssl_major = *(p++); + ssl_minor = *(p++); + version = (ssl_major << 8) | ssl_minor; + + /* sequence number is 64 bits, with top 2 bytes = epoch */ + n2s(p, rr->epoch); + + memcpy(&(s->s3->read_sequence[2]), p, 6); + p += 6; + + n2s(p, rr->length); + + /* Lets check version */ + if (!s->first_packet) { + if (version != s->version) { + /* unexpected version, silently discard */ + rr->length = 0; + s->packet_length = 0; + goto again; + } + } + + if ((version & 0xff00) != (s->version & 0xff00)) { + /* wrong version, silently discard record */ + rr->length = 0; + s->packet_length = 0; + goto again; + } + + if (rr->length > SSL3_RT_MAX_ENCRYPTED_LENGTH) { + /* record too long, silently discard it */ + rr->length = 0; + s->packet_length = 0; + goto again; + } + + /* now s->rstate == SSL_ST_READ_BODY */ + } + + /* s->rstate == SSL_ST_READ_BODY, get and decode the data */ + + if (rr->length > s->packet_length - DTLS1_RT_HEADER_LENGTH) { + /* now s->packet_length == DTLS1_RT_HEADER_LENGTH */ + i = rr->length; + n = ssl3_read_n(s, i, i, 1); + /* this packet contained a partial record, dump it */ + if (n != i) { + rr->length = 0; + s->packet_length = 0; + goto again; + } + + /* + * now n == rr->length, and s->packet_length == + * DTLS1_RT_HEADER_LENGTH + rr->length + */ + } + s->rstate = SSL_ST_READ_HEADER; /* set state for later operations */ + + /* match epochs. NULL means the packet is dropped on the floor */ + bitmap = dtls1_get_bitmap(s, rr, &is_next_epoch); + if (bitmap == NULL) { + rr->length = 0; + s->packet_length = 0; /* dump this record */ + goto again; /* get another record */ + } +#ifndef OPENSSL_NO_SCTP + /* Only do replay check if no SCTP bio */ + if (!BIO_dgram_is_sctp(SSL_get_rbio(s))) { +#endif + /* + * Check whether this is a repeat, or aged record. Don't check if + * we're listening and this message is a ClientHello. They can look + * as if they're replayed, since they arrive from different + * connections and would be dropped unnecessarily. + */ + if (!(s->d1->listen && rr->type == SSL3_RT_HANDSHAKE && + s->packet_length > DTLS1_RT_HEADER_LENGTH && + s->packet[DTLS1_RT_HEADER_LENGTH] == SSL3_MT_CLIENT_HELLO) && + !dtls1_record_replay_check(s, bitmap)) { + rr->length = 0; + s->packet_length = 0; /* dump this record */ + goto again; /* get another record */ + } +#ifndef OPENSSL_NO_SCTP + } +#endif + + /* just read a 0 length packet */ + if (rr->length == 0) + goto again; + + /* + * If this record is from the next epoch (either HM or ALERT), and a + * handshake is currently in progress, buffer it since it cannot be + * processed at this time. However, do not buffer anything while + * listening. + */ + if (is_next_epoch) { + if ((SSL_in_init(s) || s->in_handshake) && !s->d1->listen) { + if (dtls1_buffer_record + (s, &(s->d1->unprocessed_rcds), rr->seq_num) < 0) + return -1; + /* Mark receipt of record. */ + dtls1_record_bitmap_update(s, bitmap); + } + rr->length = 0; + s->packet_length = 0; + goto again; + } + + if (!dtls1_process_record(s)) { + rr->length = 0; + s->packet_length = 0; /* dump this record */ + goto again; /* get another record */ + } + dtls1_record_bitmap_update(s, bitmap); /* Mark receipt of record. */ + + return (1); + +} + +/*- + * 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 dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek) +{ + int al, i, j, ret; + unsigned int n; + SSL3_RECORD *rr; + void (*cb) (const SSL *ssl, int type2, int val) = NULL; + + if (s->s3->rbuf.buf == NULL) /* Not initialized yet */ + if (!ssl3_setup_buffers(s)) + return (-1); + + /* XXX: check what the second '&& type' is about */ + if ((type && (type != SSL3_RT_APPLICATION_DATA) && + (type != SSL3_RT_HANDSHAKE) && type) || + (peek && (type != SSL3_RT_APPLICATION_DATA))) { + SSLerr(SSL_F_DTLS1_READ_BYTES, ERR_R_INTERNAL_ERROR); + return -1; + } + + /* + * check whether there's a handshake message (client hello?) waiting + */ + if ((ret = have_handshake_fragment(s, type, buf, len, peek))) + return ret; + + /* + * Now s->d1->handshake_fragment_len == 0 if type == SSL3_RT_HANDSHAKE. + */ + +#ifndef OPENSSL_NO_SCTP + /* + * Continue handshake if it had to be interrupted to read app data with + * SCTP. + */ + if ((!s->in_handshake && SSL_in_init(s)) || + (BIO_dgram_is_sctp(SSL_get_rbio(s)) && + (s->state == DTLS1_SCTP_ST_SR_READ_SOCK + || s->state == DTLS1_SCTP_ST_CR_READ_SOCK) + && s->s3->in_read_app_data != 2)) +#else + if (!s->in_handshake && SSL_in_init(s)) +#endif + { + /* type == SSL3_RT_APPLICATION_DATA */ + i = s->handshake_func(s); + if (i < 0) + return (i); + if (i == 0) { + SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_SSL_HANDSHAKE_FAILURE); + return (-1); + } + } + + start: + s->rwstate = SSL_NOTHING; + + /*- + * s->s3->rrec.type - is the type of record + * s->s3->rrec.data, - data + * s->s3->rrec.off, - offset into 'data' for next read + * s->s3->rrec.length, - number of bytes. + */ + rr = &(s->s3->rrec); + + /* + * We are not handshaking and have no data yet, so process data buffered + * during the last handshake in advance, if any. + */ + if (s->state == SSL_ST_OK && rr->length == 0) { + pitem *item; + item = pqueue_pop(s->d1->buffered_app_data.q); + if (item) { +#ifndef OPENSSL_NO_SCTP + /* Restore bio_dgram_sctp_rcvinfo struct */ + if (BIO_dgram_is_sctp(SSL_get_rbio(s))) { + DTLS1_RECORD_DATA *rdata = (DTLS1_RECORD_DATA *)item->data; + BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SCTP_SET_RCVINFO, + sizeof(rdata->recordinfo), &rdata->recordinfo); + } +#endif + + dtls1_copy_record(s, item); + + OPENSSL_free(item->data); + pitem_free(item); + } + } + + /* Check for timeout */ + if (dtls1_handle_timeout(s) > 0) + goto start; + + /* get new packet if necessary */ + if ((rr->length == 0) || (s->rstate == SSL_ST_READ_BODY)) { + ret = dtls1_get_record(s); + if (ret <= 0) { + ret = dtls1_read_failed(s, ret); + /* anything other than a timeout is an error */ + if (ret <= 0) + return (ret); + else + goto start; + } + } + + if (s->d1->listen && rr->type != SSL3_RT_HANDSHAKE) { + rr->length = 0; + goto start; + } + + /* we now have a packet which can be read and processed */ + + if (s->s3->change_cipher_spec /* set when we receive ChangeCipherSpec, + * reset by ssl3_get_finished */ + && (rr->type != SSL3_RT_HANDSHAKE)) { + /* + * We now have application data between CCS and Finished. Most likely + * the packets were reordered on their way, so buffer the application + * data for later processing rather than dropping the connection. + */ + if (dtls1_buffer_record(s, &(s->d1->buffered_app_data), rr->seq_num) < + 0) { + SSLerr(SSL_F_DTLS1_READ_BYTES, ERR_R_INTERNAL_ERROR); + return -1; + } + rr->length = 0; + goto start; + } + + /* + * If the other end has shut down, throw anything we read away (even in + * 'peek' mode) + */ + if (s->shutdown & SSL_RECEIVED_SHUTDOWN) { + rr->length = 0; + s->rwstate = SSL_NOTHING; + return (0); + } + + if (type == rr->type) { /* SSL3_RT_APPLICATION_DATA or + * SSL3_RT_HANDSHAKE */ + /* + * 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_DTLS1_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) { + rr->length -= n; + rr->off += n; + if (rr->length == 0) { + s->rstate = SSL_ST_READ_HEADER; + rr->off = 0; + } + } +#ifndef OPENSSL_NO_SCTP + /* + * We were about to renegotiate but had to read belated application + * data first, so retry. + */ + if (BIO_dgram_is_sctp(SSL_get_rbio(s)) && + rr->type == SSL3_RT_APPLICATION_DATA && + (s->state == DTLS1_SCTP_ST_SR_READ_SOCK + || s->state == DTLS1_SCTP_ST_CR_READ_SOCK)) { + s->rwstate = SSL_READING; + BIO_clear_retry_flags(SSL_get_rbio(s)); + BIO_set_retry_read(SSL_get_rbio(s)); + } + + /* + * We might had to delay a close_notify alert because of reordered + * app data. If there was an alert and there is no message to read + * anymore, finally set shutdown. + */ + if (BIO_dgram_is_sctp(SSL_get_rbio(s)) && + s->d1->shutdown_received + && !BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s))) { + s->shutdown |= SSL_RECEIVED_SHUTDOWN; + return (0); + } +#endif + 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 k, dest_maxlen = 0; + unsigned char *dest = NULL; + unsigned int *dest_len = NULL; + + if (rr->type == SSL3_RT_HANDSHAKE) { + dest_maxlen = sizeof s->d1->handshake_fragment; + dest = s->d1->handshake_fragment; + dest_len = &s->d1->handshake_fragment_len; + } else if (rr->type == SSL3_RT_ALERT) { + dest_maxlen = sizeof(s->d1->alert_fragment); + dest = s->d1->alert_fragment; + dest_len = &s->d1->alert_fragment_len; + } +#ifndef OPENSSL_NO_HEARTBEATS + else if (rr->type == TLS1_RT_HEARTBEAT) { + dtls1_process_heartbeat(s); + + /* Exit and notify application to read again */ + rr->length = 0; + s->rwstate = SSL_READING; + BIO_clear_retry_flags(SSL_get_rbio(s)); + BIO_set_retry_read(SSL_get_rbio(s)); + return (-1); + } +#endif + /* else it's a CCS message, or application data or wrong */ + else if (rr->type != SSL3_RT_CHANGE_CIPHER_SPEC) { + /* + * Application data while renegotiating is allowed. Try again + * reading. + */ + if (rr->type == SSL3_RT_APPLICATION_DATA) { + BIO *bio; + s->s3->in_read_app_data = 2; + bio = SSL_get_rbio(s); + s->rwstate = SSL_READING; + BIO_clear_retry_flags(bio); + BIO_set_retry_read(bio); + return (-1); + } + + /* Not certain if this is the right error handling */ + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_UNEXPECTED_RECORD); + goto f_err; + } + + if (dest_maxlen > 0) { + /* + * XDTLS: In a pathalogical case, the Client Hello may be + * fragmented--don't always expect dest_maxlen bytes + */ + if (rr->length < dest_maxlen) { +#ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE + /* + * for normal alerts rr->length is 2, while + * dest_maxlen is 7 if we were to handle this + * non-existing alert... + */ + FIX ME +#endif + s->rstate = SSL_ST_READ_HEADER; + rr->length = 0; + goto start; + } + + /* now move 'n' bytes: */ + for (k = 0; k < dest_maxlen; k++) { + dest[k] = rr->data[rr->off++]; + rr->length--; + } + *dest_len = dest_maxlen; + } + } + + /*- + * s->d1->handshake_fragment_len == 12 iff rr->type == SSL3_RT_HANDSHAKE; + * s->d1->alert_fragment_len == 7 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) && + (s->d1->handshake_fragment_len >= DTLS1_HM_HEADER_LENGTH) && + (s->d1->handshake_fragment[0] == SSL3_MT_HELLO_REQUEST) && + (s->session != NULL) && (s->session->cipher != NULL)) { + s->d1->handshake_fragment_len = 0; + + if ((s->d1->handshake_fragment[1] != 0) || + (s->d1->handshake_fragment[2] != 0) || + (s->d1->handshake_fragment[3] != 0)) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_BAD_HELLO_REQUEST); + goto f_err; + } + + /* + * no need to check sequence number on HELLO REQUEST messages + */ + + if (s->msg_callback) + s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, + s->d1->handshake_fragment, 4, s, + s->msg_callback_arg); + + if (SSL_is_init_finished(s) && + !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) && + !s->s3->renegotiate) { + s->d1->handshake_read_seq++; + s->new_session = 1; + ssl3_renegotiate(s); + if (ssl3_renegotiate_check(s)) { + i = s->handshake_func(s); + if (i < 0) + return (i); + if (i == 0) { + SSLerr(SSL_F_DTLS1_READ_BYTES, + SSL_R_SSL_HANDSHAKE_FAILURE); + return (-1); + } + + if (!(s->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->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 (s->d1->alert_fragment_len >= DTLS1_AL_HEADER_LENGTH) { + int alert_level = s->d1->alert_fragment[0]; + int alert_descr = s->d1->alert_fragment[1]; + + s->d1->alert_fragment_len = 0; + + if (s->msg_callback) + s->msg_callback(0, s->version, SSL3_RT_ALERT, + s->d1->alert_fragment, 2, s, s->msg_callback_arg); + + if (s->info_callback != NULL) + cb = s->info_callback; + else if (s->ctx->info_callback != NULL) + cb = s->ctx->info_callback; + + if (cb != NULL) { + j = (alert_level << 8) | alert_descr; + cb(s, SSL_CB_READ_ALERT, j); + } + + if (alert_level == SSL3_AL_WARNING) { + s->s3->warn_alert = alert_descr; + if (alert_descr == SSL_AD_CLOSE_NOTIFY) { +#ifndef OPENSSL_NO_SCTP + /* + * With SCTP and streams the socket may deliver app data + * after a close_notify alert. We have to check this first so + * that nothing gets discarded. + */ + if (BIO_dgram_is_sctp(SSL_get_rbio(s)) && + BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s))) { + s->d1->shutdown_received = 1; + s->rwstate = SSL_READING; + BIO_clear_retry_flags(SSL_get_rbio(s)); + BIO_set_retry_read(SSL_get_rbio(s)); + return -1; + } +#endif + s->shutdown |= SSL_RECEIVED_SHUTDOWN; + return (0); + } +#if 0 + /* XXX: this is a possible improvement in the future */ + /* now check if it's a missing record */ + if (alert_descr == DTLS1_AD_MISSING_HANDSHAKE_MESSAGE) { + unsigned short seq; + unsigned int frag_off; + unsigned char *p = &(s->d1->alert_fragment[2]); + + n2s(p, seq); + n2l3(p, frag_off); + + dtls1_retransmit_message(s, + dtls1_get_queue_priority + (frag->msg_header.seq, 0), frag_off, + &found); + if (!found && SSL_in_init(s)) { + /* + * fprintf( stderr,"in init = %d\n", SSL_in_init(s)); + */ + /* + * requested a message not yet sent, send an alert + * ourselves + */ + ssl3_send_alert(s, SSL3_AL_WARNING, + DTLS1_AD_MISSING_HANDSHAKE_MESSAGE); + } + } +#endif + } else if (alert_level == SSL3_AL_FATAL) { + char tmp[16]; + + s->rwstate = SSL_NOTHING; + s->s3->fatal_alert = alert_descr; + SSLerr(SSL_F_DTLS1_READ_BYTES, + SSL_AD_REASON_OFFSET + alert_descr); + BIO_snprintf(tmp, sizeof tmp, "%d", alert_descr); + ERR_add_error_data(2, "SSL alert number ", tmp); + s->shutdown |= SSL_RECEIVED_SHUTDOWN; + SSL_CTX_remove_session(s->ctx, s->session); + return (0); + } else { + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_UNKNOWN_ALERT_TYPE); + goto f_err; + } + + goto start; + } + + if (s->shutdown & SSL_SENT_SHUTDOWN) { /* but we have not received a + * shutdown */ + s->rwstate = SSL_NOTHING; + rr->length = 0; + return (0); + } + + if (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC) { + struct ccs_header_st ccs_hdr; + unsigned int ccs_hdr_len = DTLS1_CCS_HEADER_LENGTH; + + dtls1_get_ccs_header(rr->data, &ccs_hdr); + + if (s->version == DTLS1_BAD_VER) + ccs_hdr_len = 3; + + /* + * 'Change Cipher Spec' is just a single byte, so we know exactly + * what the record payload has to look like + */ + /* XDTLS: check that epoch is consistent */ + if ((rr->length != ccs_hdr_len) || + (rr->off != 0) || (rr->data[0] != SSL3_MT_CCS)) { + i = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_BAD_CHANGE_CIPHER_SPEC); + goto err; + } + + rr->length = 0; + + if (s->msg_callback) + s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC, + rr->data, 1, s, s->msg_callback_arg); + + /* + * We can't process a CCS now, because previous handshake messages + * are still missing, so just drop it. + */ + if (!s->d1->change_cipher_spec_ok) { + goto start; + } + + s->d1->change_cipher_spec_ok = 0; + + s->s3->change_cipher_spec = 1; + if (!ssl3_do_change_cipher_spec(s)) + goto err; + + /* do this whenever CCS is processed */ + dtls1_reset_seq_numbers(s, SSL3_CC_READ); + + if (s->version == DTLS1_BAD_VER) + s->d1->handshake_read_seq++; + +#ifndef OPENSSL_NO_SCTP + /* + * Remember that a CCS has been received, so that an old key of + * SCTP-Auth can be deleted when a CCS is sent. Will be ignored if no + * SCTP is used + */ + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD, 1, NULL); +#endif + + goto start; + } + + /* + * Unexpected handshake message (Client Hello, or protocol violation) + */ + if ((s->d1->handshake_fragment_len >= DTLS1_HM_HEADER_LENGTH) && + !s->in_handshake) { + struct hm_header_st msg_hdr; + + /* this may just be a stale retransmit */ + dtls1_get_message_header(rr->data, &msg_hdr); + if (rr->epoch != s->d1->r_epoch) { + rr->length = 0; + goto start; + } + + /* + * If we are server, we may have a repeated FINISHED of the client + * here, then retransmit our CCS and FINISHED. + */ + if (msg_hdr.type == SSL3_MT_FINISHED) { + if (dtls1_check_timeout_num(s) < 0) + return -1; + + dtls1_retransmit_buffered_messages(s); + rr->length = 0; + goto start; + } + + if (((s->state & SSL_ST_MASK) == SSL_ST_OK) && + !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS)) { +#if 0 /* worked only because C operator preferences + * are not as expected (and because this is + * not really needed for clients except for + * detecting protocol violations): */ + s->state = SSL_ST_BEFORE | (s->server) + ? SSL_ST_ACCEPT : SSL_ST_CONNECT; +#else + s->state = s->server ? SSL_ST_ACCEPT : SSL_ST_CONNECT; +#endif + s->renegotiate = 1; + s->new_session = 1; + } + i = s->handshake_func(s); + if (i < 0) + return (i); + if (i == 0) { + SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_SSL_HANDSHAKE_FAILURE); + return (-1); + } + + if (!(s->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->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: +#ifndef OPENSSL_NO_TLS + /* TLS just ignores unknown message types */ + if (s->version == TLS1_VERSION) { + rr->length = 0; + goto start; + } +#endif + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_DTLS1_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->in_handshake is set, but that should not + * happen when type != rr->type + */ + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_DTLS1_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 (s->s3->in_read_app_data && + (s->s3->total_renegotiations != 0) && + (((s->state & SSL_ST_CONNECT) && + (s->state >= SSL3_ST_CW_CLNT_HELLO_A) && + (s->state <= SSL3_ST_CR_SRVR_HELLO_A) + ) || ((s->state & SSL_ST_ACCEPT) && + (s->state <= SSL3_ST_SW_HELLO_REQ_A) && + (s->state >= SSL3_ST_SR_CLNT_HELLO_A) + ) + )) { + s->s3->in_read_app_data = 2; + return (-1); + } else { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_DTLS1_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 dtls1_write_app_data_bytes(SSL *s, int type, const void *buf_, int len) +{ + int i; + +#ifndef OPENSSL_NO_SCTP + /* + * Check if we have to continue an interrupted handshake for reading + * belated app data with SCTP. + */ + if ((SSL_in_init(s) && !s->in_handshake) || + (BIO_dgram_is_sctp(SSL_get_wbio(s)) && + (s->state == DTLS1_SCTP_ST_SR_READ_SOCK + || s->state == DTLS1_SCTP_ST_CR_READ_SOCK))) +#else + if (SSL_in_init(s) && !s->in_handshake) +#endif + { + i = s->handshake_func(s); + if (i < 0) + return (i); + if (i == 0) { + SSLerr(SSL_F_DTLS1_WRITE_APP_DATA_BYTES, + SSL_R_SSL_HANDSHAKE_FAILURE); + return -1; + } + } + + if (len > SSL3_RT_MAX_PLAIN_LENGTH) { + SSLerr(SSL_F_DTLS1_WRITE_APP_DATA_BYTES, SSL_R_DTLS_MESSAGE_TOO_BIG); + return -1; + } + + i = dtls1_write_bytes(s, type, buf_, len); + return i; +} + + /* + * this only happens when a client hello is received and a handshake + * is started. + */ +static int +have_handshake_fragment(SSL *s, int type, unsigned char *buf, + int len, int peek) +{ + + if ((type == SSL3_RT_HANDSHAKE) && (s->d1->handshake_fragment_len > 0)) + /* (partially) satisfy request from storage */ + { + unsigned char *src = s->d1->handshake_fragment; + unsigned char *dst = buf; + unsigned int k, n; + + /* peek == 0 */ + n = 0; + while ((len > 0) && (s->d1->handshake_fragment_len > 0)) { + *dst++ = *src++; + len--; + s->d1->handshake_fragment_len--; + n++; + } + /* move any remaining fragment bytes: */ + for (k = 0; k < s->d1->handshake_fragment_len; k++) + s->d1->handshake_fragment[k] = *src++; + return n; + } + + return 0; +} + +/* + * 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 dtls1_write_bytes(SSL *s, int type, const void *buf, int len) +{ + int i; + + OPENSSL_assert(len <= SSL3_RT_MAX_PLAIN_LENGTH); + s->rwstate = SSL_NOTHING; + i = do_dtls1_write(s, type, buf, len, 0); + return i; +} + +int do_dtls1_write(SSL *s, int type, const unsigned char *buf, + unsigned int len, int create_empty_fragment) +{ + unsigned char *p, *pseq; + int i, mac_size, clear = 0; + int prefix_len = 0; + int eivlen; + SSL3_RECORD *wr; + SSL3_BUFFER *wb; + SSL_SESSION *sess; + + /* + * first check if there is a SSL3_BUFFER still being written out. This + * will happen with non blocking IO + */ + if (s->s3->wbuf.left != 0) { + OPENSSL_assert(0); /* XDTLS: want to see if we ever get here */ + 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 */ + } + + if (len == 0 && !create_empty_fragment) + return 0; + + wr = &(s->s3->wrec); + wb = &(s->s3->wbuf); + sess = s->session; + + if ((sess == NULL) || + (s->enc_write_ctx == NULL) || (EVP_MD_CTX_md(s->write_hash) == NULL)) + clear = 1; + + if (clear) + mac_size = 0; + else { + mac_size = EVP_MD_CTX_size(s->write_hash); + if (mac_size < 0) + goto err; + } + + /* DTLS implements explicit IV, so no need for empty fragments */ +#if 0 + /* + * 'create_empty_fragment' is true only when this function calls itself + */ + if (!clear && !create_empty_fragment && !s->s3->empty_fragment_done + && SSL_version(s) != DTLS1_VERSION && SSL_version(s) != DTLS1_BAD_VER) + { + /* + * countermeasure against known-IV weakness in CBC ciphersuites (see + * http://www.openssl.org/~bodo/tls-cbc.txt) + */ + + if (s->s3->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 = s->method->do_ssl_write(s, type, buf, 0, 1); + if (prefix_len <= 0) + goto err; + + if (s->s3->wbuf.len < + (size_t)prefix_len + SSL3_RT_MAX_PACKET_SIZE) { + /* insufficient space */ + SSLerr(SSL_F_DO_DTLS1_WRITE, ERR_R_INTERNAL_ERROR); + goto err; + } + } + + s->s3->empty_fragment_done = 1; + } +#endif + p = wb->buf + prefix_len; + + /* write the header */ + + *(p++) = type & 0xff; + wr->type = type; + /* + * Special case: for hello verify request, client version 1.0 and we + * haven't decided which version to use yet send back using version 1.0 + * header: otherwise some clients will ignore it. + */ + if (s->method->version == DTLS_ANY_VERSION) { + *(p++) = DTLS1_VERSION >> 8; + *(p++) = DTLS1_VERSION & 0xff; + } else { + *(p++) = s->version >> 8; + *(p++) = s->version & 0xff; + } + + /* field where we are to write out packet epoch, seq num and len */ + pseq = p; + p += 10; + + /* Explicit IV length, block ciphers appropriate version flag */ + if (s->enc_write_ctx) { + int mode = EVP_CIPHER_CTX_mode(s->enc_write_ctx); + if (mode == EVP_CIPH_CBC_MODE) { + eivlen = EVP_CIPHER_CTX_iv_length(s->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 + eivlen = 0; + + /* lets setup the record stuff. */ + wr->data = p + eivlen; /* make room for IV in case of CBC */ + wr->length = (int)len; + wr->input = (unsigned char *)buf; + + /* + * we now 'read' from wr->input, wr->length bytes into wr->data + */ + + /* first we compress */ + if (s->compress != NULL) { + if (!ssl3_do_compress(s)) { + SSLerr(SSL_F_DO_DTLS1_WRITE, SSL_R_COMPRESSION_FAILURE); + goto err; + } + } else { + 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->ssl3_enc->mac(s, &(p[wr->length + eivlen]), 1) < 0) + goto err; + wr->length += mac_size; + } + + /* this is true regardless of mac size */ + wr->input = p; + wr->data = p; + + if (eivlen) + wr->length += eivlen; + + if (s->method->ssl3_enc->enc(s, 1) < 1) + goto err; + + /* record length after mac and block padding */ + /* + * if (type == SSL3_RT_APPLICATION_DATA || (type == SSL3_RT_ALERT && ! + * SSL_in_init(s))) + */ + + /* there's only one epoch between handshake and app data */ + + s2n(s->d1->w_epoch, pseq); + + /* XDTLS: ?? */ + /* + * else s2n(s->d1->handshake_epoch, pseq); + */ + + memcpy(pseq, &(s->s3->write_sequence[2]), 6); + pseq += 6; + s2n(wr->length, pseq); + + if (s->msg_callback) + s->msg_callback(1, 0, SSL3_RT_HEADER, pseq - DTLS1_RT_HEADER_LENGTH, + DTLS1_RT_HEADER_LENGTH, s, s->msg_callback_arg); + + /* + * 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 += DTLS1_RT_HEADER_LENGTH; + +#if 0 /* this is now done at the message layer */ + /* buffer the record, making it easy to handle retransmits */ + if (type == SSL3_RT_HANDSHAKE || type == SSL3_RT_CHANGE_CIPHER_SPEC) + dtls1_buffer_record(s, wr->data, wr->length, + *((PQ_64BIT *) & (s->s3->write_sequence[0]))); +#endif + + ssl3_record_sequence_update(&(s->s3->write_sequence[0])); + + 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; + wb->offset = 0; + + /* + * memorize arguments so that ssl3_write_pending can detect bad write + * retries later + */ + s->s3->wpend_tot = len; + s->s3->wpend_buf = buf; + s->s3->wpend_type = type; + s->s3->wpend_ret = len; + + /* we now just need to write the buffer */ + return ssl3_write_pending(s, type, buf, len); + err: + return -1; +} + +static int dtls1_record_replay_check(SSL *s, DTLS1_BITMAP *bitmap) +{ + int cmp; + unsigned int shift; + const unsigned char *seq = s->s3->read_sequence; + + cmp = satsub64be(seq, bitmap->max_seq_num); + if (cmp > 0) { + memcpy(s->s3->rrec.seq_num, seq, 8); + return 1; /* this record in new */ + } + shift = -cmp; + if (shift >= sizeof(bitmap->map) * 8) + return 0; /* stale, outside the window */ + else if (bitmap->map & (1UL << shift)) + return 0; /* record previously received */ + + memcpy(s->s3->rrec.seq_num, seq, 8); + return 1; +} + +static void dtls1_record_bitmap_update(SSL *s, DTLS1_BITMAP *bitmap) +{ + int cmp; + unsigned int shift; + const unsigned char *seq = s->s3->read_sequence; + + cmp = satsub64be(seq, bitmap->max_seq_num); + if (cmp > 0) { + shift = cmp; + if (shift < sizeof(bitmap->map) * 8) + bitmap->map <<= shift, bitmap->map |= 1UL; + else + bitmap->map = 1UL; + memcpy(bitmap->max_seq_num, seq, 8); + } else { + shift = -cmp; + if (shift < sizeof(bitmap->map) * 8) + bitmap->map |= 1UL << shift; + } +} + +int dtls1_dispatch_alert(SSL *s) +{ + int i, j; + void (*cb) (const SSL *ssl, int type, int val) = NULL; + unsigned char buf[DTLS1_AL_HEADER_LENGTH]; + unsigned char *ptr = &buf[0]; + + s->s3->alert_dispatch = 0; + + memset(buf, 0x00, sizeof(buf)); + *ptr++ = s->s3->send_alert[0]; + *ptr++ = s->s3->send_alert[1]; + +#ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE + if (s->s3->send_alert[1] == DTLS1_AD_MISSING_HANDSHAKE_MESSAGE) { + s2n(s->d1->handshake_read_seq, ptr); +# if 0 + if (s->d1->r_msg_hdr.frag_off == 0) + /* + * waiting for a new msg + */ + else + s2n(s->d1->r_msg_hdr.seq, ptr); /* partial msg read */ +# endif + +# if 0 + fprintf(stderr, + "s->d1->handshake_read_seq = %d, s->d1->r_msg_hdr.seq = %d\n", + s->d1->handshake_read_seq, s->d1->r_msg_hdr.seq); +# endif + l2n3(s->d1->r_msg_hdr.frag_off, ptr); + } +#endif + + i = do_dtls1_write(s, SSL3_RT_ALERT, &buf[0], sizeof(buf), 0); + if (i <= 0) { + s->s3->alert_dispatch = 1; + /* fprintf( stderr, "not done with alert\n" ); */ + } else { + if (s->s3->send_alert[0] == SSL3_AL_FATAL +#ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE + || s->s3->send_alert[1] == DTLS1_AD_MISSING_HANDSHAKE_MESSAGE +#endif + ) + (void)BIO_flush(s->wbio); + + if (s->msg_callback) + s->msg_callback(1, s->version, SSL3_RT_ALERT, s->s3->send_alert, + 2, s, s->msg_callback_arg); + + if (s->info_callback != NULL) + cb = s->info_callback; + else if (s->ctx->info_callback != NULL) + cb = s->ctx->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); +} + +static DTLS1_BITMAP *dtls1_get_bitmap(SSL *s, SSL3_RECORD *rr, + unsigned int *is_next_epoch) +{ + + *is_next_epoch = 0; + + /* In current epoch, accept HM, CCS, DATA, & ALERT */ + if (rr->epoch == s->d1->r_epoch) + return &s->d1->bitmap; + + /* Only HM and ALERT messages can be from the next epoch */ + else if (rr->epoch == (unsigned long)(s->d1->r_epoch + 1) && + (rr->type == SSL3_RT_HANDSHAKE || rr->type == SSL3_RT_ALERT)) { + *is_next_epoch = 1; + return &s->d1->next_bitmap; + } + + return NULL; +} + +#if 0 +static int +dtls1_record_needs_buffering(SSL *s, SSL3_RECORD *rr, + unsigned short *priority, unsigned long *offset) +{ + + /* alerts are passed up immediately */ + if (rr->type == SSL3_RT_APPLICATION_DATA || rr->type == SSL3_RT_ALERT) + return 0; + + /* + * Only need to buffer if a handshake is underway. (this implies that + * Hello Request and Client Hello are passed up immediately) + */ + if (SSL_in_init(s)) { + unsigned char *data = rr->data; + /* need to extract the HM/CCS sequence number here */ + if (rr->type == SSL3_RT_HANDSHAKE || + rr->type == SSL3_RT_CHANGE_CIPHER_SPEC) { + unsigned short seq_num; + struct hm_header_st msg_hdr; + struct ccs_header_st ccs_hdr; + + if (rr->type == SSL3_RT_HANDSHAKE) { + dtls1_get_message_header(data, &msg_hdr); + seq_num = msg_hdr.seq; + *offset = msg_hdr.frag_off; + } else { + dtls1_get_ccs_header(data, &ccs_hdr); + seq_num = ccs_hdr.seq; + *offset = 0; + } + + /* + * this is either a record we're waiting for, or a retransmit of + * something we happened to previously receive (higher layers + * will drop the repeat silently + */ + if (seq_num < s->d1->handshake_read_seq) + return 0; + if (rr->type == SSL3_RT_HANDSHAKE && + seq_num == s->d1->handshake_read_seq && + msg_hdr.frag_off < s->d1->r_msg_hdr.frag_off) + return 0; + else if (seq_num == s->d1->handshake_read_seq && + (rr->type == SSL3_RT_CHANGE_CIPHER_SPEC || + msg_hdr.frag_off == s->d1->r_msg_hdr.frag_off)) + return 0; + else { + *priority = seq_num; + return 1; + } + } else /* unknown record type */ + return 0; + } + + return 0; +} +#endif + +void dtls1_reset_seq_numbers(SSL *s, int rw) +{ + unsigned char *seq; + unsigned int seq_bytes = sizeof(s->s3->read_sequence); + + if (rw & SSL3_CC_READ) { + seq = s->s3->read_sequence; + s->d1->r_epoch++; + memcpy(&(s->d1->bitmap), &(s->d1->next_bitmap), sizeof(DTLS1_BITMAP)); + memset(&(s->d1->next_bitmap), 0x00, sizeof(DTLS1_BITMAP)); + } else { + seq = s->s3->write_sequence; + memcpy(s->d1->last_write_sequence, seq, + sizeof(s->s3->write_sequence)); + s->d1->w_epoch++; + } + + memset(seq, 0x00, seq_bytes); +} diff --git a/thirdparty/openssl/ssl/d1_srtp.c b/thirdparty/openssl/ssl/d1_srtp.c new file mode 100644 index 0000000000..64d0634a38 --- /dev/null +++ b/thirdparty/openssl/ssl/d1_srtp.c @@ -0,0 +1,448 @@ +/* ssl/t1_lib.c */ +/* 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-2006 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). + * + */ +/* + * DTLS code by Eric Rescorla <ekr@rtfm.com> + * + * Copyright (C) 2006, Network Resonance, Inc. Copyright (C) 2011, RTFM, Inc. + */ + +#include <stdio.h> +#include <openssl/objects.h> +#include "ssl_locl.h" +#include "srtp.h" + +#ifndef OPENSSL_NO_SRTP + +static SRTP_PROTECTION_PROFILE srtp_known_profiles[] = { + { + "SRTP_AES128_CM_SHA1_80", + SRTP_AES128_CM_SHA1_80, + }, + { + "SRTP_AES128_CM_SHA1_32", + SRTP_AES128_CM_SHA1_32, + }, +# if 0 + { + "SRTP_NULL_SHA1_80", + SRTP_NULL_SHA1_80, + }, + { + "SRTP_NULL_SHA1_32", + SRTP_NULL_SHA1_32, + }, +# endif + {0} +}; + +static int find_profile_by_name(char *profile_name, + SRTP_PROTECTION_PROFILE **pptr, unsigned len) +{ + SRTP_PROTECTION_PROFILE *p; + + p = srtp_known_profiles; + while (p->name) { + if ((len == strlen(p->name)) && !strncmp(p->name, profile_name, len)) { + *pptr = p; + return 0; + } + + p++; + } + + return 1; +} + +static int ssl_ctx_make_profiles(const char *profiles_string, + STACK_OF(SRTP_PROTECTION_PROFILE) **out) +{ + STACK_OF(SRTP_PROTECTION_PROFILE) *profiles; + + char *col; + char *ptr = (char *)profiles_string; + + SRTP_PROTECTION_PROFILE *p; + + if (!(profiles = sk_SRTP_PROTECTION_PROFILE_new_null())) { + SSLerr(SSL_F_SSL_CTX_MAKE_PROFILES, + SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES); + return 1; + } + + do { + col = strchr(ptr, ':'); + + if (!find_profile_by_name(ptr, &p, + col ? col - ptr : (int)strlen(ptr))) { + if (sk_SRTP_PROTECTION_PROFILE_find(profiles, p) >= 0) { + SSLerr(SSL_F_SSL_CTX_MAKE_PROFILES, + SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); + sk_SRTP_PROTECTION_PROFILE_free(profiles); + return 1; + } + + sk_SRTP_PROTECTION_PROFILE_push(profiles, p); + } else { + SSLerr(SSL_F_SSL_CTX_MAKE_PROFILES, + SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE); + sk_SRTP_PROTECTION_PROFILE_free(profiles); + return 1; + } + + if (col) + ptr = col + 1; + } while (col); + + *out = profiles; + + return 0; +} + +int SSL_CTX_set_tlsext_use_srtp(SSL_CTX *ctx, const char *profiles) +{ + return ssl_ctx_make_profiles(profiles, &ctx->srtp_profiles); +} + +int SSL_set_tlsext_use_srtp(SSL *s, const char *profiles) +{ + return ssl_ctx_make_profiles(profiles, &s->srtp_profiles); +} + +STACK_OF(SRTP_PROTECTION_PROFILE) *SSL_get_srtp_profiles(SSL *s) +{ + if (s != NULL) { + if (s->srtp_profiles != NULL) { + return s->srtp_profiles; + } else if ((s->ctx != NULL) && (s->ctx->srtp_profiles != NULL)) { + return s->ctx->srtp_profiles; + } + } + + return NULL; +} + +SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile(SSL *s) +{ + return s->srtp_profile; +} + +/* + * Note: this function returns 0 length if there are no profiles specified + */ +int ssl_add_clienthello_use_srtp_ext(SSL *s, unsigned char *p, int *len, + int maxlen) +{ + int ct = 0; + int i; + STACK_OF(SRTP_PROTECTION_PROFILE) *clnt = 0; + SRTP_PROTECTION_PROFILE *prof; + + clnt = SSL_get_srtp_profiles(s); + ct = sk_SRTP_PROTECTION_PROFILE_num(clnt); /* -1 if clnt == 0 */ + + if (p) { + if (ct == 0) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_USE_SRTP_EXT, + SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST); + return 1; + } + + if ((2 + ct * 2 + 1) > maxlen) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_USE_SRTP_EXT, + SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG); + return 1; + } + + /* Add the length */ + s2n(ct * 2, p); + for (i = 0; i < ct; i++) { + prof = sk_SRTP_PROTECTION_PROFILE_value(clnt, i); + s2n(prof->id, p); + } + + /* Add an empty use_mki value */ + *p++ = 0; + } + + *len = 2 + ct * 2 + 1; + + return 0; +} + +int ssl_parse_clienthello_use_srtp_ext(SSL *s, unsigned char *d, int len, + int *al) +{ + SRTP_PROTECTION_PROFILE *sprof; + STACK_OF(SRTP_PROTECTION_PROFILE) *srvr; + int ct; + int mki_len; + int i, srtp_pref; + unsigned int id; + + /* Length value + the MKI length */ + if (len < 3) { + SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_USE_SRTP_EXT, + SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); + *al = SSL_AD_DECODE_ERROR; + return 1; + } + + /* Pull off the length of the cipher suite list */ + n2s(d, ct); + len -= 2; + + /* Check that it is even */ + if (ct % 2) { + SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_USE_SRTP_EXT, + SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); + *al = SSL_AD_DECODE_ERROR; + return 1; + } + + /* Check that lengths are consistent */ + if (len < (ct + 1)) { + SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_USE_SRTP_EXT, + SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); + *al = SSL_AD_DECODE_ERROR; + return 1; + } + + srvr = SSL_get_srtp_profiles(s); + s->srtp_profile = NULL; + /* Search all profiles for a match initially */ + srtp_pref = sk_SRTP_PROTECTION_PROFILE_num(srvr); + + while (ct) { + n2s(d, id); + ct -= 2; + len -= 2; + + /* + * Only look for match in profiles of higher preference than + * current match. + * If no profiles have been have been configured then this + * does nothing. + */ + for (i = 0; i < srtp_pref; i++) { + sprof = sk_SRTP_PROTECTION_PROFILE_value(srvr, i); + if (sprof->id == id) { + s->srtp_profile = sprof; + srtp_pref = i; + break; + } + } + } + + /* + * Now extract the MKI value as a sanity check, but discard it for now + */ + mki_len = *d; + d++; + len--; + + if (mki_len != len) { + SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_USE_SRTP_EXT, + SSL_R_BAD_SRTP_MKI_VALUE); + *al = SSL_AD_DECODE_ERROR; + return 1; + } + + return 0; +} + +int ssl_add_serverhello_use_srtp_ext(SSL *s, unsigned char *p, int *len, + int maxlen) +{ + if (p) { + if (maxlen < 5) { + SSLerr(SSL_F_SSL_ADD_SERVERHELLO_USE_SRTP_EXT, + SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG); + return 1; + } + + if (s->srtp_profile == 0) { + SSLerr(SSL_F_SSL_ADD_SERVERHELLO_USE_SRTP_EXT, + SSL_R_USE_SRTP_NOT_NEGOTIATED); + return 1; + } + s2n(2, p); + s2n(s->srtp_profile->id, p); + *p++ = 0; + } + *len = 5; + + return 0; +} + +int ssl_parse_serverhello_use_srtp_ext(SSL *s, unsigned char *d, int len, + int *al) +{ + unsigned id; + int i; + int ct; + + STACK_OF(SRTP_PROTECTION_PROFILE) *clnt; + SRTP_PROTECTION_PROFILE *prof; + + if (len != 5) { + SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_USE_SRTP_EXT, + SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); + *al = SSL_AD_DECODE_ERROR; + return 1; + } + + n2s(d, ct); + if (ct != 2) { + SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_USE_SRTP_EXT, + SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); + *al = SSL_AD_DECODE_ERROR; + return 1; + } + + n2s(d, id); + if (*d) { /* Must be no MKI, since we never offer one */ + SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_USE_SRTP_EXT, + SSL_R_BAD_SRTP_MKI_VALUE); + *al = SSL_AD_ILLEGAL_PARAMETER; + return 1; + } + + clnt = SSL_get_srtp_profiles(s); + + /* Throw an error if the server gave us an unsolicited extension */ + if (clnt == NULL) { + SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_USE_SRTP_EXT, + SSL_R_NO_SRTP_PROFILES); + *al = SSL_AD_DECODE_ERROR; + return 1; + } + + /* + * Check to see if the server gave us something we support (and + * presumably offered) + */ + for (i = 0; i < sk_SRTP_PROTECTION_PROFILE_num(clnt); i++) { + prof = sk_SRTP_PROTECTION_PROFILE_value(clnt, i); + + if (prof->id == id) { + s->srtp_profile = prof; + *al = 0; + return 0; + } + } + + SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_USE_SRTP_EXT, + SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); + *al = SSL_AD_DECODE_ERROR; + return 1; +} + +#endif diff --git a/thirdparty/openssl/ssl/d1_srvr.c b/thirdparty/openssl/ssl/d1_srvr.c new file mode 100644 index 0000000000..e677d880f0 --- /dev/null +++ b/thirdparty/openssl/ssl/d1_srvr.c @@ -0,0 +1,980 @@ +/* ssl/d1_srvr.c */ +/* + * DTLS implementation written by Nagendra Modadugu + * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. + */ +/* ==================================================================== + * Copyright (c) 1999-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 (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.] + */ + +#include <stdio.h> +#include "ssl_locl.h" +#include <openssl/buffer.h> +#include <openssl/rand.h> +#include <openssl/objects.h> +#include <openssl/evp.h> +#include <openssl/x509.h> +#include <openssl/md5.h> +#include <openssl/bn.h> +#ifndef OPENSSL_NO_DH +# include <openssl/dh.h> +#endif + +static const SSL_METHOD *dtls1_get_server_method(int ver); +static int dtls1_send_hello_verify_request(SSL *s); + +static const SSL_METHOD *dtls1_get_server_method(int ver) +{ + if (ver == DTLS_ANY_VERSION) + return DTLS_server_method(); + else if (ver == DTLS1_VERSION) + return DTLSv1_server_method(); + else if (ver == DTLS1_2_VERSION) + return DTLSv1_2_server_method(); + else + return NULL; +} + +IMPLEMENT_dtls1_meth_func(DTLS1_VERSION, + DTLSv1_server_method, + dtls1_accept, + ssl_undefined_function, + dtls1_get_server_method, DTLSv1_enc_data) + +IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION, + DTLSv1_2_server_method, + dtls1_accept, + ssl_undefined_function, + dtls1_get_server_method, DTLSv1_2_enc_data) + +IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION, + DTLS_server_method, + dtls1_accept, + ssl_undefined_function, + dtls1_get_server_method, DTLSv1_2_enc_data) + +int dtls1_accept(SSL *s) +{ + BUF_MEM *buf; + unsigned long Time = (unsigned long)time(NULL); + void (*cb) (const SSL *ssl, int type, int val) = NULL; + unsigned long alg_k; + int ret = -1; + int new_state, state, skip = 0; + int listen; +#ifndef OPENSSL_NO_SCTP + unsigned char sctpauthkey[64]; + char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)]; +#endif + + RAND_add(&Time, sizeof(Time), 0); + ERR_clear_error(); + clear_sys_error(); + + if (s->info_callback != NULL) + cb = s->info_callback; + else if (s->ctx->info_callback != NULL) + cb = s->ctx->info_callback; + + listen = s->d1->listen; + + /* init things to blank */ + s->in_handshake++; + if (!SSL_in_init(s) || SSL_in_before(s)) + SSL_clear(s); + + s->d1->listen = listen; +#ifndef OPENSSL_NO_SCTP + /* + * Notify SCTP BIO socket to enter handshake mode and prevent stream + * identifier other than 0. Will be ignored if no SCTP is used. + */ + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE, + s->in_handshake, NULL); +#endif + + if (s->cert == NULL) { + SSLerr(SSL_F_DTLS1_ACCEPT, SSL_R_NO_CERTIFICATE_SET); + return (-1); + } +#ifndef OPENSSL_NO_HEARTBEATS + /* + * If we're awaiting a HeartbeatResponse, pretend we already got and + * don't await it anymore, because Heartbeats don't make sense during + * handshakes anyway. + */ + if (s->tlsext_hb_pending) { + dtls1_stop_timer(s); + s->tlsext_hb_pending = 0; + s->tlsext_hb_seq++; + } +#endif + + for (;;) { + state = s->state; + + switch (s->state) { + case SSL_ST_RENEGOTIATE: + s->renegotiate = 1; + /* s->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 & 0xff00) != (DTLS1_VERSION & 0xff00)) { + SSLerr(SSL_F_DTLS1_ACCEPT, ERR_R_INTERNAL_ERROR); + return -1; + } + s->type = SSL_ST_ACCEPT; + + if (s->init_buf == NULL) { + if ((buf = BUF_MEM_new()) == NULL) { + ret = -1; + s->state = SSL_ST_ERR; + goto end; + } + if (!BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) { + BUF_MEM_free(buf); + ret = -1; + s->state = SSL_ST_ERR; + goto end; + } + s->init_buf = buf; + } + + if (!ssl3_setup_buffers(s)) { + ret = -1; + s->state = SSL_ST_ERR; + goto end; + } + + s->init_num = 0; + s->d1->change_cipher_spec_ok = 0; + /* + * Should have been reset by ssl3_get_finished, too. + */ + s->s3->change_cipher_spec = 0; + + if (s->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 :-) ...but not with + * SCTP :-) + */ +#ifndef OPENSSL_NO_SCTP + if (!BIO_dgram_is_sctp(SSL_get_wbio(s))) +#endif + if (!ssl_init_wbio_buffer(s, 1)) { + ret = -1; + s->state = SSL_ST_ERR; + goto end; + } + + ssl3_init_finished_mac(s); + s->state = SSL3_ST_SR_CLNT_HELLO_A; + s->ctx->stats.sess_accept++; + } else if (!s->s3->send_connection_binding && + !(s->options & + SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) { + /* + * Server attempting to renegotiate with client that doesn't + * support secure renegotiation. + */ + SSLerr(SSL_F_DTLS1_ACCEPT, + SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED); + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); + ret = -1; + s->state = SSL_ST_ERR; + goto end; + } else { + /* + * s->state == SSL_ST_RENEGOTIATE, we will just send a + * HelloRequest + */ + s->ctx->stats.sess_accept_renegotiate++; + s->state = SSL3_ST_SW_HELLO_REQ_A; + } + + break; + + case SSL3_ST_SW_HELLO_REQ_A: + case SSL3_ST_SW_HELLO_REQ_B: + + s->shutdown = 0; + dtls1_clear_record_buffer(s); + dtls1_start_timer(s); + ret = ssl3_send_hello_request(s); + if (ret <= 0) + goto end; + s->s3->tmp.next_state = SSL3_ST_SR_CLNT_HELLO_A; + s->state = SSL3_ST_SW_FLUSH; + s->init_num = 0; + + ssl3_init_finished_mac(s); + break; + + case SSL3_ST_SW_HELLO_REQ_C: + s->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->shutdown = 0; + ret = ssl3_get_client_hello(s); + if (ret <= 0) + goto end; + dtls1_stop_timer(s); + + if (ret == 1 && (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE)) + s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A; + else + s->state = SSL3_ST_SW_SRVR_HELLO_A; + + s->init_num = 0; + + /* + * Reflect ClientHello sequence to remain stateless while + * listening + */ + if (listen) { + memcpy(s->s3->write_sequence, s->s3->read_sequence, + sizeof(s->s3->write_sequence)); + } + + /* If we're just listening, stop here */ + if (listen && s->state == SSL3_ST_SW_SRVR_HELLO_A) { + ret = 2; + s->d1->listen = 0; + /* + * Set expected sequence numbers to continue the handshake. + */ + s->d1->handshake_read_seq = 2; + s->d1->handshake_write_seq = 1; + s->d1->next_handshake_write_seq = 1; + goto end; + } + + break; + + case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A: + case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B: + + ret = dtls1_send_hello_verify_request(s); + if (ret <= 0) + goto end; + s->state = SSL3_ST_SW_FLUSH; + s->s3->tmp.next_state = SSL3_ST_SR_CLNT_HELLO_A; + + /* HelloVerifyRequest resets Finished MAC */ + if (s->version != DTLS1_BAD_VER) + ssl3_init_finished_mac(s); + break; + +#ifndef OPENSSL_NO_SCTP + case DTLS1_SCTP_ST_SR_READ_SOCK: + + if (BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s))) { + s->s3->in_read_app_data = 2; + s->rwstate = SSL_READING; + BIO_clear_retry_flags(SSL_get_rbio(s)); + BIO_set_retry_read(SSL_get_rbio(s)); + ret = -1; + goto end; + } + + s->state = SSL3_ST_SR_FINISHED_A; + break; + + case DTLS1_SCTP_ST_SW_WRITE_SOCK: + ret = BIO_dgram_sctp_wait_for_dry(SSL_get_wbio(s)); + if (ret < 0) + goto end; + + if (ret == 0) { + if (s->d1->next_state != SSL_ST_OK) { + s->s3->in_read_app_data = 2; + s->rwstate = SSL_READING; + BIO_clear_retry_flags(SSL_get_rbio(s)); + BIO_set_retry_read(SSL_get_rbio(s)); + ret = -1; + goto end; + } + } + + s->state = s->d1->next_state; + break; +#endif + + case SSL3_ST_SW_SRVR_HELLO_A: + case SSL3_ST_SW_SRVR_HELLO_B: + s->renegotiate = 2; + dtls1_start_timer(s); + ret = ssl3_send_server_hello(s); + if (ret <= 0) + goto end; + + if (s->hit) { +#ifndef OPENSSL_NO_SCTP + /* + * Add new shared key for SCTP-Auth, will be ignored if no + * SCTP used. + */ + snprintf((char *)labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL), + DTLS1_SCTP_AUTH_LABEL); + + if (SSL_export_keying_material(s, sctpauthkey, + sizeof(sctpauthkey), labelbuffer, + sizeof(labelbuffer), NULL, 0, 0) <= 0) { + ret = -1; + s->state = SSL_ST_ERR; + goto end; + } + + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY, + sizeof(sctpauthkey), sctpauthkey); +#endif +#ifndef OPENSSL_NO_TLSEXT + if (s->tlsext_ticket_expected) + s->state = SSL3_ST_SW_SESSION_TICKET_A; + else + s->state = SSL3_ST_SW_CHANGE_A; +#else + s->state = SSL3_ST_SW_CHANGE_A; +#endif + } else + s->state = SSL3_ST_SW_CERT_A; + s->init_num = 0; + break; + + case SSL3_ST_SW_CERT_A: + case SSL3_ST_SW_CERT_B: + /* Check if it is anon DH or normal PSK */ + if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) + && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) { + dtls1_start_timer(s); + ret = ssl3_send_server_certificate(s); + if (ret <= 0) + goto end; +#ifndef OPENSSL_NO_TLSEXT + if (s->tlsext_status_expected) + s->state = SSL3_ST_SW_CERT_STATUS_A; + else + s->state = SSL3_ST_SW_KEY_EXCH_A; + } else { + skip = 1; + s->state = SSL3_ST_SW_KEY_EXCH_A; + } +#else + } else + skip = 1; + + s->state = SSL3_ST_SW_KEY_EXCH_A; +#endif + s->init_num = 0; + break; + + case SSL3_ST_SW_KEY_EXCH_A: + case SSL3_ST_SW_KEY_EXCH_B: + alg_k = s->s3->tmp.new_cipher->algorithm_mkey; + + /* + * clear this, it may get reset by + * send_server_key_exchange + */ + s->s3->tmp.use_rsa_tmp = 0; + + /* + * only send if a DH key exchange or RSA but we have a sign only + * certificate + */ + if (0 + /* + * PSK: send ServerKeyExchange if PSK identity hint if + * provided + */ +#ifndef OPENSSL_NO_PSK + || ((alg_k & SSL_kPSK) && s->ctx->psk_identity_hint) +#endif + || (alg_k & SSL_kDHE) + || (alg_k & SSL_kEECDH) + || ((alg_k & SSL_kRSA) + && (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL + || (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) + && EVP_PKEY_size(s->cert->pkeys + [SSL_PKEY_RSA_ENC].privatekey) * + 8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher) + ) + ) + ) + ) { + dtls1_start_timer(s); + ret = ssl3_send_server_key_exchange(s); + if (ret <= 0) + goto end; + } else + skip = 1; + + s->state = SSL3_ST_SW_CERT_REQ_A; + s->init_num = 0; + break; + + case SSL3_ST_SW_CERT_REQ_A: + case SSL3_ST_SW_CERT_REQ_B: + if ( /* don't request cert unless asked for it: */ + !(s->verify_mode & SSL_VERIFY_PEER) || + /* + * if SSL_VERIFY_CLIENT_ONCE is set, don't request cert + * during re-negotiation: + */ + ((s->session->peer != NULL) && + (s->verify_mode & SSL_VERIFY_CLIENT_ONCE)) || + /* + * never request cert in anonymous ciphersuites (see + * section "Certificate request" in SSL 3 drafts and in + * RFC 2246): + */ + ((s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) && + /* + * ... except when the application insists on + * verification (against the specs, but s3_clnt.c accepts + * this for SSL 3) + */ + !(s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) || + /* + * never request cert in Kerberos ciphersuites + */ + (s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5) + /* + * With normal PSK Certificates and Certificate Requests + * are omitted + */ + || (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) { + /* no cert request */ + skip = 1; + s->s3->tmp.cert_request = 0; + s->state = SSL3_ST_SW_SRVR_DONE_A; +#ifndef OPENSSL_NO_SCTP + if (BIO_dgram_is_sctp(SSL_get_wbio(s))) { + s->d1->next_state = SSL3_ST_SW_SRVR_DONE_A; + s->state = DTLS1_SCTP_ST_SW_WRITE_SOCK; + } +#endif + } else { + s->s3->tmp.cert_request = 1; + dtls1_start_timer(s); + ret = ssl3_send_certificate_request(s); + if (ret <= 0) + goto end; +#ifndef NETSCAPE_HANG_BUG + s->state = SSL3_ST_SW_SRVR_DONE_A; +# ifndef OPENSSL_NO_SCTP + if (BIO_dgram_is_sctp(SSL_get_wbio(s))) { + s->d1->next_state = SSL3_ST_SW_SRVR_DONE_A; + s->state = DTLS1_SCTP_ST_SW_WRITE_SOCK; + } +# endif +#else + s->state = SSL3_ST_SW_FLUSH; + s->s3->tmp.next_state = SSL3_ST_SR_CERT_A; +# ifndef OPENSSL_NO_SCTP + if (BIO_dgram_is_sctp(SSL_get_wbio(s))) { + s->d1->next_state = s->s3->tmp.next_state; + s->s3->tmp.next_state = DTLS1_SCTP_ST_SW_WRITE_SOCK; + } +# endif +#endif + s->init_num = 0; + } + break; + + case SSL3_ST_SW_SRVR_DONE_A: + case SSL3_ST_SW_SRVR_DONE_B: + dtls1_start_timer(s); + ret = ssl3_send_server_done(s); + if (ret <= 0) + goto end; + s->s3->tmp.next_state = SSL3_ST_SR_CERT_A; + s->state = SSL3_ST_SW_FLUSH; + s->init_num = 0; + break; + + case SSL3_ST_SW_FLUSH: + s->rwstate = SSL_WRITING; + if (BIO_flush(s->wbio) <= 0) { + /* + * If the write error was fatal, stop trying + */ + if (!BIO_should_retry(s->wbio)) { + s->rwstate = SSL_NOTHING; + s->state = s->s3->tmp.next_state; + } + + ret = -1; + goto end; + } + s->rwstate = SSL_NOTHING; + s->state = s->s3->tmp.next_state; + break; + + case SSL3_ST_SR_CERT_A: + case SSL3_ST_SR_CERT_B: + if (s->s3->tmp.cert_request) { + ret = ssl3_get_client_certificate(s); + if (ret <= 0) + goto end; + } + s->init_num = 0; + s->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; +#ifndef OPENSSL_NO_SCTP + /* + * Add new shared key for SCTP-Auth, will be ignored if no SCTP + * used. + */ + snprintf((char *)labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL), + DTLS1_SCTP_AUTH_LABEL); + + if (SSL_export_keying_material(s, sctpauthkey, + sizeof(sctpauthkey), labelbuffer, + sizeof(labelbuffer), NULL, 0, 0) <= 0) { + ret = -1; + s->state = SSL_ST_ERR; + goto end; + } + + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY, + sizeof(sctpauthkey), sctpauthkey); +#endif + + s->state = SSL3_ST_SR_CERT_VRFY_A; + s->init_num = 0; + + if (ret == 2) { + /* + * For the ECDH ciphersuites when the client sends its ECDH + * pub key in a certificate, the CertificateVerify message is + * not sent. + */ + s->state = SSL3_ST_SR_FINISHED_A; + s->init_num = 0; + } else if (SSL_USE_SIGALGS(s)) { + s->state = SSL3_ST_SR_CERT_VRFY_A; + s->init_num = 0; + if (!s->session->peer) + break; + /* + * For sigalgs freeze the handshake buffer at this point and + * digest cached records. + */ + if (!s->s3->handshake_buffer) { + SSLerr(SSL_F_DTLS1_ACCEPT, ERR_R_INTERNAL_ERROR); + s->state = SSL_ST_ERR; + return -1; + } + s->s3->flags |= TLS1_FLAGS_KEEP_HANDSHAKE; + if (!ssl3_digest_cached_records(s)) { + s->state = SSL_ST_ERR; + return -1; + } + } else { + s->state = SSL3_ST_SR_CERT_VRFY_A; + s->init_num = 0; + + /* + * We need to get hashes here so if there is a client cert, + * it can be verified + */ + s->method->ssl3_enc->cert_verify_mac(s, + NID_md5, + &(s->s3-> + tmp.cert_verify_md + [0])); + s->method->ssl3_enc->cert_verify_mac(s, NID_sha1, + &(s->s3-> + tmp.cert_verify_md + [MD5_DIGEST_LENGTH])); + } + break; + + case SSL3_ST_SR_CERT_VRFY_A: + case SSL3_ST_SR_CERT_VRFY_B: + ret = ssl3_get_cert_verify(s); + if (ret <= 0) + goto end; +#ifndef OPENSSL_NO_SCTP + if (BIO_dgram_is_sctp(SSL_get_wbio(s)) && + state == SSL_ST_RENEGOTIATE) + s->state = DTLS1_SCTP_ST_SR_READ_SOCK; + else +#endif + s->state = SSL3_ST_SR_FINISHED_A; + s->init_num = 0; + break; + + case SSL3_ST_SR_FINISHED_A: + case SSL3_ST_SR_FINISHED_B: + /* + * Enable CCS. Receiving a CCS clears the flag, so make + * sure not to re-enable it to ban duplicates. This *should* be the + * first time we have received one - but we check anyway to be + * cautious. + * s->s3->change_cipher_spec is set when a CCS is + * processed in d1_pkt.c, and remains set until + * the client's Finished message is read. + */ + if (!s->s3->change_cipher_spec) + s->d1->change_cipher_spec_ok = 1; + ret = ssl3_get_finished(s, SSL3_ST_SR_FINISHED_A, + SSL3_ST_SR_FINISHED_B); + if (ret <= 0) + goto end; + dtls1_stop_timer(s); + if (s->hit) + s->state = SSL_ST_OK; +#ifndef OPENSSL_NO_TLSEXT + else if (s->tlsext_ticket_expected) + s->state = SSL3_ST_SW_SESSION_TICKET_A; +#endif + else + s->state = SSL3_ST_SW_CHANGE_A; + s->init_num = 0; + break; + +#ifndef OPENSSL_NO_TLSEXT + 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->state = SSL3_ST_SW_CHANGE_A; + s->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->state = SSL3_ST_SW_KEY_EXCH_A; + s->init_num = 0; + break; + +#endif + + case SSL3_ST_SW_CHANGE_A: + case SSL3_ST_SW_CHANGE_B: + + s->session->cipher = s->s3->tmp.new_cipher; + if (!s->method->ssl3_enc->setup_key_block(s)) { + ret = -1; + s->state = SSL_ST_ERR; + goto end; + } + + ret = dtls1_send_change_cipher_spec(s, + SSL3_ST_SW_CHANGE_A, + SSL3_ST_SW_CHANGE_B); + + if (ret <= 0) + goto end; + +#ifndef OPENSSL_NO_SCTP + if (!s->hit) { + /* + * Change to new shared key of SCTP-Auth, will be ignored if + * no SCTP used. + */ + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY, + 0, NULL); + } +#endif + + s->state = SSL3_ST_SW_FINISHED_A; + s->init_num = 0; + + if (!s->method->ssl3_enc->change_cipher_state(s, + SSL3_CHANGE_CIPHER_SERVER_WRITE)) + { + ret = -1; + s->state = SSL_ST_ERR; + goto end; + } + + dtls1_reset_seq_numbers(s, SSL3_CC_WRITE); + 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-> + ssl3_enc->server_finished_label, + s->method-> + ssl3_enc->server_finished_label_len); + if (ret <= 0) + goto end; + s->state = SSL3_ST_SW_FLUSH; + if (s->hit) { + s->s3->tmp.next_state = SSL3_ST_SR_FINISHED_A; + +#ifndef OPENSSL_NO_SCTP + /* + * Change to new shared key of SCTP-Auth, will be ignored if + * no SCTP used. + */ + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY, + 0, NULL); +#endif + } else { + s->s3->tmp.next_state = SSL_ST_OK; +#ifndef OPENSSL_NO_SCTP + if (BIO_dgram_is_sctp(SSL_get_wbio(s))) { + s->d1->next_state = s->s3->tmp.next_state; + s->s3->tmp.next_state = DTLS1_SCTP_ST_SW_WRITE_SOCK; + } +#endif + } + s->init_num = 0; + break; + + case SSL_ST_OK: + /* clean a few things up */ + ssl3_cleanup_key_block(s); + +#if 0 + BUF_MEM_free(s->init_buf); + s->init_buf = NULL; +#endif + + /* remove buffering on output */ + ssl_free_wbio_buffer(s); + + s->init_num = 0; + + if (s->renegotiate == 2) { /* skipped if we just sent a + * HelloRequest */ + s->renegotiate = 0; + s->new_session = 0; + + ssl_update_cache(s, SSL_SESS_CACHE_SERVER); + + s->ctx->stats.sess_accept_good++; + /* s->server=1; */ + s->handshake_func = dtls1_accept; + + if (cb != NULL) + cb(s, SSL_CB_HANDSHAKE_DONE, 1); + } + + ret = 1; + + /* done handshaking, next message is client hello */ + s->d1->handshake_read_seq = 0; + /* next message is server hello */ + s->d1->handshake_write_seq = 0; + s->d1->next_handshake_write_seq = 0; + goto end; + /* break; */ + + case SSL_ST_ERR: + default: + SSLerr(SSL_F_DTLS1_ACCEPT, SSL_R_UNKNOWN_STATE); + ret = -1; + goto end; + /* break; */ + } + + if (!s->s3->tmp.reuse_message && !skip) { + if (s->debug) { + if ((ret = BIO_flush(s->wbio)) <= 0) + goto end; + } + + if ((cb != NULL) && (s->state != state)) { + new_state = s->state; + s->state = state; + cb(s, SSL_CB_ACCEPT_LOOP, 1); + s->state = new_state; + } + } + skip = 0; + } + end: + /* BIO_flush(s->wbio); */ + + s->in_handshake--; +#ifndef OPENSSL_NO_SCTP + /* + * Notify SCTP BIO socket to leave handshake mode and prevent stream + * identifier other than 0. Will be ignored if no SCTP is used. + */ + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE, + s->in_handshake, NULL); +#endif + + if (cb != NULL) + cb(s, SSL_CB_ACCEPT_EXIT, ret); + return (ret); +} + +int dtls1_send_hello_verify_request(SSL *s) +{ + unsigned int msg_len; + unsigned char *msg, *buf, *p; + + if (s->state == DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A) { + buf = (unsigned char *)s->init_buf->data; + + msg = p = &(buf[DTLS1_HM_HEADER_LENGTH]); + /* Always use DTLS 1.0 version: see RFC 6347 */ + *(p++) = DTLS1_VERSION >> 8; + *(p++) = DTLS1_VERSION & 0xFF; + + if (s->ctx->app_gen_cookie_cb == NULL || + s->ctx->app_gen_cookie_cb(s, s->d1->cookie, + &(s->d1->cookie_len)) == 0) { + SSLerr(SSL_F_DTLS1_SEND_HELLO_VERIFY_REQUEST, + ERR_R_INTERNAL_ERROR); + s->state = SSL_ST_ERR; + return 0; + } + + *(p++) = (unsigned char)s->d1->cookie_len; + memcpy(p, s->d1->cookie, s->d1->cookie_len); + p += s->d1->cookie_len; + msg_len = p - msg; + + dtls1_set_message_header(s, buf, + DTLS1_MT_HELLO_VERIFY_REQUEST, msg_len, 0, + msg_len); + + s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B; + /* number of bytes to write */ + s->init_num = p - buf; + s->init_off = 0; + } + + /* s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B */ + return (dtls1_do_write(s, SSL3_RT_HANDSHAKE)); +} diff --git a/thirdparty/openssl/ssl/install-ssl.com b/thirdparty/openssl/ssl/install-ssl.com new file mode 100755 index 0000000000..afe6967f85 --- /dev/null +++ b/thirdparty/openssl/ssl/install-ssl.com @@ -0,0 +1,136 @@ +$! INSTALL-SSL.COM -- Installs the files in a given directory tree +$! +$! Author: Richard Levitte <richard@levitte.org> +$! Time of creation: 22-MAY-1998 10:13 +$! +$! P1 root of the directory tree +$! P2 "64" for 64-bit pointers. +$! +$! +$! Announce/identify. +$! +$ proc = f$environment( "procedure") +$ write sys$output "@@@ "+ - + f$parse( proc, , , "name")+ f$parse( proc, , , "type") +$! +$ on error then goto tidy +$ on control_c then goto tidy +$! +$ if p1 .eqs. "" +$ then +$ write sys$output "First argument missing." +$ write sys$output - + "It should be the directory where you want things installed." +$ exit +$ endif +$! +$ if (f$getsyi( "cpu") .lt. 128) +$ then +$ arch = "VAX" +$ else +$ arch = f$edit( f$getsyi( "arch_name"), "upcase") +$ if (arch .eqs. "") then arch = "UNK" +$ endif +$! +$ archd = arch +$ lib32 = "32" +$ shr = "_SHR32" +$! +$ if (p2 .nes. "") +$ then +$ if (p2 .eqs. "64") +$ then +$ archd = arch+ "_64" +$ lib32 = "" +$ shr = "_SHR" +$ else +$ if (p2 .nes. "32") +$ then +$ write sys$output "Second argument invalid." +$ write sys$output "It should be "32", "64", or nothing." +$ exit +$ endif +$ endif +$ endif +$! +$ root = f$parse( p1, "[]A.;0", , , "syntax_only, no_conceal") - "A.;0" +$ root_dev = f$parse(root,,,"device","syntax_only") +$ root_dir = f$parse(root,,,"directory","syntax_only") - - + "[000000." - "][" - "[" - "]" +$ root = root_dev + "[" + root_dir +$! +$ define /nolog wrk_sslroot 'root'.] /trans=conc +$ define /nolog wrk_sslinclude wrk_sslroot:[include] +$ define /nolog wrk_sslxexe wrk_sslroot:['archd'_exe] +$ define /nolog wrk_sslxlib wrk_sslroot:['arch'_lib] +$! +$ if f$parse("wrk_sslroot:[000000]") .eqs. "" then - + create /directory /log wrk_sslroot:[000000] +$ if f$parse("wrk_sslinclude:") .eqs. "" then - + create /directory /log wrk_sslinclude: +$ if f$parse("wrk_sslxexe:") .eqs. "" then - + create /directory /log wrk_sslxexe: +$ if f$parse("wrk_sslxlib:") .eqs. "" then - + create /directory /log wrk_sslxlib: +$! +$ exheader := ssl.h, ssl2.h, ssl3.h, ssl23.h, tls1.h, dtls1.h, kssl.h, srtp.h +$ e_exe := ssl_task +$ libs := ssl_libssl +$! +$ xexe_dir := [-.'archd'.exe.ssl] +$! +$ copy /protection = w:re 'exheader' wrk_sslinclude: /log +$! +$ i = 0 +$ loop_exe: +$ e = f$edit( f$element( i, ",", e_exe), "trim") +$ i = i + 1 +$ if e .eqs. "," then goto loop_exe_end +$ set noon +$ file = xexe_dir+ e+ ".exe" +$ if f$search( file) .nes. "" +$ then +$ copy /protection = w:re 'file' wrk_sslxexe: /log +$ endif +$ set on +$ goto loop_exe +$ loop_exe_end: +$! +$ i = 0 +$ loop_lib: +$ e = f$edit(f$element(i, ",", libs),"trim") +$ i = i + 1 +$ if e .eqs. "," then goto loop_lib_end +$ set noon +$! Object library. +$ file = xexe_dir+ e+ lib32+ ".olb" +$ if f$search( file) .nes. "" +$ then +$ copy /protection = w:re 'file' wrk_sslxlib: /log +$ endif +$! Shareable image. +$ file = xexe_dir+ e+ shr+ ".exe" +$ if f$search( file) .nes. "" +$ then +$ copy /protection = w:re 'file' wrk_sslxlib: /log +$ endif +$ set on +$ goto loop_lib +$ loop_lib_end: +$! +$ tidy: +$! +$ call deass wrk_sslroot +$ call deass wrk_sslinclude +$ call deass wrk_sslxexe +$ call deass wrk_sslxlib +$! +$ exit +$! +$ deass: subroutine +$ if (f$trnlnm( p1, "LNM$PROCESS") .nes. "") +$ then +$ deassign /process 'p1' +$ endif +$ endsubroutine +$! diff --git a/thirdparty/openssl/ssl/kssl.c b/thirdparty/openssl/ssl/kssl.c new file mode 100644 index 0000000000..f2839bdcd7 --- /dev/null +++ b/thirdparty/openssl/ssl/kssl.c @@ -0,0 +1,2260 @@ +/* ssl/kssl.c */ +/* + * Written by Vern Staats <staatsvr@asc.hpc.mil> for the OpenSSL project + * 2000. + */ +/* ==================================================================== + * Copyright (c) 2000 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 + * licensing@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). + * + */ + +/*- + * ssl/kssl.c -- Routines to support (& debug) Kerberos5 auth for openssl + * + * 19990701 VRS Started. + * 200011?? Jeffrey Altman, Richard Levitte + * Generalized for Heimdal, Newer MIT, & Win32. + * Integrated into main OpenSSL 0.9.7 snapshots. + * 20010413 Simon Wilkinson, VRS + * Real RFC2712 KerberosWrapper replaces AP_REQ. + */ + +#include <openssl/opensslconf.h> + +#include <string.h> + +#define KRB5_PRIVATE 1 + +#include <openssl/ssl.h> +#include <openssl/evp.h> +#include <openssl/objects.h> +#include <openssl/krb5_asn.h> +#include "kssl_lcl.h" + +#ifndef OPENSSL_NO_KRB5 + +# ifndef ENOMEM +# define ENOMEM KRB5KRB_ERR_GENERIC +# endif + +/* + * When OpenSSL is built on Windows, we do not want to require that + * the Kerberos DLLs be available in order for the OpenSSL DLLs to + * work. Therefore, all Kerberos routines are loaded at run time + * and we do not link to a .LIB file. + */ + +# if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32) +/* + * The purpose of the following pre-processor statements is to provide + * compatibility with different releases of MIT Kerberos for Windows. + * All versions up to 1.2 used macros. But macros do not allow for + * a binary compatible interface for DLLs. Therefore, all macros are + * being replaced by function calls. The following code will allow + * an OpenSSL DLL built on Windows to work whether or not the macro + * or function form of the routines are utilized. + */ +# ifdef krb5_cc_get_principal +# define NO_DEF_KRB5_CCACHE +# undef krb5_cc_get_principal +# endif +# define krb5_cc_get_principal kssl_krb5_cc_get_principal + +# define krb5_free_data_contents kssl_krb5_free_data_contents +# define krb5_free_context kssl_krb5_free_context +# define krb5_auth_con_free kssl_krb5_auth_con_free +# define krb5_free_principal kssl_krb5_free_principal +# define krb5_mk_req_extended kssl_krb5_mk_req_extended +# define krb5_get_credentials kssl_krb5_get_credentials +# define krb5_cc_default kssl_krb5_cc_default +# define krb5_sname_to_principal kssl_krb5_sname_to_principal +# define krb5_init_context kssl_krb5_init_context +# define krb5_free_ticket kssl_krb5_free_ticket +# define krb5_rd_req kssl_krb5_rd_req +# define krb5_kt_default kssl_krb5_kt_default +# define krb5_kt_resolve kssl_krb5_kt_resolve +/* macros in mit 1.2.2 and earlier; functions in mit 1.2.3 and greater */ +# ifndef krb5_kt_close +# define krb5_kt_close kssl_krb5_kt_close +# endif /* krb5_kt_close */ +# ifndef krb5_kt_get_entry +# define krb5_kt_get_entry kssl_krb5_kt_get_entry +# endif /* krb5_kt_get_entry */ +# define krb5_auth_con_init kssl_krb5_auth_con_init + +# define krb5_principal_compare kssl_krb5_principal_compare +# define krb5_decrypt_tkt_part kssl_krb5_decrypt_tkt_part +# define krb5_timeofday kssl_krb5_timeofday +# define krb5_rc_default kssl_krb5_rc_default + +# ifdef krb5_rc_initialize +# undef krb5_rc_initialize +# endif +# define krb5_rc_initialize kssl_krb5_rc_initialize + +# ifdef krb5_rc_get_lifespan +# undef krb5_rc_get_lifespan +# endif +# define krb5_rc_get_lifespan kssl_krb5_rc_get_lifespan + +# ifdef krb5_rc_destroy +# undef krb5_rc_destroy +# endif +# define krb5_rc_destroy kssl_krb5_rc_destroy + +# define valid_cksumtype kssl_valid_cksumtype +# define krb5_checksum_size kssl_krb5_checksum_size +# define krb5_kt_free_entry kssl_krb5_kt_free_entry +# define krb5_auth_con_setrcache kssl_krb5_auth_con_setrcache +# define krb5_auth_con_getrcache kssl_krb5_auth_con_getrcache +# define krb5_get_server_rcache kssl_krb5_get_server_rcache + +/* Prototypes for built in stubs */ +void kssl_krb5_free_data_contents(krb5_context, krb5_data *); +void kssl_krb5_free_principal(krb5_context, krb5_principal); +krb5_error_code kssl_krb5_kt_resolve(krb5_context, + krb5_const char *, krb5_keytab *); +krb5_error_code kssl_krb5_kt_default(krb5_context, krb5_keytab *); +krb5_error_code kssl_krb5_free_ticket(krb5_context, krb5_ticket *); +krb5_error_code kssl_krb5_rd_req(krb5_context, krb5_auth_context *, + krb5_const krb5_data *, + krb5_const_principal, krb5_keytab, + krb5_flags *, krb5_ticket **); + +krb5_boolean kssl_krb5_principal_compare(krb5_context, krb5_const_principal, + krb5_const_principal); +krb5_error_code kssl_krb5_mk_req_extended(krb5_context, + krb5_auth_context *, + krb5_const krb5_flags, + krb5_data *, + krb5_creds *, krb5_data *); +krb5_error_code kssl_krb5_init_context(krb5_context *); +void kssl_krb5_free_context(krb5_context); +krb5_error_code kssl_krb5_cc_default(krb5_context, krb5_ccache *); +krb5_error_code kssl_krb5_sname_to_principal(krb5_context, + krb5_const char *, + krb5_const char *, + krb5_int32, krb5_principal *); +krb5_error_code kssl_krb5_get_credentials(krb5_context, + krb5_const krb5_flags, + krb5_ccache, + krb5_creds *, krb5_creds * *); +krb5_error_code kssl_krb5_auth_con_init(krb5_context, krb5_auth_context *); +krb5_error_code kssl_krb5_cc_get_principal(krb5_context context, + krb5_ccache cache, + krb5_principal *principal); +krb5_error_code kssl_krb5_auth_con_free(krb5_context, krb5_auth_context); +size_t kssl_krb5_checksum_size(krb5_context context, krb5_cksumtype ctype); +krb5_boolean kssl_valid_cksumtype(krb5_cksumtype ctype); +krb5_error_code krb5_kt_free_entry(krb5_context, krb5_keytab_entry FAR *); +krb5_error_code kssl_krb5_auth_con_setrcache(krb5_context, + krb5_auth_context, krb5_rcache); +krb5_error_code kssl_krb5_get_server_rcache(krb5_context, + krb5_const krb5_data *, + krb5_rcache *); +krb5_error_code kssl_krb5_auth_con_getrcache(krb5_context, + krb5_auth_context, + krb5_rcache *); + +/* Function pointers (almost all Kerberos functions are _stdcall) */ +static void (_stdcall *p_krb5_free_data_contents) (krb5_context, krb5_data *) + = NULL; +static void (_stdcall *p_krb5_free_principal) (krb5_context, krb5_principal) + = NULL; +static krb5_error_code(_stdcall *p_krb5_kt_resolve) + (krb5_context, krb5_const char *, krb5_keytab *) = NULL; +static krb5_error_code(_stdcall *p_krb5_kt_default) (krb5_context, + krb5_keytab *) = NULL; +static krb5_error_code(_stdcall *p_krb5_free_ticket) (krb5_context, + krb5_ticket *) = NULL; +static krb5_error_code(_stdcall *p_krb5_rd_req) (krb5_context, + krb5_auth_context *, + krb5_const krb5_data *, + krb5_const_principal, + krb5_keytab, krb5_flags *, + krb5_ticket **) = NULL; +static krb5_error_code(_stdcall *p_krb5_mk_req_extended) + (krb5_context, krb5_auth_context *, + krb5_const krb5_flags, krb5_data *, krb5_creds *, krb5_data *) = NULL; +static krb5_error_code(_stdcall *p_krb5_init_context) (krb5_context *) = NULL; +static void (_stdcall *p_krb5_free_context) (krb5_context) = NULL; +static krb5_error_code(_stdcall *p_krb5_cc_default) (krb5_context, + krb5_ccache *) = NULL; +static krb5_error_code(_stdcall *p_krb5_sname_to_principal) + (krb5_context, krb5_const char *, krb5_const char *, + krb5_int32, krb5_principal *) = NULL; +static krb5_error_code(_stdcall *p_krb5_get_credentials) + (krb5_context, krb5_const krb5_flags, krb5_ccache, + krb5_creds *, krb5_creds **) = NULL; +static krb5_error_code(_stdcall *p_krb5_auth_con_init) + (krb5_context, krb5_auth_context *) = NULL; +static krb5_error_code(_stdcall *p_krb5_cc_get_principal) + (krb5_context context, krb5_ccache cache, krb5_principal *principal) = NULL; +static krb5_error_code(_stdcall *p_krb5_auth_con_free) + (krb5_context, krb5_auth_context) = NULL; +static krb5_error_code(_stdcall *p_krb5_decrypt_tkt_part) + (krb5_context, krb5_const krb5_keyblock *, krb5_ticket *) = NULL; +static krb5_error_code(_stdcall *p_krb5_timeofday) + (krb5_context context, krb5_int32 *timeret) = NULL; +static krb5_error_code(_stdcall *p_krb5_rc_default) + (krb5_context context, krb5_rcache *rc) = NULL; +static krb5_error_code(_stdcall *p_krb5_rc_initialize) + (krb5_context context, krb5_rcache rc, krb5_deltat lifespan) = NULL; +static krb5_error_code(_stdcall *p_krb5_rc_get_lifespan) + (krb5_context context, krb5_rcache rc, krb5_deltat *lifespan) = NULL; +static krb5_error_code(_stdcall *p_krb5_rc_destroy) + (krb5_context context, krb5_rcache rc) = NULL; +static krb5_boolean(_stdcall *p_krb5_principal_compare) + (krb5_context, krb5_const_principal, krb5_const_principal) = NULL; +static size_t (_stdcall *p_krb5_checksum_size) (krb5_context context, + krb5_cksumtype ctype) = NULL; +static krb5_boolean(_stdcall *p_valid_cksumtype) (krb5_cksumtype ctype) = + NULL; +static krb5_error_code(_stdcall *p_krb5_kt_free_entry) + (krb5_context, krb5_keytab_entry *) = NULL; +static krb5_error_code(_stdcall *p_krb5_auth_con_setrcache) (krb5_context, + krb5_auth_context, + krb5_rcache) = + NULL; +static krb5_error_code(_stdcall *p_krb5_get_server_rcache) (krb5_context, + krb5_const + krb5_data *, + krb5_rcache *) = + NULL; +static krb5_error_code(*p_krb5_auth_con_getrcache) (krb5_context, + krb5_auth_context, + krb5_rcache *) = NULL; +static krb5_error_code(_stdcall *p_krb5_kt_close) (krb5_context context, + krb5_keytab keytab) = NULL; +static krb5_error_code(_stdcall *p_krb5_kt_get_entry) (krb5_context context, + krb5_keytab keytab, + krb5_const_principal + principal, + krb5_kvno vno, + krb5_enctype enctype, + krb5_keytab_entry + *entry) = NULL; +static int krb5_loaded = 0; /* only attempt to initialize func ptrs once */ + +/* Function to Load the Kerberos 5 DLL and initialize function pointers */ +void load_krb5_dll(void) +{ + HANDLE hKRB5_32; + + krb5_loaded++; + hKRB5_32 = LoadLibrary(TEXT("KRB5_32")); + if (!hKRB5_32) + return; + + (FARPROC) p_krb5_free_data_contents = + GetProcAddress(hKRB5_32, "krb5_free_data_contents"); + (FARPROC) p_krb5_free_context = + GetProcAddress(hKRB5_32, "krb5_free_context"); + (FARPROC) p_krb5_auth_con_free = + GetProcAddress(hKRB5_32, "krb5_auth_con_free"); + (FARPROC) p_krb5_free_principal = + GetProcAddress(hKRB5_32, "krb5_free_principal"); + (FARPROC) p_krb5_mk_req_extended = + GetProcAddress(hKRB5_32, "krb5_mk_req_extended"); + (FARPROC) p_krb5_get_credentials = + GetProcAddress(hKRB5_32, "krb5_get_credentials"); + (FARPROC) p_krb5_cc_get_principal = + GetProcAddress(hKRB5_32, "krb5_cc_get_principal"); + (FARPROC) p_krb5_cc_default = GetProcAddress(hKRB5_32, "krb5_cc_default"); + (FARPROC) p_krb5_sname_to_principal = + GetProcAddress(hKRB5_32, "krb5_sname_to_principal"); + (FARPROC) p_krb5_init_context = + GetProcAddress(hKRB5_32, "krb5_init_context"); + (FARPROC) p_krb5_free_ticket = + GetProcAddress(hKRB5_32, "krb5_free_ticket"); + (FARPROC) p_krb5_rd_req = GetProcAddress(hKRB5_32, "krb5_rd_req"); + (FARPROC) p_krb5_principal_compare = + GetProcAddress(hKRB5_32, "krb5_principal_compare"); + (FARPROC) p_krb5_decrypt_tkt_part = + GetProcAddress(hKRB5_32, "krb5_decrypt_tkt_part"); + (FARPROC) p_krb5_timeofday = GetProcAddress(hKRB5_32, "krb5_timeofday"); + (FARPROC) p_krb5_rc_default = GetProcAddress(hKRB5_32, "krb5_rc_default"); + (FARPROC) p_krb5_rc_initialize = + GetProcAddress(hKRB5_32, "krb5_rc_initialize"); + (FARPROC) p_krb5_rc_get_lifespan = + GetProcAddress(hKRB5_32, "krb5_rc_get_lifespan"); + (FARPROC) p_krb5_rc_destroy = GetProcAddress(hKRB5_32, "krb5_rc_destroy"); + (FARPROC) p_krb5_kt_default = GetProcAddress(hKRB5_32, "krb5_kt_default"); + (FARPROC) p_krb5_kt_resolve = GetProcAddress(hKRB5_32, "krb5_kt_resolve"); + (FARPROC) p_krb5_auth_con_init = + GetProcAddress(hKRB5_32, "krb5_auth_con_init"); + (FARPROC) p_valid_cksumtype = GetProcAddress(hKRB5_32, "valid_cksumtype"); + (FARPROC) p_krb5_checksum_size = + GetProcAddress(hKRB5_32, "krb5_checksum_size"); + (FARPROC) p_krb5_kt_free_entry = + GetProcAddress(hKRB5_32, "krb5_kt_free_entry"); + (FARPROC) p_krb5_auth_con_setrcache = + GetProcAddress(hKRB5_32, "krb5_auth_con_setrcache"); + (FARPROC) p_krb5_get_server_rcache = + GetProcAddress(hKRB5_32, "krb5_get_server_rcache"); + (FARPROC) p_krb5_auth_con_getrcache = + GetProcAddress(hKRB5_32, "krb5_auth_con_getrcache"); + (FARPROC) p_krb5_kt_close = GetProcAddress(hKRB5_32, "krb5_kt_close"); + (FARPROC) p_krb5_kt_get_entry = + GetProcAddress(hKRB5_32, "krb5_kt_get_entry"); +} + +/* Stubs for each function to be dynamicly loaded */ +void kssl_krb5_free_data_contents(krb5_context CO, krb5_data *data) +{ + if (!krb5_loaded) + load_krb5_dll(); + + if (p_krb5_free_data_contents) + p_krb5_free_data_contents(CO, data); +} + +krb5_error_code +kssl_krb5_mk_req_extended(krb5_context CO, + krb5_auth_context *pACO, + krb5_const krb5_flags F, + krb5_data *pD1, krb5_creds *pC, krb5_data *pD2) +{ + if (!krb5_loaded) + load_krb5_dll(); + + if (p_krb5_mk_req_extended) + return (p_krb5_mk_req_extended(CO, pACO, F, pD1, pC, pD2)); + else + return KRB5KRB_ERR_GENERIC; +} + +krb5_error_code +kssl_krb5_auth_con_init(krb5_context CO, krb5_auth_context *pACO) +{ + if (!krb5_loaded) + load_krb5_dll(); + + if (p_krb5_auth_con_init) + return (p_krb5_auth_con_init(CO, pACO)); + else + return KRB5KRB_ERR_GENERIC; +} + +krb5_error_code +kssl_krb5_auth_con_free(krb5_context CO, krb5_auth_context ACO) +{ + if (!krb5_loaded) + load_krb5_dll(); + + if (p_krb5_auth_con_free) + return (p_krb5_auth_con_free(CO, ACO)); + else + return KRB5KRB_ERR_GENERIC; +} + +krb5_error_code +kssl_krb5_get_credentials(krb5_context CO, + krb5_const krb5_flags F, + krb5_ccache CC, krb5_creds *pCR, krb5_creds **ppCR) +{ + if (!krb5_loaded) + load_krb5_dll(); + + if (p_krb5_get_credentials) + return (p_krb5_get_credentials(CO, F, CC, pCR, ppCR)); + else + return KRB5KRB_ERR_GENERIC; +} + +krb5_error_code +kssl_krb5_sname_to_principal(krb5_context CO, + krb5_const char *pC1, + krb5_const char *pC2, + krb5_int32 I, krb5_principal *pPR) +{ + if (!krb5_loaded) + load_krb5_dll(); + + if (p_krb5_sname_to_principal) + return (p_krb5_sname_to_principal(CO, pC1, pC2, I, pPR)); + else + return KRB5KRB_ERR_GENERIC; +} + +krb5_error_code kssl_krb5_cc_default(krb5_context CO, krb5_ccache *pCC) +{ + if (!krb5_loaded) + load_krb5_dll(); + + if (p_krb5_cc_default) + return (p_krb5_cc_default(CO, pCC)); + else + return KRB5KRB_ERR_GENERIC; +} + +krb5_error_code kssl_krb5_init_context(krb5_context *pCO) +{ + if (!krb5_loaded) + load_krb5_dll(); + + if (p_krb5_init_context) + return (p_krb5_init_context(pCO)); + else + return KRB5KRB_ERR_GENERIC; +} + +void kssl_krb5_free_context(krb5_context CO) +{ + if (!krb5_loaded) + load_krb5_dll(); + + if (p_krb5_free_context) + p_krb5_free_context(CO); +} + +void kssl_krb5_free_principal(krb5_context c, krb5_principal p) +{ + if (!krb5_loaded) + load_krb5_dll(); + + if (p_krb5_free_principal) + p_krb5_free_principal(c, p); +} + +krb5_error_code +kssl_krb5_kt_resolve(krb5_context con, krb5_const char *sz, krb5_keytab *kt) +{ + if (!krb5_loaded) + load_krb5_dll(); + + if (p_krb5_kt_resolve) + return (p_krb5_kt_resolve(con, sz, kt)); + else + return KRB5KRB_ERR_GENERIC; +} + +krb5_error_code kssl_krb5_kt_default(krb5_context con, krb5_keytab *kt) +{ + if (!krb5_loaded) + load_krb5_dll(); + + if (p_krb5_kt_default) + return (p_krb5_kt_default(con, kt)); + else + return KRB5KRB_ERR_GENERIC; +} + +krb5_error_code kssl_krb5_free_ticket(krb5_context con, krb5_ticket *kt) +{ + if (!krb5_loaded) + load_krb5_dll(); + + if (p_krb5_free_ticket) + return (p_krb5_free_ticket(con, kt)); + else + return KRB5KRB_ERR_GENERIC; +} + +krb5_error_code +kssl_krb5_rd_req(krb5_context con, krb5_auth_context *pacon, + krb5_const krb5_data *data, + krb5_const_principal princ, krb5_keytab keytab, + krb5_flags *flags, krb5_ticket **pptkt) +{ + if (!krb5_loaded) + load_krb5_dll(); + + if (p_krb5_rd_req) + return (p_krb5_rd_req(con, pacon, data, princ, keytab, flags, pptkt)); + else + return KRB5KRB_ERR_GENERIC; +} + +krb5_boolean +krb5_principal_compare(krb5_context con, krb5_const_principal princ1, + krb5_const_principal princ2) +{ + if (!krb5_loaded) + load_krb5_dll(); + + if (p_krb5_principal_compare) + return (p_krb5_principal_compare(con, princ1, princ2)); + else + return KRB5KRB_ERR_GENERIC; +} + +krb5_error_code +krb5_decrypt_tkt_part(krb5_context con, krb5_const krb5_keyblock *keys, + krb5_ticket *ticket) +{ + if (!krb5_loaded) + load_krb5_dll(); + + if (p_krb5_decrypt_tkt_part) + return (p_krb5_decrypt_tkt_part(con, keys, ticket)); + else + return KRB5KRB_ERR_GENERIC; +} + +krb5_error_code krb5_timeofday(krb5_context con, krb5_int32 *timeret) +{ + if (!krb5_loaded) + load_krb5_dll(); + + if (p_krb5_timeofday) + return (p_krb5_timeofday(con, timeret)); + else + return KRB5KRB_ERR_GENERIC; +} + +krb5_error_code krb5_rc_default(krb5_context con, krb5_rcache *rc) +{ + if (!krb5_loaded) + load_krb5_dll(); + + if (p_krb5_rc_default) + return (p_krb5_rc_default(con, rc)); + else + return KRB5KRB_ERR_GENERIC; +} + +krb5_error_code +krb5_rc_initialize(krb5_context con, krb5_rcache rc, krb5_deltat lifespan) +{ + if (!krb5_loaded) + load_krb5_dll(); + + if (p_krb5_rc_initialize) + return (p_krb5_rc_initialize(con, rc, lifespan)); + else + return KRB5KRB_ERR_GENERIC; +} + +krb5_error_code +krb5_rc_get_lifespan(krb5_context con, krb5_rcache rc, krb5_deltat *lifespanp) +{ + if (!krb5_loaded) + load_krb5_dll(); + + if (p_krb5_rc_get_lifespan) + return (p_krb5_rc_get_lifespan(con, rc, lifespanp)); + else + return KRB5KRB_ERR_GENERIC; +} + +krb5_error_code krb5_rc_destroy(krb5_context con, krb5_rcache rc) +{ + if (!krb5_loaded) + load_krb5_dll(); + + if (p_krb5_rc_destroy) + return (p_krb5_rc_destroy(con, rc)); + else + return KRB5KRB_ERR_GENERIC; +} + +size_t krb5_checksum_size(krb5_context context, krb5_cksumtype ctype) +{ + if (!krb5_loaded) + load_krb5_dll(); + + if (p_krb5_checksum_size) + return (p_krb5_checksum_size(context, ctype)); + else + return KRB5KRB_ERR_GENERIC; +} + +krb5_boolean valid_cksumtype(krb5_cksumtype ctype) +{ + if (!krb5_loaded) + load_krb5_dll(); + + if (p_valid_cksumtype) + return (p_valid_cksumtype(ctype)); + else + return KRB5KRB_ERR_GENERIC; +} + +krb5_error_code krb5_kt_free_entry(krb5_context con, krb5_keytab_entry *entry) +{ + if (!krb5_loaded) + load_krb5_dll(); + + if (p_krb5_kt_free_entry) + return (p_krb5_kt_free_entry(con, entry)); + else + return KRB5KRB_ERR_GENERIC; +} + +/* Structure definitions */ +# ifndef NO_DEF_KRB5_CCACHE +# ifndef krb5_x +# define krb5_x(ptr,args) ((ptr)?((*(ptr)) args):(abort(),1)) +# define krb5_xc(ptr,args) ((ptr)?((*(ptr)) args):(abort(),(char*)0)) +# endif + +typedef krb5_pointer krb5_cc_cursor; /* cursor for sequential lookup */ + +typedef struct _krb5_ccache { + krb5_magic magic; + struct _krb5_cc_ops FAR *ops; + krb5_pointer data; +} *krb5_ccache; + +typedef struct _krb5_cc_ops { + krb5_magic magic; + char *prefix; + char *(KRB5_CALLCONV *get_name) + (krb5_context, krb5_ccache); + krb5_error_code(KRB5_CALLCONV *resolve) + (krb5_context, krb5_ccache *, const char *); + krb5_error_code(KRB5_CALLCONV *gen_new) + (krb5_context, krb5_ccache *); + krb5_error_code(KRB5_CALLCONV *init) + (krb5_context, krb5_ccache, krb5_principal); + krb5_error_code(KRB5_CALLCONV *destroy) + (krb5_context, krb5_ccache); + krb5_error_code(KRB5_CALLCONV *close) + (krb5_context, krb5_ccache); + krb5_error_code(KRB5_CALLCONV *store) + (krb5_context, krb5_ccache, krb5_creds *); + krb5_error_code(KRB5_CALLCONV *retrieve) + (krb5_context, krb5_ccache, krb5_flags, krb5_creds *, krb5_creds *); + krb5_error_code(KRB5_CALLCONV *get_princ) + (krb5_context, krb5_ccache, krb5_principal *); + krb5_error_code(KRB5_CALLCONV *get_first) + (krb5_context, krb5_ccache, krb5_cc_cursor *); + krb5_error_code(KRB5_CALLCONV *get_next) + (krb5_context, krb5_ccache, krb5_cc_cursor *, krb5_creds *); + krb5_error_code(KRB5_CALLCONV *end_get) + (krb5_context, krb5_ccache, krb5_cc_cursor *); + krb5_error_code(KRB5_CALLCONV *remove_cred) + (krb5_context, krb5_ccache, krb5_flags, krb5_creds *); + krb5_error_code(KRB5_CALLCONV *set_flags) + (krb5_context, krb5_ccache, krb5_flags); +} krb5_cc_ops; +# endif /* NO_DEF_KRB5_CCACHE */ + +krb5_error_code + kssl_krb5_cc_get_principal + (krb5_context context, krb5_ccache cache, krb5_principal *principal) { + if (p_krb5_cc_get_principal) + return (p_krb5_cc_get_principal(context, cache, principal)); + else + return (krb5_x((cache)->ops->get_princ, (context, cache, principal))); +} + +krb5_error_code +kssl_krb5_auth_con_setrcache(krb5_context con, krb5_auth_context acon, + krb5_rcache rcache) +{ + if (p_krb5_auth_con_setrcache) + return (p_krb5_auth_con_setrcache(con, acon, rcache)); + else + return KRB5KRB_ERR_GENERIC; +} + +krb5_error_code +kssl_krb5_get_server_rcache(krb5_context con, krb5_const krb5_data *data, + krb5_rcache *rcache) +{ + if (p_krb5_get_server_rcache) + return (p_krb5_get_server_rcache(con, data, rcache)); + else + return KRB5KRB_ERR_GENERIC; +} + +krb5_error_code +kssl_krb5_auth_con_getrcache(krb5_context con, krb5_auth_context acon, + krb5_rcache *prcache) +{ + if (p_krb5_auth_con_getrcache) + return (p_krb5_auth_con_getrcache(con, acon, prcache)); + else + return KRB5KRB_ERR_GENERIC; +} + +krb5_error_code kssl_krb5_kt_close(krb5_context context, krb5_keytab keytab) +{ + if (p_krb5_kt_close) + return (p_krb5_kt_close(context, keytab)); + else + return KRB5KRB_ERR_GENERIC; +} + +krb5_error_code +kssl_krb5_kt_get_entry(krb5_context context, krb5_keytab keytab, + krb5_const_principal principal, krb5_kvno vno, + krb5_enctype enctype, krb5_keytab_entry *entry) +{ + if (p_krb5_kt_get_entry) + return (p_krb5_kt_get_entry + (context, keytab, principal, vno, enctype, entry)); + else + return KRB5KRB_ERR_GENERIC; +} +# endif /* OPENSSL_SYS_WINDOWS || OPENSSL_SYS_WIN32 */ + +/* + * memory allocation functions for non-temporary storage (e.g. stuff that + * gets saved into the kssl context) + */ +static void *kssl_calloc(size_t nmemb, size_t size) +{ + void *p; + + p = OPENSSL_malloc(nmemb * size); + if (p) { + memset(p, 0, nmemb * size); + } + return p; +} + +# define kssl_malloc(size) OPENSSL_malloc((size)) +# define kssl_realloc(ptr, size) OPENSSL_realloc(ptr, size) +# define kssl_free(ptr) OPENSSL_free((ptr)) + +char +*kstring(char *string) +{ + static char *null = "[NULL]"; + + return ((string == NULL) ? null : string); +} + +/* + * Given KRB5 enctype (basically DES or 3DES), return closest match openssl + * EVP_ encryption algorithm. Return NULL for unknown or problematic + * (krb5_dk_encrypt) enctypes. Assume ENCTYPE_*_RAW (krb5_raw_encrypt) are + * OK. + */ +const EVP_CIPHER *kssl_map_enc(krb5_enctype enctype) +{ + switch (enctype) { + case ENCTYPE_DES_HMAC_SHA1: /* EVP_des_cbc(); */ + case ENCTYPE_DES_CBC_CRC: + case ENCTYPE_DES_CBC_MD4: + case ENCTYPE_DES_CBC_MD5: + case ENCTYPE_DES_CBC_RAW: + return EVP_des_cbc(); + break; + case ENCTYPE_DES3_CBC_SHA1: /* EVP_des_ede3_cbc(); */ + case ENCTYPE_DES3_CBC_SHA: + case ENCTYPE_DES3_CBC_RAW: + return EVP_des_ede3_cbc(); + break; + default: + return NULL; + break; + } +} + +/* + * Return true:1 if p "looks like" the start of the real authenticator + * described in kssl_skip_confound() below. The ASN.1 pattern is "62 xx 30 + * yy" (APPLICATION-2, SEQUENCE), where xx-yy =~ 2, and xx and yy are + * possibly multi-byte length fields. + */ +static int kssl_test_confound(unsigned char *p) +{ + int len = 2; + int xx = 0, yy = 0; + + if (*p++ != 0x62) + return 0; + if (*p > 0x82) + return 0; + switch (*p) { + case 0x82: + p++; + xx = (*p++ << 8); + xx += *p++; + break; + case 0x81: + p++; + xx = *p++; + break; + case 0x80: + return 0; + default: + xx = *p++; + break; + } + if (*p++ != 0x30) + return 0; + if (*p > 0x82) + return 0; + switch (*p) { + case 0x82: + p++; + len += 2; + yy = (*p++ << 8); + yy += *p++; + break; + case 0x81: + p++; + len++; + yy = *p++; + break; + case 0x80: + return 0; + default: + yy = *p++; + break; + } + + return (xx - len == yy) ? 1 : 0; +} + +/* + * Allocate, fill, and return cksumlens array of checksum lengths. This + * array holds just the unique elements from the krb5_cksumarray[]. array[n] + * == 0 signals end of data. The krb5_cksumarray[] was an internal variable + * that has since been replaced by a more general method for storing the + * data. It should not be used. Instead we use real API calls and make a + * guess for what the highest assigned CKSUMTYPE_ constant is. As of 1.2.2 + * it is 0x000c (CKSUMTYPE_HMAC_SHA1_DES3). So we will use 0x0010. + */ +static size_t *populate_cksumlens(void) +{ + int i, j, n; + static size_t *cklens = NULL; + +# ifdef KRB5_MIT_OLD11 + n = krb5_max_cksum; +# else + n = 0x0010; +# endif /* KRB5_MIT_OLD11 */ + +# ifdef KRB5CHECKAUTH + if (!cklens && !(cklens = (size_t *)calloc(sizeof(int), n + 1))) + return NULL; + + for (i = 0; i < n; i++) { + if (!valid_cksumtype(i)) + continue; /* array has holes */ + for (j = 0; j < n; j++) { + if (cklens[j] == 0) { + cklens[j] = krb5_checksum_size(NULL, i); + break; /* krb5 elem was new: add */ + } + if (cklens[j] == krb5_checksum_size(NULL, i)) { + break; /* ignore duplicate elements */ + } + } + } +# endif /* KRB5CHECKAUTH */ + + return cklens; +} + +/*- + * Return pointer to start of real authenticator within authenticator, or + * return NULL on error. + * Decrypted authenticator looks like this: + * [0 or 8 byte confounder] [4-24 byte checksum] [real authent'r] + * This hackery wouldn't be necessary if MIT KRB5 1.0.6 had the + * krb5_auth_con_getcksumtype() function advertised in its krb5.h. + */ +unsigned char *kssl_skip_confound(krb5_enctype etype, unsigned char *a) +{ + int i, conlen; + size_t cklen; + static size_t *cksumlens = NULL; + unsigned char *test_auth; + + conlen = (etype) ? 8 : 0; + + if (!cksumlens && !(cksumlens = populate_cksumlens())) + return NULL; + for (i = 0; (cklen = cksumlens[i]) != 0; i++) { + test_auth = a + conlen + cklen; + if (kssl_test_confound(test_auth)) + return test_auth; + } + + return NULL; +} + +/* + * Set kssl_err error info when reason text is a simple string kssl_err = + * struct { int reason; char text[KSSL_ERR_MAX+1]; } + */ +void kssl_err_set(KSSL_ERR *kssl_err, int reason, char *text) +{ + if (kssl_err == NULL) + return; + + kssl_err->reason = reason; + BIO_snprintf(kssl_err->text, KSSL_ERR_MAX, "%s", text); + return; +} + +/* + * Display contents of krb5_data struct, for debugging + */ +void print_krb5_data(char *label, krb5_data *kdata) +{ + int i; + + fprintf(stderr, "%s[%d] ", label, kdata->length); + for (i = 0; i < (int)kdata->length; i++) { + if (0 && isprint((int)kdata->data[i])) + fprintf(stderr, "%c ", kdata->data[i]); + else + fprintf(stderr, "%02x ", (unsigned char)kdata->data[i]); + } + fprintf(stderr, "\n"); +} + +/* + * Display contents of krb5_authdata struct, for debugging + */ +void print_krb5_authdata(char *label, krb5_authdata **adata) +{ + if (adata == NULL) { + fprintf(stderr, "%s, authdata==0\n", label); + return; + } + fprintf(stderr, "%s [%p]\n", label, (void *)adata); +# if 0 + { + int i; + fprintf(stderr, "%s[at%d:%d] ", label, adata->ad_type, adata->length); + for (i = 0; i < adata->length; i++) { + fprintf(stderr, (isprint(adata->contents[i])) ? "%c " : "%02x", + adata->contents[i]); + } + fprintf(stderr, "\n"); + } +# endif +} + +/* + * Display contents of krb5_keyblock struct, for debugging + */ +void print_krb5_keyblock(char *label, krb5_keyblock *keyblk) +{ + int i; + + if (keyblk == NULL) { + fprintf(stderr, "%s, keyblk==0\n", label); + return; + } +# ifdef KRB5_HEIMDAL + fprintf(stderr, "%s\n\t[et%d:%d]: ", label, keyblk->keytype, + keyblk->keyvalue->length); + for (i = 0; i < (int)keyblk->keyvalue->length; i++) { + fprintf(stderr, "%02x", + (unsigned char *)(keyblk->keyvalue->contents)[i]); + } + fprintf(stderr, "\n"); +# else + fprintf(stderr, "%s\n\t[et%d:%d]: ", label, keyblk->enctype, + keyblk->length); + for (i = 0; i < (int)keyblk->length; i++) { + fprintf(stderr, "%02x", keyblk->contents[i]); + } + fprintf(stderr, "\n"); +# endif +} + +/* + * Display contents of krb5_principal_data struct, for debugging + * (krb5_principal is typedef'd == krb5_principal_data *) + */ +static void print_krb5_princ(char *label, krb5_principal_data *princ) +{ + int i, ui, uj; + + fprintf(stderr, "%s principal Realm: ", label); + if (princ == NULL) + return; + for (ui = 0; ui < (int)princ->realm.length; ui++) + putchar(princ->realm.data[ui]); + fprintf(stderr, " (nametype %d) has %d strings:\n", princ->type, + princ->length); + for (i = 0; i < (int)princ->length; i++) { + fprintf(stderr, "\t%d [%d]: ", i, princ->data[i].length); + for (uj = 0; uj < (int)princ->data[i].length; uj++) { + putchar(princ->data[i].data[uj]); + } + fprintf(stderr, "\n"); + } + return; +} + +/*- Given krb5 service (typically "kssl") and hostname in kssl_ctx, + * Return encrypted Kerberos ticket for service @ hostname. + * If authenp is non-NULL, also return encrypted authenticator, + * whose data should be freed by caller. + * (Originally was: Create Kerberos AP_REQ message for SSL Client.) + * + * 19990628 VRS Started; Returns Kerberos AP_REQ message. + * 20010409 VRS Modified for RFC2712; Returns enc tkt. + * 20010606 VRS May also return optional authenticator. + */ +krb5_error_code kssl_cget_tkt( /* UPDATE */ KSSL_CTX *kssl_ctx, + /* + * OUT + */ krb5_data **enc_ticketp, + /* + * UPDATE + */ krb5_data *authenp, + /* + * OUT + */ KSSL_ERR *kssl_err) +{ + krb5_error_code krb5rc = KRB5KRB_ERR_GENERIC; + krb5_context krb5context = NULL; + krb5_auth_context krb5auth_context = NULL; + krb5_ccache krb5ccdef = NULL; + krb5_creds krb5creds, *krb5credsp = NULL; + krb5_data krb5_app_req; + + kssl_err_set(kssl_err, 0, ""); + memset((char *)&krb5creds, 0, sizeof(krb5creds)); + + if (!kssl_ctx) { + kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, "No kssl_ctx defined.\n"); + goto err; + } else if (!kssl_ctx->service_host) { + kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, + "kssl_ctx service_host undefined.\n"); + goto err; + } + + if ((krb5rc = krb5_init_context(&krb5context)) != 0) { + BIO_snprintf(kssl_err->text, KSSL_ERR_MAX, + "krb5_init_context() fails: %d\n", krb5rc); + kssl_err->reason = SSL_R_KRB5_C_INIT; + goto err; + } + + if ((krb5rc = krb5_sname_to_principal(krb5context, + kssl_ctx->service_host, + (kssl_ctx->service_name) ? + kssl_ctx->service_name : KRB5SVC, + KRB5_NT_SRV_HST, + &krb5creds.server)) != 0) { + BIO_snprintf(kssl_err->text, KSSL_ERR_MAX, + "krb5_sname_to_principal() fails for %s/%s\n", + kssl_ctx->service_host, + (kssl_ctx-> + service_name) ? kssl_ctx->service_name : KRB5SVC); + kssl_err->reason = SSL_R_KRB5_C_INIT; + goto err; + } + + if ((krb5rc = krb5_cc_default(krb5context, &krb5ccdef)) != 0) { + kssl_err_set(kssl_err, SSL_R_KRB5_C_CC_PRINC, + "krb5_cc_default fails.\n"); + goto err; + } + + if ((krb5rc = krb5_cc_get_principal(krb5context, krb5ccdef, + &krb5creds.client)) != 0) { + kssl_err_set(kssl_err, SSL_R_KRB5_C_CC_PRINC, + "krb5_cc_get_principal() fails.\n"); + goto err; + } + + if ((krb5rc = krb5_get_credentials(krb5context, 0, krb5ccdef, + &krb5creds, &krb5credsp)) != 0) { + kssl_err_set(kssl_err, SSL_R_KRB5_C_GET_CRED, + "krb5_get_credentials() fails.\n"); + goto err; + } + + *enc_ticketp = &krb5credsp->ticket; +# ifdef KRB5_HEIMDAL + kssl_ctx->enctype = krb5credsp->session.keytype; +# else + kssl_ctx->enctype = krb5credsp->keyblock.enctype; +# endif + + krb5rc = KRB5KRB_ERR_GENERIC; + /* caller should free data of krb5_app_req */ + /* + * 20010406 VRS deleted for real KerberosWrapper 20010605 VRS reinstated + * to offer Authenticator to KerberosWrapper + */ + krb5_app_req.length = 0; + if (authenp) { + krb5_data krb5in_data; + const unsigned char *p; + long arlen; + KRB5_APREQBODY *ap_req; + + authenp->length = 0; + krb5in_data.data = NULL; + krb5in_data.length = 0; + if ((krb5rc = krb5_mk_req_extended(krb5context, + &krb5auth_context, 0, &krb5in_data, + krb5credsp, &krb5_app_req)) != 0) { + kssl_err_set(kssl_err, SSL_R_KRB5_C_MK_REQ, + "krb5_mk_req_extended() fails.\n"); + goto err; + } + + arlen = krb5_app_req.length; + p = (unsigned char *)krb5_app_req.data; + ap_req = (KRB5_APREQBODY *)d2i_KRB5_APREQ(NULL, &p, arlen); + if (ap_req) { + authenp->length = i2d_KRB5_ENCDATA(ap_req->authenticator, NULL); + if (authenp->length && (authenp->data = malloc(authenp->length))) { + unsigned char *adp = (unsigned char *)authenp->data; + authenp->length = + i2d_KRB5_ENCDATA(ap_req->authenticator, &adp); + } + } + + if (ap_req) + KRB5_APREQ_free((KRB5_APREQ *) ap_req); + if (krb5_app_req.length) + kssl_krb5_free_data_contents(krb5context, &krb5_app_req); + } +# ifdef KRB5_HEIMDAL + if (kssl_ctx_setkey(kssl_ctx, &krb5credsp->session)) { + kssl_err_set(kssl_err, SSL_R_KRB5_C_INIT, + "kssl_ctx_setkey() fails.\n"); + } +# else + if (kssl_ctx_setkey(kssl_ctx, &krb5credsp->keyblock)) { + kssl_err_set(kssl_err, SSL_R_KRB5_C_INIT, + "kssl_ctx_setkey() fails.\n"); + } +# endif + else + krb5rc = 0; + + err: +# ifdef KSSL_DEBUG + kssl_ctx_show(kssl_ctx); +# endif /* KSSL_DEBUG */ + + if (krb5creds.client) + krb5_free_principal(krb5context, krb5creds.client); + if (krb5creds.server) + krb5_free_principal(krb5context, krb5creds.server); + if (krb5auth_context) + krb5_auth_con_free(krb5context, krb5auth_context); + if (krb5context) + krb5_free_context(krb5context); + return (krb5rc); +} + +/*- + * Given d2i_-decoded asn1ticket, allocate and return a new krb5_ticket. + * Return Kerberos error code and kssl_err struct on error. + * Allocates krb5_ticket and krb5_principal; caller should free these. + * + * 20010410 VRS Implemented krb5_decode_ticket() as + * old_krb5_decode_ticket(). Missing from MIT1.0.6. + * 20010615 VRS Re-cast as openssl/asn1 d2i_*() functions. + * Re-used some of the old krb5_decode_ticket() + * code here. This tkt should alloc/free just + * like the real thing. + */ +static krb5_error_code kssl_TKT2tkt( /* IN */ krb5_context krb5context, + /* + * IN + */ KRB5_TKTBODY *asn1ticket, + /* + * OUT + */ krb5_ticket **krb5ticket, + /* + * OUT + */ KSSL_ERR *kssl_err) +{ + krb5_error_code krb5rc = KRB5KRB_ERR_GENERIC; + krb5_ticket *new5ticket = NULL; + ASN1_GENERALSTRING *gstr_svc, *gstr_host; + + *krb5ticket = NULL; + + if (asn1ticket == NULL || asn1ticket->realm == NULL || + asn1ticket->sname == NULL || + sk_ASN1_GENERALSTRING_num(asn1ticket->sname->namestring) < 2) { + BIO_snprintf(kssl_err->text, KSSL_ERR_MAX, + "Null field in asn1ticket.\n"); + kssl_err->reason = SSL_R_KRB5_S_RD_REQ; + return KRB5KRB_ERR_GENERIC; + } + + if ((new5ticket = (krb5_ticket *)calloc(1, sizeof(krb5_ticket))) == NULL) { + BIO_snprintf(kssl_err->text, KSSL_ERR_MAX, + "Unable to allocate new krb5_ticket.\n"); + kssl_err->reason = SSL_R_KRB5_S_RD_REQ; + return ENOMEM; /* or KRB5KRB_ERR_GENERIC; */ + } + + gstr_svc = sk_ASN1_GENERALSTRING_value(asn1ticket->sname->namestring, 0); + gstr_host = sk_ASN1_GENERALSTRING_value(asn1ticket->sname->namestring, 1); + + if ((krb5rc = kssl_build_principal_2(krb5context, + &new5ticket->server, + asn1ticket->realm->length, + (char *)asn1ticket->realm->data, + gstr_svc->length, + (char *)gstr_svc->data, + gstr_host->length, + (char *)gstr_host->data)) != 0) { + free(new5ticket); + BIO_snprintf(kssl_err->text, KSSL_ERR_MAX, + "Error building ticket server principal.\n"); + kssl_err->reason = SSL_R_KRB5_S_RD_REQ; + return krb5rc; /* or KRB5KRB_ERR_GENERIC; */ + } + + krb5_princ_type(krb5context, new5ticket->server) = + asn1ticket->sname->nametype->data[0]; + new5ticket->enc_part.enctype = asn1ticket->encdata->etype->data[0]; + new5ticket->enc_part.kvno = asn1ticket->encdata->kvno->data[0]; + new5ticket->enc_part.ciphertext.length = + asn1ticket->encdata->cipher->length; + if ((new5ticket->enc_part.ciphertext.data = + calloc(1, asn1ticket->encdata->cipher->length)) == NULL) { + free(new5ticket); + BIO_snprintf(kssl_err->text, KSSL_ERR_MAX, + "Error allocating cipher in krb5ticket.\n"); + kssl_err->reason = SSL_R_KRB5_S_RD_REQ; + return KRB5KRB_ERR_GENERIC; + } else { + memcpy(new5ticket->enc_part.ciphertext.data, + asn1ticket->encdata->cipher->data, + asn1ticket->encdata->cipher->length); + } + + *krb5ticket = new5ticket; + return 0; +} + +/*- + * Given krb5 service name in KSSL_CTX *kssl_ctx (typically "kssl"), + * and krb5 AP_REQ message & message length, + * Return Kerberos session key and client principle + * to SSL Server in KSSL_CTX *kssl_ctx. + * + * 19990702 VRS Started. + */ +krb5_error_code kssl_sget_tkt( /* UPDATE */ KSSL_CTX *kssl_ctx, + /* + * IN + */ krb5_data *indata, + /* + * OUT + */ krb5_ticket_times *ttimes, + /* + * OUT + */ KSSL_ERR *kssl_err) +{ + krb5_error_code krb5rc = KRB5KRB_ERR_GENERIC; + static krb5_context krb5context = NULL; + static krb5_auth_context krb5auth_context = NULL; + krb5_ticket *krb5ticket = NULL; + KRB5_TKTBODY *asn1ticket = NULL; + const unsigned char *p; + krb5_keytab krb5keytab = NULL; + krb5_keytab_entry kt_entry; + krb5_principal krb5server; + krb5_rcache rcache = NULL; + + kssl_err_set(kssl_err, 0, ""); + + if (!kssl_ctx) { + kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, "No kssl_ctx defined.\n"); + goto err; + } +# ifdef KSSL_DEBUG + fprintf(stderr, "in kssl_sget_tkt(%s)\n", + kstring(kssl_ctx->service_name)); +# endif /* KSSL_DEBUG */ + + if (!krb5context && (krb5rc = krb5_init_context(&krb5context))) { + kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, + "krb5_init_context() fails.\n"); + goto err; + } + if (krb5auth_context && + (krb5rc = krb5_auth_con_free(krb5context, krb5auth_context))) { + kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, + "krb5_auth_con_free() fails.\n"); + goto err; + } else + krb5auth_context = NULL; + if (!krb5auth_context && + (krb5rc = krb5_auth_con_init(krb5context, &krb5auth_context))) { + kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, + "krb5_auth_con_init() fails.\n"); + goto err; + } + + if ((krb5rc = krb5_auth_con_getrcache(krb5context, krb5auth_context, + &rcache))) { + kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, + "krb5_auth_con_getrcache() fails.\n"); + goto err; + } + + if ((krb5rc = krb5_sname_to_principal(krb5context, NULL, + (kssl_ctx->service_name) ? + kssl_ctx->service_name : KRB5SVC, + KRB5_NT_SRV_HST, + &krb5server)) != 0) { + kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, + "krb5_sname_to_principal() fails.\n"); + goto err; + } + + if (rcache == NULL) { + if ((krb5rc = krb5_get_server_rcache(krb5context, + krb5_princ_component(krb5context, + krb5server, + 0), + &rcache))) { + kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, + "krb5_get_server_rcache() fails.\n"); + goto err; + } + } + + if ((krb5rc = + krb5_auth_con_setrcache(krb5context, krb5auth_context, rcache))) { + kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, + "krb5_auth_con_setrcache() fails.\n"); + goto err; + } + + /* + * kssl_ctx->keytab_file == NULL ==> use Kerberos default + */ + if (kssl_ctx->keytab_file) { + krb5rc = krb5_kt_resolve(krb5context, kssl_ctx->keytab_file, + &krb5keytab); + if (krb5rc) { + kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, + "krb5_kt_resolve() fails.\n"); + goto err; + } + } else { + krb5rc = krb5_kt_default(krb5context, &krb5keytab); + if (krb5rc) { + kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, + "krb5_kt_default() fails.\n"); + goto err; + } + } + + /*- Actual Kerberos5 krb5_recvauth() has initial conversation here + * o check KRB5_SENDAUTH_BADAUTHVERS + * unless KRB5_RECVAUTH_SKIP_VERSION + * o check KRB5_SENDAUTH_BADAPPLVERS + * o send "0" msg if all OK + */ + + /*- + * 20010411 was using AP_REQ instead of true KerberosWrapper + * + * if ((krb5rc = krb5_rd_req(krb5context, &krb5auth_context, + * &krb5in_data, krb5server, krb5keytab, + * &ap_option, &krb5ticket)) != 0) { Error } + */ + + p = (unsigned char *)indata->data; + if ((asn1ticket = (KRB5_TKTBODY *)d2i_KRB5_TICKET(NULL, &p, + (long)indata->length)) + == NULL) { + BIO_snprintf(kssl_err->text, KSSL_ERR_MAX, + "d2i_KRB5_TICKET() ASN.1 decode failure.\n"); + kssl_err->reason = SSL_R_KRB5_S_RD_REQ; + goto err; + } + + /* + * Was: krb5rc = krb5_decode_ticket(krb5in_data,&krb5ticket)) != 0) + */ + if ((krb5rc = kssl_TKT2tkt(krb5context, asn1ticket, &krb5ticket, + kssl_err)) != 0) { + BIO_snprintf(kssl_err->text, KSSL_ERR_MAX, + "Error converting ASN.1 ticket to krb5_ticket.\n"); + kssl_err->reason = SSL_R_KRB5_S_RD_REQ; + goto err; + } + + if (!krb5_principal_compare(krb5context, krb5server, krb5ticket->server)) { + krb5rc = KRB5_PRINC_NOMATCH; + BIO_snprintf(kssl_err->text, KSSL_ERR_MAX, + "server principal != ticket principal\n"); + kssl_err->reason = SSL_R_KRB5_S_RD_REQ; + goto err; + } + if ((krb5rc = krb5_kt_get_entry(krb5context, krb5keytab, + krb5ticket->server, + krb5ticket->enc_part.kvno, + krb5ticket->enc_part.enctype, + &kt_entry)) != 0) { + BIO_snprintf(kssl_err->text, KSSL_ERR_MAX, + "krb5_kt_get_entry() fails with %x.\n", krb5rc); + kssl_err->reason = SSL_R_KRB5_S_RD_REQ; + goto err; + } + if ((krb5rc = krb5_decrypt_tkt_part(krb5context, &kt_entry.key, + krb5ticket)) != 0) { + BIO_snprintf(kssl_err->text, KSSL_ERR_MAX, + "krb5_decrypt_tkt_part() failed.\n"); + kssl_err->reason = SSL_R_KRB5_S_RD_REQ; + goto err; + } else { + krb5_kt_free_entry(krb5context, &kt_entry); +# ifdef KSSL_DEBUG + { + int i; + krb5_address **paddr = krb5ticket->enc_part2->caddrs; + fprintf(stderr, "Decrypted ticket fields:\n"); + fprintf(stderr, "\tflags: %X, transit-type: %X", + krb5ticket->enc_part2->flags, + krb5ticket->enc_part2->transited.tr_type); + print_krb5_data("\ttransit-data: ", + &(krb5ticket->enc_part2->transited.tr_contents)); + fprintf(stderr, "\tcaddrs: %p, authdata: %p\n", + krb5ticket->enc_part2->caddrs, + krb5ticket->enc_part2->authorization_data); + if (paddr) { + fprintf(stderr, "\tcaddrs:\n"); + for (i = 0; paddr[i] != NULL; i++) { + krb5_data d; + d.length = paddr[i]->length; + d.data = paddr[i]->contents; + print_krb5_data("\t\tIP: ", &d); + } + } + fprintf(stderr, "\tstart/auth/end times: %d / %d / %d\n", + krb5ticket->enc_part2->times.starttime, + krb5ticket->enc_part2->times.authtime, + krb5ticket->enc_part2->times.endtime); + } +# endif /* KSSL_DEBUG */ + } + + krb5rc = KRB5_NO_TKT_SUPPLIED; + if (!krb5ticket || !krb5ticket->enc_part2 || + !krb5ticket->enc_part2->client || + !krb5ticket->enc_part2->client->data || + !krb5ticket->enc_part2->session) { + kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET, + "bad ticket from krb5_rd_req.\n"); + } else if (kssl_ctx_setprinc(kssl_ctx, KSSL_CLIENT, + &krb5ticket->enc_part2->client->realm, + krb5ticket->enc_part2->client->data, + krb5ticket->enc_part2->client->length)) { + kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET, + "kssl_ctx_setprinc() fails.\n"); + } else if (kssl_ctx_setkey(kssl_ctx, krb5ticket->enc_part2->session)) { + kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET, + "kssl_ctx_setkey() fails.\n"); + } else if (krb5ticket->enc_part2->flags & TKT_FLG_INVALID) { + krb5rc = KRB5KRB_AP_ERR_TKT_INVALID; + kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET, + "invalid ticket from krb5_rd_req.\n"); + } else + krb5rc = 0; + + kssl_ctx->enctype = krb5ticket->enc_part.enctype; + ttimes->authtime = krb5ticket->enc_part2->times.authtime; + ttimes->starttime = krb5ticket->enc_part2->times.starttime; + ttimes->endtime = krb5ticket->enc_part2->times.endtime; + ttimes->renew_till = krb5ticket->enc_part2->times.renew_till; + + err: +# ifdef KSSL_DEBUG + kssl_ctx_show(kssl_ctx); +# endif /* KSSL_DEBUG */ + + if (asn1ticket) + KRB5_TICKET_free((KRB5_TICKET *) asn1ticket); + if (krb5keytab) + krb5_kt_close(krb5context, krb5keytab); + if (krb5ticket) + krb5_free_ticket(krb5context, krb5ticket); + if (krb5server) + krb5_free_principal(krb5context, krb5server); + return (krb5rc); +} + +/* + * Allocate & return a new kssl_ctx struct. + */ +KSSL_CTX *kssl_ctx_new(void) +{ + return ((KSSL_CTX *)kssl_calloc(1, sizeof(KSSL_CTX))); +} + +/* + * Frees a kssl_ctx struct and any allocated memory it holds. Returns NULL. + */ +KSSL_CTX *kssl_ctx_free(KSSL_CTX *kssl_ctx) +{ + if (kssl_ctx == NULL) + return kssl_ctx; + + if (kssl_ctx->key) + OPENSSL_cleanse(kssl_ctx->key, kssl_ctx->length); + if (kssl_ctx->key) + kssl_free(kssl_ctx->key); + if (kssl_ctx->client_princ) + kssl_free(kssl_ctx->client_princ); + if (kssl_ctx->service_host) + kssl_free(kssl_ctx->service_host); + if (kssl_ctx->service_name) + kssl_free(kssl_ctx->service_name); + if (kssl_ctx->keytab_file) + kssl_free(kssl_ctx->keytab_file); + + kssl_free(kssl_ctx); + return (KSSL_CTX *)NULL; +} + +/* + * Given an array of (krb5_data *) entity (and optional realm), set the plain + * (char *) client_princ or service_host member of the kssl_ctx struct. + */ +krb5_error_code +kssl_ctx_setprinc(KSSL_CTX *kssl_ctx, int which, + krb5_data *realm, krb5_data *entity, int nentities) +{ + char **princ; + int length; + int i; + + if (kssl_ctx == NULL || entity == NULL) + return KSSL_CTX_ERR; + + switch (which) { + case KSSL_CLIENT: + princ = &kssl_ctx->client_princ; + break; + case KSSL_SERVER: + princ = &kssl_ctx->service_host; + break; + default: + return KSSL_CTX_ERR; + break; + } + if (*princ) + kssl_free(*princ); + + /* Add up all the entity->lengths */ + length = 0; + for (i = 0; i < nentities; i++) { + length += entity[i].length; + } + /* Add in space for the '/' character(s) (if any) */ + length += nentities - 1; + /* Space for the ('@'+realm+NULL | NULL) */ + length += ((realm) ? realm->length + 2 : 1); + + if ((*princ = kssl_calloc(1, length)) == NULL) + return KSSL_CTX_ERR; + else { + for (i = 0; i < nentities; i++) { + strncat(*princ, entity[i].data, entity[i].length); + if (i < nentities - 1) { + strcat(*princ, "/"); + } + } + if (realm) { + strcat(*princ, "@"); + (void)strncat(*princ, realm->data, realm->length); + } + } + + return KSSL_CTX_OK; +} + +/*- Set one of the plain (char *) string members of the kssl_ctx struct. + * Default values should be: + * which == KSSL_SERVICE => "khost" (KRB5SVC) + * which == KSSL_KEYTAB => "/etc/krb5.keytab" (KRB5KEYTAB) + */ +krb5_error_code kssl_ctx_setstring(KSSL_CTX *kssl_ctx, int which, char *text) +{ + char **string; + + if (!kssl_ctx) + return KSSL_CTX_ERR; + + switch (which) { + case KSSL_SERVICE: + string = &kssl_ctx->service_name; + break; + case KSSL_SERVER: + string = &kssl_ctx->service_host; + break; + case KSSL_CLIENT: + string = &kssl_ctx->client_princ; + break; + case KSSL_KEYTAB: + string = &kssl_ctx->keytab_file; + break; + default: + return KSSL_CTX_ERR; + break; + } + if (*string) + kssl_free(*string); + + if (!text) { + *string = '\0'; + return KSSL_CTX_OK; + } + + if ((*string = kssl_calloc(1, strlen(text) + 1)) == NULL) + return KSSL_CTX_ERR; + else + strcpy(*string, text); + + return KSSL_CTX_OK; +} + +/* + * Copy the Kerberos session key from a (krb5_keyblock *) to a kssl_ctx + * struct. Clear kssl_ctx->key if Kerberos session key is NULL. + */ +krb5_error_code kssl_ctx_setkey(KSSL_CTX *kssl_ctx, krb5_keyblock *session) +{ + int length; + krb5_enctype enctype; + krb5_octet FAR *contents = NULL; + + if (!kssl_ctx) + return KSSL_CTX_ERR; + + if (kssl_ctx->key) { + OPENSSL_cleanse(kssl_ctx->key, kssl_ctx->length); + kssl_free(kssl_ctx->key); + } + + if (session) { + +# ifdef KRB5_HEIMDAL + length = session->keyvalue->length; + enctype = session->keytype; + contents = session->keyvalue->contents; +# else + length = session->length; + enctype = session->enctype; + contents = session->contents; +# endif + kssl_ctx->enctype = enctype; + kssl_ctx->length = length; + } else { + kssl_ctx->enctype = ENCTYPE_UNKNOWN; + kssl_ctx->length = 0; + return KSSL_CTX_OK; + } + + if ((kssl_ctx->key = + (krb5_octet FAR *)kssl_calloc(1, kssl_ctx->length)) == NULL) { + kssl_ctx->length = 0; + return KSSL_CTX_ERR; + } else + memcpy(kssl_ctx->key, contents, length); + + return KSSL_CTX_OK; +} + +/* + * Display contents of kssl_ctx struct + */ +void kssl_ctx_show(KSSL_CTX *kssl_ctx) +{ + int i; + + printf("kssl_ctx: "); + if (kssl_ctx == NULL) { + printf("NULL\n"); + return; + } else + printf("%p\n", (void *)kssl_ctx); + + printf("\tservice:\t%s\n", + (kssl_ctx->service_name) ? kssl_ctx->service_name : "NULL"); + printf("\tclient:\t%s\n", + (kssl_ctx->client_princ) ? kssl_ctx->client_princ : "NULL"); + printf("\tserver:\t%s\n", + (kssl_ctx->service_host) ? kssl_ctx->service_host : "NULL"); + printf("\tkeytab:\t%s\n", + (kssl_ctx->keytab_file) ? kssl_ctx->keytab_file : "NULL"); + printf("\tkey [%d:%d]:\t", kssl_ctx->enctype, kssl_ctx->length); + + for (i = 0; i < kssl_ctx->length && kssl_ctx->key; i++) { + printf("%02x", kssl_ctx->key[i]); + } + printf("\n"); + return; +} + +int kssl_keytab_is_available(KSSL_CTX *kssl_ctx) +{ + krb5_context krb5context = NULL; + krb5_keytab krb5keytab = NULL; + krb5_keytab_entry entry; + krb5_principal princ = NULL; + krb5_error_code krb5rc = KRB5KRB_ERR_GENERIC; + int rc = 0; + + if ((krb5rc = krb5_init_context(&krb5context))) + return (0); + + /* + * kssl_ctx->keytab_file == NULL ==> use Kerberos default + */ + if (kssl_ctx->keytab_file) { + krb5rc = krb5_kt_resolve(krb5context, kssl_ctx->keytab_file, + &krb5keytab); + if (krb5rc) + goto exit; + } else { + krb5rc = krb5_kt_default(krb5context, &krb5keytab); + if (krb5rc) + goto exit; + } + + /* the host key we are looking for */ + krb5rc = krb5_sname_to_principal(krb5context, NULL, + kssl_ctx-> + service_name ? kssl_ctx->service_name : + KRB5SVC, KRB5_NT_SRV_HST, &princ); + + if (krb5rc) + goto exit; + + krb5rc = krb5_kt_get_entry(krb5context, krb5keytab, princ, + /* IGNORE_VNO */ + 0, + /* IGNORE_ENCTYPE */ + 0, &entry); + if (krb5rc == KRB5_KT_NOTFOUND) { + rc = 1; + goto exit; + } else if (krb5rc) + goto exit; + + krb5_kt_free_entry(krb5context, &entry); + rc = 1; + + exit: + if (krb5keytab) + krb5_kt_close(krb5context, krb5keytab); + if (princ) + krb5_free_principal(krb5context, princ); + if (krb5context) + krb5_free_context(krb5context); + return (rc); +} + +int kssl_tgt_is_available(KSSL_CTX *kssl_ctx) +{ + krb5_error_code krb5rc = KRB5KRB_ERR_GENERIC; + krb5_context krb5context = NULL; + krb5_ccache krb5ccdef = NULL; + krb5_creds krb5creds, *krb5credsp = NULL; + int rc = 0; + + memset((char *)&krb5creds, 0, sizeof(krb5creds)); + + if (!kssl_ctx) + return (0); + + if (!kssl_ctx->service_host) + return (0); + + if ((krb5rc = krb5_init_context(&krb5context)) != 0) + goto err; + + if ((krb5rc = krb5_sname_to_principal(krb5context, + kssl_ctx->service_host, + (kssl_ctx->service_name) ? + kssl_ctx->service_name : KRB5SVC, + KRB5_NT_SRV_HST, + &krb5creds.server)) != 0) + goto err; + + if ((krb5rc = krb5_cc_default(krb5context, &krb5ccdef)) != 0) + goto err; + + if ((krb5rc = krb5_cc_get_principal(krb5context, krb5ccdef, + &krb5creds.client)) != 0) + goto err; + + if ((krb5rc = krb5_get_credentials(krb5context, 0, krb5ccdef, + &krb5creds, &krb5credsp)) != 0) + goto err; + + rc = 1; + + err: +# ifdef KSSL_DEBUG + kssl_ctx_show(kssl_ctx); +# endif /* KSSL_DEBUG */ + + if (krb5creds.client) + krb5_free_principal(krb5context, krb5creds.client); + if (krb5creds.server) + krb5_free_principal(krb5context, krb5creds.server); + if (krb5context) + krb5_free_context(krb5context); + return (rc); +} + +# if !defined(OPENSSL_SYS_WINDOWS) && !defined(OPENSSL_SYS_WIN32) +void kssl_krb5_free_data_contents(krb5_context context, krb5_data *data) +{ +# ifdef KRB5_HEIMDAL + data->length = 0; + if (data->data) + free(data->data); +# elif defined(KRB5_MIT_OLD11) + if (data->data) { + krb5_xfree(data->data); + data->data = 0; + } +# else + krb5_free_data_contents(NULL, data); +# endif +} +# endif +/* !OPENSSL_SYS_WINDOWS && !OPENSSL_SYS_WIN32 */ + +/* + * Given pointers to KerberosTime and struct tm structs, convert the + * KerberosTime string to struct tm. Note that KerberosTime is a + * ASN1_GENERALIZEDTIME value, constrained to GMT with no fractional seconds + * as defined in RFC 1510. Return pointer to the (partially) filled in + * struct tm on success, return NULL on failure. + */ +static struct tm *k_gmtime(ASN1_GENERALIZEDTIME *gtime, struct tm *k_tm) +{ + char c, *p; + + if (!k_tm) + return NULL; + if (gtime == NULL || gtime->length < 14) + return NULL; + if (gtime->data == NULL) + return NULL; + + p = (char *)>ime->data[14]; + + c = *p; + *p = '\0'; + p -= 2; + k_tm->tm_sec = atoi(p); + *(p + 2) = c; + c = *p; + *p = '\0'; + p -= 2; + k_tm->tm_min = atoi(p); + *(p + 2) = c; + c = *p; + *p = '\0'; + p -= 2; + k_tm->tm_hour = atoi(p); + *(p + 2) = c; + c = *p; + *p = '\0'; + p -= 2; + k_tm->tm_mday = atoi(p); + *(p + 2) = c; + c = *p; + *p = '\0'; + p -= 2; + k_tm->tm_mon = atoi(p) - 1; + *(p + 2) = c; + c = *p; + *p = '\0'; + p -= 4; + k_tm->tm_year = atoi(p) - 1900; + *(p + 4) = c; + + return k_tm; +} + +/* + * Helper function for kssl_validate_times(). We need context->clockskew, + * but krb5_context is an opaque struct. So we try to sneek the clockskew + * out through the replay cache. If that fails just return a likely default + * (300 seconds). + */ +static krb5_deltat get_rc_clockskew(krb5_context context) +{ + krb5_rcache rc; + krb5_deltat clockskew; + + if (krb5_rc_default(context, &rc)) + return KSSL_CLOCKSKEW; + if (krb5_rc_initialize(context, rc, 0)) + return KSSL_CLOCKSKEW; + if (krb5_rc_get_lifespan(context, rc, &clockskew)) { + clockskew = KSSL_CLOCKSKEW; + } + (void)krb5_rc_destroy(context, rc); + return clockskew; +} + +/* + * kssl_validate_times() combines (and more importantly exposes) the MIT KRB5 + * internal function krb5_validate_times() and the in_clock_skew() macro. + * The authenticator client time is checked to be within clockskew secs of + * the current time and the current time is checked to be within the ticket + * start and expire times. Either check may be omitted by supplying a NULL + * value. Returns 0 for valid times, SSL_R_KRB5* error codes otherwise. See + * Also: (Kerberos source)/krb5/lib/krb5/krb/valid_times.c 20010420 VRS + */ +krb5_error_code kssl_validate_times(krb5_timestamp atime, + krb5_ticket_times *ttimes) +{ + krb5_deltat skew; + krb5_timestamp start, now; + krb5_error_code rc; + krb5_context context; + + if ((rc = krb5_init_context(&context))) + return SSL_R_KRB5_S_BAD_TICKET; + skew = get_rc_clockskew(context); + if ((rc = krb5_timeofday(context, &now))) + return SSL_R_KRB5_S_BAD_TICKET; + krb5_free_context(context); + + if (atime && labs(atime - now) >= skew) + return SSL_R_KRB5_S_TKT_SKEW; + + if (!ttimes) + return 0; + + start = (ttimes->starttime != 0) ? ttimes->starttime : ttimes->authtime; + if (start - now > skew) + return SSL_R_KRB5_S_TKT_NYV; + if ((now - ttimes->endtime) > skew) + return SSL_R_KRB5_S_TKT_EXPIRED; + +# ifdef KSSL_DEBUG + fprintf(stderr, "kssl_validate_times: %d |<- | %d - %d | < %d ->| %d\n", + start, atime, now, skew, ttimes->endtime); +# endif /* KSSL_DEBUG */ + + return 0; +} + +/* + * Decode and decrypt given DER-encoded authenticator, then pass + * authenticator ctime back in *atimep (or 0 if time unavailable). Returns + * krb5_error_code and kssl_err on error. A NULL authenticator + * (authentp->length == 0) is not considered an error. Note that + * kssl_check_authent() makes use of the KRB5 session key; you must call + * kssl_sget_tkt() to get the key before calling this routine. + */ +krb5_error_code kssl_check_authent( + /* + * IN + */ KSSL_CTX *kssl_ctx, + /* + * IN + */ krb5_data *authentp, + /* + * OUT + */ krb5_timestamp *atimep, + /* + * OUT + */ KSSL_ERR *kssl_err) +{ + krb5_error_code krb5rc = 0; + KRB5_ENCDATA *dec_authent = NULL; + KRB5_AUTHENTBODY *auth = NULL; + krb5_enctype enctype; + EVP_CIPHER_CTX ciph_ctx; + const EVP_CIPHER *enc = NULL; + unsigned char iv[EVP_MAX_IV_LENGTH]; + const unsigned char *p; + unsigned char *unenc_authent; + int outl, unencbufsize; + struct tm tm_time, *tm_l, *tm_g; + time_t now, tl, tg, tr, tz_offset; + + EVP_CIPHER_CTX_init(&ciph_ctx); + *atimep = 0; + kssl_err_set(kssl_err, 0, ""); + +# ifndef KRB5CHECKAUTH + authentp = NULL; +# else +# if KRB5CHECKAUTH == 0 + authentp = NULL; +# endif +# endif /* KRB5CHECKAUTH */ + + if (authentp == NULL || authentp->length == 0) + return 0; + +# ifdef KSSL_DEBUG + { + unsigned int ui; + fprintf(stderr, "kssl_check_authent: authenticator[%d]:\n", + authentp->length); + p = authentp->data; + for (ui = 0; ui < authentp->length; ui++) + fprintf(stderr, "%02x ", p[ui]); + fprintf(stderr, "\n"); + } +# endif /* KSSL_DEBUG */ + + unencbufsize = 2 * authentp->length; + if ((unenc_authent = calloc(1, unencbufsize)) == NULL) { + kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, + "Unable to allocate authenticator buffer.\n"); + krb5rc = KRB5KRB_ERR_GENERIC; + goto err; + } + + p = (unsigned char *)authentp->data; + if ((dec_authent = d2i_KRB5_ENCDATA(NULL, &p, + (long)authentp->length)) == NULL) { + kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, + "Error decoding authenticator.\n"); + krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY; + goto err; + } + + enctype = dec_authent->etype->data[0]; /* should = kssl_ctx->enctype */ +# if !defined(KRB5_MIT_OLD11) + switch (enctype) { + case ENCTYPE_DES3_CBC_SHA1: /* EVP_des_ede3_cbc(); */ + case ENCTYPE_DES3_CBC_SHA: + case ENCTYPE_DES3_CBC_RAW: + krb5rc = 0; /* Skip, can't handle derived keys */ + goto err; + } +# endif + enc = kssl_map_enc(enctype); + memset(iv, 0, sizeof iv); /* per RFC 1510 */ + + if (enc == NULL) { + /* + * Disable kssl_check_authent for ENCTYPE_DES3_CBC_SHA1. This + * enctype indicates the authenticator was encrypted using key-usage + * derived keys which openssl cannot decrypt. + */ + goto err; + } + + if (!EVP_CipherInit(&ciph_ctx, enc, kssl_ctx->key, iv, 0)) { + kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, + "EVP_CipherInit error decrypting authenticator.\n"); + krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY; + goto err; + } + outl = dec_authent->cipher->length; + if (!EVP_Cipher + (&ciph_ctx, unenc_authent, dec_authent->cipher->data, outl)) { + kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, + "EVP_Cipher error decrypting authenticator.\n"); + krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY; + goto err; + } + EVP_CIPHER_CTX_cleanup(&ciph_ctx); + +# ifdef KSSL_DEBUG + { + int padl; + fprintf(stderr, "kssl_check_authent: decrypted authenticator[%d] =\n", + outl); + for (padl = 0; padl < outl; padl++) + fprintf(stderr, "%02x ", unenc_authent[padl]); + fprintf(stderr, "\n"); + } +# endif /* KSSL_DEBUG */ + + if ((p = kssl_skip_confound(enctype, unenc_authent)) == NULL) { + kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, + "confounded by authenticator.\n"); + krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY; + goto err; + } + outl -= p - unenc_authent; + + if ((auth = (KRB5_AUTHENTBODY *)d2i_KRB5_AUTHENT(NULL, &p, + (long)outl)) == NULL) { + kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, + "Error decoding authenticator body.\n"); + krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY; + goto err; + } + + memset(&tm_time, 0, sizeof(struct tm)); + if (k_gmtime(auth->ctime, &tm_time) && + ((tr = mktime(&tm_time)) != (time_t)(-1))) { + now = time(&now); + tm_l = localtime(&now); + tl = mktime(tm_l); + tm_g = gmtime(&now); + tg = mktime(tm_g); + tz_offset = tg - tl; + + *atimep = (krb5_timestamp)(tr - tz_offset); + } +# ifdef KSSL_DEBUG + fprintf(stderr, "kssl_check_authent: returns %d for client time ", + *atimep); + if (auth && auth->ctime && auth->ctime->length && auth->ctime->data) + fprintf(stderr, "%.*s\n", auth->ctime->length, auth->ctime->data); + else + fprintf(stderr, "NULL\n"); +# endif /* KSSL_DEBUG */ + + err: + if (auth) + KRB5_AUTHENT_free((KRB5_AUTHENT *) auth); + if (dec_authent) + KRB5_ENCDATA_free(dec_authent); + if (unenc_authent) + free(unenc_authent); + EVP_CIPHER_CTX_cleanup(&ciph_ctx); + return krb5rc; +} + +/* + * Replaces krb5_build_principal_ext(), with varargs length == 2 (svc, host), + * because I don't know how to stub varargs. Returns krb5_error_code == + * ENOMEM on alloc error, otherwise passes back newly constructed principal, + * which should be freed by caller. + */ +krb5_error_code kssl_build_principal_2( + /* + * UPDATE + */ krb5_context context, + /* + * OUT + */ krb5_principal *princ, + /* + * IN + */ int rlen, const char *realm, + /* + * IN + */ int slen, const char *svc, + /* + * IN + */ int hlen, const char *host) +{ + krb5_data *p_data = NULL; + krb5_principal new_p = NULL; + char *new_r = NULL; + + if ((p_data = (krb5_data *)calloc(2, sizeof(krb5_data))) == NULL || + (new_p = (krb5_principal)calloc(1, sizeof(krb5_principal_data))) + == NULL) + goto err; + new_p->length = 2; + new_p->data = p_data; + + if ((new_r = calloc(1, rlen + 1)) == NULL) + goto err; + memcpy(new_r, realm, rlen); + krb5_princ_set_realm_length(context, new_p, rlen); + krb5_princ_set_realm_data(context, new_p, new_r); + + if ((new_p->data[0].data = calloc(1, slen + 1)) == NULL) + goto err; + memcpy(new_p->data[0].data, svc, slen); + new_p->data[0].length = slen; + + if ((new_p->data[1].data = calloc(1, hlen + 1)) == NULL) + goto err; + memcpy(new_p->data[1].data, host, hlen); + new_p->data[1].length = hlen; + + krb5_princ_type(context, new_p) = KRB5_NT_UNKNOWN; + *princ = new_p; + return 0; + + err: + if (new_p && new_p[0].data) + free(new_p[0].data); + if (new_p && new_p[1].data) + free(new_p[1].data); + if (new_p) + free(new_p); + if (new_r) + free(new_r); + return ENOMEM; +} + +void SSL_set0_kssl_ctx(SSL *s, KSSL_CTX *kctx) +{ + s->kssl_ctx = kctx; +} + +KSSL_CTX *SSL_get0_kssl_ctx(SSL *s) +{ + return s->kssl_ctx; +} + +char *kssl_ctx_get0_client_princ(KSSL_CTX *kctx) +{ + if (kctx) + return kctx->client_princ; + return NULL; +} + +#else /* !OPENSSL_NO_KRB5 */ + +# if defined(PEDANTIC) || defined(OPENSSL_SYS_VMS) +static void *dummy = &dummy; +# endif + +#endif /* !OPENSSL_NO_KRB5 */ diff --git a/thirdparty/openssl/ssl/kssl_lcl.h b/thirdparty/openssl/ssl/kssl_lcl.h new file mode 100644 index 0000000000..8e6a6d69e9 --- /dev/null +++ b/thirdparty/openssl/ssl/kssl_lcl.h @@ -0,0 +1,88 @@ +/* ssl/kssl.h */ +/* + * Written by Vern Staats <staatsvr@asc.hpc.mil> for the OpenSSL project + * 2000. project 2000. + */ +/* ==================================================================== + * Copyright (c) 2000 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 + * licensing@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). + * + */ + +#ifndef KSSL_LCL_H +# define KSSL_LCL_H + +# include <openssl/kssl.h> + +# ifndef OPENSSL_NO_KRB5 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Private (internal to OpenSSL) */ +void print_krb5_data(char *label, krb5_data *kdata); +void print_krb5_authdata(char *label, krb5_authdata **adata); +void print_krb5_keyblock(char *label, krb5_keyblock *keyblk); + +char *kstring(char *string); +char *knumber(int len, krb5_octet *contents); + +const EVP_CIPHER *kssl_map_enc(krb5_enctype enctype); + +int kssl_keytab_is_available(KSSL_CTX *kssl_ctx); +int kssl_tgt_is_available(KSSL_CTX *kssl_ctx); + +#ifdef __cplusplus +} +#endif +# endif /* OPENSSL_NO_KRB5 */ +#endif /* KSSL_LCL_H */ diff --git a/thirdparty/openssl/ssl/s23_clnt.c b/thirdparty/openssl/ssl/s23_clnt.c new file mode 100644 index 0000000000..f782010c47 --- /dev/null +++ b/thirdparty/openssl/ssl/s23_clnt.c @@ -0,0 +1,802 @@ +/* ssl/s23_clnt.c */ +/* 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-2006 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 <stdio.h> +#include "ssl_locl.h" +#include <openssl/buffer.h> +#include <openssl/rand.h> +#include <openssl/objects.h> +#include <openssl/evp.h> + +static const SSL_METHOD *ssl23_get_client_method(int ver); +static int ssl23_client_hello(SSL *s); +static int ssl23_get_server_hello(SSL *s); +static const SSL_METHOD *ssl23_get_client_method(int ver) +{ +#ifndef OPENSSL_NO_SSL2 + if (ver == SSL2_VERSION) + return (SSLv2_client_method()); +#endif +#ifndef OPENSSL_NO_SSL3 + if (ver == SSL3_VERSION) + return (SSLv3_client_method()); +#endif + if (ver == TLS1_VERSION) + return (TLSv1_client_method()); + else if (ver == TLS1_1_VERSION) + return (TLSv1_1_client_method()); + else if (ver == TLS1_2_VERSION) + return (TLSv1_2_client_method()); + else + return (NULL); +} + +IMPLEMENT_ssl23_meth_func(SSLv23_client_method, + ssl_undefined_function, + ssl23_connect, ssl23_get_client_method) + +int ssl23_connect(SSL *s) +{ + BUF_MEM *buf = NULL; + unsigned long Time = (unsigned long)time(NULL); + void (*cb) (const SSL *ssl, int type, int val) = NULL; + int ret = -1; + int new_state, state; + + RAND_add(&Time, sizeof(Time), 0); + ERR_clear_error(); + clear_sys_error(); + + if (s->info_callback != NULL) + cb = s->info_callback; + else if (s->ctx->info_callback != NULL) + cb = s->ctx->info_callback; + + s->in_handshake++; + if (!SSL_in_init(s) || SSL_in_before(s)) + SSL_clear(s); + + for (;;) { + state = s->state; + + switch (s->state) { + case SSL_ST_BEFORE: + case SSL_ST_CONNECT: + case SSL_ST_BEFORE | SSL_ST_CONNECT: + case SSL_ST_OK | SSL_ST_CONNECT: + + if (s->session != NULL) { + SSLerr(SSL_F_SSL23_CONNECT, + SSL_R_SSL23_DOING_SESSION_ID_REUSE); + ret = -1; + goto end; + } + s->server = 0; + if (cb != NULL) + cb(s, SSL_CB_HANDSHAKE_START, 1); + + /* s->version=TLS1_VERSION; */ + s->type = SSL_ST_CONNECT; + + if (s->init_buf == NULL) { + if ((buf = BUF_MEM_new()) == NULL) { + ret = -1; + goto end; + } + if (!BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) { + ret = -1; + goto end; + } + s->init_buf = buf; + buf = NULL; + } + + if (!ssl3_setup_buffers(s)) { + ret = -1; + goto end; + } + + ssl3_init_finished_mac(s); + + s->state = SSL23_ST_CW_CLNT_HELLO_A; + s->ctx->stats.sess_connect++; + s->init_num = 0; + break; + + case SSL23_ST_CW_CLNT_HELLO_A: + case SSL23_ST_CW_CLNT_HELLO_B: + + s->shutdown = 0; + ret = ssl23_client_hello(s); + if (ret <= 0) + goto end; + s->state = SSL23_ST_CR_SRVR_HELLO_A; + s->init_num = 0; + + break; + + case SSL23_ST_CR_SRVR_HELLO_A: + case SSL23_ST_CR_SRVR_HELLO_B: + ret = ssl23_get_server_hello(s); + if (ret >= 0) + cb = NULL; + goto end; + /* break; */ + + default: + SSLerr(SSL_F_SSL23_CONNECT, SSL_R_UNKNOWN_STATE); + ret = -1; + goto end; + /* break; */ + } + + if (s->debug) { + (void)BIO_flush(s->wbio); + } + + if ((cb != NULL) && (s->state != state)) { + new_state = s->state; + s->state = state; + cb(s, SSL_CB_CONNECT_LOOP, 1); + s->state = new_state; + } + } + end: + s->in_handshake--; + if (buf != NULL) + BUF_MEM_free(buf); + if (cb != NULL) + cb(s, SSL_CB_CONNECT_EXIT, ret); + return (ret); +} + +static int ssl23_no_ssl2_ciphers(SSL *s) +{ + SSL_CIPHER *cipher; + STACK_OF(SSL_CIPHER) *ciphers; + int i; + ciphers = SSL_get_ciphers(s); + for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) { + cipher = sk_SSL_CIPHER_value(ciphers, i); + if (cipher->algorithm_ssl == SSL_SSLV2) + return 0; + } + return 1; +} + +/* + * Fill a ClientRandom or ServerRandom field of length len. Returns <= 0 on + * failure, 1 on success. + */ +int ssl_fill_hello_random(SSL *s, int server, unsigned char *result, int len) +{ + int send_time = 0; + if (len < 4) + return 0; + if (server) + send_time = (s->mode & SSL_MODE_SEND_SERVERHELLO_TIME) != 0; + else + send_time = (s->mode & SSL_MODE_SEND_CLIENTHELLO_TIME) != 0; + if (send_time) { + unsigned long Time = (unsigned long)time(NULL); + unsigned char *p = result; + l2n(Time, p); + return RAND_pseudo_bytes(p, len - 4); + } else + return RAND_pseudo_bytes(result, len); +} + +static int ssl23_client_hello(SSL *s) +{ + unsigned char *buf; + unsigned char *p, *d; + int i, ch_len; + unsigned long l; + int ssl2_compat; + int version = 0, version_major, version_minor; + int al = 0; +#ifndef OPENSSL_NO_COMP + int j; + SSL_COMP *comp; +#endif + int ret; + unsigned long mask, options = s->options; + + ssl2_compat = (options & SSL_OP_NO_SSLv2) ? 0 : 1; + + if (ssl2_compat && ssl23_no_ssl2_ciphers(s)) + ssl2_compat = 0; + + /* + * SSL_OP_NO_X disables all protocols above X *if* there are + * some protocols below X enabled. This is required in order + * to maintain "version capability" vector contiguous. So + * that if application wants to disable TLS1.0 in favour of + * TLS1>=1, it would be insufficient to pass SSL_NO_TLSv1, the + * answer is SSL_OP_NO_TLSv1|SSL_OP_NO_SSLv3|SSL_OP_NO_SSLv2. + */ + mask = SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1 +#if !defined(OPENSSL_NO_SSL3) + | SSL_OP_NO_SSLv3 +#endif +#if !defined(OPENSSL_NO_SSL2) + | (ssl2_compat ? SSL_OP_NO_SSLv2 : 0) +#endif + ; +#if !defined(OPENSSL_NO_TLS1_2_CLIENT) + version = TLS1_2_VERSION; + + if ((options & SSL_OP_NO_TLSv1_2) && (options & mask) != mask) + version = TLS1_1_VERSION; +#else + version = TLS1_1_VERSION; +#endif + mask &= ~SSL_OP_NO_TLSv1_1; + if ((options & SSL_OP_NO_TLSv1_1) && (options & mask) != mask) + version = TLS1_VERSION; + mask &= ~SSL_OP_NO_TLSv1; +#if !defined(OPENSSL_NO_SSL3) + if ((options & SSL_OP_NO_TLSv1) && (options & mask) != mask) + version = SSL3_VERSION; + mask &= ~SSL_OP_NO_SSLv3; +#endif +#if !defined(OPENSSL_NO_SSL2) + if ((options & SSL_OP_NO_SSLv3) && (options & mask) != mask) + version = SSL2_VERSION; +#endif + +#ifndef OPENSSL_NO_TLSEXT + if (version != SSL2_VERSION) { + /* + * have to disable SSL 2.0 compatibility if we need TLS extensions + */ + + if (s->tlsext_hostname != NULL) + ssl2_compat = 0; + if (s->tlsext_status_type != -1) + ssl2_compat = 0; +# ifdef TLSEXT_TYPE_opaque_prf_input + if (s->ctx->tlsext_opaque_prf_input_callback != 0 + || s->tlsext_opaque_prf_input != NULL) + ssl2_compat = 0; +# endif + if (s->cert->cli_ext.meths_count != 0) + ssl2_compat = 0; + } +#endif + + buf = (unsigned char *)s->init_buf->data; + if (s->state == SSL23_ST_CW_CLNT_HELLO_A) { + /* + * Since we're sending s23 client hello, we're not reusing a session, as + * we'd be using the method from the saved session instead + */ + if (!ssl_get_new_session(s, 0)) { + return -1; + } + + p = s->s3->client_random; + if (ssl_fill_hello_random(s, 0, p, SSL3_RANDOM_SIZE) <= 0) + return -1; + + if (version == TLS1_2_VERSION) { + version_major = TLS1_2_VERSION_MAJOR; + version_minor = TLS1_2_VERSION_MINOR; + } else if (tls1_suiteb(s)) { + SSLerr(SSL_F_SSL23_CLIENT_HELLO, + SSL_R_ONLY_TLS_1_2_ALLOWED_IN_SUITEB_MODE); + return -1; + } else if (version == TLS1_1_VERSION) { + version_major = TLS1_1_VERSION_MAJOR; + version_minor = TLS1_1_VERSION_MINOR; + } else if (version == TLS1_VERSION) { + version_major = TLS1_VERSION_MAJOR; + version_minor = TLS1_VERSION_MINOR; + } +#ifdef OPENSSL_FIPS + else if (FIPS_mode()) { + SSLerr(SSL_F_SSL23_CLIENT_HELLO, + SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE); + return -1; + } +#endif + else if (version == SSL3_VERSION) { + version_major = SSL3_VERSION_MAJOR; + version_minor = SSL3_VERSION_MINOR; + } else if (version == SSL2_VERSION) { + version_major = SSL2_VERSION_MAJOR; + version_minor = SSL2_VERSION_MINOR; + } else { + SSLerr(SSL_F_SSL23_CLIENT_HELLO, SSL_R_NO_PROTOCOLS_AVAILABLE); + return (-1); + } + + s->client_version = version; + + if (ssl2_compat) { + /* create SSL 2.0 compatible Client Hello */ + + /* two byte record header will be written last */ + d = &(buf[2]); + p = d + 9; /* leave space for message type, version, + * individual length fields */ + + *(d++) = SSL2_MT_CLIENT_HELLO; + *(d++) = version_major; + *(d++) = version_minor; + + /* Ciphers supported */ + i = ssl_cipher_list_to_bytes(s, SSL_get_ciphers(s), p, 0); + if (i == 0) { + /* no ciphers */ + SSLerr(SSL_F_SSL23_CLIENT_HELLO, SSL_R_NO_CIPHERS_AVAILABLE); + return -1; + } + s2n(i, d); + p += i; + + /* + * put in the session-id length (zero since there is no reuse) + */ + s2n(0, d); + + if (s->options & SSL_OP_NETSCAPE_CHALLENGE_BUG) + ch_len = SSL2_CHALLENGE_LENGTH; + else + ch_len = SSL2_MAX_CHALLENGE_LENGTH; + + /* write out sslv2 challenge */ + /* + * Note that ch_len must be <= SSL3_RANDOM_SIZE (32), because it + * is one of SSL2_MAX_CHALLENGE_LENGTH (32) or + * SSL2_MAX_CHALLENGE_LENGTH (16), but leave the check in for + * futurproofing + */ + if (SSL3_RANDOM_SIZE < ch_len) + i = SSL3_RANDOM_SIZE; + else + i = ch_len; + s2n(i, d); + memset(&(s->s3->client_random[0]), 0, SSL3_RANDOM_SIZE); + if (RAND_pseudo_bytes + (&(s->s3->client_random[SSL3_RANDOM_SIZE - i]), i) <= 0) + return -1; + + memcpy(p, &(s->s3->client_random[SSL3_RANDOM_SIZE - i]), i); + p += i; + + i = p - &(buf[2]); + buf[0] = ((i >> 8) & 0xff) | 0x80; + buf[1] = (i & 0xff); + + /* number of bytes to write */ + s->init_num = i + 2; + s->init_off = 0; + + ssl3_finish_mac(s, &(buf[2]), i); + } else { + /* create Client Hello in SSL 3.0/TLS 1.0 format */ + + /* + * do the record header (5 bytes) and handshake message header (4 + * bytes) last + */ + d = p = &(buf[9]); + + *(p++) = version_major; + *(p++) = version_minor; + + /* Random stuff */ + memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE); + p += SSL3_RANDOM_SIZE; + + /* Session ID (zero since there is no reuse) */ + *(p++) = 0; + + /* Ciphers supported (using SSL 3.0/TLS 1.0 format) */ + i = ssl_cipher_list_to_bytes(s, SSL_get_ciphers(s), &(p[2]), + ssl3_put_cipher_by_char); + if (i == 0) { + SSLerr(SSL_F_SSL23_CLIENT_HELLO, SSL_R_NO_CIPHERS_AVAILABLE); + return -1; + } +#ifdef OPENSSL_MAX_TLS1_2_CIPHER_LENGTH + /* + * Some servers hang if client hello > 256 bytes as hack + * workaround chop number of supported ciphers to keep it well + * below this if we use TLS v1.2 + */ + if (TLS1_get_version(s) >= TLS1_2_VERSION + && i > OPENSSL_MAX_TLS1_2_CIPHER_LENGTH) + i = OPENSSL_MAX_TLS1_2_CIPHER_LENGTH & ~1; +#endif + s2n(i, p); + p += i; + + /* COMPRESSION */ +#ifdef OPENSSL_NO_COMP + *(p++) = 1; +#else + if ((s->options & SSL_OP_NO_COMPRESSION) + || !s->ctx->comp_methods) + j = 0; + else + j = sk_SSL_COMP_num(s->ctx->comp_methods); + *(p++) = 1 + j; + for (i = 0; i < j; i++) { + comp = sk_SSL_COMP_value(s->ctx->comp_methods, i); + *(p++) = comp->id; + } +#endif + *(p++) = 0; /* Add the NULL method */ + +#ifndef OPENSSL_NO_TLSEXT + /* TLS extensions */ + if (ssl_prepare_clienthello_tlsext(s) <= 0) { + SSLerr(SSL_F_SSL23_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT); + return -1; + } + if ((p = + ssl_add_clienthello_tlsext(s, p, + buf + SSL3_RT_MAX_PLAIN_LENGTH, + &al)) == NULL) { + ssl3_send_alert(s, SSL3_AL_FATAL, al); + SSLerr(SSL_F_SSL23_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); + return -1; + } +#endif + + l = p - d; + + /* fill in 4-byte handshake header */ + d = &(buf[5]); + *(d++) = SSL3_MT_CLIENT_HELLO; + l2n3(l, d); + + l += 4; + + if (l > SSL3_RT_MAX_PLAIN_LENGTH) { + SSLerr(SSL_F_SSL23_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); + return -1; + } + + /* fill in 5-byte record header */ + d = buf; + *(d++) = SSL3_RT_HANDSHAKE; + *(d++) = version_major; + /* + * Some servers hang if we use long client hellos and a record + * number > TLS 1.0. + */ + if (TLS1_get_client_version(s) > TLS1_VERSION) + *(d++) = 1; + else + *(d++) = version_minor; + s2n((int)l, d); + + /* number of bytes to write */ + s->init_num = p - buf; + s->init_off = 0; + + ssl3_finish_mac(s, &(buf[5]), s->init_num - 5); + } + + s->state = SSL23_ST_CW_CLNT_HELLO_B; + s->init_off = 0; + } + + /* SSL3_ST_CW_CLNT_HELLO_B */ + ret = ssl23_write_bytes(s); + + if ((ret >= 2) && s->msg_callback) { + /* Client Hello has been sent; tell msg_callback */ + + if (ssl2_compat) + s->msg_callback(1, SSL2_VERSION, 0, s->init_buf->data + 2, + ret - 2, s, s->msg_callback_arg); + else { + s->msg_callback(1, version, SSL3_RT_HEADER, s->init_buf->data, 5, + s, s->msg_callback_arg); + s->msg_callback(1, version, SSL3_RT_HANDSHAKE, + s->init_buf->data + 5, ret - 5, s, + s->msg_callback_arg); + } + } + + return ret; +} + +static int ssl23_get_server_hello(SSL *s) +{ + char buf[8]; + unsigned char *p; + int i; + int n; + + n = ssl23_read_bytes(s, 7); + + if (n != 7) + return (n); + p = s->packet; + + memcpy(buf, p, n); + + if ((p[0] & 0x80) && (p[2] == SSL2_MT_SERVER_HELLO) && + (p[5] == 0x00) && (p[6] == 0x02)) { +#ifdef OPENSSL_NO_SSL2 + SSLerr(SSL_F_SSL23_GET_SERVER_HELLO, SSL_R_UNSUPPORTED_PROTOCOL); + goto err; +#else + /* we are talking sslv2 */ + /* + * we need to clean up the SSLv3 setup and put in the sslv2 stuff. + */ + int ch_len; + + if (s->options & SSL_OP_NO_SSLv2) { + SSLerr(SSL_F_SSL23_GET_SERVER_HELLO, SSL_R_UNSUPPORTED_PROTOCOL); + goto err; + } + if (s->s2 == NULL) { + if (!ssl2_new(s)) + goto err; + } else + ssl2_clear(s); + + if (s->options & SSL_OP_NETSCAPE_CHALLENGE_BUG) + ch_len = SSL2_CHALLENGE_LENGTH; + else + ch_len = SSL2_MAX_CHALLENGE_LENGTH; + + /* write out sslv2 challenge */ + /* + * Note that ch_len must be <= SSL3_RANDOM_SIZE (32), because it is + * one of SSL2_MAX_CHALLENGE_LENGTH (32) or SSL2_MAX_CHALLENGE_LENGTH + * (16), but leave the check in for futurproofing + */ + i = (SSL3_RANDOM_SIZE < ch_len) + ? SSL3_RANDOM_SIZE : ch_len; + s->s2->challenge_length = i; + memcpy(s->s2->challenge, + &(s->s3->client_random[SSL3_RANDOM_SIZE - i]), i); + + if (s->s3 != NULL) + ssl3_free(s); + + if (!BUF_MEM_grow_clean(s->init_buf, + SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER)) { + SSLerr(SSL_F_SSL23_GET_SERVER_HELLO, ERR_R_BUF_LIB); + goto err; + } + + s->state = SSL2_ST_GET_SERVER_HELLO_A; + if (!(s->client_version == SSL2_VERSION)) + /* + * use special padding (SSL 3.0 draft/RFC 2246, App. E.2) + */ + s->s2->ssl2_rollback = 1; + + /* + * setup the 7 bytes we have read so we get them from the sslv2 + * buffer + */ + s->rstate = SSL_ST_READ_HEADER; + s->packet_length = n; + s->packet = &(s->s2->rbuf[0]); + memcpy(s->packet, buf, n); + s->s2->rbuf_left = n; + s->s2->rbuf_offs = 0; + + /* we have already written one */ + s->s2->write_sequence = 1; + + s->method = SSLv2_client_method(); + s->handshake_func = s->method->ssl_connect; +#endif + } else if (p[1] == SSL3_VERSION_MAJOR && + p[2] <= TLS1_2_VERSION_MINOR && + ((p[0] == SSL3_RT_HANDSHAKE && p[5] == SSL3_MT_SERVER_HELLO) || + (p[0] == SSL3_RT_ALERT && p[3] == 0 && p[4] == 2))) { + /* we have sslv3 or tls1 (server hello or alert) */ + +#ifndef OPENSSL_NO_SSL3 + if ((p[2] == SSL3_VERSION_MINOR) && !(s->options & SSL_OP_NO_SSLv3)) { +# ifdef OPENSSL_FIPS + if (FIPS_mode()) { + SSLerr(SSL_F_SSL23_GET_SERVER_HELLO, + SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE); + goto err; + } +# endif + s->version = SSL3_VERSION; + s->method = SSLv3_client_method(); + } else +#endif + if ((p[2] == TLS1_VERSION_MINOR) && !(s->options & SSL_OP_NO_TLSv1)) { + s->version = TLS1_VERSION; + s->method = TLSv1_client_method(); + } else if ((p[2] == TLS1_1_VERSION_MINOR) && + !(s->options & SSL_OP_NO_TLSv1_1)) { + s->version = TLS1_1_VERSION; + s->method = TLSv1_1_client_method(); + } else if ((p[2] == TLS1_2_VERSION_MINOR) && + !(s->options & SSL_OP_NO_TLSv1_2)) { + s->version = TLS1_2_VERSION; + s->method = TLSv1_2_client_method(); + } else { + SSLerr(SSL_F_SSL23_GET_SERVER_HELLO, SSL_R_UNSUPPORTED_PROTOCOL); + goto err; + } + + s->session->ssl_version = s->version; + + /* ensure that TLS_MAX_VERSION is up-to-date */ + OPENSSL_assert(s->version <= TLS_MAX_VERSION); + + if (p[0] == SSL3_RT_ALERT && p[5] != SSL3_AL_WARNING) { + /* fatal alert */ + + void (*cb) (const SSL *ssl, int type, int val) = NULL; + int j; + + if (s->info_callback != NULL) + cb = s->info_callback; + else if (s->ctx->info_callback != NULL) + cb = s->ctx->info_callback; + + i = p[5]; + if (cb != NULL) { + j = (i << 8) | p[6]; + cb(s, SSL_CB_READ_ALERT, j); + } + + if (s->msg_callback) { + s->msg_callback(0, s->version, SSL3_RT_HEADER, p, 5, s, + s->msg_callback_arg); + s->msg_callback(0, s->version, SSL3_RT_ALERT, p + 5, 2, s, + s->msg_callback_arg); + } + + s->rwstate = SSL_NOTHING; + SSLerr(SSL_F_SSL23_GET_SERVER_HELLO, SSL_AD_REASON_OFFSET + p[6]); + goto err; + } + + if (!ssl_init_wbio_buffer(s, 1)) + goto err; + + /* we are in this state */ + s->state = SSL3_ST_CR_SRVR_HELLO_A; + + /* + * put the 7 bytes we have read into the input buffer for SSLv3 + */ + s->rstate = SSL_ST_READ_HEADER; + s->packet_length = n; + if (s->s3->rbuf.buf == NULL) + if (!ssl3_setup_read_buffer(s)) + goto err; + s->packet = &(s->s3->rbuf.buf[0]); + memcpy(s->packet, buf, n); + s->s3->rbuf.left = n; + s->s3->rbuf.offset = 0; + + s->handshake_func = s->method->ssl_connect; + } else { + SSLerr(SSL_F_SSL23_GET_SERVER_HELLO, SSL_R_UNKNOWN_PROTOCOL); + goto err; + } + s->init_num = 0; + + return (SSL_connect(s)); + err: + return (-1); +} diff --git a/thirdparty/openssl/ssl/s23_lib.c b/thirdparty/openssl/ssl/s23_lib.c new file mode 100644 index 0000000000..9056d39e83 --- /dev/null +++ b/thirdparty/openssl/ssl/s23_lib.c @@ -0,0 +1,185 @@ +/* ssl/s23_lib.c */ +/* 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.] + */ + +#include <stdio.h> +#include <openssl/objects.h> +#include "ssl_locl.h" + +long ssl23_default_timeout(void) +{ + return (300); +} + +int ssl23_num_ciphers(void) +{ + return (ssl3_num_ciphers() +#ifndef OPENSSL_NO_SSL2 + + ssl2_num_ciphers() +#endif + ); +} + +const SSL_CIPHER *ssl23_get_cipher(unsigned int u) +{ + unsigned int uu = ssl3_num_ciphers(); + + if (u < uu) + return (ssl3_get_cipher(u)); + else +#ifndef OPENSSL_NO_SSL2 + return (ssl2_get_cipher(u - uu)); +#else + return (NULL); +#endif +} + +/* + * This function needs to check if the ciphers required are actually + * available + */ +const SSL_CIPHER *ssl23_get_cipher_by_char(const unsigned char *p) +{ + const SSL_CIPHER *cp; + + cp = ssl3_get_cipher_by_char(p); +#ifndef OPENSSL_NO_SSL2 + if (cp == NULL) + cp = ssl2_get_cipher_by_char(p); +#endif + return (cp); +} + +int ssl23_put_cipher_by_char(const SSL_CIPHER *c, unsigned char *p) +{ + long l; + + /* We can write SSLv2 and SSLv3 ciphers */ + /* but no ECC ciphers */ + if (c->algorithm_mkey == SSL_kECDHr || + c->algorithm_mkey == SSL_kECDHe || + c->algorithm_mkey == SSL_kEECDH || + c->algorithm_auth == SSL_aECDH || c->algorithm_auth == SSL_aECDSA) + return 0; + if (p != NULL) { + l = c->id; + p[0] = ((unsigned char)(l >> 16L)) & 0xFF; + p[1] = ((unsigned char)(l >> 8L)) & 0xFF; + p[2] = ((unsigned char)(l)) & 0xFF; + } + return (3); +} + +int ssl23_read(SSL *s, void *buf, int len) +{ + int n; + + clear_sys_error(); + if (SSL_in_init(s) && (!s->in_handshake)) { + n = s->handshake_func(s); + if (n < 0) + return (n); + if (n == 0) { + SSLerr(SSL_F_SSL23_READ, SSL_R_SSL_HANDSHAKE_FAILURE); + return (-1); + } + return (SSL_read(s, buf, len)); + } else { + ssl_undefined_function(s); + return (-1); + } +} + +int ssl23_peek(SSL *s, void *buf, int len) +{ + int n; + + clear_sys_error(); + if (SSL_in_init(s) && (!s->in_handshake)) { + n = s->handshake_func(s); + if (n < 0) + return (n); + if (n == 0) { + SSLerr(SSL_F_SSL23_PEEK, SSL_R_SSL_HANDSHAKE_FAILURE); + return (-1); + } + return (SSL_peek(s, buf, len)); + } else { + ssl_undefined_function(s); + return (-1); + } +} + +int ssl23_write(SSL *s, const void *buf, int len) +{ + int n; + + clear_sys_error(); + if (SSL_in_init(s) && (!s->in_handshake)) { + n = s->handshake_func(s); + if (n < 0) + return (n); + if (n == 0) { + SSLerr(SSL_F_SSL23_WRITE, SSL_R_SSL_HANDSHAKE_FAILURE); + return (-1); + } + return (SSL_write(s, buf, len)); + } else { + ssl_undefined_function(s); + return (-1); + } +} diff --git a/thirdparty/openssl/ssl/s23_meth.c b/thirdparty/openssl/ssl/s23_meth.c new file mode 100644 index 0000000000..eb76098792 --- /dev/null +++ b/thirdparty/openssl/ssl/s23_meth.c @@ -0,0 +1,89 @@ +/* ssl/s23_meth.c */ +/* 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.] + */ + +#include <stdio.h> +#include <openssl/objects.h> +#include "ssl_locl.h" + +static const SSL_METHOD *ssl23_get_method(int ver); +static const SSL_METHOD *ssl23_get_method(int ver) +{ +#ifndef OPENSSL_NO_SSL2 + if (ver == SSL2_VERSION) + return (SSLv2_method()); + else +#endif +#ifndef OPENSSL_NO_SSL3 + if (ver == SSL3_VERSION) + return (SSLv3_method()); + else +#endif +#ifndef OPENSSL_NO_TLS1 + if (ver == TLS1_VERSION) + return (TLSv1_method()); + else if (ver == TLS1_1_VERSION) + return (TLSv1_1_method()); + else if (ver == TLS1_2_VERSION) + return (TLSv1_2_method()); + else +#endif + return (NULL); +} + +IMPLEMENT_ssl23_meth_func(SSLv23_method, + ssl23_accept, ssl23_connect, ssl23_get_method) diff --git a/thirdparty/openssl/ssl/s23_pkt.c b/thirdparty/openssl/ssl/s23_pkt.c new file mode 100644 index 0000000000..efc8647841 --- /dev/null +++ b/thirdparty/openssl/ssl/s23_pkt.c @@ -0,0 +1,113 @@ +/* ssl/s23_pkt.c */ +/* 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.] + */ + +#include <stdio.h> +#include <errno.h> +#define USE_SOCKETS +#include "ssl_locl.h" +#include <openssl/evp.h> +#include <openssl/buffer.h> + +int ssl23_write_bytes(SSL *s) +{ + int i, num, tot; + char *buf; + + buf = s->init_buf->data; + tot = s->init_off; + num = s->init_num; + for (;;) { + s->rwstate = SSL_WRITING; + i = BIO_write(s->wbio, &(buf[tot]), num); + if (i <= 0) { + s->init_off = tot; + s->init_num = num; + return (i); + } + s->rwstate = SSL_NOTHING; + if (i == num) + return (tot + i); + + num -= i; + tot += i; + } +} + +/* return regularly only when we have read (at least) 'n' bytes */ +int ssl23_read_bytes(SSL *s, int n) +{ + unsigned char *p; + int j; + + if (s->packet_length < (unsigned int)n) { + p = s->packet; + + for (;;) { + s->rwstate = SSL_READING; + j = BIO_read(s->rbio, (char *)&(p[s->packet_length]), + n - s->packet_length); + if (j <= 0) + return (j); + s->rwstate = SSL_NOTHING; + s->packet_length += j; + if (s->packet_length >= (unsigned int)n) + return (s->packet_length); + } + } + return (n); +} diff --git a/thirdparty/openssl/ssl/s23_srvr.c b/thirdparty/openssl/ssl/s23_srvr.c new file mode 100644 index 0000000000..470bd3d94f --- /dev/null +++ b/thirdparty/openssl/ssl/s23_srvr.c @@ -0,0 +1,652 @@ +/* ssl/s23_srvr.c */ +/* 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-2006 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 <stdio.h> +#include "ssl_locl.h" +#include <openssl/buffer.h> +#include <openssl/rand.h> +#include <openssl/objects.h> +#include <openssl/evp.h> +#ifdef OPENSSL_FIPS +# include <openssl/fips.h> +#endif + +static const SSL_METHOD *ssl23_get_server_method(int ver); +int ssl23_get_client_hello(SSL *s); +static const SSL_METHOD *ssl23_get_server_method(int ver) +{ +#ifndef OPENSSL_NO_SSL2 + if (ver == SSL2_VERSION) + return (SSLv2_server_method()); +#endif +#ifndef OPENSSL_NO_SSL3 + if (ver == SSL3_VERSION) + return (SSLv3_server_method()); +#endif + if (ver == TLS1_VERSION) + return (TLSv1_server_method()); + else if (ver == TLS1_1_VERSION) + return (TLSv1_1_server_method()); + else if (ver == TLS1_2_VERSION) + return (TLSv1_2_server_method()); + else + return (NULL); +} + +IMPLEMENT_ssl23_meth_func(SSLv23_server_method, + ssl23_accept, + ssl_undefined_function, ssl23_get_server_method) + +int ssl23_accept(SSL *s) +{ + BUF_MEM *buf; + unsigned long Time = (unsigned long)time(NULL); + void (*cb) (const SSL *ssl, int type, int val) = NULL; + int ret = -1; + int new_state, state; + + RAND_add(&Time, sizeof(Time), 0); + ERR_clear_error(); + clear_sys_error(); + + if (s->info_callback != NULL) + cb = s->info_callback; + else if (s->ctx->info_callback != NULL) + cb = s->ctx->info_callback; + + s->in_handshake++; + if (!SSL_in_init(s) || SSL_in_before(s)) + SSL_clear(s); + + for (;;) { + state = s->state; + + switch (s->state) { + 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); + + /* s->version=SSL3_VERSION; */ + s->type = SSL_ST_ACCEPT; + + if (s->init_buf == NULL) { + if ((buf = BUF_MEM_new()) == NULL) { + ret = -1; + goto end; + } + if (!BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) { + BUF_MEM_free(buf); + ret = -1; + goto end; + } + s->init_buf = buf; + } + + ssl3_init_finished_mac(s); + + s->state = SSL23_ST_SR_CLNT_HELLO_A; + s->ctx->stats.sess_accept++; + s->init_num = 0; + break; + + case SSL23_ST_SR_CLNT_HELLO_A: + case SSL23_ST_SR_CLNT_HELLO_B: + + s->shutdown = 0; + ret = ssl23_get_client_hello(s); + if (ret >= 0) + cb = NULL; + goto end; + /* break; */ + + default: + SSLerr(SSL_F_SSL23_ACCEPT, SSL_R_UNKNOWN_STATE); + ret = -1; + goto end; + /* break; */ + } + + if ((cb != NULL) && (s->state != state)) { + new_state = s->state; + s->state = state; + cb(s, SSL_CB_ACCEPT_LOOP, 1); + s->state = new_state; + } + } + end: + s->in_handshake--; + if (cb != NULL) + cb(s, SSL_CB_ACCEPT_EXIT, ret); + return (ret); +} + +int ssl23_get_client_hello(SSL *s) +{ + /*- + * Request this many bytes in initial read. + * We can detect SSL 3.0/TLS 1.0 Client Hellos + * ('type == 3') correctly only when the following + * is in a single record, which is not guaranteed by + * the protocol specification: + * Byte Content + * 0 type \ + * 1/2 version > record header + * 3/4 length / + * 5 msg_type \ + * 6-8 length > Client Hello message + * 9/10 client_version / + */ + char buf_space[11]; + char *buf = &(buf_space[0]); + unsigned char *p, *d, *d_len, *dd; + unsigned int i; + unsigned int csl, sil, cl; + int n = 0, j; + int type = 0; + int v[2]; + + if (s->state == SSL23_ST_SR_CLNT_HELLO_A) { + /* read the initial header */ + v[0] = v[1] = 0; + + if (!ssl3_setup_buffers(s)) + goto err; + + n = ssl23_read_bytes(s, sizeof buf_space); + if (n != sizeof buf_space) + return (n); /* n == -1 || n == 0 */ + + p = s->packet; + + memcpy(buf, p, n); + + if ((p[0] & 0x80) && (p[2] == SSL2_MT_CLIENT_HELLO)) { + /* + * SSLv2 header + */ + if ((p[3] == 0x00) && (p[4] == 0x02)) { + v[0] = p[3]; + v[1] = p[4]; + /* SSLv2 */ + if (!(s->options & SSL_OP_NO_SSLv2)) + type = 1; + } else if (p[3] == SSL3_VERSION_MAJOR) { + v[0] = p[3]; + v[1] = p[4]; + /* SSLv3/TLSv1 */ + if (p[4] >= TLS1_VERSION_MINOR) { + if (p[4] >= TLS1_2_VERSION_MINOR && + !(s->options & SSL_OP_NO_TLSv1_2)) { + s->version = TLS1_2_VERSION; + s->state = SSL23_ST_SR_CLNT_HELLO_B; + } else if (p[4] >= TLS1_1_VERSION_MINOR && + !(s->options & SSL_OP_NO_TLSv1_1)) { + s->version = TLS1_1_VERSION; + /* + * type=2; + *//* + * done later to survive restarts + */ + s->state = SSL23_ST_SR_CLNT_HELLO_B; + } else if (!(s->options & SSL_OP_NO_TLSv1)) { + s->version = TLS1_VERSION; + /* + * type=2; + *//* + * done later to survive restarts + */ + s->state = SSL23_ST_SR_CLNT_HELLO_B; + } else if (!(s->options & SSL_OP_NO_SSLv3)) { + s->version = SSL3_VERSION; + /* type=2; */ + s->state = SSL23_ST_SR_CLNT_HELLO_B; + } else if (!(s->options & SSL_OP_NO_SSLv2)) { + type = 1; + } + } else if (!(s->options & SSL_OP_NO_SSLv3)) { + s->version = SSL3_VERSION; + /* type=2; */ + s->state = SSL23_ST_SR_CLNT_HELLO_B; + } else if (!(s->options & SSL_OP_NO_SSLv2)) + type = 1; + + } + } + /* p[4] < 5 ... silly record length? */ + else if ((p[0] == SSL3_RT_HANDSHAKE) && + (p[1] == SSL3_VERSION_MAJOR) && + (p[5] == SSL3_MT_CLIENT_HELLO) && ((p[3] == 0 && p[4] < 5) + || (p[9] >= p[1]))) { + /* + * SSLv3 or tls1 header + */ + + v[0] = p[1]; /* major version (= SSL3_VERSION_MAJOR) */ + /* + * We must look at client_version inside the Client Hello message + * to get the correct minor version. However if we have only a + * pathologically small fragment of the Client Hello message, this + * would be difficult, and we'd have to read more records to find + * out. No known SSL 3.0 client fragments ClientHello like this, + * so we simply reject such connections to avoid protocol version + * downgrade attacks. + */ + if (p[3] == 0 && p[4] < 6) { + SSLerr(SSL_F_SSL23_GET_CLIENT_HELLO, SSL_R_RECORD_TOO_SMALL); + goto err; + } + /* + * if major version number > 3 set minor to a value which will + * use the highest version 3 we support. If TLS 2.0 ever appears + * we will need to revise this.... + */ + if (p[9] > SSL3_VERSION_MAJOR) + v[1] = 0xff; + else + v[1] = p[10]; /* minor version according to client_version */ + if (v[1] >= TLS1_VERSION_MINOR) { + if (v[1] >= TLS1_2_VERSION_MINOR && + !(s->options & SSL_OP_NO_TLSv1_2)) { + s->version = TLS1_2_VERSION; + type = 3; + } else if (v[1] >= TLS1_1_VERSION_MINOR && + !(s->options & SSL_OP_NO_TLSv1_1)) { + s->version = TLS1_1_VERSION; + type = 3; + } else if (!(s->options & SSL_OP_NO_TLSv1)) { + s->version = TLS1_VERSION; + type = 3; + } else if (!(s->options & SSL_OP_NO_SSLv3)) { + s->version = SSL3_VERSION; + type = 3; + } + } else { + /* client requests SSL 3.0 */ + if (!(s->options & SSL_OP_NO_SSLv3)) { + s->version = SSL3_VERSION; + type = 3; + } else if (!(s->options & SSL_OP_NO_TLSv1)) { + /* + * we won't be able to use TLS of course, but this will + * send an appropriate alert + */ + s->version = TLS1_VERSION; + type = 3; + } + } + } else if ((strncmp("GET ", (char *)p, 4) == 0) || + (strncmp("POST ", (char *)p, 5) == 0) || + (strncmp("HEAD ", (char *)p, 5) == 0) || + (strncmp("PUT ", (char *)p, 4) == 0)) { + SSLerr(SSL_F_SSL23_GET_CLIENT_HELLO, SSL_R_HTTP_REQUEST); + goto err; + } else if (strncmp("CONNECT", (char *)p, 7) == 0) { + SSLerr(SSL_F_SSL23_GET_CLIENT_HELLO, SSL_R_HTTPS_PROXY_REQUEST); + goto err; + } + } + + /* ensure that TLS_MAX_VERSION is up-to-date */ + OPENSSL_assert(s->version <= TLS_MAX_VERSION); + + if (s->version < TLS1_2_VERSION && tls1_suiteb(s)) { + SSLerr(SSL_F_SSL23_GET_CLIENT_HELLO, + SSL_R_ONLY_TLS_1_2_ALLOWED_IN_SUITEB_MODE); + goto err; + } +#ifdef OPENSSL_FIPS + if (FIPS_mode() && (s->version < TLS1_VERSION)) { + SSLerr(SSL_F_SSL23_GET_CLIENT_HELLO, + SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE); + goto err; + } +#endif + + if (s->state == SSL23_ST_SR_CLNT_HELLO_B) { + /* + * we have SSLv3/TLSv1 in an SSLv2 header (other cases skip this + * state) + */ + + type = 2; + p = s->packet; + v[0] = p[3]; /* == SSL3_VERSION_MAJOR */ + v[1] = p[4]; + + /*- + * An SSLv3/TLSv1 backwards-compatible CLIENT-HELLO in an SSLv2 + * header is sent directly on the wire, not wrapped as a TLS + * record. It's format is: + * Byte Content + * 0-1 msg_length + * 2 msg_type + * 3-4 version + * 5-6 cipher_spec_length + * 7-8 session_id_length + * 9-10 challenge_length + * ... ... + */ + n = ((p[0] & 0x7f) << 8) | p[1]; + if (n > (1024 * 4)) { + SSLerr(SSL_F_SSL23_GET_CLIENT_HELLO, SSL_R_RECORD_TOO_LARGE); + goto err; + } + if (n < 9) { + SSLerr(SSL_F_SSL23_GET_CLIENT_HELLO, + SSL_R_RECORD_LENGTH_MISMATCH); + goto err; + } + + j = ssl23_read_bytes(s, n + 2); + /* + * We previously read 11 bytes, so if j > 0, we must have j == n+2 == + * s->packet_length. We have at least 11 valid packet bytes. + */ + if (j <= 0) + return (j); + + ssl3_finish_mac(s, s->packet + 2, s->packet_length - 2); + + /* CLIENT-HELLO */ + if (s->msg_callback) + s->msg_callback(0, SSL2_VERSION, 0, s->packet + 2, + s->packet_length - 2, s, s->msg_callback_arg); + + p = s->packet; + p += 5; + n2s(p, csl); + n2s(p, sil); + n2s(p, cl); + d = (unsigned char *)s->init_buf->data; + if ((csl + sil + cl + 11) != s->packet_length) { /* We can't have TLS + * extensions in SSL + * 2.0 format * + * Client Hello, can + * we? Error + * condition should + * be * '>' + * otherweise */ + SSLerr(SSL_F_SSL23_GET_CLIENT_HELLO, + SSL_R_RECORD_LENGTH_MISMATCH); + goto err; + } + + /* record header: msg_type ... */ + *(d++) = SSL3_MT_CLIENT_HELLO; + /* ... and length (actual value will be written later) */ + d_len = d; + d += 3; + + /* client_version */ + *(d++) = SSL3_VERSION_MAJOR; /* == v[0] */ + *(d++) = v[1]; + + /* lets populate the random area */ + /* get the challenge_length */ + i = (cl > SSL3_RANDOM_SIZE) ? SSL3_RANDOM_SIZE : cl; + memset(d, 0, SSL3_RANDOM_SIZE); + memcpy(&(d[SSL3_RANDOM_SIZE - i]), &(p[csl + sil]), i); + d += SSL3_RANDOM_SIZE; + + /* no session-id reuse */ + *(d++) = 0; + + /* ciphers */ + j = 0; + dd = d; + d += 2; + for (i = 0; i < csl; i += 3) { + if (p[i] != 0) + continue; + *(d++) = p[i + 1]; + *(d++) = p[i + 2]; + j += 2; + } + s2n(j, dd); + + /* COMPRESSION */ + *(d++) = 1; + *(d++) = 0; + +#if 0 + /* copy any remaining data with may be extensions */ + p = p + csl + sil + cl; + while (p < s->packet + s->packet_length) { + *(d++) = *(p++); + } +#endif + + i = (d - (unsigned char *)s->init_buf->data) - 4; + l2n3((long)i, d_len); + + /* get the data reused from the init_buf */ + s->s3->tmp.reuse_message = 1; + s->s3->tmp.message_type = SSL3_MT_CLIENT_HELLO; + s->s3->tmp.message_size = i; + } + + /* imaginary new state (for program structure): */ + /* s->state = SSL23_SR_CLNT_HELLO_C */ + + if (type == 1) { +#ifdef OPENSSL_NO_SSL2 + SSLerr(SSL_F_SSL23_GET_CLIENT_HELLO, SSL_R_UNSUPPORTED_PROTOCOL); + goto err; +#else + /* we are talking sslv2 */ + /* + * we need to clean up the SSLv3/TLSv1 setup and put in the sslv2 + * stuff. + */ + + if (s->s2 == NULL) { + if (!ssl2_new(s)) + goto err; + } else + ssl2_clear(s); + + if (s->s3 != NULL) + ssl3_free(s); + + if (!BUF_MEM_grow_clean(s->init_buf, + SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER)) { + goto err; + } + + s->state = SSL2_ST_GET_CLIENT_HELLO_A; + if (s->options & SSL_OP_NO_TLSv1 && s->options & SSL_OP_NO_SSLv3) + s->s2->ssl2_rollback = 0; + else + /* + * reject SSL 2.0 session if client supports SSL 3.0 or TLS 1.0 + * (SSL 3.0 draft/RFC 2246, App. E.2) + */ + s->s2->ssl2_rollback = 1; + + /* + * setup the n bytes we have read so we get them from the sslv2 + * buffer + */ + s->rstate = SSL_ST_READ_HEADER; + s->packet_length = n; + s->packet = &(s->s2->rbuf[0]); + memcpy(s->packet, buf, n); + s->s2->rbuf_left = n; + s->s2->rbuf_offs = 0; + + s->method = SSLv2_server_method(); + s->handshake_func = s->method->ssl_accept; +#endif + } + + if ((type == 2) || (type == 3)) { + /* + * we have SSLv3/TLSv1 (type 2: SSL2 style, type 3: SSL3/TLS style) + */ + const SSL_METHOD *new_method; + new_method = ssl23_get_server_method(s->version); + if (new_method == NULL) { + SSLerr(SSL_F_SSL23_GET_CLIENT_HELLO, SSL_R_UNSUPPORTED_PROTOCOL); + goto err; + } + s->method = new_method; + + if (!ssl_init_wbio_buffer(s, 1)) + goto err; + + /* we are in this state */ + s->state = SSL3_ST_SR_CLNT_HELLO_A; + + if (type == 3) { + /* + * put the 'n' bytes we have read into the input buffer for SSLv3 + */ + s->rstate = SSL_ST_READ_HEADER; + s->packet_length = n; + if (s->s3->rbuf.buf == NULL) + if (!ssl3_setup_read_buffer(s)) + goto err; + + s->packet = &(s->s3->rbuf.buf[0]); + memcpy(s->packet, buf, n); + s->s3->rbuf.left = n; + s->s3->rbuf.offset = 0; + } else { + s->packet_length = 0; + s->s3->rbuf.left = 0; + s->s3->rbuf.offset = 0; + } +#if 0 /* ssl3_get_client_hello does this */ + s->client_version = (v[0] << 8) | v[1]; +#endif + s->handshake_func = s->method->ssl_accept; + } + + if ((type < 1) || (type > 3)) { + /* bad, very bad */ + SSLerr(SSL_F_SSL23_GET_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL); + goto err; + } + s->init_num = 0; + + if (buf != buf_space) + OPENSSL_free(buf); + return (SSL_accept(s)); + err: + if (buf != buf_space) + OPENSSL_free(buf); + return (-1); +} diff --git a/thirdparty/openssl/ssl/s2_clnt.c b/thirdparty/openssl/ssl/s2_clnt.c new file mode 100644 index 0000000000..69da6b1421 --- /dev/null +++ b/thirdparty/openssl/ssl/s2_clnt.c @@ -0,0 +1,1094 @@ +/* ssl/s2_clnt.c */ +/* 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-2001 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 "ssl_locl.h" +#ifndef OPENSSL_NO_SSL2 +# include <stdio.h> +# include <openssl/rand.h> +# include <openssl/buffer.h> +# include <openssl/objects.h> +# include <openssl/evp.h> + +static const SSL_METHOD *ssl2_get_client_method(int ver); +static int get_server_finished(SSL *s); +static int get_server_verify(SSL *s); +static int get_server_hello(SSL *s); +static int client_hello(SSL *s); +static int client_master_key(SSL *s); +static int client_finished(SSL *s); +static int client_certificate(SSL *s); +static int ssl_rsa_public_encrypt(SESS_CERT *sc, int len, unsigned char *from, + unsigned char *to, int padding); +# define BREAK break + +static const SSL_METHOD *ssl2_get_client_method(int ver) +{ + if (ver == SSL2_VERSION) + return (SSLv2_client_method()); + else + return (NULL); +} + +IMPLEMENT_ssl2_meth_func(SSLv2_client_method, + ssl_undefined_function, + ssl2_connect, ssl2_get_client_method) + +int ssl2_connect(SSL *s) +{ + unsigned long l = (unsigned long)time(NULL); + BUF_MEM *buf = NULL; + int ret = -1; + void (*cb) (const SSL *ssl, int type, int val) = NULL; + int new_state, state; + + RAND_add(&l, sizeof(l), 0); + ERR_clear_error(); + clear_sys_error(); + + if (s->info_callback != NULL) + cb = s->info_callback; + else if (s->ctx->info_callback != NULL) + cb = s->ctx->info_callback; + + /* init things to blank */ + s->in_handshake++; + if (!SSL_in_init(s) || SSL_in_before(s)) + SSL_clear(s); + + for (;;) { + state = s->state; + + switch (s->state) { + 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); + + s->version = SSL2_VERSION; + s->type = SSL_ST_CONNECT; + + buf = s->init_buf; + if ((buf == NULL) && ((buf = BUF_MEM_new()) == NULL)) { + ret = -1; + goto end; + } + if (!BUF_MEM_grow(buf, SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER)) { + if (buf == s->init_buf) + buf = NULL; + ret = -1; + goto end; + } + s->init_buf = buf; + buf = NULL; + s->init_num = 0; + s->state = SSL2_ST_SEND_CLIENT_HELLO_A; + s->ctx->stats.sess_connect++; + s->handshake_func = ssl2_connect; + BREAK; + + case SSL2_ST_SEND_CLIENT_HELLO_A: + case SSL2_ST_SEND_CLIENT_HELLO_B: + s->shutdown = 0; + ret = client_hello(s); + if (ret <= 0) + goto end; + s->init_num = 0; + s->state = SSL2_ST_GET_SERVER_HELLO_A; + BREAK; + + case SSL2_ST_GET_SERVER_HELLO_A: + case SSL2_ST_GET_SERVER_HELLO_B: + ret = get_server_hello(s); + if (ret <= 0) + goto end; + s->init_num = 0; + if (!s->hit) { /* new session */ + s->state = SSL2_ST_SEND_CLIENT_MASTER_KEY_A; + BREAK; + } else { + s->state = SSL2_ST_CLIENT_START_ENCRYPTION; + break; + } + + case SSL2_ST_SEND_CLIENT_MASTER_KEY_A: + case SSL2_ST_SEND_CLIENT_MASTER_KEY_B: + ret = client_master_key(s); + if (ret <= 0) + goto end; + s->init_num = 0; + s->state = SSL2_ST_CLIENT_START_ENCRYPTION; + break; + + case SSL2_ST_CLIENT_START_ENCRYPTION: + /* + * Ok, we now have all the stuff needed to start encrypting, so + * lets fire it up :-) + */ + if (!ssl2_enc_init(s, 1)) { + ret = -1; + goto end; + } + s->s2->clear_text = 0; + s->state = SSL2_ST_SEND_CLIENT_FINISHED_A; + break; + + case SSL2_ST_SEND_CLIENT_FINISHED_A: + case SSL2_ST_SEND_CLIENT_FINISHED_B: + ret = client_finished(s); + if (ret <= 0) + goto end; + s->init_num = 0; + s->state = SSL2_ST_GET_SERVER_VERIFY_A; + break; + + case SSL2_ST_GET_SERVER_VERIFY_A: + case SSL2_ST_GET_SERVER_VERIFY_B: + ret = get_server_verify(s); + if (ret <= 0) + goto end; + s->init_num = 0; + s->state = SSL2_ST_GET_SERVER_FINISHED_A; + break; + + case SSL2_ST_GET_SERVER_FINISHED_A: + case SSL2_ST_GET_SERVER_FINISHED_B: + ret = get_server_finished(s); + if (ret <= 0) + goto end; + break; + + case SSL2_ST_SEND_CLIENT_CERTIFICATE_A: + case SSL2_ST_SEND_CLIENT_CERTIFICATE_B: + case SSL2_ST_SEND_CLIENT_CERTIFICATE_C: + case SSL2_ST_SEND_CLIENT_CERTIFICATE_D: + case SSL2_ST_X509_GET_CLIENT_CERTIFICATE: + ret = client_certificate(s); + if (ret <= 0) + goto end; + s->init_num = 0; + s->state = SSL2_ST_GET_SERVER_FINISHED_A; + break; + + case SSL_ST_OK: + if (s->init_buf != NULL) { + BUF_MEM_free(s->init_buf); + s->init_buf = NULL; + } + s->init_num = 0; + /* ERR_clear_error(); */ + + /* + * If we want to cache session-ids in the client and we + * successfully add the session-id to the cache, and there is a + * callback, then pass it out. 26/11/96 - eay - only add if not a + * re-used session. + */ + + ssl_update_cache(s, SSL_SESS_CACHE_CLIENT); + if (s->hit) + s->ctx->stats.sess_hit++; + + ret = 1; + /* s->server=0; */ + s->ctx->stats.sess_connect_good++; + + if (cb != NULL) + cb(s, SSL_CB_HANDSHAKE_DONE, 1); + + goto end; + /* break; */ + default: + SSLerr(SSL_F_SSL2_CONNECT, SSL_R_UNKNOWN_STATE); + return (-1); + /* break; */ + } + + if ((cb != NULL) && (s->state != state)) { + new_state = s->state; + s->state = state; + cb(s, SSL_CB_CONNECT_LOOP, 1); + s->state = new_state; + } + } + end: + s->in_handshake--; + if (buf != NULL) + BUF_MEM_free(buf); + if (cb != NULL) + cb(s, SSL_CB_CONNECT_EXIT, ret); + return (ret); +} + +static int get_server_hello(SSL *s) +{ + unsigned char *buf; + unsigned char *p; + int i, j; + unsigned long len; + STACK_OF(SSL_CIPHER) *sk = NULL, *cl, *prio, *allow; + + buf = (unsigned char *)s->init_buf->data; + p = buf; + if (s->state == SSL2_ST_GET_SERVER_HELLO_A) { + i = ssl2_read(s, (char *)&(buf[s->init_num]), 11 - s->init_num); + if (i < (11 - s->init_num)) + return (ssl2_part_read(s, SSL_F_GET_SERVER_HELLO, i)); + s->init_num = 11; + + if (*(p++) != SSL2_MT_SERVER_HELLO) { + if (p[-1] != SSL2_MT_ERROR) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_GET_SERVER_HELLO, SSL_R_READ_WRONG_PACKET_TYPE); + } else + SSLerr(SSL_F_GET_SERVER_HELLO, SSL_R_PEER_ERROR); + return (-1); + } +# if 0 + s->hit = (*(p++)) ? 1 : 0; + /* + * Some [PPC?] compilers fail to increment p in above statement, e.g. + * one provided with Rhapsody 5.5, but most recent example XL C 11.1 + * for AIX, even without optimization flag... + */ +# else + s->hit = (*p) ? 1 : 0; + p++; +# endif + s->s2->tmp.cert_type = *(p++); + n2s(p, i); + if (i < s->version) + s->version = i; + n2s(p, i); + s->s2->tmp.cert_length = i; + n2s(p, i); + s->s2->tmp.csl = i; + n2s(p, i); + s->s2->tmp.conn_id_length = i; + s->state = SSL2_ST_GET_SERVER_HELLO_B; + } + + /* SSL2_ST_GET_SERVER_HELLO_B */ + len = + 11 + (unsigned long)s->s2->tmp.cert_length + + (unsigned long)s->s2->tmp.csl + + (unsigned long)s->s2->tmp.conn_id_length; + if (len > SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER) { + SSLerr(SSL_F_GET_SERVER_HELLO, SSL_R_MESSAGE_TOO_LONG); + return -1; + } + j = (int)len - s->init_num; + i = ssl2_read(s, (char *)&(buf[s->init_num]), j); + if (i != j) + return (ssl2_part_read(s, SSL_F_GET_SERVER_HELLO, i)); + if (s->msg_callback) { + /* SERVER-HELLO */ + s->msg_callback(0, s->version, 0, buf, (size_t)len, s, + s->msg_callback_arg); + } + + /* things are looking good */ + + p = buf + 11; + if (s->hit) { + if (s->s2->tmp.cert_length != 0) { + SSLerr(SSL_F_GET_SERVER_HELLO, SSL_R_REUSE_CERT_LENGTH_NOT_ZERO); + return (-1); + } + if (s->s2->tmp.cert_type != 0) { + if (!(s->options & SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG)) { + SSLerr(SSL_F_GET_SERVER_HELLO, + SSL_R_REUSE_CERT_TYPE_NOT_ZERO); + return (-1); + } + } + if (s->s2->tmp.csl != 0) { + SSLerr(SSL_F_GET_SERVER_HELLO, SSL_R_REUSE_CIPHER_LIST_NOT_ZERO); + return (-1); + } + } else { +# if 0 + /* very bad */ + memset(s->session->session_id, 0, + SSL_MAX_SSL_SESSION_ID_LENGTH_IN_BYTES); + s->session->session_id_length = 0; +# endif + + /* + * we need to do this in case we were trying to reuse a client + * session but others are already reusing it. If this was a new + * 'blank' session ID, the session-id length will still be 0 + */ + if (s->session->session_id_length > 0) { + if (!ssl_get_new_session(s, 0)) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + return (-1); + } + } + + if (ssl2_set_certificate(s, s->s2->tmp.cert_type, + s->s2->tmp.cert_length, p) <= 0) { + ssl2_return_error(s, SSL2_PE_BAD_CERTIFICATE); + return (-1); + } + p += s->s2->tmp.cert_length; + + if (s->s2->tmp.csl == 0) { + ssl2_return_error(s, SSL2_PE_NO_CIPHER); + SSLerr(SSL_F_GET_SERVER_HELLO, SSL_R_NO_CIPHER_LIST); + return (-1); + } + + /* + * We have just received a list of ciphers back from the server. We + * need to get the ones that match, then select the one we want the + * most :-). + */ + + /* load the ciphers */ + sk = ssl_bytes_to_cipher_list(s, p, s->s2->tmp.csl, + &s->session->ciphers); + p += s->s2->tmp.csl; + if (sk == NULL) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_GET_SERVER_HELLO, ERR_R_MALLOC_FAILURE); + return (-1); + } + + (void)sk_SSL_CIPHER_set_cmp_func(sk, ssl_cipher_ptr_id_cmp); + + /* get the array of ciphers we will accept */ + cl = SSL_get_ciphers(s); + (void)sk_SSL_CIPHER_set_cmp_func(cl, ssl_cipher_ptr_id_cmp); + + /* + * If server preference flag set, choose the first + * (highest priority) cipher the server sends, otherwise + * client preference has priority. + */ + if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE) { + prio = sk; + allow = cl; + } else { + prio = cl; + allow = sk; + } + /* + * In theory we could have ciphers sent back that we don't want to + * use but that does not matter since we will check against the list + * we originally sent and for performance reasons we should not + * bother to match the two lists up just to check. + */ + for (i = 0; i < sk_SSL_CIPHER_num(prio); i++) { + if (sk_SSL_CIPHER_find(allow, sk_SSL_CIPHER_value(prio, i)) >= 0) + break; + } + + if (i >= sk_SSL_CIPHER_num(prio)) { + ssl2_return_error(s, SSL2_PE_NO_CIPHER); + SSLerr(SSL_F_GET_SERVER_HELLO, SSL_R_NO_CIPHER_MATCH); + return (-1); + } + s->session->cipher = sk_SSL_CIPHER_value(prio, i); + + if (s->session->peer != NULL) { /* can't happen */ + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_GET_SERVER_HELLO, ERR_R_INTERNAL_ERROR); + return (-1); + } + + s->session->peer = s->session->sess_cert->peer_key->x509; + /* peer_key->x509 has been set by ssl2_set_certificate. */ + CRYPTO_add(&s->session->peer->references, 1, CRYPTO_LOCK_X509); + } + + if (s->session->sess_cert == NULL + || s->session->peer != s->session->sess_cert->peer_key->x509) + /* can't happen */ + { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_GET_SERVER_HELLO, ERR_R_INTERNAL_ERROR); + return (-1); + } + + s->s2->conn_id_length = s->s2->tmp.conn_id_length; + if (s->s2->conn_id_length > sizeof s->s2->conn_id) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_GET_SERVER_HELLO, SSL_R_SSL2_CONNECTION_ID_TOO_LONG); + return -1; + } + memcpy(s->s2->conn_id, p, s->s2->tmp.conn_id_length); + return (1); +} + +static int client_hello(SSL *s) +{ + unsigned char *buf; + unsigned char *p, *d; +/* CIPHER **cipher;*/ + int i, n, j; + + buf = (unsigned char *)s->init_buf->data; + if (s->state == SSL2_ST_SEND_CLIENT_HELLO_A) { + if ((s->session == NULL) || (s->session->ssl_version != s->version)) { + if (!ssl_get_new_session(s, 0)) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + return (-1); + } + } + /* else use the pre-loaded session */ + + p = buf; /* header */ + d = p + 9; /* data section */ + *(p++) = SSL2_MT_CLIENT_HELLO; /* type */ + s2n(SSL2_VERSION, p); /* version */ + n = j = 0; + + n = ssl_cipher_list_to_bytes(s, SSL_get_ciphers(s), d, 0); + d += n; + + if (n == 0) { + SSLerr(SSL_F_CLIENT_HELLO, SSL_R_NO_CIPHERS_AVAILABLE); + return (-1); + } + + s2n(n, p); /* cipher spec num bytes */ + + if ((s->session->session_id_length > 0) && + (s->session->session_id_length <= + SSL2_MAX_SSL_SESSION_ID_LENGTH)) { + i = s->session->session_id_length; + s2n(i, p); /* session id length */ + memcpy(d, s->session->session_id, (unsigned int)i); + d += i; + } else { + s2n(0, p); + } + + s->s2->challenge_length = SSL2_CHALLENGE_LENGTH; + s2n(SSL2_CHALLENGE_LENGTH, p); /* challenge length */ + /* + * challenge id data + */ + if (RAND_pseudo_bytes(s->s2->challenge, SSL2_CHALLENGE_LENGTH) <= 0) + return -1; + memcpy(d, s->s2->challenge, SSL2_CHALLENGE_LENGTH); + d += SSL2_CHALLENGE_LENGTH; + + s->state = SSL2_ST_SEND_CLIENT_HELLO_B; + s->init_num = d - buf; + s->init_off = 0; + } + /* SSL2_ST_SEND_CLIENT_HELLO_B */ + return (ssl2_do_write(s)); +} + +static int client_master_key(SSL *s) +{ + unsigned char *buf; + unsigned char *p, *d; + int clear, enc, karg, i; + SSL_SESSION *sess; + const EVP_CIPHER *c; + const EVP_MD *md; + + buf = (unsigned char *)s->init_buf->data; + if (s->state == SSL2_ST_SEND_CLIENT_MASTER_KEY_A) { + + if (!ssl_cipher_get_evp(s->session, &c, &md, NULL, NULL, NULL)) { + ssl2_return_error(s, SSL2_PE_NO_CIPHER); + SSLerr(SSL_F_CLIENT_MASTER_KEY, + SSL_R_PROBLEMS_MAPPING_CIPHER_FUNCTIONS); + return (-1); + } + sess = s->session; + p = buf; + d = p + 10; + *(p++) = SSL2_MT_CLIENT_MASTER_KEY; /* type */ + + i = ssl_put_cipher_by_char(s, sess->cipher, p); + p += i; + + /* make key_arg data */ + i = EVP_CIPHER_iv_length(c); + sess->key_arg_length = i; + if (i > SSL_MAX_KEY_ARG_LENGTH) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_CLIENT_MASTER_KEY, ERR_R_INTERNAL_ERROR); + return -1; + } + if (i > 0) + if (RAND_pseudo_bytes(sess->key_arg, i) <= 0) + return -1; + + /* make a master key */ + i = EVP_CIPHER_key_length(c); + sess->master_key_length = i; + if (i > 0) { + if (i > (int)sizeof(sess->master_key)) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_CLIENT_MASTER_KEY, ERR_R_INTERNAL_ERROR); + return -1; + } + if (RAND_bytes(sess->master_key, i) <= 0) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + return (-1); + } + } + + if (sess->cipher->algorithm2 & SSL2_CF_8_BYTE_ENC) + enc = 8; + else if (SSL_C_IS_EXPORT(sess->cipher)) + enc = 5; + else + enc = i; + + if ((int)i < enc) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_CLIENT_MASTER_KEY, SSL_R_CIPHER_TABLE_SRC_ERROR); + return (-1); + } + clear = i - enc; + s2n(clear, p); + memcpy(d, sess->master_key, (unsigned int)clear); + d += clear; + + enc = ssl_rsa_public_encrypt(sess->sess_cert, enc, + &(sess->master_key[clear]), d, + (s-> + s2->ssl2_rollback) ? RSA_SSLV23_PADDING + : RSA_PKCS1_PADDING); + if (enc <= 0) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_CLIENT_MASTER_KEY, SSL_R_PUBLIC_KEY_ENCRYPT_ERROR); + return (-1); + } +# ifdef PKCS1_CHECK + if (s->options & SSL_OP_PKCS1_CHECK_1) + d[1]++; + if (s->options & SSL_OP_PKCS1_CHECK_2) + sess->master_key[clear]++; +# endif + s2n(enc, p); + d += enc; + karg = sess->key_arg_length; + s2n(karg, p); /* key arg size */ + if (karg > (int)sizeof(sess->key_arg)) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_CLIENT_MASTER_KEY, ERR_R_INTERNAL_ERROR); + return -1; + } + memcpy(d, sess->key_arg, (unsigned int)karg); + d += karg; + + s->state = SSL2_ST_SEND_CLIENT_MASTER_KEY_B; + s->init_num = d - buf; + s->init_off = 0; + } + + /* SSL2_ST_SEND_CLIENT_MASTER_KEY_B */ + return (ssl2_do_write(s)); +} + +static int client_finished(SSL *s) +{ + unsigned char *p; + + if (s->state == SSL2_ST_SEND_CLIENT_FINISHED_A) { + p = (unsigned char *)s->init_buf->data; + *(p++) = SSL2_MT_CLIENT_FINISHED; + if (s->s2->conn_id_length > sizeof s->s2->conn_id) { + SSLerr(SSL_F_CLIENT_FINISHED, ERR_R_INTERNAL_ERROR); + return -1; + } + memcpy(p, s->s2->conn_id, (unsigned int)s->s2->conn_id_length); + + s->state = SSL2_ST_SEND_CLIENT_FINISHED_B; + s->init_num = s->s2->conn_id_length + 1; + s->init_off = 0; + } + return (ssl2_do_write(s)); +} + +/* read the data and then respond */ +static int client_certificate(SSL *s) +{ + unsigned char *buf; + unsigned char *p, *d; + int i; + unsigned int n; + int cert_ch_len; + unsigned char *cert_ch; + + buf = (unsigned char *)s->init_buf->data; + + /* + * We have a cert associated with the SSL, so attach it to the session if + * it does not have one + */ + + if (s->state == SSL2_ST_SEND_CLIENT_CERTIFICATE_A) { + i = ssl2_read(s, (char *)&(buf[s->init_num]), + SSL2_MAX_CERT_CHALLENGE_LENGTH + 2 - s->init_num); + if (i < (SSL2_MIN_CERT_CHALLENGE_LENGTH + 2 - s->init_num)) + return (ssl2_part_read(s, SSL_F_CLIENT_CERTIFICATE, i)); + s->init_num += i; + if (s->msg_callback) { + /* REQUEST-CERTIFICATE */ + s->msg_callback(0, s->version, 0, buf, (size_t)s->init_num, s, + s->msg_callback_arg); + } + + /* type=buf[0]; */ + /* type eq x509 */ + if (buf[1] != SSL2_AT_MD5_WITH_RSA_ENCRYPTION) { + ssl2_return_error(s, SSL2_PE_UNSUPPORTED_CERTIFICATE_TYPE); + SSLerr(SSL_F_CLIENT_CERTIFICATE, SSL_R_BAD_AUTHENTICATION_TYPE); + return (-1); + } + + if ((s->cert == NULL) || + (s->cert->key->x509 == NULL) || + (s->cert->key->privatekey == NULL)) { + s->state = SSL2_ST_X509_GET_CLIENT_CERTIFICATE; + } else + s->state = SSL2_ST_SEND_CLIENT_CERTIFICATE_C; + } + + cert_ch = buf + 2; + cert_ch_len = s->init_num - 2; + + if (s->state == SSL2_ST_X509_GET_CLIENT_CERTIFICATE) { + X509 *x509 = NULL; + EVP_PKEY *pkey = NULL; + + /* + * If we get an error we need to ssl->rwstate=SSL_X509_LOOKUP; + * return(error); We should then be retried when things are ok and we + * can get a cert or not + */ + + i = 0; + if (s->ctx->client_cert_cb != NULL) { + i = s->ctx->client_cert_cb(s, &(x509), &(pkey)); + } + + if (i < 0) { + s->rwstate = SSL_X509_LOOKUP; + return (-1); + } + s->rwstate = SSL_NOTHING; + + if ((i == 1) && (pkey != NULL) && (x509 != NULL)) { + s->state = SSL2_ST_SEND_CLIENT_CERTIFICATE_C; + if (!SSL_use_certificate(s, x509) || !SSL_use_PrivateKey(s, pkey)) { + i = 0; + } + X509_free(x509); + EVP_PKEY_free(pkey); + } else if (i == 1) { + if (x509 != NULL) + X509_free(x509); + if (pkey != NULL) + EVP_PKEY_free(pkey); + SSLerr(SSL_F_CLIENT_CERTIFICATE, + SSL_R_BAD_DATA_RETURNED_BY_CALLBACK); + i = 0; + } + + if (i == 0) { + /* + * We have no client certificate to respond with so send the + * correct error message back + */ + s->state = SSL2_ST_SEND_CLIENT_CERTIFICATE_B; + p = buf; + *(p++) = SSL2_MT_ERROR; + s2n(SSL2_PE_NO_CERTIFICATE, p); + s->init_off = 0; + s->init_num = 3; + /* Write is done at the end */ + } + } + + if (s->state == SSL2_ST_SEND_CLIENT_CERTIFICATE_B) { + return (ssl2_do_write(s)); + } + + if (s->state == SSL2_ST_SEND_CLIENT_CERTIFICATE_C) { + EVP_MD_CTX ctx; + + /* + * ok, now we calculate the checksum do it first so we can reuse buf + * :-) + */ + p = buf; + EVP_MD_CTX_init(&ctx); + EVP_SignInit_ex(&ctx, s->ctx->rsa_md5, NULL); + EVP_SignUpdate(&ctx, s->s2->key_material, s->s2->key_material_length); + EVP_SignUpdate(&ctx, cert_ch, (unsigned int)cert_ch_len); + i = i2d_X509(s->session->sess_cert->peer_key->x509, &p); + /* + * Don't update the signature if it fails - FIXME: probably should + * handle this better + */ + if (i > 0) + EVP_SignUpdate(&ctx, buf, (unsigned int)i); + + p = buf; + d = p + 6; + *(p++) = SSL2_MT_CLIENT_CERTIFICATE; + *(p++) = SSL2_CT_X509_CERTIFICATE; + n = i2d_X509(s->cert->key->x509, &d); + s2n(n, p); + + if (!EVP_SignFinal(&ctx, d, &n, s->cert->key->privatekey)) { + /* + * this is not good. If things have failed it means there so + * something wrong with the key. We will continue with a 0 length + * signature + */ + } + EVP_MD_CTX_cleanup(&ctx); + s2n(n, p); + d += n; + + s->state = SSL2_ST_SEND_CLIENT_CERTIFICATE_D; + s->init_num = d - buf; + s->init_off = 0; + } + /* if (s->state == SSL2_ST_SEND_CLIENT_CERTIFICATE_D) */ + return (ssl2_do_write(s)); +} + +static int get_server_verify(SSL *s) +{ + unsigned char *p; + int i, n, len; + + p = (unsigned char *)s->init_buf->data; + if (s->state == SSL2_ST_GET_SERVER_VERIFY_A) { + i = ssl2_read(s, (char *)&(p[s->init_num]), 1 - s->init_num); + if (i < (1 - s->init_num)) + return (ssl2_part_read(s, SSL_F_GET_SERVER_VERIFY, i)); + s->init_num += i; + + s->state = SSL2_ST_GET_SERVER_VERIFY_B; + if (*p != SSL2_MT_SERVER_VERIFY) { + if (p[0] != SSL2_MT_ERROR) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_GET_SERVER_VERIFY, SSL_R_READ_WRONG_PACKET_TYPE); + } else { + SSLerr(SSL_F_GET_SERVER_VERIFY, SSL_R_PEER_ERROR); + /* try to read the error message */ + i = ssl2_read(s, (char *)&(p[s->init_num]), 3 - s->init_num); + return ssl2_part_read(s, SSL_F_GET_SERVER_VERIFY, i); + } + return (-1); + } + } + + p = (unsigned char *)s->init_buf->data; + len = 1 + s->s2->challenge_length; + n = len - s->init_num; + i = ssl2_read(s, (char *)&(p[s->init_num]), n); + if (i < n) + return (ssl2_part_read(s, SSL_F_GET_SERVER_VERIFY, i)); + if (s->msg_callback) { + /* SERVER-VERIFY */ + s->msg_callback(0, s->version, 0, p, len, s, s->msg_callback_arg); + } + p += 1; + + if (CRYPTO_memcmp(p, s->s2->challenge, s->s2->challenge_length) != 0) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_GET_SERVER_VERIFY, SSL_R_CHALLENGE_IS_DIFFERENT); + return (-1); + } + return (1); +} + +static int get_server_finished(SSL *s) +{ + unsigned char *buf; + unsigned char *p; + int i, n, len; + + buf = (unsigned char *)s->init_buf->data; + p = buf; + if (s->state == SSL2_ST_GET_SERVER_FINISHED_A) { + i = ssl2_read(s, (char *)&(buf[s->init_num]), 1 - s->init_num); + if (i < (1 - s->init_num)) + return (ssl2_part_read(s, SSL_F_GET_SERVER_FINISHED, i)); + s->init_num += i; + + if (*p == SSL2_MT_REQUEST_CERTIFICATE) { + s->state = SSL2_ST_SEND_CLIENT_CERTIFICATE_A; + return (1); + } else if (*p != SSL2_MT_SERVER_FINISHED) { + if (p[0] != SSL2_MT_ERROR) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_GET_SERVER_FINISHED, + SSL_R_READ_WRONG_PACKET_TYPE); + } else { + SSLerr(SSL_F_GET_SERVER_FINISHED, SSL_R_PEER_ERROR); + /* try to read the error message */ + i = ssl2_read(s, (char *)&(p[s->init_num]), 3 - s->init_num); + return ssl2_part_read(s, SSL_F_GET_SERVER_VERIFY, i); + } + return (-1); + } + s->state = SSL2_ST_GET_SERVER_FINISHED_B; + } + + len = 1 + SSL2_SSL_SESSION_ID_LENGTH; + n = len - s->init_num; + i = ssl2_read(s, (char *)&(buf[s->init_num]), n); + if (i < n) { + /* + * XXX could be shorter than SSL2_SSL_SESSION_ID_LENGTH, + * that's the maximum + */ + return (ssl2_part_read(s, SSL_F_GET_SERVER_FINISHED, i)); + } + s->init_num += i; + if (s->msg_callback) { + /* SERVER-FINISHED */ + s->msg_callback(0, s->version, 0, buf, (size_t)s->init_num, s, + s->msg_callback_arg); + } + + if (!s->hit) { /* new session */ + /* new session-id */ + /* + * Make sure we were not trying to re-use an old SSL_SESSION or bad + * things can happen + */ + /* ZZZZZZZZZZZZZ */ + s->session->session_id_length = SSL2_SSL_SESSION_ID_LENGTH; + memcpy(s->session->session_id, p + 1, SSL2_SSL_SESSION_ID_LENGTH); + } else { + if (!(s->options & SSL_OP_MICROSOFT_SESS_ID_BUG)) { + if ((s->session->session_id_length > + sizeof s->session->session_id) + || (0 != + memcmp(buf + 1, s->session->session_id, + (unsigned int)s->session->session_id_length))) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_GET_SERVER_FINISHED, + SSL_R_SSL_SESSION_ID_IS_DIFFERENT); + return (-1); + } + } + } + s->state = SSL_ST_OK; + return (1); +} + +/* loads in the certificate from the server */ +int ssl2_set_certificate(SSL *s, int type, int len, const unsigned char *data) +{ + STACK_OF(X509) *sk = NULL; + EVP_PKEY *pkey = NULL; + SESS_CERT *sc = NULL; + int i; + X509 *x509 = NULL; + int ret = 0; + + x509 = d2i_X509(NULL, &data, (long)len); + if (x509 == NULL) { + SSLerr(SSL_F_SSL2_SET_CERTIFICATE, ERR_R_X509_LIB); + goto err; + } + + if ((sk = sk_X509_new_null()) == NULL || !sk_X509_push(sk, x509)) { + SSLerr(SSL_F_SSL2_SET_CERTIFICATE, ERR_R_MALLOC_FAILURE); + goto err; + } + + i = ssl_verify_cert_chain(s, sk); + + if ((s->verify_mode != SSL_VERIFY_NONE) && (i <= 0)) { + SSLerr(SSL_F_SSL2_SET_CERTIFICATE, SSL_R_CERTIFICATE_VERIFY_FAILED); + goto err; + } + ERR_clear_error(); /* but we keep s->verify_result */ + s->session->verify_result = s->verify_result; + + /* server's cert for this session */ + sc = ssl_sess_cert_new(); + if (sc == NULL) { + ret = -1; + goto err; + } + if (s->session->sess_cert) + ssl_sess_cert_free(s->session->sess_cert); + s->session->sess_cert = sc; + + sc->peer_pkeys[SSL_PKEY_RSA_ENC].x509 = x509; + sc->peer_key = &(sc->peer_pkeys[SSL_PKEY_RSA_ENC]); + + pkey = X509_get_pubkey(x509); + x509 = NULL; + if (pkey == NULL) { + SSLerr(SSL_F_SSL2_SET_CERTIFICATE, + SSL_R_UNABLE_TO_EXTRACT_PUBLIC_KEY); + goto err; + } + if (pkey->type != EVP_PKEY_RSA) { + SSLerr(SSL_F_SSL2_SET_CERTIFICATE, SSL_R_PUBLIC_KEY_NOT_RSA); + goto err; + } + + if (!ssl_set_peer_cert_type(sc, SSL2_CT_X509_CERTIFICATE)) + goto err; + ret = 1; + err: + sk_X509_free(sk); + X509_free(x509); + EVP_PKEY_free(pkey); + return (ret); +} + +static int ssl_rsa_public_encrypt(SESS_CERT *sc, int len, unsigned char *from, + unsigned char *to, int padding) +{ + EVP_PKEY *pkey = NULL; + int i = -1; + + if ((sc == NULL) || (sc->peer_key->x509 == NULL) || + ((pkey = X509_get_pubkey(sc->peer_key->x509)) == NULL)) { + SSLerr(SSL_F_SSL_RSA_PUBLIC_ENCRYPT, SSL_R_NO_PUBLICKEY); + return (-1); + } + if (pkey->type != EVP_PKEY_RSA) { + SSLerr(SSL_F_SSL_RSA_PUBLIC_ENCRYPT, SSL_R_PUBLIC_KEY_IS_NOT_RSA); + goto end; + } + + /* we have the public key */ + i = RSA_public_encrypt(len, from, to, pkey->pkey.rsa, padding); + if (i < 0) + SSLerr(SSL_F_SSL_RSA_PUBLIC_ENCRYPT, ERR_R_RSA_LIB); + end: + EVP_PKEY_free(pkey); + return (i); +} +#else /* !OPENSSL_NO_SSL2 */ + +# if PEDANTIC +static void *dummy = &dummy; +# endif + +#endif diff --git a/thirdparty/openssl/ssl/s2_enc.c b/thirdparty/openssl/ssl/s2_enc.c new file mode 100644 index 0000000000..23eef72aa4 --- /dev/null +++ b/thirdparty/openssl/ssl/s2_enc.c @@ -0,0 +1,197 @@ +/* ssl/s2_enc.c */ +/* 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.] + */ + +#include "ssl_locl.h" +#ifndef OPENSSL_NO_SSL2 +# include <stdio.h> + +int ssl2_enc_init(SSL *s, int client) +{ + /* Max number of bytes needed */ + EVP_CIPHER_CTX *rs, *ws; + const EVP_CIPHER *c; + const EVP_MD *md; + int num; + + if (!ssl_cipher_get_evp(s->session, &c, &md, NULL, NULL, NULL)) { + ssl2_return_error(s, SSL2_PE_NO_CIPHER); + SSLerr(SSL_F_SSL2_ENC_INIT, SSL_R_PROBLEMS_MAPPING_CIPHER_FUNCTIONS); + return (0); + } + ssl_replace_hash(&s->read_hash, md); + ssl_replace_hash(&s->write_hash, md); + + if ((s->enc_read_ctx == NULL) && ((s->enc_read_ctx = (EVP_CIPHER_CTX *) + OPENSSL_malloc(sizeof(EVP_CIPHER_CTX))) + == NULL)) + goto err; + + /* + * make sure it's intialized in case the malloc for enc_write_ctx fails + * and we exit with an error + */ + rs = s->enc_read_ctx; + EVP_CIPHER_CTX_init(rs); + + if ((s->enc_write_ctx == NULL) && ((s->enc_write_ctx = (EVP_CIPHER_CTX *) + OPENSSL_malloc(sizeof + (EVP_CIPHER_CTX))) == + NULL)) + goto err; + + ws = s->enc_write_ctx; + EVP_CIPHER_CTX_init(ws); + + num = c->key_len; + s->s2->key_material_length = num * 2; + OPENSSL_assert(s->s2->key_material_length <= sizeof s->s2->key_material); + + if (ssl2_generate_key_material(s) <= 0) + return 0; + + OPENSSL_assert(c->iv_len <= (int)sizeof(s->session->key_arg)); + EVP_EncryptInit_ex(ws, c, NULL, + &(s->s2->key_material[(client) ? num : 0]), + s->session->key_arg); + EVP_DecryptInit_ex(rs, c, NULL, + &(s->s2->key_material[(client) ? 0 : num]), + s->session->key_arg); + s->s2->read_key = &(s->s2->key_material[(client) ? 0 : num]); + s->s2->write_key = &(s->s2->key_material[(client) ? num : 0]); + return (1); + err: + SSLerr(SSL_F_SSL2_ENC_INIT, ERR_R_MALLOC_FAILURE); + return (0); +} + +/* + * read/writes from s->s2->mac_data using length for encrypt and decrypt. + * It sets s->s2->padding and s->[rw]length if we are encrypting Returns 0 on + * error and 1 on success + */ +int ssl2_enc(SSL *s, int send) +{ + EVP_CIPHER_CTX *ds; + unsigned long l; + int bs; + + if (send) { + ds = s->enc_write_ctx; + l = s->s2->wlength; + } else { + ds = s->enc_read_ctx; + l = s->s2->rlength; + } + + /* check for NULL cipher */ + if (ds == NULL) + return 1; + + bs = ds->cipher->block_size; + /* + * This should be using (bs-1) and bs instead of 7 and 8, but what the + * hell. + */ + if (bs == 8) + l = (l + 7) / 8 * 8; + + if (EVP_Cipher(ds, s->s2->mac_data, s->s2->mac_data, l) < 1) + return 0; + + return 1; +} + +void ssl2_mac(SSL *s, unsigned char *md, int send) +{ + EVP_MD_CTX c; + unsigned char sequence[4], *p, *sec, *act; + unsigned long seq; + unsigned int len; + + if (send) { + seq = s->s2->write_sequence; + sec = s->s2->write_key; + len = s->s2->wact_data_length; + act = s->s2->wact_data; + } else { + seq = s->s2->read_sequence; + sec = s->s2->read_key; + len = s->s2->ract_data_length; + act = s->s2->ract_data; + } + + p = &(sequence[0]); + l2n(seq, p); + + /* There has to be a MAC algorithm. */ + EVP_MD_CTX_init(&c); + EVP_MD_CTX_copy(&c, s->read_hash); + EVP_DigestUpdate(&c, sec, EVP_CIPHER_CTX_key_length(s->enc_read_ctx)); + EVP_DigestUpdate(&c, act, len); + /* the above line also does the pad data */ + EVP_DigestUpdate(&c, sequence, 4); + EVP_DigestFinal_ex(&c, md, NULL); + EVP_MD_CTX_cleanup(&c); +} +#else /* !OPENSSL_NO_SSL2 */ + +# if PEDANTIC +static void *dummy = &dummy; +# endif + +#endif diff --git a/thirdparty/openssl/ssl/s2_lib.c b/thirdparty/openssl/ssl/s2_lib.c new file mode 100644 index 0000000000..88e67f083a --- /dev/null +++ b/thirdparty/openssl/ssl/s2_lib.c @@ -0,0 +1,570 @@ +/* ssl/s2_lib.c */ +/* 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). + * + */ + +#include "ssl_locl.h" +#ifndef OPENSSL_NO_SSL2 +# include <stdio.h> +# include <openssl/objects.h> +# include <openssl/evp.h> +# include <openssl/md5.h> + +const char ssl2_version_str[] = "SSLv2" OPENSSL_VERSION_PTEXT; + +# define SSL2_NUM_CIPHERS (sizeof(ssl2_ciphers)/sizeof(SSL_CIPHER)) + +/* list of available SSLv2 ciphers (sorted by id) */ +OPENSSL_GLOBAL const SSL_CIPHER ssl2_ciphers[] = { +# if 0 +/* NULL_WITH_MD5 v3 */ + { + 1, + SSL2_TXT_NULL_WITH_MD5, + SSL2_CK_NULL_WITH_MD5, + SSL_kRSA, + SSL_aRSA, + SSL_eNULL, + SSL_MD5, + SSL_SSLV2, + SSL_EXPORT | SSL_EXP40 | SSL_STRONG_NONE, + 0, + 0, + 0, + }, +# endif + +/* RC4_128_WITH_MD5 */ + { + 1, + SSL2_TXT_RC4_128_WITH_MD5, + SSL2_CK_RC4_128_WITH_MD5, + SSL_kRSA, + SSL_aRSA, + SSL_RC4, + SSL_MD5, + SSL_SSLV2, + SSL_NOT_DEFAULT | SSL_NOT_EXP | SSL_MEDIUM, + 0, + 128, + 128, + }, + +# if 0 +/* RC4_128_EXPORT40_WITH_MD5 */ + { + 1, + SSL2_TXT_RC4_128_EXPORT40_WITH_MD5, + SSL2_CK_RC4_128_EXPORT40_WITH_MD5, + SSL_kRSA, + SSL_aRSA, + SSL_RC4, + SSL_MD5, + SSL_SSLV2, + SSL_NOT_DEFAULT | SSL_EXPORT | SSL_EXP40, + SSL2_CF_5_BYTE_ENC, + 40, + 128, + }, +# endif + +/* RC2_128_CBC_WITH_MD5 */ + { + 1, + SSL2_TXT_RC2_128_CBC_WITH_MD5, + SSL2_CK_RC2_128_CBC_WITH_MD5, + SSL_kRSA, + SSL_aRSA, + SSL_RC2, + SSL_MD5, + SSL_SSLV2, + SSL_NOT_DEFAULT | SSL_NOT_EXP | SSL_MEDIUM, + 0, + 128, + 128, + }, + +# if 0 +/* RC2_128_CBC_EXPORT40_WITH_MD5 */ + { + 1, + SSL2_TXT_RC2_128_CBC_EXPORT40_WITH_MD5, + SSL2_CK_RC2_128_CBC_EXPORT40_WITH_MD5, + SSL_kRSA, + SSL_aRSA, + SSL_RC2, + SSL_MD5, + SSL_SSLV2, + SSL_NOT_DEFAULT | SSL_EXPORT | SSL_EXP40, + SSL2_CF_5_BYTE_ENC, + 40, + 128, + }, +# endif + +# ifndef OPENSSL_NO_IDEA +/* IDEA_128_CBC_WITH_MD5 */ + { + 1, + SSL2_TXT_IDEA_128_CBC_WITH_MD5, + SSL2_CK_IDEA_128_CBC_WITH_MD5, + SSL_kRSA, + SSL_aRSA, + SSL_IDEA, + SSL_MD5, + SSL_SSLV2, + SSL_NOT_DEFAULT | SSL_NOT_EXP | SSL_MEDIUM, + 0, + 128, + 128, + }, +# endif + +# if 0 +/* DES_64_CBC_WITH_MD5 */ + { + 1, + SSL2_TXT_DES_64_CBC_WITH_MD5, + SSL2_CK_DES_64_CBC_WITH_MD5, + SSL_kRSA, + SSL_aRSA, + SSL_DES, + SSL_MD5, + SSL_SSLV2, + SSL_NOT_DEFAULT | SSL_NOT_EXP | SSL_LOW, + 0, + 56, + 56, + }, +# endif + +/* DES_192_EDE3_CBC_WITH_MD5 */ + { + 1, + SSL2_TXT_DES_192_EDE3_CBC_WITH_MD5, + SSL2_CK_DES_192_EDE3_CBC_WITH_MD5, + SSL_kRSA, + SSL_aRSA, + SSL_3DES, + SSL_MD5, + SSL_SSLV2, + SSL_NOT_DEFAULT | SSL_NOT_EXP | SSL_HIGH, + 0, + 112, + 168, + }, + +# if 0 +/* RC4_64_WITH_MD5 */ + { + 1, + SSL2_TXT_RC4_64_WITH_MD5, + SSL2_CK_RC4_64_WITH_MD5, + SSL_kRSA, + SSL_aRSA, + SSL_RC4, + SSL_MD5, + SSL_SSLV2, + SSL_NOT_DEFAULT | SSL_NOT_EXP | SSL_LOW, + SSL2_CF_8_BYTE_ENC, + 64, + 64, + }, +# endif + +# if 0 +/* NULL SSLeay (testing) */ + { + 0, + SSL2_TXT_NULL, + SSL2_CK_NULL, + 0, + 0, + 0, + 0, + SSL_SSLV2, + SSL_STRONG_NONE, + 0, + 0, + 0, + }, +# endif + +/* end of list :-) */ +}; + +long ssl2_default_timeout(void) +{ + return (300); +} + +int ssl2_num_ciphers(void) +{ + return (SSL2_NUM_CIPHERS); +} + +const SSL_CIPHER *ssl2_get_cipher(unsigned int u) +{ + if (u < SSL2_NUM_CIPHERS) + return (&(ssl2_ciphers[SSL2_NUM_CIPHERS - 1 - u])); + else + return (NULL); +} + +int ssl2_pending(const SSL *s) +{ + return SSL_in_init(s) ? 0 : s->s2->ract_data_length; +} + +int ssl2_new(SSL *s) +{ + SSL2_STATE *s2; + + if ((s2 = OPENSSL_malloc(sizeof *s2)) == NULL) + goto err; + memset(s2, 0, sizeof *s2); + +# if SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER + 3 > SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER + 2 +# error "assertion failed" +# endif + + if ((s2->rbuf = + OPENSSL_malloc(SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER + 2)) == NULL) + goto err; + /* + * wbuf needs one byte more because when using two-byte headers, we leave + * the first byte unused in do_ssl_write (s2_pkt.c) + */ + if ((s2->wbuf = + OPENSSL_malloc(SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER + 3)) == NULL) + goto err; + s->s2 = s2; + + ssl2_clear(s); + return (1); + err: + if (s2 != NULL) { + if (s2->wbuf != NULL) + OPENSSL_free(s2->wbuf); + if (s2->rbuf != NULL) + OPENSSL_free(s2->rbuf); + OPENSSL_free(s2); + } + return (0); +} + +void ssl2_free(SSL *s) +{ + SSL2_STATE *s2; + + if (s == NULL) + return; + + s2 = s->s2; + if (s2->rbuf != NULL) + OPENSSL_free(s2->rbuf); + if (s2->wbuf != NULL) + OPENSSL_free(s2->wbuf); + OPENSSL_cleanse(s2, sizeof *s2); + OPENSSL_free(s2); + s->s2 = NULL; +} + +void ssl2_clear(SSL *s) +{ + SSL2_STATE *s2; + unsigned char *rbuf, *wbuf; + + s2 = s->s2; + + rbuf = s2->rbuf; + wbuf = s2->wbuf; + + memset(s2, 0, sizeof *s2); + + s2->rbuf = rbuf; + s2->wbuf = wbuf; + s2->clear_text = 1; + s->packet = s2->rbuf; + s->version = SSL2_VERSION; + s->packet_length = 0; +} + +long ssl2_ctrl(SSL *s, int cmd, long larg, void *parg) +{ + int ret = 0; + + switch (cmd) { + case SSL_CTRL_GET_SESSION_REUSED: + ret = s->hit; + break; + case SSL_CTRL_CHECK_PROTO_VERSION: + return ssl3_ctrl(s, SSL_CTRL_CHECK_PROTO_VERSION, larg, parg); + default: + break; + } + return (ret); +} + +long ssl2_callback_ctrl(SSL *s, int cmd, void (*fp) (void)) +{ + return (0); +} + +long ssl2_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) +{ + return (0); +} + +long ssl2_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp) (void)) +{ + return (0); +} + +/* + * This function needs to check if the ciphers required are actually + * available + */ +const SSL_CIPHER *ssl2_get_cipher_by_char(const unsigned char *p) +{ + SSL_CIPHER c; + const SSL_CIPHER *cp; + unsigned long id; + + id = 0x02000000L | ((unsigned long)p[0] << 16L) | + ((unsigned long)p[1] << 8L) | (unsigned long)p[2]; + c.id = id; + cp = OBJ_bsearch_ssl_cipher_id(&c, ssl2_ciphers, SSL2_NUM_CIPHERS); + return cp; +} + +int ssl2_put_cipher_by_char(const SSL_CIPHER *c, unsigned char *p) +{ + long l; + + if (p != NULL) { + l = c->id; + if ((l & 0xff000000) != 0x02000000 && l != SSL3_CK_FALLBACK_SCSV) + return (0); + p[0] = ((unsigned char)(l >> 16L)) & 0xFF; + p[1] = ((unsigned char)(l >> 8L)) & 0xFF; + p[2] = ((unsigned char)(l)) & 0xFF; + } + return (3); +} + +int ssl2_generate_key_material(SSL *s) +{ + unsigned int i; + EVP_MD_CTX ctx; + unsigned char *km; + unsigned char c = '0'; + const EVP_MD *md5; + int md_size; + + md5 = EVP_md5(); + +# ifdef CHARSET_EBCDIC + c = os_toascii['0']; /* Must be an ASCII '0', not EBCDIC '0', see + * SSLv2 docu */ +# endif + EVP_MD_CTX_init(&ctx); + km = s->s2->key_material; + + if (s->session->master_key_length < 0 || + s->session->master_key_length > (int)sizeof(s->session->master_key)) { + SSLerr(SSL_F_SSL2_GENERATE_KEY_MATERIAL, ERR_R_INTERNAL_ERROR); + return 0; + } + md_size = EVP_MD_size(md5); + if (md_size < 0) + return 0; + for (i = 0; i < s->s2->key_material_length; i += md_size) { + if (((km - s->s2->key_material) + md_size) > + (int)sizeof(s->s2->key_material)) { + /* + * EVP_DigestFinal_ex() below would write beyond buffer + */ + SSLerr(SSL_F_SSL2_GENERATE_KEY_MATERIAL, ERR_R_INTERNAL_ERROR); + return 0; + } + + EVP_DigestInit_ex(&ctx, md5, NULL); + + OPENSSL_assert(s->session->master_key_length >= 0 + && s->session->master_key_length + <= (int)sizeof(s->session->master_key)); + EVP_DigestUpdate(&ctx, s->session->master_key, + s->session->master_key_length); + EVP_DigestUpdate(&ctx, &c, 1); + c++; + EVP_DigestUpdate(&ctx, s->s2->challenge, s->s2->challenge_length); + EVP_DigestUpdate(&ctx, s->s2->conn_id, s->s2->conn_id_length); + EVP_DigestFinal_ex(&ctx, km, NULL); + km += md_size; + } + + EVP_MD_CTX_cleanup(&ctx); + return 1; +} + +void ssl2_return_error(SSL *s, int err) +{ + if (!s->error) { + s->error = 3; + s->error_code = err; + + ssl2_write_error(s); + } +} + +void ssl2_write_error(SSL *s) +{ + unsigned char buf[3]; + int i, error; + + buf[0] = SSL2_MT_ERROR; + buf[1] = (s->error_code >> 8) & 0xff; + buf[2] = (s->error_code) & 0xff; + +/* state=s->rwstate;*/ + + error = s->error; /* number of bytes left to write */ + s->error = 0; + OPENSSL_assert(error >= 0 && error <= (int)sizeof(buf)); + i = ssl2_write(s, &(buf[3 - error]), error); + +/* if (i == error) s->rwstate=state; */ + + if (i < 0) + s->error = error; + else { + s->error = error - i; + + if (s->error == 0) + if (s->msg_callback) { + /* ERROR */ + s->msg_callback(1, s->version, 0, buf, 3, s, + s->msg_callback_arg); + } + } +} + +int ssl2_shutdown(SSL *s) +{ + s->shutdown = (SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); + return (1); +} +#else /* !OPENSSL_NO_SSL2 */ + +# if PEDANTIC +static void *dummy = &dummy; +# endif + +#endif diff --git a/thirdparty/openssl/ssl/s2_meth.c b/thirdparty/openssl/ssl/s2_meth.c new file mode 100644 index 0000000000..73885b7ecf --- /dev/null +++ b/thirdparty/openssl/ssl/s2_meth.c @@ -0,0 +1,91 @@ +/* ssl/s2_meth.c */ +/* 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.] + */ + +#include "ssl_locl.h" +#ifndef OPENSSL_NO_SSL2_METHOD +# ifndef OPENSSL_NO_SSL2 +# include <stdio.h> +# include <openssl/objects.h> + +static const SSL_METHOD *ssl2_get_method(int ver); +static const SSL_METHOD *ssl2_get_method(int ver) +{ + if (ver == SSL2_VERSION) + return (SSLv2_method()); + else + return (NULL); +} + +IMPLEMENT_ssl2_meth_func(SSLv2_method, + ssl2_accept, ssl2_connect, ssl2_get_method) + +# else /* !OPENSSL_NO_SSL2 */ + +const SSL_METHOD *SSLv2_method(void) { return NULL; } +const SSL_METHOD *SSLv2_client_method(void) { return NULL; } +const SSL_METHOD *SSLv2_server_method(void) { return NULL; } + +# endif + +#else /* !OPENSSL_NO_SSL2_METHOD */ + +# if PEDANTIC +static void *dummy = &dummy; +# endif + +#endif diff --git a/thirdparty/openssl/ssl/s2_pkt.c b/thirdparty/openssl/ssl/s2_pkt.c new file mode 100644 index 0000000000..7a61888134 --- /dev/null +++ b/thirdparty/openssl/ssl/s2_pkt.c @@ -0,0 +1,725 @@ +/* ssl/s2_pkt.c */ +/* 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-2001 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 "ssl_locl.h" +#ifndef OPENSSL_NO_SSL2 +# include <stdio.h> +# include <errno.h> +# define USE_SOCKETS + +static int read_n(SSL *s, unsigned int n, unsigned int max, + unsigned int extend); +static int n_do_ssl_write(SSL *s, const unsigned char *buf, unsigned int len); +static int write_pending(SSL *s, const unsigned char *buf, unsigned int len); +static int ssl_mt_error(int n); + +/* + * SSL 2.0 imlementation for SSL_read/SSL_peek - This routine will return 0 + * to len bytes, decrypted etc if required. + */ +static int ssl2_read_internal(SSL *s, void *buf, int len, int peek) +{ + int n; + unsigned char mac[MAX_MAC_SIZE]; + unsigned char *p; + int i; + int mac_size; + + ssl2_read_again: + if (SSL_in_init(s) && !s->in_handshake) { + n = s->handshake_func(s); + if (n < 0) + return (n); + if (n == 0) { + SSLerr(SSL_F_SSL2_READ_INTERNAL, SSL_R_SSL_HANDSHAKE_FAILURE); + return (-1); + } + } + + clear_sys_error(); + s->rwstate = SSL_NOTHING; + if (len <= 0) + return (len); + + if (s->s2->ract_data_length != 0) { /* read from buffer */ + if (len > s->s2->ract_data_length) + n = s->s2->ract_data_length; + else + n = len; + + memcpy(buf, s->s2->ract_data, (unsigned int)n); + if (!peek) { + s->s2->ract_data_length -= n; + s->s2->ract_data += n; + if (s->s2->ract_data_length == 0) + s->rstate = SSL_ST_READ_HEADER; + } + + return (n); + } + + /* + * s->s2->ract_data_length == 0 Fill the buffer, then goto + * ssl2_read_again. + */ + + if (s->rstate == SSL_ST_READ_HEADER) { + if (s->first_packet) { + n = read_n(s, 5, SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER + 2, 0); + if (n <= 0) + return (n); /* error or non-blocking */ + s->first_packet = 0; + p = s->packet; + if (!((p[0] & 0x80) && ((p[2] == SSL2_MT_CLIENT_HELLO) || + (p[2] == SSL2_MT_SERVER_HELLO)))) { + SSLerr(SSL_F_SSL2_READ_INTERNAL, + SSL_R_NON_SSLV2_INITIAL_PACKET); + return (-1); + } + } else { + n = read_n(s, 2, SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER + 2, 0); + if (n <= 0) + return (n); /* error or non-blocking */ + } + /* part read stuff */ + + s->rstate = SSL_ST_READ_BODY; + p = s->packet; + /* Do header */ + /* + * s->s2->padding=0; + */ + s->s2->escape = 0; + s->s2->rlength = (((unsigned int)p[0]) << 8) | ((unsigned int)p[1]); + if ((p[0] & TWO_BYTE_BIT)) { /* Two byte header? */ + s->s2->three_byte_header = 0; + s->s2->rlength &= TWO_BYTE_MASK; + } else { + s->s2->three_byte_header = 1; + s->s2->rlength &= THREE_BYTE_MASK; + + /* security >s2->escape */ + s->s2->escape = ((p[0] & SEC_ESC_BIT)) ? 1 : 0; + } + } + + if (s->rstate == SSL_ST_READ_BODY) { + n = s->s2->rlength + 2 + s->s2->three_byte_header; + if (n > (int)s->packet_length) { + n -= s->packet_length; + i = read_n(s, (unsigned int)n, (unsigned int)n, 1); + if (i <= 0) + return (i); /* ERROR */ + } + + p = &(s->packet[2]); + s->rstate = SSL_ST_READ_HEADER; + if (s->s2->three_byte_header) + s->s2->padding = *(p++); + else + s->s2->padding = 0; + + /* Data portion */ + if (s->s2->clear_text) { + mac_size = 0; + s->s2->mac_data = p; + s->s2->ract_data = p; + if (s->s2->padding) { + SSLerr(SSL_F_SSL2_READ_INTERNAL, SSL_R_ILLEGAL_PADDING); + return (-1); + } + } else { + mac_size = EVP_MD_CTX_size(s->read_hash); + if (mac_size < 0) + return -1; + OPENSSL_assert(mac_size <= MAX_MAC_SIZE); + s->s2->mac_data = p; + s->s2->ract_data = &p[mac_size]; + if (s->s2->padding + mac_size > s->s2->rlength) { + SSLerr(SSL_F_SSL2_READ_INTERNAL, SSL_R_ILLEGAL_PADDING); + return (-1); + } + } + + s->s2->ract_data_length = s->s2->rlength; + /* + * added a check for length > max_size in case encryption was not + * turned on yet due to an error + */ + if ((!s->s2->clear_text) && + (s->s2->rlength >= (unsigned int)mac_size)) { + if (!ssl2_enc(s, 0)) { + SSLerr(SSL_F_SSL2_READ_INTERNAL, SSL_R_DECRYPTION_FAILED); + return (-1); + } + s->s2->ract_data_length -= mac_size; + ssl2_mac(s, mac, 0); + s->s2->ract_data_length -= s->s2->padding; + if ((CRYPTO_memcmp(mac, s->s2->mac_data, mac_size) != 0) || + (s->s2->rlength % + EVP_CIPHER_CTX_block_size(s->enc_read_ctx) != 0)) { + SSLerr(SSL_F_SSL2_READ_INTERNAL, SSL_R_BAD_MAC_DECODE); + return (-1); + } + } + INC32(s->s2->read_sequence); /* expect next number */ + /* s->s2->ract_data is now available for processing */ + + /* + * Possibly the packet that we just read had 0 actual data bytes. + * (SSLeay/OpenSSL itself never sends such packets; see ssl2_write.) + * In this case, returning 0 would be interpreted by the caller as + * indicating EOF, so it's not a good idea. Instead, we just + * continue reading; thus ssl2_read_internal may have to process + * multiple packets before it can return. [Note that using select() + * for blocking sockets *never* guarantees that the next SSL_read + * will not block -- the available data may contain incomplete + * packets, and except for SSL 2, renegotiation can confuse things + * even more.] + */ + + goto ssl2_read_again; /* This should really be "return + * ssl2_read(s,buf,len)", but that would + * allow for denial-of-service attacks if a C + * compiler is used that does not recognize + * end-recursion. */ + } else { + SSLerr(SSL_F_SSL2_READ_INTERNAL, SSL_R_BAD_STATE); + return (-1); + } +} + +int ssl2_read(SSL *s, void *buf, int len) +{ + return ssl2_read_internal(s, buf, len, 0); +} + +int ssl2_peek(SSL *s, void *buf, int len) +{ + return ssl2_read_internal(s, buf, len, 1); +} + +static int read_n(SSL *s, unsigned int n, unsigned int max, + unsigned int extend) +{ + int i, off, newb; + + /* + * if there is stuff still in the buffer from a previous read, and there + * is more than we want, take some. + */ + if (s->s2->rbuf_left >= (int)n) { + if (extend) + s->packet_length += n; + else { + s->packet = &(s->s2->rbuf[s->s2->rbuf_offs]); + s->packet_length = n; + } + s->s2->rbuf_left -= n; + s->s2->rbuf_offs += n; + return (n); + } + + if (!s->read_ahead) + max = n; + if (max > (unsigned int)(SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER + 2)) + max = SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER + 2; + + /* + * Else we want more than we have. First, if there is some left or we + * want to extend + */ + off = 0; + if ((s->s2->rbuf_left != 0) || ((s->packet_length != 0) && extend)) { + newb = s->s2->rbuf_left; + if (extend) { + off = s->packet_length; + if (s->packet != s->s2->rbuf) + memcpy(s->s2->rbuf, s->packet, (unsigned int)newb + off); + } else if (s->s2->rbuf_offs != 0) { + memcpy(s->s2->rbuf, &(s->s2->rbuf[s->s2->rbuf_offs]), + (unsigned int)newb); + s->s2->rbuf_offs = 0; + } + s->s2->rbuf_left = 0; + } else + newb = 0; + + /* + * off is the offset to start writing too. r->s2->rbuf_offs is the + * 'unread data', now 0. newb is the number of new bytes so far + */ + s->packet = s->s2->rbuf; + while (newb < (int)n) { + clear_sys_error(); + if (s->rbio != NULL) { + s->rwstate = SSL_READING; + i = BIO_read(s->rbio, (char *)&(s->s2->rbuf[off + newb]), + max - newb); + } else { + SSLerr(SSL_F_READ_N, SSL_R_READ_BIO_NOT_SET); + i = -1; + } +# ifdef PKT_DEBUG + if (s->debug & 0x01) + sleep(1); +# endif + if (i <= 0) { + s->s2->rbuf_left += newb; + return (i); + } + newb += i; + } + + /* record unread data */ + if (newb > (int)n) { + s->s2->rbuf_offs = n + off; + s->s2->rbuf_left = newb - n; + } else { + s->s2->rbuf_offs = 0; + s->s2->rbuf_left = 0; + } + if (extend) + s->packet_length += n; + else + s->packet_length = n; + s->rwstate = SSL_NOTHING; + return (n); +} + +int ssl2_write(SSL *s, const void *_buf, int len) +{ + const unsigned char *buf = _buf; + unsigned int n, tot; + int i; + + if (SSL_in_init(s) && !s->in_handshake) { + i = s->handshake_func(s); + if (i < 0) + return (i); + if (i == 0) { + SSLerr(SSL_F_SSL2_WRITE, SSL_R_SSL_HANDSHAKE_FAILURE); + return (-1); + } + } + + if (s->error) { + ssl2_write_error(s); + if (s->error) + return (-1); + } + + clear_sys_error(); + s->rwstate = SSL_NOTHING; + if (len <= 0) + return (len); + + tot = s->s2->wnum; + s->s2->wnum = 0; + + n = (len - tot); + for (;;) { + i = n_do_ssl_write(s, &(buf[tot]), n); + if (i <= 0) { + s->s2->wnum = tot; + return (i); + } + if ((i == (int)n) || (s->mode & SSL_MODE_ENABLE_PARTIAL_WRITE)) { + return (tot + i); + } + + n -= i; + tot += i; + } +} + +static int write_pending(SSL *s, const unsigned char *buf, unsigned int len) +{ + int i; + + /* s->s2->wpend_len != 0 MUST be true. */ + + /* + * check that they have given us the same buffer to write + */ + if ((s->s2->wpend_tot > (int)len) || + ((s->s2->wpend_buf != buf) && + !(s->mode & SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER))) { + SSLerr(SSL_F_WRITE_PENDING, SSL_R_BAD_WRITE_RETRY); + return (-1); + } + + for (;;) { + clear_sys_error(); + if (s->wbio != NULL) { + s->rwstate = SSL_WRITING; + i = BIO_write(s->wbio, + (char *)&(s->s2->write_ptr[s->s2->wpend_off]), + (unsigned int)s->s2->wpend_len); + } else { + SSLerr(SSL_F_WRITE_PENDING, SSL_R_WRITE_BIO_NOT_SET); + i = -1; + } +# ifdef PKT_DEBUG + if (s->debug & 0x01) + sleep(1); +# endif + if (i == s->s2->wpend_len) { + s->s2->wpend_len = 0; + s->rwstate = SSL_NOTHING; + return (s->s2->wpend_ret); + } else if (i <= 0) + return (i); + s->s2->wpend_off += i; + s->s2->wpend_len -= i; + } +} + +static int n_do_ssl_write(SSL *s, const unsigned char *buf, unsigned int len) +{ + unsigned int j, k, olen, p, bs; + int mac_size; + register unsigned char *pp; + + olen = len; + + /* + * first check if there is data from an encryption waiting to be sent - + * it must be sent because the other end is waiting. This will happen + * with non-blocking IO. We print it and then return. + */ + if (s->s2->wpend_len != 0) + return (write_pending(s, buf, len)); + + /* set mac_size to mac size */ + if (s->s2->clear_text) + mac_size = 0; + else { + mac_size = EVP_MD_CTX_size(s->write_hash); + if (mac_size < 0) + return -1; + } + + /* lets set the pad p */ + if (s->s2->clear_text) { + if (len > SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER) + len = SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER; + p = 0; + s->s2->three_byte_header = 0; + /* len=len; */ + } else { + bs = EVP_CIPHER_CTX_block_size(s->enc_read_ctx); + j = len + mac_size; + /* + * Two-byte headers allow for a larger record length than three-byte + * headers, but we can't use them if we need padding or if we have to + * set the escape bit. + */ + if ((j > SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER) && (!s->s2->escape)) { + if (j > SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER) + j = SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER; + /* + * set k to the max number of bytes with 2 byte header + */ + k = j - (j % bs); + /* how many data bytes? */ + len = k - mac_size; + s->s2->three_byte_header = 0; + p = 0; + } else if ((bs <= 1) && (!s->s2->escape)) { + /*- + * j <= SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER, thus + * j < SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER + */ + s->s2->three_byte_header = 0; + p = 0; + } else { /* we may have to use a 3 byte header */ + + /*- + * If s->s2->escape is not set, then + * j <= SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER, and thus + * j < SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER. + */ + p = (j % bs); + p = (p == 0) ? 0 : (bs - p); + if (s->s2->escape) { + s->s2->three_byte_header = 1; + if (j > SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER) + j = SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER; + } else + s->s2->three_byte_header = (p == 0) ? 0 : 1; + } + } + + /*- + * Now + * j <= SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER + * holds, and if s->s2->three_byte_header is set, then even + * j <= SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER. + */ + + /* + * mac_size is the number of MAC bytes len is the number of data bytes we + * are going to send p is the number of padding bytes (if it is a + * two-byte header, then p == 0) + */ + + s->s2->wlength = len; + s->s2->padding = p; + s->s2->mac_data = &(s->s2->wbuf[3]); + s->s2->wact_data = &(s->s2->wbuf[3 + mac_size]); + + /* + * It would be clearer to write this as follows: + * if (mac_size + len + p > SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER) + * However |len| is user input that could in theory be very large. We + * know |mac_size| and |p| are small, so to avoid any possibility of + * overflow we write it like this. + * + * In theory this should never fail because the logic above should have + * modified |len| if it is too big. But we are being cautious. + */ + if (len > (SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER - (mac_size + p))) { + return -1; + } + /* we copy the data into s->s2->wbuf */ + memcpy(s->s2->wact_data, buf, len); + if (p) + memset(&(s->s2->wact_data[len]), 0, p); /* arbitrary padding */ + + if (!s->s2->clear_text) { + s->s2->wact_data_length = len + p; + ssl2_mac(s, s->s2->mac_data, 1); + s->s2->wlength += p + mac_size; + if (ssl2_enc(s, 1) < 1) + return -1; + } + + /* package up the header */ + s->s2->wpend_len = s->s2->wlength; + if (s->s2->three_byte_header) { /* 3 byte header */ + pp = s->s2->mac_data; + pp -= 3; + pp[0] = (s->s2->wlength >> 8) & (THREE_BYTE_MASK >> 8); + if (s->s2->escape) + pp[0] |= SEC_ESC_BIT; + pp[1] = s->s2->wlength & 0xff; + pp[2] = s->s2->padding; + s->s2->wpend_len += 3; + } else { + pp = s->s2->mac_data; + pp -= 2; + pp[0] = ((s->s2->wlength >> 8) & (TWO_BYTE_MASK >> 8)) | TWO_BYTE_BIT; + pp[1] = s->s2->wlength & 0xff; + s->s2->wpend_len += 2; + } + s->s2->write_ptr = pp; + + INC32(s->s2->write_sequence); /* expect next number */ + + /* lets try to actually write the data */ + s->s2->wpend_tot = olen; + s->s2->wpend_buf = buf; + + s->s2->wpend_ret = len; + + s->s2->wpend_off = 0; + return (write_pending(s, buf, olen)); +} + +int ssl2_part_read(SSL *s, unsigned long f, int i) +{ + unsigned char *p; + int j; + + if (i < 0) { + /* ssl2_return_error(s); */ + /* + * for non-blocking io, this is not necessarily fatal + */ + return (i); + } else { + s->init_num += i; + + /* + * Check for error. While there are recoverable errors, this + * function is not called when those must be expected; any error + * detected here is fatal. + */ + if (s->init_num >= 3) { + p = (unsigned char *)s->init_buf->data; + if (p[0] == SSL2_MT_ERROR) { + j = (p[1] << 8) | p[2]; + SSLerr((int)f, ssl_mt_error(j)); + s->init_num -= 3; + if (s->init_num > 0) + memmove(p, p + 3, s->init_num); + } + } + + /* + * If it's not an error message, we have some error anyway -- the + * message was shorter than expected. This too is treated as fatal + * (at least if SSL_get_error is asked for its opinion). + */ + return (0); + } +} + +int ssl2_do_write(SSL *s) +{ + int ret; + + ret = ssl2_write(s, &s->init_buf->data[s->init_off], s->init_num); + if (ret == s->init_num) { + if (s->msg_callback) + s->msg_callback(1, s->version, 0, s->init_buf->data, + (size_t)(s->init_off + s->init_num), s, + s->msg_callback_arg); + return (1); + } + if (ret < 0) + return (-1); + s->init_off += ret; + s->init_num -= ret; + return (0); +} + +static int ssl_mt_error(int n) +{ + int ret; + + switch (n) { + case SSL2_PE_NO_CIPHER: + ret = SSL_R_PEER_ERROR_NO_CIPHER; + break; + case SSL2_PE_NO_CERTIFICATE: + ret = SSL_R_PEER_ERROR_NO_CERTIFICATE; + break; + case SSL2_PE_BAD_CERTIFICATE: + ret = SSL_R_PEER_ERROR_CERTIFICATE; + break; + case SSL2_PE_UNSUPPORTED_CERTIFICATE_TYPE: + ret = SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE; + break; + default: + ret = SSL_R_UNKNOWN_REMOTE_ERROR_TYPE; + break; + } + return (ret); +} +#else /* !OPENSSL_NO_SSL2 */ + +# if PEDANTIC +static void *dummy = &dummy; +# endif + +#endif diff --git a/thirdparty/openssl/ssl/s2_srvr.c b/thirdparty/openssl/ssl/s2_srvr.c new file mode 100644 index 0000000000..07e9df8282 --- /dev/null +++ b/thirdparty/openssl/ssl/s2_srvr.c @@ -0,0 +1,1171 @@ +/* ssl/s2_srvr.c */ +/* 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-2001 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 "ssl_locl.h" +#ifndef OPENSSL_NO_SSL2 +#include "../crypto/constant_time_locl.h" +# include <stdio.h> +# include <openssl/bio.h> +# include <openssl/rand.h> +# include <openssl/objects.h> +# include <openssl/evp.h> + +static const SSL_METHOD *ssl2_get_server_method(int ver); +static int get_client_master_key(SSL *s); +static int get_client_hello(SSL *s); +static int server_hello(SSL *s); +static int get_client_finished(SSL *s); +static int server_verify(SSL *s); +static int server_finish(SSL *s); +static int request_certificate(SSL *s); +static int ssl_rsa_private_decrypt(CERT *c, int len, unsigned char *from, + unsigned char *to, int padding); +# define BREAK break + +static const SSL_METHOD *ssl2_get_server_method(int ver) +{ + if (ver == SSL2_VERSION) + return (SSLv2_server_method()); + else + return (NULL); +} + +IMPLEMENT_ssl2_meth_func(SSLv2_server_method, + ssl2_accept, + ssl_undefined_function, ssl2_get_server_method) + +int ssl2_accept(SSL *s) +{ + unsigned long l = (unsigned long)time(NULL); + BUF_MEM *buf = NULL; + int ret = -1; + long num1; + void (*cb) (const SSL *ssl, int type, int val) = NULL; + int new_state, state; + + RAND_add(&l, sizeof(l), 0); + ERR_clear_error(); + clear_sys_error(); + + if (s->info_callback != NULL) + cb = s->info_callback; + else if (s->ctx->info_callback != NULL) + cb = s->ctx->info_callback; + + /* init things to blank */ + s->in_handshake++; + if (!SSL_in_init(s) || SSL_in_before(s)) + SSL_clear(s); + + if (s->cert == NULL) { + SSLerr(SSL_F_SSL2_ACCEPT, SSL_R_NO_CERTIFICATE_SET); + return (-1); + } + + clear_sys_error(); + for (;;) { + state = s->state; + + switch (s->state) { + 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); + + s->version = SSL2_VERSION; + s->type = SSL_ST_ACCEPT; + + if (s->init_buf == NULL) { + if ((buf = BUF_MEM_new()) == NULL) { + ret = -1; + goto end; + } + if (!BUF_MEM_grow + (buf, (int)SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER)) { + BUF_MEM_free(buf); + ret = -1; + goto end; + } + s->init_buf = buf; + } + s->init_num = 0; + s->ctx->stats.sess_accept++; + s->handshake_func = ssl2_accept; + s->state = SSL2_ST_GET_CLIENT_HELLO_A; + BREAK; + + case SSL2_ST_GET_CLIENT_HELLO_A: + case SSL2_ST_GET_CLIENT_HELLO_B: + case SSL2_ST_GET_CLIENT_HELLO_C: + s->shutdown = 0; + ret = get_client_hello(s); + if (ret <= 0) + goto end; + s->init_num = 0; + s->state = SSL2_ST_SEND_SERVER_HELLO_A; + BREAK; + + case SSL2_ST_SEND_SERVER_HELLO_A: + case SSL2_ST_SEND_SERVER_HELLO_B: + ret = server_hello(s); + if (ret <= 0) + goto end; + s->init_num = 0; + if (!s->hit) { + s->state = SSL2_ST_GET_CLIENT_MASTER_KEY_A; + BREAK; + } else { + s->state = SSL2_ST_SERVER_START_ENCRYPTION; + BREAK; + } + case SSL2_ST_GET_CLIENT_MASTER_KEY_A: + case SSL2_ST_GET_CLIENT_MASTER_KEY_B: + ret = get_client_master_key(s); + if (ret <= 0) + goto end; + s->init_num = 0; + s->state = SSL2_ST_SERVER_START_ENCRYPTION; + BREAK; + + case SSL2_ST_SERVER_START_ENCRYPTION: + /* + * Ok we how have sent all the stuff needed to start encrypting, + * the next packet back will be encrypted. + */ + if (!ssl2_enc_init(s, 0)) { + ret = -1; + goto end; + } + s->s2->clear_text = 0; + s->state = SSL2_ST_SEND_SERVER_VERIFY_A; + BREAK; + + case SSL2_ST_SEND_SERVER_VERIFY_A: + case SSL2_ST_SEND_SERVER_VERIFY_B: + ret = server_verify(s); + if (ret <= 0) + goto end; + s->init_num = 0; + if (s->hit) { + /* + * If we are in here, we have been buffering the output, so + * we need to flush it and remove buffering from future + * traffic + */ + s->state = SSL2_ST_SEND_SERVER_VERIFY_C; + BREAK; + } else { + s->state = SSL2_ST_GET_CLIENT_FINISHED_A; + break; + } + + case SSL2_ST_SEND_SERVER_VERIFY_C: + /* get the number of bytes to write */ + num1 = BIO_ctrl(s->wbio, BIO_CTRL_INFO, 0, NULL); + if (num1 > 0) { + s->rwstate = SSL_WRITING; + num1 = BIO_flush(s->wbio); + if (num1 <= 0) { + ret = -1; + goto end; + } + s->rwstate = SSL_NOTHING; + } + + /* flushed and now remove buffering */ + s->wbio = BIO_pop(s->wbio); + + s->state = SSL2_ST_GET_CLIENT_FINISHED_A; + BREAK; + + case SSL2_ST_GET_CLIENT_FINISHED_A: + case SSL2_ST_GET_CLIENT_FINISHED_B: + ret = get_client_finished(s); + if (ret <= 0) + goto end; + s->init_num = 0; + s->state = SSL2_ST_SEND_REQUEST_CERTIFICATE_A; + BREAK; + + case SSL2_ST_SEND_REQUEST_CERTIFICATE_A: + case SSL2_ST_SEND_REQUEST_CERTIFICATE_B: + case SSL2_ST_SEND_REQUEST_CERTIFICATE_C: + case SSL2_ST_SEND_REQUEST_CERTIFICATE_D: + /* + * don't do a 'request certificate' if we don't want to, or we + * already have one, and we only want to do it once. + */ + if (!(s->verify_mode & SSL_VERIFY_PEER) || + ((s->session->peer != NULL) && + (s->verify_mode & SSL_VERIFY_CLIENT_ONCE))) { + s->state = SSL2_ST_SEND_SERVER_FINISHED_A; + break; + } else { + ret = request_certificate(s); + if (ret <= 0) + goto end; + s->init_num = 0; + s->state = SSL2_ST_SEND_SERVER_FINISHED_A; + } + BREAK; + + case SSL2_ST_SEND_SERVER_FINISHED_A: + case SSL2_ST_SEND_SERVER_FINISHED_B: + ret = server_finish(s); + if (ret <= 0) + goto end; + s->init_num = 0; + s->state = SSL_ST_OK; + break; + + case SSL_ST_OK: + BUF_MEM_free(s->init_buf); + ssl_free_wbio_buffer(s); + s->init_buf = NULL; + s->init_num = 0; + /* ERR_clear_error(); */ + + ssl_update_cache(s, SSL_SESS_CACHE_SERVER); + + s->ctx->stats.sess_accept_good++; + /* s->server=1; */ + ret = 1; + + if (cb != NULL) + cb(s, SSL_CB_HANDSHAKE_DONE, 1); + + goto end; + /* BREAK; */ + + default: + SSLerr(SSL_F_SSL2_ACCEPT, SSL_R_UNKNOWN_STATE); + ret = -1; + goto end; + /* BREAK; */ + } + + if ((cb != NULL) && (s->state != state)) { + new_state = s->state; + s->state = state; + cb(s, SSL_CB_ACCEPT_LOOP, 1); + s->state = new_state; + } + } + end: + s->in_handshake--; + if (cb != NULL) + cb(s, SSL_CB_ACCEPT_EXIT, ret); + return (ret); +} + +static int get_client_master_key(SSL *s) +{ + int is_export, i, n, keya; + unsigned int num_encrypted_key_bytes, key_length; + unsigned long len; + unsigned char *p; + const SSL_CIPHER *cp; + const EVP_CIPHER *c; + const EVP_MD *md; + unsigned char rand_premaster_secret[SSL_MAX_MASTER_KEY_LENGTH]; + unsigned char decrypt_good; + size_t j; + + p = (unsigned char *)s->init_buf->data; + if (s->state == SSL2_ST_GET_CLIENT_MASTER_KEY_A) { + i = ssl2_read(s, (char *)&(p[s->init_num]), 10 - s->init_num); + + if (i < (10 - s->init_num)) + return (ssl2_part_read(s, SSL_F_GET_CLIENT_MASTER_KEY, i)); + s->init_num = 10; + + if (*(p++) != SSL2_MT_CLIENT_MASTER_KEY) { + if (p[-1] != SSL2_MT_ERROR) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, + SSL_R_READ_WRONG_PACKET_TYPE); + } else + SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, SSL_R_PEER_ERROR); + return (-1); + } + + cp = ssl2_get_cipher_by_char(p); + if (cp == NULL || sk_SSL_CIPHER_find(s->session->ciphers, cp) < 0) { + ssl2_return_error(s, SSL2_PE_NO_CIPHER); + SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, SSL_R_NO_CIPHER_MATCH); + return (-1); + } + s->session->cipher = cp; + + p += 3; + n2s(p, i); + s->s2->tmp.clear = i; + n2s(p, i); + s->s2->tmp.enc = i; + n2s(p, i); + if (i > SSL_MAX_KEY_ARG_LENGTH) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, SSL_R_KEY_ARG_TOO_LONG); + return -1; + } + s->session->key_arg_length = i; + s->state = SSL2_ST_GET_CLIENT_MASTER_KEY_B; + } + + /* SSL2_ST_GET_CLIENT_MASTER_KEY_B */ + p = (unsigned char *)s->init_buf->data; + if (s->init_buf->length < SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, ERR_R_INTERNAL_ERROR); + return -1; + } + keya = s->session->key_arg_length; + len = + 10 + (unsigned long)s->s2->tmp.clear + (unsigned long)s->s2->tmp.enc + + (unsigned long)keya; + if (len > SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, SSL_R_MESSAGE_TOO_LONG); + return -1; + } + n = (int)len - s->init_num; + i = ssl2_read(s, (char *)&(p[s->init_num]), n); + if (i != n) + return (ssl2_part_read(s, SSL_F_GET_CLIENT_MASTER_KEY, i)); + if (s->msg_callback) { + /* CLIENT-MASTER-KEY */ + s->msg_callback(0, s->version, 0, p, (size_t)len, s, + s->msg_callback_arg); + } + p += 10; + + memcpy(s->session->key_arg, &(p[s->s2->tmp.clear + s->s2->tmp.enc]), + (unsigned int)keya); + + if (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, SSL_R_NO_PRIVATEKEY); + return (-1); + } + + is_export = SSL_C_IS_EXPORT(s->session->cipher); + + if (!ssl_cipher_get_evp(s->session, &c, &md, NULL, NULL, NULL)) { + ssl2_return_error(s, SSL2_PE_NO_CIPHER); + SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, + SSL_R_PROBLEMS_MAPPING_CIPHER_FUNCTIONS); + return (0); + } + + /* + * The format of the CLIENT-MASTER-KEY message is + * 1 byte message type + * 3 bytes cipher + * 2-byte clear key length (stored in s->s2->tmp.clear) + * 2-byte encrypted key length (stored in s->s2->tmp.enc) + * 2-byte key args length (IV etc) + * clear key + * encrypted key + * key args + * + * If the cipher is an export cipher, then the encrypted key bytes + * are a fixed portion of the total key (5 or 8 bytes). The size of + * this portion is in |num_encrypted_key_bytes|. If the cipher is not an + * export cipher, then the entire key material is encrypted (i.e., clear + * key length must be zero). + */ + key_length = (unsigned int)EVP_CIPHER_key_length(c); + if (key_length > SSL_MAX_MASTER_KEY_LENGTH) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_GET_CLIENT_MASTER_KEY, ERR_R_INTERNAL_ERROR); + return -1; + } + + if (s->session->cipher->algorithm2 & SSL2_CF_8_BYTE_ENC) { + is_export = 1; + num_encrypted_key_bytes = 8; + } else if (is_export) { + num_encrypted_key_bytes = 5; + } else { + num_encrypted_key_bytes = key_length; + } + + if (s->s2->tmp.clear + num_encrypted_key_bytes != key_length) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_BAD_LENGTH); + return -1; + } + /* + * The encrypted blob must decrypt to the encrypted portion of the key. + * Decryption can't be expanding, so if we don't have enough encrypted + * bytes to fit the key in the buffer, stop now. + */ + if (s->s2->tmp.enc < num_encrypted_key_bytes) { + ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_LENGTH_TOO_SHORT); + return -1; + } + + /* + * We must not leak whether a decryption failure occurs because of + * Bleichenbacher's attack on PKCS #1 v1.5 RSA padding (see RFC 2246, + * section 7.4.7.1). The code follows that advice of the TLS RFC and + * generates a random premaster secret for the case that the decrypt + * fails. See https://tools.ietf.org/html/rfc5246#section-7.4.7.1 + */ + + /* + * should be RAND_bytes, but we cannot work around a failure. + */ + if (RAND_pseudo_bytes(rand_premaster_secret, + (int)num_encrypted_key_bytes) <= 0) + return 0; + + i = ssl_rsa_private_decrypt(s->cert, s->s2->tmp.enc, + &(p[s->s2->tmp.clear]), + &(p[s->s2->tmp.clear]), + (s->s2->ssl2_rollback) ? RSA_SSLV23_PADDING : + RSA_PKCS1_PADDING); + ERR_clear_error(); + /* + * If a bad decrypt, continue with protocol but with a random master + * secret (Bleichenbacher attack) + */ + decrypt_good = constant_time_eq_int_8(i, (int)num_encrypted_key_bytes); + for (j = 0; j < num_encrypted_key_bytes; j++) { + p[s->s2->tmp.clear + j] = + constant_time_select_8(decrypt_good, p[s->s2->tmp.clear + j], + rand_premaster_secret[j]); + } + + s->session->master_key_length = (int)key_length; + memcpy(s->session->master_key, p, key_length); + OPENSSL_cleanse(p, key_length); + + return 1; +} + +static int get_client_hello(SSL *s) +{ + int i, n; + unsigned long len; + unsigned char *p; + STACK_OF(SSL_CIPHER) *cs; /* a stack of SSL_CIPHERS */ + STACK_OF(SSL_CIPHER) *cl; /* the ones we want to use */ + STACK_OF(SSL_CIPHER) *prio, *allow; + int z; + + /* + * This is a bit of a hack to check for the correct packet type the first + * time round. + */ + if (s->state == SSL2_ST_GET_CLIENT_HELLO_A) { + s->first_packet = 1; + s->state = SSL2_ST_GET_CLIENT_HELLO_B; + } + + p = (unsigned char *)s->init_buf->data; + if (s->state == SSL2_ST_GET_CLIENT_HELLO_B) { + i = ssl2_read(s, (char *)&(p[s->init_num]), 9 - s->init_num); + if (i < (9 - s->init_num)) + return (ssl2_part_read(s, SSL_F_GET_CLIENT_HELLO, i)); + s->init_num = 9; + + if (*(p++) != SSL2_MT_CLIENT_HELLO) { + if (p[-1] != SSL2_MT_ERROR) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_GET_CLIENT_HELLO, SSL_R_READ_WRONG_PACKET_TYPE); + } else + SSLerr(SSL_F_GET_CLIENT_HELLO, SSL_R_PEER_ERROR); + return (-1); + } + n2s(p, i); + if (i < s->version) + s->version = i; + n2s(p, i); + s->s2->tmp.cipher_spec_length = i; + n2s(p, i); + s->s2->tmp.session_id_length = i; + if ((i < 0) || (i > SSL_MAX_SSL_SESSION_ID_LENGTH)) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_GET_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH); + return -1; + } + n2s(p, i); + s->s2->challenge_length = i; + if ((i < SSL2_MIN_CHALLENGE_LENGTH) || + (i > SSL2_MAX_CHALLENGE_LENGTH)) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_GET_CLIENT_HELLO, SSL_R_INVALID_CHALLENGE_LENGTH); + return (-1); + } + s->state = SSL2_ST_GET_CLIENT_HELLO_C; + } + + /* SSL2_ST_GET_CLIENT_HELLO_C */ + p = (unsigned char *)s->init_buf->data; + len = + 9 + (unsigned long)s->s2->tmp.cipher_spec_length + + (unsigned long)s->s2->challenge_length + + (unsigned long)s->s2->tmp.session_id_length; + if (len > SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_GET_CLIENT_HELLO, SSL_R_MESSAGE_TOO_LONG); + return -1; + } + n = (int)len - s->init_num; + i = ssl2_read(s, (char *)&(p[s->init_num]), n); + if (i != n) + return (ssl2_part_read(s, SSL_F_GET_CLIENT_HELLO, i)); + if (s->msg_callback) { + /* CLIENT-HELLO */ + s->msg_callback(0, s->version, 0, p, (size_t)len, s, + s->msg_callback_arg); + } + p += 9; + + /* + * get session-id before cipher stuff so we can get out session structure + * if it is cached + */ + /* session-id */ + if ((s->s2->tmp.session_id_length != 0) && + (s->s2->tmp.session_id_length != SSL2_SSL_SESSION_ID_LENGTH)) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_GET_CLIENT_HELLO, SSL_R_BAD_SSL_SESSION_ID_LENGTH); + return (-1); + } + + if (s->s2->tmp.session_id_length == 0) { + if (!ssl_get_new_session(s, 1)) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + return (-1); + } + } else { + i = ssl_get_prev_session(s, &(p[s->s2->tmp.cipher_spec_length]), + s->s2->tmp.session_id_length, NULL); + if (i == 1) { /* previous session */ + s->hit = 1; + } else if (i == -1) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + return (-1); + } else { + if (s->cert == NULL) { + ssl2_return_error(s, SSL2_PE_NO_CERTIFICATE); + SSLerr(SSL_F_GET_CLIENT_HELLO, SSL_R_NO_CERTIFICATE_SET); + return (-1); + } + + if (!ssl_get_new_session(s, 1)) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + return (-1); + } + } + } + + if (!s->hit) { + cs = ssl_bytes_to_cipher_list(s, p, s->s2->tmp.cipher_spec_length, + &s->session->ciphers); + if (cs == NULL) + goto mem_err; + + cl = SSL_get_ciphers(s); + + if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE) { + prio = sk_SSL_CIPHER_dup(cl); + if (prio == NULL) + goto mem_err; + allow = cs; + } else { + prio = cs; + allow = cl; + } + + /* Generate list of SSLv2 ciphers shared between client and server */ + for (z = 0; z < sk_SSL_CIPHER_num(prio); z++) { + const SSL_CIPHER *cp = sk_SSL_CIPHER_value(prio, z); + if ((cp->algorithm_ssl & SSL_SSLV2) == 0 || + sk_SSL_CIPHER_find(allow, cp) < 0) { + (void)sk_SSL_CIPHER_delete(prio, z); + z--; + } + } + if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE) { + sk_SSL_CIPHER_free(s->session->ciphers); + s->session->ciphers = prio; + } + + /* Make sure we have at least one cipher in common */ + if (sk_SSL_CIPHER_num(s->session->ciphers) == 0) { + ssl2_return_error(s, SSL2_PE_NO_CIPHER); + SSLerr(SSL_F_GET_CLIENT_HELLO, SSL_R_NO_CIPHER_MATCH); + return -1; + } + /* + * s->session->ciphers should now have a list of ciphers that are on + * both the client and server. This list is ordered by the order the + * client sent the ciphers or in the order of the server's preference + * if SSL_OP_CIPHER_SERVER_PREFERENCE was set. + */ + } + p += s->s2->tmp.cipher_spec_length; + /* done cipher selection */ + + /* session id extracted already */ + p += s->s2->tmp.session_id_length; + + /* challenge */ + if (s->s2->challenge_length > sizeof s->s2->challenge) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_GET_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); + return -1; + } + memcpy(s->s2->challenge, p, (unsigned int)s->s2->challenge_length); + return (1); + mem_err: + SSLerr(SSL_F_GET_CLIENT_HELLO, ERR_R_MALLOC_FAILURE); + return (0); +} + +static int server_hello(SSL *s) +{ + unsigned char *p, *d; + int n, hit; + + p = (unsigned char *)s->init_buf->data; + if (s->state == SSL2_ST_SEND_SERVER_HELLO_A) { + d = p + 11; + *(p++) = SSL2_MT_SERVER_HELLO; /* type */ + hit = s->hit; + *(p++) = (unsigned char)hit; +# if 1 + if (!hit) { + if (s->session->sess_cert != NULL) + /* + * This can't really happen because get_client_hello has + * called ssl_get_new_session, which does not set sess_cert. + */ + ssl_sess_cert_free(s->session->sess_cert); + s->session->sess_cert = ssl_sess_cert_new(); + if (s->session->sess_cert == NULL) { + SSLerr(SSL_F_SERVER_HELLO, ERR_R_MALLOC_FAILURE); + return (-1); + } + } + /* + * If 'hit' is set, then s->sess_cert may be non-NULL or NULL, + * depending on whether it survived in the internal cache or was + * retrieved from an external cache. If it is NULL, we cannot put any + * useful data in it anyway, so we don't touch it. + */ + +# else /* That's what used to be done when cert_st + * and sess_cert_st were * the same. */ + if (!hit) { /* else add cert to session */ + CRYPTO_add(&s->cert->references, 1, CRYPTO_LOCK_SSL_CERT); + if (s->session->sess_cert != NULL) + ssl_cert_free(s->session->sess_cert); + s->session->sess_cert = s->cert; + } else { /* We have a session id-cache hit, if the * + * session-id has no certificate listed + * against * the 'cert' structure, grab the + * 'old' one * listed against the SSL + * connection */ + if (s->session->sess_cert == NULL) { + CRYPTO_add(&s->cert->references, 1, CRYPTO_LOCK_SSL_CERT); + s->session->sess_cert = s->cert; + } + } +# endif + + if (s->cert == NULL) { + ssl2_return_error(s, SSL2_PE_NO_CERTIFICATE); + SSLerr(SSL_F_SERVER_HELLO, SSL_R_NO_CERTIFICATE_SPECIFIED); + return (-1); + } + + if (hit) { + *(p++) = 0; /* no certificate type */ + s2n(s->version, p); /* version */ + s2n(0, p); /* cert len */ + s2n(0, p); /* ciphers len */ + } else { + /* EAY EAY */ + /* put certificate type */ + *(p++) = SSL2_CT_X509_CERTIFICATE; + s2n(s->version, p); /* version */ + n = i2d_X509(s->cert->pkeys[SSL_PKEY_RSA_ENC].x509, NULL); + s2n(n, p); /* certificate length */ + i2d_X509(s->cert->pkeys[SSL_PKEY_RSA_ENC].x509, &d); + n = 0; + + /* + * lets send out the ciphers we like in the prefered order + */ + n = ssl_cipher_list_to_bytes(s, s->session->ciphers, d, 0); + d += n; + s2n(n, p); /* add cipher length */ + } + + /* make and send conn_id */ + s2n(SSL2_CONNECTION_ID_LENGTH, p); /* add conn_id length */ + s->s2->conn_id_length = SSL2_CONNECTION_ID_LENGTH; + if (RAND_pseudo_bytes(s->s2->conn_id, (int)s->s2->conn_id_length) <= + 0) + return -1; + memcpy(d, s->s2->conn_id, SSL2_CONNECTION_ID_LENGTH); + d += SSL2_CONNECTION_ID_LENGTH; + + s->state = SSL2_ST_SEND_SERVER_HELLO_B; + s->init_num = d - (unsigned char *)s->init_buf->data; + s->init_off = 0; + } + /* SSL2_ST_SEND_SERVER_HELLO_B */ + /* + * If we are using TCP/IP, the performance is bad if we do 2 writes + * without a read between them. This occurs when Session-id reuse is + * used, so I will put in a buffering module + */ + if (s->hit) { + if (!ssl_init_wbio_buffer(s, 1)) + return (-1); + } + + return (ssl2_do_write(s)); +} + +static int get_client_finished(SSL *s) +{ + unsigned char *p; + int i, n; + unsigned long len; + + p = (unsigned char *)s->init_buf->data; + if (s->state == SSL2_ST_GET_CLIENT_FINISHED_A) { + i = ssl2_read(s, (char *)&(p[s->init_num]), 1 - s->init_num); + if (i < 1 - s->init_num) + return (ssl2_part_read(s, SSL_F_GET_CLIENT_FINISHED, i)); + s->init_num += i; + + if (*p != SSL2_MT_CLIENT_FINISHED) { + if (*p != SSL2_MT_ERROR) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_GET_CLIENT_FINISHED, + SSL_R_READ_WRONG_PACKET_TYPE); + } else { + SSLerr(SSL_F_GET_CLIENT_FINISHED, SSL_R_PEER_ERROR); + /* try to read the error message */ + i = ssl2_read(s, (char *)&(p[s->init_num]), 3 - s->init_num); + return ssl2_part_read(s, SSL_F_GET_SERVER_VERIFY, i); + } + return (-1); + } + s->state = SSL2_ST_GET_CLIENT_FINISHED_B; + } + + /* SSL2_ST_GET_CLIENT_FINISHED_B */ + if (s->s2->conn_id_length > sizeof s->s2->conn_id) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_GET_CLIENT_FINISHED, ERR_R_INTERNAL_ERROR); + return -1; + } + len = 1 + (unsigned long)s->s2->conn_id_length; + n = (int)len - s->init_num; + i = ssl2_read(s, (char *)&(p[s->init_num]), n); + if (i < n) { + return (ssl2_part_read(s, SSL_F_GET_CLIENT_FINISHED, i)); + } + if (s->msg_callback) { + /* CLIENT-FINISHED */ + s->msg_callback(0, s->version, 0, p, len, s, s->msg_callback_arg); + } + p += 1; + if (memcmp(p, s->s2->conn_id, s->s2->conn_id_length) != 0) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_GET_CLIENT_FINISHED, SSL_R_CONNECTION_ID_IS_DIFFERENT); + return (-1); + } + return (1); +} + +static int server_verify(SSL *s) +{ + unsigned char *p; + + if (s->state == SSL2_ST_SEND_SERVER_VERIFY_A) { + p = (unsigned char *)s->init_buf->data; + *(p++) = SSL2_MT_SERVER_VERIFY; + if (s->s2->challenge_length > sizeof s->s2->challenge) { + SSLerr(SSL_F_SERVER_VERIFY, ERR_R_INTERNAL_ERROR); + return -1; + } + memcpy(p, s->s2->challenge, (unsigned int)s->s2->challenge_length); + /* p+=s->s2->challenge_length; */ + + s->state = SSL2_ST_SEND_SERVER_VERIFY_B; + s->init_num = s->s2->challenge_length + 1; + s->init_off = 0; + } + return (ssl2_do_write(s)); +} + +static int server_finish(SSL *s) +{ + unsigned char *p; + + if (s->state == SSL2_ST_SEND_SERVER_FINISHED_A) { + p = (unsigned char *)s->init_buf->data; + *(p++) = SSL2_MT_SERVER_FINISHED; + + if (s->session->session_id_length > sizeof s->session->session_id) { + SSLerr(SSL_F_SERVER_FINISH, ERR_R_INTERNAL_ERROR); + return -1; + } + memcpy(p, s->session->session_id, + (unsigned int)s->session->session_id_length); + /* p+=s->session->session_id_length; */ + + s->state = SSL2_ST_SEND_SERVER_FINISHED_B; + s->init_num = s->session->session_id_length + 1; + s->init_off = 0; + } + + /* SSL2_ST_SEND_SERVER_FINISHED_B */ + return (ssl2_do_write(s)); +} + +/* send the request and check the response */ +static int request_certificate(SSL *s) +{ + const unsigned char *cp; + unsigned char *p, *p2, *buf2; + unsigned char *ccd; + int i, j, ctype, ret = -1; + unsigned long len; + X509 *x509 = NULL; + STACK_OF(X509) *sk = NULL; + + ccd = s->s2->tmp.ccl; + if (s->state == SSL2_ST_SEND_REQUEST_CERTIFICATE_A) { + p = (unsigned char *)s->init_buf->data; + *(p++) = SSL2_MT_REQUEST_CERTIFICATE; + *(p++) = SSL2_AT_MD5_WITH_RSA_ENCRYPTION; + if (RAND_pseudo_bytes(ccd, SSL2_MIN_CERT_CHALLENGE_LENGTH) <= 0) + return -1; + memcpy(p, ccd, SSL2_MIN_CERT_CHALLENGE_LENGTH); + + s->state = SSL2_ST_SEND_REQUEST_CERTIFICATE_B; + s->init_num = SSL2_MIN_CERT_CHALLENGE_LENGTH + 2; + s->init_off = 0; + } + + if (s->state == SSL2_ST_SEND_REQUEST_CERTIFICATE_B) { + i = ssl2_do_write(s); + if (i <= 0) { + ret = i; + goto end; + } + + s->init_num = 0; + s->state = SSL2_ST_SEND_REQUEST_CERTIFICATE_C; + } + + if (s->state == SSL2_ST_SEND_REQUEST_CERTIFICATE_C) { + p = (unsigned char *)s->init_buf->data; + /* try to read 6 octets ... */ + i = ssl2_read(s, (char *)&(p[s->init_num]), 6 - s->init_num); + /* + * ... but don't call ssl2_part_read now if we got at least 3 + * (probably NO-CERTIFICATE-ERROR) + */ + if (i < 3 - s->init_num) { + ret = ssl2_part_read(s, SSL_F_REQUEST_CERTIFICATE, i); + goto end; + } + s->init_num += i; + + if ((s->init_num >= 3) && (p[0] == SSL2_MT_ERROR)) { + n2s(p, i); + if (i != SSL2_PE_NO_CERTIFICATE) { + /* + * not the error message we expected -- let ssl2_part_read + * handle it + */ + s->init_num -= 3; + ret = ssl2_part_read(s, SSL_F_REQUEST_CERTIFICATE, 3); + goto end; + } + + if (s->msg_callback) { + /* ERROR */ + s->msg_callback(0, s->version, 0, p, 3, s, + s->msg_callback_arg); + } + + /* + * this is the one place where we can recover from an SSL 2.0 + * error + */ + + if (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) { + ssl2_return_error(s, SSL2_PE_BAD_CERTIFICATE); + SSLerr(SSL_F_REQUEST_CERTIFICATE, + SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE); + goto end; + } + ret = 1; + goto end; + } + if ((*(p++) != SSL2_MT_CLIENT_CERTIFICATE) || (s->init_num < 6)) { + ssl2_return_error(s, SSL2_PE_UNDEFINED_ERROR); + SSLerr(SSL_F_REQUEST_CERTIFICATE, SSL_R_SHORT_READ); + goto end; + } + if (s->init_num != 6) { + SSLerr(SSL_F_REQUEST_CERTIFICATE, ERR_R_INTERNAL_ERROR); + goto end; + } + + /* ok we have a response */ + /* certificate type, there is only one right now. */ + ctype = *(p++); + if (ctype != SSL2_AT_MD5_WITH_RSA_ENCRYPTION) { + ssl2_return_error(s, SSL2_PE_UNSUPPORTED_CERTIFICATE_TYPE); + SSLerr(SSL_F_REQUEST_CERTIFICATE, SSL_R_BAD_RESPONSE_ARGUMENT); + goto end; + } + n2s(p, i); + s->s2->tmp.clen = i; + n2s(p, i); + s->s2->tmp.rlen = i; + s->state = SSL2_ST_SEND_REQUEST_CERTIFICATE_D; + } + + /* SSL2_ST_SEND_REQUEST_CERTIFICATE_D */ + p = (unsigned char *)s->init_buf->data; + len = 6 + (unsigned long)s->s2->tmp.clen + (unsigned long)s->s2->tmp.rlen; + if (len > SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER) { + SSLerr(SSL_F_REQUEST_CERTIFICATE, SSL_R_MESSAGE_TOO_LONG); + goto end; + } + j = (int)len - s->init_num; + i = ssl2_read(s, (char *)&(p[s->init_num]), j); + if (i < j) { + ret = ssl2_part_read(s, SSL_F_REQUEST_CERTIFICATE, i); + goto end; + } + if (s->msg_callback) { + /* CLIENT-CERTIFICATE */ + s->msg_callback(0, s->version, 0, p, len, s, s->msg_callback_arg); + } + p += 6; + + cp = p; + x509 = (X509 *)d2i_X509(NULL, &cp, (long)s->s2->tmp.clen); + if (x509 == NULL) { + SSLerr(SSL_F_REQUEST_CERTIFICATE, ERR_R_X509_LIB); + goto msg_end; + } + + if (((sk = sk_X509_new_null()) == NULL) || (!sk_X509_push(sk, x509))) { + SSLerr(SSL_F_REQUEST_CERTIFICATE, ERR_R_MALLOC_FAILURE); + goto msg_end; + } + + i = ssl_verify_cert_chain(s, sk); + + if (i > 0) { /* we like the packet, now check the chksum */ + EVP_MD_CTX ctx; + EVP_PKEY *pkey = NULL; + + EVP_MD_CTX_init(&ctx); + if (!EVP_VerifyInit_ex(&ctx, s->ctx->rsa_md5, NULL) + || !EVP_VerifyUpdate(&ctx, s->s2->key_material, + s->s2->key_material_length) + || !EVP_VerifyUpdate(&ctx, ccd, SSL2_MIN_CERT_CHALLENGE_LENGTH)) + goto msg_end; + + i = i2d_X509(s->cert->pkeys[SSL_PKEY_RSA_ENC].x509, NULL); + buf2 = OPENSSL_malloc((unsigned int)i); + if (buf2 == NULL) { + SSLerr(SSL_F_REQUEST_CERTIFICATE, ERR_R_MALLOC_FAILURE); + goto msg_end; + } + p2 = buf2; + i = i2d_X509(s->cert->pkeys[SSL_PKEY_RSA_ENC].x509, &p2); + if (!EVP_VerifyUpdate(&ctx, buf2, (unsigned int)i)) { + OPENSSL_free(buf2); + goto msg_end; + } + OPENSSL_free(buf2); + + pkey = X509_get_pubkey(x509); + if (pkey == NULL) + goto end; + i = EVP_VerifyFinal(&ctx, cp, s->s2->tmp.rlen, pkey); + EVP_PKEY_free(pkey); + EVP_MD_CTX_cleanup(&ctx); + + if (i > 0) { + if (s->session->peer != NULL) + X509_free(s->session->peer); + s->session->peer = x509; + CRYPTO_add(&x509->references, 1, CRYPTO_LOCK_X509); + s->session->verify_result = s->verify_result; + ret = 1; + goto end; + } else { + SSLerr(SSL_F_REQUEST_CERTIFICATE, SSL_R_BAD_CHECKSUM); + goto msg_end; + } + } else { + msg_end: + ssl2_return_error(s, SSL2_PE_BAD_CERTIFICATE); + } + end: + sk_X509_free(sk); + X509_free(x509); + return (ret); +} + +static int ssl_rsa_private_decrypt(CERT *c, int len, unsigned char *from, + unsigned char *to, int padding) +{ + RSA *rsa; + int i; + + if ((c == NULL) || (c->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL)) { + SSLerr(SSL_F_SSL_RSA_PRIVATE_DECRYPT, SSL_R_NO_PRIVATEKEY); + return (-1); + } + if (c->pkeys[SSL_PKEY_RSA_ENC].privatekey->type != EVP_PKEY_RSA) { + SSLerr(SSL_F_SSL_RSA_PRIVATE_DECRYPT, SSL_R_PUBLIC_KEY_IS_NOT_RSA); + return (-1); + } + rsa = c->pkeys[SSL_PKEY_RSA_ENC].privatekey->pkey.rsa; + + /* we have the public key */ + i = RSA_private_decrypt(len, from, to, rsa, padding); + if (i < 0) + SSLerr(SSL_F_SSL_RSA_PRIVATE_DECRYPT, ERR_R_RSA_LIB); + return (i); +} +#else /* !OPENSSL_NO_SSL2 */ + +# if PEDANTIC +static void *dummy = &dummy; +# endif + +#endif diff --git a/thirdparty/openssl/ssl/s3_both.c b/thirdparty/openssl/ssl/s3_both.c new file mode 100644 index 0000000000..09d0661e81 --- /dev/null +++ b/thirdparty/openssl/ssl/s3_both.c @@ -0,0 +1,747 @@ +/* ssl/s3_both.c */ +/* 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 <limits.h> +#include <string.h> +#include <stdio.h> +#include "ssl_locl.h" +#include <openssl/buffer.h> +#include <openssl/rand.h> +#include <openssl/objects.h> +#include <openssl/evp.h> +#include <openssl/x509.h> + +/* + * send s->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->init_buf->data[s->init_off], + s->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 + */ + ssl3_finish_mac(s, (unsigned char *)&s->init_buf->data[s->init_off], + ret); + + if (ret == s->init_num) { + if (s->msg_callback) + s->msg_callback(1, s->version, type, s->init_buf->data, + (size_t)(s->init_off + s->init_num), s, + s->msg_callback_arg); + return (1); + } + s->init_off += ret; + s->init_num -= ret; + return (0); +} + +int ssl3_send_finished(SSL *s, int a, int b, const char *sender, int slen) +{ + unsigned char *p; + int i; + unsigned long l; + + if (s->state == a) { + p = ssl_handshake_start(s); + + i = s->method->ssl3_enc->final_finish_mac(s, + sender, slen, + s->s3->tmp.finish_md); + if (i <= 0) + return 0; + s->s3->tmp.finish_md_len = i; + memcpy(p, s->s3->tmp.finish_md, i); + l = i; + + /* + * Copy the finished so we can use it for renegotiation checks + */ + if (s->type == SSL_ST_CONNECT) { + OPENSSL_assert(i <= EVP_MAX_MD_SIZE); + memcpy(s->s3->previous_client_finished, s->s3->tmp.finish_md, i); + s->s3->previous_client_finished_len = i; + } else { + OPENSSL_assert(i <= EVP_MAX_MD_SIZE); + memcpy(s->s3->previous_server_finished, s->s3->tmp.finish_md, i); + s->s3->previous_server_finished_len = i; + } + +#ifdef OPENSSL_SYS_WIN16 + /* + * MSVC 1.5 does not clear the top bytes of the word unless I do + * this. + */ + l &= 0xffff; +#endif + ssl_set_handshake_header(s, SSL3_MT_FINISHED, l); + s->state = b; + } + + /* SSL3_ST_SEND_xxxxxx_HELLO_B */ + return ssl_do_write(s); +} + +#ifndef OPENSSL_NO_NEXTPROTONEG +/* + * ssl3_take_mac calculates the Finished MAC for the handshakes messages seen + * to 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 (s->s3->tmp.new_cipher == NULL) + return; + if (s->state & SSL_ST_CONNECT) { + sender = s->method->ssl3_enc->server_finished_label; + slen = s->method->ssl3_enc->server_finished_label_len; + } else { + sender = s->method->ssl3_enc->client_finished_label; + slen = s->method->ssl3_enc->client_finished_label_len; + } + + s->s3->tmp.peer_finish_md_len = s->method->ssl3_enc->final_finish_mac(s, + sender, + slen, + s->s3->tmp.peer_finish_md); +} +#endif + +int ssl3_get_finished(SSL *s, int a, int b) +{ + int al, i, ok; + long n; + unsigned char *p; + +#ifdef OPENSSL_NO_NEXTPROTONEG + /* + * the mac has already been generated when we received the change cipher + * spec message and is in s->s3->tmp.peer_finish_md + */ +#endif + + /* 64 argument should actually be 36+4 :-) */ + n = s->method->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 (!s->s3->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; + } + s->s3->change_cipher_spec = 0; + + p = (unsigned char *)s->init_msg; + i = s->s3->tmp.peer_finish_md_len; + + if (i != n) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_FINISHED, SSL_R_BAD_DIGEST_LENGTH); + goto f_err; + } + + if (CRYPTO_memcmp(p, s->s3->tmp.peer_finish_md, i) != 0) { + al = SSL_AD_DECRYPT_ERROR; + SSLerr(SSL_F_SSL3_GET_FINISHED, SSL_R_DIGEST_CHECK_FAILED); + goto f_err; + } + + /* + * Copy the finished so we can use it for renegotiation checks + */ + if (s->type == SSL_ST_ACCEPT) { + OPENSSL_assert(i <= EVP_MAX_MD_SIZE); + memcpy(s->s3->previous_client_finished, s->s3->tmp.peer_finish_md, i); + s->s3->previous_client_finished_len = i; + } else { + OPENSSL_assert(i <= EVP_MAX_MD_SIZE); + memcpy(s->s3->previous_server_finished, s->s3->tmp.peer_finish_md, i); + s->s3->previous_server_finished_len = i; + } + + 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->read_sequence zero + * ssl->s3->read_mac_secret re-init + * ssl->session->read_sym_enc assign + * ssl->session->read_compression assign + * ssl->session->read_hash assign + */ +int ssl3_send_change_cipher_spec(SSL *s, int a, int b) +{ + unsigned char *p; + + if (s->state == a) { + p = (unsigned char *)s->init_buf->data; + *p = SSL3_MT_CCS; + s->init_num = 1; + s->init_off = 0; + + s->state = b; + } + + /* SSL3_ST_CW_CHANGE_B */ + return (ssl3_do_write(s, SSL3_RT_CHANGE_CIPHER_SPEC)); +} + +unsigned long ssl3_output_cert_chain(SSL *s, CERT_PKEY *cpk) +{ + unsigned char *p; + unsigned long l = 3 + SSL_HM_HEADER_LENGTH(s); + + if (!ssl_add_cert_chain(s, cpk, &l)) + return 0; + + l -= 3 + SSL_HM_HEADER_LENGTH(s); + p = ssl_handshake_start(s); + l2n3(l, p); + l += 3; + ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE, l); + return l + SSL_HM_HEADER_LENGTH(s); +} + +/* + * 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; + unsigned long l; + long n; + int i, al; + + if (s->s3->tmp.reuse_message) { + s->s3->tmp.reuse_message = 0; + if ((mt >= 0) && (s->s3->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->state = stn; + s->init_msg = s->init_buf->data + 4; + s->init_num = (int)s->s3->tmp.message_size; + return s->init_num; + } + + p = (unsigned char *)s->init_buf->data; + + if (s->state == st1) { /* s->init_num < 4 */ + int skip_message; + + do { + while (s->init_num < 4) { + i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, + &p[s->init_num], + 4 - s->init_num, 0); + if (i <= 0) { + s->rwstate = SSL_READING; + *ok = 0; + return i; + } + s->init_num += i; + } + + skip_message = 0; + if (!s->server) + if (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->init_num = 0; + skip_message = 1; + + if (s->msg_callback) + s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, + p, 4, s, s->msg_callback_arg); + } + } + while (skip_message); + + /* s->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; + } + + s->s3->tmp.message_type = *(p++); + + n2l3(p, l); + 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 > (INT_MAX - 4)) { /* BUF_MEM_grow takes an 'int' parameter */ + 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->init_buf, (int)l + 4)) { + SSLerr(SSL_F_SSL3_GET_MESSAGE, ERR_R_BUF_LIB); + goto err; + } + s->s3->tmp.message_size = l; + s->state = stn; + + s->init_msg = s->init_buf->data + 4; + s->init_num = 0; + } + + /* next state (stn) */ + p = s->init_msg; + n = s->s3->tmp.message_size - s->init_num; + while (n > 0) { + i = s->method->ssl_read_bytes(s, SSL3_RT_HANDSHAKE, &p[s->init_num], + n, 0); + if (i <= 0) { + s->rwstate = SSL_READING; + *ok = 0; + return i; + } + s->init_num += i; + n -= i; + } + +#ifndef OPENSSL_NO_NEXTPROTONEG + /* + * If receiving Finished, record MAC of prior handshake messages for + * Finished verification. + */ + if (*s->init_buf->data == SSL3_MT_FINISHED) + ssl3_take_mac(s); +#endif + + /* Feed this message into MAC computation. */ + ssl3_finish_mac(s, (unsigned char *)s->init_buf->data, s->init_num + 4); + if (s->msg_callback) + s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->init_buf->data, + (size_t)s->init_num + 4, s, s->msg_callback_arg); + *ok = 1; + return s->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; + } +#ifndef OPENSSL_NO_EC + else if (i == EVP_PKEY_EC) { + ret = SSL_PKEY_ECC; + } +#endif + else if (i == NID_id_GostR3410_94 || i == NID_id_GostR3410_94_cc) { + ret = SSL_PKEY_GOST94; + } else if (i == NID_id_GostR3410_2001 || i == NID_id_GostR3410_2001_cc) { + ret = SSL_PKEY_GOST01; + } else if (x && (i == EVP_PKEY_DH || i == EVP_PKEY_DHX)) { + /* + * For DH two cases: DH certificate signed with RSA and DH + * certificate signed with DSA. + */ + i = X509_certificate_type(x, pk); + if (i & EVP_PKS_RSA) + ret = SSL_PKEY_DH_RSA; + else if (i & EVP_PKS_DSA) + ret = SSL_PKEY_DH_DSA; + } + + 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); +} + +#ifndef OPENSSL_NO_BUF_FREELISTS +/*- + * On some platforms, malloc() performance is bad enough that you can't just + * free() and malloc() buffers all the time, so we need to use freelists from + * unused buffers. Currently, each freelist holds memory chunks of only a + * given size (list->chunklen); other sized chunks are freed and malloced. + * This doesn't help much if you're using many different SSL option settings + * with a given context. (The options affecting buffer size are + * max_send_fragment, read buffer vs write buffer, + * SSL_OP_MICROSOFT_BIG_WRITE_BUFFER, SSL_OP_NO_COMPRESSION, and + * SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS.) Using a separate freelist for every + * possible size is not an option, since max_send_fragment can take on many + * different values. + * + * If you are on a platform with a slow malloc(), and you're using SSL + * connections with many different settings for these options, and you need to + * use the SSL_MOD_RELEASE_BUFFERS feature, you have a few options: + * - Link against a faster malloc implementation. + * - Use a separate SSL_CTX for each option set. + * - Improve this code. + */ +static void *freelist_extract(SSL_CTX *ctx, int for_read, int sz) +{ + SSL3_BUF_FREELIST *list; + SSL3_BUF_FREELIST_ENTRY *ent = NULL; + void *result = NULL; + + CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); + list = for_read ? ctx->rbuf_freelist : ctx->wbuf_freelist; + if (list != NULL && sz == (int)list->chunklen) + ent = list->head; + if (ent != NULL) { + list->head = ent->next; + result = ent; + if (--list->len == 0) + list->chunklen = 0; + } + CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); + if (!result) + result = OPENSSL_malloc(sz); + return result; +} + +static void freelist_insert(SSL_CTX *ctx, int for_read, size_t sz, void *mem) +{ + SSL3_BUF_FREELIST *list; + SSL3_BUF_FREELIST_ENTRY *ent; + + CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); + list = for_read ? ctx->rbuf_freelist : ctx->wbuf_freelist; + if (list != NULL && + (sz == list->chunklen || list->chunklen == 0) && + list->len < ctx->freelist_max_len && sz >= sizeof(*ent)) { + list->chunklen = sz; + ent = mem; + ent->next = list->head; + list->head = ent; + ++list->len; + mem = NULL; + } + + CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); + if (mem) + OPENSSL_free(mem); +} +#else +# define freelist_extract(c,fr,sz) OPENSSL_malloc(sz) +# define freelist_insert(c,fr,sz,m) OPENSSL_free(m) +#endif + +int ssl3_setup_read_buffer(SSL *s) +{ + unsigned char *p; + size_t len, align = 0, headerlen; + + if (SSL_IS_DTLS(s)) + headerlen = DTLS1_RT_HEADER_LENGTH; + else + headerlen = SSL3_RT_HEADER_LENGTH; + +#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0 + align = (-SSL3_RT_HEADER_LENGTH) & (SSL3_ALIGN_PAYLOAD - 1); +#endif + + if (s->s3->rbuf.buf == NULL) { + len = SSL3_RT_MAX_PLAIN_LENGTH + + SSL3_RT_MAX_ENCRYPTED_OVERHEAD + headerlen + align; + if (s->options & SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER) { + s->s3->init_extra = 1; + len += SSL3_RT_MAX_EXTRA; + } +#ifndef OPENSSL_NO_COMP + if (!(s->options & SSL_OP_NO_COMPRESSION)) + len += SSL3_RT_MAX_COMPRESSED_OVERHEAD; +#endif + if ((p = freelist_extract(s->ctx, 1, len)) == NULL) + goto err; + s->s3->rbuf.buf = p; + s->s3->rbuf.len = len; + } + + s->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 = 0, headerlen; + + if (SSL_IS_DTLS(s)) + headerlen = DTLS1_RT_HEADER_LENGTH + 1; + else + headerlen = SSL3_RT_HEADER_LENGTH; + +#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0 + align = (-SSL3_RT_HEADER_LENGTH) & (SSL3_ALIGN_PAYLOAD - 1); +#endif + + if (s->s3->wbuf.buf == NULL) { + len = s->max_send_fragment + + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD + headerlen + align; +#ifndef OPENSSL_NO_COMP + if (!(s->options & SSL_OP_NO_COMPRESSION)) + len += SSL3_RT_MAX_COMPRESSED_OVERHEAD; +#endif + if (!(s->options & SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS)) + len += headerlen + align + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD; + + if ((p = freelist_extract(s->ctx, 0, 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) +{ + if (s->s3->wbuf.buf != NULL) { + freelist_insert(s->ctx, 0, s->s3->wbuf.len, s->s3->wbuf.buf); + s->s3->wbuf.buf = NULL; + } + return 1; +} + +int ssl3_release_read_buffer(SSL *s) +{ + if (s->s3->rbuf.buf != NULL) { + freelist_insert(s->ctx, 1, s->s3->rbuf.len, s->s3->rbuf.buf); + s->s3->rbuf.buf = NULL; + } + return 1; +} diff --git a/thirdparty/openssl/ssl/s3_cbc.c b/thirdparty/openssl/ssl/s3_cbc.c new file mode 100644 index 0000000000..557622f513 --- /dev/null +++ b/thirdparty/openssl/ssl/s3_cbc.c @@ -0,0 +1,820 @@ +/* ssl/s3_cbc.c */ +/* ==================================================================== + * Copyright (c) 2012 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 "../crypto/constant_time_locl.h" +#include "ssl_locl.h" + +#include <openssl/md5.h> +#include <openssl/sha.h> + +/* + * MAX_HASH_BIT_COUNT_BYTES is the maximum number of bytes in the hash's + * length field. (SHA-384/512 have 128-bit length.) + */ +#define MAX_HASH_BIT_COUNT_BYTES 16 + +/* + * MAX_HASH_BLOCK_SIZE is the maximum hash block size that we'll support. + * Currently SHA-384/512 has a 128-byte block size and that's the largest + * supported by TLS.) + */ +#define MAX_HASH_BLOCK_SIZE 128 + +/*- + * ssl3_cbc_remove_padding removes padding from the decrypted, SSLv3, CBC + * record in |rec| by updating |rec->length| in constant time. + * + * block_size: the block size of the cipher used to encrypt the record. + * returns: + * 0: (in non-constant time) if the record is publicly invalid. + * 1: if the padding was valid + * -1: otherwise. + */ +int ssl3_cbc_remove_padding(const SSL *s, + SSL3_RECORD *rec, + unsigned block_size, unsigned mac_size) +{ + unsigned padding_length, good; + const unsigned overhead = 1 /* padding length byte */ + mac_size; + + /* + * These lengths are all public so we can test them in non-constant time. + */ + if (overhead > rec->length) + return 0; + + padding_length = rec->data[rec->length - 1]; + good = constant_time_ge(rec->length, padding_length + overhead); + /* SSLv3 requires that the padding is minimal. */ + good &= constant_time_ge(block_size, padding_length + 1); + padding_length = good & (padding_length + 1); + rec->length -= padding_length; + rec->type |= padding_length << 8; /* kludge: pass padding length */ + return constant_time_select_int(good, 1, -1); +} + +/*- + * tls1_cbc_remove_padding removes the CBC padding from the decrypted, TLS, CBC + * record in |rec| in constant time and returns 1 if the padding is valid and + * -1 otherwise. It also removes any explicit IV from the start of the record + * without leaking any timing about whether there was enough space after the + * padding was removed. + * + * block_size: the block size of the cipher used to encrypt the record. + * returns: + * 0: (in non-constant time) if the record is publicly invalid. + * 1: if the padding was valid + * -1: otherwise. + */ +int tls1_cbc_remove_padding(const SSL *s, + SSL3_RECORD *rec, + unsigned block_size, unsigned mac_size) +{ + unsigned padding_length, good, to_check, i; + const unsigned overhead = 1 /* padding length byte */ + mac_size; + /* Check if version requires explicit IV */ + if (SSL_USE_EXPLICIT_IV(s)) { + /* + * These lengths are all public so we can test them in non-constant + * time. + */ + if (overhead + block_size > rec->length) + return 0; + /* We can now safely skip explicit IV */ + rec->data += block_size; + rec->input += block_size; + rec->length -= block_size; + } else if (overhead > rec->length) + return 0; + + padding_length = rec->data[rec->length - 1]; + + /* + * NB: if compression is in operation the first packet may not be of even + * length so the padding bug check cannot be performed. This bug + * workaround has been around since SSLeay so hopefully it is either + * fixed now or no buggy implementation supports compression [steve] + */ + if ((s->options & SSL_OP_TLS_BLOCK_PADDING_BUG) && !s->expand) { + /* First packet is even in size, so check */ + if ((CRYPTO_memcmp(s->s3->read_sequence, "\0\0\0\0\0\0\0\0", 8) == 0) && + !(padding_length & 1)) { + s->s3->flags |= TLS1_FLAGS_TLS_PADDING_BUG; + } + if ((s->s3->flags & TLS1_FLAGS_TLS_PADDING_BUG) && padding_length > 0) { + padding_length--; + } + } + + if (EVP_CIPHER_flags(s->enc_read_ctx->cipher) & EVP_CIPH_FLAG_AEAD_CIPHER) { + /* padding is already verified */ + rec->length -= padding_length + 1; + return 1; + } + + good = constant_time_ge(rec->length, overhead + padding_length); + /* + * The padding consists of a length byte at the end of the record and + * then that many bytes of padding, all with the same value as the length + * byte. Thus, with the length byte included, there are i+1 bytes of + * padding. We can't check just |padding_length+1| bytes because that + * leaks decrypted information. Therefore we always have to check the + * maximum amount of padding possible. (Again, the length of the record + * is public information so we can use it.) + */ + to_check = 255; /* maximum amount of padding. */ + if (to_check > rec->length - 1) + to_check = rec->length - 1; + + for (i = 0; i < to_check; i++) { + unsigned char mask = constant_time_ge_8(padding_length, i); + unsigned char b = rec->data[rec->length - 1 - i]; + /* + * The final |padding_length+1| bytes should all have the value + * |padding_length|. Therefore the XOR should be zero. + */ + good &= ~(mask & (padding_length ^ b)); + } + + /* + * If any of the final |padding_length+1| bytes had the wrong value, one + * or more of the lower eight bits of |good| will be cleared. + */ + good = constant_time_eq(0xff, good & 0xff); + padding_length = good & (padding_length + 1); + rec->length -= padding_length; + rec->type |= padding_length << 8; /* kludge: pass padding length */ + + return constant_time_select_int(good, 1, -1); +} + +/*- + * ssl3_cbc_copy_mac copies |md_size| bytes from the end of |rec| to |out| in + * constant time (independent of the concrete value of rec->length, which may + * vary within a 256-byte window). + * + * ssl3_cbc_remove_padding or tls1_cbc_remove_padding must be called prior to + * this function. + * + * On entry: + * rec->orig_len >= md_size + * md_size <= EVP_MAX_MD_SIZE + * + * If CBC_MAC_ROTATE_IN_PLACE is defined then the rotation is performed with + * variable accesses in a 64-byte-aligned buffer. Assuming that this fits into + * a single or pair of cache-lines, then the variable memory accesses don't + * actually affect the timing. CPUs with smaller cache-lines [if any] are + * not multi-core and are not considered vulnerable to cache-timing attacks. + */ +#define CBC_MAC_ROTATE_IN_PLACE + +void ssl3_cbc_copy_mac(unsigned char *out, + const SSL3_RECORD *rec, + unsigned md_size, unsigned orig_len) +{ +#if defined(CBC_MAC_ROTATE_IN_PLACE) + unsigned char rotated_mac_buf[64 + EVP_MAX_MD_SIZE]; + unsigned char *rotated_mac; +#else + unsigned char rotated_mac[EVP_MAX_MD_SIZE]; +#endif + + /* + * mac_end is the index of |rec->data| just after the end of the MAC. + */ + unsigned mac_end = rec->length; + unsigned mac_start = mac_end - md_size; + /* + * scan_start contains the number of bytes that we can ignore because the + * MAC's position can only vary by 255 bytes. + */ + unsigned scan_start = 0; + unsigned i, j; + unsigned div_spoiler; + unsigned rotate_offset; + + OPENSSL_assert(orig_len >= md_size); + OPENSSL_assert(md_size <= EVP_MAX_MD_SIZE); + +#if defined(CBC_MAC_ROTATE_IN_PLACE) + rotated_mac = rotated_mac_buf + ((0 - (size_t)rotated_mac_buf) & 63); +#endif + + /* This information is public so it's safe to branch based on it. */ + if (orig_len > md_size + 255 + 1) + scan_start = orig_len - (md_size + 255 + 1); + /* + * div_spoiler contains a multiple of md_size that is used to cause the + * modulo operation to be constant time. Without this, the time varies + * based on the amount of padding when running on Intel chips at least. + * The aim of right-shifting md_size is so that the compiler doesn't + * figure out that it can remove div_spoiler as that would require it to + * prove that md_size is always even, which I hope is beyond it. + */ + div_spoiler = md_size >> 1; + div_spoiler <<= (sizeof(div_spoiler) - 1) * 8; + rotate_offset = (div_spoiler + mac_start - scan_start) % md_size; + + memset(rotated_mac, 0, md_size); + for (i = scan_start, j = 0; i < orig_len; i++) { + unsigned char mac_started = constant_time_ge_8(i, mac_start); + unsigned char mac_ended = constant_time_ge_8(i, mac_end); + unsigned char b = rec->data[i]; + rotated_mac[j++] |= b & mac_started & ~mac_ended; + j &= constant_time_lt(j, md_size); + } + + /* Now rotate the MAC */ +#if defined(CBC_MAC_ROTATE_IN_PLACE) + j = 0; + for (i = 0; i < md_size; i++) { + /* in case cache-line is 32 bytes, touch second line */ + ((volatile unsigned char *)rotated_mac)[rotate_offset ^ 32]; + out[j++] = rotated_mac[rotate_offset++]; + rotate_offset &= constant_time_lt(rotate_offset, md_size); + } +#else + memset(out, 0, md_size); + rotate_offset = md_size - rotate_offset; + rotate_offset &= constant_time_lt(rotate_offset, md_size); + for (i = 0; i < md_size; i++) { + for (j = 0; j < md_size; j++) + out[j] |= rotated_mac[i] & constant_time_eq_8(j, rotate_offset); + rotate_offset++; + rotate_offset &= constant_time_lt(rotate_offset, md_size); + } +#endif +} + +/* + * u32toLE serialises an unsigned, 32-bit number (n) as four bytes at (p) in + * little-endian order. The value of p is advanced by four. + */ +#define u32toLE(n, p) \ + (*((p)++)=(unsigned char)(n), \ + *((p)++)=(unsigned char)(n>>8), \ + *((p)++)=(unsigned char)(n>>16), \ + *((p)++)=(unsigned char)(n>>24)) + +/* + * These functions serialize the state of a hash and thus perform the + * standard "final" operation without adding the padding and length that such + * a function typically does. + */ +static void tls1_md5_final_raw(void *ctx, unsigned char *md_out) +{ + MD5_CTX *md5 = ctx; + u32toLE(md5->A, md_out); + u32toLE(md5->B, md_out); + u32toLE(md5->C, md_out); + u32toLE(md5->D, md_out); +} + +static void tls1_sha1_final_raw(void *ctx, unsigned char *md_out) +{ + SHA_CTX *sha1 = ctx; + l2n(sha1->h0, md_out); + l2n(sha1->h1, md_out); + l2n(sha1->h2, md_out); + l2n(sha1->h3, md_out); + l2n(sha1->h4, md_out); +} + +#define LARGEST_DIGEST_CTX SHA_CTX + +#ifndef OPENSSL_NO_SHA256 +static void tls1_sha256_final_raw(void *ctx, unsigned char *md_out) +{ + SHA256_CTX *sha256 = ctx; + unsigned i; + + for (i = 0; i < 8; i++) { + l2n(sha256->h[i], md_out); + } +} + +# undef LARGEST_DIGEST_CTX +# define LARGEST_DIGEST_CTX SHA256_CTX +#endif + +#ifndef OPENSSL_NO_SHA512 +static void tls1_sha512_final_raw(void *ctx, unsigned char *md_out) +{ + SHA512_CTX *sha512 = ctx; + unsigned i; + + for (i = 0; i < 8; i++) { + l2n8(sha512->h[i], md_out); + } +} + +# undef LARGEST_DIGEST_CTX +# define LARGEST_DIGEST_CTX SHA512_CTX +#endif + +/* + * ssl3_cbc_record_digest_supported returns 1 iff |ctx| uses a hash function + * which ssl3_cbc_digest_record supports. + */ +char ssl3_cbc_record_digest_supported(const EVP_MD_CTX *ctx) +{ +#ifdef OPENSSL_FIPS + if (FIPS_mode()) + return 0; +#endif + switch (EVP_MD_CTX_type(ctx)) { + case NID_md5: + case NID_sha1: +#ifndef OPENSSL_NO_SHA256 + case NID_sha224: + case NID_sha256: +#endif +#ifndef OPENSSL_NO_SHA512 + case NID_sha384: + case NID_sha512: +#endif + return 1; + default: + return 0; + } +} + +/*- + * ssl3_cbc_digest_record computes the MAC of a decrypted, padded SSLv3/TLS + * record. + * + * ctx: the EVP_MD_CTX from which we take the hash function. + * ssl3_cbc_record_digest_supported must return true for this EVP_MD_CTX. + * md_out: the digest output. At most EVP_MAX_MD_SIZE bytes will be written. + * md_out_size: if non-NULL, the number of output bytes is written here. + * header: the 13-byte, TLS record header. + * data: the record data itself, less any preceeding explicit IV. + * data_plus_mac_size: the secret, reported length of the data and MAC + * once the padding has been removed. + * data_plus_mac_plus_padding_size: the public length of the whole + * record, including padding. + * is_sslv3: non-zero if we are to use SSLv3. Otherwise, TLS. + * + * On entry: by virtue of having been through one of the remove_padding + * functions, above, we know that data_plus_mac_size is large enough to contain + * a padding byte and MAC. (If the padding was invalid, it might contain the + * padding too. ) + * Returns 1 on success or 0 on error + */ +int ssl3_cbc_digest_record(const EVP_MD_CTX *ctx, + unsigned char *md_out, + size_t *md_out_size, + const unsigned char header[13], + const unsigned char *data, + size_t data_plus_mac_size, + size_t data_plus_mac_plus_padding_size, + const unsigned char *mac_secret, + unsigned mac_secret_length, char is_sslv3) +{ + union { + double align; + unsigned char c[sizeof(LARGEST_DIGEST_CTX)]; + } md_state; + void (*md_final_raw) (void *ctx, unsigned char *md_out); + void (*md_transform) (void *ctx, const unsigned char *block); + unsigned md_size, md_block_size = 64; + unsigned sslv3_pad_length = 40, header_length, variance_blocks, + len, max_mac_bytes, num_blocks, + num_starting_blocks, k, mac_end_offset, c, index_a, index_b; + unsigned int bits; /* at most 18 bits */ + unsigned char length_bytes[MAX_HASH_BIT_COUNT_BYTES]; + /* hmac_pad is the masked HMAC key. */ + unsigned char hmac_pad[MAX_HASH_BLOCK_SIZE]; + unsigned char first_block[MAX_HASH_BLOCK_SIZE]; + unsigned char mac_out[EVP_MAX_MD_SIZE]; + unsigned i, j, md_out_size_u; + EVP_MD_CTX md_ctx; + /* + * mdLengthSize is the number of bytes in the length field that + * terminates * the hash. + */ + unsigned md_length_size = 8; + char length_is_big_endian = 1; + + /* + * This is a, hopefully redundant, check that allows us to forget about + * many possible overflows later in this function. + */ + OPENSSL_assert(data_plus_mac_plus_padding_size < 1024 * 1024); + + switch (EVP_MD_CTX_type(ctx)) { + case NID_md5: + if (MD5_Init((MD5_CTX *)md_state.c) <= 0) + return 0; + md_final_raw = tls1_md5_final_raw; + md_transform = + (void (*)(void *ctx, const unsigned char *block))MD5_Transform; + md_size = 16; + sslv3_pad_length = 48; + length_is_big_endian = 0; + break; + case NID_sha1: + if (SHA1_Init((SHA_CTX *)md_state.c) <= 0) + return 0; + md_final_raw = tls1_sha1_final_raw; + md_transform = + (void (*)(void *ctx, const unsigned char *block))SHA1_Transform; + md_size = 20; + break; +#ifndef OPENSSL_NO_SHA256 + case NID_sha224: + if (SHA224_Init((SHA256_CTX *)md_state.c) <= 0) + return 0; + md_final_raw = tls1_sha256_final_raw; + md_transform = + (void (*)(void *ctx, const unsigned char *block))SHA256_Transform; + md_size = 224 / 8; + break; + case NID_sha256: + if (SHA256_Init((SHA256_CTX *)md_state.c) <= 0) + return 0; + md_final_raw = tls1_sha256_final_raw; + md_transform = + (void (*)(void *ctx, const unsigned char *block))SHA256_Transform; + md_size = 32; + break; +#endif +#ifndef OPENSSL_NO_SHA512 + case NID_sha384: + if (SHA384_Init((SHA512_CTX *)md_state.c) <= 0) + return 0; + md_final_raw = tls1_sha512_final_raw; + md_transform = + (void (*)(void *ctx, const unsigned char *block))SHA512_Transform; + md_size = 384 / 8; + md_block_size = 128; + md_length_size = 16; + break; + case NID_sha512: + if (SHA512_Init((SHA512_CTX *)md_state.c) <= 0) + return 0; + md_final_raw = tls1_sha512_final_raw; + md_transform = + (void (*)(void *ctx, const unsigned char *block))SHA512_Transform; + md_size = 64; + md_block_size = 128; + md_length_size = 16; + break; +#endif + default: + /* + * ssl3_cbc_record_digest_supported should have been called first to + * check that the hash function is supported. + */ + OPENSSL_assert(0); + if (md_out_size) + *md_out_size = 0; + return 0; + } + + OPENSSL_assert(md_length_size <= MAX_HASH_BIT_COUNT_BYTES); + OPENSSL_assert(md_block_size <= MAX_HASH_BLOCK_SIZE); + OPENSSL_assert(md_size <= EVP_MAX_MD_SIZE); + + header_length = 13; + if (is_sslv3) { + header_length = mac_secret_length + sslv3_pad_length + 8 /* sequence + * number */ + + 1 /* record type */ + + 2 /* record length */ ; + } + + /* + * variance_blocks is the number of blocks of the hash that we have to + * calculate in constant time because they could be altered by the + * padding value. In SSLv3, the padding must be minimal so the end of + * the plaintext varies by, at most, 15+20 = 35 bytes. (We conservatively + * assume that the MAC size varies from 0..20 bytes.) In case the 9 bytes + * of hash termination (0x80 + 64-bit length) don't fit in the final + * block, we say that the final two blocks can vary based on the padding. + * TLSv1 has MACs up to 48 bytes long (SHA-384) and the padding is not + * required to be minimal. Therefore we say that the final six blocks can + * vary based on the padding. Later in the function, if the message is + * short and there obviously cannot be this many blocks then + * variance_blocks can be reduced. + */ + variance_blocks = is_sslv3 ? 2 : 6; + /* + * From now on we're dealing with the MAC, which conceptually has 13 + * bytes of `header' before the start of the data (TLS) or 71/75 bytes + * (SSLv3) + */ + len = data_plus_mac_plus_padding_size + header_length; + /* + * max_mac_bytes contains the maximum bytes of bytes in the MAC, + * including * |header|, assuming that there's no padding. + */ + max_mac_bytes = len - md_size - 1; + /* num_blocks is the maximum number of hash blocks. */ + num_blocks = + (max_mac_bytes + 1 + md_length_size + md_block_size - + 1) / md_block_size; + /* + * In order to calculate the MAC in constant time we have to handle the + * final blocks specially because the padding value could cause the end + * to appear somewhere in the final |variance_blocks| blocks and we can't + * leak where. However, |num_starting_blocks| worth of data can be hashed + * right away because no padding value can affect whether they are + * plaintext. + */ + num_starting_blocks = 0; + /* + * k is the starting byte offset into the conceptual header||data where + * we start processing. + */ + k = 0; + /* + * mac_end_offset is the index just past the end of the data to be MACed. + */ + mac_end_offset = data_plus_mac_size + header_length - md_size; + /* + * c is the index of the 0x80 byte in the final hash block that contains + * application data. + */ + c = mac_end_offset % md_block_size; + /* + * index_a is the hash block number that contains the 0x80 terminating + * value. + */ + index_a = mac_end_offset / md_block_size; + /* + * index_b is the hash block number that contains the 64-bit hash length, + * in bits. + */ + index_b = (mac_end_offset + md_length_size) / md_block_size; + /* + * bits is the hash-length in bits. It includes the additional hash block + * for the masked HMAC key, or whole of |header| in the case of SSLv3. + */ + + /* + * For SSLv3, if we're going to have any starting blocks then we need at + * least two because the header is larger than a single block. + */ + if (num_blocks > variance_blocks + (is_sslv3 ? 1 : 0)) { + num_starting_blocks = num_blocks - variance_blocks; + k = md_block_size * num_starting_blocks; + } + + bits = 8 * mac_end_offset; + if (!is_sslv3) { + /* + * Compute the initial HMAC block. For SSLv3, the padding and secret + * bytes are included in |header| because they take more than a + * single block. + */ + bits += 8 * md_block_size; + memset(hmac_pad, 0, md_block_size); + OPENSSL_assert(mac_secret_length <= sizeof(hmac_pad)); + memcpy(hmac_pad, mac_secret, mac_secret_length); + for (i = 0; i < md_block_size; i++) + hmac_pad[i] ^= 0x36; + + md_transform(md_state.c, hmac_pad); + } + + if (length_is_big_endian) { + memset(length_bytes, 0, md_length_size - 4); + length_bytes[md_length_size - 4] = (unsigned char)(bits >> 24); + length_bytes[md_length_size - 3] = (unsigned char)(bits >> 16); + length_bytes[md_length_size - 2] = (unsigned char)(bits >> 8); + length_bytes[md_length_size - 1] = (unsigned char)bits; + } else { + memset(length_bytes, 0, md_length_size); + length_bytes[md_length_size - 5] = (unsigned char)(bits >> 24); + length_bytes[md_length_size - 6] = (unsigned char)(bits >> 16); + length_bytes[md_length_size - 7] = (unsigned char)(bits >> 8); + length_bytes[md_length_size - 8] = (unsigned char)bits; + } + + if (k > 0) { + if (is_sslv3) { + unsigned overhang; + + /* + * The SSLv3 header is larger than a single block. overhang is + * the number of bytes beyond a single block that the header + * consumes: either 7 bytes (SHA1) or 11 bytes (MD5). There are no + * ciphersuites in SSLv3 that are not SHA1 or MD5 based and + * therefore we can be confident that the header_length will be + * greater than |md_block_size|. However we add a sanity check just + * in case + */ + if (header_length <= md_block_size) { + /* Should never happen */ + return 0; + } + overhang = header_length - md_block_size; + md_transform(md_state.c, header); + memcpy(first_block, header + md_block_size, overhang); + memcpy(first_block + overhang, data, md_block_size - overhang); + md_transform(md_state.c, first_block); + for (i = 1; i < k / md_block_size - 1; i++) + md_transform(md_state.c, data + md_block_size * i - overhang); + } else { + /* k is a multiple of md_block_size. */ + memcpy(first_block, header, 13); + memcpy(first_block + 13, data, md_block_size - 13); + md_transform(md_state.c, first_block); + for (i = 1; i < k / md_block_size; i++) + md_transform(md_state.c, data + md_block_size * i - 13); + } + } + + memset(mac_out, 0, sizeof(mac_out)); + + /* + * We now process the final hash blocks. For each block, we construct it + * in constant time. If the |i==index_a| then we'll include the 0x80 + * bytes and zero pad etc. For each block we selectively copy it, in + * constant time, to |mac_out|. + */ + for (i = num_starting_blocks; i <= num_starting_blocks + variance_blocks; + i++) { + unsigned char block[MAX_HASH_BLOCK_SIZE]; + unsigned char is_block_a = constant_time_eq_8(i, index_a); + unsigned char is_block_b = constant_time_eq_8(i, index_b); + for (j = 0; j < md_block_size; j++) { + unsigned char b = 0, is_past_c, is_past_cp1; + if (k < header_length) + b = header[k]; + else if (k < data_plus_mac_plus_padding_size + header_length) + b = data[k - header_length]; + k++; + + is_past_c = is_block_a & constant_time_ge_8(j, c); + is_past_cp1 = is_block_a & constant_time_ge_8(j, c + 1); + /* + * If this is the block containing the end of the application + * data, and we are at the offset for the 0x80 value, then + * overwrite b with 0x80. + */ + b = constant_time_select_8(is_past_c, 0x80, b); + /* + * If this the the block containing the end of the application + * data and we're past the 0x80 value then just write zero. + */ + b = b & ~is_past_cp1; + /* + * If this is index_b (the final block), but not index_a (the end + * of the data), then the 64-bit length didn't fit into index_a + * and we're having to add an extra block of zeros. + */ + b &= ~is_block_b | is_block_a; + + /* + * The final bytes of one of the blocks contains the length. + */ + if (j >= md_block_size - md_length_size) { + /* If this is index_b, write a length byte. */ + b = constant_time_select_8(is_block_b, + length_bytes[j - + (md_block_size - + md_length_size)], b); + } + block[j] = b; + } + + md_transform(md_state.c, block); + md_final_raw(md_state.c, block); + /* If this is index_b, copy the hash value to |mac_out|. */ + for (j = 0; j < md_size; j++) + mac_out[j] |= block[j] & is_block_b; + } + + EVP_MD_CTX_init(&md_ctx); + if (EVP_DigestInit_ex(&md_ctx, ctx->digest, NULL /* engine */ ) <= 0) + goto err; + if (is_sslv3) { + /* We repurpose |hmac_pad| to contain the SSLv3 pad2 block. */ + memset(hmac_pad, 0x5c, sslv3_pad_length); + + if (EVP_DigestUpdate(&md_ctx, mac_secret, mac_secret_length) <= 0 + || EVP_DigestUpdate(&md_ctx, hmac_pad, sslv3_pad_length) <= 0 + || EVP_DigestUpdate(&md_ctx, mac_out, md_size) <= 0) + goto err; + } else { + /* Complete the HMAC in the standard manner. */ + for (i = 0; i < md_block_size; i++) + hmac_pad[i] ^= 0x6a; + + if (EVP_DigestUpdate(&md_ctx, hmac_pad, md_block_size) <= 0 + || EVP_DigestUpdate(&md_ctx, mac_out, md_size) <= 0) + goto err; + } + EVP_DigestFinal(&md_ctx, md_out, &md_out_size_u); + if (md_out_size) + *md_out_size = md_out_size_u; + EVP_MD_CTX_cleanup(&md_ctx); + + return 1; +err: + EVP_MD_CTX_cleanup(&md_ctx); + return 0; +} + +#ifdef OPENSSL_FIPS + +/* + * Due to the need to use EVP in FIPS mode we can't reimplement digests but + * we can ensure the number of blocks processed is equal for all cases by + * digesting additional data. + */ + +void tls_fips_digest_extra(const EVP_CIPHER_CTX *cipher_ctx, + EVP_MD_CTX *mac_ctx, const unsigned char *data, + size_t data_len, size_t orig_len) +{ + size_t block_size, digest_pad, blocks_data, blocks_orig; + if (EVP_CIPHER_CTX_mode(cipher_ctx) != EVP_CIPH_CBC_MODE) + return; + block_size = EVP_MD_CTX_block_size(mac_ctx); + /*- + * We are in FIPS mode if we get this far so we know we have only SHA* + * digests and TLS to deal with. + * Minimum digest padding length is 17 for SHA384/SHA512 and 9 + * otherwise. + * Additional header is 13 bytes. To get the number of digest blocks + * processed round up the amount of data plus padding to the nearest + * block length. Block length is 128 for SHA384/SHA512 and 64 otherwise. + * So we have: + * blocks = (payload_len + digest_pad + 13 + block_size - 1)/block_size + * equivalently: + * blocks = (payload_len + digest_pad + 12)/block_size + 1 + * HMAC adds a constant overhead. + * We're ultimately only interested in differences so this becomes + * blocks = (payload_len + 29)/128 + * for SHA384/SHA512 and + * blocks = (payload_len + 21)/64 + * otherwise. + */ + digest_pad = block_size == 64 ? 21 : 29; + blocks_orig = (orig_len + digest_pad) / block_size; + blocks_data = (data_len + digest_pad) / block_size; + /* + * MAC enough blocks to make up the difference between the original and + * actual lengths plus one extra block to ensure this is never a no op. + * The "data" pointer should always have enough space to perform this + * operation as it is large enough for a maximum length TLS buffer. + */ + EVP_DigestSignUpdate(mac_ctx, data, + (blocks_orig - blocks_data + 1) * block_size); +} +#endif diff --git a/thirdparty/openssl/ssl/s3_clnt.c b/thirdparty/openssl/ssl/s3_clnt.c new file mode 100644 index 0000000000..19dc8648b9 --- /dev/null +++ b/thirdparty/openssl/ssl/s3_clnt.c @@ -0,0 +1,3763 @@ +/* ssl/s3_clnt.c */ +/* 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 <stdio.h> +#include "ssl_locl.h" +#include "kssl_lcl.h" +#include <openssl/buffer.h> +#include <openssl/rand.h> +#include <openssl/objects.h> +#include <openssl/evp.h> +#include <openssl/md5.h> +#ifdef OPENSSL_FIPS +# include <openssl/fips.h> +#endif +#ifndef OPENSSL_NO_DH +# include <openssl/dh.h> +#endif +#include <openssl/bn.h> +#ifndef OPENSSL_NO_ENGINE +# include <openssl/engine.h> +#endif + +static int ca_dn_cmp(const X509_NAME *const *a, const X509_NAME *const *b); +#ifndef OPENSSL_NO_TLSEXT +static int ssl3_check_finished(SSL *s); +#endif + +#ifndef OPENSSL_NO_SSL3_METHOD +static const SSL_METHOD *ssl3_get_client_method(int ver) +{ + if (ver == SSL3_VERSION) + return (SSLv3_client_method()); + else + return (NULL); +} + +IMPLEMENT_ssl3_meth_func(SSLv3_client_method, + ssl_undefined_function, + ssl3_connect, ssl3_get_client_method) +#endif +int ssl3_connect(SSL *s) +{ + BUF_MEM *buf = NULL; + unsigned long Time = (unsigned long)time(NULL); + void (*cb) (const SSL *ssl, int type, int val) = NULL; + int ret = -1; + int new_state, state, skip = 0; + + RAND_add(&Time, sizeof(Time), 0); + ERR_clear_error(); + clear_sys_error(); + + if (s->info_callback != NULL) + cb = s->info_callback; + else if (s->ctx->info_callback != NULL) + cb = s->ctx->info_callback; + + s->in_handshake++; + if (!SSL_in_init(s) || SSL_in_before(s)) + SSL_clear(s); + +#ifndef OPENSSL_NO_HEARTBEATS + /* + * If we're awaiting a HeartbeatResponse, pretend we already got and + * don't await it anymore, because Heartbeats don't make sense during + * handshakes anyway. + */ + if (s->tlsext_hb_pending) { + s->tlsext_hb_pending = 0; + s->tlsext_hb_seq++; + } +#endif + + for (;;) { + state = s->state; + + switch (s->state) { + case SSL_ST_RENEGOTIATE: + s->renegotiate = 1; + s->state = SSL_ST_CONNECT; + s->ctx->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); + s->state = SSL_ST_ERR; + ret = -1; + goto end; + } + + /* s->version=SSL3_VERSION; */ + s->type = SSL_ST_CONNECT; + + if (s->init_buf == NULL) { + if ((buf = BUF_MEM_new()) == NULL) { + ret = -1; + s->state = SSL_ST_ERR; + goto end; + } + if (!BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) { + ret = -1; + s->state = SSL_ST_ERR; + goto end; + } + s->init_buf = buf; + buf = NULL; + } + + if (!ssl3_setup_buffers(s)) { + ret = -1; + goto end; + } + + /* setup buffing BIO */ + if (!ssl_init_wbio_buffer(s, 0)) { + ret = -1; + s->state = SSL_ST_ERR; + goto end; + } + + /* don't push the buffering BIO quite yet */ + + ssl3_init_finished_mac(s); + + s->state = SSL3_ST_CW_CLNT_HELLO_A; + s->ctx->stats.sess_connect++; + s->init_num = 0; + s->s3->flags &= ~SSL3_FLAGS_CCS_OK; + /* + * Should have been reset by ssl3_get_finished, too. + */ + s->s3->change_cipher_spec = 0; + break; + + case SSL3_ST_CW_CLNT_HELLO_A: + case SSL3_ST_CW_CLNT_HELLO_B: + + s->shutdown = 0; + ret = ssl3_client_hello(s); + if (ret <= 0) + goto end; + s->state = SSL3_ST_CR_SRVR_HELLO_A; + s->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->hit) { + s->state = SSL3_ST_CR_FINISHED_A; +#ifndef OPENSSL_NO_TLSEXT + if (s->tlsext_ticket_expected) { + /* receive renewed session ticket */ + s->state = SSL3_ST_CR_SESSION_TICKET_A; + } +#endif + } else { + s->state = SSL3_ST_CR_CERT_A; + } + s->init_num = 0; + break; + case SSL3_ST_CR_CERT_A: + case SSL3_ST_CR_CERT_B: +#ifndef OPENSSL_NO_TLSEXT + /* Noop (ret = 0) for everything but EAP-FAST. */ + ret = ssl3_check_finished(s); + if (ret < 0) + goto end; + if (ret == 1) { + s->hit = 1; + s->state = SSL3_ST_CR_FINISHED_A; + s->init_num = 0; + break; + } +#endif + /* Check if it is anon DH/ECDH, SRP auth */ + /* or PSK */ + if (! + (s->s3->tmp. + new_cipher->algorithm_auth & (SSL_aNULL | SSL_aSRP)) + && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) { + ret = ssl3_get_server_certificate(s); + if (ret <= 0) + goto end; +#ifndef OPENSSL_NO_TLSEXT + if (s->tlsext_status_expected) + s->state = SSL3_ST_CR_CERT_STATUS_A; + else + s->state = SSL3_ST_CR_KEY_EXCH_A; + } else { + skip = 1; + s->state = SSL3_ST_CR_KEY_EXCH_A; + } +#else + } else + skip = 1; + + s->state = SSL3_ST_CR_KEY_EXCH_A; +#endif + s->init_num = 0; + break; + + case SSL3_ST_CR_KEY_EXCH_A: + case SSL3_ST_CR_KEY_EXCH_B: + ret = ssl3_get_key_exchange(s); + if (ret <= 0) + goto end; + s->state = SSL3_ST_CR_CERT_REQ_A; + s->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; + s->state = SSL_ST_ERR; + 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->state = SSL3_ST_CR_SRVR_DONE_A; + s->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; +#ifndef OPENSSL_NO_SRP + if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP) { + if ((ret = SRP_Calc_A_param(s)) <= 0) { + SSLerr(SSL_F_SSL3_CONNECT, SSL_R_SRP_A_CALC); + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + s->state = SSL_ST_ERR; + goto end; + } + } +#endif + if (s->s3->tmp.cert_req) + s->state = SSL3_ST_CW_CERT_A; + else + s->state = SSL3_ST_CW_KEY_EXCH_A; + s->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->state = SSL3_ST_CW_KEY_EXCH_A; + s->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 (s->s3->tmp.cert_req == 1) { + s->state = SSL3_ST_CW_CERT_VRFY_A; + } else { + s->state = SSL3_ST_CW_CHANGE_A; + } + if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY) { + s->state = SSL3_ST_CW_CHANGE_A; + } + + s->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->state = SSL3_ST_CW_CHANGE_A; + s->init_num = 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 defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG) + s->state = SSL3_ST_CW_FINISHED_A; +#else + if (s->s3->next_proto_neg_seen) + s->state = SSL3_ST_CW_NEXT_PROTO_A; + else + s->state = SSL3_ST_CW_FINISHED_A; +#endif + s->init_num = 0; + + s->session->cipher = s->s3->tmp.new_cipher; +#ifdef OPENSSL_NO_COMP + s->session->compress_meth = 0; +#else + if (s->s3->tmp.new_compression == NULL) + s->session->compress_meth = 0; + else + s->session->compress_meth = s->s3->tmp.new_compression->id; +#endif + if (!s->method->ssl3_enc->setup_key_block(s)) { + ret = -1; + s->state = SSL_ST_ERR; + goto end; + } + + if (!s->method->ssl3_enc->change_cipher_state(s, + SSL3_CHANGE_CIPHER_CLIENT_WRITE)) + { + ret = -1; + s->state = SSL_ST_ERR; + goto end; + } + + break; + +#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) + 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->state = SSL3_ST_CW_FINISHED_A; + break; +#endif + + 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-> + ssl3_enc->client_finished_label, + s->method-> + ssl3_enc->client_finished_label_len); + if (ret <= 0) + goto end; + s->state = SSL3_ST_CW_FLUSH; + + /* clear flags */ + s->s3->flags &= ~SSL3_FLAGS_POP_BUFFER; + if (s->hit) { + s->s3->tmp.next_state = SSL_ST_OK; + if (s->s3->flags & SSL3_FLAGS_DELAY_CLIENT_FINISHED) { + s->state = SSL_ST_OK; + s->s3->flags |= SSL3_FLAGS_POP_BUFFER; + s->s3->delay_buf_pop_ret = 0; + } + } else { +#ifndef OPENSSL_NO_TLSEXT + /* + * Allow NewSessionTicket if ticket expected + */ + if (s->tlsext_ticket_expected) + s->s3->tmp.next_state = SSL3_ST_CR_SESSION_TICKET_A; + else +#endif + + s->s3->tmp.next_state = SSL3_ST_CR_FINISHED_A; + } + s->init_num = 0; + break; + +#ifndef OPENSSL_NO_TLSEXT + 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->state = SSL3_ST_CR_FINISHED_A; + s->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->state = SSL3_ST_CR_KEY_EXCH_A; + s->init_num = 0; + break; +#endif + + case SSL3_ST_CR_FINISHED_A: + case SSL3_ST_CR_FINISHED_B: + if (!s->s3->change_cipher_spec) + 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->hit) + s->state = SSL3_ST_CW_CHANGE_A; + else + s->state = SSL_ST_OK; + s->init_num = 0; + break; + + case SSL3_ST_CW_FLUSH: + s->rwstate = SSL_WRITING; + if (BIO_flush(s->wbio) <= 0) { + ret = -1; + goto end; + } + s->rwstate = SSL_NOTHING; + s->state = s->s3->tmp.next_state; + break; + + case SSL_ST_OK: + /* clean a few things up */ + ssl3_cleanup_key_block(s); + + if (s->init_buf != NULL) { + BUF_MEM_free(s->init_buf); + s->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->init_num = 0; + s->renegotiate = 0; + s->new_session = 0; + + ssl_update_cache(s, SSL_SESS_CACHE_CLIENT); + if (s->hit) + s->ctx->stats.sess_hit++; + + ret = 1; + /* s->server=0; */ + s->handshake_func = ssl3_connect; + s->ctx->stats.sess_connect_good++; + + if (cb != NULL) + cb(s, SSL_CB_HANDSHAKE_DONE, 1); + + goto end; + /* break; */ + + case SSL_ST_ERR: + default: + SSLerr(SSL_F_SSL3_CONNECT, SSL_R_UNKNOWN_STATE); + ret = -1; + goto end; + /* break; */ + } + + /* did we do anything */ + if (!s->s3->tmp.reuse_message && !skip) { + if (s->debug) { + if ((ret = BIO_flush(s->wbio)) <= 0) + goto end; + } + + if ((cb != NULL) && (s->state != state)) { + new_state = s->state; + s->state = state; + cb(s, SSL_CB_CONNECT_LOOP, 1); + s->state = new_state; + } + } + skip = 0; + } + end: + s->in_handshake--; + if (buf != NULL) + BUF_MEM_free(buf); + if (cb != NULL) + cb(s, SSL_CB_CONNECT_EXIT, ret); + return (ret); +} + +int ssl3_client_hello(SSL *s) +{ + unsigned char *buf; + unsigned char *p, *d; + int i; + unsigned long l; + int al = 0; +#ifndef OPENSSL_NO_COMP + int j; + SSL_COMP *comp; +#endif + + buf = (unsigned char *)s->init_buf->data; + if (s->state == SSL3_ST_CW_CLNT_HELLO_A) { + SSL_SESSION *sess = s->session; + if ((sess == NULL) || (sess->ssl_version != s->version) || +#ifdef OPENSSL_NO_TLSEXT + !sess->session_id_length || +#else + /* + * In the case of EAP-FAST, we can have a pre-shared + * "ticket" without a session ID. + */ + (!sess->session_id_length && !sess->tlsext_tick) || +#endif + (sess->not_resumable)) { + if (!ssl_get_new_session(s, 0)) + goto err; + } + if (s->method->version == DTLS_ANY_VERSION) { + /* Determine which DTLS version to use */ + int options = s->options; + /* If DTLS 1.2 disabled correct the version number */ + if (options & SSL_OP_NO_DTLSv1_2) { + if (tls1_suiteb(s)) { + SSLerr(SSL_F_SSL3_CLIENT_HELLO, + SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE); + goto err; + } + /* + * Disabling all versions is silly: return an error. + */ + if (options & SSL_OP_NO_DTLSv1) { + SSLerr(SSL_F_SSL3_CLIENT_HELLO, SSL_R_WRONG_SSL_VERSION); + goto err; + } + /* + * Update method so we don't use any DTLS 1.2 features. + */ + s->method = DTLSv1_client_method(); + s->version = DTLS1_VERSION; + } else { + /* + * We only support one version: update method + */ + if (options & SSL_OP_NO_DTLSv1) + s->method = DTLSv1_2_client_method(); + s->version = DTLS1_2_VERSION; + } + s->client_version = s->version; + } + /* else use the pre-loaded session */ + + p = s->s3->client_random; + + /* + * for DTLS if client_random is initialized, reuse it, we are + * required to use same upon reply to HelloVerify + */ + if (SSL_IS_DTLS(s)) { + size_t idx; + i = 1; + for (idx = 0; idx < sizeof(s->s3->client_random); idx++) { + if (p[idx]) { + i = 0; + break; + } + } + } else + i = 1; + + if (i && ssl_fill_hello_random(s, 0, p, + sizeof(s->s3->client_random)) <= 0) + goto err; + + /* Do the message type and length last */ + d = p = ssl_handshake_start(s); + + /*- + * 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. + */ +#if 0 + *(p++) = s->version >> 8; + *(p++) = s->version & 0xff; + s->client_version = s->version; +#else + *(p++) = s->client_version >> 8; + *(p++) = s->client_version & 0xff; +#endif + + /* Random stuff */ + memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE); + p += SSL3_RANDOM_SIZE; + + /* Session ID */ + if (s->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; + } + + /* cookie stuff for DTLS */ + if (SSL_IS_DTLS(s)) { + if (s->d1->cookie_len > sizeof(s->d1->cookie)) { + SSLerr(SSL_F_SSL3_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); + goto err; + } + *(p++) = s->d1->cookie_len; + memcpy(p, s->d1->cookie, s->d1->cookie_len); + p += s->d1->cookie_len; + } + + /* Ciphers supported */ + i = ssl_cipher_list_to_bytes(s, SSL_get_ciphers(s), &(p[2]), 0); + if (i == 0) { + SSLerr(SSL_F_SSL3_CLIENT_HELLO, SSL_R_NO_CIPHERS_AVAILABLE); + goto err; + } +#ifdef OPENSSL_MAX_TLS1_2_CIPHER_LENGTH + /* + * Some servers hang if client hello > 256 bytes as hack workaround + * chop number of supported ciphers to keep it well below this if we + * use TLS v1.2 + */ + if (TLS1_get_version(s) >= TLS1_2_VERSION + && i > OPENSSL_MAX_TLS1_2_CIPHER_LENGTH) + i = OPENSSL_MAX_TLS1_2_CIPHER_LENGTH & ~1; +#endif + s2n(i, p); + p += i; + + /* COMPRESSION */ +#ifdef OPENSSL_NO_COMP + *(p++) = 1; +#else + + if ((s->options & SSL_OP_NO_COMPRESSION) + || !s->ctx->comp_methods) + j = 0; + else + j = sk_SSL_COMP_num(s->ctx->comp_methods); + *(p++) = 1 + j; + for (i = 0; i < j; i++) { + comp = sk_SSL_COMP_value(s->ctx->comp_methods, i); + *(p++) = comp->id; + } +#endif + *(p++) = 0; /* Add the NULL method */ + +#ifndef OPENSSL_NO_TLSEXT + /* TLS extensions */ + if (ssl_prepare_clienthello_tlsext(s) <= 0) { + SSLerr(SSL_F_SSL3_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT); + goto err; + } + if ((p = + ssl_add_clienthello_tlsext(s, p, buf + SSL3_RT_MAX_PLAIN_LENGTH, + &al)) == NULL) { + ssl3_send_alert(s, SSL3_AL_FATAL, al); + SSLerr(SSL_F_SSL3_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); + goto err; + } +#endif + + l = p - d; + ssl_set_handshake_header(s, SSL3_MT_CLIENT_HELLO, l); + s->state = SSL3_ST_CW_CLNT_HELLO_B; + } + + /* SSL3_ST_CW_CLNT_HELLO_B */ + return ssl_do_write(s); + err: + s->state = SSL_ST_ERR; + return (-1); +} + +int ssl3_get_server_hello(SSL *s) +{ + STACK_OF(SSL_CIPHER) *sk; + const SSL_CIPHER *c; + CERT *ct = s->cert; + unsigned char *p, *d; + int i, al = SSL_AD_INTERNAL_ERROR, ok; + unsigned int j; + long n; +#ifndef OPENSSL_NO_COMP + SSL_COMP *comp; +#endif + /* + * Hello verify request and/or server hello version may not match so set + * first packet if we're negotiating version. + */ + if (SSL_IS_DTLS(s)) + s->first_packet = 1; + + n = s->method->ssl_get_message(s, + SSL3_ST_CR_SRVR_HELLO_A, + SSL3_ST_CR_SRVR_HELLO_B, -1, 20000, &ok); + + if (!ok) + return ((int)n); + + if (SSL_IS_DTLS(s)) { + s->first_packet = 0; + if (s->s3->tmp.message_type == DTLS1_MT_HELLO_VERIFY_REQUEST) { + if (s->d1->send_cookie == 0) { + s->s3->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 (s->s3->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; + } + + d = p = (unsigned char *)s->init_msg; + if (s->method->version == DTLS_ANY_VERSION) { + /* Work out correct protocol version to use */ + int hversion = (p[0] << 8) | p[1]; + int options = s->options; + if (hversion == DTLS1_2_VERSION && !(options & SSL_OP_NO_DTLSv1_2)) + s->method = DTLSv1_2_client_method(); + else if (tls1_suiteb(s)) { + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, + SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE); + s->version = hversion; + al = SSL_AD_PROTOCOL_VERSION; + goto f_err; + } else if (hversion == DTLS1_VERSION && !(options & SSL_OP_NO_DTLSv1)) + s->method = DTLSv1_client_method(); + else { + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_WRONG_SSL_VERSION); + s->version = hversion; + al = SSL_AD_PROTOCOL_VERSION; + goto f_err; + } + s->session->ssl_version = s->version = s->method->version; + } + + if ((p[0] != (s->version >> 8)) || (p[1] != (s->version & 0xff))) { + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_WRONG_SSL_VERSION); + s->version = (s->version & 0xff00) | p[1]; + al = SSL_AD_PROTOCOL_VERSION; + goto f_err; + } + p += 2; + + /* load the server hello data */ + /* load the server random */ + memcpy(s->s3->server_random, p, SSL3_RANDOM_SIZE); + p += SSL3_RANDOM_SIZE; + + s->hit = 0; + + /* get the session-id */ + j = *(p++); + + if ((j > sizeof s->session->session_id) || (j > 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; + } +#ifndef OPENSSL_NO_TLSEXT + /* + * Check if we can resume the session based on external pre-shared secret. + * EAP-FAST (RFC 4851) supports two types of session resumption. + * Resumption based on server-side state works with session IDs. + * Resumption based on pre-shared Protected Access Credentials (PACs) + * works by overriding the SessionTicket extension at the application + * layer, and does not send a session ID. (We do not know whether EAP-FAST + * servers would honour the session ID.) Therefore, the session ID alone + * is not a reliable indicator of session resumption, so we first check if + * we can resume, and later peek at the next handshake message to see if the + * server wants to resume. + */ + if (s->version >= TLS1_VERSION && s->tls_session_secret_cb && + s->session->tlsext_tick) { + SSL_CIPHER *pref_cipher = NULL; + s->session->master_key_length = sizeof(s->session->master_key); + if (s->tls_session_secret_cb(s, s->session->master_key, + &s->session->master_key_length, + NULL, &pref_cipher, + s->tls_session_secret_cb_arg)) { + s->session->cipher = pref_cipher ? + pref_cipher : ssl_get_cipher_by_char(s, p + j); + } else { + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, ERR_R_INTERNAL_ERROR); + al = SSL_AD_INTERNAL_ERROR; + goto f_err; + } + } +#endif /* OPENSSL_NO_TLSEXT */ + + if (j != 0 && j == s->session->session_id_length + && memcmp(p, s->session->session_id, j) == 0) { + if (s->sid_ctx_length != s->session->sid_ctx_length + || memcmp(s->session->sid_ctx, s->sid_ctx, s->sid_ctx_length)) { + /* 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->hit = 1; + } else { + /* + * If we were trying for session-id reuse but the server + * didn't echo the ID, make a new SSL_SESSION. + * In the case of EAP-FAST and PAC, we do not send a session ID, + * so the PAC-based session secret is always preserved. It'll be + * overwritten if the server refuses resumption. + */ + if (s->session->session_id_length > 0) { + if (!ssl_get_new_session(s, 0)) { + goto f_err; + } + } + s->session->session_id_length = j; + memcpy(s->session->session_id, p, j); /* j could be 0 */ + } + p += j; + c = ssl_get_cipher_by_char(s, p); + if (c == NULL) { + /* unknown cipher */ + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_UNKNOWN_CIPHER_RETURNED); + goto f_err; + } + /* Set version disabled mask now we know version */ + if (!SSL_USE_TLS1_2_CIPHERS(s)) + ct->mask_ssl = SSL_TLSV1_2; + else + ct->mask_ssl = 0; + /* + * If it is a disabled cipher we didn't send it in client hello, so + * return an error. + */ + if (c->algorithm_ssl & ct->mask_ssl || + c->algorithm_mkey & ct->mask_k || c->algorithm_auth & ct->mask_a) { + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_WRONG_CIPHER_RETURNED); + goto f_err; + } + p += ssl_put_cipher_by_char(s, NULL, NULL); + + sk = ssl_get_ciphers_by_id(s); + i = sk_SSL_CIPHER_find(sk, c); + 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->hit && (s->session->cipher_id != c->id)) { +/* Workaround is now obsolete */ +#if 0 + if (!(s->options & SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG)) +#endif + { + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, + SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED); + goto f_err; + } + } + s->s3->tmp.new_cipher = c; + /* + * Don't digest cached records if no sigalgs: we may need them for client + * authentication. + */ + if (!SSL_USE_SIGALGS(s) && !ssl3_digest_cached_records(s)) + goto f_err; + /* lets get the compression algorithm */ + /* COMPRESSION */ +#ifdef OPENSSL_NO_COMP + if (*(p++) != 0) { + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, + SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM); + goto f_err; + } + /* + * If compression is disabled we'd better not try to resume a session + * using compression. + */ + if (s->session->compress_meth != 0) { + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_INCONSISTENT_COMPRESSION); + goto f_err; + } +#else + j = *(p++); + if (s->hit && j != s->session->compress_meth) { + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, + SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED); + goto f_err; + } + if (j == 0) + comp = NULL; + else if (s->options & SSL_OP_NO_COMPRESSION) { + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_COMPRESSION_DISABLED); + goto f_err; + } else + comp = ssl3_comp_find(s->ctx->comp_methods, j); + + if ((j != 0) && (comp == NULL)) { + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, + SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM); + goto f_err; + } else { + s->s3->tmp.new_compression = comp; + } +#endif + +#ifndef OPENSSL_NO_TLSEXT + /* TLS extensions */ + if (!ssl_parse_serverhello_tlsext(s, &p, d, n)) { + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_PARSE_TLSEXT); + goto err; + } +#endif + + if (p != (d + n)) { + /* wrong packet length */ + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_BAD_PACKET_LENGTH); + goto f_err; + } + + return (1); + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + err: + s->state = SSL_ST_ERR; + return (-1); +} + +int ssl3_get_server_certificate(SSL *s) +{ + int al, i, ok, ret = -1; + unsigned long n, nc, llen, l; + X509 *x = NULL; + const unsigned char *q, *p; + unsigned char *d; + STACK_OF(X509) *sk = NULL; + SESS_CERT *sc; + EVP_PKEY *pkey = NULL; + int need_cert = 1; /* VRS: 0=> will allow null cert if auth == + * KRB5 */ + + n = s->method->ssl_get_message(s, + SSL3_ST_CR_CERT_A, + SSL3_ST_CR_CERT_B, + -1, s->max_cert_list, &ok); + + if (!ok) + return ((int)n); + + if ((s->s3->tmp.message_type == SSL3_MT_SERVER_KEY_EXCHANGE) || + ((s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5) && + (s->s3->tmp.message_type == SSL3_MT_SERVER_DONE))) { + s->s3->tmp.reuse_message = 1; + return (1); + } + + if (s->s3->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; + } + p = d = (unsigned char *)s->init_msg; + + if ((sk = sk_X509_new_null()) == NULL) { + SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, ERR_R_MALLOC_FAILURE); + goto err; + } + + n2l3(p, llen); + if (llen + 3 != n) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, SSL_R_LENGTH_MISMATCH); + goto f_err; + } + for (nc = 0; nc < llen;) { + n2l3(p, l); + if ((l + nc + 3) > llen) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, + SSL_R_CERT_LENGTH_MISMATCH); + goto f_err; + } + + q = p; + x = d2i_X509(NULL, &q, l); + if (x == NULL) { + al = SSL_AD_BAD_CERTIFICATE; + SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, ERR_R_ASN1_LIB); + goto f_err; + } + if (q != (p + l)) { + 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; + nc += l + 3; + p = q; + } + + i = ssl_verify_cert_chain(s, sk); + if ((s->verify_mode != SSL_VERIFY_NONE) && (i <= 0) +#ifndef OPENSSL_NO_KRB5 + && !((s->s3->tmp.new_cipher->algorithm_mkey & SSL_kKRB5) && + (s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5)) +#endif /* OPENSSL_NO_KRB5 */ + ) { + 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; + + if (s->session->sess_cert) + ssl_sess_cert_free(s->session->sess_cert); + s->session->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); + + /* VRS: allow null cert if auth == KRB5 */ + need_cert = ((s->s3->tmp.new_cipher->algorithm_mkey & SSL_kKRB5) && + (s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5)) + ? 0 : 1; + +#ifdef KSSL_DEBUG + fprintf(stderr, "pkey,x = %p, %p\n", pkey, x); + fprintf(stderr, "ssl_cert_type(x,pkey) = %d\n", ssl_cert_type(x, pkey)); + fprintf(stderr, "cipher, alg, nc = %s, %lx, %lx, %d\n", + s->s3->tmp.new_cipher->name, + s->s3->tmp.new_cipher->algorithm_mkey, + s->s3->tmp.new_cipher->algorithm_auth, need_cert); +#endif /* KSSL_DEBUG */ + + if (need_cert && ((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 (need_cert && i < 0) { + x = NULL; + al = SSL3_AL_FATAL; + SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, + SSL_R_UNKNOWN_CERTIFICATE_TYPE); + goto f_err; + } + + if (need_cert) { + int exp_idx = ssl_cipher_get_cert_index(s->s3->tmp.new_cipher); + if (exp_idx >= 0 && i != exp_idx) { + x = NULL; + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE, + SSL_R_WRONG_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. + */ + if (sc->peer_pkeys[i].x509 != NULL) + X509_free(sc->peer_pkeys[i].x509); + sc->peer_pkeys[i].x509 = x; + sc->peer_key = &(sc->peer_pkeys[i]); + + if (s->session->peer != NULL) + X509_free(s->session->peer); + CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); + s->session->peer = x; + } else { + sc->peer_cert_type = i; + sc->peer_key = NULL; + + if (s->session->peer != NULL) + X509_free(s->session->peer); + s->session->peer = NULL; + } + s->session->verify_result = s->verify_result; + + x = NULL; + ret = 1; + if (0) { + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + err: + s->state = SSL_ST_ERR; + } + + EVP_PKEY_free(pkey); + X509_free(x); + sk_X509_pop_free(sk, X509_free); + return (ret); +} + +int ssl3_get_key_exchange(SSL *s) +{ +#ifndef OPENSSL_NO_RSA + unsigned char *q, md_buf[EVP_MAX_MD_SIZE * 2]; +#endif + EVP_MD_CTX md_ctx; + unsigned char *param, *p; + int al, j, ok; + long i, param_len, n, alg_k, alg_a; + EVP_PKEY *pkey = NULL; + const EVP_MD *md = NULL; +#ifndef OPENSSL_NO_RSA + RSA *rsa = NULL; +#endif +#ifndef OPENSSL_NO_DH + DH *dh = NULL; +#endif +#ifndef OPENSSL_NO_ECDH + EC_KEY *ecdh = NULL; + BN_CTX *bn_ctx = NULL; + EC_POINT *srvr_ecpoint = NULL; + int curve_nid = 0; + int encoded_pt_len = 0; +#endif + + EVP_MD_CTX_init(&md_ctx); + + /* + * use same message size as in ssl3_get_certificate_request() as + * ServerKeyExchange message may be skipped + */ + n = s->method->ssl_get_message(s, + SSL3_ST_CR_KEY_EXCH_A, + SSL3_ST_CR_KEY_EXCH_B, + -1, s->max_cert_list, &ok); + if (!ok) + return ((int)n); + + alg_k = s->s3->tmp.new_cipher->algorithm_mkey; + + if (s->s3->tmp.message_type != SSL3_MT_SERVER_KEY_EXCHANGE) { + /* + * Can't skip server key exchange if this is an ephemeral + * ciphersuite. + */ + 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; + } +#ifndef OPENSSL_NO_PSK + /* + * In plain PSK ciphersuite, ServerKeyExchange can be omitted if no + * identity hint is sent. Set session->sess_cert anyway to avoid + * problems later. + */ + if (alg_k & SSL_kPSK) { + s->session->sess_cert = ssl_sess_cert_new(); + if (s->ctx->psk_identity_hint) + OPENSSL_free(s->ctx->psk_identity_hint); + s->ctx->psk_identity_hint = NULL; + } +#endif + s->s3->tmp.reuse_message = 1; + return (1); + } + + param = p = (unsigned char *)s->init_msg; + if (s->session->sess_cert != NULL) { +#ifndef OPENSSL_NO_RSA + if (s->session->sess_cert->peer_rsa_tmp != NULL) { + RSA_free(s->session->sess_cert->peer_rsa_tmp); + s->session->sess_cert->peer_rsa_tmp = NULL; + } +#endif +#ifndef OPENSSL_NO_DH + if (s->session->sess_cert->peer_dh_tmp) { + DH_free(s->session->sess_cert->peer_dh_tmp); + s->session->sess_cert->peer_dh_tmp = NULL; + } +#endif +#ifndef OPENSSL_NO_ECDH + if (s->session->sess_cert->peer_ecdh_tmp) { + EC_KEY_free(s->session->sess_cert->peer_ecdh_tmp); + s->session->sess_cert->peer_ecdh_tmp = NULL; + } +#endif + } else { + s->session->sess_cert = ssl_sess_cert_new(); + } + + /* Total length of the parameters including the length prefix */ + param_len = 0; + + alg_a = s->s3->tmp.new_cipher->algorithm_auth; + + al = SSL_AD_DECODE_ERROR; + +#ifndef OPENSSL_NO_PSK + if (alg_k & SSL_kPSK) { + param_len = 2; + if (param_len > n) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_TOO_SHORT); + goto f_err; + } + n2s(p, i); + + /* + * Store PSK identity hint for later use, hint is used in + * ssl3_send_client_key_exchange. Assume that the maximum length of + * a PSK identity hint can be as long as the maximum length of a PSK + * identity. + */ + if (i > PSK_MAX_IDENTITY_LEN) { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_DATA_LENGTH_TOO_LONG); + goto f_err; + } + if (i > n - param_len) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, + SSL_R_BAD_PSK_IDENTITY_HINT_LENGTH); + goto f_err; + } + param_len += i; + + s->session->psk_identity_hint = BUF_strndup((char *)p, i); + if (s->session->psk_identity_hint == NULL) { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE); + goto f_err; + } + + p += i; + n -= param_len; + } else +#endif /* !OPENSSL_NO_PSK */ +#ifndef OPENSSL_NO_SRP + if (alg_k & SSL_kSRP) { + param_len = 2; + if (param_len > n) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_TOO_SHORT); + goto f_err; + } + n2s(p, i); + + if (i > n - param_len) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_SRP_N_LENGTH); + goto f_err; + } + param_len += i; + + if (!(s->srp_ctx.N = BN_bin2bn(p, i, NULL))) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_BN_LIB); + goto err; + } + p += i; + + if (2 > n - param_len) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_TOO_SHORT); + goto f_err; + } + param_len += 2; + + n2s(p, i); + + if (i > n - param_len) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_SRP_G_LENGTH); + goto f_err; + } + param_len += i; + + if (!(s->srp_ctx.g = BN_bin2bn(p, i, NULL))) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_BN_LIB); + goto err; + } + p += i; + + if (1 > n - param_len) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_TOO_SHORT); + goto f_err; + } + param_len += 1; + + i = (unsigned int)(p[0]); + p++; + + if (i > n - param_len) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_SRP_S_LENGTH); + goto f_err; + } + param_len += i; + + if (!(s->srp_ctx.s = BN_bin2bn(p, i, NULL))) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_BN_LIB); + goto err; + } + p += i; + + if (2 > n - param_len) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_TOO_SHORT); + goto f_err; + } + param_len += 2; + + n2s(p, i); + + if (i > n - param_len) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_SRP_B_LENGTH); + goto f_err; + } + param_len += i; + + if (!(s->srp_ctx.B = BN_bin2bn(p, i, NULL))) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_BN_LIB); + goto err; + } + p += i; + n -= param_len; + + if (!srp_verify_server_param(s, &al)) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_SRP_PARAMETERS); + goto f_err; + } + +/* We must check if there is a certificate */ +# ifndef OPENSSL_NO_RSA + if (alg_a & SSL_aRSA) + pkey = + X509_get_pubkey(s->session-> + sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509); +# else + if (0) ; +# endif +# ifndef OPENSSL_NO_DSA + else if (alg_a & SSL_aDSS) + pkey = + X509_get_pubkey(s->session-> + sess_cert->peer_pkeys[SSL_PKEY_DSA_SIGN]. + x509); +# endif + } else +#endif /* !OPENSSL_NO_SRP */ +#ifndef OPENSSL_NO_RSA + if (alg_k & SSL_kRSA) { + /* Temporary RSA keys only allowed in export ciphersuites */ + if (!SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_UNEXPECTED_MESSAGE); + goto f_err; + } + if ((rsa = RSA_new()) == NULL) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE); + goto err; + } + + param_len = 2; + if (param_len > n) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_TOO_SHORT); + goto f_err; + } + n2s(p, i); + + if (i > n - param_len) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_RSA_MODULUS_LENGTH); + goto f_err; + } + param_len += i; + + if (!(rsa->n = BN_bin2bn(p, i, rsa->n))) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_BN_LIB); + goto err; + } + p += i; + + if (2 > n - param_len) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_TOO_SHORT); + goto f_err; + } + param_len += 2; + + n2s(p, i); + + if (i > n - param_len) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_RSA_E_LENGTH); + goto f_err; + } + param_len += i; + + if (!(rsa->e = BN_bin2bn(p, i, rsa->e))) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_BN_LIB); + goto err; + } + p += i; + n -= param_len; + + /* this should be because we are using an export cipher */ + if (alg_a & SSL_aRSA) + pkey = + X509_get_pubkey(s->session-> + sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509); + else { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR); + goto err; + } + + if (EVP_PKEY_bits(pkey) <= SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_UNEXPECTED_MESSAGE); + goto f_err; + } + + s->session->sess_cert->peer_rsa_tmp = rsa; + rsa = NULL; + } +#else /* OPENSSL_NO_RSA */ + if (0) ; +#endif +#ifndef OPENSSL_NO_DH + else if (alg_k & SSL_kEDH) { + if ((dh = DH_new()) == NULL) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_DH_LIB); + goto err; + } + + param_len = 2; + if (param_len > n) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_TOO_SHORT); + goto f_err; + } + n2s(p, i); + + if (i > n - param_len) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_DH_P_LENGTH); + goto f_err; + } + param_len += i; + + if (!(dh->p = BN_bin2bn(p, i, NULL))) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_BN_LIB); + goto err; + } + p += i; + + if (BN_is_zero(dh->p)) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_DH_P_VALUE); + goto f_err; + } + + + if (2 > n - param_len) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_TOO_SHORT); + goto f_err; + } + param_len += 2; + + n2s(p, i); + + if (i > n - param_len) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_DH_G_LENGTH); + goto f_err; + } + param_len += i; + + if (!(dh->g = BN_bin2bn(p, i, NULL))) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_BN_LIB); + goto err; + } + p += i; + + if (BN_is_zero(dh->g)) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_DH_G_VALUE); + goto f_err; + } + + if (2 > n - param_len) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_TOO_SHORT); + goto f_err; + } + param_len += 2; + + n2s(p, i); + + if (i > n - param_len) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_DH_PUB_KEY_LENGTH); + goto f_err; + } + param_len += i; + + if (!(dh->pub_key = BN_bin2bn(p, i, NULL))) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_BN_LIB); + goto err; + } + p += i; + n -= param_len; + + if (BN_is_zero(dh->pub_key)) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_DH_PUB_KEY_VALUE); + goto f_err; + } + +# ifndef OPENSSL_NO_RSA + if (alg_a & SSL_aRSA) + pkey = + X509_get_pubkey(s->session-> + sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509); +# else + if (0) ; +# endif +# ifndef OPENSSL_NO_DSA + else if (alg_a & SSL_aDSS) + pkey = + X509_get_pubkey(s->session-> + sess_cert->peer_pkeys[SSL_PKEY_DSA_SIGN]. + x509); +# endif + /* else anonymous DH, so no certificate or pkey. */ + + s->session->sess_cert->peer_dh_tmp = dh; + dh = NULL; + } else if ((alg_k & SSL_kDHr) || (alg_k & SSL_kDHd)) { + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, + SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER); + goto f_err; + } +#endif /* !OPENSSL_NO_DH */ + +#ifndef OPENSSL_NO_ECDH + else if (alg_k & SSL_kEECDH) { + EC_GROUP *ngroup; + const EC_GROUP *group; + + if ((ecdh = EC_KEY_new()) == NULL) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* + * Extract elliptic curve parameters and the server's ephemeral ECDH + * public key. Keep accumulating lengths of various components in + * param_len and make sure it never exceeds n. + */ + + /* + * XXX: For now we only support named (not generic) curves and the + * ECParameters in this case is just three bytes. We also need one + * byte for the length of the encoded point + */ + param_len = 4; + if (param_len > n) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_TOO_SHORT); + goto f_err; + } + /* + * Check curve is one of our preferences, if not server has sent an + * invalid curve. ECParameters is 3 bytes. + */ + if (!tls1_check_curve(s, p, 3)) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_WRONG_CURVE); + goto f_err; + } + + if ((curve_nid = tls1_ec_curve_id2nid(*(p + 2))) == 0) { + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, + SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS); + goto f_err; + } + + ngroup = EC_GROUP_new_by_curve_name(curve_nid); + if (ngroup == 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; + } + EC_GROUP_free(ngroup); + + group = EC_KEY_get0_group(ecdh); + + if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && + (EC_GROUP_get_degree(group) > 163)) { + al = SSL_AD_EXPORT_RESTRICTION; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, + SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER); + goto f_err; + } + + p += 3; + + /* Next, get the encoded ECPoint */ + if (((srvr_ecpoint = EC_POINT_new(group)) == NULL) || + ((bn_ctx = BN_CTX_new()) == NULL)) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE); + goto err; + } + + encoded_pt_len = *p; /* length of encoded point */ + p += 1; + + if ((encoded_pt_len > n - param_len) || + (EC_POINT_oct2point(group, srvr_ecpoint, + p, encoded_pt_len, bn_ctx) == 0)) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_BAD_ECPOINT); + goto f_err; + } + param_len += encoded_pt_len; + + n -= param_len; + p += encoded_pt_len; + + /* + * 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 (0) ; +# ifndef OPENSSL_NO_RSA + else if (alg_a & SSL_aRSA) + pkey = + X509_get_pubkey(s->session-> + sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509); +# endif +# ifndef OPENSSL_NO_ECDSA + else if (alg_a & SSL_aECDSA) + pkey = + X509_get_pubkey(s->session-> + sess_cert->peer_pkeys[SSL_PKEY_ECC].x509); +# endif + /* else anonymous ECDH, so no certificate or pkey. */ + EC_KEY_set_public_key(ecdh, srvr_ecpoint); + s->session->sess_cert->peer_ecdh_tmp = ecdh; + ecdh = NULL; + BN_CTX_free(bn_ctx); + bn_ctx = NULL; + EC_POINT_free(srvr_ecpoint); + srvr_ecpoint = NULL; + } else if (alg_k) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_UNEXPECTED_MESSAGE); + goto f_err; + } +#endif /* !OPENSSL_NO_ECDH */ + + /* p points to the next byte, there are 'n' bytes left */ + + /* if it was signed, check the signature */ + if (pkey != NULL) { + if (SSL_USE_SIGALGS(s)) { + int rv; + if (2 > n) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_TOO_SHORT); + goto f_err; + } + rv = tls12_check_peer_sigalg(&md, s, p, pkey); + if (rv == -1) + goto err; + else if (rv == 0) { + goto f_err; + } +#ifdef SSL_DEBUG + fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md)); +#endif + p += 2; + n -= 2; + } else + md = EVP_sha1(); + + if (2 > n) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_LENGTH_TOO_SHORT); + goto f_err; + } + n2s(p, i); + n -= 2; + j = EVP_PKEY_size(pkey); + + /* + * Check signature length. If n is 0 then signature is empty + */ + if ((i != n) || (n > j) || (n <= 0)) { + /* wrong packet length */ + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_WRONG_SIGNATURE_LENGTH); + goto f_err; + } +#ifndef OPENSSL_NO_RSA + if (pkey->type == EVP_PKEY_RSA && !SSL_USE_SIGALGS(s)) { + int num; + unsigned int size; + + j = 0; + q = md_buf; + for (num = 2; num > 0; num--) { + EVP_MD_CTX_set_flags(&md_ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); + if (EVP_DigestInit_ex(&md_ctx, + (num == 2) ? s->ctx->md5 : s->ctx->sha1, + NULL) <= 0 + || EVP_DigestUpdate(&md_ctx, &(s->s3->client_random[0]), + SSL3_RANDOM_SIZE) <= 0 + || EVP_DigestUpdate(&md_ctx, &(s->s3->server_random[0]), + SSL3_RANDOM_SIZE) <= 0 + || EVP_DigestUpdate(&md_ctx, param, param_len) <= 0 + || EVP_DigestFinal_ex(&md_ctx, q, &size) <= 0) { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + al = SSL_AD_INTERNAL_ERROR; + goto f_err; + } + q += size; + j += size; + } + 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 +#endif + { + if (EVP_VerifyInit_ex(&md_ctx, md, NULL) <= 0 + || EVP_VerifyUpdate(&md_ctx, &(s->s3->client_random[0]), + SSL3_RANDOM_SIZE) <= 0 + || EVP_VerifyUpdate(&md_ctx, &(s->s3->server_random[0]), + SSL3_RANDOM_SIZE) <= 0 + || EVP_VerifyUpdate(&md_ctx, param, param_len) <= 0) { + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_EVP_LIB); + goto f_err; + } + 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, aSRP or kPSK do not need public keys */ + if (!(alg_a & (SSL_aNULL | SSL_aSRP)) && !(alg_k & SSL_kPSK)) { + /* Might be wrong key type, check it */ + if (ssl3_check_cert_and_algorithm(s)) + /* Otherwise this shouldn't happen */ + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR); + goto err; + } + /* still data left over */ + if (n != 0) { + 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); + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + err: + EVP_PKEY_free(pkey); +#ifndef OPENSSL_NO_RSA + if (rsa != NULL) + RSA_free(rsa); +#endif +#ifndef OPENSSL_NO_DH + if (dh != NULL) + DH_free(dh); +#endif +#ifndef OPENSSL_NO_ECDH + BN_CTX_free(bn_ctx); + EC_POINT_free(srvr_ecpoint); + if (ecdh != NULL) + EC_KEY_free(ecdh); +#endif + EVP_MD_CTX_cleanup(&md_ctx); + s->state = SSL_ST_ERR; + return (-1); +} + +int ssl3_get_certificate_request(SSL *s) +{ + int ok, ret = 0; + unsigned long n, nc, l; + unsigned int llen, ctype_num, i; + X509_NAME *xn = NULL; + const unsigned char *p, *q; + unsigned char *d; + STACK_OF(X509_NAME) *ca_sk = NULL; + + n = s->method->ssl_get_message(s, + SSL3_ST_CR_CERT_REQ_A, + SSL3_ST_CR_CERT_REQ_B, + -1, s->max_cert_list, &ok); + + if (!ok) + return ((int)n); + + s->s3->tmp.cert_req = 0; + + if (s->s3->tmp.message_type == SSL3_MT_SERVER_DONE) { + s->s3->tmp.reuse_message = 1; + /* + * If we get here we don't need any cached handshake records as we + * wont be doing client auth. + */ + if (s->s3->handshake_buffer) { + if (!ssl3_digest_cached_records(s)) + goto err; + } + return (1); + } + + if (s->s3->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 (s->version > SSL3_VERSION) { + if (s->s3->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; + } + } + + p = d = (unsigned char *)s->init_msg; + + 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 */ + ctype_num = *(p++); + if (s->cert->ctypes) { + OPENSSL_free(s->cert->ctypes); + s->cert->ctypes = NULL; + } + if (ctype_num > SSL3_CT_NUMBER) { + /* If we exceed static buffer copy all to cert structure */ + s->cert->ctypes = OPENSSL_malloc(ctype_num); + memcpy(s->cert->ctypes, p, ctype_num); + s->cert->ctype_num = (size_t)ctype_num; + ctype_num = SSL3_CT_NUMBER; + } + for (i = 0; i < ctype_num; i++) + s->s3->tmp.ctype[i] = p[i]; + p += p[-1]; + if (SSL_USE_SIGALGS(s)) { + n2s(p, llen); + /* + * Check we have enough room for signature algorithms and following + * length value. + */ + if ((unsigned long)(p - d + llen + 2) > n) { + 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; + } + /* Clear certificate digests and validity flags */ + for (i = 0; i < SSL_PKEY_NUM; i++) { + s->cert->pkeys[i].digest = NULL; + s->cert->pkeys[i].valid_flags = 0; + } + if ((llen & 1) || !tls1_save_sigalgs(s, p, llen)) { + 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; + } + if (!tls1_process_sigalgs(s)) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, ERR_R_MALLOC_FAILURE); + goto err; + } + p += llen; + } + + /* get the CA RDNs */ + n2s(p, llen); +#if 0 + { + FILE *out; + out = fopen("/tmp/vsign.der", "w"); + fwrite(p, 1, llen, out); + fclose(out); + } +#endif + + if ((unsigned long)(p - d + llen) != n) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, SSL_R_LENGTH_MISMATCH); + goto err; + } + + for (nc = 0; nc < llen;) { + n2s(p, l); + if ((l + nc + 2) > llen) { + if ((s->options & SSL_OP_NETSCAPE_CA_DN_BUG)) + goto cont; /* netscape bugs */ + 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 = p; + + if ((xn = d2i_X509_NAME(NULL, &q, l)) == NULL) { + /* If netscape tolerance is on, ignore errors */ + if (s->options & SSL_OP_NETSCAPE_CA_DN_BUG) + goto cont; + else { + 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 != (p + l)) { + 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; + + p += l; + nc += l + 2; + } + + if (0) { + cont: + ERR_clear_error(); + } + + /* we should setup a certificate to return.... */ + s->s3->tmp.cert_req = 1; + s->s3->tmp.ctype_num = ctype_num; + if (s->s3->tmp.ca_names != NULL) + sk_X509_NAME_pop_free(s->s3->tmp.ca_names, X509_NAME_free); + s->s3->tmp.ca_names = ca_sk; + ca_sk = NULL; + + ret = 1; + goto done; + err: + s->state = SSL_ST_ERR; + done: + X509_NAME_free(xn); + if (ca_sk != NULL) + 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)); +} + +#ifndef OPENSSL_NO_TLSEXT +int ssl3_get_new_session_ticket(SSL *s) +{ + int ok, al, ret = 0, ticklen; + long n; + const unsigned char *p; + unsigned char *d; + unsigned long ticket_lifetime_hint; + + n = s->method->ssl_get_message(s, + SSL3_ST_CR_SESSION_TICKET_A, + SSL3_ST_CR_SESSION_TICKET_B, + SSL3_MT_NEWSESSION_TICKET, 16384, &ok); + + if (!ok) + return ((int)n); + + if (n < 6) { + /* need at least ticket_lifetime_hint + ticket length */ + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET, SSL_R_LENGTH_MISMATCH); + goto f_err; + } + + p = d = (unsigned char *)s->init_msg; + + n2l(p, ticket_lifetime_hint); + n2s(p, ticklen); + /* ticket_lifetime_hint + ticket_length + ticket */ + if (ticklen + 6 != n) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET, SSL_R_LENGTH_MISMATCH); + goto f_err; + } + + /* Server is allowed to change its mind and send an empty ticket. */ + if (ticklen == 0) + return 1; + + if (s->session->session_id_length > 0) { + int i = s->session_ctx->session_cache_mode; + SSL_SESSION *new_sess; + /* + * We reused an existing session, so we need to replace it with a new + * one + */ + if (i & SSL_SESS_CACHE_CLIENT) { + /* + * Remove the old session from the cache + */ + if (i & SSL_SESS_CACHE_NO_INTERNAL_STORE) { + if (s->session_ctx->remove_session_cb != NULL) + s->session_ctx->remove_session_cb(s->session_ctx, + s->session); + } else { + /* We carry on if this fails */ + SSL_CTX_remove_session(s->session_ctx, s->session); + } + } + + if ((new_sess = ssl_session_dup(s->session, 0)) == 0) { + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET, ERR_R_MALLOC_FAILURE); + goto f_err; + } + + SSL_SESSION_free(s->session); + s->session = new_sess; + } + + if (s->session->tlsext_tick) { + OPENSSL_free(s->session->tlsext_tick); + s->session->tlsext_ticklen = 0; + } + s->session->tlsext_tick = OPENSSL_malloc(ticklen); + if (!s->session->tlsext_tick) { + SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET, ERR_R_MALLOC_FAILURE); + goto err; + } + memcpy(s->session->tlsext_tick, p, ticklen); + s->session->tlsext_tick_lifetime_hint = ticket_lifetime_hint; + s->session->tlsext_ticklen = ticklen; + /* + * There are two ways to detect a resumed ticket session. 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(p, ticklen, + s->session->session_id, &s->session->session_id_length, +# ifndef OPENSSL_NO_SHA256 + EVP_sha256(), NULL); +# else + EVP_sha1(), NULL); +# endif + ret = 1; + return (ret); + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + err: + s->state = SSL_ST_ERR; + return (-1); +} + +int ssl3_get_cert_status(SSL *s) +{ + int ok, al; + unsigned long resplen, n; + const unsigned char *p; + + n = s->method->ssl_get_message(s, + SSL3_ST_CR_CERT_STATUS_A, + SSL3_ST_CR_CERT_STATUS_B, + -1, 16384, &ok); + + if (!ok) + return ((int)n); + + if (s->s3->tmp.message_type != SSL3_MT_CERTIFICATE_STATUS) { + /* + * The CertificateStatus message is optional even if + * tlsext_status_expected is set + */ + s->s3->tmp.reuse_message = 1; + } else { + if (n < 4) { + /* 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; + } + p = (unsigned char *)s->init_msg; + if (*p++ != TLSEXT_STATUSTYPE_ocsp) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CERT_STATUS, SSL_R_UNSUPPORTED_STATUS_TYPE); + goto f_err; + } + n2l3(p, resplen); + if (resplen + 4 != n) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CERT_STATUS, SSL_R_LENGTH_MISMATCH); + goto f_err; + } + s->tlsext_ocsp_resp = BUF_memdup(p, resplen); + if (s->tlsext_ocsp_resp == NULL) { + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL3_GET_CERT_STATUS, ERR_R_MALLOC_FAILURE); + goto f_err; + } + s->tlsext_ocsp_resplen = resplen; + } + if (s->ctx->tlsext_status_cb) { + int ret; + ret = s->ctx->tlsext_status_cb(s, s->ctx->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); + s->state = SSL_ST_ERR; + return (-1); +} +#endif + +int ssl3_get_server_done(SSL *s) +{ + int ok, ret = 0; + long n; + + /* Second to last param should be very small, like 0 :-) */ + n = s->method->ssl_get_message(s, + SSL3_ST_CR_SRVR_DONE_A, + SSL3_ST_CR_SRVR_DONE_B, + SSL3_MT_SERVER_DONE, 30, &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); + s->state = SSL_ST_ERR; + return -1; + } + ret = 1; + return (ret); +} + +#ifndef OPENSSL_NO_DH +static DH *get_server_static_dh_key(SESS_CERT *scert) +{ + DH *dh_srvr = NULL; + EVP_PKEY *spkey = NULL; + int idx = scert->peer_cert_type; + + if (idx >= 0) + spkey = X509_get_pubkey(scert->peer_pkeys[idx].x509); + if (spkey) { + dh_srvr = EVP_PKEY_get1_DH(spkey); + EVP_PKEY_free(spkey); + } + if (dh_srvr == NULL) + SSLerr(SSL_F_GET_SERVER_STATIC_DH_KEY, ERR_R_INTERNAL_ERROR); + return dh_srvr; +} +#endif + +int ssl3_send_client_key_exchange(SSL *s) +{ + unsigned char *p; + int n; + unsigned long alg_k; +#ifndef OPENSSL_NO_RSA + unsigned char *q; + EVP_PKEY *pkey = NULL; +#endif +#ifndef OPENSSL_NO_KRB5 + KSSL_ERR kssl_err; +#endif /* OPENSSL_NO_KRB5 */ +#ifndef OPENSSL_NO_ECDH + EC_KEY *clnt_ecdh = NULL; + const EC_POINT *srvr_ecpoint = NULL; + EVP_PKEY *srvr_pub_pkey = NULL; + unsigned char *encodedPoint = NULL; + int encoded_pt_len = 0; + BN_CTX *bn_ctx = NULL; +#endif + + if (s->state == SSL3_ST_CW_KEY_EXCH_A) { + p = ssl_handshake_start(s); + + alg_k = s->s3->tmp.new_cipher->algorithm_mkey; + + /* Fool emacs indentation */ + if (0) { + } +#ifndef OPENSSL_NO_RSA + else if (alg_k & SSL_kRSA) { + RSA *rsa; + unsigned char tmp_buf[SSL_MAX_MASTER_KEY_LENGTH]; + + if (s->session->sess_cert == NULL) { + /* + * We should always have a server certificate with SSL_kRSA. + */ + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + if (s->session->sess_cert->peer_rsa_tmp != NULL) + rsa = s->session->sess_cert->peer_rsa_tmp; + else { + pkey = + X509_get_pubkey(s->session-> + 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); + EVP_PKEY_free(pkey); + goto err; + } + rsa = pkey->pkey.rsa; + EVP_PKEY_free(pkey); + } + + tmp_buf[0] = s->client_version >> 8; + tmp_buf[1] = s->client_version & 0xff; + if (RAND_bytes(&(tmp_buf[2]), sizeof tmp_buf - 2) <= 0) + goto err; + + s->session->master_key_length = sizeof tmp_buf; + + q = p; + /* Fix buf for TLS and beyond */ + if (s->version > SSL3_VERSION) + p += 2; + n = RSA_public_encrypt(sizeof tmp_buf, + tmp_buf, p, rsa, RSA_PKCS1_PADDING); +# ifdef PKCS1_CHECK + if (s->options & SSL_OP_PKCS1_CHECK_1) + p[1]++; + if (s->options & SSL_OP_PKCS1_CHECK_2) + tmp_buf[0] = 0x70; +# endif + if (n <= 0) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + SSL_R_BAD_RSA_ENCRYPT); + goto err; + } + + /* Fix buf for TLS and beyond */ + if (s->version > SSL3_VERSION) { + s2n(n, q); + n += 2; + } + + s->session->master_key_length = + s->method->ssl3_enc->generate_master_secret(s, + s-> + session->master_key, + tmp_buf, + sizeof tmp_buf); + OPENSSL_cleanse(tmp_buf, sizeof tmp_buf); + } +#endif +#ifndef OPENSSL_NO_KRB5 + else if (alg_k & SSL_kKRB5) { + krb5_error_code krb5rc; + KSSL_CTX *kssl_ctx = s->kssl_ctx; + /* krb5_data krb5_ap_req; */ + krb5_data *enc_ticket; + krb5_data authenticator, *authp = NULL; + EVP_CIPHER_CTX ciph_ctx; + const EVP_CIPHER *enc = NULL; + unsigned char iv[EVP_MAX_IV_LENGTH]; + unsigned char tmp_buf[SSL_MAX_MASTER_KEY_LENGTH]; + unsigned char epms[SSL_MAX_MASTER_KEY_LENGTH + EVP_MAX_IV_LENGTH]; + int padl, outl = sizeof(epms); + + EVP_CIPHER_CTX_init(&ciph_ctx); + +# ifdef KSSL_DEBUG + fprintf(stderr, "ssl3_send_client_key_exchange(%lx & %lx)\n", + alg_k, SSL_kKRB5); +# endif /* KSSL_DEBUG */ + + authp = NULL; +# ifdef KRB5SENDAUTH + if (KRB5SENDAUTH) + authp = &authenticator; +# endif /* KRB5SENDAUTH */ + + krb5rc = kssl_cget_tkt(kssl_ctx, &enc_ticket, authp, &kssl_err); + enc = kssl_map_enc(kssl_ctx->enctype); + if (enc == NULL) + goto err; +# ifdef KSSL_DEBUG + { + fprintf(stderr, "kssl_cget_tkt rtn %d\n", krb5rc); + if (krb5rc && kssl_err.text) + fprintf(stderr, "kssl_cget_tkt kssl_err=%s\n", + kssl_err.text); + } +# endif /* KSSL_DEBUG */ + + if (krb5rc) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, kssl_err.reason); + goto err; + } + + /*- + * 20010406 VRS - Earlier versions used KRB5 AP_REQ + * in place of RFC 2712 KerberosWrapper, as in: + * + * Send ticket (copy to *p, set n = length) + * n = krb5_ap_req.length; + * memcpy(p, krb5_ap_req.data, krb5_ap_req.length); + * if (krb5_ap_req.data) + * kssl_krb5_free_data_contents(NULL,&krb5_ap_req); + * + * Now using real RFC 2712 KerberosWrapper + * (Thanks to Simon Wilkinson <sxw@sxw.org.uk>) + * Note: 2712 "opaque" types are here replaced + * with a 2-byte length followed by the value. + * Example: + * KerberosWrapper= xx xx asn1ticket 0 0 xx xx encpms + * Where "xx xx" = length bytes. Shown here with + * optional authenticator omitted. + */ + + /* KerberosWrapper.Ticket */ + s2n(enc_ticket->length, p); + memcpy(p, enc_ticket->data, enc_ticket->length); + p += enc_ticket->length; + n = enc_ticket->length + 2; + + /* KerberosWrapper.Authenticator */ + if (authp && authp->length) { + s2n(authp->length, p); + memcpy(p, authp->data, authp->length); + p += authp->length; + n += authp->length + 2; + + free(authp->data); + authp->data = NULL; + authp->length = 0; + } else { + s2n(0, p); /* null authenticator length */ + n += 2; + } + + tmp_buf[0] = s->client_version >> 8; + tmp_buf[1] = s->client_version & 0xff; + if (RAND_bytes(&(tmp_buf[2]), sizeof tmp_buf - 2) <= 0) + goto err; + + /*- + * 20010420 VRS. Tried it this way; failed. + * EVP_EncryptInit_ex(&ciph_ctx,enc, NULL,NULL); + * EVP_CIPHER_CTX_set_key_length(&ciph_ctx, + * kssl_ctx->length); + * EVP_EncryptInit_ex(&ciph_ctx,NULL, key,iv); + */ + + memset(iv, 0, sizeof iv); /* per RFC 1510 */ + EVP_EncryptInit_ex(&ciph_ctx, enc, NULL, kssl_ctx->key, iv); + EVP_EncryptUpdate(&ciph_ctx, epms, &outl, tmp_buf, + sizeof tmp_buf); + EVP_EncryptFinal_ex(&ciph_ctx, &(epms[outl]), &padl); + outl += padl; + if (outl > (int)sizeof epms) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } + EVP_CIPHER_CTX_cleanup(&ciph_ctx); + + /* KerberosWrapper.EncryptedPreMasterSecret */ + s2n(outl, p); + memcpy(p, epms, outl); + p += outl; + n += outl + 2; + + s->session->master_key_length = + s->method->ssl3_enc->generate_master_secret(s, + s-> + session->master_key, + tmp_buf, + sizeof tmp_buf); + + OPENSSL_cleanse(tmp_buf, sizeof tmp_buf); + OPENSSL_cleanse(epms, outl); + } +#endif +#ifndef OPENSSL_NO_DH + else if (alg_k & (SSL_kEDH | SSL_kDHr | SSL_kDHd)) { + DH *dh_srvr, *dh_clnt; + SESS_CERT *scert = s->session->sess_cert; + + if (scert == NULL) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + SSL_R_UNEXPECTED_MESSAGE); + goto err; + } + + if (scert->peer_dh_tmp != NULL) { + dh_srvr = scert->peer_dh_tmp; + } else { + dh_srvr = get_server_static_dh_key(scert); + if (dh_srvr == NULL) + goto err; + } + + if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY) { + /* Use client certificate key */ + EVP_PKEY *clkey = s->cert->key->privatekey; + dh_clnt = NULL; + if (clkey) + dh_clnt = EVP_PKEY_get1_DH(clkey); + if (dh_clnt == NULL) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } + } else { + /* 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); + DH_free(dh_clnt); + goto err; + } + } + + /* + * use the 'p' output buffer for the DH key, but make sure to + * clear it out afterwards + */ + + n = DH_compute_key(p, dh_srvr->pub_key, dh_clnt); + if (scert->peer_dh_tmp == NULL) + DH_free(dh_srvr); + + if (n <= 0) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB); + DH_free(dh_clnt); + goto err; + } + + /* generate master key from the result */ + s->session->master_key_length = + s->method->ssl3_enc->generate_master_secret(s, + s-> + session->master_key, + p, n); + /* clean up */ + memset(p, 0, n); + + if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY) + n = 0; + else { + /* send off the data */ + n = BN_num_bytes(dh_clnt->pub_key); + s2n(n, p); + BN_bn2bin(dh_clnt->pub_key, p); + n += 2; + } + + DH_free(dh_clnt); + } +#endif + +#ifndef OPENSSL_NO_ECDH + else if (alg_k & (SSL_kEECDH | SSL_kECDHr | SSL_kECDHe)) { + const EC_GROUP *srvr_group = NULL; + EC_KEY *tkey; + int ecdh_clnt_cert = 0; + int field_size = 0; + + if (s->session->sess_cert == NULL) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + SSL_R_UNEXPECTED_MESSAGE); + goto err; + } + + /* + * Did we send out the client's ECDH share for use in premaster + * computation as part of client certificate? If so, set + * ecdh_clnt_cert to 1. + */ + if ((alg_k & (SSL_kECDHr | SSL_kECDHe)) && (s->cert != NULL)) { + /*- + * XXX: For now, we do not support client + * authentication using ECDH certificates. + * To add such support, one needs to add + * code that checks for appropriate + * conditions and sets ecdh_clnt_cert to 1. + * For example, the cert have an ECC + * key on the same curve as the server's + * and the key should be authorized for + * key agreement. + * + * One also needs to add code in ssl3_connect + * to skip sending the certificate verify + * message. + * + * if ((s->cert->key->privatekey != NULL) && + * (s->cert->key->privatekey->type == + * EVP_PKEY_EC) && ...) + * ecdh_clnt_cert = 1; + */ + } + + if (s->session->sess_cert->peer_ecdh_tmp != NULL) { + tkey = s->session->sess_cert->peer_ecdh_tmp; + } else { + /* Get the Server Public Key from Cert */ + srvr_pub_pkey = + X509_get_pubkey(s->session-> + sess_cert->peer_pkeys[SSL_PKEY_ECC].x509); + if ((srvr_pub_pkey == NULL) + || (srvr_pub_pkey->type != EVP_PKEY_EC) + || (srvr_pub_pkey->pkey.ec == NULL)) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + tkey = srvr_pub_pkey->pkey.ec; + } + + srvr_group = EC_KEY_get0_group(tkey); + srvr_ecpoint = EC_KEY_get0_public_key(tkey); + + if ((srvr_group == NULL) || (srvr_ecpoint == NULL)) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + if ((clnt_ecdh = EC_KEY_new()) == NULL) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!EC_KEY_set_group(clnt_ecdh, srvr_group)) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB); + goto err; + } + if (ecdh_clnt_cert) { + /* + * Reuse key info from our certificate We only need our + * private key to perform the ECDH computation. + */ + const BIGNUM *priv_key; + tkey = s->cert->key->privatekey->pkey.ec; + priv_key = EC_KEY_get0_private_key(tkey); + if (priv_key == NULL) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_MALLOC_FAILURE); + goto err; + } + if (!EC_KEY_set_private_key(clnt_ecdh, priv_key)) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_EC_LIB); + goto err; + } + } else { + /* Generate a new ECDH key pair */ + if (!(EC_KEY_generate_key(clnt_ecdh))) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_ECDH_LIB); + goto err; + } + } + + /* + * use the 'p' output buffer for the ECDH key, but make sure to + * clear it out afterwards + */ + + field_size = EC_GROUP_get_degree(srvr_group); + if (field_size <= 0) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB); + goto err; + } + n = ECDH_compute_key(p, (field_size + 7) / 8, srvr_ecpoint, + clnt_ecdh, NULL); + if (n <= 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->ssl3_enc->generate_master_secret(s, + s-> + session->master_key, + p, n); + + memset(p, 0, n); /* clean up */ + + if (ecdh_clnt_cert) { + /* Send empty client key exch message */ + n = 0; + } else { + /* + * First check the size of encoding and allocate memory + * accordingly. + */ + encoded_pt_len = + EC_POINT_point2oct(srvr_group, + EC_KEY_get0_public_key(clnt_ecdh), + POINT_CONVERSION_UNCOMPRESSED, + NULL, 0, NULL); + + encodedPoint = (unsigned char *) + OPENSSL_malloc(encoded_pt_len * sizeof(unsigned char)); + bn_ctx = BN_CTX_new(); + if ((encodedPoint == NULL) || (bn_ctx == NULL)) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_MALLOC_FAILURE); + goto err; + } + + /* Encode the public key */ + n = EC_POINT_point2oct(srvr_group, + EC_KEY_get0_public_key(clnt_ecdh), + POINT_CONVERSION_UNCOMPRESSED, + encodedPoint, encoded_pt_len, bn_ctx); + + *p = n; /* length of encoded point */ + /* Encoded point will be copied here */ + p += 1; + /* copy the point */ + memcpy((unsigned char *)p, encodedPoint, n); + /* increment n to account for length field */ + n += 1; + } + + /* Free allocated memory */ + BN_CTX_free(bn_ctx); + if (encodedPoint != NULL) + OPENSSL_free(encodedPoint); + if (clnt_ecdh != NULL) + EC_KEY_free(clnt_ecdh); + EVP_PKEY_free(srvr_pub_pkey); + } +#endif /* !OPENSSL_NO_ECDH */ + else if (alg_k & SSL_kGOST) { + /* GOST key exchange message creation */ + EVP_PKEY_CTX *pkey_ctx; + X509 *peer_cert; + size_t msglen; + unsigned int md_len; + int keytype; + unsigned char premaster_secret[32], shared_ukm[32], tmp[256]; + EVP_MD_CTX *ukm_hash; + EVP_PKEY *pub_key; + + /* + * Get server sertificate PKEY and create ctx from it + */ + peer_cert = + s->session-> + sess_cert->peer_pkeys[(keytype = SSL_PKEY_GOST01)].x509; + if (!peer_cert) + peer_cert = + s->session-> + sess_cert->peer_pkeys[(keytype = SSL_PKEY_GOST94)].x509; + if (!peer_cert) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER); + goto err; + } + + pkey_ctx = EVP_PKEY_CTX_new(pub_key = + X509_get_pubkey(peer_cert), NULL); + if (pkey_ctx == NULL) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_MALLOC_FAILURE); + goto err; + } + /* + * 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 */ + + if (pkey_ctx == NULL + || EVP_PKEY_encrypt_init(pkey_ctx) <= 0 + /* Generate session key */ + || RAND_bytes(premaster_secret, 32) <= 0) { + EVP_PKEY_CTX_free(pkey_ctx); + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } + /* + * If we have client certificate, use its secret as peer key + */ + if (s->s3->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 (EVP_DigestInit(ukm_hash, + EVP_get_digestbynid(NID_id_GostR3411_94)) <= 0 + || EVP_DigestUpdate(ukm_hash, s->s3->client_random, + SSL3_RANDOM_SIZE) <= 0 + || EVP_DigestUpdate(ukm_hash, s->s3->server_random, + SSL3_RANDOM_SIZE) <= 0 + || EVP_DigestFinal_ex(ukm_hash, shared_ukm, &md_len) <= 0) { + EVP_MD_CTX_destroy(ukm_hash); + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } + 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 + */ + *(p++) = V_ASN1_SEQUENCE | V_ASN1_CONSTRUCTED; + 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 (msglen >= 0x80) { + *(p++) = 0x81; + *(p++) = msglen & 0xff; + n = msglen + 3; + } else { + *(p++) = msglen & 0xff; + n = msglen + 2; + } + memcpy(p, tmp, msglen); + /* 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->ssl3_enc->generate_master_secret(s, + s-> + session->master_key, + premaster_secret, + 32); + EVP_PKEY_free(pub_key); + + } +#ifndef OPENSSL_NO_SRP + else if (alg_k & SSL_kSRP) { + if (s->srp_ctx.A != NULL) { + /* send off the data */ + n = BN_num_bytes(s->srp_ctx.A); + s2n(n, p); + BN_bn2bin(s->srp_ctx.A, p); + n += 2; + } else { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } + if (s->session->srp_username != NULL) + OPENSSL_free(s->session->srp_username); + s->session->srp_username = BUF_strdup(s->srp_ctx.login); + if (s->session->srp_username == NULL) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_MALLOC_FAILURE); + goto err; + } + + if ((s->session->master_key_length = + SRP_generate_client_master_secret(s, + s->session->master_key)) < + 0) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } + } +#endif +#ifndef OPENSSL_NO_PSK + else if (alg_k & SSL_kPSK) { + /* + * The callback needs PSK_MAX_IDENTITY_LEN + 1 bytes to return a + * \0-terminated identity. The last byte is for us for simulating + * strnlen. + */ + char identity[PSK_MAX_IDENTITY_LEN + 2]; + size_t identity_len; + unsigned char *t = NULL; + unsigned char psk_or_pre_ms[PSK_MAX_PSK_LEN * 2 + 4]; + unsigned int pre_ms_len = 0, psk_len = 0; + int psk_err = 1; + + n = 0; + if (s->psk_client_callback == NULL) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + SSL_R_PSK_NO_CLIENT_CB); + goto err; + } + + memset(identity, 0, sizeof(identity)); + psk_len = s->psk_client_callback(s, s->session->psk_identity_hint, + identity, sizeof(identity) - 1, + psk_or_pre_ms, + sizeof(psk_or_pre_ms)); + if (psk_len > PSK_MAX_PSK_LEN) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto psk_err; + } else if (psk_len == 0) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + SSL_R_PSK_IDENTITY_NOT_FOUND); + goto psk_err; + } + identity[PSK_MAX_IDENTITY_LEN + 1] = '\0'; + identity_len = strlen(identity); + if (identity_len > PSK_MAX_IDENTITY_LEN) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto psk_err; + } + /* create PSK pre_master_secret */ + pre_ms_len = 2 + psk_len + 2 + psk_len; + t = psk_or_pre_ms; + memmove(psk_or_pre_ms + psk_len + 4, psk_or_pre_ms, psk_len); + s2n(psk_len, t); + memset(t, 0, psk_len); + t += psk_len; + s2n(psk_len, t); + + if (s->session->psk_identity_hint != NULL) + OPENSSL_free(s->session->psk_identity_hint); + s->session->psk_identity_hint = + BUF_strdup(s->ctx->psk_identity_hint); + if (s->ctx->psk_identity_hint != NULL + && s->session->psk_identity_hint == NULL) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_MALLOC_FAILURE); + goto psk_err; + } + + if (s->session->psk_identity != NULL) + OPENSSL_free(s->session->psk_identity); + s->session->psk_identity = BUF_strdup(identity); + if (s->session->psk_identity == NULL) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_MALLOC_FAILURE); + goto psk_err; + } + + s->session->master_key_length = + s->method->ssl3_enc->generate_master_secret(s, + s-> + session->master_key, + psk_or_pre_ms, + pre_ms_len); + s2n(identity_len, p); + memcpy(p, identity, identity_len); + n = 2 + identity_len; + psk_err = 0; + psk_err: + OPENSSL_cleanse(identity, sizeof(identity)); + OPENSSL_cleanse(psk_or_pre_ms, sizeof(psk_or_pre_ms)); + if (psk_err != 0) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); + goto err; + } + } +#endif + 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; + } + + ssl_set_handshake_header(s, SSL3_MT_CLIENT_KEY_EXCHANGE, n); + s->state = SSL3_ST_CW_KEY_EXCH_B; + } + + /* SSL3_ST_CW_KEY_EXCH_B */ + return ssl_do_write(s); + err: +#ifndef OPENSSL_NO_ECDH + BN_CTX_free(bn_ctx); + if (encodedPoint != NULL) + OPENSSL_free(encodedPoint); + if (clnt_ecdh != NULL) + EC_KEY_free(clnt_ecdh); + EVP_PKEY_free(srvr_pub_pkey); +#endif + s->state = SSL_ST_ERR; + 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->state == SSL3_ST_CW_CERT_VRFY_A) { + p = ssl_handshake_start(s); + pkey = s->cert->key->privatekey; +/* Create context from key and test if sha1 is allowed as digest */ + pctx = EVP_PKEY_CTX_new(pkey, NULL); + if (pctx == NULL || EVP_PKEY_sign_init(pctx) <= 0) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR); + goto err; + } + if (EVP_PKEY_CTX_set_signature_md(pctx, EVP_sha1()) > 0) { + if (!SSL_USE_SIGALGS(s)) + s->method->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(s->s3->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; +#ifdef SSL_DEBUG + fprintf(stderr, "Using TLS 1.2 with client alg %s\n", + EVP_MD_name(md)); +#endif + 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 (!ssl3_digest_cached_records(s)) + goto err; + } else +#ifndef OPENSSL_NO_RSA + if (pkey->type == EVP_PKEY_RSA) { + s->method->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 +#endif +#ifndef OPENSSL_NO_DSA + 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 +#endif +#ifndef OPENSSL_NO_ECDSA + 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; + } else +#endif + if (pkey->type == NID_id_GostR3410_94 + || pkey->type == NID_id_GostR3410_2001) { + unsigned char signbuf[64]; + int i; + size_t sigsize = 64; + s->method->ssl3_enc->cert_verify_mac(s, + NID_id_GostR3411_94, data); + if (EVP_PKEY_sign(pctx, signbuf, &sigsize, data, 32) <= 0) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR); + goto err; + } + for (i = 63, j = 0; i >= 0; j++, i--) { + p[2 + j] = signbuf[i]; + } + s2n(j, p); + n = j + 2; + } else { + SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR); + goto err; + } + ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE_VERIFY, n); + s->state = SSL3_ST_CW_CERT_VRFY_B; + } + EVP_MD_CTX_cleanup(&mctx); + EVP_PKEY_CTX_free(pctx); + return ssl_do_write(s); + err: + EVP_MD_CTX_cleanup(&mctx); + EVP_PKEY_CTX_free(pctx); + s->state = SSL_ST_ERR; + return (-1); +} + +/* + * Check a certificate can be used for client authentication. Currently check + * cert exists, if we have a suitable digest for TLS 1.2 if static DH client + * certificates can be used and optionally checks suitability for Suite B. + */ +static int ssl3_check_client_certificate(SSL *s) +{ + unsigned long alg_k; + if (!s->cert || !s->cert->key->x509 || !s->cert->key->privatekey) + return 0; + /* If no suitable signature algorithm can't use certificate */ + if (SSL_USE_SIGALGS(s) && !s->cert->key->digest) + return 0; + /* + * If strict mode check suitability of chain before using it. This also + * adjusts suite B digest if necessary. + */ + if (s->cert->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT && + !tls1_check_chain(s, NULL, NULL, NULL, -2)) + return 0; + alg_k = s->s3->tmp.new_cipher->algorithm_mkey; + /* See if we can use client certificate for fixed DH */ + if (alg_k & (SSL_kDHr | SSL_kDHd)) { + SESS_CERT *scert = s->session->sess_cert; + int i = scert->peer_cert_type; + EVP_PKEY *clkey = NULL, *spkey = NULL; + clkey = s->cert->key->privatekey; + /* If client key not DH assume it can be used */ + if (EVP_PKEY_id(clkey) != EVP_PKEY_DH) + return 1; + if (i >= 0) + spkey = X509_get_pubkey(scert->peer_pkeys[i].x509); + if (spkey) { + /* Compare server and client parameters */ + i = EVP_PKEY_cmp_parameters(clkey, spkey); + EVP_PKEY_free(spkey); + if (i != 1) + return 0; + } + s->s3->flags |= TLS1_FLAGS_SKIP_CERT_VERIFY; + } + return 1; +} + +int ssl3_send_client_certificate(SSL *s) +{ + X509 *x509 = NULL; + EVP_PKEY *pkey = NULL; + int i; + + if (s->state == SSL3_ST_CW_CERT_A) { + /* Let cert callback update client certificates if required */ + if (s->cert->cert_cb) { + i = s->cert->cert_cb(s, s->cert->cert_cb_arg); + if (i < 0) { + s->rwstate = SSL_X509_LOOKUP; + return -1; + } + if (i == 0) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + s->state = SSL_ST_ERR; + return 0; + } + s->rwstate = SSL_NOTHING; + } + if (ssl3_check_client_certificate(s)) + s->state = SSL3_ST_CW_CERT_C; + else + s->state = SSL3_ST_CW_CERT_B; + } + + /* We need to get a client cert */ + if (s->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->rwstate = SSL_X509_LOOKUP; + return (-1); + } + s->rwstate = SSL_NOTHING; + if ((i == 1) && (pkey != NULL) && (x509 != NULL)) { + s->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); + } + + if (x509 != NULL) + X509_free(x509); + if (pkey != NULL) + EVP_PKEY_free(pkey); + if (i && !ssl3_check_client_certificate(s)) + i = 0; + if (i == 0) { + if (s->version == SSL3_VERSION) { + s->s3->tmp.cert_req = 0; + ssl3_send_alert(s, SSL3_AL_WARNING, SSL_AD_NO_CERTIFICATE); + return (1); + } else { + s->s3->tmp.cert_req = 2; + } + } + + /* Ok, we have a cert */ + s->state = SSL3_ST_CW_CERT_C; + } + + if (s->state == SSL3_ST_CW_CERT_C) { + s->state = SSL3_ST_CW_CERT_D; + if (!ssl3_output_cert_chain(s, + (s->s3->tmp.cert_req == + 2) ? NULL : s->cert->key)) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_CERTIFICATE, ERR_R_INTERNAL_ERROR); + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + s->state = SSL_ST_ERR; + return 0; + } + } + /* SSL3_ST_CW_CERT_D */ + return ssl_do_write(s); +} + +#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; + int pkey_bits; + SESS_CERT *sc; +#ifndef OPENSSL_NO_RSA + RSA *rsa; +#endif +#ifndef OPENSSL_NO_DH + DH *dh; +#endif + int al = SSL_AD_HANDSHAKE_FAILURE; + + alg_k = s->s3->tmp.new_cipher->algorithm_mkey; + alg_a = s->s3->tmp.new_cipher->algorithm_auth; + + /* we don't have a certificate */ + if ((alg_a & (SSL_aNULL | SSL_aKRB5)) || (alg_k & SSL_kPSK)) + return (1); + + sc = s->session->sess_cert; + if (sc == NULL) { + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, ERR_R_INTERNAL_ERROR); + goto err; + } +#ifndef OPENSSL_NO_RSA + rsa = s->session->sess_cert->peer_rsa_tmp; +#endif +#ifndef OPENSSL_NO_DH + dh = s->session->sess_cert->peer_dh_tmp; +#endif + + /* This is the passed certificate */ + + idx = sc->peer_cert_type; +#ifndef OPENSSL_NO_ECDH + 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; + } + } else if (alg_a & SSL_aECDSA) { + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, + SSL_R_MISSING_ECDSA_SIGNING_CERT); + goto f_err; + } else if (alg_k & (SSL_kECDHr | SSL_kECDHe)) { + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, SSL_R_MISSING_ECDH_CERT); + goto f_err; + } +#endif + pkey = X509_get_pubkey(sc->peer_pkeys[idx].x509); + pkey_bits = EVP_PKEY_bits(pkey); + 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; + } +#ifndef OPENSSL_NO_DSA + 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; + } +#endif +#ifndef OPENSSL_NO_RSA + if (alg_k & SSL_kRSA) { + if (!SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && + !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; + } else if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)) { + if (pkey_bits <= SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) { + if (!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 (rsa != NULL) { + /* server key exchange is not allowed. */ + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, ERR_R_INTERNAL_ERROR); + goto f_err; + } + } + } + } +#endif +#ifndef OPENSSL_NO_DH + if ((alg_k & SSL_kEDH) && dh == NULL) { + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, ERR_R_INTERNAL_ERROR); + goto f_err; + } + if ((alg_k & SSL_kDHr) && !SSL_USE_SIGALGS(s) && + !has_bits(i, EVP_PK_DH | EVP_PKS_RSA)) { + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, + SSL_R_MISSING_DH_RSA_CERT); + goto f_err; + } +# ifndef OPENSSL_NO_DSA + if ((alg_k & SSL_kDHd) && !SSL_USE_SIGALGS(s) && + !has_bits(i, EVP_PK_DH | EVP_PKS_DSA)) { + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, + SSL_R_MISSING_DH_DSA_CERT); + goto f_err; + } +# endif + + if (alg_k & (SSL_kDHE | SSL_kDHr | SSL_kDHd)) { + int dh_size; + if (alg_k & SSL_kDHE) { + dh_size = BN_num_bits(dh->p); + } else { + DH *dh_srvr = get_server_static_dh_key(sc); + if (dh_srvr == NULL) + goto f_err; + dh_size = BN_num_bits(dh_srvr->p); + DH_free(dh_srvr); + } + + if ((!SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && dh_size < 1024) + || (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && dh_size < 512)) { + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, SSL_R_DH_KEY_TOO_SMALL); + goto f_err; + } + } +#endif /* !OPENSSL_NO_DH */ + + if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && + pkey_bits > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) { +#ifndef OPENSSL_NO_RSA + if (alg_k & SSL_kRSA) { + if (rsa == NULL) { + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, + SSL_R_MISSING_EXPORT_TMP_RSA_KEY); + goto f_err; + } else if (BN_num_bits(rsa->n) > + SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) { + /* We have a temporary RSA key but it's too large. */ + al = SSL_AD_EXPORT_RESTRICTION; + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, + SSL_R_MISSING_EXPORT_TMP_RSA_KEY); + goto f_err; + } + } else +#endif +#ifndef OPENSSL_NO_DH + if (alg_k & SSL_kDHE) { + if (BN_num_bits(dh->p) > + SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) { + /* We have a temporary DH key but it's too large. */ + al = SSL_AD_EXPORT_RESTRICTION; + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, + SSL_R_MISSING_EXPORT_TMP_DH_KEY); + goto f_err; + } + } else if (alg_k & (SSL_kDHr | SSL_kDHd)) { + /* The cert should have had an export DH key. */ + al = SSL_AD_EXPORT_RESTRICTION; + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, + SSL_R_MISSING_EXPORT_TMP_DH_KEY); + goto f_err; + } else +#endif + { + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM, + SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE); + goto f_err; + } + } + return (1); + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + err: + return (0); +} + +#ifndef OPENSSL_NO_TLSEXT +/* + * Normally, we can tell if the server is resuming the session from + * the session ID. EAP-FAST (RFC 4851), however, relies on the next server + * message after the ServerHello to determine if the server is resuming. + * Therefore, we allow EAP-FAST to peek ahead. + * ssl3_check_finished returns 1 if we are resuming from an external + * pre-shared secret, we have a "ticket" and the next server handshake message + * is Finished; and 0 otherwise. It returns -1 upon an error. + */ +static int ssl3_check_finished(SSL *s) +{ + int ok = 0; + + if (s->version < TLS1_VERSION || !s->tls_session_secret_cb || + !s->session->tlsext_tick) + return 0; + + /* Need to permit this temporarily, in case the next message is Finished. */ + s->s3->flags |= SSL3_FLAGS_CCS_OK; + /* + * This function is called when we might get a Certificate message instead, + * so permit appropriate message length. + * We ignore the return value as we're only interested in the message type + * and not its length. + */ + s->method->ssl_get_message(s, + SSL3_ST_CR_CERT_A, + SSL3_ST_CR_CERT_B, + -1, s->max_cert_list, &ok); + s->s3->flags &= ~SSL3_FLAGS_CCS_OK; + + if (!ok) + return -1; + + s->s3->tmp.reuse_message = 1; + + if (s->s3->tmp.message_type == SSL3_MT_FINISHED) + return 1; + + /* If we're not done, then the CCS arrived early and we should bail. */ + if (s->s3->change_cipher_spec) { + SSLerr(SSL_F_SSL3_CHECK_FINISHED, SSL_R_CCS_RECEIVED_EARLY); + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); + return -1; + } + + return 0; +} + +# ifndef OPENSSL_NO_NEXTPROTONEG +int ssl3_send_next_proto(SSL *s) +{ + unsigned int len, padding_len; + unsigned char *d; + + if (s->state == SSL3_ST_CW_NEXT_PROTO_A) { + len = s->next_proto_negotiated_len; + padding_len = 32 - ((len + 2) % 32); + d = (unsigned char *)s->init_buf->data; + d[4] = len; + memcpy(d + 5, s->next_proto_negotiated, len); + d[5 + len] = padding_len; + memset(d + 6 + len, 0, padding_len); + *(d++) = SSL3_MT_NEXT_PROTO; + l2n3(2 + len + padding_len, d); + s->state = SSL3_ST_CW_NEXT_PROTO_B; + s->init_num = 4 + 2 + len + padding_len; + s->init_off = 0; + } + + return ssl3_do_write(s, SSL3_RT_HANDSHAKE); +} +#endif /* !OPENSSL_NO_NEXTPROTONEG */ +#endif /* !OPENSSL_NO_TLSEXT */ + +int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey) +{ + int i = 0; +#ifndef OPENSSL_NO_ENGINE + if (s->ctx->client_cert_engine) { + i = ENGINE_load_ssl_client_cert(s->ctx->client_cert_engine, s, + SSL_get_client_CA_list(s), + px509, ppkey, NULL, NULL, NULL); + if (i != 0) + return i; + } +#endif + if (s->ctx->client_cert_cb) + i = s->ctx->client_cert_cb(s, px509, ppkey); + return i; +} diff --git a/thirdparty/openssl/ssl/s3_enc.c b/thirdparty/openssl/ssl/s3_enc.c new file mode 100644 index 0000000000..47a0ec9fe0 --- /dev/null +++ b/thirdparty/openssl/ssl/s3_enc.c @@ -0,0 +1,970 @@ +/* ssl/s3_enc.c */ +/* 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 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 <stdio.h> +#include "ssl_locl.h" +#include <openssl/evp.h> +#include <openssl/md5.h> + +static unsigned char ssl3_pad_1[48] = { + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36 +}; + +static unsigned char ssl3_pad_2[48] = { + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, + 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c +}; + +static int ssl3_handshake_mac(SSL *s, int md_nid, + const char *sender, int len, unsigned char *p); +static int ssl3_generate_key_block(SSL *s, unsigned char *km, int num) +{ + EVP_MD_CTX m5; + EVP_MD_CTX s1; + unsigned char buf[16], smd[SHA_DIGEST_LENGTH]; + unsigned char c = 'A'; + unsigned int i, j, k; + +#ifdef CHARSET_EBCDIC + c = os_toascii[c]; /* 'A' in ASCII */ +#endif + k = 0; + EVP_MD_CTX_init(&m5); + EVP_MD_CTX_set_flags(&m5, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); + EVP_MD_CTX_init(&s1); + for (i = 0; (int)i < num; i += MD5_DIGEST_LENGTH) { + k++; + if (k > sizeof buf) { + /* bug: 'buf' is too small for this ciphersuite */ + SSLerr(SSL_F_SSL3_GENERATE_KEY_BLOCK, ERR_R_INTERNAL_ERROR); + return 0; + } + + for (j = 0; j < k; j++) + buf[j] = c; + c++; + EVP_DigestInit_ex(&s1, EVP_sha1(), NULL); + EVP_DigestUpdate(&s1, buf, k); + EVP_DigestUpdate(&s1, s->session->master_key, + s->session->master_key_length); + EVP_DigestUpdate(&s1, s->s3->server_random, SSL3_RANDOM_SIZE); + EVP_DigestUpdate(&s1, s->s3->client_random, SSL3_RANDOM_SIZE); + EVP_DigestFinal_ex(&s1, smd, NULL); + + EVP_DigestInit_ex(&m5, EVP_md5(), NULL); + EVP_DigestUpdate(&m5, s->session->master_key, + s->session->master_key_length); + EVP_DigestUpdate(&m5, smd, SHA_DIGEST_LENGTH); + if ((int)(i + MD5_DIGEST_LENGTH) > num) { + EVP_DigestFinal_ex(&m5, smd, NULL); + memcpy(km, smd, (num - i)); + } else + EVP_DigestFinal_ex(&m5, km, NULL); + + km += MD5_DIGEST_LENGTH; + } + OPENSSL_cleanse(smd, SHA_DIGEST_LENGTH); + EVP_MD_CTX_cleanup(&m5); + EVP_MD_CTX_cleanup(&s1); + return 1; +} + +int ssl3_change_cipher_state(SSL *s, int which) +{ + unsigned char *p, *mac_secret; + unsigned char exp_key[EVP_MAX_KEY_LENGTH]; + unsigned char exp_iv[EVP_MAX_IV_LENGTH]; + unsigned char *ms, *key, *iv, *er1, *er2; + EVP_CIPHER_CTX *dd; + const EVP_CIPHER *c; +#ifndef OPENSSL_NO_COMP + COMP_METHOD *comp; +#endif + const EVP_MD *m; + EVP_MD_CTX md; + int is_exp, n, i, j, k, cl; + int reuse_dd = 0; + + is_exp = SSL_C_IS_EXPORT(s->s3->tmp.new_cipher); + c = s->s3->tmp.new_sym_enc; + m = s->s3->tmp.new_hash; + /* m == NULL will lead to a crash later */ + OPENSSL_assert(m); +#ifndef OPENSSL_NO_COMP + if (s->s3->tmp.new_compression == NULL) + comp = NULL; + else + comp = s->s3->tmp.new_compression->method; +#endif + + if (which & SSL3_CC_READ) { + if (s->enc_read_ctx != NULL) + reuse_dd = 1; + else if ((s->enc_read_ctx = + OPENSSL_malloc(sizeof(EVP_CIPHER_CTX))) == NULL) + goto err; + else + /* + * make sure it's intialized in case we exit later with an error + */ + EVP_CIPHER_CTX_init(s->enc_read_ctx); + dd = s->enc_read_ctx; + + if (ssl_replace_hash(&s->read_hash, m) == NULL) { + SSLerr(SSL_F_SSL3_CHANGE_CIPHER_STATE, ERR_R_INTERNAL_ERROR); + goto err2; + } +#ifndef OPENSSL_NO_COMP + /* COMPRESS */ + if (s->expand != NULL) { + COMP_CTX_free(s->expand); + s->expand = NULL; + } + if (comp != NULL) { + s->expand = COMP_CTX_new(comp); + if (s->expand == NULL) { + SSLerr(SSL_F_SSL3_CHANGE_CIPHER_STATE, + SSL_R_COMPRESSION_LIBRARY_ERROR); + goto err2; + } + if (s->s3->rrec.comp == NULL) + s->s3->rrec.comp = (unsigned char *) + OPENSSL_malloc(SSL3_RT_MAX_PLAIN_LENGTH); + if (s->s3->rrec.comp == NULL) + goto err; + } +#endif + memset(&(s->s3->read_sequence[0]), 0, 8); + mac_secret = &(s->s3->read_mac_secret[0]); + } else { + if (s->enc_write_ctx != NULL) + reuse_dd = 1; + else if ((s->enc_write_ctx = + OPENSSL_malloc(sizeof(EVP_CIPHER_CTX))) == NULL) + goto err; + else + /* + * make sure it's intialized in case we exit later with an error + */ + EVP_CIPHER_CTX_init(s->enc_write_ctx); + dd = s->enc_write_ctx; + if (ssl_replace_hash(&s->write_hash, m) == NULL) { + SSLerr(SSL_F_SSL3_CHANGE_CIPHER_STATE, ERR_R_INTERNAL_ERROR); + goto err2; + } +#ifndef OPENSSL_NO_COMP + /* COMPRESS */ + if (s->compress != NULL) { + COMP_CTX_free(s->compress); + s->compress = NULL; + } + if (comp != NULL) { + s->compress = COMP_CTX_new(comp); + if (s->compress == NULL) { + SSLerr(SSL_F_SSL3_CHANGE_CIPHER_STATE, + SSL_R_COMPRESSION_LIBRARY_ERROR); + goto err2; + } + } +#endif + memset(&(s->s3->write_sequence[0]), 0, 8); + mac_secret = &(s->s3->write_mac_secret[0]); + } + + if (reuse_dd) + EVP_CIPHER_CTX_cleanup(dd); + + p = s->s3->tmp.key_block; + i = EVP_MD_size(m); + if (i < 0) + goto err2; + cl = EVP_CIPHER_key_length(c); + j = is_exp ? (cl < SSL_C_EXPORT_KEYLENGTH(s->s3->tmp.new_cipher) ? + cl : SSL_C_EXPORT_KEYLENGTH(s->s3->tmp.new_cipher)) : cl; + /* Was j=(is_exp)?5:EVP_CIPHER_key_length(c); */ + k = EVP_CIPHER_iv_length(c); + if ((which == SSL3_CHANGE_CIPHER_CLIENT_WRITE) || + (which == SSL3_CHANGE_CIPHER_SERVER_READ)) { + ms = &(p[0]); + n = i + i; + key = &(p[n]); + n += j + j; + iv = &(p[n]); + n += k + k; + er1 = &(s->s3->client_random[0]); + er2 = &(s->s3->server_random[0]); + } else { + n = i; + ms = &(p[n]); + n += i + j; + key = &(p[n]); + n += j + k; + iv = &(p[n]); + n += k; + er1 = &(s->s3->server_random[0]); + er2 = &(s->s3->client_random[0]); + } + + if (n > s->s3->tmp.key_block_length) { + SSLerr(SSL_F_SSL3_CHANGE_CIPHER_STATE, ERR_R_INTERNAL_ERROR); + goto err2; + } + + EVP_MD_CTX_init(&md); + memcpy(mac_secret, ms, i); + if (is_exp) { + /* + * In here I set both the read and write key/iv to the same value + * since only the correct one will be used :-). + */ + EVP_DigestInit_ex(&md, EVP_md5(), NULL); + EVP_DigestUpdate(&md, key, j); + EVP_DigestUpdate(&md, er1, SSL3_RANDOM_SIZE); + EVP_DigestUpdate(&md, er2, SSL3_RANDOM_SIZE); + EVP_DigestFinal_ex(&md, &(exp_key[0]), NULL); + key = &(exp_key[0]); + + if (k > 0) { + EVP_DigestInit_ex(&md, EVP_md5(), NULL); + EVP_DigestUpdate(&md, er1, SSL3_RANDOM_SIZE); + EVP_DigestUpdate(&md, er2, SSL3_RANDOM_SIZE); + EVP_DigestFinal_ex(&md, &(exp_iv[0]), NULL); + iv = &(exp_iv[0]); + } + } + + s->session->key_arg_length = 0; + + EVP_CipherInit_ex(dd, c, NULL, key, iv, (which & SSL3_CC_WRITE)); + +#ifdef OPENSSL_SSL_TRACE_CRYPTO + if (s->msg_callback) { + + int wh = which & SSL3_CC_WRITE ? + TLS1_RT_CRYPTO_WRITE : TLS1_RT_CRYPTO_READ; + s->msg_callback(2, s->version, wh | TLS1_RT_CRYPTO_MAC, + mac_secret, EVP_MD_size(m), s, s->msg_callback_arg); + if (c->key_len) + s->msg_callback(2, s->version, wh | TLS1_RT_CRYPTO_KEY, + key, c->key_len, s, s->msg_callback_arg); + if (k) { + s->msg_callback(2, s->version, wh | TLS1_RT_CRYPTO_IV, + iv, k, s, s->msg_callback_arg); + } + } +#endif + + OPENSSL_cleanse(&(exp_key[0]), sizeof(exp_key)); + OPENSSL_cleanse(&(exp_iv[0]), sizeof(exp_iv)); + EVP_MD_CTX_cleanup(&md); + return (1); + err: + SSLerr(SSL_F_SSL3_CHANGE_CIPHER_STATE, ERR_R_MALLOC_FAILURE); + err2: + return (0); +} + +int ssl3_setup_key_block(SSL *s) +{ + unsigned char *p; + const EVP_CIPHER *c; + const EVP_MD *hash; + int num; + int ret = 0; + SSL_COMP *comp; + + if (s->s3->tmp.key_block_length != 0) + return (1); + + if (!ssl_cipher_get_evp(s->session, &c, &hash, NULL, NULL, &comp)) { + SSLerr(SSL_F_SSL3_SETUP_KEY_BLOCK, SSL_R_CIPHER_OR_HASH_UNAVAILABLE); + return (0); + } + + s->s3->tmp.new_sym_enc = c; + s->s3->tmp.new_hash = hash; +#ifdef OPENSSL_NO_COMP + s->s3->tmp.new_compression = NULL; +#else + s->s3->tmp.new_compression = comp; +#endif + + num = EVP_MD_size(hash); + if (num < 0) + return 0; + + num = EVP_CIPHER_key_length(c) + num + EVP_CIPHER_iv_length(c); + num *= 2; + + ssl3_cleanup_key_block(s); + + if ((p = OPENSSL_malloc(num)) == NULL) + goto err; + + s->s3->tmp.key_block_length = num; + s->s3->tmp.key_block = p; + + ret = ssl3_generate_key_block(s, p, num); + + if (!(s->options & SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS)) { + /* + * enable vulnerability countermeasure for CBC ciphers with known-IV + * problem (http://www.openssl.org/~bodo/tls-cbc.txt) + */ + s->s3->need_empty_fragments = 1; + + if (s->session->cipher != NULL) { + if (s->session->cipher->algorithm_enc == SSL_eNULL) + s->s3->need_empty_fragments = 0; + +#ifndef OPENSSL_NO_RC4 + if (s->session->cipher->algorithm_enc == SSL_RC4) + s->s3->need_empty_fragments = 0; +#endif + } + } + + return ret; + + err: + SSLerr(SSL_F_SSL3_SETUP_KEY_BLOCK, ERR_R_MALLOC_FAILURE); + return (0); +} + +void ssl3_cleanup_key_block(SSL *s) +{ + if (s->s3->tmp.key_block != NULL) { + OPENSSL_cleanse(s->s3->tmp.key_block, s->s3->tmp.key_block_length); + OPENSSL_free(s->s3->tmp.key_block); + s->s3->tmp.key_block = NULL; + } + s->s3->tmp.key_block_length = 0; +} + +/*- + * ssl3_enc encrypts/decrypts the record in |s->wrec| / |s->rrec|, respectively. + * + * Returns: + * 0: (in non-constant time) if the record is publically invalid (i.e. too + * short etc). + * 1: if the record's padding is valid / the encryption was successful. + * -1: if the record's padding is invalid or, if sending, an internal error + * occured. + */ +int ssl3_enc(SSL *s, int send) +{ + SSL3_RECORD *rec; + EVP_CIPHER_CTX *ds; + unsigned long l; + int bs, i, mac_size = 0; + const EVP_CIPHER *enc; + + if (send) { + ds = s->enc_write_ctx; + rec = &(s->s3->wrec); + if (s->enc_write_ctx == NULL) + enc = NULL; + else + enc = EVP_CIPHER_CTX_cipher(s->enc_write_ctx); + } else { + ds = s->enc_read_ctx; + rec = &(s->s3->rrec); + if (s->enc_read_ctx == NULL) + enc = NULL; + else + enc = EVP_CIPHER_CTX_cipher(s->enc_read_ctx); + } + + if ((s->session == NULL) || (ds == NULL) || (enc == NULL)) { + memmove(rec->data, rec->input, rec->length); + rec->input = rec->data; + } else { + l = rec->length; + bs = EVP_CIPHER_block_size(ds->cipher); + + /* COMPRESS */ + + if ((bs != 1) && send) { + i = bs - ((int)l % bs); + + /* we need to add 'i-1' padding bytes */ + l += i; + /* + * the last of these zero bytes will be overwritten with the + * padding length. + */ + memset(&rec->input[rec->length], 0, i); + rec->length += i; + rec->input[l - 1] = (i - 1); + } + + if (!send) { + if (l == 0 || l % bs != 0) + return 0; + /* otherwise, rec->length >= bs */ + } + + if (EVP_Cipher(ds, rec->data, rec->input, l) < 1) + return -1; + + if (EVP_MD_CTX_md(s->read_hash) != NULL) + mac_size = EVP_MD_CTX_size(s->read_hash); + if ((bs != 1) && !send) + return ssl3_cbc_remove_padding(s, rec, bs, mac_size); + } + return (1); +} + +void ssl3_init_finished_mac(SSL *s) +{ + if (s->s3->handshake_buffer) + BIO_free(s->s3->handshake_buffer); + if (s->s3->handshake_dgst) + ssl3_free_digest_list(s); + s->s3->handshake_buffer = BIO_new(BIO_s_mem()); + (void)BIO_set_close(s->s3->handshake_buffer, BIO_CLOSE); +} + +void ssl3_free_digest_list(SSL *s) +{ + int i; + if (!s->s3->handshake_dgst) + return; + for (i = 0; i < SSL_MAX_DIGEST; i++) { + if (s->s3->handshake_dgst[i]) + EVP_MD_CTX_destroy(s->s3->handshake_dgst[i]); + } + OPENSSL_free(s->s3->handshake_dgst); + s->s3->handshake_dgst = NULL; +} + +void ssl3_finish_mac(SSL *s, const unsigned char *buf, int len) +{ + if (s->s3->handshake_buffer + && !(s->s3->flags & TLS1_FLAGS_KEEP_HANDSHAKE)) { + BIO_write(s->s3->handshake_buffer, (void *)buf, len); + } else { + int i; + for (i = 0; i < SSL_MAX_DIGEST; i++) { + if (s->s3->handshake_dgst[i] != NULL) + EVP_DigestUpdate(s->s3->handshake_dgst[i], buf, len); + } + } +} + +int ssl3_digest_cached_records(SSL *s) +{ + int i; + long mask; + const EVP_MD *md; + long hdatalen; + void *hdata; + + /* Allocate handshake_dgst array */ + ssl3_free_digest_list(s); + s->s3->handshake_dgst = + OPENSSL_malloc(SSL_MAX_DIGEST * sizeof(EVP_MD_CTX *)); + memset(s->s3->handshake_dgst, 0, SSL_MAX_DIGEST * sizeof(EVP_MD_CTX *)); + hdatalen = BIO_get_mem_data(s->s3->handshake_buffer, &hdata); + if (hdatalen <= 0) { + SSLerr(SSL_F_SSL3_DIGEST_CACHED_RECORDS, SSL_R_BAD_HANDSHAKE_LENGTH); + return 0; + } + + /* Loop through bitso of algorithm2 field and create MD_CTX-es */ + for (i = 0; ssl_get_handshake_digest(i, &mask, &md); i++) { + if ((mask & ssl_get_algorithm2(s)) && md) { + s->s3->handshake_dgst[i] = EVP_MD_CTX_create(); +#ifdef OPENSSL_FIPS + if (EVP_MD_nid(md) == NID_md5) { + EVP_MD_CTX_set_flags(s->s3->handshake_dgst[i], + EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); + } +#endif + EVP_DigestInit_ex(s->s3->handshake_dgst[i], md, NULL); + EVP_DigestUpdate(s->s3->handshake_dgst[i], hdata, hdatalen); + } else { + s->s3->handshake_dgst[i] = NULL; + } + } + if (!(s->s3->flags & TLS1_FLAGS_KEEP_HANDSHAKE)) { + /* Free handshake_buffer BIO */ + BIO_free(s->s3->handshake_buffer); + s->s3->handshake_buffer = NULL; + } + + return 1; +} + +int ssl3_cert_verify_mac(SSL *s, int md_nid, unsigned char *p) +{ + return (ssl3_handshake_mac(s, md_nid, NULL, 0, p)); +} + +int ssl3_final_finish_mac(SSL *s, + const char *sender, int len, unsigned char *p) +{ + int ret, sha1len; + ret = ssl3_handshake_mac(s, NID_md5, sender, len, p); + if (ret == 0) + return 0; + + p += ret; + + sha1len = ssl3_handshake_mac(s, NID_sha1, sender, len, p); + if (sha1len == 0) + return 0; + + ret += sha1len; + return (ret); +} + +static int ssl3_handshake_mac(SSL *s, int md_nid, + const char *sender, int len, unsigned char *p) +{ + unsigned int ret; + int npad, n; + unsigned int i; + unsigned char md_buf[EVP_MAX_MD_SIZE]; + EVP_MD_CTX ctx, *d = NULL; + + if (s->s3->handshake_buffer) + if (!ssl3_digest_cached_records(s)) + return 0; + + /* + * Search for digest of specified type in the handshake_dgst array + */ + for (i = 0; i < SSL_MAX_DIGEST; i++) { + if (s->s3->handshake_dgst[i] + && EVP_MD_CTX_type(s->s3->handshake_dgst[i]) == md_nid) { + d = s->s3->handshake_dgst[i]; + break; + } + } + if (!d) { + SSLerr(SSL_F_SSL3_HANDSHAKE_MAC, SSL_R_NO_REQUIRED_DIGEST); + return 0; + } + EVP_MD_CTX_init(&ctx); + EVP_MD_CTX_set_flags(&ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); + EVP_MD_CTX_copy_ex(&ctx, d); + n = EVP_MD_CTX_size(&ctx); + if (n < 0) + return 0; + + npad = (48 / n) * n; + if ((sender != NULL && EVP_DigestUpdate(&ctx, sender, len) <= 0) + || EVP_DigestUpdate(&ctx, s->session->master_key, + s->session->master_key_length) <= 0 + || EVP_DigestUpdate(&ctx, ssl3_pad_1, npad) <= 0 + || EVP_DigestFinal_ex(&ctx, md_buf, &i) <= 0 + + || EVP_DigestInit_ex(&ctx, EVP_MD_CTX_md(&ctx), NULL) <= 0 + || EVP_DigestUpdate(&ctx, s->session->master_key, + s->session->master_key_length) <= 0 + || EVP_DigestUpdate(&ctx, ssl3_pad_2, npad) <= 0 + || EVP_DigestUpdate(&ctx, md_buf, i) <= 0 + || EVP_DigestFinal_ex(&ctx, p, &ret) <= 0) { + SSLerr(SSL_F_SSL3_HANDSHAKE_MAC, ERR_R_INTERNAL_ERROR); + ret = 0; + } + + EVP_MD_CTX_cleanup(&ctx); + + return ((int)ret); +} + +int n_ssl3_mac(SSL *ssl, unsigned char *md, int send) +{ + SSL3_RECORD *rec; + unsigned char *mac_sec, *seq; + EVP_MD_CTX md_ctx; + const EVP_MD_CTX *hash; + unsigned char *p, rec_char; + size_t md_size, orig_len; + int npad; + int t; + + if (send) { + rec = &(ssl->s3->wrec); + mac_sec = &(ssl->s3->write_mac_secret[0]); + seq = &(ssl->s3->write_sequence[0]); + hash = ssl->write_hash; + } else { + rec = &(ssl->s3->rrec); + mac_sec = &(ssl->s3->read_mac_secret[0]); + seq = &(ssl->s3->read_sequence[0]); + hash = ssl->read_hash; + } + + t = EVP_MD_CTX_size(hash); + if (t < 0) + return -1; + md_size = t; + npad = (48 / md_size) * md_size; + + /* + * kludge: ssl3_cbc_remove_padding passes padding length in rec->type + */ + orig_len = rec->length + md_size + ((unsigned int)rec->type >> 8); + rec->type &= 0xff; + + if (!send && + EVP_CIPHER_CTX_mode(ssl->enc_read_ctx) == EVP_CIPH_CBC_MODE && + ssl3_cbc_record_digest_supported(hash)) { + /* + * This is a CBC-encrypted record. We must avoid leaking any + * timing-side channel information about how many blocks of data we + * are hashing because that gives an attacker a timing-oracle. + */ + + /*- + * npad is, at most, 48 bytes and that's with MD5: + * 16 + 48 + 8 (sequence bytes) + 1 + 2 = 75. + * + * With SHA-1 (the largest hash speced for SSLv3) the hash size + * goes up 4, but npad goes down by 8, resulting in a smaller + * total size. + */ + unsigned char header[75]; + unsigned j = 0; + memcpy(header + j, mac_sec, md_size); + j += md_size; + memcpy(header + j, ssl3_pad_1, npad); + j += npad; + memcpy(header + j, seq, 8); + j += 8; + header[j++] = rec->type; + header[j++] = rec->length >> 8; + header[j++] = rec->length & 0xff; + + /* Final param == is SSLv3 */ + if (ssl3_cbc_digest_record(hash, + md, &md_size, + header, rec->input, + rec->length + md_size, orig_len, + mac_sec, md_size, 1) <= 0) + return -1; + } else { + unsigned int md_size_u; + /* Chop the digest off the end :-) */ + EVP_MD_CTX_init(&md_ctx); + + rec_char = rec->type; + p = md; + s2n(rec->length, p); + if (EVP_MD_CTX_copy_ex(&md_ctx, hash) <= 0 + || EVP_DigestUpdate(&md_ctx, mac_sec, md_size) <= 0 + || EVP_DigestUpdate(&md_ctx, ssl3_pad_1, npad) <= 0 + || EVP_DigestUpdate(&md_ctx, seq, 8) <= 0 + || EVP_DigestUpdate(&md_ctx, &rec_char, 1) <= 0 + || EVP_DigestUpdate(&md_ctx, md, 2) <= 0 + || EVP_DigestUpdate(&md_ctx, rec->input, rec->length) <= 0 + || EVP_DigestFinal_ex(&md_ctx, md, NULL) <= 0 + || EVP_MD_CTX_copy_ex(&md_ctx, hash) <= 0 + || EVP_DigestUpdate(&md_ctx, mac_sec, md_size) <= 0 + || EVP_DigestUpdate(&md_ctx, ssl3_pad_2, npad) <= 0 + || EVP_DigestUpdate(&md_ctx, md, md_size) <= 0 + || EVP_DigestFinal_ex(&md_ctx, md, &md_size_u) <= 0) { + EVP_MD_CTX_cleanup(&md_ctx); + return -1; + } + md_size = md_size_u; + + EVP_MD_CTX_cleanup(&md_ctx); + } + + ssl3_record_sequence_update(seq); + return (md_size); +} + +void ssl3_record_sequence_update(unsigned char *seq) +{ + int i; + + for (i = 7; i >= 0; i--) { + ++seq[i]; + if (seq[i] != 0) + break; + } +} + +int ssl3_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p, + int len) +{ + static const unsigned char *salt[3] = { +#ifndef CHARSET_EBCDIC + (const unsigned char *)"A", + (const unsigned char *)"BB", + (const unsigned char *)"CCC", +#else + (const unsigned char *)"\x41", + (const unsigned char *)"\x42\x42", + (const unsigned char *)"\x43\x43\x43", +#endif + }; + unsigned char buf[EVP_MAX_MD_SIZE]; + EVP_MD_CTX ctx; + int i, ret = 0; + unsigned int n; +#ifdef OPENSSL_SSL_TRACE_CRYPTO + unsigned char *tmpout = out; +#endif + + EVP_MD_CTX_init(&ctx); + for (i = 0; i < 3; i++) { + if (EVP_DigestInit_ex(&ctx, s->ctx->sha1, NULL) <= 0 + || EVP_DigestUpdate(&ctx, salt[i], + strlen((const char *)salt[i])) <= 0 + || EVP_DigestUpdate(&ctx, p, len) <= 0 + || EVP_DigestUpdate(&ctx, &(s->s3->client_random[0]), + SSL3_RANDOM_SIZE) <= 0 + || EVP_DigestUpdate(&ctx, &(s->s3->server_random[0]), + SSL3_RANDOM_SIZE) <= 0 + || EVP_DigestFinal_ex(&ctx, buf, &n) <= 0 + + || EVP_DigestInit_ex(&ctx, s->ctx->md5, NULL) <= 0 + || EVP_DigestUpdate(&ctx, p, len) <= 0 + || EVP_DigestUpdate(&ctx, buf, n) <= 0 + || EVP_DigestFinal_ex(&ctx, out, &n) <= 0) { + SSLerr(SSL_F_SSL3_GENERATE_MASTER_SECRET, ERR_R_INTERNAL_ERROR); + ret = 0; + break; + } + out += n; + ret += n; + } + EVP_MD_CTX_cleanup(&ctx); + +#ifdef OPENSSL_SSL_TRACE_CRYPTO + if (ret > 0 && s->msg_callback) { + s->msg_callback(2, s->version, TLS1_RT_CRYPTO_PREMASTER, + p, len, s, s->msg_callback_arg); + s->msg_callback(2, s->version, TLS1_RT_CRYPTO_CLIENT_RANDOM, + s->s3->client_random, SSL3_RANDOM_SIZE, + s, s->msg_callback_arg); + s->msg_callback(2, s->version, TLS1_RT_CRYPTO_SERVER_RANDOM, + s->s3->server_random, SSL3_RANDOM_SIZE, + s, s->msg_callback_arg); + s->msg_callback(2, s->version, TLS1_RT_CRYPTO_MASTER, + tmpout, SSL3_MASTER_SECRET_SIZE, + s, s->msg_callback_arg); + } +#endif + OPENSSL_cleanse(buf, sizeof buf); + return (ret); +} + +int ssl3_alert_code(int code) +{ + switch (code) { + case SSL_AD_CLOSE_NOTIFY: + return (SSL3_AD_CLOSE_NOTIFY); + case SSL_AD_UNEXPECTED_MESSAGE: + return (SSL3_AD_UNEXPECTED_MESSAGE); + case SSL_AD_BAD_RECORD_MAC: + return (SSL3_AD_BAD_RECORD_MAC); + case SSL_AD_DECRYPTION_FAILED: + return (SSL3_AD_BAD_RECORD_MAC); + case SSL_AD_RECORD_OVERFLOW: + return (SSL3_AD_BAD_RECORD_MAC); + case SSL_AD_DECOMPRESSION_FAILURE: + return (SSL3_AD_DECOMPRESSION_FAILURE); + case SSL_AD_HANDSHAKE_FAILURE: + return (SSL3_AD_HANDSHAKE_FAILURE); + case SSL_AD_NO_CERTIFICATE: + return (SSL3_AD_NO_CERTIFICATE); + case SSL_AD_BAD_CERTIFICATE: + return (SSL3_AD_BAD_CERTIFICATE); + case SSL_AD_UNSUPPORTED_CERTIFICATE: + return (SSL3_AD_UNSUPPORTED_CERTIFICATE); + case SSL_AD_CERTIFICATE_REVOKED: + return (SSL3_AD_CERTIFICATE_REVOKED); + case SSL_AD_CERTIFICATE_EXPIRED: + return (SSL3_AD_CERTIFICATE_EXPIRED); + case SSL_AD_CERTIFICATE_UNKNOWN: + return (SSL3_AD_CERTIFICATE_UNKNOWN); + case SSL_AD_ILLEGAL_PARAMETER: + return (SSL3_AD_ILLEGAL_PARAMETER); + case SSL_AD_UNKNOWN_CA: + return (SSL3_AD_BAD_CERTIFICATE); + case SSL_AD_ACCESS_DENIED: + return (SSL3_AD_HANDSHAKE_FAILURE); + case SSL_AD_DECODE_ERROR: + return (SSL3_AD_HANDSHAKE_FAILURE); + case SSL_AD_DECRYPT_ERROR: + return (SSL3_AD_HANDSHAKE_FAILURE); + case SSL_AD_EXPORT_RESTRICTION: + return (SSL3_AD_HANDSHAKE_FAILURE); + case SSL_AD_PROTOCOL_VERSION: + return (SSL3_AD_HANDSHAKE_FAILURE); + case SSL_AD_INSUFFICIENT_SECURITY: + return (SSL3_AD_HANDSHAKE_FAILURE); + case SSL_AD_INTERNAL_ERROR: + return (SSL3_AD_HANDSHAKE_FAILURE); + case SSL_AD_USER_CANCELLED: + return (SSL3_AD_HANDSHAKE_FAILURE); + case SSL_AD_NO_RENEGOTIATION: + return (-1); /* Don't send it :-) */ + case SSL_AD_UNSUPPORTED_EXTENSION: + return (SSL3_AD_HANDSHAKE_FAILURE); + case SSL_AD_CERTIFICATE_UNOBTAINABLE: + return (SSL3_AD_HANDSHAKE_FAILURE); + case SSL_AD_UNRECOGNIZED_NAME: + return (SSL3_AD_HANDSHAKE_FAILURE); + case SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE: + return (SSL3_AD_HANDSHAKE_FAILURE); + case SSL_AD_BAD_CERTIFICATE_HASH_VALUE: + return (SSL3_AD_HANDSHAKE_FAILURE); + case SSL_AD_UNKNOWN_PSK_IDENTITY: + return (TLS1_AD_UNKNOWN_PSK_IDENTITY); + case SSL_AD_INAPPROPRIATE_FALLBACK: + return (TLS1_AD_INAPPROPRIATE_FALLBACK); + default: + return (-1); + } +} diff --git a/thirdparty/openssl/ssl/s3_lib.c b/thirdparty/openssl/ssl/s3_lib.c new file mode 100644 index 0000000000..872e636af9 --- /dev/null +++ b/thirdparty/openssl/ssl/s3_lib.c @@ -0,0 +1,4536 @@ +/* ssl/s3_lib.c */ +/* 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 <stdio.h> +#include <openssl/objects.h> +#include "ssl_locl.h" +#include "kssl_lcl.h" +#include <openssl/md5.h> +#ifndef OPENSSL_NO_DH +# include <openssl/dh.h> +#endif + +const char ssl3_version_str[] = "SSLv3" OPENSSL_VERSION_PTEXT; + +#define SSL3_NUM_CIPHERS (sizeof(ssl3_ciphers)/sizeof(SSL_CIPHER)) + +/* list of available SSLv3 ciphers (sorted by id) */ +OPENSSL_GLOBAL SSL_CIPHER ssl3_ciphers[] = { + +/* The RSA ciphers */ +/* Cipher 01 */ + { + 1, + SSL3_TXT_RSA_NULL_MD5, + SSL3_CK_RSA_NULL_MD5, + SSL_kRSA, + SSL_aRSA, + SSL_eNULL, + SSL_MD5, + SSL_SSLV3, + SSL_NOT_EXP | SSL_STRONG_NONE, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 0, + 0, + }, + +/* Cipher 02 */ + { + 1, + SSL3_TXT_RSA_NULL_SHA, + SSL3_CK_RSA_NULL_SHA, + SSL_kRSA, + SSL_aRSA, + SSL_eNULL, + SSL_SHA1, + SSL_SSLV3, + SSL_NOT_EXP | SSL_STRONG_NONE | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 0, + 0, + }, + +/* Cipher 03 */ +#ifndef OPENSSL_NO_WEAK_SSL_CIPHERS + { + 1, + SSL3_TXT_RSA_RC4_40_MD5, + SSL3_CK_RSA_RC4_40_MD5, + SSL_kRSA, + SSL_aRSA, + SSL_RC4, + SSL_MD5, + SSL_SSLV3, + SSL_NOT_DEFAULT | SSL_EXPORT | SSL_EXP40, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 40, + 128, + }, +#endif + +/* Cipher 04 */ + { + 1, + SSL3_TXT_RSA_RC4_128_MD5, + SSL3_CK_RSA_RC4_128_MD5, + SSL_kRSA, + SSL_aRSA, + SSL_RC4, + SSL_MD5, + SSL_SSLV3, + SSL_NOT_EXP | SSL_MEDIUM, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + +/* Cipher 05 */ + { + 1, + SSL3_TXT_RSA_RC4_128_SHA, + SSL3_CK_RSA_RC4_128_SHA, + SSL_kRSA, + SSL_aRSA, + SSL_RC4, + SSL_SHA1, + SSL_SSLV3, + SSL_NOT_EXP | SSL_MEDIUM, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + +/* Cipher 06 */ +#ifndef OPENSSL_NO_WEAK_SSL_CIPHERS + { + 1, + SSL3_TXT_RSA_RC2_40_MD5, + SSL3_CK_RSA_RC2_40_MD5, + SSL_kRSA, + SSL_aRSA, + SSL_RC2, + SSL_MD5, + SSL_SSLV3, + SSL_NOT_DEFAULT | SSL_EXPORT | SSL_EXP40, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 40, + 128, + }, +#endif + +/* Cipher 07 */ +#ifndef OPENSSL_NO_IDEA + { + 1, + SSL3_TXT_RSA_IDEA_128_SHA, + SSL3_CK_RSA_IDEA_128_SHA, + SSL_kRSA, + SSL_aRSA, + SSL_IDEA, + SSL_SHA1, + SSL_SSLV3, + SSL_NOT_EXP | SSL_MEDIUM, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, +#endif + +/* Cipher 08 */ +#ifndef OPENSSL_NO_WEAK_SSL_CIPHERS + { + 1, + SSL3_TXT_RSA_DES_40_CBC_SHA, + SSL3_CK_RSA_DES_40_CBC_SHA, + SSL_kRSA, + SSL_aRSA, + SSL_DES, + SSL_SHA1, + SSL_SSLV3, + SSL_NOT_DEFAULT | SSL_EXPORT | SSL_EXP40, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 40, + 56, + }, +#endif + +/* Cipher 09 */ +#ifndef OPENSSL_NO_WEAK_SSL_CIPHERS + { + 1, + SSL3_TXT_RSA_DES_64_CBC_SHA, + SSL3_CK_RSA_DES_64_CBC_SHA, + SSL_kRSA, + SSL_aRSA, + SSL_DES, + SSL_SHA1, + SSL_SSLV3, + SSL_NOT_DEFAULT | SSL_NOT_EXP | SSL_LOW, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 56, + 56, + }, +#endif + +/* Cipher 0A */ + { + 1, + SSL3_TXT_RSA_DES_192_CBC3_SHA, + SSL3_CK_RSA_DES_192_CBC3_SHA, + SSL_kRSA, + SSL_aRSA, + SSL_3DES, + SSL_SHA1, + SSL_SSLV3, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 112, + 168, + }, + +/* The DH ciphers */ +/* Cipher 0B */ +#ifndef OPENSSL_NO_WEAK_SSL_CIPHERS + { + 0, + SSL3_TXT_DH_DSS_DES_40_CBC_SHA, + SSL3_CK_DH_DSS_DES_40_CBC_SHA, + SSL_kDHd, + SSL_aDH, + SSL_DES, + SSL_SHA1, + SSL_SSLV3, + SSL_NOT_DEFAULT | SSL_EXPORT | SSL_EXP40, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 40, + 56, + }, +#endif + +/* Cipher 0C */ +#ifndef OPENSSL_NO_WEAK_SSL_CIPHERS + { + 1, + SSL3_TXT_DH_DSS_DES_64_CBC_SHA, + SSL3_CK_DH_DSS_DES_64_CBC_SHA, + SSL_kDHd, + SSL_aDH, + SSL_DES, + SSL_SHA1, + SSL_SSLV3, + SSL_NOT_DEFAULT | SSL_NOT_EXP | SSL_LOW, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 56, + 56, + }, +#endif + +/* Cipher 0D */ + { + 1, + SSL3_TXT_DH_DSS_DES_192_CBC3_SHA, + SSL3_CK_DH_DSS_DES_192_CBC3_SHA, + SSL_kDHd, + SSL_aDH, + SSL_3DES, + SSL_SHA1, + SSL_SSLV3, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 112, + 168, + }, + +/* Cipher 0E */ +#ifndef OPENSSL_NO_WEAK_SSL_CIPHERS + { + 0, + SSL3_TXT_DH_RSA_DES_40_CBC_SHA, + SSL3_CK_DH_RSA_DES_40_CBC_SHA, + SSL_kDHr, + SSL_aDH, + SSL_DES, + SSL_SHA1, + SSL_SSLV3, + SSL_NOT_DEFAULT | SSL_EXPORT | SSL_EXP40, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 40, + 56, + }, +#endif + +/* Cipher 0F */ +#ifndef OPENSSL_NO_WEAK_SSL_CIPHERS + { + 1, + SSL3_TXT_DH_RSA_DES_64_CBC_SHA, + SSL3_CK_DH_RSA_DES_64_CBC_SHA, + SSL_kDHr, + SSL_aDH, + SSL_DES, + SSL_SHA1, + SSL_SSLV3, + SSL_NOT_DEFAULT | SSL_NOT_EXP | SSL_LOW, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 56, + 56, + }, +#endif + +/* Cipher 10 */ + { + 1, + SSL3_TXT_DH_RSA_DES_192_CBC3_SHA, + SSL3_CK_DH_RSA_DES_192_CBC3_SHA, + SSL_kDHr, + SSL_aDH, + SSL_3DES, + SSL_SHA1, + SSL_SSLV3, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 112, + 168, + }, + +/* The Ephemeral DH ciphers */ +/* Cipher 11 */ +#ifndef OPENSSL_NO_WEAK_SSL_CIPHERS + { + 1, + SSL3_TXT_EDH_DSS_DES_40_CBC_SHA, + SSL3_CK_EDH_DSS_DES_40_CBC_SHA, + SSL_kEDH, + SSL_aDSS, + SSL_DES, + SSL_SHA1, + SSL_SSLV3, + SSL_NOT_DEFAULT | SSL_EXPORT | SSL_EXP40, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 40, + 56, + }, +#endif + +/* Cipher 12 */ +#ifndef OPENSSL_NO_WEAK_SSL_CIPHERS + { + 1, + SSL3_TXT_EDH_DSS_DES_64_CBC_SHA, + SSL3_CK_EDH_DSS_DES_64_CBC_SHA, + SSL_kEDH, + SSL_aDSS, + SSL_DES, + SSL_SHA1, + SSL_SSLV3, + SSL_NOT_DEFAULT | SSL_NOT_EXP | SSL_LOW, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 56, + 56, + }, +#endif + +/* Cipher 13 */ + { + 1, + SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA, + SSL3_CK_EDH_DSS_DES_192_CBC3_SHA, + SSL_kEDH, + SSL_aDSS, + SSL_3DES, + SSL_SHA1, + SSL_SSLV3, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 112, + 168, + }, + +/* Cipher 14 */ +#ifndef OPENSSL_NO_WEAK_SSL_CIPHERS + { + 1, + SSL3_TXT_EDH_RSA_DES_40_CBC_SHA, + SSL3_CK_EDH_RSA_DES_40_CBC_SHA, + SSL_kEDH, + SSL_aRSA, + SSL_DES, + SSL_SHA1, + SSL_SSLV3, + SSL_NOT_DEFAULT | SSL_EXPORT | SSL_EXP40, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 40, + 56, + }, +#endif + +/* Cipher 15 */ +#ifndef OPENSSL_NO_WEAK_SSL_CIPHERS + { + 1, + SSL3_TXT_EDH_RSA_DES_64_CBC_SHA, + SSL3_CK_EDH_RSA_DES_64_CBC_SHA, + SSL_kEDH, + SSL_aRSA, + SSL_DES, + SSL_SHA1, + SSL_SSLV3, + SSL_NOT_DEFAULT | SSL_NOT_EXP | SSL_LOW, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 56, + 56, + }, +#endif + +/* Cipher 16 */ + { + 1, + SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA, + SSL3_CK_EDH_RSA_DES_192_CBC3_SHA, + SSL_kEDH, + SSL_aRSA, + SSL_3DES, + SSL_SHA1, + SSL_SSLV3, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 112, + 168, + }, + +/* Cipher 17 */ +#ifndef OPENSSL_NO_WEAK_SSL_CIPHERS + { + 1, + SSL3_TXT_ADH_RC4_40_MD5, + SSL3_CK_ADH_RC4_40_MD5, + SSL_kEDH, + SSL_aNULL, + SSL_RC4, + SSL_MD5, + SSL_SSLV3, + SSL_NOT_DEFAULT | SSL_EXPORT | SSL_EXP40, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 40, + 128, + }, +#endif + +/* Cipher 18 */ + { + 1, + SSL3_TXT_ADH_RC4_128_MD5, + SSL3_CK_ADH_RC4_128_MD5, + SSL_kEDH, + SSL_aNULL, + SSL_RC4, + SSL_MD5, + SSL_SSLV3, + SSL_NOT_DEFAULT | SSL_NOT_EXP | SSL_MEDIUM, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + +/* Cipher 19 */ +#ifndef OPENSSL_NO_WEAK_SSL_CIPHERS + { + 1, + SSL3_TXT_ADH_DES_40_CBC_SHA, + SSL3_CK_ADH_DES_40_CBC_SHA, + SSL_kEDH, + SSL_aNULL, + SSL_DES, + SSL_SHA1, + SSL_SSLV3, + SSL_NOT_DEFAULT | SSL_EXPORT | SSL_EXP40, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 40, + 128, + }, +#endif + +/* Cipher 1A */ +#ifndef OPENSSL_NO_WEAK_SSL_CIPHERS + { + 1, + SSL3_TXT_ADH_DES_64_CBC_SHA, + SSL3_CK_ADH_DES_64_CBC_SHA, + SSL_kEDH, + SSL_aNULL, + SSL_DES, + SSL_SHA1, + SSL_SSLV3, + SSL_NOT_DEFAULT | SSL_NOT_EXP | SSL_LOW, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 56, + 56, + }, +#endif + +/* Cipher 1B */ + { + 1, + SSL3_TXT_ADH_DES_192_CBC_SHA, + SSL3_CK_ADH_DES_192_CBC_SHA, + SSL_kEDH, + SSL_aNULL, + SSL_3DES, + SSL_SHA1, + SSL_SSLV3, + SSL_NOT_DEFAULT | SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 112, + 168, + }, + +/* Fortezza ciphersuite from SSL 3.0 spec */ +#if 0 +/* Cipher 1C */ + { + 0, + SSL3_TXT_FZA_DMS_NULL_SHA, + SSL3_CK_FZA_DMS_NULL_SHA, + SSL_kFZA, + SSL_aFZA, + SSL_eNULL, + SSL_SHA1, + SSL_SSLV3, + SSL_NOT_EXP | SSL_STRONG_NONE, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 0, + 0, + }, + +/* Cipher 1D */ + { + 0, + SSL3_TXT_FZA_DMS_FZA_SHA, + SSL3_CK_FZA_DMS_FZA_SHA, + SSL_kFZA, + SSL_aFZA, + SSL_eFZA, + SSL_SHA1, + SSL_SSLV3, + SSL_NOT_EXP | SSL_STRONG_NONE, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 0, + 0, + }, + +/* Cipher 1E */ + { + 0, + SSL3_TXT_FZA_DMS_RC4_SHA, + SSL3_CK_FZA_DMS_RC4_SHA, + SSL_kFZA, + SSL_aFZA, + SSL_RC4, + SSL_SHA1, + SSL_SSLV3, + SSL_NOT_EXP | SSL_MEDIUM, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, +#endif + +#ifndef OPENSSL_NO_KRB5 +/* The Kerberos ciphers*/ +/* Cipher 1E */ +# ifndef OPENSSL_NO_WEAK_SSL_CIPHERS + { + 1, + SSL3_TXT_KRB5_DES_64_CBC_SHA, + SSL3_CK_KRB5_DES_64_CBC_SHA, + SSL_kKRB5, + SSL_aKRB5, + SSL_DES, + SSL_SHA1, + SSL_SSLV3, + SSL_NOT_DEFAULT | SSL_NOT_EXP | SSL_LOW, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 56, + 56, + }, +# endif + +/* Cipher 1F */ + { + 1, + SSL3_TXT_KRB5_DES_192_CBC3_SHA, + SSL3_CK_KRB5_DES_192_CBC3_SHA, + SSL_kKRB5, + SSL_aKRB5, + SSL_3DES, + SSL_SHA1, + SSL_SSLV3, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 112, + 168, + }, + +/* Cipher 20 */ + { + 1, + SSL3_TXT_KRB5_RC4_128_SHA, + SSL3_CK_KRB5_RC4_128_SHA, + SSL_kKRB5, + SSL_aKRB5, + SSL_RC4, + SSL_SHA1, + SSL_SSLV3, + SSL_NOT_EXP | SSL_MEDIUM, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + +/* Cipher 21 */ + { + 1, + SSL3_TXT_KRB5_IDEA_128_CBC_SHA, + SSL3_CK_KRB5_IDEA_128_CBC_SHA, + SSL_kKRB5, + SSL_aKRB5, + SSL_IDEA, + SSL_SHA1, + SSL_SSLV3, + SSL_NOT_EXP | SSL_MEDIUM, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + +/* Cipher 22 */ +# ifndef OPENSSL_NO_WEAK_SSL_CIPHERS + { + 1, + SSL3_TXT_KRB5_DES_64_CBC_MD5, + SSL3_CK_KRB5_DES_64_CBC_MD5, + SSL_kKRB5, + SSL_aKRB5, + SSL_DES, + SSL_MD5, + SSL_SSLV3, + SSL_NOT_DEFAULT | SSL_NOT_EXP | SSL_LOW, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 56, + 56, + }, +# endif + +/* Cipher 23 */ + { + 1, + SSL3_TXT_KRB5_DES_192_CBC3_MD5, + SSL3_CK_KRB5_DES_192_CBC3_MD5, + SSL_kKRB5, + SSL_aKRB5, + SSL_3DES, + SSL_MD5, + SSL_SSLV3, + SSL_NOT_EXP | SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 112, + 168, + }, + +/* Cipher 24 */ + { + 1, + SSL3_TXT_KRB5_RC4_128_MD5, + SSL3_CK_KRB5_RC4_128_MD5, + SSL_kKRB5, + SSL_aKRB5, + SSL_RC4, + SSL_MD5, + SSL_SSLV3, + SSL_NOT_EXP | SSL_MEDIUM, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + +/* Cipher 25 */ + { + 1, + SSL3_TXT_KRB5_IDEA_128_CBC_MD5, + SSL3_CK_KRB5_IDEA_128_CBC_MD5, + SSL_kKRB5, + SSL_aKRB5, + SSL_IDEA, + SSL_MD5, + SSL_SSLV3, + SSL_NOT_EXP | SSL_MEDIUM, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + +/* Cipher 26 */ +# ifndef OPENSSL_NO_WEAK_SSL_CIPHERS + { + 1, + SSL3_TXT_KRB5_DES_40_CBC_SHA, + SSL3_CK_KRB5_DES_40_CBC_SHA, + SSL_kKRB5, + SSL_aKRB5, + SSL_DES, + SSL_SHA1, + SSL_SSLV3, + SSL_NOT_DEFAULT | SSL_EXPORT | SSL_EXP40, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 40, + 56, + }, +# endif + +/* Cipher 27 */ +# ifndef OPENSSL_NO_WEAK_SSL_CIPHERS + { + 1, + SSL3_TXT_KRB5_RC2_40_CBC_SHA, + SSL3_CK_KRB5_RC2_40_CBC_SHA, + SSL_kKRB5, + SSL_aKRB5, + SSL_RC2, + SSL_SHA1, + SSL_SSLV3, + SSL_NOT_DEFAULT | SSL_EXPORT | SSL_EXP40, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 40, + 128, + }, +# endif + +/* Cipher 28 */ +# ifndef OPENSSL_NO_WEAK_SSL_CIPHERS + { + 1, + SSL3_TXT_KRB5_RC4_40_SHA, + SSL3_CK_KRB5_RC4_40_SHA, + SSL_kKRB5, + SSL_aKRB5, + SSL_RC4, + SSL_SHA1, + SSL_SSLV3, + SSL_NOT_DEFAULT | SSL_EXPORT | SSL_EXP40, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 40, + 128, + }, +# endif + +/* Cipher 29 */ +# ifndef OPENSSL_NO_WEAK_SSL_CIPHERS + { + 1, + SSL3_TXT_KRB5_DES_40_CBC_MD5, + SSL3_CK_KRB5_DES_40_CBC_MD5, + SSL_kKRB5, + SSL_aKRB5, + SSL_DES, + SSL_MD5, + SSL_SSLV3, + SSL_NOT_DEFAULT | SSL_EXPORT | SSL_EXP40, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 40, + 56, + }, +# endif + +/* Cipher 2A */ +# ifndef OPENSSL_NO_WEAK_SSL_CIPHERS + { + 1, + SSL3_TXT_KRB5_RC2_40_CBC_MD5, + SSL3_CK_KRB5_RC2_40_CBC_MD5, + SSL_kKRB5, + SSL_aKRB5, + SSL_RC2, + SSL_MD5, + SSL_SSLV3, + SSL_NOT_DEFAULT | SSL_EXPORT | SSL_EXP40, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 40, + 128, + }, +# endif + +/* Cipher 2B */ +# ifndef OPENSSL_NO_WEAK_SSL_CIPHERS + { + 1, + SSL3_TXT_KRB5_RC4_40_MD5, + SSL3_CK_KRB5_RC4_40_MD5, + SSL_kKRB5, + SSL_aKRB5, + SSL_RC4, + SSL_MD5, + SSL_SSLV3, + SSL_NOT_DEFAULT | SSL_EXPORT | SSL_EXP40, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 40, + 128, + }, +# endif +#endif /* OPENSSL_NO_KRB5 */ + +/* New AES ciphersuites */ +/* Cipher 2F */ + { + 1, + TLS1_TXT_RSA_WITH_AES_128_SHA, + TLS1_CK_RSA_WITH_AES_128_SHA, + SSL_kRSA, + SSL_aRSA, + SSL_AES128, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, +/* Cipher 30 */ + { + 1, + TLS1_TXT_DH_DSS_WITH_AES_128_SHA, + TLS1_CK_DH_DSS_WITH_AES_128_SHA, + SSL_kDHd, + SSL_aDH, + SSL_AES128, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, +/* Cipher 31 */ + { + 1, + TLS1_TXT_DH_RSA_WITH_AES_128_SHA, + TLS1_CK_DH_RSA_WITH_AES_128_SHA, + SSL_kDHr, + SSL_aDH, + SSL_AES128, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, +/* Cipher 32 */ + { + 1, + TLS1_TXT_DHE_DSS_WITH_AES_128_SHA, + TLS1_CK_DHE_DSS_WITH_AES_128_SHA, + SSL_kEDH, + SSL_aDSS, + SSL_AES128, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, +/* Cipher 33 */ + { + 1, + TLS1_TXT_DHE_RSA_WITH_AES_128_SHA, + TLS1_CK_DHE_RSA_WITH_AES_128_SHA, + SSL_kEDH, + SSL_aRSA, + SSL_AES128, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, +/* Cipher 34 */ + { + 1, + TLS1_TXT_ADH_WITH_AES_128_SHA, + TLS1_CK_ADH_WITH_AES_128_SHA, + SSL_kEDH, + SSL_aNULL, + SSL_AES128, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_DEFAULT | SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + +/* Cipher 35 */ + { + 1, + TLS1_TXT_RSA_WITH_AES_256_SHA, + TLS1_CK_RSA_WITH_AES_256_SHA, + SSL_kRSA, + SSL_aRSA, + SSL_AES256, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 256, + 256, + }, +/* Cipher 36 */ + { + 1, + TLS1_TXT_DH_DSS_WITH_AES_256_SHA, + TLS1_CK_DH_DSS_WITH_AES_256_SHA, + SSL_kDHd, + SSL_aDH, + SSL_AES256, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 256, + 256, + }, + +/* Cipher 37 */ + { + 1, + TLS1_TXT_DH_RSA_WITH_AES_256_SHA, + TLS1_CK_DH_RSA_WITH_AES_256_SHA, + SSL_kDHr, + SSL_aDH, + SSL_AES256, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 256, + 256, + }, + +/* Cipher 38 */ + { + 1, + TLS1_TXT_DHE_DSS_WITH_AES_256_SHA, + TLS1_CK_DHE_DSS_WITH_AES_256_SHA, + SSL_kEDH, + SSL_aDSS, + SSL_AES256, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 256, + 256, + }, + +/* Cipher 39 */ + { + 1, + TLS1_TXT_DHE_RSA_WITH_AES_256_SHA, + TLS1_CK_DHE_RSA_WITH_AES_256_SHA, + SSL_kEDH, + SSL_aRSA, + SSL_AES256, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 256, + 256, + }, + + /* Cipher 3A */ + { + 1, + TLS1_TXT_ADH_WITH_AES_256_SHA, + TLS1_CK_ADH_WITH_AES_256_SHA, + SSL_kEDH, + SSL_aNULL, + SSL_AES256, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_DEFAULT | SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 256, + 256, + }, + + /* TLS v1.2 ciphersuites */ + /* Cipher 3B */ + { + 1, + TLS1_TXT_RSA_WITH_NULL_SHA256, + TLS1_CK_RSA_WITH_NULL_SHA256, + SSL_kRSA, + SSL_aRSA, + SSL_eNULL, + SSL_SHA256, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_STRONG_NONE | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 0, + 0, + }, + + /* Cipher 3C */ + { + 1, + TLS1_TXT_RSA_WITH_AES_128_SHA256, + TLS1_CK_RSA_WITH_AES_128_SHA256, + SSL_kRSA, + SSL_aRSA, + SSL_AES128, + SSL_SHA256, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + + /* Cipher 3D */ + { + 1, + TLS1_TXT_RSA_WITH_AES_256_SHA256, + TLS1_CK_RSA_WITH_AES_256_SHA256, + SSL_kRSA, + SSL_aRSA, + SSL_AES256, + SSL_SHA256, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 256, + 256, + }, + + /* Cipher 3E */ + { + 1, + TLS1_TXT_DH_DSS_WITH_AES_128_SHA256, + TLS1_CK_DH_DSS_WITH_AES_128_SHA256, + SSL_kDHd, + SSL_aDH, + SSL_AES128, + SSL_SHA256, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + + /* Cipher 3F */ + { + 1, + TLS1_TXT_DH_RSA_WITH_AES_128_SHA256, + TLS1_CK_DH_RSA_WITH_AES_128_SHA256, + SSL_kDHr, + SSL_aDH, + SSL_AES128, + SSL_SHA256, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + + /* Cipher 40 */ + { + 1, + TLS1_TXT_DHE_DSS_WITH_AES_128_SHA256, + TLS1_CK_DHE_DSS_WITH_AES_128_SHA256, + SSL_kEDH, + SSL_aDSS, + SSL_AES128, + SSL_SHA256, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + +#ifndef OPENSSL_NO_CAMELLIA + /* Camellia ciphersuites from RFC4132 (128-bit portion) */ + + /* Cipher 41 */ + { + 1, + TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA, + TLS1_CK_RSA_WITH_CAMELLIA_128_CBC_SHA, + SSL_kRSA, + SSL_aRSA, + SSL_CAMELLIA128, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + + /* Cipher 42 */ + { + 1, + TLS1_TXT_DH_DSS_WITH_CAMELLIA_128_CBC_SHA, + TLS1_CK_DH_DSS_WITH_CAMELLIA_128_CBC_SHA, + SSL_kDHd, + SSL_aDH, + SSL_CAMELLIA128, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + + /* Cipher 43 */ + { + 1, + TLS1_TXT_DH_RSA_WITH_CAMELLIA_128_CBC_SHA, + TLS1_CK_DH_RSA_WITH_CAMELLIA_128_CBC_SHA, + SSL_kDHr, + SSL_aDH, + SSL_CAMELLIA128, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + + /* Cipher 44 */ + { + 1, + TLS1_TXT_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA, + TLS1_CK_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA, + SSL_kEDH, + SSL_aDSS, + SSL_CAMELLIA128, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + + /* Cipher 45 */ + { + 1, + TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, + TLS1_CK_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, + SSL_kEDH, + SSL_aRSA, + SSL_CAMELLIA128, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + + /* Cipher 46 */ + { + 1, + TLS1_TXT_ADH_WITH_CAMELLIA_128_CBC_SHA, + TLS1_CK_ADH_WITH_CAMELLIA_128_CBC_SHA, + SSL_kEDH, + SSL_aNULL, + SSL_CAMELLIA128, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_DEFAULT | SSL_NOT_EXP | SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, +#endif /* OPENSSL_NO_CAMELLIA */ + +#if TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES + /* New TLS Export CipherSuites from expired ID */ +# if 0 + /* Cipher 60 */ + { + 1, + TLS1_TXT_RSA_EXPORT1024_WITH_RC4_56_MD5, + TLS1_CK_RSA_EXPORT1024_WITH_RC4_56_MD5, + SSL_kRSA, + SSL_aRSA, + SSL_RC4, + SSL_MD5, + SSL_TLSV1, + SSL_NOT_DEFAULT | SSL_EXPORT | SSL_EXP56, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 56, + 128, + }, + + /* Cipher 61 */ + { + 1, + TLS1_TXT_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5, + TLS1_CK_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5, + SSL_kRSA, + SSL_aRSA, + SSL_RC2, + SSL_MD5, + SSL_TLSV1, + SSL_NOT_DEFAULT | SSL_EXPORT | SSL_EXP56, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 56, + 128, + }, +# endif + + /* Cipher 62 */ +# ifndef OPENSSL_NO_WEAK_SSL_CIPHERS + { + 1, + TLS1_TXT_RSA_EXPORT1024_WITH_DES_CBC_SHA, + TLS1_CK_RSA_EXPORT1024_WITH_DES_CBC_SHA, + SSL_kRSA, + SSL_aRSA, + SSL_DES, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_DEFAULT | SSL_EXPORT | SSL_EXP56, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 56, + 56, + }, +# endif + + /* Cipher 63 */ +# ifndef OPENSSL_NO_WEAK_SSL_CIPHERS + { + 1, + TLS1_TXT_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA, + TLS1_CK_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA, + SSL_kEDH, + SSL_aDSS, + SSL_DES, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_DEFAULT | SSL_EXPORT | SSL_EXP56, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 56, + 56, + }, +# endif + + /* Cipher 64 */ +# ifndef OPENSSL_NO_WEAK_SSL_CIPHERS + { + 1, + TLS1_TXT_RSA_EXPORT1024_WITH_RC4_56_SHA, + TLS1_CK_RSA_EXPORT1024_WITH_RC4_56_SHA, + SSL_kRSA, + SSL_aRSA, + SSL_RC4, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_DEFAULT | SSL_EXPORT | SSL_EXP56, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 56, + 128, + }, +# endif + + /* Cipher 65 */ +# ifndef OPENSSL_NO_WEAK_SSL_CIPHERS + { + 1, + TLS1_TXT_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA, + TLS1_CK_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA, + SSL_kEDH, + SSL_aDSS, + SSL_RC4, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_DEFAULT | SSL_EXPORT | SSL_EXP56, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 56, + 128, + }, +# endif + + /* Cipher 66 */ + { + 1, + TLS1_TXT_DHE_DSS_WITH_RC4_128_SHA, + TLS1_CK_DHE_DSS_WITH_RC4_128_SHA, + SSL_kEDH, + SSL_aDSS, + SSL_RC4, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_MEDIUM, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, +#endif + + /* TLS v1.2 ciphersuites */ + /* Cipher 67 */ + { + 1, + TLS1_TXT_DHE_RSA_WITH_AES_128_SHA256, + TLS1_CK_DHE_RSA_WITH_AES_128_SHA256, + SSL_kEDH, + SSL_aRSA, + SSL_AES128, + SSL_SHA256, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + + /* Cipher 68 */ + { + 1, + TLS1_TXT_DH_DSS_WITH_AES_256_SHA256, + TLS1_CK_DH_DSS_WITH_AES_256_SHA256, + SSL_kDHd, + SSL_aDH, + SSL_AES256, + SSL_SHA256, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 256, + 256, + }, + + /* Cipher 69 */ + { + 1, + TLS1_TXT_DH_RSA_WITH_AES_256_SHA256, + TLS1_CK_DH_RSA_WITH_AES_256_SHA256, + SSL_kDHr, + SSL_aDH, + SSL_AES256, + SSL_SHA256, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 256, + 256, + }, + + /* Cipher 6A */ + { + 1, + TLS1_TXT_DHE_DSS_WITH_AES_256_SHA256, + TLS1_CK_DHE_DSS_WITH_AES_256_SHA256, + SSL_kEDH, + SSL_aDSS, + SSL_AES256, + SSL_SHA256, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 256, + 256, + }, + + /* Cipher 6B */ + { + 1, + TLS1_TXT_DHE_RSA_WITH_AES_256_SHA256, + TLS1_CK_DHE_RSA_WITH_AES_256_SHA256, + SSL_kEDH, + SSL_aRSA, + SSL_AES256, + SSL_SHA256, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 256, + 256, + }, + + /* Cipher 6C */ + { + 1, + TLS1_TXT_ADH_WITH_AES_128_SHA256, + TLS1_CK_ADH_WITH_AES_128_SHA256, + SSL_kEDH, + SSL_aNULL, + SSL_AES128, + SSL_SHA256, + SSL_TLSV1_2, + SSL_NOT_DEFAULT | SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + + /* Cipher 6D */ + { + 1, + TLS1_TXT_ADH_WITH_AES_256_SHA256, + TLS1_CK_ADH_WITH_AES_256_SHA256, + SSL_kEDH, + SSL_aNULL, + SSL_AES256, + SSL_SHA256, + SSL_TLSV1_2, + SSL_NOT_DEFAULT | SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 256, + 256, + }, + + /* GOST Ciphersuites */ + + { + 1, + "GOST94-GOST89-GOST89", + 0x3000080, + SSL_kGOST, + SSL_aGOST94, + SSL_eGOST2814789CNT, + SSL_GOST89MAC, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH, + SSL_HANDSHAKE_MAC_GOST94 | TLS1_PRF_GOST94 | TLS1_STREAM_MAC, + 256, + 256}, + { + 1, + "GOST2001-GOST89-GOST89", + 0x3000081, + SSL_kGOST, + SSL_aGOST01, + SSL_eGOST2814789CNT, + SSL_GOST89MAC, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH, + SSL_HANDSHAKE_MAC_GOST94 | TLS1_PRF_GOST94 | TLS1_STREAM_MAC, + 256, + 256}, + { + 1, + "GOST94-NULL-GOST94", + 0x3000082, + SSL_kGOST, + SSL_aGOST94, + SSL_eNULL, + SSL_GOST94, + SSL_TLSV1, + SSL_NOT_EXP | SSL_STRONG_NONE, + SSL_HANDSHAKE_MAC_GOST94 | TLS1_PRF_GOST94, + 0, + 0}, + { + 1, + "GOST2001-NULL-GOST94", + 0x3000083, + SSL_kGOST, + SSL_aGOST01, + SSL_eNULL, + SSL_GOST94, + SSL_TLSV1, + SSL_NOT_EXP | SSL_STRONG_NONE, + SSL_HANDSHAKE_MAC_GOST94 | TLS1_PRF_GOST94, + 0, + 0}, + +#ifndef OPENSSL_NO_CAMELLIA + /* Camellia ciphersuites from RFC4132 (256-bit portion) */ + + /* Cipher 84 */ + { + 1, + TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA, + TLS1_CK_RSA_WITH_CAMELLIA_256_CBC_SHA, + SSL_kRSA, + SSL_aRSA, + SSL_CAMELLIA256, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 256, + 256, + }, + /* Cipher 85 */ + { + 1, + TLS1_TXT_DH_DSS_WITH_CAMELLIA_256_CBC_SHA, + TLS1_CK_DH_DSS_WITH_CAMELLIA_256_CBC_SHA, + SSL_kDHd, + SSL_aDH, + SSL_CAMELLIA256, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 256, + 256, + }, + + /* Cipher 86 */ + { + 1, + TLS1_TXT_DH_RSA_WITH_CAMELLIA_256_CBC_SHA, + TLS1_CK_DH_RSA_WITH_CAMELLIA_256_CBC_SHA, + SSL_kDHr, + SSL_aDH, + SSL_CAMELLIA256, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 256, + 256, + }, + + /* Cipher 87 */ + { + 1, + TLS1_TXT_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA, + TLS1_CK_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA, + SSL_kEDH, + SSL_aDSS, + SSL_CAMELLIA256, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 256, + 256, + }, + + /* Cipher 88 */ + { + 1, + TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, + TLS1_CK_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, + SSL_kEDH, + SSL_aRSA, + SSL_CAMELLIA256, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 256, + 256, + }, + + /* Cipher 89 */ + { + 1, + TLS1_TXT_ADH_WITH_CAMELLIA_256_CBC_SHA, + TLS1_CK_ADH_WITH_CAMELLIA_256_CBC_SHA, + SSL_kEDH, + SSL_aNULL, + SSL_CAMELLIA256, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_DEFAULT | SSL_NOT_EXP | SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 256, + 256, + }, +#endif /* OPENSSL_NO_CAMELLIA */ + +#ifndef OPENSSL_NO_PSK + /* Cipher 8A */ + { + 1, + TLS1_TXT_PSK_WITH_RC4_128_SHA, + TLS1_CK_PSK_WITH_RC4_128_SHA, + SSL_kPSK, + SSL_aPSK, + SSL_RC4, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_MEDIUM, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + + /* Cipher 8B */ + { + 1, + TLS1_TXT_PSK_WITH_3DES_EDE_CBC_SHA, + TLS1_CK_PSK_WITH_3DES_EDE_CBC_SHA, + SSL_kPSK, + SSL_aPSK, + SSL_3DES, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 112, + 168, + }, + + /* Cipher 8C */ + { + 1, + TLS1_TXT_PSK_WITH_AES_128_CBC_SHA, + TLS1_CK_PSK_WITH_AES_128_CBC_SHA, + SSL_kPSK, + SSL_aPSK, + SSL_AES128, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + + /* Cipher 8D */ + { + 1, + TLS1_TXT_PSK_WITH_AES_256_CBC_SHA, + TLS1_CK_PSK_WITH_AES_256_CBC_SHA, + SSL_kPSK, + SSL_aPSK, + SSL_AES256, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 256, + 256, + }, +#endif /* OPENSSL_NO_PSK */ + +#ifndef OPENSSL_NO_SEED + /* SEED ciphersuites from RFC4162 */ + + /* Cipher 96 */ + { + 1, + TLS1_TXT_RSA_WITH_SEED_SHA, + TLS1_CK_RSA_WITH_SEED_SHA, + SSL_kRSA, + SSL_aRSA, + SSL_SEED, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_MEDIUM, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + + /* Cipher 97 */ + { + 1, + TLS1_TXT_DH_DSS_WITH_SEED_SHA, + TLS1_CK_DH_DSS_WITH_SEED_SHA, + SSL_kDHd, + SSL_aDH, + SSL_SEED, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_MEDIUM, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + + /* Cipher 98 */ + { + 1, + TLS1_TXT_DH_RSA_WITH_SEED_SHA, + TLS1_CK_DH_RSA_WITH_SEED_SHA, + SSL_kDHr, + SSL_aDH, + SSL_SEED, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_MEDIUM, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + + /* Cipher 99 */ + { + 1, + TLS1_TXT_DHE_DSS_WITH_SEED_SHA, + TLS1_CK_DHE_DSS_WITH_SEED_SHA, + SSL_kEDH, + SSL_aDSS, + SSL_SEED, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_MEDIUM, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + + /* Cipher 9A */ + { + 1, + TLS1_TXT_DHE_RSA_WITH_SEED_SHA, + TLS1_CK_DHE_RSA_WITH_SEED_SHA, + SSL_kEDH, + SSL_aRSA, + SSL_SEED, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_MEDIUM, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + + /* Cipher 9B */ + { + 1, + TLS1_TXT_ADH_WITH_SEED_SHA, + TLS1_CK_ADH_WITH_SEED_SHA, + SSL_kEDH, + SSL_aNULL, + SSL_SEED, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_DEFAULT | SSL_NOT_EXP | SSL_MEDIUM, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + +#endif /* OPENSSL_NO_SEED */ + + /* GCM ciphersuites from RFC5288 */ + + /* Cipher 9C */ + { + 1, + TLS1_TXT_RSA_WITH_AES_128_GCM_SHA256, + TLS1_CK_RSA_WITH_AES_128_GCM_SHA256, + SSL_kRSA, + SSL_aRSA, + SSL_AES128GCM, + SSL_AEAD, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256, + 128, + 128, + }, + + /* Cipher 9D */ + { + 1, + TLS1_TXT_RSA_WITH_AES_256_GCM_SHA384, + TLS1_CK_RSA_WITH_AES_256_GCM_SHA384, + SSL_kRSA, + SSL_aRSA, + SSL_AES256GCM, + SSL_AEAD, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384, + 256, + 256, + }, + + /* Cipher 9E */ + { + 1, + TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256, + TLS1_CK_DHE_RSA_WITH_AES_128_GCM_SHA256, + SSL_kEDH, + SSL_aRSA, + SSL_AES128GCM, + SSL_AEAD, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256, + 128, + 128, + }, + + /* Cipher 9F */ + { + 1, + TLS1_TXT_DHE_RSA_WITH_AES_256_GCM_SHA384, + TLS1_CK_DHE_RSA_WITH_AES_256_GCM_SHA384, + SSL_kEDH, + SSL_aRSA, + SSL_AES256GCM, + SSL_AEAD, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384, + 256, + 256, + }, + + /* Cipher A0 */ + { + 1, + TLS1_TXT_DH_RSA_WITH_AES_128_GCM_SHA256, + TLS1_CK_DH_RSA_WITH_AES_128_GCM_SHA256, + SSL_kDHr, + SSL_aDH, + SSL_AES128GCM, + SSL_AEAD, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256, + 128, + 128, + }, + + /* Cipher A1 */ + { + 1, + TLS1_TXT_DH_RSA_WITH_AES_256_GCM_SHA384, + TLS1_CK_DH_RSA_WITH_AES_256_GCM_SHA384, + SSL_kDHr, + SSL_aDH, + SSL_AES256GCM, + SSL_AEAD, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384, + 256, + 256, + }, + + /* Cipher A2 */ + { + 1, + TLS1_TXT_DHE_DSS_WITH_AES_128_GCM_SHA256, + TLS1_CK_DHE_DSS_WITH_AES_128_GCM_SHA256, + SSL_kEDH, + SSL_aDSS, + SSL_AES128GCM, + SSL_AEAD, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256, + 128, + 128, + }, + + /* Cipher A3 */ + { + 1, + TLS1_TXT_DHE_DSS_WITH_AES_256_GCM_SHA384, + TLS1_CK_DHE_DSS_WITH_AES_256_GCM_SHA384, + SSL_kEDH, + SSL_aDSS, + SSL_AES256GCM, + SSL_AEAD, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384, + 256, + 256, + }, + + /* Cipher A4 */ + { + 1, + TLS1_TXT_DH_DSS_WITH_AES_128_GCM_SHA256, + TLS1_CK_DH_DSS_WITH_AES_128_GCM_SHA256, + SSL_kDHd, + SSL_aDH, + SSL_AES128GCM, + SSL_AEAD, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256, + 128, + 128, + }, + + /* Cipher A5 */ + { + 1, + TLS1_TXT_DH_DSS_WITH_AES_256_GCM_SHA384, + TLS1_CK_DH_DSS_WITH_AES_256_GCM_SHA384, + SSL_kDHd, + SSL_aDH, + SSL_AES256GCM, + SSL_AEAD, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384, + 256, + 256, + }, + + /* Cipher A6 */ + { + 1, + TLS1_TXT_ADH_WITH_AES_128_GCM_SHA256, + TLS1_CK_ADH_WITH_AES_128_GCM_SHA256, + SSL_kEDH, + SSL_aNULL, + SSL_AES128GCM, + SSL_AEAD, + SSL_TLSV1_2, + SSL_NOT_DEFAULT | SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256, + 128, + 128, + }, + + /* Cipher A7 */ + { + 1, + TLS1_TXT_ADH_WITH_AES_256_GCM_SHA384, + TLS1_CK_ADH_WITH_AES_256_GCM_SHA384, + SSL_kEDH, + SSL_aNULL, + SSL_AES256GCM, + SSL_AEAD, + SSL_TLSV1_2, + SSL_NOT_DEFAULT | SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384, + 256, + 256, + }, +#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL + { + 1, + "SCSV", + SSL3_CK_SCSV, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0}, +#endif + +#ifndef OPENSSL_NO_ECDH + /* Cipher C001 */ + { + 1, + TLS1_TXT_ECDH_ECDSA_WITH_NULL_SHA, + TLS1_CK_ECDH_ECDSA_WITH_NULL_SHA, + SSL_kECDHe, + SSL_aECDH, + SSL_eNULL, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_STRONG_NONE | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 0, + 0, + }, + + /* Cipher C002 */ + { + 1, + TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA, + TLS1_CK_ECDH_ECDSA_WITH_RC4_128_SHA, + SSL_kECDHe, + SSL_aECDH, + SSL_RC4, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_MEDIUM, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + + /* Cipher C003 */ + { + 1, + TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA, + TLS1_CK_ECDH_ECDSA_WITH_DES_192_CBC3_SHA, + SSL_kECDHe, + SSL_aECDH, + SSL_3DES, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 112, + 168, + }, + + /* Cipher C004 */ + { + 1, + TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA, + TLS1_CK_ECDH_ECDSA_WITH_AES_128_CBC_SHA, + SSL_kECDHe, + SSL_aECDH, + SSL_AES128, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + + /* Cipher C005 */ + { + 1, + TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA, + TLS1_CK_ECDH_ECDSA_WITH_AES_256_CBC_SHA, + SSL_kECDHe, + SSL_aECDH, + SSL_AES256, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 256, + 256, + }, + + /* Cipher C006 */ + { + 1, + TLS1_TXT_ECDHE_ECDSA_WITH_NULL_SHA, + TLS1_CK_ECDHE_ECDSA_WITH_NULL_SHA, + SSL_kEECDH, + SSL_aECDSA, + SSL_eNULL, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_STRONG_NONE | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 0, + 0, + }, + + /* Cipher C007 */ + { + 1, + TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA, + TLS1_CK_ECDHE_ECDSA_WITH_RC4_128_SHA, + SSL_kEECDH, + SSL_aECDSA, + SSL_RC4, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_MEDIUM, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + + /* Cipher C008 */ + { + 1, + TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA, + TLS1_CK_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA, + SSL_kEECDH, + SSL_aECDSA, + SSL_3DES, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 112, + 168, + }, + + /* Cipher C009 */ + { + 1, + TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + SSL_kEECDH, + SSL_aECDSA, + SSL_AES128, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + + /* Cipher C00A */ + { + 1, + TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + TLS1_CK_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + SSL_kEECDH, + SSL_aECDSA, + SSL_AES256, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 256, + 256, + }, + + /* Cipher C00B */ + { + 1, + TLS1_TXT_ECDH_RSA_WITH_NULL_SHA, + TLS1_CK_ECDH_RSA_WITH_NULL_SHA, + SSL_kECDHr, + SSL_aECDH, + SSL_eNULL, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_STRONG_NONE | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 0, + 0, + }, + + /* Cipher C00C */ + { + 1, + TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA, + TLS1_CK_ECDH_RSA_WITH_RC4_128_SHA, + SSL_kECDHr, + SSL_aECDH, + SSL_RC4, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_MEDIUM, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + + /* Cipher C00D */ + { + 1, + TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA, + TLS1_CK_ECDH_RSA_WITH_DES_192_CBC3_SHA, + SSL_kECDHr, + SSL_aECDH, + SSL_3DES, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 112, + 168, + }, + + /* Cipher C00E */ + { + 1, + TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA, + TLS1_CK_ECDH_RSA_WITH_AES_128_CBC_SHA, + SSL_kECDHr, + SSL_aECDH, + SSL_AES128, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + + /* Cipher C00F */ + { + 1, + TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA, + TLS1_CK_ECDH_RSA_WITH_AES_256_CBC_SHA, + SSL_kECDHr, + SSL_aECDH, + SSL_AES256, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 256, + 256, + }, + + /* Cipher C010 */ + { + 1, + TLS1_TXT_ECDHE_RSA_WITH_NULL_SHA, + TLS1_CK_ECDHE_RSA_WITH_NULL_SHA, + SSL_kEECDH, + SSL_aRSA, + SSL_eNULL, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_STRONG_NONE | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 0, + 0, + }, + + /* Cipher C011 */ + { + 1, + TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA, + TLS1_CK_ECDHE_RSA_WITH_RC4_128_SHA, + SSL_kEECDH, + SSL_aRSA, + SSL_RC4, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_MEDIUM, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + + /* Cipher C012 */ + { + 1, + TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA, + TLS1_CK_ECDHE_RSA_WITH_DES_192_CBC3_SHA, + SSL_kEECDH, + SSL_aRSA, + SSL_3DES, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 112, + 168, + }, + + /* Cipher C013 */ + { + 1, + TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA, + TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA, + SSL_kEECDH, + SSL_aRSA, + SSL_AES128, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + + /* Cipher C014 */ + { + 1, + TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA, + TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA, + SSL_kEECDH, + SSL_aRSA, + SSL_AES256, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 256, + 256, + }, + + /* Cipher C015 */ + { + 1, + TLS1_TXT_ECDH_anon_WITH_NULL_SHA, + TLS1_CK_ECDH_anon_WITH_NULL_SHA, + SSL_kEECDH, + SSL_aNULL, + SSL_eNULL, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_STRONG_NONE | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 0, + 0, + }, + + /* Cipher C016 */ + { + 1, + TLS1_TXT_ECDH_anon_WITH_RC4_128_SHA, + TLS1_CK_ECDH_anon_WITH_RC4_128_SHA, + SSL_kEECDH, + SSL_aNULL, + SSL_RC4, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_DEFAULT | SSL_NOT_EXP | SSL_MEDIUM, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + + /* Cipher C017 */ + { + 1, + TLS1_TXT_ECDH_anon_WITH_DES_192_CBC3_SHA, + TLS1_CK_ECDH_anon_WITH_DES_192_CBC3_SHA, + SSL_kEECDH, + SSL_aNULL, + SSL_3DES, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_DEFAULT | SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 112, + 168, + }, + + /* Cipher C018 */ + { + 1, + TLS1_TXT_ECDH_anon_WITH_AES_128_CBC_SHA, + TLS1_CK_ECDH_anon_WITH_AES_128_CBC_SHA, + SSL_kEECDH, + SSL_aNULL, + SSL_AES128, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_DEFAULT | SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + + /* Cipher C019 */ + { + 1, + TLS1_TXT_ECDH_anon_WITH_AES_256_CBC_SHA, + TLS1_CK_ECDH_anon_WITH_AES_256_CBC_SHA, + SSL_kEECDH, + SSL_aNULL, + SSL_AES256, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_DEFAULT | SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 256, + 256, + }, +#endif /* OPENSSL_NO_ECDH */ + +#ifndef OPENSSL_NO_SRP + /* Cipher C01A */ + { + 1, + TLS1_TXT_SRP_SHA_WITH_3DES_EDE_CBC_SHA, + TLS1_CK_SRP_SHA_WITH_3DES_EDE_CBC_SHA, + SSL_kSRP, + SSL_aSRP, + SSL_3DES, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 112, + 168, + }, + + /* Cipher C01B */ + { + 1, + TLS1_TXT_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA, + TLS1_CK_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA, + SSL_kSRP, + SSL_aRSA, + SSL_3DES, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 112, + 168, + }, + + /* Cipher C01C */ + { + 1, + TLS1_TXT_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA, + TLS1_CK_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA, + SSL_kSRP, + SSL_aDSS, + SSL_3DES, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 112, + 168, + }, + + /* Cipher C01D */ + { + 1, + TLS1_TXT_SRP_SHA_WITH_AES_128_CBC_SHA, + TLS1_CK_SRP_SHA_WITH_AES_128_CBC_SHA, + SSL_kSRP, + SSL_aSRP, + SSL_AES128, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + + /* Cipher C01E */ + { + 1, + TLS1_TXT_SRP_SHA_RSA_WITH_AES_128_CBC_SHA, + TLS1_CK_SRP_SHA_RSA_WITH_AES_128_CBC_SHA, + SSL_kSRP, + SSL_aRSA, + SSL_AES128, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + + /* Cipher C01F */ + { + 1, + TLS1_TXT_SRP_SHA_DSS_WITH_AES_128_CBC_SHA, + TLS1_CK_SRP_SHA_DSS_WITH_AES_128_CBC_SHA, + SSL_kSRP, + SSL_aDSS, + SSL_AES128, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 128, + 128, + }, + + /* Cipher C020 */ + { + 1, + TLS1_TXT_SRP_SHA_WITH_AES_256_CBC_SHA, + TLS1_CK_SRP_SHA_WITH_AES_256_CBC_SHA, + SSL_kSRP, + SSL_aSRP, + SSL_AES256, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 256, + 256, + }, + + /* Cipher C021 */ + { + 1, + TLS1_TXT_SRP_SHA_RSA_WITH_AES_256_CBC_SHA, + TLS1_CK_SRP_SHA_RSA_WITH_AES_256_CBC_SHA, + SSL_kSRP, + SSL_aRSA, + SSL_AES256, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 256, + 256, + }, + + /* Cipher C022 */ + { + 1, + TLS1_TXT_SRP_SHA_DSS_WITH_AES_256_CBC_SHA, + TLS1_CK_SRP_SHA_DSS_WITH_AES_256_CBC_SHA, + SSL_kSRP, + SSL_aDSS, + SSL_AES256, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 256, + 256, + }, +#endif /* OPENSSL_NO_SRP */ +#ifndef OPENSSL_NO_ECDH + + /* HMAC based TLS v1.2 ciphersuites from RFC5289 */ + + /* Cipher C023 */ + { + 1, + TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_SHA256, + TLS1_CK_ECDHE_ECDSA_WITH_AES_128_SHA256, + SSL_kEECDH, + SSL_aECDSA, + SSL_AES128, + SSL_SHA256, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256, + 128, + 128, + }, + + /* Cipher C024 */ + { + 1, + TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_SHA384, + TLS1_CK_ECDHE_ECDSA_WITH_AES_256_SHA384, + SSL_kEECDH, + SSL_aECDSA, + SSL_AES256, + SSL_SHA384, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384, + 256, + 256, + }, + + /* Cipher C025 */ + { + 1, + TLS1_TXT_ECDH_ECDSA_WITH_AES_128_SHA256, + TLS1_CK_ECDH_ECDSA_WITH_AES_128_SHA256, + SSL_kECDHe, + SSL_aECDH, + SSL_AES128, + SSL_SHA256, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256, + 128, + 128, + }, + + /* Cipher C026 */ + { + 1, + TLS1_TXT_ECDH_ECDSA_WITH_AES_256_SHA384, + TLS1_CK_ECDH_ECDSA_WITH_AES_256_SHA384, + SSL_kECDHe, + SSL_aECDH, + SSL_AES256, + SSL_SHA384, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384, + 256, + 256, + }, + + /* Cipher C027 */ + { + 1, + TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256, + TLS1_CK_ECDHE_RSA_WITH_AES_128_SHA256, + SSL_kEECDH, + SSL_aRSA, + SSL_AES128, + SSL_SHA256, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256, + 128, + 128, + }, + + /* Cipher C028 */ + { + 1, + TLS1_TXT_ECDHE_RSA_WITH_AES_256_SHA384, + TLS1_CK_ECDHE_RSA_WITH_AES_256_SHA384, + SSL_kEECDH, + SSL_aRSA, + SSL_AES256, + SSL_SHA384, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384, + 256, + 256, + }, + + /* Cipher C029 */ + { + 1, + TLS1_TXT_ECDH_RSA_WITH_AES_128_SHA256, + TLS1_CK_ECDH_RSA_WITH_AES_128_SHA256, + SSL_kECDHr, + SSL_aECDH, + SSL_AES128, + SSL_SHA256, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256, + 128, + 128, + }, + + /* Cipher C02A */ + { + 1, + TLS1_TXT_ECDH_RSA_WITH_AES_256_SHA384, + TLS1_CK_ECDH_RSA_WITH_AES_256_SHA384, + SSL_kECDHr, + SSL_aECDH, + SSL_AES256, + SSL_SHA384, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384, + 256, + 256, + }, + + /* GCM based TLS v1.2 ciphersuites from RFC5289 */ + + /* Cipher C02B */ + { + 1, + TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + SSL_kEECDH, + SSL_aECDSA, + SSL_AES128GCM, + SSL_AEAD, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256, + 128, + 128, + }, + + /* Cipher C02C */ + { + 1, + TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + SSL_kEECDH, + SSL_aECDSA, + SSL_AES256GCM, + SSL_AEAD, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384, + 256, + 256, + }, + + /* Cipher C02D */ + { + 1, + TLS1_TXT_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, + TLS1_CK_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, + SSL_kECDHe, + SSL_aECDH, + SSL_AES128GCM, + SSL_AEAD, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256, + 128, + 128, + }, + + /* Cipher C02E */ + { + 1, + TLS1_TXT_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, + TLS1_CK_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, + SSL_kECDHe, + SSL_aECDH, + SSL_AES256GCM, + SSL_AEAD, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384, + 256, + 256, + }, + + /* Cipher C02F */ + { + 1, + TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + SSL_kEECDH, + SSL_aRSA, + SSL_AES128GCM, + SSL_AEAD, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256, + 128, + 128, + }, + + /* Cipher C030 */ + { + 1, + TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + SSL_kEECDH, + SSL_aRSA, + SSL_AES256GCM, + SSL_AEAD, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384, + 256, + 256, + }, + + /* Cipher C031 */ + { + 1, + TLS1_TXT_ECDH_RSA_WITH_AES_128_GCM_SHA256, + TLS1_CK_ECDH_RSA_WITH_AES_128_GCM_SHA256, + SSL_kECDHr, + SSL_aECDH, + SSL_AES128GCM, + SSL_AEAD, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256, + 128, + 128, + }, + + /* Cipher C032 */ + { + 1, + TLS1_TXT_ECDH_RSA_WITH_AES_256_GCM_SHA384, + TLS1_CK_ECDH_RSA_WITH_AES_256_GCM_SHA384, + SSL_kECDHr, + SSL_aECDH, + SSL_AES256GCM, + SSL_AEAD, + SSL_TLSV1_2, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA384 | TLS1_PRF_SHA384, + 256, + 256, + }, + +#endif /* OPENSSL_NO_ECDH */ + +#ifdef TEMP_GOST_TLS +/* Cipher FF00 */ + { + 1, + "GOST-MD5", + 0x0300ff00, + SSL_kRSA, + SSL_aRSA, + SSL_eGOST2814789CNT, + SSL_MD5, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 256, + 256, + }, + { + 1, + "GOST-GOST94", + 0x0300ff01, + SSL_kRSA, + SSL_aRSA, + SSL_eGOST2814789CNT, + SSL_GOST94, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 256, + 256}, + { + 1, + "GOST-GOST89MAC", + 0x0300ff02, + SSL_kRSA, + SSL_aRSA, + SSL_eGOST2814789CNT, + SSL_GOST89MAC, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, + 256, + 256}, + { + 1, + "GOST-GOST89STREAM", + 0x0300ff03, + SSL_kRSA, + SSL_aRSA, + SSL_eGOST2814789CNT, + SSL_GOST89MAC, + SSL_TLSV1, + SSL_NOT_EXP | SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF | TLS1_STREAM_MAC, + 256, + 256}, +#endif + +/* end of list */ +}; + +SSL3_ENC_METHOD SSLv3_enc_data = { + ssl3_enc, + n_ssl3_mac, + ssl3_setup_key_block, + ssl3_generate_master_secret, + ssl3_change_cipher_state, + ssl3_final_finish_mac, + MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH, + ssl3_cert_verify_mac, + SSL3_MD_CLIENT_FINISHED_CONST, 4, + SSL3_MD_SERVER_FINISHED_CONST, 4, + ssl3_alert_code, + (int (*)(SSL *, unsigned char *, size_t, const char *, + size_t, const unsigned char *, size_t, + int use_context))ssl_undefined_function, + 0, + SSL3_HM_HEADER_LENGTH, + ssl3_set_handshake_header, + ssl3_handshake_write +}; + +long ssl3_default_timeout(void) +{ + /* + * 2 hours, the 24 hours mentioned in the SSLv3 spec is way too long for + * http, the cache would over fill + */ + return (60 * 60 * 2); +} + +int ssl3_num_ciphers(void) +{ + return (SSL3_NUM_CIPHERS); +} + +const SSL_CIPHER *ssl3_get_cipher(unsigned int u) +{ + if (u < SSL3_NUM_CIPHERS) + return (&(ssl3_ciphers[SSL3_NUM_CIPHERS - 1 - u])); + else + return (NULL); +} + +int ssl3_pending(const SSL *s) +{ + if (s->rstate == SSL_ST_READ_BODY) + return 0; + + return (s->s3->rrec.type == + SSL3_RT_APPLICATION_DATA) ? s->s3->rrec.length : 0; +} + +void ssl3_set_handshake_header(SSL *s, int htype, unsigned long len) +{ + unsigned char *p = (unsigned char *)s->init_buf->data; + *(p++) = htype; + l2n3(len, p); + s->init_num = (int)len + SSL3_HM_HEADER_LENGTH; + s->init_off = 0; +} + +int ssl3_handshake_write(SSL *s) +{ + return ssl3_do_write(s, SSL3_RT_HANDSHAKE); +} + +int ssl3_new(SSL *s) +{ + SSL3_STATE *s3; + + if ((s3 = OPENSSL_malloc(sizeof *s3)) == NULL) + goto err; + memset(s3, 0, sizeof *s3); + memset(s3->rrec.seq_num, 0, sizeof(s3->rrec.seq_num)); + memset(s3->wrec.seq_num, 0, sizeof(s3->wrec.seq_num)); + + s->s3 = s3; + +#ifndef OPENSSL_NO_SRP + SSL_SRP_CTX_init(s); +#endif + s->method->ssl_clear(s); + return (1); + err: + return (0); +} + +void ssl3_free(SSL *s) +{ + if (s == NULL || s->s3 == NULL) + return; + +#ifdef TLSEXT_TYPE_opaque_prf_input + if (s->s3->client_opaque_prf_input != NULL) + OPENSSL_free(s->s3->client_opaque_prf_input); + if (s->s3->server_opaque_prf_input != NULL) + OPENSSL_free(s->s3->server_opaque_prf_input); +#endif + + ssl3_cleanup_key_block(s); + if (s->s3->rbuf.buf != NULL) + ssl3_release_read_buffer(s); + if (s->s3->wbuf.buf != NULL) + ssl3_release_write_buffer(s); + if (s->s3->rrec.comp != NULL) + OPENSSL_free(s->s3->rrec.comp); +#ifndef OPENSSL_NO_DH + if (s->s3->tmp.dh != NULL) + DH_free(s->s3->tmp.dh); +#endif +#ifndef OPENSSL_NO_ECDH + if (s->s3->tmp.ecdh != NULL) + EC_KEY_free(s->s3->tmp.ecdh); +#endif + + if (s->s3->tmp.ca_names != NULL) + sk_X509_NAME_pop_free(s->s3->tmp.ca_names, X509_NAME_free); + if (s->s3->handshake_buffer) { + BIO_free(s->s3->handshake_buffer); + } + if (s->s3->handshake_dgst) + ssl3_free_digest_list(s); +#ifndef OPENSSL_NO_TLSEXT + if (s->s3->alpn_selected) + OPENSSL_free(s->s3->alpn_selected); +#endif + +#ifndef OPENSSL_NO_SRP + SSL_SRP_CTX_free(s); +#endif + OPENSSL_cleanse(s->s3, sizeof *s->s3); + OPENSSL_free(s->s3); + s->s3 = NULL; +} + +void ssl3_clear(SSL *s) +{ + unsigned char *rp, *wp; + size_t rlen, wlen; + int init_extra; + +#ifdef TLSEXT_TYPE_opaque_prf_input + if (s->s3->client_opaque_prf_input != NULL) + OPENSSL_free(s->s3->client_opaque_prf_input); + s->s3->client_opaque_prf_input = NULL; + if (s->s3->server_opaque_prf_input != NULL) + OPENSSL_free(s->s3->server_opaque_prf_input); + s->s3->server_opaque_prf_input = NULL; +#endif + + ssl3_cleanup_key_block(s); + if (s->s3->tmp.ca_names != NULL) + sk_X509_NAME_pop_free(s->s3->tmp.ca_names, X509_NAME_free); + + if (s->s3->rrec.comp != NULL) { + OPENSSL_free(s->s3->rrec.comp); + s->s3->rrec.comp = NULL; + } +#ifndef OPENSSL_NO_DH + if (s->s3->tmp.dh != NULL) { + DH_free(s->s3->tmp.dh); + s->s3->tmp.dh = NULL; + } +#endif +#ifndef OPENSSL_NO_ECDH + if (s->s3->tmp.ecdh != NULL) { + EC_KEY_free(s->s3->tmp.ecdh); + s->s3->tmp.ecdh = NULL; + } +#endif +#ifndef OPENSSL_NO_TLSEXT +# ifndef OPENSSL_NO_EC + s->s3->is_probably_safari = 0; +# endif /* !OPENSSL_NO_EC */ +#endif /* !OPENSSL_NO_TLSEXT */ + + rp = s->s3->rbuf.buf; + wp = s->s3->wbuf.buf; + rlen = s->s3->rbuf.len; + wlen = s->s3->wbuf.len; + init_extra = s->s3->init_extra; + if (s->s3->handshake_buffer) { + BIO_free(s->s3->handshake_buffer); + s->s3->handshake_buffer = NULL; + } + if (s->s3->handshake_dgst) { + ssl3_free_digest_list(s); + } +#if !defined(OPENSSL_NO_TLSEXT) + if (s->s3->alpn_selected) { + OPENSSL_free(s->s3->alpn_selected); + s->s3->alpn_selected = NULL; + } +#endif + memset(s->s3, 0, sizeof *s->s3); + s->s3->rbuf.buf = rp; + s->s3->wbuf.buf = wp; + s->s3->rbuf.len = rlen; + s->s3->wbuf.len = wlen; + s->s3->init_extra = init_extra; + + ssl_free_wbio_buffer(s); + + s->packet_length = 0; + s->s3->renegotiate = 0; + s->s3->total_renegotiations = 0; + s->s3->num_renegotiations = 0; + s->s3->in_read_app_data = 0; + s->version = SSL3_VERSION; + +#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) + if (s->next_proto_negotiated) { + OPENSSL_free(s->next_proto_negotiated); + s->next_proto_negotiated = NULL; + s->next_proto_negotiated_len = 0; + } +#endif +} + +#ifndef OPENSSL_NO_SRP +static char *MS_CALLBACK srp_password_from_info_cb(SSL *s, void *arg) +{ + return BUF_strdup(s->srp_ctx.info); +} +#endif + +static int ssl3_set_req_cert_type(CERT *c, const unsigned char *p, + size_t len); + +long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg) +{ + int ret = 0; + +#if !defined(OPENSSL_NO_DSA) || !defined(OPENSSL_NO_RSA) + if ( +# ifndef OPENSSL_NO_RSA + cmd == SSL_CTRL_SET_TMP_RSA || cmd == SSL_CTRL_SET_TMP_RSA_CB || +# endif +# ifndef OPENSSL_NO_DSA + cmd == SSL_CTRL_SET_TMP_DH || cmd == SSL_CTRL_SET_TMP_DH_CB || +# endif + 0) { + if (!ssl_cert_inst(&s->cert)) { + SSLerr(SSL_F_SSL3_CTRL, ERR_R_MALLOC_FAILURE); + return (0); + } + } +#endif + + switch (cmd) { + case SSL_CTRL_GET_SESSION_REUSED: + ret = s->hit; + break; + case SSL_CTRL_GET_CLIENT_CERT_REQUEST: + break; + case SSL_CTRL_GET_NUM_RENEGOTIATIONS: + ret = s->s3->num_renegotiations; + break; + case SSL_CTRL_CLEAR_NUM_RENEGOTIATIONS: + ret = s->s3->num_renegotiations; + s->s3->num_renegotiations = 0; + break; + case SSL_CTRL_GET_TOTAL_RENEGOTIATIONS: + ret = s->s3->total_renegotiations; + break; + case SSL_CTRL_GET_FLAGS: + ret = (int)(s->s3->flags); + break; +#ifndef OPENSSL_NO_RSA + case SSL_CTRL_NEED_TMP_RSA: + if ((s->cert != NULL) && (s->cert->rsa_tmp == NULL) && + ((s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL) || + (EVP_PKEY_size(s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey) > + (512 / 8)))) + ret = 1; + break; + case SSL_CTRL_SET_TMP_RSA: + { + RSA *rsa = (RSA *)parg; + if (rsa == NULL) { + SSLerr(SSL_F_SSL3_CTRL, ERR_R_PASSED_NULL_PARAMETER); + return (ret); + } + if ((rsa = RSAPrivateKey_dup(rsa)) == NULL) { + SSLerr(SSL_F_SSL3_CTRL, ERR_R_RSA_LIB); + return (ret); + } + if (s->cert->rsa_tmp != NULL) + RSA_free(s->cert->rsa_tmp); + s->cert->rsa_tmp = rsa; + ret = 1; + } + break; + case SSL_CTRL_SET_TMP_RSA_CB: + { + SSLerr(SSL_F_SSL3_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return (ret); + } + break; +#endif +#ifndef OPENSSL_NO_DH + case SSL_CTRL_SET_TMP_DH: + { + DH *dh = (DH *)parg; + if (dh == NULL) { + SSLerr(SSL_F_SSL3_CTRL, ERR_R_PASSED_NULL_PARAMETER); + return (ret); + } + if ((dh = DHparams_dup(dh)) == NULL) { + SSLerr(SSL_F_SSL3_CTRL, ERR_R_DH_LIB); + return (ret); + } + if (s->cert->dh_tmp != NULL) + DH_free(s->cert->dh_tmp); + s->cert->dh_tmp = dh; + ret = 1; + } + break; + case SSL_CTRL_SET_TMP_DH_CB: + { + SSLerr(SSL_F_SSL3_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return (ret); + } + break; +#endif +#ifndef OPENSSL_NO_ECDH + case SSL_CTRL_SET_TMP_ECDH: + { + EC_KEY *ecdh = NULL; + + if (parg == NULL) { + SSLerr(SSL_F_SSL3_CTRL, ERR_R_PASSED_NULL_PARAMETER); + return (ret); + } + if (!EC_KEY_up_ref((EC_KEY *)parg)) { + SSLerr(SSL_F_SSL3_CTRL, ERR_R_ECDH_LIB); + return (ret); + } + ecdh = (EC_KEY *)parg; + if (!(s->options & SSL_OP_SINGLE_ECDH_USE)) { + if (!EC_KEY_generate_key(ecdh)) { + EC_KEY_free(ecdh); + SSLerr(SSL_F_SSL3_CTRL, ERR_R_ECDH_LIB); + return (ret); + } + } + if (s->cert->ecdh_tmp != NULL) + EC_KEY_free(s->cert->ecdh_tmp); + s->cert->ecdh_tmp = ecdh; + ret = 1; + } + break; + case SSL_CTRL_SET_TMP_ECDH_CB: + { + SSLerr(SSL_F_SSL3_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return (ret); + } + break; +#endif /* !OPENSSL_NO_ECDH */ +#ifndef OPENSSL_NO_TLSEXT + case SSL_CTRL_SET_TLSEXT_HOSTNAME: + if (larg == TLSEXT_NAMETYPE_host_name) { + size_t len; + + if (s->tlsext_hostname != NULL) + OPENSSL_free(s->tlsext_hostname); + s->tlsext_hostname = NULL; + + ret = 1; + if (parg == NULL) + break; + len = strlen((char *)parg); + if (len == 0 || len > TLSEXT_MAXLEN_host_name) { + SSLerr(SSL_F_SSL3_CTRL, SSL_R_SSL3_EXT_INVALID_SERVERNAME); + return 0; + } + if ((s->tlsext_hostname = BUF_strdup((char *)parg)) == NULL) { + SSLerr(SSL_F_SSL3_CTRL, ERR_R_INTERNAL_ERROR); + return 0; + } + } else { + SSLerr(SSL_F_SSL3_CTRL, SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE); + return 0; + } + break; + case SSL_CTRL_SET_TLSEXT_DEBUG_ARG: + s->tlsext_debug_arg = parg; + ret = 1; + break; + +# ifdef TLSEXT_TYPE_opaque_prf_input + case SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT: + if (larg > 12288) { /* actual internal limit is 2^16 for the + * complete hello message * (including the + * cert chain and everything) */ + SSLerr(SSL_F_SSL3_CTRL, SSL_R_OPAQUE_PRF_INPUT_TOO_LONG); + break; + } + if (s->tlsext_opaque_prf_input != NULL) + OPENSSL_free(s->tlsext_opaque_prf_input); + if ((size_t)larg == 0) + s->tlsext_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte + * just to get + * non-NULL */ + else + s->tlsext_opaque_prf_input = BUF_memdup(parg, (size_t)larg); + if (s->tlsext_opaque_prf_input != NULL) { + s->tlsext_opaque_prf_input_len = (size_t)larg; + ret = 1; + } else + s->tlsext_opaque_prf_input_len = 0; + break; +# endif + + case SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE: + s->tlsext_status_type = larg; + ret = 1; + break; + + case SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS: + *(STACK_OF(X509_EXTENSION) **)parg = s->tlsext_ocsp_exts; + ret = 1; + break; + + case SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS: + s->tlsext_ocsp_exts = parg; + ret = 1; + break; + + case SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS: + *(STACK_OF(OCSP_RESPID) **)parg = s->tlsext_ocsp_ids; + ret = 1; + break; + + case SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS: + s->tlsext_ocsp_ids = parg; + ret = 1; + break; + + case SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP: + *(unsigned char **)parg = s->tlsext_ocsp_resp; + return s->tlsext_ocsp_resplen; + + case SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP: + if (s->tlsext_ocsp_resp) + OPENSSL_free(s->tlsext_ocsp_resp); + s->tlsext_ocsp_resp = parg; + s->tlsext_ocsp_resplen = larg; + ret = 1; + break; + +# ifndef OPENSSL_NO_HEARTBEATS + case SSL_CTRL_TLS_EXT_SEND_HEARTBEAT: + if (SSL_IS_DTLS(s)) + ret = dtls1_heartbeat(s); + else + ret = tls1_heartbeat(s); + break; + + case SSL_CTRL_GET_TLS_EXT_HEARTBEAT_PENDING: + ret = s->tlsext_hb_pending; + break; + + case SSL_CTRL_SET_TLS_EXT_HEARTBEAT_NO_REQUESTS: + if (larg) + s->tlsext_heartbeat |= SSL_TLSEXT_HB_DONT_RECV_REQUESTS; + else + s->tlsext_heartbeat &= ~SSL_TLSEXT_HB_DONT_RECV_REQUESTS; + ret = 1; + break; +# endif + +#endif /* !OPENSSL_NO_TLSEXT */ + + case SSL_CTRL_CHAIN: + if (larg) + return ssl_cert_set1_chain(s->cert, (STACK_OF(X509) *)parg); + else + return ssl_cert_set0_chain(s->cert, (STACK_OF(X509) *)parg); + + case SSL_CTRL_CHAIN_CERT: + if (larg) + return ssl_cert_add1_chain_cert(s->cert, (X509 *)parg); + else + return ssl_cert_add0_chain_cert(s->cert, (X509 *)parg); + + case SSL_CTRL_GET_CHAIN_CERTS: + *(STACK_OF(X509) **)parg = s->cert->key->chain; + break; + + case SSL_CTRL_SELECT_CURRENT_CERT: + return ssl_cert_select_current(s->cert, (X509 *)parg); + + case SSL_CTRL_SET_CURRENT_CERT: + if (larg == SSL_CERT_SET_SERVER) { + CERT_PKEY *cpk; + const SSL_CIPHER *cipher; + if (!s->server) + return 0; + cipher = s->s3->tmp.new_cipher; + if (!cipher) + return 0; + /* + * No certificate for unauthenticated ciphersuites or using SRP + * authentication + */ + if (cipher->algorithm_auth & (SSL_aNULL | SSL_aSRP)) + return 2; + cpk = ssl_get_server_send_pkey(s); + if (!cpk) + return 0; + s->cert->key = cpk; + return 1; + } + return ssl_cert_set_current(s->cert, larg); + +#ifndef OPENSSL_NO_EC + case SSL_CTRL_GET_CURVES: + { + unsigned char *clist; + size_t clistlen; + if (!s->session) + return 0; + clist = s->session->tlsext_ellipticcurvelist; + clistlen = s->session->tlsext_ellipticcurvelist_length / 2; + if (parg) { + size_t i; + int *cptr = parg; + unsigned int cid, nid; + for (i = 0; i < clistlen; i++) { + n2s(clist, cid); + nid = tls1_ec_curve_id2nid(cid); + if (nid != 0) + cptr[i] = nid; + else + cptr[i] = TLSEXT_nid_unknown | cid; + } + } + return (int)clistlen; + } + + case SSL_CTRL_SET_CURVES: + return tls1_set_curves(&s->tlsext_ellipticcurvelist, + &s->tlsext_ellipticcurvelist_length, + parg, larg); + + case SSL_CTRL_SET_CURVES_LIST: + return tls1_set_curves_list(&s->tlsext_ellipticcurvelist, + &s->tlsext_ellipticcurvelist_length, + parg); + + case SSL_CTRL_GET_SHARED_CURVE: + return tls1_shared_curve(s, larg); + +# ifndef OPENSSL_NO_ECDH + case SSL_CTRL_SET_ECDH_AUTO: + s->cert->ecdh_tmp_auto = larg; + return 1; +# endif +#endif + case SSL_CTRL_SET_SIGALGS: + return tls1_set_sigalgs(s->cert, parg, larg, 0); + + case SSL_CTRL_SET_SIGALGS_LIST: + return tls1_set_sigalgs_list(s->cert, parg, 0); + + case SSL_CTRL_SET_CLIENT_SIGALGS: + return tls1_set_sigalgs(s->cert, parg, larg, 1); + + case SSL_CTRL_SET_CLIENT_SIGALGS_LIST: + return tls1_set_sigalgs_list(s->cert, parg, 1); + + case SSL_CTRL_GET_CLIENT_CERT_TYPES: + { + const unsigned char **pctype = parg; + if (s->server || !s->s3->tmp.cert_req) + return 0; + if (s->cert->ctypes) { + if (pctype) + *pctype = s->cert->ctypes; + return (int)s->cert->ctype_num; + } + if (pctype) + *pctype = (unsigned char *)s->s3->tmp.ctype; + return s->s3->tmp.ctype_num; + } + + case SSL_CTRL_SET_CLIENT_CERT_TYPES: + if (!s->server) + return 0; + return ssl3_set_req_cert_type(s->cert, parg, larg); + + case SSL_CTRL_BUILD_CERT_CHAIN: + return ssl_build_cert_chain(s->cert, s->ctx->cert_store, larg); + + case SSL_CTRL_SET_VERIFY_CERT_STORE: + return ssl_cert_set_cert_store(s->cert, parg, 0, larg); + + case SSL_CTRL_SET_CHAIN_CERT_STORE: + return ssl_cert_set_cert_store(s->cert, parg, 1, larg); + + case SSL_CTRL_GET_PEER_SIGNATURE_NID: + if (SSL_USE_SIGALGS(s)) { + if (s->session && s->session->sess_cert) { + const EVP_MD *sig; + sig = s->session->sess_cert->peer_key->digest; + if (sig) { + *(int *)parg = EVP_MD_type(sig); + return 1; + } + } + return 0; + } + /* Might want to do something here for other versions */ + else + return 0; + + case SSL_CTRL_GET_SERVER_TMP_KEY: + if (s->server || !s->session || !s->session->sess_cert) + return 0; + else { + SESS_CERT *sc; + EVP_PKEY *ptmp; + int rv = 0; + sc = s->session->sess_cert; +#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_DH) && !defined(OPENSSL_NO_EC) && !defined(OPENSSL_NO_ECDH) + if (!sc->peer_rsa_tmp && !sc->peer_dh_tmp && !sc->peer_ecdh_tmp) + return 0; +#endif + ptmp = EVP_PKEY_new(); + if (!ptmp) + return 0; + if (0) ; +#ifndef OPENSSL_NO_RSA + else if (sc->peer_rsa_tmp) + rv = EVP_PKEY_set1_RSA(ptmp, sc->peer_rsa_tmp); +#endif +#ifndef OPENSSL_NO_DH + else if (sc->peer_dh_tmp) + rv = EVP_PKEY_set1_DH(ptmp, sc->peer_dh_tmp); +#endif +#ifndef OPENSSL_NO_ECDH + else if (sc->peer_ecdh_tmp) + rv = EVP_PKEY_set1_EC_KEY(ptmp, sc->peer_ecdh_tmp); +#endif + if (rv) { + *(EVP_PKEY **)parg = ptmp; + return 1; + } + EVP_PKEY_free(ptmp); + return 0; + } +#ifndef OPENSSL_NO_EC + case SSL_CTRL_GET_EC_POINT_FORMATS: + { + SSL_SESSION *sess = s->session; + const unsigned char **pformat = parg; + if (!sess || !sess->tlsext_ecpointformatlist) + return 0; + *pformat = sess->tlsext_ecpointformatlist; + return (int)sess->tlsext_ecpointformatlist_length; + } +#endif + + case SSL_CTRL_CHECK_PROTO_VERSION: + /* + * For library-internal use; checks that the current protocol is the + * highest enabled version (according to s->ctx->method, as version + * negotiation may have changed s->method). + */ + if (s->version == s->ctx->method->version) + return 1; + /* + * Apparently we're using a version-flexible SSL_METHOD (not at its + * highest protocol version). + */ + if (s->ctx->method->version == SSLv23_method()->version) { +#if TLS_MAX_VERSION != TLS1_2_VERSION +# error Code needs update for SSLv23_method() support beyond TLS1_2_VERSION. +#endif + if (!(s->options & SSL_OP_NO_TLSv1_2)) + return s->version == TLS1_2_VERSION; + if (!(s->options & SSL_OP_NO_TLSv1_1)) + return s->version == TLS1_1_VERSION; + if (!(s->options & SSL_OP_NO_TLSv1)) + return s->version == TLS1_VERSION; + if (!(s->options & SSL_OP_NO_SSLv3)) + return s->version == SSL3_VERSION; + if (!(s->options & SSL_OP_NO_SSLv2)) + return s->version == SSL2_VERSION; + } + return 0; /* Unexpected state; fail closed. */ + + default: + break; + } + return (ret); +} + +long ssl3_callback_ctrl(SSL *s, int cmd, void (*fp) (void)) +{ + int ret = 0; + +#if !defined(OPENSSL_NO_DSA) || !defined(OPENSSL_NO_RSA) + if ( +# ifndef OPENSSL_NO_RSA + cmd == SSL_CTRL_SET_TMP_RSA_CB || +# endif +# ifndef OPENSSL_NO_DSA + cmd == SSL_CTRL_SET_TMP_DH_CB || +# endif + 0) { + if (!ssl_cert_inst(&s->cert)) { + SSLerr(SSL_F_SSL3_CALLBACK_CTRL, ERR_R_MALLOC_FAILURE); + return (0); + } + } +#endif + + switch (cmd) { +#ifndef OPENSSL_NO_RSA + case SSL_CTRL_SET_TMP_RSA_CB: + { + s->cert->rsa_tmp_cb = (RSA *(*)(SSL *, int, int))fp; + } + break; +#endif +#ifndef OPENSSL_NO_DH + case SSL_CTRL_SET_TMP_DH_CB: + { + s->cert->dh_tmp_cb = (DH *(*)(SSL *, int, int))fp; + } + break; +#endif +#ifndef OPENSSL_NO_ECDH + case SSL_CTRL_SET_TMP_ECDH_CB: + { + s->cert->ecdh_tmp_cb = (EC_KEY *(*)(SSL *, int, int))fp; + } + break; +#endif +#ifndef OPENSSL_NO_TLSEXT + case SSL_CTRL_SET_TLSEXT_DEBUG_CB: + s->tlsext_debug_cb = (void (*)(SSL *, int, int, + unsigned char *, int, void *))fp; + break; +#endif + default: + break; + } + return (ret); +} + +long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) +{ + CERT *cert; + + cert = ctx->cert; + + switch (cmd) { +#ifndef OPENSSL_NO_RSA + case SSL_CTRL_NEED_TMP_RSA: + if ((cert->rsa_tmp == NULL) && + ((cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL) || + (EVP_PKEY_size(cert->pkeys[SSL_PKEY_RSA_ENC].privatekey) > + (512 / 8))) + ) + return (1); + else + return (0); + /* break; */ + case SSL_CTRL_SET_TMP_RSA: + { + RSA *rsa; + int i; + + rsa = (RSA *)parg; + i = 1; + if (rsa == NULL) + i = 0; + else { + if ((rsa = RSAPrivateKey_dup(rsa)) == NULL) + i = 0; + } + if (!i) { + SSLerr(SSL_F_SSL3_CTX_CTRL, ERR_R_RSA_LIB); + return (0); + } else { + if (cert->rsa_tmp != NULL) + RSA_free(cert->rsa_tmp); + cert->rsa_tmp = rsa; + return (1); + } + } + /* break; */ + case SSL_CTRL_SET_TMP_RSA_CB: + { + SSLerr(SSL_F_SSL3_CTX_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return (0); + } + break; +#endif +#ifndef OPENSSL_NO_DH + case SSL_CTRL_SET_TMP_DH: + { + DH *new = NULL, *dh; + + dh = (DH *)parg; + if ((new = DHparams_dup(dh)) == NULL) { + SSLerr(SSL_F_SSL3_CTX_CTRL, ERR_R_DH_LIB); + return 0; + } + if (cert->dh_tmp != NULL) + DH_free(cert->dh_tmp); + cert->dh_tmp = new; + return 1; + } + /* + * break; + */ + case SSL_CTRL_SET_TMP_DH_CB: + { + SSLerr(SSL_F_SSL3_CTX_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return (0); + } + break; +#endif +#ifndef OPENSSL_NO_ECDH + case SSL_CTRL_SET_TMP_ECDH: + { + EC_KEY *ecdh = NULL; + + if (parg == NULL) { + SSLerr(SSL_F_SSL3_CTX_CTRL, ERR_R_ECDH_LIB); + return 0; + } + ecdh = EC_KEY_dup((EC_KEY *)parg); + if (ecdh == NULL) { + SSLerr(SSL_F_SSL3_CTX_CTRL, ERR_R_EC_LIB); + return 0; + } + if (!(ctx->options & SSL_OP_SINGLE_ECDH_USE)) { + if (!EC_KEY_generate_key(ecdh)) { + EC_KEY_free(ecdh); + SSLerr(SSL_F_SSL3_CTX_CTRL, ERR_R_ECDH_LIB); + return 0; + } + } + + if (cert->ecdh_tmp != NULL) { + EC_KEY_free(cert->ecdh_tmp); + } + cert->ecdh_tmp = ecdh; + return 1; + } + /* break; */ + case SSL_CTRL_SET_TMP_ECDH_CB: + { + SSLerr(SSL_F_SSL3_CTX_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return (0); + } + break; +#endif /* !OPENSSL_NO_ECDH */ +#ifndef OPENSSL_NO_TLSEXT + case SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG: + ctx->tlsext_servername_arg = parg; + break; + case SSL_CTRL_SET_TLSEXT_TICKET_KEYS: + case SSL_CTRL_GET_TLSEXT_TICKET_KEYS: + { + unsigned char *keys = parg; + if (!keys) + return 48; + if (larg != 48) { + SSLerr(SSL_F_SSL3_CTX_CTRL, SSL_R_INVALID_TICKET_KEYS_LENGTH); + return 0; + } + if (cmd == SSL_CTRL_SET_TLSEXT_TICKET_KEYS) { + memcpy(ctx->tlsext_tick_key_name, keys, 16); + memcpy(ctx->tlsext_tick_hmac_key, keys + 16, 16); + memcpy(ctx->tlsext_tick_aes_key, keys + 32, 16); + } else { + memcpy(keys, ctx->tlsext_tick_key_name, 16); + memcpy(keys + 16, ctx->tlsext_tick_hmac_key, 16); + memcpy(keys + 32, ctx->tlsext_tick_aes_key, 16); + } + return 1; + } + +# ifdef TLSEXT_TYPE_opaque_prf_input + case SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB_ARG: + ctx->tlsext_opaque_prf_input_callback_arg = parg; + return 1; +# endif + + case SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG: + ctx->tlsext_status_arg = parg; + return 1; + break; + +# ifndef OPENSSL_NO_SRP + case SSL_CTRL_SET_TLS_EXT_SRP_USERNAME: + ctx->srp_ctx.srp_Mask |= SSL_kSRP; + if (ctx->srp_ctx.login != NULL) + OPENSSL_free(ctx->srp_ctx.login); + ctx->srp_ctx.login = NULL; + if (parg == NULL) + break; + if (strlen((const char *)parg) > 255 + || strlen((const char *)parg) < 1) { + SSLerr(SSL_F_SSL3_CTX_CTRL, SSL_R_INVALID_SRP_USERNAME); + return 0; + } + if ((ctx->srp_ctx.login = BUF_strdup((char *)parg)) == NULL) { + SSLerr(SSL_F_SSL3_CTX_CTRL, ERR_R_INTERNAL_ERROR); + return 0; + } + break; + case SSL_CTRL_SET_TLS_EXT_SRP_PASSWORD: + ctx->srp_ctx.SRP_give_srp_client_pwd_callback = + srp_password_from_info_cb; + ctx->srp_ctx.info = parg; + break; + case SSL_CTRL_SET_SRP_ARG: + ctx->srp_ctx.srp_Mask |= SSL_kSRP; + ctx->srp_ctx.SRP_cb_arg = parg; + break; + + case SSL_CTRL_SET_TLS_EXT_SRP_STRENGTH: + ctx->srp_ctx.strength = larg; + break; +# endif + +# ifndef OPENSSL_NO_EC + case SSL_CTRL_SET_CURVES: + return tls1_set_curves(&ctx->tlsext_ellipticcurvelist, + &ctx->tlsext_ellipticcurvelist_length, + parg, larg); + + case SSL_CTRL_SET_CURVES_LIST: + return tls1_set_curves_list(&ctx->tlsext_ellipticcurvelist, + &ctx->tlsext_ellipticcurvelist_length, + parg); +# ifndef OPENSSL_NO_ECDH + case SSL_CTRL_SET_ECDH_AUTO: + ctx->cert->ecdh_tmp_auto = larg; + return 1; +# endif +# endif + case SSL_CTRL_SET_SIGALGS: + return tls1_set_sigalgs(ctx->cert, parg, larg, 0); + + case SSL_CTRL_SET_SIGALGS_LIST: + return tls1_set_sigalgs_list(ctx->cert, parg, 0); + + case SSL_CTRL_SET_CLIENT_SIGALGS: + return tls1_set_sigalgs(ctx->cert, parg, larg, 1); + + case SSL_CTRL_SET_CLIENT_SIGALGS_LIST: + return tls1_set_sigalgs_list(ctx->cert, parg, 1); + + case SSL_CTRL_SET_CLIENT_CERT_TYPES: + return ssl3_set_req_cert_type(ctx->cert, parg, larg); + + case SSL_CTRL_BUILD_CERT_CHAIN: + return ssl_build_cert_chain(ctx->cert, ctx->cert_store, larg); + + case SSL_CTRL_SET_VERIFY_CERT_STORE: + return ssl_cert_set_cert_store(ctx->cert, parg, 0, larg); + + case SSL_CTRL_SET_CHAIN_CERT_STORE: + return ssl_cert_set_cert_store(ctx->cert, parg, 1, larg); + +#endif /* !OPENSSL_NO_TLSEXT */ + + /* A Thawte special :-) */ + case SSL_CTRL_EXTRA_CHAIN_CERT: + if (ctx->extra_certs == NULL) { + if ((ctx->extra_certs = sk_X509_new_null()) == NULL) + return (0); + } + sk_X509_push(ctx->extra_certs, (X509 *)parg); + break; + + case SSL_CTRL_GET_EXTRA_CHAIN_CERTS: + if (ctx->extra_certs == NULL && larg == 0) + *(STACK_OF(X509) **)parg = ctx->cert->key->chain; + else + *(STACK_OF(X509) **)parg = ctx->extra_certs; + break; + + case SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS: + if (ctx->extra_certs) { + sk_X509_pop_free(ctx->extra_certs, X509_free); + ctx->extra_certs = NULL; + } + break; + + case SSL_CTRL_CHAIN: + if (larg) + return ssl_cert_set1_chain(ctx->cert, (STACK_OF(X509) *)parg); + else + return ssl_cert_set0_chain(ctx->cert, (STACK_OF(X509) *)parg); + + case SSL_CTRL_CHAIN_CERT: + if (larg) + return ssl_cert_add1_chain_cert(ctx->cert, (X509 *)parg); + else + return ssl_cert_add0_chain_cert(ctx->cert, (X509 *)parg); + + case SSL_CTRL_GET_CHAIN_CERTS: + *(STACK_OF(X509) **)parg = ctx->cert->key->chain; + break; + + case SSL_CTRL_SELECT_CURRENT_CERT: + return ssl_cert_select_current(ctx->cert, (X509 *)parg); + + case SSL_CTRL_SET_CURRENT_CERT: + return ssl_cert_set_current(ctx->cert, larg); + + default: + return (0); + } + return (1); +} + +long ssl3_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp) (void)) +{ + CERT *cert; + + cert = ctx->cert; + + switch (cmd) { +#ifndef OPENSSL_NO_RSA + case SSL_CTRL_SET_TMP_RSA_CB: + { + cert->rsa_tmp_cb = (RSA *(*)(SSL *, int, int))fp; + } + break; +#endif +#ifndef OPENSSL_NO_DH + case SSL_CTRL_SET_TMP_DH_CB: + { + cert->dh_tmp_cb = (DH *(*)(SSL *, int, int))fp; + } + break; +#endif +#ifndef OPENSSL_NO_ECDH + case SSL_CTRL_SET_TMP_ECDH_CB: + { + cert->ecdh_tmp_cb = (EC_KEY *(*)(SSL *, int, int))fp; + } + break; +#endif +#ifndef OPENSSL_NO_TLSEXT + case SSL_CTRL_SET_TLSEXT_SERVERNAME_CB: + ctx->tlsext_servername_callback = (int (*)(SSL *, int *, void *))fp; + break; + +# ifdef TLSEXT_TYPE_opaque_prf_input + case SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB: + ctx->tlsext_opaque_prf_input_callback = + (int (*)(SSL *, void *, size_t, void *))fp; + break; +# endif + + case SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB: + ctx->tlsext_status_cb = (int (*)(SSL *, void *))fp; + break; + + case SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB: + ctx->tlsext_ticket_key_cb = (int (*)(SSL *, unsigned char *, + unsigned char *, + EVP_CIPHER_CTX *, + HMAC_CTX *, int))fp; + break; + +# ifndef OPENSSL_NO_SRP + case SSL_CTRL_SET_SRP_VERIFY_PARAM_CB: + ctx->srp_ctx.srp_Mask |= SSL_kSRP; + ctx->srp_ctx.SRP_verify_param_callback = (int (*)(SSL *, void *))fp; + break; + case SSL_CTRL_SET_TLS_EXT_SRP_USERNAME_CB: + ctx->srp_ctx.srp_Mask |= SSL_kSRP; + ctx->srp_ctx.TLS_ext_srp_username_callback = + (int (*)(SSL *, int *, void *))fp; + break; + case SSL_CTRL_SET_SRP_GIVE_CLIENT_PWD_CB: + ctx->srp_ctx.srp_Mask |= SSL_kSRP; + ctx->srp_ctx.SRP_give_srp_client_pwd_callback = + (char *(*)(SSL *, void *))fp; + break; +# endif +#endif + default: + return (0); + } + return (1); +} + +/* + * This function needs to check if the ciphers required are actually + * available + */ +const SSL_CIPHER *ssl3_get_cipher_by_char(const unsigned char *p) +{ + SSL_CIPHER c; + const SSL_CIPHER *cp; + unsigned long id; + + id = 0x03000000L | ((unsigned long)p[0] << 8L) | (unsigned long)p[1]; + c.id = id; + cp = OBJ_bsearch_ssl_cipher_id(&c, ssl3_ciphers, SSL3_NUM_CIPHERS); +#ifdef DEBUG_PRINT_UNKNOWN_CIPHERSUITES + if (cp == NULL) + fprintf(stderr, "Unknown cipher ID %x\n", (p[0] << 8) | p[1]); +#endif + return cp; +} + +int ssl3_put_cipher_by_char(const SSL_CIPHER *c, unsigned char *p) +{ + long l; + + if (p != NULL) { + l = c->id; + if ((l & 0xff000000) != 0x03000000) + return (0); + p[0] = ((unsigned char)(l >> 8L)) & 0xFF; + p[1] = ((unsigned char)(l)) & 0xFF; + } + return (2); +} + +SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt, + STACK_OF(SSL_CIPHER) *srvr) +{ + SSL_CIPHER *c, *ret = NULL; + STACK_OF(SSL_CIPHER) *prio, *allow; + int i, ii, ok; + CERT *cert; + unsigned long alg_k, alg_a, mask_k, mask_a, emask_k, emask_a; + + /* Let's see which ciphers we can support */ + cert = s->cert; + +#if 0 + /* + * Do not set the compare functions, because this may lead to a + * reordering by "id". We want to keep the original ordering. We may pay + * a price in performance during sk_SSL_CIPHER_find(), but would have to + * pay with the price of sk_SSL_CIPHER_dup(). + */ + sk_SSL_CIPHER_set_cmp_func(srvr, ssl_cipher_ptr_id_cmp); + sk_SSL_CIPHER_set_cmp_func(clnt, ssl_cipher_ptr_id_cmp); +#endif + +#ifdef CIPHER_DEBUG + fprintf(stderr, "Server has %d from %p:\n", sk_SSL_CIPHER_num(srvr), + (void *)srvr); + for (i = 0; i < sk_SSL_CIPHER_num(srvr); ++i) { + c = sk_SSL_CIPHER_value(srvr, i); + fprintf(stderr, "%p:%s\n", (void *)c, c->name); + } + fprintf(stderr, "Client sent %d from %p:\n", sk_SSL_CIPHER_num(clnt), + (void *)clnt); + for (i = 0; i < sk_SSL_CIPHER_num(clnt); ++i) { + c = sk_SSL_CIPHER_value(clnt, i); + fprintf(stderr, "%p:%s\n", (void *)c, c->name); + } +#endif + + if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE || tls1_suiteb(s)) { + prio = srvr; + allow = clnt; + } else { + prio = clnt; + allow = srvr; + } + + tls1_set_cert_validity(s); + + for (i = 0; i < sk_SSL_CIPHER_num(prio); i++) { + c = sk_SSL_CIPHER_value(prio, i); + + /* Skip TLS v1.2 only ciphersuites if not supported */ + if ((c->algorithm_ssl & SSL_TLSV1_2) && !SSL_USE_TLS1_2_CIPHERS(s)) + continue; + + ssl_set_cert_masks(cert, c); + mask_k = cert->mask_k; + mask_a = cert->mask_a; + emask_k = cert->export_mask_k; + emask_a = cert->export_mask_a; +#ifndef OPENSSL_NO_SRP + if (s->srp_ctx.srp_Mask & SSL_kSRP) { + mask_k |= SSL_kSRP; + emask_k |= SSL_kSRP; + mask_a |= SSL_aSRP; + emask_a |= SSL_aSRP; + } +#endif + +#ifdef KSSL_DEBUG + /* + * fprintf(stderr,"ssl3_choose_cipher %d alg= %lx\n", + * i,c->algorithms); + */ +#endif /* KSSL_DEBUG */ + + alg_k = c->algorithm_mkey; + alg_a = c->algorithm_auth; + +#ifndef OPENSSL_NO_KRB5 + if (alg_k & SSL_kKRB5) { + if (!kssl_keytab_is_available(s->kssl_ctx)) + continue; + } +#endif /* OPENSSL_NO_KRB5 */ +#ifndef OPENSSL_NO_PSK + /* with PSK there must be server callback set */ + if ((alg_k & SSL_kPSK) && s->psk_server_callback == NULL) + continue; +#endif /* OPENSSL_NO_PSK */ + + if (SSL_C_IS_EXPORT(c)) { + ok = (alg_k & emask_k) && (alg_a & emask_a); +#ifdef CIPHER_DEBUG + fprintf(stderr, "%d:[%08lX:%08lX:%08lX:%08lX]%p:%s (export)\n", + ok, alg_k, alg_a, emask_k, emask_a, (void *)c, c->name); +#endif + } else { + ok = (alg_k & mask_k) && (alg_a & mask_a); +#ifdef CIPHER_DEBUG + fprintf(stderr, "%d:[%08lX:%08lX:%08lX:%08lX]%p:%s\n", ok, alg_k, + alg_a, mask_k, mask_a, (void *)c, c->name); +#endif + } + +#ifndef OPENSSL_NO_TLSEXT +# ifndef OPENSSL_NO_EC +# ifndef OPENSSL_NO_ECDH + /* + * if we are considering an ECC cipher suite that uses an ephemeral + * EC key check it + */ + if (alg_k & SSL_kEECDH) + ok = ok && tls1_check_ec_tmp_key(s, c->id); +# endif /* OPENSSL_NO_ECDH */ +# endif /* OPENSSL_NO_EC */ +#endif /* OPENSSL_NO_TLSEXT */ + + if (!ok) + continue; + ii = sk_SSL_CIPHER_find(allow, c); + if (ii >= 0) { +#if !defined(OPENSSL_NO_EC) && !defined(OPENSSL_NO_TLSEXT) + if ((alg_k & SSL_kEECDH) && (alg_a & SSL_aECDSA) + && s->s3->is_probably_safari) { + if (!ret) + ret = sk_SSL_CIPHER_value(allow, ii); + continue; + } +#endif + ret = sk_SSL_CIPHER_value(allow, ii); + break; + } + } + return (ret); +} + +int ssl3_get_req_cert_type(SSL *s, unsigned char *p) +{ + int ret = 0; + const unsigned char *sig; + size_t i, siglen; + int have_rsa_sign = 0, have_dsa_sign = 0; +#ifndef OPENSSL_NO_ECDSA + int have_ecdsa_sign = 0; +#endif + int nostrict = 1; + unsigned long alg_k; + + /* If we have custom certificate types set, use them */ + if (s->cert->ctypes) { + memcpy(p, s->cert->ctypes, s->cert->ctype_num); + return (int)s->cert->ctype_num; + } + /* get configured sigalgs */ + siglen = tls12_get_psigalgs(s, &sig); + if (s->cert->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT) + nostrict = 0; + for (i = 0; i < siglen; i += 2, sig += 2) { + switch (sig[1]) { + case TLSEXT_signature_rsa: + have_rsa_sign = 1; + break; + + case TLSEXT_signature_dsa: + have_dsa_sign = 1; + break; +#ifndef OPENSSL_NO_ECDSA + case TLSEXT_signature_ecdsa: + have_ecdsa_sign = 1; + break; +#endif + } + } + + alg_k = s->s3->tmp.new_cipher->algorithm_mkey; + +#ifndef OPENSSL_NO_GOST + if (s->version >= TLS1_VERSION) { + if (alg_k & SSL_kGOST) { + p[ret++] = TLS_CT_GOST94_SIGN; + p[ret++] = TLS_CT_GOST01_SIGN; + return (ret); + } + } +#endif + +#ifndef OPENSSL_NO_DH + if (alg_k & (SSL_kDHr | SSL_kEDH)) { +# ifndef OPENSSL_NO_RSA + /* + * Since this refers to a certificate signed with an RSA algorithm, + * only check for rsa signing in strict mode. + */ + if (nostrict || have_rsa_sign) + p[ret++] = SSL3_CT_RSA_FIXED_DH; +# endif +# ifndef OPENSSL_NO_DSA + if (nostrict || have_dsa_sign) + p[ret++] = SSL3_CT_DSS_FIXED_DH; +# endif + } + if ((s->version == SSL3_VERSION) && + (alg_k & (SSL_kEDH | SSL_kDHd | SSL_kDHr))) { +# ifndef OPENSSL_NO_RSA + p[ret++] = SSL3_CT_RSA_EPHEMERAL_DH; +# endif +# ifndef OPENSSL_NO_DSA + p[ret++] = SSL3_CT_DSS_EPHEMERAL_DH; +# endif + } +#endif /* !OPENSSL_NO_DH */ +#ifndef OPENSSL_NO_RSA + if (have_rsa_sign) + p[ret++] = SSL3_CT_RSA_SIGN; +#endif +#ifndef OPENSSL_NO_DSA + if (have_dsa_sign) + p[ret++] = SSL3_CT_DSS_SIGN; +#endif +#ifndef OPENSSL_NO_ECDH + if ((alg_k & (SSL_kECDHr | SSL_kECDHe)) && (s->version >= TLS1_VERSION)) { + if (nostrict || have_rsa_sign) + p[ret++] = TLS_CT_RSA_FIXED_ECDH; + if (nostrict || have_ecdsa_sign) + p[ret++] = TLS_CT_ECDSA_FIXED_ECDH; + } +#endif + +#ifndef OPENSSL_NO_ECDSA + /* + * ECDSA certs can be used with RSA cipher suites as well so we don't + * need to check for SSL_kECDH or SSL_kEECDH + */ + if (s->version >= TLS1_VERSION) { + if (have_ecdsa_sign) + p[ret++] = TLS_CT_ECDSA_SIGN; + } +#endif + return (ret); +} + +static int ssl3_set_req_cert_type(CERT *c, const unsigned char *p, size_t len) +{ + if (c->ctypes) { + OPENSSL_free(c->ctypes); + c->ctypes = NULL; + } + if (!p || !len) + return 1; + if (len > 0xff) + return 0; + c->ctypes = OPENSSL_malloc(len); + if (!c->ctypes) + return 0; + memcpy(c->ctypes, p, len); + c->ctype_num = len; + return 1; +} + +int ssl3_shutdown(SSL *s) +{ + int ret; + + /* + * Don't do anything much if we have not done the handshake or we don't + * want to send messages :-) + */ + if ((s->quiet_shutdown) || (s->state == SSL_ST_BEFORE)) { + s->shutdown = (SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); + return (1); + } + + if (!(s->shutdown & SSL_SENT_SHUTDOWN)) { + s->shutdown |= SSL_SENT_SHUTDOWN; +#if 1 + ssl3_send_alert(s, SSL3_AL_WARNING, SSL_AD_CLOSE_NOTIFY); +#endif + /* + * our shutdown alert has been sent now, and if it still needs to be + * written, s->s3->alert_dispatch will be true + */ + if (s->s3->alert_dispatch) + return (-1); /* return WANT_WRITE */ + } else if (s->s3->alert_dispatch) { + /* resend it if not sent */ +#if 1 + ret = s->method->ssl_dispatch_alert(s); + if (ret == -1) { + /* + * we only get to return -1 here the 2nd/Nth invocation, we must + * have already signalled return 0 upon a previous invoation, + * return WANT_WRITE + */ + return (ret); + } +#endif + } else if (!(s->shutdown & SSL_RECEIVED_SHUTDOWN)) { + /* + * If we are waiting for a close from our peer, we are closed + */ + s->method->ssl_read_bytes(s, 0, NULL, 0, 0); + if (!(s->shutdown & SSL_RECEIVED_SHUTDOWN)) { + return (-1); /* return WANT_READ */ + } + } + + if ((s->shutdown == (SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN)) && + !s->s3->alert_dispatch) + return (1); + else + return (0); +} + +int ssl3_write(SSL *s, const void *buf, int len) +{ + int ret, n; + +#if 0 + if (s->shutdown & SSL_SEND_SHUTDOWN) { + s->rwstate = SSL_NOTHING; + return (0); + } +#endif + clear_sys_error(); + if (s->s3->renegotiate) + ssl3_renegotiate_check(s); + + /* + * This is an experimental flag that sends the last handshake message in + * the same packet as the first use data - used to see if it helps the + * TCP protocol during session-id reuse + */ + /* The second test is because the buffer may have been removed */ + if ((s->s3->flags & SSL3_FLAGS_POP_BUFFER) && (s->wbio == s->bbio)) { + /* First time through, we write into the buffer */ + if (s->s3->delay_buf_pop_ret == 0) { + ret = ssl3_write_bytes(s, SSL3_RT_APPLICATION_DATA, buf, len); + if (ret <= 0) + return (ret); + + s->s3->delay_buf_pop_ret = ret; + } + + s->rwstate = SSL_WRITING; + n = BIO_flush(s->wbio); + if (n <= 0) + return (n); + s->rwstate = SSL_NOTHING; + + /* We have flushed the buffer, so remove it */ + ssl_free_wbio_buffer(s); + s->s3->flags &= ~SSL3_FLAGS_POP_BUFFER; + + ret = s->s3->delay_buf_pop_ret; + s->s3->delay_buf_pop_ret = 0; + } else { + ret = s->method->ssl_write_bytes(s, SSL3_RT_APPLICATION_DATA, + buf, len); + if (ret <= 0) + return (ret); + } + + return (ret); +} + +static int ssl3_read_internal(SSL *s, void *buf, int len, int peek) +{ + int ret; + + clear_sys_error(); + if (s->s3->renegotiate) + ssl3_renegotiate_check(s); + s->s3->in_read_app_data = 1; + ret = + s->method->ssl_read_bytes(s, SSL3_RT_APPLICATION_DATA, buf, len, + peek); + if ((ret == -1) && (s->s3->in_read_app_data == 2)) { + /* + * ssl3_read_bytes decided to call s->handshake_func, which called + * ssl3_read_bytes to read handshake data. However, ssl3_read_bytes + * actually found application data and thinks that application data + * makes sense here; so disable handshake processing and try to read + * application data again. + */ + s->in_handshake++; + ret = + s->method->ssl_read_bytes(s, SSL3_RT_APPLICATION_DATA, buf, len, + peek); + s->in_handshake--; + } else + s->s3->in_read_app_data = 0; + + return (ret); +} + +int ssl3_read(SSL *s, void *buf, int len) +{ + return ssl3_read_internal(s, buf, len, 0); +} + +int ssl3_peek(SSL *s, void *buf, int len) +{ + return ssl3_read_internal(s, buf, len, 1); +} + +int ssl3_renegotiate(SSL *s) +{ + if (s->handshake_func == NULL) + return (1); + + if (s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) + return (0); + + s->s3->renegotiate = 1; + return (1); +} + +int ssl3_renegotiate_check(SSL *s) +{ + int ret = 0; + + if (s->s3->renegotiate) { + if ((s->s3->rbuf.left == 0) && + (s->s3->wbuf.left == 0) && !SSL_in_init(s)) { + /* + * if we are the server, and we have sent a 'RENEGOTIATE' + * message, we need to go to SSL_ST_ACCEPT. + */ + /* SSL_ST_ACCEPT */ + s->state = SSL_ST_RENEGOTIATE; + s->s3->renegotiate = 0; + s->s3->num_renegotiations++; + s->s3->total_renegotiations++; + ret = 1; + } + } + return (ret); +} + +/* + * If we are using default SHA1+MD5 algorithms switch to new SHA256 PRF and + * handshake macs if required. + */ +long ssl_get_algorithm2(SSL *s) +{ + long alg2 = s->s3->tmp.new_cipher->algorithm2; + if (s->method->ssl3_enc->enc_flags & SSL_ENC_FLAG_SHA256_PRF + && alg2 == (SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF)) + return SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256; + return alg2; +} diff --git a/thirdparty/openssl/ssl/s3_meth.c b/thirdparty/openssl/ssl/s3_meth.c new file mode 100644 index 0000000000..e5a52993fc --- /dev/null +++ b/thirdparty/openssl/ssl/s3_meth.c @@ -0,0 +1,74 @@ +/* ssl/s3_meth.c */ +/* 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.] + */ + +#include <stdio.h> +#include <openssl/objects.h> +#include "ssl_locl.h" + +#ifndef OPENSSL_NO_SSL3_METHOD +static const SSL_METHOD *ssl3_get_method(int ver) +{ + if (ver == SSL3_VERSION) + return (SSLv3_method()); + else + return (NULL); +} + +IMPLEMENT_ssl3_meth_func(SSLv3_method, + ssl3_accept, ssl3_connect, ssl3_get_method) +#endif diff --git a/thirdparty/openssl/ssl/s3_pkt.c b/thirdparty/openssl/ssl/s3_pkt.c new file mode 100644 index 0000000000..379890237e --- /dev/null +++ b/thirdparty/openssl/ssl/s3_pkt.c @@ -0,0 +1,1748 @@ +/* ssl/s3_pkt.c */ +/* 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 <stdio.h> +#include <limits.h> +#include <errno.h> +#define USE_SOCKETS +#include "ssl_locl.h" +#include <openssl/evp.h> +#include <openssl/buffer.h> +#include <openssl/rand.h> + +#ifndef EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK +# define EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK 0 +#endif + +#if defined(OPENSSL_SMALL_FOOTPRINT) || \ + !( defined(AES_ASM) && ( \ + defined(__x86_64) || defined(__x86_64__) || \ + defined(_M_AMD64) || defined(_M_X64) || \ + defined(__INTEL__) ) \ + ) +# undef EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK +# define EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK 0 +#endif + +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); + +int ssl3_read_n(SSL *s, int n, int max, int extend) +{ + /* + * 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->packet and s->packet_length. (If + * s->read_ahead is set, 'max' bytes may be stored in rbuf [plus + * s->packet_length bytes if extend == 1].) + */ + int i, len, left; + long align = 0; + 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; +#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0 + align = (long)rb->buf + SSL3_RT_HEADER_LENGTH; + align = (-align) & (SSL3_ALIGN_PAYLOAD - 1); +#endif + + 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->packet = rb->buf + rb->offset; + s->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 && extend) + return 0; + if (left > 0 && n > left) + n = left; + } + + /* if there is enough in the buffer from a previous read, take some */ + if (left >= n) { + s->packet_length += n; + rb->left = left - n; + rb->offset += n; + return (n); + } + + /* else we need to read more data */ + + len = s->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->packet != pkt) { /* len > 0 */ + memmove(pkt, s->packet, len + left); + s->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; + } + + /* We always act like read_ahead is set for DTLS */ + if (!s->read_ahead && !SSL_IS_DTLS(s)) + /* 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) + */ + + clear_sys_error(); + if (s->rbio != NULL) { + s->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->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->packet_length += n; + s->rwstate = SSL_NOTHING; + return (n); +} + +/* + * MAX_EMPTY_RECORDS defines the number of consecutive, empty records that + * will be processed per call to ssl3_get_record. Without this limit an + * attacker could send empty records at a faster rate than we can process and + * cause ssl3_get_record to loop forever. + */ +#define MAX_EMPTY_RECORDS 32 + +/*- + * 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->rrec.type - is the type of record + * ssl->s3->rrec.data, - data + * ssl->s3->rrec.length, - number of bytes + */ +/* used only by ssl3_read_bytes */ +static int ssl3_get_record(SSL *s) +{ + int ssl_major, ssl_minor, al; + int enc_err, n, i, ret = -1; + SSL3_RECORD *rr; + SSL_SESSION *sess; + unsigned char *p; + unsigned char md[EVP_MAX_MD_SIZE]; + short version; + unsigned mac_size, orig_len; + size_t extra; + unsigned empty_record_count = 0; + + rr = &(s->s3->rrec); + sess = s->session; + + if (s->options & SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER) + extra = SSL3_RT_MAX_EXTRA; + else + extra = 0; + if (extra && !s->s3->init_extra) { + /* + * An application error: SLS_OP_MICROSOFT_BIG_SSLV3_BUFFER set after + * ssl3_setup_buffers() was done + */ + SSLerr(SSL_F_SSL3_GET_RECORD, ERR_R_INTERNAL_ERROR); + return -1; + } + + again: + /* check if we have the header */ + if ((s->rstate != SSL_ST_READ_BODY) || + (s->packet_length < SSL3_RT_HEADER_LENGTH)) { + n = ssl3_read_n(s, SSL3_RT_HEADER_LENGTH, s->s3->rbuf.len, 0); + if (n <= 0) + return (n); /* error or non-blocking */ + s->rstate = SSL_ST_READ_BODY; + + p = s->packet; + if (s->msg_callback) + s->msg_callback(0, 0, SSL3_RT_HEADER, p, 5, s, + s->msg_callback_arg); + + /* Pull apart the header into the SSL3_RECORD */ + rr->type = *(p++); + ssl_major = *(p++); + ssl_minor = *(p++); + version = (ssl_major << 8) | ssl_minor; + n2s(p, rr->length); +#if 0 + fprintf(stderr, "Record type=%d, Length=%d\n", rr->type, rr->length); +#endif + + /* Lets check version */ + if (!s->first_packet) { + if (version != s->version) { + SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_WRONG_VERSION_NUMBER); + if ((s->version & 0xFF00) == (version & 0xFF00) + && !s->enc_write_ctx && !s->write_hash) { + if (rr->type == SSL3_RT_ALERT) { + /* + * The record is using an incorrect version number, but + * what we've got appears to be an alert. We haven't + * read the body yet to check whether its a fatal or + * not - but chances are it is. We probably shouldn't + * send a fatal alert back. We'll just end. + */ + goto err; + } + /* + * Send back error using their minor version number :-) + */ + s->version = (unsigned short)version; + } + al = SSL_AD_PROTOCOL_VERSION; + goto f_err; + } + } + + if ((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->rstate == SSL_ST_READ_BODY */ + } + + /* s->rstate == SSL_ST_READ_BODY, get and decode the data */ + + if (rr->length > s->packet_length - SSL3_RT_HEADER_LENGTH) { + /* now s->packet_length == SSL3_RT_HEADER_LENGTH */ + i = rr->length; + n = ssl3_read_n(s, i, i, 1); + if (n <= 0) + return (n); /* error or non-blocking io */ + /* + * now n == rr->length, and s->packet_length == SSL3_RT_HEADER_LENGTH + * + rr->length + */ + } + + s->rstate = SSL_ST_READ_HEADER; /* set state for later operations */ + + /* + * At this point, s->packet_length == SSL3_RT_HEADER_LNGTH + rr->length, + * and we have that many bytes in s->packet + */ + rr->input = &(s->packet[SSL3_RT_HEADER_LENGTH]); + + /* + * ok, we can now read from 's->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 + extra) { + 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->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; + } +#ifdef TLS_DEBUG + printf("dec %d\n", rr->length); + { + unsigned int z; + for (z = 0; z < rr->length; z++) + printf("%02X%c", rr->data[z], ((z + 1) % 16) ? ' ' : '\n'); + } + printf("\n"); +#endif + + /* 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->ssl3_enc->mac(s, md, 0 /* not send */ ); + if (i < 0 || mac == NULL + || CRYPTO_memcmp(md, mac, (size_t)mac_size) != 0) + enc_err = -1; + if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH + extra + 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 occured -- 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; + } + + /* r->length is now just compressed */ + if (s->expand != NULL) { + if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH + extra) { + al = SSL_AD_RECORD_OVERFLOW; + SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_COMPRESSED_LENGTH_TOO_LONG); + goto f_err; + } + if (!ssl3_do_uncompress(s)) { + al = SSL_AD_DECOMPRESSION_FAILURE; + SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_BAD_DECOMPRESSION); + goto f_err; + } + } + + if (rr->length > SSL3_RT_MAX_PLAIN_LENGTH + extra) { + 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->rrec.type is the type of record + * ssl->s3->rrec.length == number of bytes in record + * ssl->s3->rrec.off == offset to first valid byte + * ssl->s3->rrec.data == where to take bytes from, increment + * after use :-). + */ + + /* we have pulled in a full packet so zero things */ + s->packet_length = 0; + + /* just read a 0 length packet */ + if (rr->length == 0) { + empty_record_count++; + if (empty_record_count > MAX_EMPTY_RECORDS) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_RECORD_TOO_SMALL); + goto f_err; + } + goto again; + } +#if 0 + fprintf(stderr, "Ultimate Record type=%d, Length=%d\n", rr->type, + rr->length); +#endif + + return (1); + + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + err: + return (ret); +} + +int ssl3_do_uncompress(SSL *ssl) +{ +#ifndef OPENSSL_NO_COMP + int i; + SSL3_RECORD *rr; + + rr = &(ssl->s3->rrec); + i = COMP_expand_block(ssl->expand, rr->comp, + SSL3_RT_MAX_PLAIN_LENGTH, rr->data, + (int)rr->length); + if (i < 0) + return (0); + else + rr->length = i; + rr->data = rr->comp; +#endif + return (1); +} + +int ssl3_do_compress(SSL *ssl) +{ +#ifndef OPENSSL_NO_COMP + int i; + SSL3_RECORD *wr; + + wr = &(ssl->s3->wrec); + i = COMP_compress_block(ssl->compress, wr->data, + SSL3_RT_MAX_COMPRESSED_LENGTH, + wr->input, (int)wr->length); + if (i < 0) + return (0); + else + wr->length = i; + + wr->input = wr->data; +#endif + return (1); +} + +/* + * 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_; + int tot; + unsigned int n, nw; +#if !defined(OPENSSL_NO_MULTIBLOCK) && EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK + unsigned int max_send_fragment; +#endif + SSL3_BUFFER *wb = &(s->s3->wbuf); + int i; + + s->rwstate = SSL_NOTHING; + OPENSSL_assert(s->s3->wnum <= INT_MAX); + tot = s->s3->wnum; + s->s3->wnum = 0; + + if (SSL_in_init(s) && !s->in_handshake) { + i = s->handshake_func(s); + if (i < 0) + return (i); + if (i == 0) { + SSLerr(SSL_F_SSL3_WRITE_BYTES, SSL_R_SSL_HANDSHAKE_FAILURE); + return -1; + } + } + + /* + * ensure that if we end up with a smaller value of data to write out + * than the the original len from a write which didn't complete for + * non-blocking I/O and also somehow ended up avoiding the check for + * this in ssl3_write_pending/SSL_R_BAD_WRITE_RETRY as it must never be + * possible to end up with (len-tot) as a large number that will then + * promptly send beyond the end of the users buffer ... so we trap and + * report the error in a way the user will notice + */ + if (len < tot) { + SSLerr(SSL_F_SSL3_WRITE_BYTES, SSL_R_BAD_LENGTH); + 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) { + i = ssl3_write_pending(s, type, &buf[tot], s->s3->wpend_tot); + if (i <= 0) { + /* XXX should we ssl3_release_write_buffer if i<0? */ + s->s3->wnum = tot; + return i; + } + tot += i; /* this might be last fragment */ + } +#if !defined(OPENSSL_NO_MULTIBLOCK) && EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK + /* + * Depending on platform multi-block can deliver several *times* + * better performance. Downside is that it has to allocate + * jumbo buffer to accomodate up to 8 records, but the + * compromise is considered worthy. + */ + if (type == SSL3_RT_APPLICATION_DATA && + len >= 4 * (int)(max_send_fragment = s->max_send_fragment) && + s->compress == NULL && s->msg_callback == NULL && + SSL_USE_EXPLICIT_IV(s) && + EVP_CIPHER_flags(s->enc_write_ctx->cipher) & + EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK) { + unsigned char aad[13]; + EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM mb_param; + int packlen; + + /* minimize address aliasing conflicts */ + if ((max_send_fragment & 0xfff) == 0) + max_send_fragment -= 512; + + if (tot == 0 || wb->buf == NULL) { /* allocate jumbo buffer */ + ssl3_release_write_buffer(s); + + packlen = EVP_CIPHER_CTX_ctrl(s->enc_write_ctx, + EVP_CTRL_TLS1_1_MULTIBLOCK_MAX_BUFSIZE, + max_send_fragment, NULL); + + if (len >= 8 * (int)max_send_fragment) + packlen *= 8; + else + packlen *= 4; + + wb->buf = OPENSSL_malloc(packlen); + if (!wb->buf) { + SSLerr(SSL_F_SSL3_WRITE_BYTES, ERR_R_MALLOC_FAILURE); + return -1; + } + wb->len = packlen; + } else if (tot == len) { /* done? */ + OPENSSL_free(wb->buf); /* free jumbo buffer */ + wb->buf = NULL; + return tot; + } + + n = (len - tot); + for (;;) { + if (n < 4 * max_send_fragment) { + OPENSSL_free(wb->buf); /* free jumbo buffer */ + wb->buf = NULL; + break; + } + + if (s->s3->alert_dispatch) { + i = s->method->ssl_dispatch_alert(s); + if (i <= 0) { + s->s3->wnum = tot; + return i; + } + } + + if (n >= 8 * max_send_fragment) + nw = max_send_fragment * (mb_param.interleave = 8); + else + nw = max_send_fragment * (mb_param.interleave = 4); + + memcpy(aad, s->s3->write_sequence, 8); + aad[8] = type; + aad[9] = (unsigned char)(s->version >> 8); + aad[10] = (unsigned char)(s->version); + aad[11] = 0; + aad[12] = 0; + mb_param.out = NULL; + mb_param.inp = aad; + mb_param.len = nw; + + packlen = EVP_CIPHER_CTX_ctrl(s->enc_write_ctx, + EVP_CTRL_TLS1_1_MULTIBLOCK_AAD, + sizeof(mb_param), &mb_param); + + if (packlen <= 0 || packlen > (int)wb->len) { /* never happens */ + OPENSSL_free(wb->buf); /* free jumbo buffer */ + wb->buf = NULL; + break; + } + + mb_param.out = wb->buf; + mb_param.inp = &buf[tot]; + mb_param.len = nw; + + if (EVP_CIPHER_CTX_ctrl(s->enc_write_ctx, + EVP_CTRL_TLS1_1_MULTIBLOCK_ENCRYPT, + sizeof(mb_param), &mb_param) <= 0) + return -1; + + s->s3->write_sequence[7] += mb_param.interleave; + if (s->s3->write_sequence[7] < mb_param.interleave) { + int j = 6; + while (j >= 0 && (++s->s3->write_sequence[j--]) == 0) ; + } + + wb->offset = 0; + wb->left = packlen; + + s->s3->wpend_tot = nw; + s->s3->wpend_buf = &buf[tot]; + s->s3->wpend_type = type; + s->s3->wpend_ret = nw; + + i = ssl3_write_pending(s, type, &buf[tot], nw); + if (i <= 0) { + if (i < 0 && (!s->wbio || !BIO_should_retry(s->wbio))) { + OPENSSL_free(wb->buf); + wb->buf = NULL; + } + s->s3->wnum = tot; + return i; + } + if (i == (int)n) { + OPENSSL_free(wb->buf); /* free jumbo buffer */ + wb->buf = NULL; + return tot + i; + } + n -= i; + tot += i; + } + } else +#endif + if (tot == len) { /* done? */ + if (s->mode & SSL_MODE_RELEASE_BUFFERS && !SSL_IS_DTLS(s)) + ssl3_release_write_buffer(s); + + return 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) { + /* XXX should we ssl3_release_write_buffer if i<0? */ + s->s3->wnum = tot; + return i; + } + + if ((i == (int)n) || + (type == SSL3_RT_APPLICATION_DATA && + (s->mode & SSL_MODE_ENABLE_PARTIAL_WRITE))) { + /* + * next chunk of data should get another prepended empty fragment + * in ciphersuites with known-IV weakness: + */ + s->s3->empty_fragment_done = 0; + + if ((i == (int)n) && s->mode & SSL_MODE_RELEASE_BUFFERS && + !SSL_IS_DTLS(s)) + ssl3_release_write_buffer(s); + + 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; + long align = 0; + SSL3_RECORD *wr; + SSL3_BUFFER *wb = &(s->s3->wbuf); + SSL_SESSION *sess; + + /* + * 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 */ + } + + if (wb->buf == NULL) + if (!ssl3_setup_write_buffer(s)) + return -1; + + if (len == 0 && !create_empty_fragment) + return 0; + + wr = &(s->s3->wrec); + sess = s->session; + + if ((sess == NULL) || + (s->enc_write_ctx == NULL) || + (EVP_MD_CTX_md(s->write_hash) == NULL)) { +#if 1 + clear = s->enc_write_ctx ? 0 : 1; /* must be AEAD cipher */ +#else + clear = 1; +#endif + mac_size = 0; + } else { + mac_size = EVP_MD_CTX_size(s->write_hash); + if (mac_size < 0) + goto err; + } + + /* + * 'create_empty_fragment' is true only when this function calls itself + */ + if (!clear && !create_empty_fragment && !s->s3->empty_fragment_done) { + /* + * countermeasure against known-IV weakness in CBC ciphersuites (see + * http://www.openssl.org/~bodo/tls-cbc.txt) + */ + + if (s->s3->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; + } + } + + s->s3->empty_fragment_done = 1; + } + + if (create_empty_fragment) { +#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0 + /* + * 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 = (long)wb->buf + 2 * SSL3_RT_HEADER_LENGTH; + align = (-align) & (SSL3_ALIGN_PAYLOAD - 1); +#endif + p = wb->buf + align; + wb->offset = align; + } else if (prefix_len) { + p = wb->buf + wb->offset + prefix_len; + } else { +#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0 + align = (long)wb->buf + SSL3_RT_HEADER_LENGTH; + align = (-align) & (SSL3_ALIGN_PAYLOAD - 1); +#endif + 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->state == SSL3_ST_CW_CLNT_HELLO_B + && !s->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, block ciphers appropriate version flag */ + if (s->enc_write_ctx && SSL_USE_EXPLICIT_IV(s)) { + int mode = EVP_CIPHER_CTX_mode(s->enc_write_ctx); + if (mode == EVP_CIPH_CBC_MODE) { + eivlen = EVP_CIPHER_CTX_iv_length(s->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 + 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 + */ + + /* first we compress */ + if (s->compress != NULL) { + if (!ssl3_do_compress(s)) { + SSLerr(SSL_F_DO_SSL3_WRITE, SSL_R_COMPRESSION_FAILURE); + goto err; + } + } else { + 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->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; + } + + if (s->method->ssl3_enc->enc(s, 1) < 1) + goto err; + + /* record length after mac and block padding */ + s2n(wr->length, plen); + + if (s->msg_callback) + s->msg_callback(1, 0, SSL3_RT_HEADER, plen - 5, 5, s, + s->msg_callback_arg); + + /* + * 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 + */ + s->s3->wpend_tot = len; + s->s3->wpend_buf = buf; + s->s3->wpend_type = type; + s->s3->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 ((s->s3->wpend_tot > (int)len) + || ((s->s3->wpend_buf != buf) && + !(s->mode & SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER)) + || (s->s3->wpend_type != type)) { + SSLerr(SSL_F_SSL3_WRITE_PENDING, SSL_R_BAD_WRITE_RETRY); + return (-1); + } + + for (;;) { + clear_sys_error(); + if (s->wbio != NULL) { + s->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; + s->rwstate = SSL_NOTHING; + return (s->s3->wpend_ret); + } else if (i <= 0) { + if (SSL_IS_DTLS(s)) { + /* + * For DTLS, just drop it. That's kind of the whole point in + * using a datagram service + */ + 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) +{ + int al, i, j, ret; + unsigned int n; + SSL3_RECORD *rr; + void (*cb) (const SSL *ssl, int type2, int val) = NULL; + + if (s->s3->rbuf.buf == NULL) /* Not initialized yet */ + if (!ssl3_setup_read_buffer(s)) + 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) && (s->s3->handshake_fragment_len > 0)) + /* (partially) satisfy request from storage */ + { + unsigned char *src = s->s3->handshake_fragment; + unsigned char *dst = buf; + unsigned int k; + + /* peek == 0 */ + n = 0; + while ((len > 0) && (s->s3->handshake_fragment_len > 0)) { + *dst++ = *src++; + len--; + s->s3->handshake_fragment_len--; + n++; + } + /* move any remaining fragment bytes: */ + for (k = 0; k < s->s3->handshake_fragment_len; k++) + s->s3->handshake_fragment[k] = *src++; + return n; + } + + /* + * Now s->s3->handshake_fragment_len == 0 if type == SSL3_RT_HANDSHAKE. + */ + + if (!s->in_handshake && SSL_in_init(s)) { + /* type == SSL3_RT_APPLICATION_DATA */ + i = s->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: + s->rwstate = SSL_NOTHING; + + /*- + * s->s3->rrec.type - is the type of record + * s->s3->rrec.data, - data + * s->s3->rrec.off, - offset into 'data' for next read + * s->s3->rrec.length, - number of bytes. + */ + rr = &(s->s3->rrec); + + /* get new packet if necessary */ + if ((rr->length == 0) || (s->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 (s->s3->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->shutdown & SSL_RECEIVED_SHUTDOWN) { + rr->length = 0; + s->rwstate = SSL_NOTHING; + return (0); + } + + if (type == rr->type) { /* SSL3_RT_APPLICATION_DATA or + * SSL3_RT_HANDSHAKE */ + /* + * 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) { + rr->length -= n; + rr->off += n; + if (rr->length == 0) { + s->rstate = SSL_ST_READ_HEADER; + rr->off = 0; + if (s->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 s->s3->handshake_fragment; + dest = s->s3->handshake_fragment; + dest_len = &s->s3->handshake_fragment_len; + } else if (rr->type == SSL3_RT_ALERT) { + dest_maxlen = sizeof s->s3->alert_fragment; + dest = s->s3->alert_fragment; + dest_len = &s->s3->alert_fragment_len; + } +#ifndef OPENSSL_NO_HEARTBEATS + else if (rr->type == TLS1_RT_HEARTBEAT) { + tls1_process_heartbeat(s); + + /* Exit and notify application to read again */ + rr->length = 0; + s->rwstate = SSL_READING; + BIO_clear_retry_flags(SSL_get_rbio(s)); + BIO_set_retry_read(SSL_get_rbio(s)); + return (-1); + } +#endif + + if (dest_maxlen > 0) { + n = dest_maxlen - *dest_len; /* available space in 'dest' */ + 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 */ + } + } + + /*- + * s->s3->handshake_fragment_len == 4 iff rr->type == SSL3_RT_HANDSHAKE; + * s->s3->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) && + (s->s3->handshake_fragment_len >= 4) && + (s->s3->handshake_fragment[0] == SSL3_MT_HELLO_REQUEST) && + (s->session != NULL) && (s->session->cipher != NULL)) { + s->s3->handshake_fragment_len = 0; + + if ((s->s3->handshake_fragment[1] != 0) || + (s->s3->handshake_fragment[2] != 0) || + (s->s3->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->msg_callback) + s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, + s->s3->handshake_fragment, 4, s, + s->msg_callback_arg); + + if (SSL_is_init_finished(s) && + !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS) && + !s->s3->renegotiate) { + ssl3_renegotiate(s); + if (ssl3_renegotiate_check(s)) { + i = s->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->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->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) && + !s->s3->send_connection_binding && + (s->version > SSL3_VERSION) && + (s->s3->handshake_fragment_len >= 4) && + (s->s3->handshake_fragment[0] == SSL3_MT_CLIENT_HELLO) && + (s->session != NULL) && (s->session->cipher != NULL) && + !(s->ctx->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) { + /* + * s->s3->handshake_fragment_len = 0; + */ + rr->length = 0; + ssl3_send_alert(s, SSL3_AL_WARNING, SSL_AD_NO_RENEGOTIATION); + goto start; + } + if (s->s3->alert_fragment_len >= 2) { + int alert_level = s->s3->alert_fragment[0]; + int alert_descr = s->s3->alert_fragment[1]; + + s->s3->alert_fragment_len = 0; + + if (s->msg_callback) + s->msg_callback(0, s->version, SSL3_RT_ALERT, + s->s3->alert_fragment, 2, s, s->msg_callback_arg); + + if (s->info_callback != NULL) + cb = s->info_callback; + else if (s->ctx->info_callback != NULL) + cb = s->ctx->info_callback; + + if (cb != NULL) { + j = (alert_level << 8) | alert_descr; + cb(s, SSL_CB_READ_ALERT, j); + } + + if (alert_level == SSL3_AL_WARNING) { + s->s3->warn_alert = alert_descr; + if (alert_descr == SSL_AD_CLOSE_NOTIFY) { + s->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; + } +#ifdef SSL_AD_MISSING_SRP_USERNAME + else if (alert_descr == SSL_AD_MISSING_SRP_USERNAME) + return (0); +#endif + } else if (alert_level == SSL3_AL_FATAL) { + char tmp[16]; + + s->rwstate = SSL_NOTHING; + s->s3->fatal_alert = alert_descr; + SSLerr(SSL_F_SSL3_READ_BYTES, SSL_AD_REASON_OFFSET + alert_descr); + BIO_snprintf(tmp, sizeof tmp, "%d", alert_descr); + ERR_add_error_data(2, "SSL alert number ", tmp); + s->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->shutdown & SSL_SENT_SHUTDOWN) { /* but we have not received a + * shutdown */ + s->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 (s->s3->tmp.new_cipher == NULL) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_CCS_RECEIVED_EARLY); + goto f_err; + } + + 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->msg_callback) + s->msg_callback(0, s->version, SSL3_RT_CHANGE_CIPHER_SPEC, + rr->data, 1, s, s->msg_callback_arg); + + s->s3->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 ((s->s3->handshake_fragment_len >= 4) && !s->in_handshake) { + if (((s->state & SSL_ST_MASK) == SSL_ST_OK) && + !(s->s3->flags & SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS)) { +#if 0 /* worked only because C operator preferences + * are not as expected (and because this is + * not really needed for clients except for + * detecting protocol violations): */ + s->state = SSL_ST_BEFORE | (s->server) + ? SSL_ST_ACCEPT : SSL_ST_CONNECT; +#else + s->state = s->server ? SSL_ST_ACCEPT : SSL_ST_CONNECT; +#endif + s->renegotiate = 1; + s->new_session = 1; + } + i = s->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->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->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: +#ifndef OPENSSL_NO_TLS + /* + * 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; + } +#endif + 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->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 (s->s3->in_read_app_data && + (s->s3->total_renegotiations != 0) && + (((s->state & SSL_ST_CONNECT) && + (s->state >= SSL3_ST_CW_CLNT_HELLO_A) && + (s->state <= SSL3_ST_CR_SRVR_HELLO_A) + ) || ((s->state & SSL_ST_ACCEPT) && + (s->state <= SSL3_ST_SW_HELLO_REQ_A) && + (s->state >= SSL3_ST_SR_CLNT_HELLO_A) + ) + )) { + s->s3->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->state & SSL_ST_ACCEPT) + i = SSL3_CHANGE_CIPHER_SERVER_READ; + else + i = SSL3_CHANGE_CIPHER_CLIENT_READ; + + if (s->s3->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 = s->s3->tmp.new_cipher; + if (!s->method->ssl3_enc->setup_key_block(s)) + return (0); + } + + if (!s->method->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->state & SSL_ST_CONNECT) { + sender = s->method->ssl3_enc->server_finished_label; + slen = s->method->ssl3_enc->server_finished_label_len; + } else { + sender = s->method->ssl3_enc->client_finished_label; + slen = s->method->ssl3_enc->client_finished_label_len; + } + + i = s->method->ssl3_enc->final_finish_mac(s, + sender, slen, + s->s3->tmp.peer_finish_md); + if (i == 0) { + SSLerr(SSL_F_SSL3_DO_CHANGE_CIPHER_SPEC, ERR_R_INTERNAL_ERROR); + return 0; + } + s->s3->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->ssl3_enc->alert_value(desc); + if (s->version == SSL3_VERSION && desc == SSL_AD_PROTOCOL_VERSION) + desc = SSL_AD_HANDSHAKE_FAILURE; /* SSL 3.0 does not have + * protocol_version alerts */ + 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->msg_callback) + s->msg_callback(1, s->version, SSL3_RT_ALERT, s->s3->send_alert, + 2, s, s->msg_callback_arg); + + if (s->info_callback != NULL) + cb = s->info_callback; + else if (s->ctx->info_callback != NULL) + cb = s->ctx->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/thirdparty/openssl/ssl/s3_srvr.c b/thirdparty/openssl/ssl/s3_srvr.c new file mode 100644 index 0000000000..ab28702ee9 --- /dev/null +++ b/thirdparty/openssl/ssl/s3_srvr.c @@ -0,0 +1,3614 @@ +/* ssl/s3_srvr.c */ +/* 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. + */ + +#define REUSE_CIPHER_BUG +#define NETSCAPE_HANG_BUG + +#include <stdio.h> +#include "ssl_locl.h" +#include "kssl_lcl.h" +#include "../crypto/constant_time_locl.h" +#include <openssl/buffer.h> +#include <openssl/rand.h> +#include <openssl/objects.h> +#include <openssl/evp.h> +#include <openssl/hmac.h> +#include <openssl/x509.h> +#ifndef OPENSSL_NO_DH +# include <openssl/dh.h> +#endif +#include <openssl/bn.h> +#ifndef OPENSSL_NO_KRB5 +# include <openssl/krb5_asn.h> +#endif +#include <openssl/md5.h> + +#ifndef OPENSSL_NO_SSL3_METHOD +static const SSL_METHOD *ssl3_get_server_method(int ver); + +static const SSL_METHOD *ssl3_get_server_method(int ver) +{ + if (ver == SSL3_VERSION) + return (SSLv3_server_method()); + else + return (NULL); +} + +IMPLEMENT_ssl3_meth_func(SSLv3_server_method, + ssl3_accept, + ssl_undefined_function, ssl3_get_server_method) +#endif +#ifndef OPENSSL_NO_SRP +static int ssl_check_srp_ext_ClientHello(SSL *s, int *al) +{ + int ret = SSL_ERROR_NONE; + + *al = SSL_AD_UNRECOGNIZED_NAME; + + if ((s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP) && + (s->srp_ctx.TLS_ext_srp_username_callback != NULL)) { + if (s->srp_ctx.login == NULL) { + /* + * RFC 5054 says SHOULD reject, we do so if There is no srp + * login name + */ + ret = SSL3_AL_FATAL; + *al = SSL_AD_UNKNOWN_PSK_IDENTITY; + } else { + ret = SSL_srp_server_param_with_username(s, al); + } + } + return ret; +} +#endif + +int ssl3_accept(SSL *s) +{ + BUF_MEM *buf; + unsigned long alg_k, Time = (unsigned long)time(NULL); + void (*cb) (const SSL *ssl, int type, int val) = NULL; + int ret = -1; + int new_state, state, skip = 0; + + RAND_add(&Time, sizeof(Time), 0); + ERR_clear_error(); + clear_sys_error(); + + if (s->info_callback != NULL) + cb = s->info_callback; + else if (s->ctx->info_callback != NULL) + cb = s->ctx->info_callback; + + /* init things to blank */ + s->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); + return (-1); + } +#ifndef OPENSSL_NO_HEARTBEATS + /* + * If we're awaiting a HeartbeatResponse, pretend we already got and + * don't await it anymore, because Heartbeats don't make sense during + * handshakes anyway. + */ + if (s->tlsext_hb_pending) { + s->tlsext_hb_pending = 0; + s->tlsext_hb_seq++; + } +#endif + + for (;;) { + state = s->state; + + switch (s->state) { + case SSL_ST_RENEGOTIATE: + s->renegotiate = 1; + /* s->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); + s->state = SSL_ST_ERR; + return -1; + } + s->type = SSL_ST_ACCEPT; + + if (s->init_buf == NULL) { + if ((buf = BUF_MEM_new()) == NULL) { + ret = -1; + s->state = SSL_ST_ERR; + goto end; + } + if (!BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) { + BUF_MEM_free(buf); + ret = -1; + s->state = SSL_ST_ERR; + goto end; + } + s->init_buf = buf; + } + + if (!ssl3_setup_buffers(s)) { + ret = -1; + s->state = SSL_ST_ERR; + goto end; + } + + s->init_num = 0; + s->s3->flags &= ~TLS1_FLAGS_SKIP_CERT_VERIFY; + s->s3->flags &= ~SSL3_FLAGS_CCS_OK; + /* + * Should have been reset by ssl3_get_finished, too. + */ + s->s3->change_cipher_spec = 0; + + if (s->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; + s->state = SSL_ST_ERR; + goto end; + } + + ssl3_init_finished_mac(s); + s->state = SSL3_ST_SR_CLNT_HELLO_A; + s->ctx->stats.sess_accept++; + } else if (!s->s3->send_connection_binding && + !(s->options & + SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) { + /* + * 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; + s->state = SSL_ST_ERR; + goto end; + } else { + /* + * s->state == SSL_ST_RENEGOTIATE, we will just send a + * HelloRequest + */ + s->ctx->stats.sess_accept_renegotiate++; + s->state = SSL3_ST_SW_HELLO_REQ_A; + } + break; + + case SSL3_ST_SW_HELLO_REQ_A: + case SSL3_ST_SW_HELLO_REQ_B: + + s->shutdown = 0; + ret = ssl3_send_hello_request(s); + if (ret <= 0) + goto end; + s->s3->tmp.next_state = SSL3_ST_SW_HELLO_REQ_C; + s->state = SSL3_ST_SW_FLUSH; + s->init_num = 0; + + ssl3_init_finished_mac(s); + break; + + case SSL3_ST_SW_HELLO_REQ_C: + s->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->shutdown = 0; + ret = ssl3_get_client_hello(s); + if (ret <= 0) + goto end; +#ifndef OPENSSL_NO_SRP + s->state = SSL3_ST_SR_CLNT_HELLO_D; + case SSL3_ST_SR_CLNT_HELLO_D: + { + int al; + if ((ret = ssl_check_srp_ext_ClientHello(s, &al)) < 0) { + /* + * callback indicates firther work to be done + */ + s->rwstate = SSL_X509_LOOKUP; + goto end; + } + if (ret != SSL_ERROR_NONE) { + ssl3_send_alert(s, SSL3_AL_FATAL, al); + /* + * This is not really an error but the only means to for + * a client to detect whether srp is supported. + */ + if (al != TLS1_AD_UNKNOWN_PSK_IDENTITY) + SSLerr(SSL_F_SSL3_ACCEPT, SSL_R_CLIENTHELLO_TLSEXT); + ret = -1; + s->state = SSL_ST_ERR; + goto end; + } + } +#endif + + s->renegotiate = 2; + s->state = SSL3_ST_SW_SRVR_HELLO_A; + s->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; +#ifndef OPENSSL_NO_TLSEXT + if (s->hit) { + if (s->tlsext_ticket_expected) + s->state = SSL3_ST_SW_SESSION_TICKET_A; + else + s->state = SSL3_ST_SW_CHANGE_A; + } +#else + if (s->hit) + s->state = SSL3_ST_SW_CHANGE_A; +#endif + else + s->state = SSL3_ST_SW_CERT_A; + s->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, */ + /* normal PSK or KRB5 or SRP */ + if (! + (s->s3->tmp. + new_cipher->algorithm_auth & (SSL_aNULL | SSL_aKRB5 | + SSL_aSRP)) +&& !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) { + ret = ssl3_send_server_certificate(s); + if (ret <= 0) + goto end; +#ifndef OPENSSL_NO_TLSEXT + if (s->tlsext_status_expected) + s->state = SSL3_ST_SW_CERT_STATUS_A; + else + s->state = SSL3_ST_SW_KEY_EXCH_A; + } else { + skip = 1; + s->state = SSL3_ST_SW_KEY_EXCH_A; + } +#else + } else + skip = 1; + + s->state = SSL3_ST_SW_KEY_EXCH_A; +#endif + s->init_num = 0; + break; + + case SSL3_ST_SW_KEY_EXCH_A: + case SSL3_ST_SW_KEY_EXCH_B: + alg_k = s->s3->tmp.new_cipher->algorithm_mkey; + + /* + * clear this, it may get reset by + * send_server_key_exchange + */ + s->s3->tmp.use_rsa_tmp = 0; + + /* + * only send if a DH key exchange, fortezza or RSA but we have a + * sign only certificate PSK: may send PSK identity hints For + * ECC ciphersuites, we send a serverKeyExchange message only if + * the cipher suite is either ECDH-anon or ECDHE. In other cases, + * the server certificate contains the server's public key for + * key exchange. + */ + if (0 + /* + * PSK: send ServerKeyExchange if PSK identity hint if + * provided + */ +#ifndef OPENSSL_NO_PSK + || ((alg_k & SSL_kPSK) && s->ctx->psk_identity_hint) +#endif +#ifndef OPENSSL_NO_SRP + /* SRP: send ServerKeyExchange */ + || (alg_k & SSL_kSRP) +#endif + || (alg_k & SSL_kEDH) + || (alg_k & SSL_kEECDH) + || ((alg_k & SSL_kRSA) + && (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL + || (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) + && EVP_PKEY_size(s->cert->pkeys + [SSL_PKEY_RSA_ENC].privatekey) * + 8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher) + ) + ) + ) + ) { + ret = ssl3_send_server_key_exchange(s); + if (ret <= 0) + goto end; + } else + skip = 1; + + s->state = SSL3_ST_SW_CERT_REQ_A; + s->init_num = 0; + break; + + case SSL3_ST_SW_CERT_REQ_A: + case SSL3_ST_SW_CERT_REQ_B: + if ( /* don't request cert unless asked for it: */ + !(s->verify_mode & SSL_VERIFY_PEER) || + /* + * if SSL_VERIFY_CLIENT_ONCE is set, don't request cert + * during re-negotiation: + */ + ((s->session->peer != NULL) && + (s->verify_mode & SSL_VERIFY_CLIENT_ONCE)) || + /* + * never request cert in anonymous ciphersuites (see + * section "Certificate request" in SSL 3 drafts and in + * RFC 2246): + */ + ((s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) && + /* + * ... except when the application insists on + * verification (against the specs, but s3_clnt.c accepts + * this for SSL 3) + */ + !(s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) || + /* + * never request cert in Kerberos ciphersuites + */ + (s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5) || + /* don't request certificate for SRP auth */ + (s->s3->tmp.new_cipher->algorithm_auth & SSL_aSRP) + /* + * With normal PSK Certificates and Certificate Requests + * are omitted + */ + || (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) { + /* no cert request */ + skip = 1; + s->s3->tmp.cert_request = 0; + s->state = SSL3_ST_SW_SRVR_DONE_A; + if (s->s3->handshake_buffer) { + if (!ssl3_digest_cached_records(s)) { + s->state = SSL_ST_ERR; + return -1; + } + } + } else { + s->s3->tmp.cert_request = 1; + ret = ssl3_send_certificate_request(s); + if (ret <= 0) + goto end; +#ifndef NETSCAPE_HANG_BUG + s->state = SSL3_ST_SW_SRVR_DONE_A; +#else + s->state = SSL3_ST_SW_FLUSH; + s->s3->tmp.next_state = SSL3_ST_SR_CERT_A; +#endif + s->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; + s->s3->tmp.next_state = SSL3_ST_SR_CERT_A; + s->state = SSL3_ST_SW_FLUSH; + s->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->rwstate = SSL_WRITING; + if (BIO_flush(s->wbio) <= 0) { + ret = -1; + goto end; + } + s->rwstate = SSL_NOTHING; + + s->state = s->s3->tmp.next_state; + break; + + case SSL3_ST_SR_CERT_A: + case SSL3_ST_SR_CERT_B: + if (s->s3->tmp.cert_request) { + ret = ssl3_get_client_certificate(s); + if (ret <= 0) + goto end; + } + s->init_num = 0; + s->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; + 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 defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG) + s->state = SSL3_ST_SR_FINISHED_A; +#else + if (s->s3->next_proto_neg_seen) + s->state = SSL3_ST_SR_NEXT_PROTO_A; + else + s->state = SSL3_ST_SR_FINISHED_A; +#endif + s->init_num = 0; + } else if (SSL_USE_SIGALGS(s)) { + s->state = SSL3_ST_SR_CERT_VRFY_A; + s->init_num = 0; + if (!s->session->peer) + break; + /* + * For sigalgs freeze the handshake buffer at this point and + * digest cached records. + */ + if (!s->s3->handshake_buffer) { + SSLerr(SSL_F_SSL3_ACCEPT, ERR_R_INTERNAL_ERROR); + s->state = SSL_ST_ERR; + return -1; + } + s->s3->flags |= TLS1_FLAGS_KEEP_HANDSHAKE; + if (!ssl3_digest_cached_records(s)) { + s->state = SSL_ST_ERR; + return -1; + } + } else { + int offset = 0; + int dgst_num; + + s->state = SSL3_ST_SR_CERT_VRFY_A; + s->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 (s->s3->handshake_buffer) { + if (!ssl3_digest_cached_records(s)) { + s->state = SSL_ST_ERR; + return -1; + } + } + for (dgst_num = 0; dgst_num < SSL_MAX_DIGEST; dgst_num++) + if (s->s3->handshake_dgst[dgst_num]) { + int dgst_size; + + s->method->ssl3_enc->cert_verify_mac(s, + EVP_MD_CTX_type + (s-> + s3->handshake_dgst + [dgst_num]), + &(s->s3-> + tmp.cert_verify_md + [offset])); + dgst_size = + EVP_MD_CTX_size(s->s3->handshake_dgst[dgst_num]); + if (dgst_size < 0) { + s->state = SSL_ST_ERR; + ret = -1; + goto end; + } + offset += dgst_size; + } + } + break; + + case SSL3_ST_SR_CERT_VRFY_A: + case SSL3_ST_SR_CERT_VRFY_B: + ret = ssl3_get_cert_verify(s); + if (ret <= 0) + goto end; + +#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG) + s->state = SSL3_ST_SR_FINISHED_A; +#else + if (s->s3->next_proto_neg_seen) + s->state = SSL3_ST_SR_NEXT_PROTO_A; + else + s->state = SSL3_ST_SR_FINISHED_A; +#endif + s->init_num = 0; + break; + +#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) + case SSL3_ST_SR_NEXT_PROTO_A: + case SSL3_ST_SR_NEXT_PROTO_B: + /* + * Enable CCS for NPN. Receiving a CCS clears the flag, so make + * sure not to re-enable it to ban duplicates. This *should* be the + * first time we have received one - but we check anyway to be + * cautious. + * s->s3->change_cipher_spec is set when a CCS is + * processed in s3_pkt.c, and remains set until + * the client's Finished message is read. + */ + if (!s->s3->change_cipher_spec) + s->s3->flags |= SSL3_FLAGS_CCS_OK; + + ret = ssl3_get_next_proto(s); + if (ret <= 0) + goto end; + s->init_num = 0; + s->state = SSL3_ST_SR_FINISHED_A; + break; +#endif + + case SSL3_ST_SR_FINISHED_A: + case SSL3_ST_SR_FINISHED_B: + /* + * Enable CCS for handshakes without NPN. In NPN the CCS flag has + * already been set. Receiving a CCS clears the flag, so make + * sure not to re-enable it to ban duplicates. + * s->s3->change_cipher_spec is set when a CCS is + * processed in s3_pkt.c, and remains set until + * the client's Finished message is read. + */ + if (!s->s3->change_cipher_spec) + 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->hit) + s->state = SSL_ST_OK; +#ifndef OPENSSL_NO_TLSEXT + else if (s->tlsext_ticket_expected) + s->state = SSL3_ST_SW_SESSION_TICKET_A; +#endif + else + s->state = SSL3_ST_SW_CHANGE_A; + s->init_num = 0; + break; + +#ifndef OPENSSL_NO_TLSEXT + 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->state = SSL3_ST_SW_CHANGE_A; + s->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->state = SSL3_ST_SW_KEY_EXCH_A; + s->init_num = 0; + break; + +#endif + + case SSL3_ST_SW_CHANGE_A: + case SSL3_ST_SW_CHANGE_B: + + s->session->cipher = s->s3->tmp.new_cipher; + if (!s->method->ssl3_enc->setup_key_block(s)) { + ret = -1; + s->state = SSL_ST_ERR; + 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->state = SSL3_ST_SW_FINISHED_A; + s->init_num = 0; + + if (!s->method->ssl3_enc->change_cipher_state(s, + SSL3_CHANGE_CIPHER_SERVER_WRITE)) + { + ret = -1; + s->state = SSL_ST_ERR; + 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-> + ssl3_enc->server_finished_label, + s->method-> + ssl3_enc->server_finished_label_len); + if (ret <= 0) + goto end; + s->state = SSL3_ST_SW_FLUSH; + if (s->hit) { +#if defined(OPENSSL_NO_TLSEXT) || defined(OPENSSL_NO_NEXTPROTONEG) + s->s3->tmp.next_state = SSL3_ST_SR_FINISHED_A; +#else + if (s->s3->next_proto_neg_seen) { + s->s3->tmp.next_state = SSL3_ST_SR_NEXT_PROTO_A; + } else + s->s3->tmp.next_state = SSL3_ST_SR_FINISHED_A; +#endif + } else + s->s3->tmp.next_state = SSL_ST_OK; + s->init_num = 0; + break; + + case SSL_ST_OK: + /* clean a few things up */ + ssl3_cleanup_key_block(s); + + BUF_MEM_free(s->init_buf); + s->init_buf = NULL; + + /* remove buffering on output */ + ssl_free_wbio_buffer(s); + + s->init_num = 0; + + if (s->renegotiate == 2) { /* skipped if we just sent a + * HelloRequest */ + s->renegotiate = 0; + s->new_session = 0; + + ssl_update_cache(s, SSL_SESS_CACHE_SERVER); + + s->ctx->stats.sess_accept_good++; + /* s->server=1; */ + s->handshake_func = ssl3_accept; + + if (cb != NULL) + cb(s, SSL_CB_HANDSHAKE_DONE, 1); + } + + ret = 1; + goto end; + /* break; */ + + case SSL_ST_ERR: + default: + SSLerr(SSL_F_SSL3_ACCEPT, SSL_R_UNKNOWN_STATE); + ret = -1; + goto end; + /* break; */ + } + + if (!s->s3->tmp.reuse_message && !skip) { + if (s->debug) { + if ((ret = BIO_flush(s->wbio)) <= 0) + goto end; + } + + if ((cb != NULL) && (s->state != state)) { + new_state = s->state; + s->state = state; + cb(s, SSL_CB_ACCEPT_LOOP, 1); + s->state = new_state; + } + } + skip = 0; + } + end: + /* BIO_flush(s->wbio); */ + + s->in_handshake--; + if (cb != NULL) + cb(s, SSL_CB_ACCEPT_EXIT, ret); + return (ret); +} + +int ssl3_send_hello_request(SSL *s) +{ + + if (s->state == SSL3_ST_SW_HELLO_REQ_A) { + ssl_set_handshake_header(s, SSL3_MT_HELLO_REQUEST, 0); + s->state = SSL3_ST_SW_HELLO_REQ_B; + } + + /* SSL3_ST_SW_HELLO_REQ_B */ + return ssl_do_write(s); +} + +int ssl3_get_client_hello(SSL *s) +{ + int i, j, ok, al = SSL_AD_INTERNAL_ERROR, ret = -1, cookie_valid = 0; + unsigned int cookie_len; + long n; + unsigned long id; + unsigned char *p, *d; + SSL_CIPHER *c; +#ifndef OPENSSL_NO_COMP + unsigned char *q; + SSL_COMP *comp = NULL; +#endif + STACK_OF(SSL_CIPHER) *ciphers = NULL; + + if (s->state == SSL3_ST_SR_CLNT_HELLO_C && !s->first_packet) + goto retry_cert; + + /* + * 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->state == SSL3_ST_SR_CLNT_HELLO_A) { + s->state = SSL3_ST_SR_CLNT_HELLO_B; + } + s->first_packet = 1; + n = s->method->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->first_packet = 0; + d = p = (unsigned char *)s->init_msg; + + /* + * 2 bytes for client version, SSL3_RANDOM_SIZE bytes for random, 1 byte + * for session id length + */ + if (n < 2 + SSL3_RANDOM_SIZE + 1) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_TOO_SHORT); + goto f_err; + } + + /* + * 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_IS_DTLS(s) ? (s->client_version > s->version && + s->method->version != DTLS_ANY_VERSION) + : (s->client_version < s->version)) { + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_WRONG_VERSION_NUMBER); + if ((s->client_version >> 8) == SSL3_VERSION_MAJOR && + !s->enc_write_ctx && !s->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; + } + + /* + * If we require cookies 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; + + session_length = *(p + SSL3_RANDOM_SIZE); + + if (p + SSL3_RANDOM_SIZE + session_length + 1 >= d + n) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_TOO_SHORT); + goto f_err; + } + cookie_length = *(p + SSL3_RANDOM_SIZE + session_length + 1); + + if (cookie_length == 0) + return 1; + } + + /* 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 + j > d + n) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_TOO_SHORT); + goto f_err; + } + + if ((j < 0) || (j > SSL_MAX_SSL_SESSION_ID_LENGTH)) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH); + goto f_err; + } + + s->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->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->new_session + && (s->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); + /* + * Only resume if the session's version matches the negotiated + * version. + * RFC 5246 does not provide much useful advice on resumption + * with a different protocol version. It doesn't forbid it but + * the sanity of such behaviour would be questionable. + * In practice, clients do not accept a version mismatch and + * will abort the handshake with an error. + */ + if (i == 1 && s->version == s->session->ssl_version) { /* previous + * session */ + s->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 + 1 > d + n) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_TOO_SHORT); + goto f_err; + } + cookie_len = *(p++); + + if (p + cookie_len > d + n) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_TOO_SHORT); + goto f_err; + } + + /* + * 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(s->d1->rcvd_cookie)) { + /* too much data */ + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_COOKIE_MISMATCH); + goto f_err; + } + + /* verify the cookie if appropriate option is set. */ + if ((SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) && cookie_len > 0) { + memcpy(s->d1->rcvd_cookie, p, cookie_len); + + if (s->ctx->app_verify_cookie_cb != NULL) { + if (s->ctx->app_verify_cookie_cb(s, s->d1->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 */ + } + /* default verification */ + else if (memcmp(s->d1->rcvd_cookie, s->d1->cookie, + s->d1->cookie_len) != 0) { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_COOKIE_MISMATCH); + goto f_err; + } + cookie_valid = 1; + } + + p += cookie_len; + if (s->method->version == DTLS_ANY_VERSION) { + /* Select version to use */ + if (s->client_version <= DTLS1_2_VERSION && + !(s->options & SSL_OP_NO_DTLSv1_2)) { + s->version = DTLS1_2_VERSION; + s->method = DTLSv1_2_server_method(); + } else if (tls1_suiteb(s)) { + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, + SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE); + s->version = s->client_version; + al = SSL_AD_PROTOCOL_VERSION; + goto f_err; + } else if (s->client_version <= DTLS1_VERSION && + !(s->options & SSL_OP_NO_DTLSv1)) { + s->version = DTLS1_VERSION; + s->method = DTLSv1_server_method(); + } else { + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, + SSL_R_WRONG_VERSION_NUMBER); + s->version = s->client_version; + al = SSL_AD_PROTOCOL_VERSION; + goto f_err; + } + s->session->ssl_version = s->version; + } + } + + if (p + 2 > d + n) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_TOO_SHORT); + goto f_err; + } + n2s(p, i); + + if (i == 0) { + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_NO_CIPHERS_SPECIFIED); + goto f_err; + } + + /* i bytes of cipher data + 1 byte for compression length later */ + if ((p + i + 1) > (d + n)) { + /* not enough data */ + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH); + goto f_err; + } + if (ssl_bytes_to_cipher_list(s, p, i, &(ciphers)) == NULL) { + goto err; + } + p += i; + + /* If it is a hit, check that the cipher is in the list */ + if (s->hit) { + j = 0; + id = s->session->cipher->id; + +#ifdef CIPHER_DEBUG + fprintf(stderr, "client sent %d ciphers\n", + sk_SSL_CIPHER_num(ciphers)); +#endif + for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) { + c = sk_SSL_CIPHER_value(ciphers, i); +#ifdef CIPHER_DEBUG + fprintf(stderr, "client [%2d of %2d]:%s\n", + i, sk_SSL_CIPHER_num(ciphers), SSL_CIPHER_get_name(c)); +#endif + if (c->id == id) { + j = 1; + break; + } + } + /* + * Disabled because it can be used in a ciphersuite downgrade attack: + * CVE-2010-4180. + */ +#if 0 + if (j == 0 && (s->options & SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG) + && (sk_SSL_CIPHER_num(ciphers) == 1)) { + /* + * Special case as client bug workaround: the previously used + * cipher may not be in the current list, the client instead + * might be trying to continue using a cipher that before wasn't + * chosen due to server preferences. We'll have to reject the + * connection if the cipher is not enabled, though. + */ + c = sk_SSL_CIPHER_value(ciphers, 0); + if (sk_SSL_CIPHER_find(SSL_get_ciphers(s), c) >= 0) { + s->session->cipher = c; + j = 1; + } + } +#endif + 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 */ + i = *(p++); + if ((p + i) > (d + n)) { + /* not enough data */ + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH); + goto f_err; + } +#ifndef OPENSSL_NO_COMP + q = p; +#endif + 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; + } +#ifndef OPENSSL_NO_TLSEXT + /* TLS extensions */ + if (s->version >= SSL3_VERSION) { + if (!ssl_parse_clienthello_tlsext(s, &p, d + n)) { + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_PARSE_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. + */ + { + unsigned char *pos; + pos = s->s3->server_random; + if (ssl_fill_hello_random(s, 1, pos, SSL3_RANDOM_SIZE) <= 0) { + goto f_err; + } + } + + if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb) { + SSL_CIPHER *pref_cipher = NULL; + + s->session->master_key_length = sizeof(s->session->master_key); + if (s->tls_session_secret_cb(s, s->session->master_key, + &s->session->master_key_length, ciphers, + &pref_cipher, + s->tls_session_secret_cb_arg)) { + s->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; + + if (s->cipher_list) + sk_SSL_CIPHER_free(s->cipher_list); + + if (s->cipher_list_by_id) + sk_SSL_CIPHER_free(s->cipher_list_by_id); + + s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers); + s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers); + } + } +#endif + + /* + * Worst case, we will use the NULL compression, but if we have other + * options, we will now look for them. We have i-1 compression + * algorithms from the client, starting at q. + */ + s->s3->tmp.new_compression = NULL; +#ifndef OPENSSL_NO_COMP + /* This only happens if we have a cache hit */ + if (s->session->compress_meth != 0) { + int m, comp_id = s->session->compress_meth; + /* Perform sanity checks on resumed compression algorithm */ + /* Can't disable compression */ + if (s->options & SSL_OP_NO_COMPRESSION) { + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, + SSL_R_INCONSISTENT_COMPRESSION); + goto f_err; + } + /* Look for resumed compression method */ + for (m = 0; m < sk_SSL_COMP_num(s->ctx->comp_methods); m++) { + comp = sk_SSL_COMP_value(s->ctx->comp_methods, m); + if (comp_id == comp->id) { + s->s3->tmp.new_compression = comp; + break; + } + } + if (s->s3->tmp.new_compression == NULL) { + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, + SSL_R_INVALID_COMPRESSION_ALGORITHM); + goto f_err; + } + /* Look for resumed method in compression list */ + for (m = 0; m < i; m++) { + if (q[m] == comp_id) + break; + } + if (m >= i) { + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, + SSL_R_REQUIRED_COMPRESSSION_ALGORITHM_MISSING); + goto f_err; + } + } else if (s->hit) + comp = NULL; + else if (!(s->options & SSL_OP_NO_COMPRESSION) && s->ctx->comp_methods) { + /* See if we have a match */ + int m, nn, o, v, done = 0; + + nn = sk_SSL_COMP_num(s->ctx->comp_methods); + for (m = 0; m < nn; m++) { + comp = sk_SSL_COMP_value(s->ctx->comp_methods, m); + v = comp->id; + for (o = 0; o < i; o++) { + if (v == q[o]) { + done = 1; + break; + } + } + if (done) + break; + } + if (done) + s->s3->tmp.new_compression = comp; + else + comp = NULL; + } +#else + /* + * If compression is disabled we'd better not try to resume a session + * using compression. + */ + if (s->session->compress_meth != 0) { + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_INCONSISTENT_COMPRESSION); + goto f_err; + } +#endif + + /* + * Given s->session->ciphers and SSL_get_ciphers, we must pick a cipher + */ + + if (!s->hit) { +#ifdef OPENSSL_NO_COMP + s->session->compress_meth = 0; +#else + s->session->compress_meth = (comp == NULL) ? 0 : comp->id; +#endif + if (s->session->ciphers != NULL) + sk_SSL_CIPHER_free(s->session->ciphers); + s->session->ciphers = ciphers; + if (ciphers == NULL) { + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); + goto f_err; + } + ciphers = NULL; + if (!tls1_set_server_sigalgs(s)) { + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT); + goto err; + } + /* Let cert callback update server certificates if required */ + retry_cert: + if (s->cert->cert_cb) { + int rv = s->cert->cert_cb(s, s->cert->cert_cb_arg); + if (rv == 0) { + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_CERT_CB_ERROR); + goto f_err; + } + if (rv < 0) { + s->rwstate = SSL_X509_LOOKUP; + return -1; + } + s->rwstate = SSL_NOTHING; + } + 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; + } + s->s3->tmp.new_cipher = c; + } else { + /* Session-id reuse */ +#ifdef REUSE_CIPHER_BUG + STACK_OF(SSL_CIPHER) *sk; + SSL_CIPHER *nc = NULL; + SSL_CIPHER *ec = NULL; + + if (s->options & SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG) { + sk = s->session->ciphers; + for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) { + c = sk_SSL_CIPHER_value(sk, i); + if (c->algorithm_enc & SSL_eNULL) + nc = c; + if (SSL_C_IS_EXPORT(c)) + ec = c; + } + if (nc != NULL) + s->s3->tmp.new_cipher = nc; + else if (ec != NULL) + s->s3->tmp.new_cipher = ec; + else + s->s3->tmp.new_cipher = s->session->cipher; + } else +#endif + s->s3->tmp.new_cipher = s->session->cipher; + } + + if (!SSL_USE_SIGALGS(s) || !(s->verify_mode & SSL_VERIFY_PEER)) { + if (!ssl3_digest_cached_records(s)) + 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->hit - session reuse flag + * s->tmp.new_cipher - the new cipher to use. + */ + + /* Handles TLS extensions that we couldn't check earlier */ + if (s->version >= SSL3_VERSION) { + if (ssl_check_clienthello_tlsext_late(s) <= 0) { + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT); + goto err; + } + } + + ret = cookie_valid ? 2 : 1; + if (0) { + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + err: + s->state = SSL_ST_ERR; + } + + if (ciphers != NULL) + sk_SSL_CIPHER_free(ciphers); + return ret; +} + +int ssl3_send_server_hello(SSL *s) +{ + unsigned char *buf; + unsigned char *p, *d; + int i, sl; + int al = 0; + unsigned long l; + + if (s->state == SSL3_ST_SW_SRVR_HELLO_A) { + buf = (unsigned char *)s->init_buf->data; +#ifdef OPENSSL_NO_TLSEXT + p = s->s3->server_random; + if (ssl_fill_hello_random(s, 1, p, SSL3_RANDOM_SIZE) <= 0) { + s->state = SSL_ST_ERR; + return -1; + } +#endif + /* Do the message type and length last */ + d = p = ssl_handshake_start(s); + + *(p++) = s->version >> 8; + *(p++) = s->version & 0xff; + + /* Random stuff */ + memcpy(p, s->s3->server_random, SSL3_RANDOM_SIZE); + p += SSL3_RANDOM_SIZE; + + /*- + * 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->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->session_cache_mode & SSL_SESS_CACHE_SERVER) + && !s->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); + s->state = SSL_ST_ERR; + return -1; + } + *(p++) = sl; + memcpy(p, s->session->session_id, sl); + p += sl; + + /* put the cipher */ + i = ssl3_put_cipher_by_char(s->s3->tmp.new_cipher, p); + p += i; + + /* put the compression method */ +#ifdef OPENSSL_NO_COMP + *(p++) = 0; +#else + if (s->s3->tmp.new_compression == NULL) + *(p++) = 0; + else + *(p++) = s->s3->tmp.new_compression->id; +#endif +#ifndef OPENSSL_NO_TLSEXT + if (ssl_prepare_serverhello_tlsext(s) <= 0) { + SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO, SSL_R_SERVERHELLO_TLSEXT); + s->state = SSL_ST_ERR; + return -1; + } + if ((p = + ssl_add_serverhello_tlsext(s, p, buf + SSL3_RT_MAX_PLAIN_LENGTH, + &al)) == NULL) { + ssl3_send_alert(s, SSL3_AL_FATAL, al); + SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO, ERR_R_INTERNAL_ERROR); + s->state = SSL_ST_ERR; + return -1; + } +#endif + /* do the header */ + l = (p - d); + ssl_set_handshake_header(s, SSL3_MT_SERVER_HELLO, l); + s->state = SSL3_ST_SW_SRVR_HELLO_B; + } + + /* SSL3_ST_SW_SRVR_HELLO_B */ + return ssl_do_write(s); +} + +int ssl3_send_server_done(SSL *s) +{ + + if (s->state == SSL3_ST_SW_SRVR_DONE_A) { + ssl_set_handshake_header(s, SSL3_MT_SERVER_DONE, 0); + s->state = SSL3_ST_SW_SRVR_DONE_B; + } + + /* SSL3_ST_SW_SRVR_DONE_B */ + return ssl_do_write(s); +} + +int ssl3_send_server_key_exchange(SSL *s) +{ +#ifndef OPENSSL_NO_RSA + unsigned char *q; + int j, num; + RSA *rsa; + unsigned char md_buf[MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH]; + unsigned int u; +#endif +#ifndef OPENSSL_NO_DH + DH *dh = NULL, *dhp; +#endif +#ifndef OPENSSL_NO_ECDH + EC_KEY *ecdh = NULL, *ecdhp; + unsigned char *encodedPoint = NULL; + int encodedlen = 0; + int curve_id = 0; + BN_CTX *bn_ctx = NULL; +#endif + EVP_PKEY *pkey; + const EVP_MD *md = NULL; + unsigned char *p, *d; + int al, i; + unsigned long type; + int n; + CERT *cert; + BIGNUM *r[4]; + int nr[4], kn; + BUF_MEM *buf; + EVP_MD_CTX md_ctx; + + EVP_MD_CTX_init(&md_ctx); + if (s->state == SSL3_ST_SW_KEY_EXCH_A) { + type = s->s3->tmp.new_cipher->algorithm_mkey; + cert = s->cert; + + buf = s->init_buf; + + r[0] = r[1] = r[2] = r[3] = NULL; + n = 0; +#ifndef OPENSSL_NO_RSA + if (type & SSL_kRSA) { + rsa = cert->rsa_tmp; + if ((rsa == NULL) && (s->cert->rsa_tmp_cb != NULL)) { + rsa = s->cert->rsa_tmp_cb(s, + SSL_C_IS_EXPORT(s->s3-> + tmp.new_cipher), + SSL_C_EXPORT_PKEYLENGTH(s->s3-> + tmp.new_cipher)); + if (rsa == NULL) { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, + SSL_R_ERROR_GENERATING_TMP_RSA_KEY); + goto f_err; + } + RSA_up_ref(rsa); + cert->rsa_tmp = rsa; + } + if (rsa == NULL) { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, + SSL_R_MISSING_TMP_RSA_KEY); + goto f_err; + } + r[0] = rsa->n; + r[1] = rsa->e; + s->s3->tmp.use_rsa_tmp = 1; + } else +#endif +#ifndef OPENSSL_NO_DH + if (type & SSL_kEDH) { + dhp = cert->dh_tmp; + if ((dhp == NULL) && (s->cert->dh_tmp_cb != NULL)) + dhp = s->cert->dh_tmp_cb(s, + SSL_C_IS_EXPORT(s->s3-> + tmp.new_cipher), + SSL_C_EXPORT_PKEYLENGTH(s->s3-> + 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 (s->s3->tmp.dh != NULL) { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + if ((dh = DHparams_dup(dhp)) == NULL) { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_DH_LIB); + goto err; + } + + s->s3->tmp.dh = dh; + if (!DH_generate_key(dh)) { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_DH_LIB); + goto err; + } + r[0] = dh->p; + r[1] = dh->g; + r[2] = dh->pub_key; + } else +#endif +#ifndef OPENSSL_NO_ECDH + if (type & SSL_kEECDH) { + const EC_GROUP *group; + + ecdhp = cert->ecdh_tmp; + if (s->cert->ecdh_tmp_auto) { + /* Get NID of appropriate shared curve */ + int nid = tls1_shared_curve(s, -2); + if (nid != NID_undef) + ecdhp = EC_KEY_new_by_curve_name(nid); + } else if ((ecdhp == NULL) && s->cert->ecdh_tmp_cb) { + ecdhp = s->cert->ecdh_tmp_cb(s, + SSL_C_IS_EXPORT(s->s3-> + tmp.new_cipher), + SSL_C_EXPORT_PKEYLENGTH(s-> + s3->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 (s->s3->tmp.ecdh != NULL) { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + /* Duplicate the ECDH structure. */ + if (ecdhp == NULL) { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_ECDH_LIB); + goto err; + } + if (s->cert->ecdh_tmp_auto) + ecdh = ecdhp; + else if ((ecdh = EC_KEY_dup(ecdhp)) == NULL) { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_R_ECDH_LIB); + goto err; + } + + s->s3->tmp.ecdh = ecdh; + if ((EC_KEY_get0_public_key(ecdh) == NULL) || + (EC_KEY_get0_private_key(ecdh) == NULL) || + (s->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; + } + + if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && + (EC_GROUP_get_degree(group) > 163)) { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, + SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER); + goto err; + } + + /* + * XXX: For now, we only support ephemeral ECDH keys over named + * (not generic) curves. 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 = (unsigned char *) + OPENSSL_malloc(encodedlen * sizeof(unsigned char)); + 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; + + /* + * XXX: For now, we only support named (not generic) curves in + * ECDH ephemeral key exchanges. In this situation, we need four + * additional bytes to encode the entire ServerECDHParams + * structure. + */ + n = 4 + encodedlen; + + /* + * We'll generate the serverKeyExchange message explicitly so we + * can set these to NULLs + */ + r[0] = NULL; + r[1] = NULL; + r[2] = NULL; + r[3] = NULL; + } else +#endif /* !OPENSSL_NO_ECDH */ +#ifndef OPENSSL_NO_PSK + if (type & SSL_kPSK) { + /* + * reserve size for record length and PSK identity hint + */ + n += 2 + strlen(s->ctx->psk_identity_hint); + } else +#endif /* !OPENSSL_NO_PSK */ +#ifndef OPENSSL_NO_SRP + if (type & SSL_kSRP) { + if ((s->srp_ctx.N == NULL) || + (s->srp_ctx.g == NULL) || + (s->srp_ctx.s == NULL) || (s->srp_ctx.B == NULL)) { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, + SSL_R_MISSING_SRP_PARAM); + goto err; + } + r[0] = s->srp_ctx.N; + r[1] = s->srp_ctx.g; + r[2] = s->srp_ctx.s; + r[3] = s->srp_ctx.B; + } else +#endif + { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, + SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE); + goto f_err; + } + for (i = 0; i < 4 && r[i] != NULL; i++) { + nr[i] = BN_num_bytes(r[i]); +#ifndef OPENSSL_NO_SRP + if ((i == 2) && (type & SSL_kSRP)) + n += 1 + nr[i]; + else +#endif + n += 2 + nr[i]; + } + + if (!(s->s3->tmp.new_cipher->algorithm_auth & (SSL_aNULL | SSL_aSRP)) + && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) { + if ((pkey = ssl_get_sign_pkey(s, s->s3->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, n + SSL_HM_HEADER_LENGTH(s) + kn)) { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_LIB_BUF); + goto err; + } + d = p = ssl_handshake_start(s); + + for (i = 0; i < 4 && r[i] != NULL; i++) { +#ifndef OPENSSL_NO_SRP + if ((i == 2) && (type & SSL_kSRP)) { + *p = nr[i]; + p++; + } else +#endif + s2n(nr[i], p); + BN_bn2bin(r[i], p); + p += nr[i]; + } + +#ifndef OPENSSL_NO_ECDH + if (type & SSL_kEECDH) { + /* + * XXX: For now, we only support named (not generic) curves. In + * this situation, the serverKeyExchange message has: [1 byte + * CurveType], [2 byte CurveName] [1 byte length of encoded + * point], followed by the actual encoded point itself + */ + *p = NAMED_CURVE_TYPE; + p += 1; + *p = 0; + p += 1; + *p = curve_id; + p += 1; + *p = encodedlen; + p += 1; + memcpy((unsigned char *)p, + (unsigned char *)encodedPoint, encodedlen); + OPENSSL_free(encodedPoint); + encodedPoint = NULL; + p += encodedlen; + } +#endif + +#ifndef OPENSSL_NO_PSK + if (type & SSL_kPSK) { + /* copy PSK identity hint */ + s2n(strlen(s->ctx->psk_identity_hint), p); + strncpy((char *)p, s->ctx->psk_identity_hint, + strlen(s->ctx->psk_identity_hint)); + p += strlen(s->ctx->psk_identity_hint); + } +#endif + + /* 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. + */ +#ifndef OPENSSL_NO_RSA + if (pkey->type == EVP_PKEY_RSA && !SSL_USE_SIGALGS(s)) { + q = md_buf; + j = 0; + for (num = 2; num > 0; num--) { + EVP_MD_CTX_set_flags(&md_ctx, + EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); + if (EVP_DigestInit_ex(&md_ctx, + (num == 2) ? s->ctx->md5 + : s->ctx->sha1, + NULL) <= 0 + || EVP_DigestUpdate(&md_ctx, &(s->s3->client_random[0]), + SSL3_RANDOM_SIZE) <= 0 + || EVP_DigestUpdate(&md_ctx, &(s->s3->server_random[0]), + SSL3_RANDOM_SIZE) <= 0 + || EVP_DigestUpdate(&md_ctx, d, n) <= 0 + || EVP_DigestFinal_ex(&md_ctx, q, + (unsigned int *)&i) <= 0) { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, + ERR_LIB_EVP); + al = SSL_AD_INTERNAL_ERROR; + goto f_err; + } + 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 +#endif + 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; + } +#ifdef SSL_DEBUG + fprintf(stderr, "Using hash %s\n", EVP_MD_name(md)); +#endif + if (EVP_SignInit_ex(&md_ctx, md, NULL) <= 0 + || EVP_SignUpdate(&md_ctx, &(s->s3->client_random[0]), + SSL3_RANDOM_SIZE) <= 0 + || EVP_SignUpdate(&md_ctx, &(s->s3->server_random[0]), + SSL3_RANDOM_SIZE) <= 0 + || EVP_SignUpdate(&md_ctx, d, n) <= 0 + || EVP_SignFinal(&md_ctx, &(p[2]), + (unsigned int *)&i, pkey) <= 0) { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, ERR_LIB_EVP); + al = SSL_AD_INTERNAL_ERROR; + goto f_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; + } + } + + ssl_set_handshake_header(s, SSL3_MT_SERVER_KEY_EXCHANGE, n); + } + + s->state = SSL3_ST_SW_KEY_EXCH_B; + EVP_MD_CTX_cleanup(&md_ctx); + return ssl_do_write(s); + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + err: +#ifndef OPENSSL_NO_ECDH + if (encodedPoint != NULL) + OPENSSL_free(encodedPoint); + BN_CTX_free(bn_ctx); +#endif + EVP_MD_CTX_cleanup(&md_ctx); + s->state = SSL_ST_ERR; + 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->state == SSL3_ST_SW_CERT_REQ_A) { + buf = s->init_buf; + + d = p = ssl_handshake_start(s); + + /* 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)) { + const unsigned char *psigs; + nl = tls12_get_psigalgs(s, &psigs); + s2n(nl, p); + memcpy(p, psigs, nl); + p += nl; + 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, SSL_HM_HEADER_LENGTH(s) + n + j + 2)) { + SSLerr(SSL_F_SSL3_SEND_CERTIFICATE_REQUEST, + ERR_R_BUF_LIB); + goto err; + } + p = ssl_handshake_start(s) + n; + if (!(s->options & SSL_OP_NETSCAPE_CA_DN_BUG)) { + s2n(j, p); + i2d_X509_NAME(name, &p); + n += 2 + j; + nl += 2 + j; + } else { + d = p; + i2d_X509_NAME(name, &p); + j -= 2; + s2n(j, d); + j += 2; + n += j; + nl += j; + } + } + } + /* else no CA names */ + p = ssl_handshake_start(s) + off; + s2n(nl, p); + + ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE_REQUEST, n); + +#ifdef NETSCAPE_HANG_BUG + if (!SSL_IS_DTLS(s)) { + if (!BUF_MEM_grow_clean(buf, s->init_num + 4)) { + SSLerr(SSL_F_SSL3_SEND_CERTIFICATE_REQUEST, ERR_R_BUF_LIB); + goto err; + } + p = (unsigned char *)s->init_buf->data + s->init_num; + /* do the header */ + *(p++) = SSL3_MT_SERVER_DONE; + *(p++) = 0; + *(p++) = 0; + *(p++) = 0; + s->init_num += 4; + } +#endif + + s->state = SSL3_ST_SW_CERT_REQ_B; + } + + /* SSL3_ST_SW_CERT_REQ_B */ + return ssl_do_write(s); + err: + s->state = SSL_ST_ERR; + return (-1); +} + +int ssl3_get_client_key_exchange(SSL *s) +{ + int i, al, ok; + long n; + unsigned long alg_k; + unsigned char *p; +#ifndef OPENSSL_NO_RSA + RSA *rsa = NULL; + EVP_PKEY *pkey = NULL; +#endif +#ifndef OPENSSL_NO_DH + BIGNUM *pub = NULL; + DH *dh_srvr, *dh_clnt = NULL; +#endif +#ifndef OPENSSL_NO_KRB5 + KSSL_ERR kssl_err; +#endif /* OPENSSL_NO_KRB5 */ + +#ifndef OPENSSL_NO_ECDH + EC_KEY *srvr_ecdh = NULL; + EVP_PKEY *clnt_pub_pkey = NULL; + EC_POINT *clnt_ecpoint = NULL; + BN_CTX *bn_ctx = NULL; +#endif + + n = s->method->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->init_msg; + + alg_k = s->s3->tmp.new_cipher->algorithm_mkey; + +#ifndef OPENSSL_NO_RSA + if (alg_k & SSL_kRSA) { + unsigned char rand_premaster_secret[SSL_MAX_MASTER_KEY_LENGTH]; + int decrypt_len; + unsigned char decrypt_good, version_good; + size_t j; + + /* FIX THIS UP EAY EAY EAY EAY */ + if (s->s3->tmp.use_rsa_tmp) { + if ((s->cert != NULL) && (s->cert->rsa_tmp != NULL)) + rsa = s->cert->rsa_tmp; + /* + * Don't do a callback because rsa_tmp should be sent already + */ + if (rsa == NULL) { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_MISSING_TMP_RSA_PKEY); + goto f_err; + + } + } else { + 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; + } + + /* TLS and [incidentally] DTLS{0xFEFF} */ + if (s->version > SSL3_VERSION && s->version != DTLS1_BAD_VER) { + n2s(p, i); + if (n != i + 2) { + if (!(s->options & SSL_OP_TLS_D5_BUG)) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG); + goto f_err; + } else + p -= 2; + } else + n = i; + } + + /* + * Reject overly short RSA ciphertext because we want to be sure + * that the buffer size makes it safe to iterate over the entire + * size of a premaster secret (SSL_MAX_MASTER_KEY_LENGTH). The + * actual expected size is larger due to RSA padding, but the + * bound is sufficient to be safe. + */ + if (n < SSL_MAX_MASTER_KEY_LENGTH) { + al = SSL_AD_DECRYPT_ERROR; + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG); + goto f_err; + } + + /* + * We must not leak whether a decryption failure occurs because of + * Bleichenbacher's attack on PKCS #1 v1.5 RSA padding (see RFC 2246, + * section 7.4.7.1). The code follows that advice of the TLS RFC and + * generates a random premaster secret for the case that the decrypt + * fails. See https://tools.ietf.org/html/rfc5246#section-7.4.7.1 + */ + + /* + * should be RAND_bytes, but we cannot work around a failure. + */ + if (RAND_pseudo_bytes(rand_premaster_secret, + sizeof(rand_premaster_secret)) <= 0) + goto err; + decrypt_len = + RSA_private_decrypt((int)n, p, p, rsa, RSA_PKCS1_PADDING); + ERR_clear_error(); + + /* + * decrypt_len should be SSL_MAX_MASTER_KEY_LENGTH. decrypt_good will + * be 0xff if so and zero otherwise. + */ + decrypt_good = + constant_time_eq_int_8(decrypt_len, SSL_MAX_MASTER_KEY_LENGTH); + + /* + * If the version in the decrypted pre-master secret is correct then + * version_good will be 0xff, otherwise it'll be zero. 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". Thus version checks are done in + * constant time and are treated like any other decryption error. + */ + version_good = + constant_time_eq_8(p[0], (unsigned)(s->client_version >> 8)); + version_good &= + constant_time_eq_8(p[1], (unsigned)(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->options & SSL_OP_TLS_ROLLBACK_BUG) { + unsigned char workaround_good; + workaround_good = + constant_time_eq_8(p[0], (unsigned)(s->version >> 8)); + workaround_good &= + constant_time_eq_8(p[1], (unsigned)(s->version & 0xff)); + version_good |= workaround_good; + } + + /* + * Both decryption and version must be good for decrypt_good to + * remain non-zero (0xff). + */ + decrypt_good &= version_good; + + /* + * Now copy rand_premaster_secret over from p using + * decrypt_good_mask. If decryption failed, then p does not + * contain valid plaintext, however, a check above guarantees + * it is still sufficiently large to read from. + */ + for (j = 0; j < sizeof(rand_premaster_secret); j++) { + p[j] = constant_time_select_8(decrypt_good, p[j], + rand_premaster_secret[j]); + } + + s->session->master_key_length = + s->method->ssl3_enc->generate_master_secret(s, + s-> + session->master_key, + p, + sizeof + (rand_premaster_secret)); + OPENSSL_cleanse(p, sizeof(rand_premaster_secret)); + } else +#endif +#ifndef OPENSSL_NO_DH + if (alg_k & (SSL_kEDH | SSL_kDHr | SSL_kDHd)) { + int idx = -1; + EVP_PKEY *skey = NULL; + if (n > 1) { + n2s(p, i); + } else { + if (alg_k & SSL_kDHE) { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG); + goto f_err; + } + i = 0; + } + if (n && n != i + 2) { + if (!(s->options & SSL_OP_SSLEAY_080_CLIENT_DH_BUG)) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG); + goto err; + } else { + p -= 2; + i = (int)n; + } + } + if (alg_k & SSL_kDHr) + idx = SSL_PKEY_DH_RSA; + else if (alg_k & SSL_kDHd) + idx = SSL_PKEY_DH_DSA; + if (idx >= 0) { + skey = s->cert->pkeys[idx].privatekey; + if ((skey == NULL) || + (skey->type != EVP_PKEY_DH) || (skey->pkey.dh == NULL)) { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_MISSING_RSA_CERTIFICATE); + goto f_err; + } + dh_srvr = skey->pkey.dh; + } else if (s->s3->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; + } else + dh_srvr = s->s3->tmp.dh; + + if (n == 0L) { + /* Get pubkey from cert */ + EVP_PKEY *clkey = X509_get_pubkey(s->session->peer); + if (clkey) { + if (EVP_PKEY_cmp_parameters(clkey, skey) == 1) + dh_clnt = EVP_PKEY_get1_DH(clkey); + } + if (dh_clnt == NULL) { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_MISSING_TMP_DH_KEY); + goto f_err; + } + EVP_PKEY_free(clkey); + pub = dh_clnt->pub_key; + } else + pub = BN_bin2bn(p, i, NULL); + if (pub == NULL) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_BN_LIB); + goto err; + } + + i = DH_compute_key(p, pub, dh_srvr); + + if (i <= 0) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_DH_LIB); + BN_clear_free(pub); + goto err; + } + + DH_free(s->s3->tmp.dh); + s->s3->tmp.dh = NULL; + if (dh_clnt) + DH_free(dh_clnt); + else + BN_clear_free(pub); + pub = NULL; + s->session->master_key_length = + s->method->ssl3_enc->generate_master_secret(s, + s-> + session->master_key, + p, i); + OPENSSL_cleanse(p, i); + if (dh_clnt) + return 2; + } else +#endif +#ifndef OPENSSL_NO_KRB5 + if (alg_k & SSL_kKRB5) { + krb5_error_code krb5rc; + krb5_data enc_ticket; + krb5_data authenticator; + krb5_data enc_pms; + KSSL_CTX *kssl_ctx = s->kssl_ctx; + EVP_CIPHER_CTX ciph_ctx; + const EVP_CIPHER *enc = NULL; + unsigned char iv[EVP_MAX_IV_LENGTH]; + unsigned char pms[SSL_MAX_MASTER_KEY_LENGTH + EVP_MAX_BLOCK_LENGTH]; + int padl, outl; + krb5_timestamp authtime = 0; + krb5_ticket_times ttimes; + int kerr = 0; + + EVP_CIPHER_CTX_init(&ciph_ctx); + + if (!kssl_ctx) + kssl_ctx = kssl_ctx_new(); + + n2s(p, i); + enc_ticket.length = i; + + if (n < (long)(enc_ticket.length + 6)) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_DATA_LENGTH_TOO_LONG); + goto err; + } + + enc_ticket.data = (char *)p; + p += enc_ticket.length; + + n2s(p, i); + authenticator.length = i; + + if (n < (long)(enc_ticket.length + authenticator.length + 6)) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_DATA_LENGTH_TOO_LONG); + goto err; + } + + authenticator.data = (char *)p; + p += authenticator.length; + + n2s(p, i); + enc_pms.length = i; + enc_pms.data = (char *)p; + p += enc_pms.length; + + /* + * Note that the length is checked again below, ** after decryption + */ + if (enc_pms.length > sizeof pms) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_DATA_LENGTH_TOO_LONG); + goto err; + } + + if (n != (long)(enc_ticket.length + authenticator.length + + enc_pms.length + 6)) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_DATA_LENGTH_TOO_LONG); + goto err; + } + + if ((krb5rc = kssl_sget_tkt(kssl_ctx, &enc_ticket, &ttimes, + &kssl_err)) != 0) { +# ifdef KSSL_DEBUG + fprintf(stderr, "kssl_sget_tkt rtn %d [%d]\n", + krb5rc, kssl_err.reason); + if (kssl_err.text) + fprintf(stderr, "kssl_err text= %s\n", kssl_err.text); +# endif /* KSSL_DEBUG */ + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, kssl_err.reason); + goto err; + } + + /* + * Note: no authenticator is not considered an error, ** but will + * return authtime == 0. + */ + if ((krb5rc = kssl_check_authent(kssl_ctx, &authenticator, + &authtime, &kssl_err)) != 0) { +# ifdef KSSL_DEBUG + fprintf(stderr, "kssl_check_authent rtn %d [%d]\n", + krb5rc, kssl_err.reason); + if (kssl_err.text) + fprintf(stderr, "kssl_err text= %s\n", kssl_err.text); +# endif /* KSSL_DEBUG */ + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, kssl_err.reason); + goto err; + } + + if ((krb5rc = kssl_validate_times(authtime, &ttimes)) != 0) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, krb5rc); + goto err; + } +# ifdef KSSL_DEBUG + kssl_ctx_show(kssl_ctx); +# endif /* KSSL_DEBUG */ + + enc = kssl_map_enc(kssl_ctx->enctype); + if (enc == NULL) + goto err; + + memset(iv, 0, sizeof iv); /* per RFC 1510 */ + + if (!EVP_DecryptInit_ex(&ciph_ctx, enc, NULL, kssl_ctx->key, iv)) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_DECRYPTION_FAILED); + goto err; + } + if (!EVP_DecryptUpdate(&ciph_ctx, pms, &outl, + (unsigned char *)enc_pms.data, enc_pms.length)) + { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_DECRYPTION_FAILED); + kerr = 1; + goto kclean; + } + if (outl > SSL_MAX_MASTER_KEY_LENGTH) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_DATA_LENGTH_TOO_LONG); + kerr = 1; + goto kclean; + } + if (!EVP_DecryptFinal_ex(&ciph_ctx, &(pms[outl]), &padl)) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_DECRYPTION_FAILED); + kerr = 1; + goto kclean; + } + outl += padl; + if (outl > SSL_MAX_MASTER_KEY_LENGTH) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_DATA_LENGTH_TOO_LONG); + kerr = 1; + goto kclean; + } + if (!((pms[0] == (s->client_version >> 8)) + && (pms[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 random + * bytes instead of the protocol version. If + * SSL_OP_TLS_ROLLBACK_BUG is set, tolerate such clients. + * (Perhaps we should have a separate BUG value for the Kerberos + * cipher) + */ + if (!(s->options & SSL_OP_TLS_ROLLBACK_BUG)) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_AD_DECODE_ERROR); + kerr = 1; + goto kclean; + } + } + + EVP_CIPHER_CTX_cleanup(&ciph_ctx); + + s->session->master_key_length = + s->method->ssl3_enc->generate_master_secret(s, + s-> + session->master_key, + pms, outl); + + if (kssl_ctx->client_princ) { + size_t len = strlen(kssl_ctx->client_princ); + if (len < SSL_MAX_KRB5_PRINCIPAL_LENGTH) { + s->session->krb5_client_princ_len = len; + memcpy(s->session->krb5_client_princ, kssl_ctx->client_princ, + len); + } + } + + /*- Was doing kssl_ctx_free() here, + * but it caused problems for apache. + * kssl_ctx = kssl_ctx_free(kssl_ctx); + * if (s->kssl_ctx) s->kssl_ctx = NULL; + */ + + kclean: + OPENSSL_cleanse(pms, sizeof(pms)); + if (kerr) + goto err; + } else +#endif /* OPENSSL_NO_KRB5 */ + +#ifndef OPENSSL_NO_ECDH + if (alg_k & (SSL_kEECDH | SSL_kECDHr | SSL_kECDHe)) { + int ret = 1; + int field_size = 0; + 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; + } + + /* Let's get server private key and group information */ + if (alg_k & (SSL_kECDHr | SSL_kECDHe)) { + /* use the certificate */ + tkey = s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec; + } else { + /* + * use the ephermeral values we saved when generating the + * ServerKeyExchange msg. + */ + tkey = s->s3->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 (alg_k & SSL_kEECDH) { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_MISSING_TMP_ECDH_KEY); + goto f_err; + } + 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->init_buf->data; + } + + /* Compute the shared pre-master secret */ + field_size = EC_GROUP_get_degree(group); + if (field_size <= 0) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB); + goto err; + } + i = ECDH_compute_key(p, (field_size + 7) / 8, 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(s->s3->tmp.ecdh); + s->s3->tmp.ecdh = NULL; + + /* Compute the master secret */ + s->session->master_key_length = + s->method->ssl3_enc->generate_master_secret(s, + s-> + session->master_key, + p, i); + + OPENSSL_cleanse(p, i); + return (ret); + } else +#endif +#ifndef OPENSSL_NO_PSK + if (alg_k & SSL_kPSK) { + unsigned char *t = NULL; + unsigned char psk_or_pre_ms[PSK_MAX_PSK_LEN * 2 + 4]; + unsigned int pre_ms_len = 0, psk_len = 0; + int psk_err = 1; + char tmp_id[PSK_MAX_IDENTITY_LEN + 1]; + + al = SSL_AD_HANDSHAKE_FAILURE; + + n2s(p, i); + if (n != i + 2) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_LENGTH_MISMATCH); + goto psk_err; + } + if (i > PSK_MAX_IDENTITY_LEN) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_DATA_LENGTH_TOO_LONG); + goto psk_err; + } + if (s->psk_server_callback == NULL) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_PSK_NO_SERVER_CB); + goto psk_err; + } + + /* + * Create guaranteed NULL-terminated identity string for the callback + */ + memcpy(tmp_id, p, i); + memset(tmp_id + i, 0, PSK_MAX_IDENTITY_LEN + 1 - i); + psk_len = s->psk_server_callback(s, tmp_id, + psk_or_pre_ms, + sizeof(psk_or_pre_ms)); + OPENSSL_cleanse(tmp_id, PSK_MAX_IDENTITY_LEN + 1); + + if (psk_len > PSK_MAX_PSK_LEN) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR); + goto psk_err; + } else if (psk_len == 0) { + /* + * PSK related to the given identity not found + */ + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_PSK_IDENTITY_NOT_FOUND); + al = SSL_AD_UNKNOWN_PSK_IDENTITY; + goto psk_err; + } + + /* create PSK pre_master_secret */ + pre_ms_len = 2 + psk_len + 2 + psk_len; + t = psk_or_pre_ms; + memmove(psk_or_pre_ms + psk_len + 4, psk_or_pre_ms, psk_len); + s2n(psk_len, t); + memset(t, 0, psk_len); + t += psk_len; + s2n(psk_len, t); + + if (s->session->psk_identity != NULL) + OPENSSL_free(s->session->psk_identity); + s->session->psk_identity = BUF_strndup((char *)p, i); + if (s->session->psk_identity == NULL) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE); + goto psk_err; + } + + if (s->session->psk_identity_hint != NULL) + OPENSSL_free(s->session->psk_identity_hint); + s->session->psk_identity_hint = BUF_strdup(s->ctx->psk_identity_hint); + if (s->ctx->psk_identity_hint != NULL && + s->session->psk_identity_hint == NULL) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE); + goto psk_err; + } + + s->session->master_key_length = + s->method->ssl3_enc->generate_master_secret(s, + s-> + session->master_key, + psk_or_pre_ms, + pre_ms_len); + psk_err = 0; + psk_err: + OPENSSL_cleanse(psk_or_pre_ms, sizeof(psk_or_pre_ms)); + if (psk_err != 0) + goto f_err; + } else +#endif +#ifndef OPENSSL_NO_SRP + if (alg_k & SSL_kSRP) { + int param_len; + + n2s(p, i); + param_len = i + 2; + if (param_len > n) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_BAD_SRP_A_LENGTH); + goto f_err; + } + if (!(s->srp_ctx.A = BN_bin2bn(p, i, NULL))) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_BN_LIB); + goto err; + } + if (BN_ucmp(s->srp_ctx.A, s->srp_ctx.N) >= 0 + || BN_is_zero(s->srp_ctx.A)) { + al = SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_BAD_SRP_PARAMETERS); + goto f_err; + } + if (s->session->srp_username != NULL) + OPENSSL_free(s->session->srp_username); + s->session->srp_username = BUF_strdup(s->srp_ctx.login); + if (s->session->srp_username == NULL) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE); + goto err; + } + + if ((s->session->master_key_length = + SRP_generate_server_master_secret(s, + s->session->master_key)) < 0) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR); + goto err; + } + + p += i; + } else +#endif /* OPENSSL_NO_SRP */ + if (alg_k & SSL_kGOST) { + int ret = 0; + 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; + + /* Get our certificate private key */ + alg_a = s->s3->tmp.new_cipher->algorithm_auth; + if (alg_a & SSL_aGOST94) + pk = s->cert->pkeys[SSL_PKEY_GOST94].privatekey; + else if (alg_a & SSL_aGOST01) + pk = s->cert->pkeys[SSL_PKEY_GOST01].privatekey; + + pkey_ctx = EVP_PKEY_CTX_new(pk, NULL); + if (pkey_ctx == NULL) { + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE); + goto f_err; + } + if (EVP_PKEY_decrypt_init(pkey_ctx) <= 0) { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR); + goto gerr; + } + /* + * 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(); + } + /* 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->ssl3_enc->generate_master_secret(s, + s-> + session->master_key, + premaster_secret, 32); + OPENSSL_cleanse(premaster_secret, sizeof(premaster_secret)); + /* 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; + } 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); +#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_RSA) || !defined(OPENSSL_NO_ECDH) || defined(OPENSSL_NO_SRP) + err: +#endif +#ifndef OPENSSL_NO_ECDH + EVP_PKEY_free(clnt_pub_pkey); + EC_POINT_free(clnt_ecpoint); + if (srvr_ecdh != NULL) + EC_KEY_free(srvr_ecdh); + BN_CTX_free(bn_ctx); +#endif + s->state = SSL_ST_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); + + /* + * We should only process a CertificateVerify message if we have received + * a Certificate from the client. If so then |s->session->peer| will be non + * NULL. In some instances a CertificateVerify message is not required even + * if the peer has sent a Certificate (e.g. such as in the case of static + * DH). In that case the ClientKeyExchange processing will skip the + * CertificateVerify state so we should not arrive here. + */ + if (s->session->peer == NULL) { + ret = 1; + goto end; + } + + n = s->method->ssl_get_message(s, + SSL3_ST_SR_CERT_VRFY_A, + SSL3_ST_SR_CERT_VRFY_B, + SSL3_MT_CERTIFICATE_VERIFY, + SSL3_RT_MAX_PLAIN_LENGTH, &ok); + + if (!ok) + return ((int)n); + + peer = s->session->peer; + pkey = X509_get_pubkey(peer); + type = X509_certificate_type(peer, pkey); + + 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; + } + + /* we now have a signature that we need to verify */ + p = (unsigned char *)s->init_msg; + /* Check for broken implementations of GOST ciphersuites */ + /* + * If key is GOST and n is exactly 64, it is 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 rv = tls12_check_peer_sigalg(&md, s, p, pkey); + if (rv == -1) { + al = SSL_AD_INTERNAL_ERROR; + goto f_err; + } else if (rv == 0) { + al = SSL_AD_DECODE_ERROR; + goto f_err; + } +#ifdef SSL_DEBUG + fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md)); +#endif + p += 2; + n -= 2; + } + n2s(p, i); + n -= 2; + if (i > n) { + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, SSL_R_LENGTH_MISMATCH); + al = SSL_AD_DECODE_ERROR; + goto f_err; + } + } + 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(s->s3->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; + } +#ifdef SSL_DEBUG + fprintf(stderr, "Using TLS 1.2 with client verify alg %s\n", + EVP_MD_name(md)); +#endif + 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 +#ifndef OPENSSL_NO_RSA + if (pkey->type == EVP_PKEY_RSA) { + i = RSA_verify(NID_md5_sha1, s->s3->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 +#endif +#ifndef OPENSSL_NO_DSA + if (pkey->type == EVP_PKEY_DSA) { + j = DSA_verify(pkey->save_type, + &(s->s3->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 +#endif +#ifndef OPENSSL_NO_ECDSA + if (pkey->type == EVP_PKEY_EC) { + j = ECDSA_verify(pkey->save_type, + &(s->s3->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 +#endif + if (pkey->type == NID_id_GostR3410_94 + || pkey->type == NID_id_GostR3410_2001) { + unsigned char signature[64]; + int idx; + EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(pkey, NULL); + if (pctx == NULL) { + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, ERR_R_MALLOC_FAILURE); + goto f_err; + } + if (EVP_PKEY_verify_init(pctx) <= 0) { + EVP_PKEY_CTX_free(pctx); + al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, ERR_R_INTERNAL_ERROR); + goto f_err; + } + if (i != 64) { + fprintf(stderr, "GOST signature length is %d", i); + } + for (idx = 0; idx < 64; idx++) { + signature[63 - idx] = p[idx]; + } + j = EVP_PKEY_verify(pctx, signature, 64, s->s3->tmp.cert_verify_md, + 32); + EVP_PKEY_CTX_free(pctx); + if (j <= 0) { + al = SSL_AD_DECRYPT_ERROR; + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, SSL_R_BAD_ECDSA_SIGNATURE); + goto f_err; + } + } else { + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY, ERR_R_INTERNAL_ERROR); + al = SSL_AD_UNSUPPORTED_CERTIFICATE; + goto f_err; + } + + ret = 1; + if (0) { + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + s->state = SSL_ST_ERR; + } + end: + if (s->s3->handshake_buffer) { + BIO_free(s->s3->handshake_buffer); + s->s3->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) +{ + int i, ok, al, ret = -1; + X509 *x = NULL; + unsigned long l, nc, llen, n; + const unsigned char *p, *q; + unsigned char *d; + STACK_OF(X509) *sk = NULL; + + n = s->method->ssl_get_message(s, + SSL3_ST_SR_CERT_A, + SSL3_ST_SR_CERT_B, + -1, s->max_cert_list, &ok); + + if (!ok) + return ((int)n); + + if (s->s3->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 ((s->version > SSL3_VERSION) && s->s3->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; + } + s->s3->tmp.reuse_message = 1; + return (1); + } + + if (s->s3->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; + } + p = d = (unsigned char *)s->init_msg; + + if ((sk = sk_X509_new_null()) == NULL) { + SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, ERR_R_MALLOC_FAILURE); + goto err; + } + + n2l3(p, llen); + if (llen + 3 != n) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, SSL_R_LENGTH_MISMATCH); + goto f_err; + } + for (nc = 0; nc < llen;) { + n2l3(p, l); + if ((l + nc + 3) > llen) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, + SSL_R_CERT_LENGTH_MISMATCH); + goto f_err; + } + + q = p; + x = d2i_X509(NULL, &p, l); + if (x == NULL) { + SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, ERR_R_ASN1_LIB); + goto err; + } + if (p != (q + l)) { + 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; + nc += l + 3; + } + + if (sk_X509_num(sk) <= 0) { + /* TLS does not mind 0 certs returned */ + if (s->version == SSL3_VERSION) { + al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, + SSL_R_NO_CERTIFICATES_RETURNED); + goto f_err; + } + /* Fail for TLS only if we required a certificate */ + else 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 (s->s3->handshake_buffer && !ssl3_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_CERTIFICATE_VERIFY_FAILED); + goto f_err; + } + } + + if (s->session->peer != NULL) /* This should not be needed */ + 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 (s->session->sess_cert == NULL) { + s->session->sess_cert = ssl_sess_cert_new(); + if (s->session->sess_cert == NULL) { + SSLerr(SSL_F_SSL3_GET_CLIENT_CERTIFICATE, ERR_R_MALLOC_FAILURE); + goto err; + } + } + if (s->session->sess_cert->cert_chain != NULL) + sk_X509_pop_free(s->session->sess_cert->cert_chain, X509_free); + s->session->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) { + f_err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + err: + s->state = SSL_ST_ERR; + } + + if (x != NULL) + X509_free(x); + if (sk != NULL) + sk_X509_pop_free(sk, X509_free); + return (ret); +} + +int ssl3_send_server_certificate(SSL *s) +{ + CERT_PKEY *cpk; + + if (s->state == SSL3_ST_SW_CERT_A) { + cpk = ssl_get_server_send_pkey(s); + if (cpk == NULL) { + /* VRS: allow null cert if auth == KRB5 */ + if ((s->s3->tmp.new_cipher->algorithm_auth != SSL_aKRB5) || + (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kKRB5)) { + SSLerr(SSL_F_SSL3_SEND_SERVER_CERTIFICATE, + ERR_R_INTERNAL_ERROR); + s->state = SSL_ST_ERR; + return (0); + } + } + + if (!ssl3_output_cert_chain(s, cpk)) { + SSLerr(SSL_F_SSL3_SEND_SERVER_CERTIFICATE, ERR_R_INTERNAL_ERROR); + s->state = SSL_ST_ERR; + return (0); + } + s->state = SSL3_ST_SW_CERT_B; + } + + /* SSL3_ST_SW_CERT_B */ + return ssl_do_write(s); +} + +#ifndef OPENSSL_NO_TLSEXT +/* send a new session ticket (not necessarily for a new session) */ +int ssl3_send_newsession_ticket(SSL *s) +{ + unsigned char *senc = NULL; + EVP_CIPHER_CTX ctx; + HMAC_CTX hctx; + + if (s->state == SSL3_ST_SW_SESSION_TICKET_A) { + unsigned char *p, *macstart; + const unsigned char *const_p; + int len, slen_full, slen; + SSL_SESSION *sess; + unsigned int hlen; + SSL_CTX *tctx = s->initial_ctx; + unsigned char iv[EVP_MAX_IV_LENGTH]; + unsigned char key_name[16]; + + /* 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 == 0 || slen_full > 0xFF00) { + s->state = SSL_ST_ERR; + return -1; + } + senc = OPENSSL_malloc(slen_full); + if (!senc) { + s->state = SSL_ST_ERR; + return -1; + } + + EVP_CIPHER_CTX_init(&ctx); + HMAC_CTX_init(&hctx); + + p = senc; + if (!i2d_SSL_SESSION(s->session, &p)) + goto err; + + /* + * 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; + sess->session_id_length = 0; /* ID is irrelevant for the ticket */ + + slen = i2d_SSL_SESSION(sess, NULL); + if (slen == 0 || slen > slen_full) { /* shouldn't ever happen */ + SSL_SESSION_free(sess); + goto err; + } + p = senc; + if (!i2d_SSL_SESSION(sess, &p)) { + SSL_SESSION_free(sess); + goto err; + } + SSL_SESSION_free(sess); + + /*- + * Grow buffer if need be: the length calculation is as + * follows handshake_header_length + + * 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->init_buf, + SSL_HM_HEADER_LENGTH(s) + 22 + EVP_MAX_IV_LENGTH + + EVP_MAX_BLOCK_LENGTH + EVP_MAX_MD_SIZE + slen)) + goto err; + + p = ssl_handshake_start(s); + /* + * Initialize HMAC and cipher contexts. If callback present it does + * all the work otherwise use generated values from parent ctx. + */ + if (tctx->tlsext_ticket_key_cb) { + if (tctx->tlsext_ticket_key_cb(s, key_name, iv, &ctx, + &hctx, 1) < 0) + goto err; + } else { + if (RAND_bytes(iv, 16) <= 0) + goto err; + if (!EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, + tctx->tlsext_tick_aes_key, iv)) + goto err; + if (!HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16, + tlsext_tick_md(), NULL)) + goto err; + memcpy(key_name, tctx->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->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 */ + if (!EVP_EncryptUpdate(&ctx, p, &len, senc, slen)) + goto err; + p += len; + if (!EVP_EncryptFinal(&ctx, p, &len)) + goto err; + p += len; + + if (!HMAC_Update(&hctx, macstart, p - macstart)) + goto err; + if (!HMAC_Final(&hctx, p, &hlen)) + goto err; + + EVP_CIPHER_CTX_cleanup(&ctx); + HMAC_CTX_cleanup(&hctx); + + p += hlen; + /* Now write out lengths: p points to end of data written */ + /* Total length */ + len = p - ssl_handshake_start(s); + /* Skip ticket lifetime hint */ + p = ssl_handshake_start(s) + 4; + s2n(len - 6, p); + ssl_set_handshake_header(s, SSL3_MT_NEWSESSION_TICKET, len); + s->state = SSL3_ST_SW_SESSION_TICKET_B; + OPENSSL_free(senc); + } + + /* SSL3_ST_SW_SESSION_TICKET_B */ + return ssl_do_write(s); + err: + if (senc) + OPENSSL_free(senc); + EVP_CIPHER_CTX_cleanup(&ctx); + HMAC_CTX_cleanup(&hctx); + s->state = SSL_ST_ERR; + return -1; +} + +int ssl3_send_cert_status(SSL *s) +{ + if (s->state == SSL3_ST_SW_CERT_STATUS_A) { + unsigned char *p; + /*- + * 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->init_buf, 8 + s->tlsext_ocsp_resplen)) { + s->state = SSL_ST_ERR; + return -1; + } + + p = (unsigned char *)s->init_buf->data; + + /* do the header */ + *(p++) = SSL3_MT_CERTIFICATE_STATUS; + /* message length */ + l2n3(s->tlsext_ocsp_resplen + 4, p); + /* status type */ + *(p++) = s->tlsext_status_type; + /* length of OCSP response */ + l2n3(s->tlsext_ocsp_resplen, p); + /* actual response */ + memcpy(p, s->tlsext_ocsp_resp, s->tlsext_ocsp_resplen); + /* number of bytes to write */ + s->init_num = 8 + s->tlsext_ocsp_resplen; + s->state = SSL3_ST_SW_CERT_STATUS_B; + s->init_off = 0; + } + + /* SSL3_ST_SW_CERT_STATUS_B */ + return (ssl3_do_write(s, SSL3_RT_HANDSHAKE)); +} + +# ifndef OPENSSL_NO_NEXTPROTONEG +/* + * 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) +{ + int ok; + int proto_len, padding_len; + long n; + const unsigned char *p; + + /* + * Clients cannot send a NextProtocol message if we didn't see the + * extension in their ClientHello + */ + if (!s->s3->next_proto_neg_seen) { + SSLerr(SSL_F_SSL3_GET_NEXT_PROTO, + SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION); + s->state = SSL_ST_ERR; + return -1; + } + + /* See the payload format below */ + n = s->method->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->state doesn't reflect whether ChangeCipherSpec has been received in + * this handshake, but s->s3->change_cipher_spec does (will be reset by + * ssl3_get_finished). + */ + if (!s->s3->change_cipher_spec) { + SSLerr(SSL_F_SSL3_GET_NEXT_PROTO, SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS); + s->state = SSL_ST_ERR; + return -1; + } + + if (n < 2) { + s->state = SSL_ST_ERR; + return 0; /* The body must be > 1 bytes long */ + } + + p = (unsigned char *)s->init_msg; + + /*- + * The payload looks like: + * uint8 proto_len; + * uint8 proto[proto_len]; + * uint8 padding_len; + * uint8 padding[padding_len]; + */ + proto_len = p[0]; + if (proto_len + 2 > s->init_num) { + s->state = SSL_ST_ERR; + return 0; + } + padding_len = p[proto_len + 1]; + if (proto_len + padding_len + 2 != s->init_num) { + s->state = SSL_ST_ERR; + return 0; + } + + s->next_proto_negotiated = OPENSSL_malloc(proto_len); + if (!s->next_proto_negotiated) { + SSLerr(SSL_F_SSL3_GET_NEXT_PROTO, ERR_R_MALLOC_FAILURE); + s->state = SSL_ST_ERR; + return 0; + } + memcpy(s->next_proto_negotiated, p + 1, proto_len); + s->next_proto_negotiated_len = proto_len; + + return 1; +} +# endif + +#endif diff --git a/thirdparty/openssl/ssl/ssl-lib.com b/thirdparty/openssl/ssl/ssl-lib.com new file mode 100644 index 0000000000..43fea17541 --- /dev/null +++ b/thirdparty/openssl/ssl/ssl-lib.com @@ -0,0 +1,1229 @@ +$! +$! SSL-LIB.COM +$! Written By: Robert Byer +$! Vice-President +$! A-Com Computing, Inc. +$! byer@mail.all-net.net +$! +$! Changes by Richard Levitte <richard@levitte.org> +$! +$! This command file compiles and creates the "[.xxx.EXE.SSL]LIBSSL.OLB" +$! library for OpenSSL. The "xxx" denotes the machine architecture of +$! ALPHA, IA64 or VAX. +$! +$! It is written to detect what type of machine you are compiling on +$! (i.e. ALPHA or VAX) and which "C" compiler you have (i.e. VAXC, DECC +$! or GNU C) or you can specify which compiler to use. +$! +$! Specify the following as P1 to build just that part or ALL to just +$! build everything. +$! +$! LIBRARY To just compile the [.xxx.EXE.SSL]LIBSSL.OLB Library. +$! SSL_TASK To just compile the [.xxx.EXE.SSL]SSL_TASK.EXE +$! +$! Specify DEBUG or NODEBUG as P2 to compile with or without debugger +$! information. +$! +$! Specify which compiler at P3 to try to compile under. +$! +$! VAXC For VAX C. +$! DECC For DEC C. +$! GNUC For GNU C. +$! +$! If you don't specify a compiler, it will try to determine which +$! "C" compiler to use. +$! +$! P4, if defined, sets a TCP/IP library to use, through one of the following +$! keywords: +$! +$! UCX for UCX +$! TCPIP for TCPIP (post UCX) +$! SOCKETSHR for SOCKETSHR+NETLIB +$! +$! P5, if defined, sets a compiler thread NOT needed on OpenVMS 7.1 (and up) +$! +$! P6, if defined, specifies the C pointer size. Ignored on VAX. +$! ("64=ARGV" gives more efficient code with HP C V7.3 or newer.) +$! Supported values are: +$! +$! "" Compile with default (/NOPOINTER_SIZE) +$! 32 Compile with /POINTER_SIZE=32 (SHORT) +$! 64 Compile with /POINTER_SIZE=64[=ARGV] (LONG[=ARGV]) +$! (Automatically select ARGV if compiler supports it.) +$! 64= Compile with /POINTER_SIZE=64 (LONG). +$! 64=ARGV Compile with /POINTER_SIZE=64=ARGV (LONG=ARGV). +$! +$! P7, if defined, specifies a directory where ZLIB files (zlib.h, +$! libz.olb) may be found. Optionally, a non-default object library +$! name may be included ("dev:[dir]libz_64.olb", for example). +$! +$! +$! Announce/identify. +$! +$ proc = f$environment( "procedure") +$ write sys$output "@@@ "+ - + f$parse( proc, , , "name")+ f$parse( proc, , , "type") +$! +$! Define A TCP/IP Library That We Will Need To Link To. +$! (That Is, If We Need To Link To One.) +$! +$ TCPIP_LIB = "" +$ ZLIB_LIB = "" +$! +$! Check What Architecture We Are Using. +$! +$ IF (F$GETSYI("CPU").LT.128) +$ THEN +$! +$! The Architecture Is VAX. +$! +$ ARCH = "VAX" +$! +$! Else... +$! +$ ELSE +$! +$! The Architecture Is Alpha, IA64 or whatever comes in the future. +$! +$ ARCH = F$EDIT( F$GETSYI( "ARCH_NAME"), "UPCASE") +$ IF (ARCH .EQS. "") THEN ARCH = "UNK" +$! +$! End The Architecture Check. +$! +$ ENDIF +$! +$ ARCHD = ARCH +$ LIB32 = "32" +$ OPT_FILE = "" +$ POINTER_SIZE = "" +$! +$! Check To Make Sure We Have Valid Command Line Parameters. +$! +$ GOSUB CHECK_OPTIONS +$! +$! Define The OBJ and EXE Directories. +$! +$ OBJ_DIR := SYS$DISK:[-.'ARCHD'.OBJ.SSL] +$ EXE_DIR := SYS$DISK:[-.'ARCHD'.EXE.SSL] +$! +$! Specify the destination directory in any /MAP option. +$! +$ if (LINKMAP .eqs. "MAP") +$ then +$ LINKMAP = LINKMAP+ "=''EXE_DIR'" +$ endif +$! +$! Add the location prefix to the linker options file name. +$! +$ if (OPT_FILE .nes. "") +$ then +$ OPT_FILE = EXE_DIR+ OPT_FILE +$ endif +$! +$! Initialise logical names and such +$! +$ GOSUB INITIALISE +$! +$! Tell The User What Kind of Machine We Run On. +$! +$ WRITE SYS$OUTPUT "Host system architecture: ''ARCHD'" +$! +$! Check To See If The Architecture Specific OBJ Directory Exists. +$! +$ IF (F$PARSE(OBJ_DIR).EQS."") +$ THEN +$! +$! It Dosen't Exist, So Create It. +$! +$ CREATE/DIR 'OBJ_DIR' +$! +$! End The Architecture Specific OBJ Directory Check. +$! +$ ENDIF +$! +$! Check To See If The Architecture Specific Directory Exists. +$! +$ IF (F$PARSE(EXE_DIR).EQS."") +$ THEN +$! +$! It Dosen't Exist, So Create It. +$! +$ CREATE/DIR 'EXE_DIR' +$! +$! End The Architecture Specific Directory Check. +$! +$ ENDIF +$! +$! Define The Library Name. +$! +$ SSL_LIB := 'EXE_DIR'SSL_LIBSSL'LIB32'.OLB +$! +$! Define The CRYPTO-LIB We Are To Use. +$! +$ CRYPTO_LIB := SYS$DISK:[-.'ARCHD'.EXE.CRYPTO]SSL_LIBCRYPTO'LIB32'.OLB +$! +$! Set up exceptional compilations. +$! +$ CC5_SHOWN = 0 +$! +$! Check To See What We Are To Do. +$! +$ IF (BUILDALL.EQS."TRUE") +$ THEN +$! +$! Since Nothing Special Was Specified, Do Everything. +$! +$ GOSUB LIBRARY +$ GOSUB SSL_TASK +$! +$! Else... +$! +$ ELSE +$! +$! Build Just What The User Wants Us To Build. +$! +$ GOSUB 'BUILDALL' +$! +$! End The BUILDALL Check. +$! +$ ENDIF +$! +$! Time To EXIT. +$! +$ EXIT: +$ GOSUB CLEANUP +$ EXIT +$! +$! Compile The Library. +$! +$ LIBRARY: +$! +$! Check To See If We Already Have A "[.xxx.EXE.SSL]SSL_LIBSSL''LIB32'.OLB" Library... +$! +$ IF (F$SEARCH(SSL_LIB).EQS."") +$ THEN +$! +$! Guess Not, Create The Library. +$! +$ LIBRARY/CREATE/OBJECT 'SSL_LIB' +$! +$! End The Library Exist Check. +$! +$ ENDIF +$! +$! Define The Different SSL "library" Files. +$! +$ LIB_SSL = "s2_meth, s2_srvr, s2_clnt, s2_lib, s2_enc, s2_pkt,"+ - + "s3_meth, s3_srvr, s3_clnt, s3_lib, s3_enc, s3_pkt, s3_both, s3_cbc,"+ - + "s23_meth,s23_srvr,s23_clnt,s23_lib, s23_pkt,"+ - + "t1_meth, t1_srvr, t1_clnt, t1_lib, t1_enc, t1_ext,"+ - + "d1_meth, d1_srvr, d1_clnt, d1_lib, d1_pkt,"+ - + "d1_both,d1_srtp,"+ - + "ssl_lib,ssl_err2,ssl_cert,ssl_sess,"+ - + "ssl_ciph,ssl_stat,ssl_rsa,"+ - + "ssl_asn1,ssl_txt,ssl_algs,ssl_conf,"+ - + "bio_ssl,ssl_err,kssl,t1_reneg,tls_srp,t1_trce,ssl_utst" +$! +$ COMPILEWITH_CC5 = "" +$! +$! Tell The User That We Are Compiling The Library. +$! +$ WRITE SYS$OUTPUT "Building The ",SSL_LIB," Library." +$! +$! Define A File Counter And Set It To "0" +$! +$ FILE_COUNTER = 0 +$! +$! Top Of The File Loop. +$! +$ NEXT_FILE: +$! +$! O.K, Extract The File Name From The File List. +$! +$ FILE_NAME = F$EDIT(F$ELEMENT(FILE_COUNTER,",",LIB_SSL),"COLLAPSE") +$! +$! Check To See If We Are At The End Of The File List. +$! +$ IF (FILE_NAME.EQS.",") THEN GOTO FILE_DONE +$! +$! Increment The Counter. +$! +$ FILE_COUNTER = FILE_COUNTER + 1 +$! +$! Create The Source File Name. +$! +$ SOURCE_FILE = "SYS$DISK:[]" + FILE_NAME + ".C" +$! +$! Create The Object File Name. +$! +$ OBJECT_FILE = OBJ_DIR + FILE_NAME + ".OBJ" +$ ON WARNING THEN GOTO NEXT_FILE +$! +$! Check To See If The File We Want To Compile Is Actually There. +$! +$ IF (F$SEARCH(SOURCE_FILE).EQS."") +$ THEN +$! +$! Tell The User That The File Dosen't Exist. +$! +$ WRITE SYS$OUTPUT "" +$ WRITE SYS$OUTPUT "The File ",SOURCE_FILE," Dosen't Exist." +$ WRITE SYS$OUTPUT "" +$! +$! Exit The Build. +$! +$ EXIT +$! +$! End The File Exists Check. +$! +$ ENDIF +$! +$! Tell The User What File We Are Compiling. +$! +$ WRITE SYS$OUTPUT " ",FILE_NAME,".c" +$! +$! Compile The File. +$! +$ ON ERROR THEN GOTO NEXT_FILE +$ CC/OBJECT='OBJECT_FILE' 'SOURCE_FILE' +$! +$! Add It To The Library. +$! +$ LIBRARY/REPLACE/OBJECT 'SSL_LIB' 'OBJECT_FILE' +$! +$! Time To Clean Up The Object File. +$! +$ DELETE 'OBJECT_FILE';* +$! +$! Go Back And Get The Next File Name. +$! +$ GOTO NEXT_FILE +$! +$! All Done With This Library. +$! +$ FILE_DONE: +$! +$! Tell The User That We Are All Done. +$! +$ WRITE SYS$OUTPUT "Library ",SSL_LIB," Compiled." +$! +$! Time To RETURN. +$! +$ RETURN +$ SSL_TASK: +$! +$! Check To See If We Have The Proper Libraries. +$! +$ GOSUB LIB_CHECK +$! +$! Check To See If We Have A Linker Option File. +$! +$ GOSUB CHECK_OPT_FILE +$! +$! Check To See If The File We Want To Compile Is Actually There. +$! +$ IF (F$SEARCH("SYS$DISK:[]SSL_TASK.C").EQS."") +$ THEN +$! +$! Tell The User That The File Dosen't Exist. +$! +$ WRITE SYS$OUTPUT "" +$ WRITE SYS$OUTPUT "The File SSL_TASK.C Dosen't Exist." +$ WRITE SYS$OUTPUT "" +$! +$! Exit The Build. +$! +$ EXIT +$! +$! End The SSL_TASK.C File Check. +$! +$ ENDIF +$! +$ COMPILEWITH_CC5 = "" !!! ",ssl_task," +$! +$! Tell The User We Are Creating The SSL_TASK. +$! +$! Tell The User We Are Creating The SSL_TASK. +$! +$ WRITE SYS$OUTPUT "Creating SSL_TASK OSU HTTP SSL Engine." +$! +$! Tell The User What File We Are Compiling. +$! +$ FILE_NAME = "ssl_task" +$ WRITE SYS$OUTPUT " ",FILE_NAME,".c" +$! +$! Compile The File. +$! +$ ON ERROR THEN GOTO SSL_TASK_END +$! +$ FILE_NAME0 = ","+ F$ELEMENT(0,".",FILE_NAME)+ "," +$ IF COMPILEWITH_CC5 - FILE_NAME0 .NES. COMPILEWITH_CC5 +$ THEN +$ if (.not. CC5_SHOWN) +$ then +$ CC5_SHOWN = 1 +$ write sys$output " \Using special rule (5)" +$ x = " "+ CC5 +$ write /symbol sys$output x +$ endif +$ CC5 /OBJECT='OBJ_DIR''FILE_NAME'.OBJ SYS$DISK:[]'FILE_NAME'.C +$ ELSE +$ CC /OBJECT='OBJ_DIR''FILE_NAME'.OBJ SYS$DISK:[]'FILE_NAME'.C +$ ENDIF +$! +$! Link The Program. +$! +$ LINK /'DEBUGGER' /'LINKMAP' /'TRACEBACK' /EXE='EXE_DIR'SSL_TASK.EXE - + 'OBJ_DIR'SSL_TASK.OBJ, - + 'SSL_LIB'/LIBRARY, - + 'CRYPTO_LIB'/LIBRARY - + 'TCPIP_LIB' - + 'ZLIB_LIB' - + ,'OPT_FILE' /OPTIONS +$! +$! Time To Return. +$! +$SSL_TASK_END: +$ RETURN +$! +$! Check For The Link Option FIle. +$! +$ CHECK_OPT_FILE: +$! +$! Check To See If We Need To Make A VAX C Option File. +$! +$ IF (COMPILER.EQS."VAXC") +$ THEN +$! +$! Check To See If We Already Have A VAX C Linker Option File. +$! +$ IF (F$SEARCH(OPT_FILE).EQS."") +$ THEN +$! +$! We Need A VAX C Linker Option File. +$! +$ CREATE 'OPT_FILE' +$DECK +! +! Default System Options File To Link Against +! The Sharable VAX C Runtime Library. +! +SYS$SHARE:VAXCRTL.EXE/SHARE +$EOD +$! +$! End The Option File Check. +$! +$ ENDIF +$! +$! End The VAXC Check. +$! +$ ENDIF +$! +$! Check To See If We Need A GNU C Option File. +$! +$ IF (COMPILER.EQS."GNUC") +$ THEN +$! +$! Check To See If We Already Have A GNU C Linker Option File. +$! +$ IF (F$SEARCH(OPT_FILE).EQS."") +$ THEN +$! +$! We Need A GNU C Linker Option File. +$! +$ CREATE 'OPT_FILE' +$DECK +! +! Default System Options File To Link Against +! The Sharable C Runtime Library. +! +GNU_CC:[000000]GCCLIB/LIBRARY +SYS$SHARE:VAXCRTL/SHARE +$EOD +$! +$! End The Option File Check. +$! +$ ENDIF +$! +$! End The GNU C Check. +$! +$ ENDIF +$! +$! Check To See If We Need A DEC C Option File. +$! +$ IF (COMPILER.EQS."DECC") +$ THEN +$! +$! Check To See If We Already Have A DEC C Linker Option File. +$! +$ IF (F$SEARCH(OPT_FILE).EQS."") +$ THEN +$! +$! Figure Out If We Need A non-VAX Or A VAX Linker Option File. +$! +$ IF (ARCH.EQS."VAX") +$ THEN +$! +$! We Need A DEC C Linker Option File For VAX. +$! +$ CREATE 'OPT_FILE' +$DECK +! +! Default System Options File To Link Against +! The Sharable DEC C Runtime Library. +! +SYS$SHARE:DECC$SHR.EXE/SHARE +$EOD +$! +$! Else... +$! +$ ELSE +$! +$! Create The non-VAX Linker Option File. +$! +$ CREATE 'OPT_FILE' +$DECK +! +! Default System Options File For non-VAX To Link Against +! The Sharable C Runtime Library. +! +SYS$SHARE:CMA$OPEN_LIB_SHR/SHARE +SYS$SHARE:CMA$OPEN_RTL/SHARE +$EOD +$! +$! End The DEC C Option File Check. +$! +$ ENDIF +$! +$! End The Option File Search. +$! +$ ENDIF +$! +$! End The DEC C Check. +$! +$ ENDIF +$! +$! Tell The User What Linker Option File We Are Using. +$! +$ WRITE SYS$OUTPUT "Using Linker Option File ",OPT_FILE,"." +$! +$! Time To RETURN. +$! +$ RETURN +$ LIB_CHECK: +$! +$! Look For The VAX Library LIBSSL.OLB. +$! +$ IF (F$SEARCH(SSL_LIB).EQS."") +$ THEN +$! +$! Tell The User We Can't Find The LIBSSL.OLB Library. +$! +$ WRITE SYS$OUTPUT "" +$ WRITE SYS$OUTPUT "Can't Find The Library ",SSL_LIB,"." +$ WRITE SYS$OUTPUT "We Can't Link Without It." +$ WRITE SYS$OUTPUT "" +$! +$! Since We Can't Link Without It, Exit. +$! +$ EXIT +$! +$! End The LIBSSL.OLB Library Check. +$! +$ ENDIF +$! +$! Look For The Library LIBCRYPTO.OLB. +$! +$ IF (F$SEARCH(CRYPTO_LIB).EQS."") +$ THEN +$! +$! Tell The User We Can't Find The LIBCRYPTO.OLB Library. +$! +$ WRITE SYS$OUTPUT "" +$ WRITE SYS$OUTPUT "Can't Find The Library ",CRYPTO_LIB,"." +$ WRITE SYS$OUTPUT "We Can't Link Without It." +$ WRITE SYS$OUTPUT "" +$! +$! Since We Can't Link Without It, Exit. +$! +$ EXIT +$! +$! End The LIBCRYPTO.OLB Library Check. +$! +$ ENDIF +$! +$! Time To Return. +$! +$ RETURN +$! +$! Check The User's Options. +$! +$ CHECK_OPTIONS: +$! +$! Check To See If P1 Is Blank. +$! +$ IF (P1.EQS."ALL") +$ THEN +$! +$! P1 Is Blank, So Build Everything. +$! +$ BUILDALL = "TRUE" +$! +$! Else... +$! +$ ELSE +$! +$! Else, Check To See If P1 Has A Valid Argument. +$! +$ IF (P1.EQS."LIBRARY").OR.(P1.EQS."SSL_TASK") +$ THEN +$! +$! A Valid Argument. +$! +$ BUILDALL = P1 +$! +$! Else... +$! +$ ELSE +$! +$! Tell The User We Don't Know What They Want. +$! +$ WRITE SYS$OUTPUT "" +$ WRITE SYS$OUTPUT "The Option ",P1," Is Invalid. The Valid Options Are:" +$ WRITE SYS$OUTPUT "" +$ WRITE SYS$OUTPUT " ALL : Just Build Everything." +$ WRITE SYS$OUTPUT " LIBRARY : To Compile Just The [.xxx.EXE.SSL]LIBSSL.OLB Library." +$ WRITE SYS$OUTPUT " SSL_TASK : To Compile Just The [.xxx.EXE.SSL]SSL_TASK.EXE Program." +$ WRITE SYS$OUTPUT "" +$ WRITE SYS$OUTPUT " Where 'xxx' Stands For:" +$ WRITE SYS$OUTPUT "" +$ WRITE SYS$OUTPUT " ALPHA[64]: Alpha Architecture." +$ WRITE SYS$OUTPUT " IA64[64] : IA64 Architecture." +$ WRITE SYS$OUTPUT " VAX : VAX Architecture." +$ WRITE SYS$OUTPUT "" +$! +$! Time To EXIT. +$! +$ EXIT +$! +$! End The Valid Argument Check. +$! +$ ENDIF +$! +$! End The P1 Check. +$! +$ ENDIF +$! +$! Check To See If P2 Is Blank. +$! +$ IF (P2.EQS."NODEBUG") +$ THEN +$! +$! P2 Is NODEBUG, So Compile Without Debugger Information. +$! +$ DEBUGGER = "NODEBUG" +$ LINKMAP = "NOMAP" +$ TRACEBACK = "NOTRACEBACK" +$ GCC_OPTIMIZE = "OPTIMIZE" +$ CC_OPTIMIZE = "OPTIMIZE" +$ WRITE SYS$OUTPUT "No Debugger Information Will Be Produced During Compile." +$ WRITE SYS$OUTPUT "Compiling With Compiler Optimization." +$! +$! Else... +$! +$ ELSE +$! +$! Check To See If We Are To Compile With Debugger Information. +$! +$ IF (P2.EQS."DEBUG") +$ THEN +$! +$! Compile With Debugger Information. +$! +$ DEBUGGER = "DEBUG" +$ LINKMAP = "MAP" +$ TRACEBACK = "TRACEBACK" +$ GCC_OPTIMIZE = "NOOPTIMIZE" +$ CC_OPTIMIZE = "NOOPTIMIZE" +$ WRITE SYS$OUTPUT "Debugger Information Will Be Produced During Compile." +$ WRITE SYS$OUTPUT "Compiling Without Compiler Optimization." +$ ELSE +$! +$! Tell The User Entered An Invalid Option. +$! +$ WRITE SYS$OUTPUT "" +$ WRITE SYS$OUTPUT "The Option ",P2," Is Invalid. The Valid Options Are:" +$ WRITE SYS$OUTPUT "" +$ WRITE SYS$OUTPUT " DEBUG : Compile With The Debugger Information." +$ WRITE SYS$OUTPUT " NODEBUG : Compile Without The Debugger Information." +$ WRITE SYS$OUTPUT "" +$! +$! Time To EXIT. +$! +$ EXIT +$! +$! End The Valid Argument Check. +$! +$ ENDIF +$! +$! End The P2 Check. +$! +$ ENDIF +$! +$! Special Threads For OpenVMS v7.1 Or Later +$! +$! Written By: Richard Levitte +$! richard@levitte.org +$! +$! +$! Check To See If We Have A Option For P5. +$! +$ IF (P5.EQS."") +$ THEN +$! +$! Get The Version Of VMS We Are Using. +$! +$ ISSEVEN := +$ TMP = F$ELEMENT(0,"-",F$EXTRACT(1,4,F$GETSYI("VERSION"))) +$ TMP = F$INTEGER(F$ELEMENT(0,".",TMP)+F$ELEMENT(1,".",TMP)) +$! +$! Check To See If The VMS Version Is v7.1 Or Later. +$! +$ IF (TMP.GE.71) +$ THEN +$! +$! We Have OpenVMS v7.1 Or Later, So Use The Special Threads. +$! +$ ISSEVEN := ,PTHREAD_USE_D4 +$! +$! End The VMS Version Check. +$! +$ ENDIF +$! +$! End The P5 Check. +$! +$ ENDIF +$! +$! Check P6 (POINTER_SIZE). +$! +$ IF (P6 .NES. "") .AND. (ARCH .NES. "VAX") +$ THEN +$! +$ IF (P6 .EQS. "32") +$ THEN +$ POINTER_SIZE = " /POINTER_SIZE=32" +$ ELSE +$ POINTER_SIZE = F$EDIT( P6, "COLLAPSE, UPCASE") +$ IF ((POINTER_SIZE .EQS. "64") .OR. - + (POINTER_SIZE .EQS. "64=") .OR. - + (POINTER_SIZE .EQS. "64=ARGV")) +$ THEN +$ ARCHD = ARCH+ "_64" +$ LIB32 = "" +$ POINTER_SIZE = " /POINTER_SIZE=64" +$ ELSE +$! +$! Tell The User Entered An Invalid Option. +$! +$ WRITE SYS$OUTPUT "" +$ WRITE SYS$OUTPUT "The Option ", P6, - + " Is Invalid. The Valid Options Are:" +$ WRITE SYS$OUTPUT "" +$ WRITE SYS$OUTPUT - + " """" : Compile with default (short) pointers." +$ WRITE SYS$OUTPUT - + " 32 : Compile with 32-bit (short) pointers." +$ WRITE SYS$OUTPUT - + " 64 : Compile with 64-bit (long) pointers (auto ARGV)." +$ WRITE SYS$OUTPUT - + " 64= : Compile with 64-bit (long) pointers (no ARGV)." +$ WRITE SYS$OUTPUT - + " 64=ARGV : Compile with 64-bit (long) pointers (ARGV)." +$ WRITE SYS$OUTPUT "" +$! +$! Time To EXIT. +$! +$ EXIT +$! +$ ENDIF +$! +$ ENDIF +$! +$! End The P6 (POINTER_SIZE) Check. +$! +$ ENDIF +$! +$! Set basic C compiler /INCLUDE directories. +$! +$ CC_INCLUDES = "SYS$DISK:[-.CRYPTO],SYS$DISK:[-]" +$! +$! Check To See If P3 Is Blank. +$! +$ IF (P3.EQS."") +$ THEN +$! +$! O.K., The User Didn't Specify A Compiler, Let's Try To +$! Find Out Which One To Use. +$! +$! Check To See If We Have GNU C. +$! +$ IF (F$TRNLNM("GNU_CC").NES."") +$ THEN +$! +$! Looks Like GNUC, Set To Use GNUC. +$! +$ P3 = "GNUC" +$! +$! End The GNU C Compiler Check. +$! +$ ELSE +$! +$! Check To See If We Have VAXC Or DECC. +$! +$ IF (ARCH.NES."VAX").OR.(F$TRNLNM("DECC$CC_DEFAULT").NES."") +$ THEN +$! +$! Looks Like DECC, Set To Use DECC. +$! +$ P3 = "DECC" +$! +$! Else... +$! +$ ELSE +$! +$! Looks Like VAXC, Set To Use VAXC. +$! +$ P3 = "VAXC" +$! +$! End The VAXC Compiler Check. +$! +$ ENDIF +$! +$! End The DECC & VAXC Compiler Check. +$! +$ ENDIF +$! +$! End The Compiler Check. +$! +$ ENDIF +$! +$! Check To See If We Have A Option For P4. +$! +$ IF (P4.EQS."") +$ THEN +$! +$! Find out what socket library we have available +$! +$ IF F$PARSE("SOCKETSHR:") .NES. "" +$ THEN +$! +$! We have SOCKETSHR, and it is my opinion that it's the best to use. +$! +$ P4 = "SOCKETSHR" +$! +$! Tell the user +$! +$ WRITE SYS$OUTPUT "Using SOCKETSHR for TCP/IP" +$! +$! Else, let's look for something else +$! +$ ELSE +$! +$! Like UCX (the reason to do this before Multinet is that the UCX +$! emulation is easier to use...) +$! +$ IF F$TRNLNM("UCX$IPC_SHR") .NES. "" - + .OR. F$PARSE("SYS$SHARE:UCX$IPC_SHR.EXE") .NES. "" - + .OR. F$PARSE("SYS$LIBRARY:UCX$IPC.OLB") .NES. "" +$ THEN +$! +$! Last resort: a UCX or UCX-compatible library +$! +$ P4 = "UCX" +$! +$! Tell the user +$! +$ WRITE SYS$OUTPUT "Using UCX or an emulation thereof for TCP/IP" +$! +$! That was all... +$! +$ ENDIF +$ ENDIF +$ ENDIF +$! +$! Set Up Initial CC Definitions, Possibly With User Ones +$! +$ CCDEFS = "TCPIP_TYPE_''P4'" +$ IF F$TYPE(USER_CCDEFS) .NES. "" THEN CCDEFS = CCDEFS + "," + USER_CCDEFS +$ CCEXTRAFLAGS = "" +$ IF F$TYPE(USER_CCFLAGS) .NES. "" THEN CCEXTRAFLAGS = USER_CCFLAGS +$ CCDISABLEWARNINGS = "" !!! "MAYLOSEDATA3" !!! "LONGLONGTYPE,LONGLONGSUFX,FOUNDCR" +$ IF F$TYPE(USER_CCDISABLEWARNINGS) .NES. "" +$ THEN +$ IF CCDISABLEWARNINGS .NES. THEN CCDISABLEWARNINGS = CCDISABLEWARNINGS + "," +$ CCDISABLEWARNINGS = CCDISABLEWARNINGS + USER_CCDISABLEWARNINGS +$ ENDIF +$! +$! Check To See If We Have A ZLIB Option. +$! +$ ZLIB = P7 +$ IF (ZLIB .NES. "") +$ THEN +$! +$! Check for expected ZLIB files. +$! +$ err = 0 +$ file1 = f$parse( "zlib.h", ZLIB, , , "SYNTAX_ONLY") +$ if (f$search( file1) .eqs. "") +$ then +$ WRITE SYS$OUTPUT "" +$ WRITE SYS$OUTPUT "The Option ", ZLIB, " Is Invalid." +$ WRITE SYS$OUTPUT " Can't find header: ''file1'" +$ err = 1 +$ endif +$ file1 = f$parse( "A.;", ZLIB)- "A.;" +$! +$ file2 = f$parse( ZLIB, "libz.olb", , , "SYNTAX_ONLY") +$ if (f$search( file2) .eqs. "") +$ then +$ if (err .eq. 0) +$ then +$ WRITE SYS$OUTPUT "" +$ WRITE SYS$OUTPUT "The Option ", ZLIB, " Is Invalid." +$ endif +$ WRITE SYS$OUTPUT " Can't find library: ''file2'" +$ WRITE SYS$OUTPUT "" +$ err = err+ 2 +$ endif +$ if (err .eq. 1) +$ then +$ WRITE SYS$OUTPUT "" +$ endif +$! +$ if (err .ne. 0) +$ then +$ EXIT +$ endif +$! +$ CCDEFS = """ZLIB=1"", "+ CCDEFS +$ CC_INCLUDES = CC_INCLUDES+ ", "+ file1 +$ ZLIB_LIB = ", ''file2' /library" +$! +$! Print info +$! +$ WRITE SYS$OUTPUT "ZLIB library spec: ", file2 +$! +$! End The ZLIB Check. +$! +$ ENDIF +$! +$! Check To See If The User Entered A Valid Parameter. +$! +$ IF (P3.EQS."VAXC").OR.(P3.EQS."DECC").OR.(P3.EQS."GNUC") +$ THEN +$! +$! Check To See If The User Wanted DECC. +$! +$ IF (P3.EQS."DECC") +$ THEN +$! +$! Looks Like DECC, Set To Use DECC. +$! +$ COMPILER = "DECC" +$! +$! Tell The User We Are Using DECC. +$! +$ WRITE SYS$OUTPUT "Using DECC 'C' Compiler." +$! +$! Use DECC... +$! +$ CC = "CC" +$ IF ARCH.EQS."VAX" .AND. F$TRNLNM("DECC$CC_DEFAULT").NES."/DECC" - + THEN CC = "CC/DECC" +$ CC = CC + " /''CC_OPTIMIZE' /''DEBUGGER' /STANDARD=RELAXED"+ - + "''POINTER_SIZE' /NOLIST /PREFIX=ALL" + - + " /INCLUDE=(''CC_INCLUDES') " + CCEXTRAFLAGS +$! +$! Define The Linker Options File Name. +$! +$ OPT_FILE = "VAX_DECC_OPTIONS.OPT" +$! +$! End DECC Check. +$! +$ ENDIF +$! +$! Check To See If We Are To Use VAXC. +$! +$ IF (P3.EQS."VAXC") +$ THEN +$! +$! Looks Like VAXC, Set To Use VAXC. +$! +$ COMPILER = "VAXC" +$! +$! Tell The User We Are Using VAX C. +$! +$ WRITE SYS$OUTPUT "Using VAXC 'C' Compiler." +$! +$! Compile Using VAXC. +$! +$ CC = "CC" +$ IF ARCH.NES."VAX" +$ THEN +$ WRITE SYS$OUTPUT "There is no VAX C on ''ARCH'!" +$ EXIT +$ ENDIF +$ IF F$TRNLNM("DECC$CC_DEFAULT").EQS."/DECC" THEN CC = "CC/VAXC" +$ CC = CC + "/''CC_OPTIMIZE'/''DEBUGGER'/NOLIST" + - + "/INCLUDE=(''CC_INCLUDES')" + CCEXTRAFLAGS +$ CCDEFS = CCDEFS + ",""VAXC""" +$! +$! Define <sys> As SYS$COMMON:[SYSLIB] +$! +$ DEFINE/NOLOG SYS SYS$COMMON:[SYSLIB] +$! +$! Define The Linker Options File Name. +$! +$ OPT_FILE = "VAX_VAXC_OPTIONS.OPT" +$! +$! End VAXC Check +$! +$ ENDIF +$! +$! Check To See If We Are To Use GNU C. +$! +$ IF (P3.EQS."GNUC") +$ THEN +$! +$! Looks Like GNUC, Set To Use GNUC. +$! +$ COMPILER = "GNUC" +$! +$! Tell The User We Are Using GNUC. +$! +$ WRITE SYS$OUTPUT "Using GNU 'C' Compiler." +$! +$! Use GNU C... +$! +$ IF F$TYPE(GCC) .EQS. "" THEN GCC := GCC +$ CC = GCC+"/NOCASE_HACK/''GCC_OPTIMIZE'/''DEBUGGER'/NOLIST" + - + "/INCLUDE=(''CC_INCLUDES')" + CCEXTRAFLAGS +$! +$! Define The Linker Options File Name. +$! +$ OPT_FILE = "VAX_GNUC_OPTIONS.OPT" +$! +$! End The GNU C Check. +$! +$ ENDIF +$! +$! Set up default defines +$! +$ CCDEFS = """FLAT_INC=1""," + CCDEFS +$! +$! Finish up the definition of CC. +$! +$ IF COMPILER .EQS. "DECC" +$ THEN +$! Not all compiler versions support MAYLOSEDATA3. +$ OPT_TEST = "MAYLOSEDATA3" +$ DEFINE /USER_MODE SYS$ERROR NL: +$ DEFINE /USER_MODE SYS$OUTPUT NL: +$ 'CC' /NOCROSS_REFERENCE /NOLIST /NOOBJECT - + /WARNINGS = DISABLE = ('OPT_TEST', EMPTYFILE) NL: +$ IF ($SEVERITY) +$ THEN +$ IF CCDISABLEWARNINGS .NES. "" THEN - + CCDISABLEWARNINGS = CCDISABLEWARNINGS+ "," +$ CCDISABLEWARNINGS = CCDISABLEWARNINGS+ OPT_TEST +$ ENDIF +$ IF CCDISABLEWARNINGS .EQS. "" +$ THEN +$ CC4DISABLEWARNINGS = "DOLLARID" +$ ELSE +$ CC4DISABLEWARNINGS = CCDISABLEWARNINGS + ",DOLLARID" +$ CCDISABLEWARNINGS = " /WARNING=(DISABLE=(" + CCDISABLEWARNINGS + "))" +$ ENDIF +$ CC4DISABLEWARNINGS = " /WARNING=(DISABLE=(" + CC4DISABLEWARNINGS + "))" +$ ELSE +$ CCDISABLEWARNINGS = "" +$ CC4DISABLEWARNINGS = "" +$ ENDIF +$ CC2 = CC + " /DEFINE=(" + CCDEFS + ",_POSIX_C_SOURCE)" + CCDISABLEWARNINGS +$ CC3 = CC + " /DEFINE=(" + CCDEFS + ISSEVEN + ")" + CCDISABLEWARNINGS +$ CC = CC + " /DEFINE=(" + CCDEFS + ")" + CCDISABLEWARNINGS +$ IF COMPILER .EQS. "DECC" +$ THEN +$ CC4 = CC - CCDISABLEWARNINGS + CC4DISABLEWARNINGS +$ CC5 = CC3 - CCDISABLEWARNINGS + CC4DISABLEWARNINGS +$ ELSE +$ CC4 = CC +$ CC5 = CC3 +$ ENDIF +$! +$! Show user the result +$! +$ WRITE/SYMBOL SYS$OUTPUT "Main Compiling Command: ",CC +$! +$! Else The User Entered An Invalid Argument. +$! +$ ELSE +$! +$! Tell The User We Don't Know What They Want. +$! +$ WRITE SYS$OUTPUT "" +$ WRITE SYS$OUTPUT "The Option ",P3," Is Invalid. The Valid Options Are:" +$ WRITE SYS$OUTPUT "" +$ WRITE SYS$OUTPUT " VAXC : To Compile With VAX C." +$ WRITE SYS$OUTPUT " DECC : To Compile With DEC C." +$ WRITE SYS$OUTPUT " GNUC : To Compile With GNU C." +$ WRITE SYS$OUTPUT "" +$! +$! Time To EXIT. +$! +$ EXIT +$ ENDIF +$! +$! Time to check the contents, and to make sure we get the correct library. +$! +$ IF P4.EQS."SOCKETSHR" .OR. P4.EQS."MULTINET" .OR. P4.EQS."UCX" - + .OR. P4.EQS."TCPIP" .OR. P4.EQS."NONE" +$ THEN +$! +$! Check to see if SOCKETSHR was chosen +$! +$ IF P4.EQS."SOCKETSHR" +$ THEN +$! +$! Set the library to use SOCKETSHR +$! +$ TCPIP_LIB = ",SYS$DISK:[-.VMS]SOCKETSHR_SHR.OPT /OPTIONS" +$! +$! Done with SOCKETSHR +$! +$ ENDIF +$! +$! Check to see if MULTINET was chosen +$! +$ IF P4.EQS."MULTINET" +$ THEN +$! +$! Set the library to use UCX emulation. +$! +$ P4 = "UCX" +$! +$! Done with MULTINET +$! +$ ENDIF +$! +$! Check to see if UCX was chosen +$! +$ IF P4.EQS."UCX" +$ THEN +$! +$! Set the library to use UCX. +$! +$ TCPIP_LIB = ",SYS$DISK:[-.VMS]UCX_SHR_DECC.OPT /OPTIONS" +$ IF F$TRNLNM("UCX$IPC_SHR") .NES. "" +$ THEN +$ TCPIP_LIB = ",SYS$DISK:[-.VMS]UCX_SHR_DECC_LOG.OPT /OPTIONS" +$ ELSE +$ IF COMPILER .NES. "DECC" .AND. ARCH .EQS. "VAX" THEN - + TCPIP_LIB = ",SYS$DISK:[-.VMS]UCX_SHR_VAXC.OPT /OPTIONS" +$ ENDIF +$! +$! Done with UCX +$! +$ ENDIF +$! +$! Check to see if TCPIP was chosen +$! +$ IF P4.EQS."TCPIP" +$ THEN +$! +$! Set the library to use TCPIP (post UCX). +$! +$ TCPIP_LIB = ",SYS$DISK:[-.VMS]TCPIP_SHR_DECC.OPT /OPTIONS" +$! +$! Done with TCPIP +$! +$ ENDIF +$! +$! Check to see if NONE was chosen +$! +$ IF P4.EQS."NONE" +$ THEN +$! +$! Do not use a TCPIP library. +$! +$ TCPIP_LIB = "" +$! +$! Done with NONE +$! +$ ENDIF +$! +$! Print info +$! +$ WRITE SYS$OUTPUT "TCP/IP library spec: ", TCPIP_LIB- "," +$! +$! Else The User Entered An Invalid Argument. +$! +$ ELSE +$! +$! Tell The User We Don't Know What They Want. +$! +$ WRITE SYS$OUTPUT "" +$ WRITE SYS$OUTPUT "The Option ",P4," Is Invalid. The Valid Options Are:" +$ WRITE SYS$OUTPUT "" +$ WRITE SYS$OUTPUT " SOCKETSHR : To link with SOCKETSHR TCP/IP library." +$ WRITE SYS$OUTPUT " UCX : To link with UCX TCP/IP library." +$ WRITE SYS$OUTPUT " TCPIP : To link with TCPIP (post UCX) TCP/IP library." +$ WRITE SYS$OUTPUT "" +$! +$! Time To EXIT. +$! +$ EXIT +$! +$! Done with TCP/IP libraries +$! +$ ENDIF +$! +$! Time To RETURN... +$! +$ RETURN +$! +$ INITIALISE: +$! +$! Save old value of the logical name OPENSSL +$! +$ __SAVE_OPENSSL = F$TRNLNM("OPENSSL","LNM$PROCESS_TABLE") +$! +$! Save directory information +$! +$ __HERE = F$PARSE(F$PARSE("A.;",F$ENVIRONMENT("PROCEDURE"))-"A.;","[]A.;") - "A.;" +$ __HERE = F$EDIT(__HERE,"UPCASE") +$ __TOP = __HERE - "SSL]" +$ __INCLUDE = __TOP + "INCLUDE.OPENSSL]" +$! +$! Set up the logical name OPENSSL to point at the include directory +$! +$ DEFINE OPENSSL/NOLOG '__INCLUDE' +$! +$! Done +$! +$ RETURN +$! +$ CLEANUP: +$! +$! Restore the logical name OPENSSL if it had a value +$! +$ IF __SAVE_OPENSSL .EQS. "" +$ THEN +$ DEASSIGN OPENSSL +$ ELSE +$ DEFINE/NOLOG OPENSSL '__SAVE_OPENSSL' +$ ENDIF +$! +$! Done +$! +$ RETURN diff --git a/thirdparty/openssl/ssl/ssl_algs.c b/thirdparty/openssl/ssl/ssl_algs.c new file mode 100644 index 0000000000..e6f515ff62 --- /dev/null +++ b/thirdparty/openssl/ssl/ssl_algs.c @@ -0,0 +1,155 @@ +/* ssl/ssl_algs.c */ +/* 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.] + */ + +#include <stdio.h> +#include <openssl/objects.h> +#include <openssl/lhash.h> +#include "ssl_locl.h" + +int SSL_library_init(void) +{ + +#ifndef OPENSSL_NO_DES + EVP_add_cipher(EVP_des_cbc()); + EVP_add_cipher(EVP_des_ede3_cbc()); +#endif +#ifndef OPENSSL_NO_IDEA + EVP_add_cipher(EVP_idea_cbc()); +#endif +#ifndef OPENSSL_NO_RC4 + EVP_add_cipher(EVP_rc4()); +# if !defined(OPENSSL_NO_MD5) && (defined(__x86_64) || defined(__x86_64__)) + EVP_add_cipher(EVP_rc4_hmac_md5()); +# endif +#endif +#ifndef OPENSSL_NO_RC2 + EVP_add_cipher(EVP_rc2_cbc()); + /* + * Not actually used for SSL/TLS but this makes PKCS#12 work if an + * application only calls SSL_library_init(). + */ + EVP_add_cipher(EVP_rc2_40_cbc()); +#endif +#ifndef OPENSSL_NO_AES + EVP_add_cipher(EVP_aes_128_cbc()); + EVP_add_cipher(EVP_aes_192_cbc()); + EVP_add_cipher(EVP_aes_256_cbc()); + EVP_add_cipher(EVP_aes_128_gcm()); + EVP_add_cipher(EVP_aes_256_gcm()); +# if !defined(OPENSSL_NO_SHA) && !defined(OPENSSL_NO_SHA1) + EVP_add_cipher(EVP_aes_128_cbc_hmac_sha1()); + EVP_add_cipher(EVP_aes_256_cbc_hmac_sha1()); +# endif +# if !defined(OPENSSL_NO_SHA) && !defined(OPENSSL_NO_SHA256) + EVP_add_cipher(EVP_aes_128_cbc_hmac_sha256()); + EVP_add_cipher(EVP_aes_256_cbc_hmac_sha256()); +# endif + +#endif +#ifndef OPENSSL_NO_CAMELLIA + EVP_add_cipher(EVP_camellia_128_cbc()); + EVP_add_cipher(EVP_camellia_256_cbc()); +#endif + +#ifndef OPENSSL_NO_SEED + EVP_add_cipher(EVP_seed_cbc()); +#endif + +#ifndef OPENSSL_NO_MD5 + EVP_add_digest(EVP_md5()); + EVP_add_digest_alias(SN_md5, "ssl2-md5"); + EVP_add_digest_alias(SN_md5, "ssl3-md5"); +#endif +#ifndef OPENSSL_NO_SHA + EVP_add_digest(EVP_sha1()); /* RSA with sha1 */ + EVP_add_digest_alias(SN_sha1, "ssl3-sha1"); + EVP_add_digest_alias(SN_sha1WithRSAEncryption, SN_sha1WithRSA); +#endif +#ifndef OPENSSL_NO_SHA256 + EVP_add_digest(EVP_sha224()); + EVP_add_digest(EVP_sha256()); +#endif +#ifndef OPENSSL_NO_SHA512 + EVP_add_digest(EVP_sha384()); + EVP_add_digest(EVP_sha512()); +#endif +#if !defined(OPENSSL_NO_SHA) && !defined(OPENSSL_NO_DSA) + EVP_add_digest(EVP_dss1()); /* DSA with sha1 */ + EVP_add_digest_alias(SN_dsaWithSHA1, SN_dsaWithSHA1_2); + EVP_add_digest_alias(SN_dsaWithSHA1, "DSS1"); + EVP_add_digest_alias(SN_dsaWithSHA1, "dss1"); +#endif +#ifndef OPENSSL_NO_ECDSA + EVP_add_digest(EVP_ecdsa()); +#endif + /* If you want support for phased out ciphers, add the following */ +#if 0 + EVP_add_digest(EVP_sha()); + EVP_add_digest(EVP_dss()); +#endif +#ifndef OPENSSL_NO_COMP + /* + * This will initialise the built-in compression algorithms. The value + * returned is a STACK_OF(SSL_COMP), but that can be discarded safely + */ + (void)SSL_COMP_get_compression_methods(); +#endif + /* initialize cipher/digest methods table */ + ssl_load_ciphers(); + return (1); +} diff --git a/thirdparty/openssl/ssl/ssl_asn1.c b/thirdparty/openssl/ssl/ssl_asn1.c new file mode 100644 index 0000000000..35cc27c5e9 --- /dev/null +++ b/thirdparty/openssl/ssl/ssl_asn1.c @@ -0,0 +1,636 @@ +/* ssl/ssl_asn1.c */ +/* 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 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 <stdio.h> +#include <stdlib.h> +#include "ssl_locl.h" +#include <openssl/asn1_mac.h> +#include <openssl/objects.h> +#include <openssl/x509.h> + +typedef struct ssl_session_asn1_st { + ASN1_INTEGER version; + ASN1_INTEGER ssl_version; + ASN1_OCTET_STRING cipher; + ASN1_OCTET_STRING comp_id; + ASN1_OCTET_STRING master_key; + ASN1_OCTET_STRING session_id; + ASN1_OCTET_STRING session_id_context; + ASN1_OCTET_STRING key_arg; +#ifndef OPENSSL_NO_KRB5 + ASN1_OCTET_STRING krb5_princ; +#endif /* OPENSSL_NO_KRB5 */ + ASN1_INTEGER time; + ASN1_INTEGER timeout; + ASN1_INTEGER verify_result; +#ifndef OPENSSL_NO_TLSEXT + ASN1_OCTET_STRING tlsext_hostname; + ASN1_INTEGER tlsext_tick_lifetime; + ASN1_OCTET_STRING tlsext_tick; +#endif /* OPENSSL_NO_TLSEXT */ +#ifndef OPENSSL_NO_PSK + ASN1_OCTET_STRING psk_identity_hint; + ASN1_OCTET_STRING psk_identity; +#endif /* OPENSSL_NO_PSK */ +#ifndef OPENSSL_NO_SRP + ASN1_OCTET_STRING srp_username; +#endif /* OPENSSL_NO_SRP */ +} SSL_SESSION_ASN1; + +int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp) +{ +#define LSIZE2 (sizeof(long)*2) + int v1 = 0, v2 = 0, v3 = 0, v4 = 0, v5 = 0; + unsigned char buf[4], ibuf1[LSIZE2], ibuf2[LSIZE2]; + unsigned char ibuf3[LSIZE2], ibuf4[LSIZE2], ibuf5[LSIZE2]; +#ifndef OPENSSL_NO_TLSEXT + int v6 = 0, v9 = 0, v10 = 0; + unsigned char ibuf6[LSIZE2]; +#endif +#ifndef OPENSSL_NO_PSK + int v7 = 0, v8 = 0; +#endif +#ifndef OPENSSL_NO_COMP + unsigned char cbuf; + int v11 = 0; +#endif +#ifndef OPENSSL_NO_SRP + int v12 = 0; +#endif + long l; + SSL_SESSION_ASN1 a; + M_ASN1_I2D_vars(in); + + if ((in == NULL) || ((in->cipher == NULL) && (in->cipher_id == 0))) + return (0); + + /* + * Note that I cheat in the following 2 assignments. I know that if the + * ASN1_INTEGER passed to ASN1_INTEGER_set is > sizeof(long)+1, the + * buffer will not be re-OPENSSL_malloc()ed. This is a bit evil but makes + * things simple, no dynamic allocation to clean up :-) + */ + a.version.length = LSIZE2; + a.version.type = V_ASN1_INTEGER; + a.version.data = ibuf1; + ASN1_INTEGER_set(&(a.version), SSL_SESSION_ASN1_VERSION); + + a.ssl_version.length = LSIZE2; + a.ssl_version.type = V_ASN1_INTEGER; + a.ssl_version.data = ibuf2; + ASN1_INTEGER_set(&(a.ssl_version), in->ssl_version); + + a.cipher.type = V_ASN1_OCTET_STRING; + a.cipher.data = buf; + + if (in->cipher == NULL) + l = in->cipher_id; + else + l = in->cipher->id; + if (in->ssl_version == SSL2_VERSION) { + a.cipher.length = 3; + buf[0] = ((unsigned char)(l >> 16L)) & 0xff; + buf[1] = ((unsigned char)(l >> 8L)) & 0xff; + buf[2] = ((unsigned char)(l)) & 0xff; + } else { + a.cipher.length = 2; + buf[0] = ((unsigned char)(l >> 8L)) & 0xff; + buf[1] = ((unsigned char)(l)) & 0xff; + } + +#ifndef OPENSSL_NO_COMP + if (in->compress_meth) { + cbuf = (unsigned char)in->compress_meth; + a.comp_id.length = 1; + a.comp_id.type = V_ASN1_OCTET_STRING; + a.comp_id.data = &cbuf; + } +#endif + + a.master_key.length = in->master_key_length; + a.master_key.type = V_ASN1_OCTET_STRING; + a.master_key.data = in->master_key; + + a.session_id.length = in->session_id_length; + a.session_id.type = V_ASN1_OCTET_STRING; + a.session_id.data = in->session_id; + + a.session_id_context.length = in->sid_ctx_length; + a.session_id_context.type = V_ASN1_OCTET_STRING; + a.session_id_context.data = in->sid_ctx; + + a.key_arg.length = in->key_arg_length; + a.key_arg.type = V_ASN1_OCTET_STRING; + a.key_arg.data = in->key_arg; + +#ifndef OPENSSL_NO_KRB5 + if (in->krb5_client_princ_len) { + a.krb5_princ.length = in->krb5_client_princ_len; + a.krb5_princ.type = V_ASN1_OCTET_STRING; + a.krb5_princ.data = in->krb5_client_princ; + } +#endif /* OPENSSL_NO_KRB5 */ + + if (in->time != 0L) { + a.time.length = LSIZE2; + a.time.type = V_ASN1_INTEGER; + a.time.data = ibuf3; + ASN1_INTEGER_set(&(a.time), in->time); + } + + if (in->timeout != 0L) { + a.timeout.length = LSIZE2; + a.timeout.type = V_ASN1_INTEGER; + a.timeout.data = ibuf4; + ASN1_INTEGER_set(&(a.timeout), in->timeout); + } + + if (in->verify_result != X509_V_OK) { + a.verify_result.length = LSIZE2; + a.verify_result.type = V_ASN1_INTEGER; + a.verify_result.data = ibuf5; + ASN1_INTEGER_set(&a.verify_result, in->verify_result); + } +#ifndef OPENSSL_NO_TLSEXT + if (in->tlsext_hostname) { + a.tlsext_hostname.length = strlen(in->tlsext_hostname); + a.tlsext_hostname.type = V_ASN1_OCTET_STRING; + a.tlsext_hostname.data = (unsigned char *)in->tlsext_hostname; + } + if (in->tlsext_tick) { + a.tlsext_tick.length = in->tlsext_ticklen; + a.tlsext_tick.type = V_ASN1_OCTET_STRING; + a.tlsext_tick.data = (unsigned char *)in->tlsext_tick; + } + if (in->tlsext_tick_lifetime_hint > 0) { + a.tlsext_tick_lifetime.length = LSIZE2; + a.tlsext_tick_lifetime.type = V_ASN1_INTEGER; + a.tlsext_tick_lifetime.data = ibuf6; + ASN1_INTEGER_set(&a.tlsext_tick_lifetime, + in->tlsext_tick_lifetime_hint); + } +#endif /* OPENSSL_NO_TLSEXT */ +#ifndef OPENSSL_NO_PSK + if (in->psk_identity_hint) { + a.psk_identity_hint.length = strlen(in->psk_identity_hint); + a.psk_identity_hint.type = V_ASN1_OCTET_STRING; + a.psk_identity_hint.data = (unsigned char *)(in->psk_identity_hint); + } + if (in->psk_identity) { + a.psk_identity.length = strlen(in->psk_identity); + a.psk_identity.type = V_ASN1_OCTET_STRING; + a.psk_identity.data = (unsigned char *)(in->psk_identity); + } +#endif /* OPENSSL_NO_PSK */ +#ifndef OPENSSL_NO_SRP + if (in->srp_username) { + a.srp_username.length = strlen(in->srp_username); + a.srp_username.type = V_ASN1_OCTET_STRING; + a.srp_username.data = (unsigned char *)(in->srp_username); + } +#endif /* OPENSSL_NO_SRP */ + + M_ASN1_I2D_len(&(a.version), i2d_ASN1_INTEGER); + M_ASN1_I2D_len(&(a.ssl_version), i2d_ASN1_INTEGER); + M_ASN1_I2D_len(&(a.cipher), i2d_ASN1_OCTET_STRING); + M_ASN1_I2D_len(&(a.session_id), i2d_ASN1_OCTET_STRING); + M_ASN1_I2D_len(&(a.master_key), i2d_ASN1_OCTET_STRING); +#ifndef OPENSSL_NO_KRB5 + if (in->krb5_client_princ_len) + M_ASN1_I2D_len(&(a.krb5_princ), i2d_ASN1_OCTET_STRING); +#endif /* OPENSSL_NO_KRB5 */ + if (in->key_arg_length > 0) + M_ASN1_I2D_len_IMP_opt(&(a.key_arg), i2d_ASN1_OCTET_STRING); + if (in->time != 0L) + M_ASN1_I2D_len_EXP_opt(&(a.time), i2d_ASN1_INTEGER, 1, v1); + if (in->timeout != 0L) + M_ASN1_I2D_len_EXP_opt(&(a.timeout), i2d_ASN1_INTEGER, 2, v2); + if (in->peer != NULL) + M_ASN1_I2D_len_EXP_opt(in->peer, i2d_X509, 3, v3); + M_ASN1_I2D_len_EXP_opt(&a.session_id_context, i2d_ASN1_OCTET_STRING, 4, + v4); + if (in->verify_result != X509_V_OK) + M_ASN1_I2D_len_EXP_opt(&(a.verify_result), i2d_ASN1_INTEGER, 5, v5); + +#ifndef OPENSSL_NO_TLSEXT + if (in->tlsext_tick_lifetime_hint > 0) + M_ASN1_I2D_len_EXP_opt(&a.tlsext_tick_lifetime, i2d_ASN1_INTEGER, 9, + v9); + if (in->tlsext_tick) + M_ASN1_I2D_len_EXP_opt(&(a.tlsext_tick), i2d_ASN1_OCTET_STRING, 10, + v10); + if (in->tlsext_hostname) + M_ASN1_I2D_len_EXP_opt(&(a.tlsext_hostname), i2d_ASN1_OCTET_STRING, 6, + v6); +# ifndef OPENSSL_NO_COMP + if (in->compress_meth) + M_ASN1_I2D_len_EXP_opt(&(a.comp_id), i2d_ASN1_OCTET_STRING, 11, v11); +# endif +#endif /* OPENSSL_NO_TLSEXT */ +#ifndef OPENSSL_NO_PSK + if (in->psk_identity_hint) + M_ASN1_I2D_len_EXP_opt(&(a.psk_identity_hint), i2d_ASN1_OCTET_STRING, + 7, v7); + if (in->psk_identity) + M_ASN1_I2D_len_EXP_opt(&(a.psk_identity), i2d_ASN1_OCTET_STRING, 8, + v8); +#endif /* OPENSSL_NO_PSK */ +#ifndef OPENSSL_NO_SRP + if (in->srp_username) + M_ASN1_I2D_len_EXP_opt(&(a.srp_username), i2d_ASN1_OCTET_STRING, 12, + v12); +#endif /* OPENSSL_NO_SRP */ + + M_ASN1_I2D_seq_total(); + + M_ASN1_I2D_put(&(a.version), i2d_ASN1_INTEGER); + M_ASN1_I2D_put(&(a.ssl_version), i2d_ASN1_INTEGER); + M_ASN1_I2D_put(&(a.cipher), i2d_ASN1_OCTET_STRING); + M_ASN1_I2D_put(&(a.session_id), i2d_ASN1_OCTET_STRING); + M_ASN1_I2D_put(&(a.master_key), i2d_ASN1_OCTET_STRING); +#ifndef OPENSSL_NO_KRB5 + if (in->krb5_client_princ_len) + M_ASN1_I2D_put(&(a.krb5_princ), i2d_ASN1_OCTET_STRING); +#endif /* OPENSSL_NO_KRB5 */ + if (in->key_arg_length > 0) + M_ASN1_I2D_put_IMP_opt(&(a.key_arg), i2d_ASN1_OCTET_STRING, 0); + if (in->time != 0L) + M_ASN1_I2D_put_EXP_opt(&(a.time), i2d_ASN1_INTEGER, 1, v1); + if (in->timeout != 0L) + M_ASN1_I2D_put_EXP_opt(&(a.timeout), i2d_ASN1_INTEGER, 2, v2); + if (in->peer != NULL) + M_ASN1_I2D_put_EXP_opt(in->peer, i2d_X509, 3, v3); + M_ASN1_I2D_put_EXP_opt(&a.session_id_context, i2d_ASN1_OCTET_STRING, 4, + v4); + if (in->verify_result != X509_V_OK) + M_ASN1_I2D_put_EXP_opt(&a.verify_result, i2d_ASN1_INTEGER, 5, v5); +#ifndef OPENSSL_NO_TLSEXT + if (in->tlsext_hostname) + M_ASN1_I2D_put_EXP_opt(&(a.tlsext_hostname), i2d_ASN1_OCTET_STRING, 6, + v6); +#endif /* OPENSSL_NO_TLSEXT */ +#ifndef OPENSSL_NO_PSK + if (in->psk_identity_hint) + M_ASN1_I2D_put_EXP_opt(&(a.psk_identity_hint), i2d_ASN1_OCTET_STRING, + 7, v7); + if (in->psk_identity) + M_ASN1_I2D_put_EXP_opt(&(a.psk_identity), i2d_ASN1_OCTET_STRING, 8, + v8); +#endif /* OPENSSL_NO_PSK */ +#ifndef OPENSSL_NO_TLSEXT + if (in->tlsext_tick_lifetime_hint > 0) + M_ASN1_I2D_put_EXP_opt(&a.tlsext_tick_lifetime, i2d_ASN1_INTEGER, 9, + v9); + if (in->tlsext_tick) + M_ASN1_I2D_put_EXP_opt(&(a.tlsext_tick), i2d_ASN1_OCTET_STRING, 10, + v10); +#endif /* OPENSSL_NO_TLSEXT */ +#ifndef OPENSSL_NO_COMP + if (in->compress_meth) + M_ASN1_I2D_put_EXP_opt(&(a.comp_id), i2d_ASN1_OCTET_STRING, 11, v11); +#endif +#ifndef OPENSSL_NO_SRP + if (in->srp_username) + M_ASN1_I2D_put_EXP_opt(&(a.srp_username), i2d_ASN1_OCTET_STRING, 12, + v12); +#endif /* OPENSSL_NO_SRP */ + M_ASN1_I2D_finish(); +} + +SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp, + long length) +{ + int ssl_version = 0, i; + long id; + ASN1_INTEGER ai, *aip; + ASN1_OCTET_STRING os, *osp; + M_ASN1_D2I_vars(a, SSL_SESSION *, SSL_SESSION_new); + + aip = &ai; + osp = &os; + + M_ASN1_D2I_Init(); + M_ASN1_D2I_start_sequence(); + + ai.data = NULL; + ai.length = 0; + M_ASN1_D2I_get_x(ASN1_INTEGER, aip, d2i_ASN1_INTEGER); + if (ai.data != NULL) { + OPENSSL_free(ai.data); + ai.data = NULL; + ai.length = 0; + } + + /* we don't care about the version right now :-) */ + M_ASN1_D2I_get_x(ASN1_INTEGER, aip, d2i_ASN1_INTEGER); + ssl_version = (int)ASN1_INTEGER_get(aip); + ret->ssl_version = ssl_version; + if (ai.data != NULL) { + OPENSSL_free(ai.data); + ai.data = NULL; + ai.length = 0; + } + + os.data = NULL; + os.length = 0; + M_ASN1_D2I_get_x(ASN1_OCTET_STRING, osp, d2i_ASN1_OCTET_STRING); + if (ssl_version == SSL2_VERSION) { + if (os.length != 3) { + c.error = SSL_R_CIPHER_CODE_WRONG_LENGTH; + c.line = __LINE__; + goto err; + } + id = 0x02000000L | + ((unsigned long)os.data[0] << 16L) | + ((unsigned long)os.data[1] << 8L) | (unsigned long)os.data[2]; + } else if ((ssl_version >> 8) == SSL3_VERSION_MAJOR + || (ssl_version >> 8) == DTLS1_VERSION_MAJOR + || ssl_version == DTLS1_BAD_VER) { + if (os.length != 2) { + c.error = SSL_R_CIPHER_CODE_WRONG_LENGTH; + c.line = __LINE__; + goto err; + } + id = 0x03000000L | + ((unsigned long)os.data[0] << 8L) | (unsigned long)os.data[1]; + } else { + c.error = SSL_R_UNKNOWN_SSL_VERSION; + c.line = __LINE__; + goto err; + } + + ret->cipher = NULL; + ret->cipher_id = id; + + M_ASN1_D2I_get_x(ASN1_OCTET_STRING, osp, d2i_ASN1_OCTET_STRING); + if ((ssl_version >> 8) >= SSL3_VERSION_MAJOR) + i = SSL3_MAX_SSL_SESSION_ID_LENGTH; + else /* if (ssl_version>>8 == SSL2_VERSION_MAJOR) */ + i = SSL2_MAX_SSL_SESSION_ID_LENGTH; + + if (os.length > i) + os.length = i; + if (os.length > (int)sizeof(ret->session_id)) /* can't happen */ + os.length = sizeof(ret->session_id); + + ret->session_id_length = os.length; + OPENSSL_assert(os.length <= (int)sizeof(ret->session_id)); + memcpy(ret->session_id, os.data, os.length); + + M_ASN1_D2I_get_x(ASN1_OCTET_STRING, osp, d2i_ASN1_OCTET_STRING); + if (os.length > SSL_MAX_MASTER_KEY_LENGTH) + ret->master_key_length = SSL_MAX_MASTER_KEY_LENGTH; + else + ret->master_key_length = os.length; + memcpy(ret->master_key, os.data, ret->master_key_length); + + os.length = 0; + +#ifndef OPENSSL_NO_KRB5 + os.length = 0; + M_ASN1_D2I_get_opt(osp, d2i_ASN1_OCTET_STRING, V_ASN1_OCTET_STRING); + if (os.data) { + if (os.length > SSL_MAX_KRB5_PRINCIPAL_LENGTH) + ret->krb5_client_princ_len = 0; + else + ret->krb5_client_princ_len = os.length; + memcpy(ret->krb5_client_princ, os.data, ret->krb5_client_princ_len); + OPENSSL_free(os.data); + os.data = NULL; + os.length = 0; + } else + ret->krb5_client_princ_len = 0; +#endif /* OPENSSL_NO_KRB5 */ + + M_ASN1_D2I_get_IMP_opt(osp, d2i_ASN1_OCTET_STRING, 0, + V_ASN1_OCTET_STRING); + if (os.length > SSL_MAX_KEY_ARG_LENGTH) + ret->key_arg_length = SSL_MAX_KEY_ARG_LENGTH; + else + ret->key_arg_length = os.length; + memcpy(ret->key_arg, os.data, ret->key_arg_length); + if (os.data != NULL) + OPENSSL_free(os.data); + + ai.length = 0; + M_ASN1_D2I_get_EXP_opt(aip, d2i_ASN1_INTEGER, 1); + if (ai.data != NULL) { + ret->time = ASN1_INTEGER_get(aip); + OPENSSL_free(ai.data); + ai.data = NULL; + ai.length = 0; + } else + ret->time = (unsigned long)time(NULL); + + ai.length = 0; + M_ASN1_D2I_get_EXP_opt(aip, d2i_ASN1_INTEGER, 2); + if (ai.data != NULL) { + ret->timeout = ASN1_INTEGER_get(aip); + OPENSSL_free(ai.data); + ai.data = NULL; + ai.length = 0; + } else + ret->timeout = 3; + + if (ret->peer != NULL) { + X509_free(ret->peer); + ret->peer = NULL; + } + M_ASN1_D2I_get_EXP_opt(ret->peer, d2i_X509, 3); + + os.length = 0; + os.data = NULL; + M_ASN1_D2I_get_EXP_opt(osp, d2i_ASN1_OCTET_STRING, 4); + + if (os.data != NULL) { + if (os.length > SSL_MAX_SID_CTX_LENGTH) { + c.error = SSL_R_BAD_LENGTH; + c.line = __LINE__; + goto err; + } else { + ret->sid_ctx_length = os.length; + memcpy(ret->sid_ctx, os.data, os.length); + } + OPENSSL_free(os.data); + os.data = NULL; + os.length = 0; + } else + ret->sid_ctx_length = 0; + + ai.length = 0; + M_ASN1_D2I_get_EXP_opt(aip, d2i_ASN1_INTEGER, 5); + if (ai.data != NULL) { + ret->verify_result = ASN1_INTEGER_get(aip); + OPENSSL_free(ai.data); + ai.data = NULL; + ai.length = 0; + } else + ret->verify_result = X509_V_OK; + +#ifndef OPENSSL_NO_TLSEXT + os.length = 0; + os.data = NULL; + M_ASN1_D2I_get_EXP_opt(osp, d2i_ASN1_OCTET_STRING, 6); + if (os.data) { + ret->tlsext_hostname = BUF_strndup((char *)os.data, os.length); + OPENSSL_free(os.data); + os.data = NULL; + os.length = 0; + } else + ret->tlsext_hostname = NULL; +#endif /* OPENSSL_NO_TLSEXT */ + +#ifndef OPENSSL_NO_PSK + os.length = 0; + os.data = NULL; + M_ASN1_D2I_get_EXP_opt(osp, d2i_ASN1_OCTET_STRING, 7); + if (os.data) { + ret->psk_identity_hint = BUF_strndup((char *)os.data, os.length); + OPENSSL_free(os.data); + os.data = NULL; + os.length = 0; + } else + ret->psk_identity_hint = NULL; + + os.length = 0; + os.data = NULL; + M_ASN1_D2I_get_EXP_opt(osp, d2i_ASN1_OCTET_STRING, 8); + if (os.data) { + ret->psk_identity = BUF_strndup((char *)os.data, os.length); + OPENSSL_free(os.data); + os.data = NULL; + os.length = 0; + } else + ret->psk_identity = NULL; +#endif /* OPENSSL_NO_PSK */ + +#ifndef OPENSSL_NO_TLSEXT + ai.length = 0; + M_ASN1_D2I_get_EXP_opt(aip, d2i_ASN1_INTEGER, 9); + if (ai.data != NULL) { + ret->tlsext_tick_lifetime_hint = ASN1_INTEGER_get(aip); + OPENSSL_free(ai.data); + ai.data = NULL; + ai.length = 0; + } else if (ret->tlsext_ticklen && ret->session_id_length) + ret->tlsext_tick_lifetime_hint = -1; + else + ret->tlsext_tick_lifetime_hint = 0; + os.length = 0; + os.data = NULL; + M_ASN1_D2I_get_EXP_opt(osp, d2i_ASN1_OCTET_STRING, 10); + if (os.data) { + ret->tlsext_tick = os.data; + ret->tlsext_ticklen = os.length; + os.data = NULL; + os.length = 0; + } else + ret->tlsext_tick = NULL; +#endif /* OPENSSL_NO_TLSEXT */ +#ifndef OPENSSL_NO_COMP + os.length = 0; + os.data = NULL; + M_ASN1_D2I_get_EXP_opt(osp, d2i_ASN1_OCTET_STRING, 11); + if (os.data) { + ret->compress_meth = os.data[0]; + OPENSSL_free(os.data); + os.data = NULL; + } +#endif + +#ifndef OPENSSL_NO_SRP + os.length = 0; + os.data = NULL; + M_ASN1_D2I_get_EXP_opt(osp, d2i_ASN1_OCTET_STRING, 12); + if (os.data) { + ret->srp_username = BUF_strndup((char *)os.data, os.length); + OPENSSL_free(os.data); + os.data = NULL; + os.length = 0; + } else + ret->srp_username = NULL; +#endif /* OPENSSL_NO_SRP */ + + M_ASN1_D2I_Finish(a, SSL_SESSION_free, SSL_F_D2I_SSL_SESSION); +} diff --git a/thirdparty/openssl/ssl/ssl_cert.c b/thirdparty/openssl/ssl/ssl_cert.c new file mode 100644 index 0000000000..f48ebaecc0 --- /dev/null +++ b/thirdparty/openssl/ssl/ssl_cert.c @@ -0,0 +1,1264 @@ +/* + * ! \file ssl/ssl_cert.c + */ +/* 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. + * ECC cipher suite support in OpenSSL originally developed by + * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. + */ + +#include <stdio.h> + +#include "e_os.h" +#ifndef NO_SYS_TYPES_H +# include <sys/types.h> +#endif + +#include "o_dir.h" +#include <openssl/objects.h> +#include <openssl/bio.h> +#include <openssl/pem.h> +#include <openssl/x509v3.h> +#ifndef OPENSSL_NO_DH +# include <openssl/dh.h> +#endif +#include <openssl/bn.h> +#include "ssl_locl.h" + +int SSL_get_ex_data_X509_STORE_CTX_idx(void) +{ + static volatile int ssl_x509_store_ctx_idx = -1; + int got_write_lock = 0; + + if (((size_t)&ssl_x509_store_ctx_idx & + (sizeof(ssl_x509_store_ctx_idx) - 1)) + == 0) { /* check alignment, practically always true */ + int ret; + + if ((ret = ssl_x509_store_ctx_idx) < 0) { + CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); + if ((ret = ssl_x509_store_ctx_idx) < 0) { + ret = ssl_x509_store_ctx_idx = + X509_STORE_CTX_get_ex_new_index(0, + "SSL for verify callback", + NULL, NULL, NULL); + } + CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); + } + + return ret; + } else { /* commonly eliminated */ + + CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX); + + if (ssl_x509_store_ctx_idx < 0) { + CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); + CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); + got_write_lock = 1; + + if (ssl_x509_store_ctx_idx < 0) { + ssl_x509_store_ctx_idx = + X509_STORE_CTX_get_ex_new_index(0, + "SSL for verify callback", + NULL, NULL, NULL); + } + } + + if (got_write_lock) + CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); + else + CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); + + return ssl_x509_store_ctx_idx; + } +} + +void ssl_cert_set_default_md(CERT *cert) +{ + /* Set digest values to defaults */ +#ifndef OPENSSL_NO_DSA + cert->pkeys[SSL_PKEY_DSA_SIGN].digest = EVP_sha1(); +#endif +#ifndef OPENSSL_NO_RSA + cert->pkeys[SSL_PKEY_RSA_SIGN].digest = EVP_sha1(); + cert->pkeys[SSL_PKEY_RSA_ENC].digest = EVP_sha1(); +#endif +#ifndef OPENSSL_NO_ECDSA + cert->pkeys[SSL_PKEY_ECC].digest = EVP_sha1(); +#endif +} + +CERT *ssl_cert_new(void) +{ + CERT *ret; + + ret = (CERT *)OPENSSL_malloc(sizeof(CERT)); + if (ret == NULL) { + SSLerr(SSL_F_SSL_CERT_NEW, ERR_R_MALLOC_FAILURE); + return (NULL); + } + memset(ret, 0, sizeof(CERT)); + + ret->key = &(ret->pkeys[SSL_PKEY_RSA_ENC]); + ret->references = 1; + ssl_cert_set_default_md(ret); + return (ret); +} + +CERT *ssl_cert_dup(CERT *cert) +{ + CERT *ret; + int i; + + ret = (CERT *)OPENSSL_malloc(sizeof(CERT)); + if (ret == NULL) { + SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_MALLOC_FAILURE); + return (NULL); + } + + memset(ret, 0, sizeof(CERT)); + + ret->references = 1; + ret->key = &ret->pkeys[cert->key - &cert->pkeys[0]]; + /* + * or ret->key = ret->pkeys + (cert->key - cert->pkeys), if you find that + * more readable + */ + + ret->valid = cert->valid; + ret->mask_k = cert->mask_k; + ret->mask_a = cert->mask_a; + ret->export_mask_k = cert->export_mask_k; + ret->export_mask_a = cert->export_mask_a; + +#ifndef OPENSSL_NO_RSA + if (cert->rsa_tmp != NULL) { + RSA_up_ref(cert->rsa_tmp); + ret->rsa_tmp = cert->rsa_tmp; + } + ret->rsa_tmp_cb = cert->rsa_tmp_cb; +#endif + +#ifndef OPENSSL_NO_DH + if (cert->dh_tmp != NULL) { + ret->dh_tmp = DHparams_dup(cert->dh_tmp); + if (ret->dh_tmp == NULL) { + SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_DH_LIB); + goto err; + } + if (cert->dh_tmp->priv_key) { + BIGNUM *b = BN_dup(cert->dh_tmp->priv_key); + if (!b) { + SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_BN_LIB); + goto err; + } + ret->dh_tmp->priv_key = b; + } + if (cert->dh_tmp->pub_key) { + BIGNUM *b = BN_dup(cert->dh_tmp->pub_key); + if (!b) { + SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_BN_LIB); + goto err; + } + ret->dh_tmp->pub_key = b; + } + } + ret->dh_tmp_cb = cert->dh_tmp_cb; +#endif + +#ifndef OPENSSL_NO_ECDH + if (cert->ecdh_tmp) { + ret->ecdh_tmp = EC_KEY_dup(cert->ecdh_tmp); + if (ret->ecdh_tmp == NULL) { + SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_EC_LIB); + goto err; + } + } + ret->ecdh_tmp_cb = cert->ecdh_tmp_cb; + ret->ecdh_tmp_auto = cert->ecdh_tmp_auto; +#endif + + for (i = 0; i < SSL_PKEY_NUM; i++) { + CERT_PKEY *cpk = cert->pkeys + i; + CERT_PKEY *rpk = ret->pkeys + i; + if (cpk->x509 != NULL) { + rpk->x509 = cpk->x509; + CRYPTO_add(&rpk->x509->references, 1, CRYPTO_LOCK_X509); + } + + if (cpk->privatekey != NULL) { + rpk->privatekey = cpk->privatekey; + CRYPTO_add(&cpk->privatekey->references, 1, CRYPTO_LOCK_EVP_PKEY); + } + + if (cpk->chain) { + rpk->chain = X509_chain_up_ref(cpk->chain); + if (!rpk->chain) { + SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_MALLOC_FAILURE); + goto err; + } + } + rpk->valid_flags = 0; +#ifndef OPENSSL_NO_TLSEXT + if (cert->pkeys[i].serverinfo != NULL) { + /* Just copy everything. */ + ret->pkeys[i].serverinfo = + OPENSSL_malloc(cert->pkeys[i].serverinfo_length); + if (ret->pkeys[i].serverinfo == NULL) { + SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_MALLOC_FAILURE); + return NULL; + } + ret->pkeys[i].serverinfo_length = + cert->pkeys[i].serverinfo_length; + memcpy(ret->pkeys[i].serverinfo, + cert->pkeys[i].serverinfo, + cert->pkeys[i].serverinfo_length); + } +#endif + } + + /* + * Set digests to defaults. NB: we don't copy existing values as they + * will be set during handshake. + */ + ssl_cert_set_default_md(ret); + /* Peer sigalgs set to NULL as we get these from handshake too */ + ret->peer_sigalgs = NULL; + ret->peer_sigalgslen = 0; + /* Configured sigalgs however we copy across */ + + if (cert->conf_sigalgs) { + ret->conf_sigalgs = OPENSSL_malloc(cert->conf_sigalgslen); + if (!ret->conf_sigalgs) + goto err; + memcpy(ret->conf_sigalgs, cert->conf_sigalgs, cert->conf_sigalgslen); + ret->conf_sigalgslen = cert->conf_sigalgslen; + } else + ret->conf_sigalgs = NULL; + + if (cert->client_sigalgs) { + ret->client_sigalgs = OPENSSL_malloc(cert->client_sigalgslen); + if (!ret->client_sigalgs) + goto err; + memcpy(ret->client_sigalgs, cert->client_sigalgs, + cert->client_sigalgslen); + ret->client_sigalgslen = cert->client_sigalgslen; + } else + ret->client_sigalgs = NULL; + /* Shared sigalgs also NULL */ + ret->shared_sigalgs = NULL; + /* Copy any custom client certificate types */ + if (cert->ctypes) { + ret->ctypes = OPENSSL_malloc(cert->ctype_num); + if (!ret->ctypes) + goto err; + memcpy(ret->ctypes, cert->ctypes, cert->ctype_num); + ret->ctype_num = cert->ctype_num; + } + + ret->cert_flags = cert->cert_flags; + + ret->cert_cb = cert->cert_cb; + ret->cert_cb_arg = cert->cert_cb_arg; + + if (cert->verify_store) { + CRYPTO_add(&cert->verify_store->references, 1, + CRYPTO_LOCK_X509_STORE); + ret->verify_store = cert->verify_store; + } + + if (cert->chain_store) { + CRYPTO_add(&cert->chain_store->references, 1, CRYPTO_LOCK_X509_STORE); + ret->chain_store = cert->chain_store; + } + + ret->ciphers_raw = NULL; + +#ifndef OPENSSL_NO_TLSEXT + if (!custom_exts_copy(&ret->cli_ext, &cert->cli_ext)) + goto err; + if (!custom_exts_copy(&ret->srv_ext, &cert->srv_ext)) + goto err; +#endif + + return (ret); + +#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_ECDH) + err: +#endif +#ifndef OPENSSL_NO_RSA + if (ret->rsa_tmp != NULL) + RSA_free(ret->rsa_tmp); +#endif +#ifndef OPENSSL_NO_DH + if (ret->dh_tmp != NULL) + DH_free(ret->dh_tmp); +#endif +#ifndef OPENSSL_NO_ECDH + if (ret->ecdh_tmp != NULL) + EC_KEY_free(ret->ecdh_tmp); +#endif + +#ifndef OPENSSL_NO_TLSEXT + custom_exts_free(&ret->cli_ext); + custom_exts_free(&ret->srv_ext); +#endif + + ssl_cert_clear_certs(ret); + + return NULL; +} + +/* Free up and clear all certificates and chains */ + +void ssl_cert_clear_certs(CERT *c) +{ + int i; + if (c == NULL) + return; + for (i = 0; i < SSL_PKEY_NUM; i++) { + CERT_PKEY *cpk = c->pkeys + i; + if (cpk->x509) { + X509_free(cpk->x509); + cpk->x509 = NULL; + } + if (cpk->privatekey) { + EVP_PKEY_free(cpk->privatekey); + cpk->privatekey = NULL; + } + if (cpk->chain) { + sk_X509_pop_free(cpk->chain, X509_free); + cpk->chain = NULL; + } +#ifndef OPENSSL_NO_TLSEXT + if (cpk->serverinfo) { + OPENSSL_free(cpk->serverinfo); + cpk->serverinfo = NULL; + cpk->serverinfo_length = 0; + } +#endif + /* Clear all flags apart from explicit sign */ + cpk->valid_flags &= CERT_PKEY_EXPLICIT_SIGN; + } +} + +void ssl_cert_free(CERT *c) +{ + int i; + + if (c == NULL) + return; + + i = CRYPTO_add(&c->references, -1, CRYPTO_LOCK_SSL_CERT); +#ifdef REF_PRINT + REF_PRINT("CERT", c); +#endif + if (i > 0) + return; +#ifdef REF_CHECK + if (i < 0) { + fprintf(stderr, "ssl_cert_free, bad reference count\n"); + abort(); /* ok */ + } +#endif + +#ifndef OPENSSL_NO_RSA + if (c->rsa_tmp) + RSA_free(c->rsa_tmp); +#endif +#ifndef OPENSSL_NO_DH + if (c->dh_tmp) + DH_free(c->dh_tmp); +#endif +#ifndef OPENSSL_NO_ECDH + if (c->ecdh_tmp) + EC_KEY_free(c->ecdh_tmp); +#endif + + ssl_cert_clear_certs(c); + if (c->peer_sigalgs) + OPENSSL_free(c->peer_sigalgs); + if (c->conf_sigalgs) + OPENSSL_free(c->conf_sigalgs); + if (c->client_sigalgs) + OPENSSL_free(c->client_sigalgs); + if (c->shared_sigalgs) + OPENSSL_free(c->shared_sigalgs); + if (c->ctypes) + OPENSSL_free(c->ctypes); + if (c->verify_store) + X509_STORE_free(c->verify_store); + if (c->chain_store) + X509_STORE_free(c->chain_store); + if (c->ciphers_raw) + OPENSSL_free(c->ciphers_raw); +#ifndef OPENSSL_NO_TLSEXT + custom_exts_free(&c->cli_ext); + custom_exts_free(&c->srv_ext); + if (c->alpn_proposed) + OPENSSL_free(c->alpn_proposed); +#endif + OPENSSL_free(c); +} + +int ssl_cert_inst(CERT **o) +{ + /* + * Create a CERT if there isn't already one (which cannot really happen, + * as it is initially created in SSL_CTX_new; but the earlier code + * usually allows for that one being non-existant, so we follow that + * behaviour, as it might turn out that there actually is a reason for it + * -- but I'm not sure that *all* of the existing code could cope with + * s->cert being NULL, otherwise we could do without the initialization + * in SSL_CTX_new). + */ + + if (o == NULL) { + SSLerr(SSL_F_SSL_CERT_INST, ERR_R_PASSED_NULL_PARAMETER); + return (0); + } + if (*o == NULL) { + if ((*o = ssl_cert_new()) == NULL) { + SSLerr(SSL_F_SSL_CERT_INST, ERR_R_MALLOC_FAILURE); + return (0); + } + } + return (1); +} + +int ssl_cert_set0_chain(CERT *c, STACK_OF(X509) *chain) +{ + CERT_PKEY *cpk = c->key; + if (!cpk) + return 0; + if (cpk->chain) + sk_X509_pop_free(cpk->chain, X509_free); + cpk->chain = chain; + return 1; +} + +int ssl_cert_set1_chain(CERT *c, STACK_OF(X509) *chain) +{ + STACK_OF(X509) *dchain; + if (!chain) + return ssl_cert_set0_chain(c, NULL); + dchain = X509_chain_up_ref(chain); + if (!dchain) + return 0; + if (!ssl_cert_set0_chain(c, dchain)) { + sk_X509_pop_free(dchain, X509_free); + return 0; + } + return 1; +} + +int ssl_cert_add0_chain_cert(CERT *c, X509 *x) +{ + CERT_PKEY *cpk = c->key; + if (!cpk) + return 0; + if (!cpk->chain) + cpk->chain = sk_X509_new_null(); + if (!cpk->chain || !sk_X509_push(cpk->chain, x)) + return 0; + return 1; +} + +int ssl_cert_add1_chain_cert(CERT *c, X509 *x) +{ + if (!ssl_cert_add0_chain_cert(c, x)) + return 0; + CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); + return 1; +} + +int ssl_cert_select_current(CERT *c, X509 *x) +{ + int i; + if (x == NULL) + return 0; + for (i = 0; i < SSL_PKEY_NUM; i++) { + CERT_PKEY *cpk = c->pkeys + i; + if (cpk->x509 == x && cpk->privatekey) { + c->key = cpk; + return 1; + } + } + + for (i = 0; i < SSL_PKEY_NUM; i++) { + CERT_PKEY *cpk = c->pkeys + i; + if (cpk->privatekey && cpk->x509 && !X509_cmp(cpk->x509, x)) { + c->key = cpk; + return 1; + } + } + return 0; +} + +int ssl_cert_set_current(CERT *c, long op) +{ + int i, idx; + if (!c) + return 0; + if (op == SSL_CERT_SET_FIRST) + idx = 0; + else if (op == SSL_CERT_SET_NEXT) { + idx = (int)(c->key - c->pkeys + 1); + if (idx >= SSL_PKEY_NUM) + return 0; + } else + return 0; + for (i = idx; i < SSL_PKEY_NUM; i++) { + CERT_PKEY *cpk = c->pkeys + i; + if (cpk->x509 && cpk->privatekey) { + c->key = cpk; + return 1; + } + } + return 0; +} + +void ssl_cert_set_cert_cb(CERT *c, int (*cb) (SSL *ssl, void *arg), void *arg) +{ + c->cert_cb = cb; + c->cert_cb_arg = arg; +} + +SESS_CERT *ssl_sess_cert_new(void) +{ + SESS_CERT *ret; + + ret = OPENSSL_malloc(sizeof *ret); + if (ret == NULL) { + SSLerr(SSL_F_SSL_SESS_CERT_NEW, ERR_R_MALLOC_FAILURE); + return NULL; + } + + memset(ret, 0, sizeof *ret); + ret->peer_key = &(ret->peer_pkeys[SSL_PKEY_RSA_ENC]); + ret->references = 1; + + return ret; +} + +void ssl_sess_cert_free(SESS_CERT *sc) +{ + int i; + + if (sc == NULL) + return; + + i = CRYPTO_add(&sc->references, -1, CRYPTO_LOCK_SSL_SESS_CERT); +#ifdef REF_PRINT + REF_PRINT("SESS_CERT", sc); +#endif + if (i > 0) + return; +#ifdef REF_CHECK + if (i < 0) { + fprintf(stderr, "ssl_sess_cert_free, bad reference count\n"); + abort(); /* ok */ + } +#endif + + /* i == 0 */ + if (sc->cert_chain != NULL) + sk_X509_pop_free(sc->cert_chain, X509_free); + for (i = 0; i < SSL_PKEY_NUM; i++) { + if (sc->peer_pkeys[i].x509 != NULL) + X509_free(sc->peer_pkeys[i].x509); +#if 0 /* We don't have the peer's private key. + * These lines are just * here as a reminder + * that we're still using a + * not-quite-appropriate * data structure. */ + if (sc->peer_pkeys[i].privatekey != NULL) + EVP_PKEY_free(sc->peer_pkeys[i].privatekey); +#endif + } + +#ifndef OPENSSL_NO_RSA + if (sc->peer_rsa_tmp != NULL) + RSA_free(sc->peer_rsa_tmp); +#endif +#ifndef OPENSSL_NO_DH + if (sc->peer_dh_tmp != NULL) + DH_free(sc->peer_dh_tmp); +#endif +#ifndef OPENSSL_NO_ECDH + if (sc->peer_ecdh_tmp != NULL) + EC_KEY_free(sc->peer_ecdh_tmp); +#endif + + OPENSSL_free(sc); +} + +int ssl_set_peer_cert_type(SESS_CERT *sc, int type) +{ + sc->peer_cert_type = type; + return (1); +} + +int ssl_verify_cert_chain(SSL *s, STACK_OF(X509) *sk) +{ + X509 *x; + int i; + X509_STORE *verify_store; + X509_STORE_CTX ctx; + + if (s->cert->verify_store) + verify_store = s->cert->verify_store; + else + verify_store = s->ctx->cert_store; + + if ((sk == NULL) || (sk_X509_num(sk) == 0)) + return (0); + + x = sk_X509_value(sk, 0); + if (!X509_STORE_CTX_init(&ctx, verify_store, x, sk)) { + SSLerr(SSL_F_SSL_VERIFY_CERT_CHAIN, ERR_R_X509_LIB); + return (0); + } + /* Set suite B flags if needed */ + X509_STORE_CTX_set_flags(&ctx, tls1_suiteb(s)); +#if 0 + if (SSL_get_verify_depth(s) >= 0) + X509_STORE_CTX_set_depth(&ctx, SSL_get_verify_depth(s)); +#endif + X509_STORE_CTX_set_ex_data(&ctx, SSL_get_ex_data_X509_STORE_CTX_idx(), s); + + /* + * We need to inherit the verify parameters. These can be determined by + * the context: if its a server it will verify SSL client certificates or + * vice versa. + */ + + X509_STORE_CTX_set_default(&ctx, s->server ? "ssl_client" : "ssl_server"); + /* + * Anything non-default in "param" should overwrite anything in the ctx. + */ + X509_VERIFY_PARAM_set1(X509_STORE_CTX_get0_param(&ctx), s->param); + + if (s->verify_callback) + X509_STORE_CTX_set_verify_cb(&ctx, s->verify_callback); + + if (s->ctx->app_verify_callback != NULL) +#if 1 /* new with OpenSSL 0.9.7 */ + i = s->ctx->app_verify_callback(&ctx, s->ctx->app_verify_arg); +#else + i = s->ctx->app_verify_callback(&ctx); /* should pass app_verify_arg */ +#endif + else { +#ifndef OPENSSL_NO_X509_VERIFY + i = X509_verify_cert(&ctx); +#else + i = 0; + ctx.error = X509_V_ERR_APPLICATION_VERIFICATION; + SSLerr(SSL_F_SSL_VERIFY_CERT_CHAIN, SSL_R_NO_VERIFY_CALLBACK); +#endif + } + + s->verify_result = ctx.error; + X509_STORE_CTX_cleanup(&ctx); + + return (i); +} + +static void set_client_CA_list(STACK_OF(X509_NAME) **ca_list, + STACK_OF(X509_NAME) *name_list) +{ + if (*ca_list != NULL) + sk_X509_NAME_pop_free(*ca_list, X509_NAME_free); + + *ca_list = name_list; +} + +STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *sk) +{ + int i; + STACK_OF(X509_NAME) *ret; + X509_NAME *name; + + ret = sk_X509_NAME_new_null(); + for (i = 0; i < sk_X509_NAME_num(sk); i++) { + name = X509_NAME_dup(sk_X509_NAME_value(sk, i)); + if ((name == NULL) || !sk_X509_NAME_push(ret, name)) { + sk_X509_NAME_pop_free(ret, X509_NAME_free); + return (NULL); + } + } + return (ret); +} + +void SSL_set_client_CA_list(SSL *s, STACK_OF(X509_NAME) *name_list) +{ + set_client_CA_list(&(s->client_CA), name_list); +} + +void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, STACK_OF(X509_NAME) *name_list) +{ + set_client_CA_list(&(ctx->client_CA), name_list); +} + +STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(const SSL_CTX *ctx) +{ + return (ctx->client_CA); +} + +STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *s) +{ + if (s->type == SSL_ST_CONNECT) { /* we are in the client */ + if (((s->version >> 8) == SSL3_VERSION_MAJOR) && (s->s3 != NULL)) + return (s->s3->tmp.ca_names); + else + return (NULL); + } else { + if (s->client_CA != NULL) + return (s->client_CA); + else + return (s->ctx->client_CA); + } +} + +static int add_client_CA(STACK_OF(X509_NAME) **sk, X509 *x) +{ + X509_NAME *name; + + if (x == NULL) + return (0); + if ((*sk == NULL) && ((*sk = sk_X509_NAME_new_null()) == NULL)) + return (0); + + if ((name = X509_NAME_dup(X509_get_subject_name(x))) == NULL) + return (0); + + if (!sk_X509_NAME_push(*sk, name)) { + X509_NAME_free(name); + return (0); + } + return (1); +} + +int SSL_add_client_CA(SSL *ssl, X509 *x) +{ + return (add_client_CA(&(ssl->client_CA), x)); +} + +int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x) +{ + return (add_client_CA(&(ctx->client_CA), x)); +} + +static int xname_cmp(const X509_NAME *const *a, const X509_NAME *const *b) +{ + return (X509_NAME_cmp(*a, *b)); +} + +#ifndef OPENSSL_NO_STDIO +/** + * Load CA certs from a file into a ::STACK. Note that it is somewhat misnamed; + * it doesn't really have anything to do with clients (except that a common use + * for a stack of CAs is to send it to the client). Actually, it doesn't have + * much to do with CAs, either, since it will load any old cert. + * \param file the file containing one or more certs. + * \return a ::STACK containing the certs. + */ +STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file) +{ + BIO *in; + X509 *x = NULL; + X509_NAME *xn = NULL; + STACK_OF(X509_NAME) *ret = NULL, *sk; + + sk = sk_X509_NAME_new(xname_cmp); + + in = BIO_new(BIO_s_file_internal()); + + if ((sk == NULL) || (in == NULL)) { + SSLerr(SSL_F_SSL_LOAD_CLIENT_CA_FILE, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!BIO_read_filename(in, file)) + goto err; + + for (;;) { + if (PEM_read_bio_X509(in, &x, NULL, NULL) == NULL) + break; + if (ret == NULL) { + ret = sk_X509_NAME_new_null(); + if (ret == NULL) { + SSLerr(SSL_F_SSL_LOAD_CLIENT_CA_FILE, ERR_R_MALLOC_FAILURE); + goto err; + } + } + if ((xn = X509_get_subject_name(x)) == NULL) + goto err; + /* check for duplicates */ + xn = X509_NAME_dup(xn); + if (xn == NULL) + goto err; + if (sk_X509_NAME_find(sk, xn) >= 0) + X509_NAME_free(xn); + else { + sk_X509_NAME_push(sk, xn); + sk_X509_NAME_push(ret, xn); + } + } + + if (0) { + err: + if (ret != NULL) + sk_X509_NAME_pop_free(ret, X509_NAME_free); + ret = NULL; + } + if (sk != NULL) + sk_X509_NAME_free(sk); + if (in != NULL) + BIO_free(in); + if (x != NULL) + X509_free(x); + if (ret != NULL) + ERR_clear_error(); + return (ret); +} +#endif + +/** + * Add a file of certs to a stack. + * \param stack the stack to add to. + * \param file the file to add from. All certs in this file that are not + * already in the stack will be added. + * \return 1 for success, 0 for failure. Note that in the case of failure some + * certs may have been added to \c stack. + */ + +int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, + const char *file) +{ + BIO *in; + X509 *x = NULL; + X509_NAME *xn = NULL; + int ret = 1; + int (*oldcmp) (const X509_NAME *const *a, const X509_NAME *const *b); + + oldcmp = sk_X509_NAME_set_cmp_func(stack, xname_cmp); + + in = BIO_new(BIO_s_file_internal()); + + if (in == NULL) { + SSLerr(SSL_F_SSL_ADD_FILE_CERT_SUBJECTS_TO_STACK, + ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!BIO_read_filename(in, file)) + goto err; + + for (;;) { + if (PEM_read_bio_X509(in, &x, NULL, NULL) == NULL) + break; + if ((xn = X509_get_subject_name(x)) == NULL) + goto err; + xn = X509_NAME_dup(xn); + if (xn == NULL) + goto err; + if (sk_X509_NAME_find(stack, xn) >= 0) + X509_NAME_free(xn); + else + sk_X509_NAME_push(stack, xn); + } + + ERR_clear_error(); + + if (0) { + err: + ret = 0; + } + if (in != NULL) + BIO_free(in); + if (x != NULL) + X509_free(x); + + (void)sk_X509_NAME_set_cmp_func(stack, oldcmp); + + return ret; +} + +/** + * Add a directory of certs to a stack. + * \param stack the stack to append to. + * \param dir the directory to append from. All files in this directory will be + * examined as potential certs. Any that are acceptable to + * SSL_add_dir_cert_subjects_to_stack() that are not already in the stack will be + * included. + * \return 1 for success, 0 for failure. Note that in the case of failure some + * certs may have been added to \c stack. + */ + +int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, + const char *dir) +{ + OPENSSL_DIR_CTX *d = NULL; + const char *filename; + int ret = 0; + + CRYPTO_w_lock(CRYPTO_LOCK_READDIR); + + /* Note that a side effect is that the CAs will be sorted by name */ + + while ((filename = OPENSSL_DIR_read(&d, dir))) { + char buf[1024]; + int r; + + if (strlen(dir) + strlen(filename) + 2 > sizeof buf) { + SSLerr(SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK, + SSL_R_PATH_TOO_LONG); + goto err; + } +#ifdef OPENSSL_SYS_VMS + r = BIO_snprintf(buf, sizeof buf, "%s%s", dir, filename); +#else + r = BIO_snprintf(buf, sizeof buf, "%s/%s", dir, filename); +#endif + if (r <= 0 || r >= (int)sizeof(buf)) + goto err; + if (!SSL_add_file_cert_subjects_to_stack(stack, buf)) + goto err; + } + + if (errno) { + SYSerr(SYS_F_OPENDIR, get_last_sys_error()); + ERR_add_error_data(3, "OPENSSL_DIR_read(&ctx, '", dir, "')"); + SSLerr(SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK, ERR_R_SYS_LIB); + goto err; + } + + ret = 1; + + err: + if (d) + OPENSSL_DIR_end(&d); + CRYPTO_w_unlock(CRYPTO_LOCK_READDIR); + return ret; +} + +/* Add a certificate to a BUF_MEM structure */ + +static int ssl_add_cert_to_buf(BUF_MEM *buf, unsigned long *l, X509 *x) +{ + int n; + unsigned char *p; + + n = i2d_X509(x, NULL); + if (n < 0 || !BUF_MEM_grow_clean(buf, (int)(n + (*l) + 3))) { + SSLerr(SSL_F_SSL_ADD_CERT_TO_BUF, ERR_R_BUF_LIB); + return 0; + } + p = (unsigned char *)&(buf->data[*l]); + l2n3(n, p); + n = i2d_X509(x, &p); + if (n < 0) { + /* Shouldn't happen */ + SSLerr(SSL_F_SSL_ADD_CERT_TO_BUF, ERR_R_BUF_LIB); + return 0; + } + *l += n + 3; + + return 1; +} + +/* Add certificate chain to internal SSL BUF_MEM strcuture */ +int ssl_add_cert_chain(SSL *s, CERT_PKEY *cpk, unsigned long *l) +{ + BUF_MEM *buf = s->init_buf; + int no_chain; + int i; + + X509 *x; + STACK_OF(X509) *extra_certs; + X509_STORE *chain_store; + + if (cpk) + x = cpk->x509; + else + x = NULL; + + if (s->cert->chain_store) + chain_store = s->cert->chain_store; + else + chain_store = s->ctx->cert_store; + + /* + * If we have a certificate specific chain use it, else use parent ctx. + */ + if (cpk && cpk->chain) + extra_certs = cpk->chain; + else + extra_certs = s->ctx->extra_certs; + + if ((s->mode & SSL_MODE_NO_AUTO_CHAIN) || extra_certs) + no_chain = 1; + else + no_chain = 0; + + /* TLSv1 sends a chain with nothing in it, instead of an alert */ + if (!BUF_MEM_grow_clean(buf, 10)) { + SSLerr(SSL_F_SSL_ADD_CERT_CHAIN, ERR_R_BUF_LIB); + return 0; + } + if (x != NULL) { + if (no_chain) { + if (!ssl_add_cert_to_buf(buf, l, x)) + return 0; + } else { + X509_STORE_CTX xs_ctx; + + if (!X509_STORE_CTX_init(&xs_ctx, chain_store, x, NULL)) { + SSLerr(SSL_F_SSL_ADD_CERT_CHAIN, ERR_R_X509_LIB); + return (0); + } + 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 (!ssl_add_cert_to_buf(buf, l, x)) { + X509_STORE_CTX_cleanup(&xs_ctx); + return 0; + } + } + X509_STORE_CTX_cleanup(&xs_ctx); + } + } + for (i = 0; i < sk_X509_num(extra_certs); i++) { + x = sk_X509_value(extra_certs, i); + if (!ssl_add_cert_to_buf(buf, l, x)) + return 0; + } + + return 1; +} + +/* Build a certificate chain for current certificate */ +int ssl_build_cert_chain(CERT *c, X509_STORE *chain_store, int flags) +{ + CERT_PKEY *cpk = c->key; + X509_STORE_CTX xs_ctx; + STACK_OF(X509) *chain = NULL, *untrusted = NULL; + X509 *x; + int i, rv = 0; + unsigned long error; + + if (!cpk->x509) { + SSLerr(SSL_F_SSL_BUILD_CERT_CHAIN, SSL_R_NO_CERTIFICATE_SET); + goto err; + } + /* Rearranging and check the chain: add everything to a store */ + if (flags & SSL_BUILD_CHAIN_FLAG_CHECK) { + chain_store = X509_STORE_new(); + if (!chain_store) + goto err; + for (i = 0; i < sk_X509_num(cpk->chain); i++) { + x = sk_X509_value(cpk->chain, i); + if (!X509_STORE_add_cert(chain_store, x)) { + error = ERR_peek_last_error(); + if (ERR_GET_LIB(error) != ERR_LIB_X509 || + ERR_GET_REASON(error) != + X509_R_CERT_ALREADY_IN_HASH_TABLE) + goto err; + ERR_clear_error(); + } + } + /* Add EE cert too: it might be self signed */ + if (!X509_STORE_add_cert(chain_store, cpk->x509)) { + error = ERR_peek_last_error(); + if (ERR_GET_LIB(error) != ERR_LIB_X509 || + ERR_GET_REASON(error) != X509_R_CERT_ALREADY_IN_HASH_TABLE) + goto err; + ERR_clear_error(); + } + } else { + if (c->chain_store) + chain_store = c->chain_store; + + if (flags & SSL_BUILD_CHAIN_FLAG_UNTRUSTED) + untrusted = cpk->chain; + } + + if (!X509_STORE_CTX_init(&xs_ctx, chain_store, cpk->x509, untrusted)) { + SSLerr(SSL_F_SSL_BUILD_CERT_CHAIN, ERR_R_X509_LIB); + goto err; + } + /* Set suite B flags if needed */ + X509_STORE_CTX_set_flags(&xs_ctx, + c->cert_flags & SSL_CERT_FLAG_SUITEB_128_LOS); + + i = X509_verify_cert(&xs_ctx); + if (i <= 0 && flags & SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR) { + if (flags & SSL_BUILD_CHAIN_FLAG_CLEAR_ERROR) + ERR_clear_error(); + i = 1; + rv = 2; + } + if (i > 0) + chain = X509_STORE_CTX_get1_chain(&xs_ctx); + if (i <= 0) { + SSLerr(SSL_F_SSL_BUILD_CERT_CHAIN, SSL_R_CERTIFICATE_VERIFY_FAILED); + i = X509_STORE_CTX_get_error(&xs_ctx); + ERR_add_error_data(2, "Verify error:", + X509_verify_cert_error_string(i)); + + X509_STORE_CTX_cleanup(&xs_ctx); + goto err; + } + X509_STORE_CTX_cleanup(&xs_ctx); + if (cpk->chain) + sk_X509_pop_free(cpk->chain, X509_free); + /* Remove EE certificate from chain */ + x = sk_X509_shift(chain); + X509_free(x); + if (flags & SSL_BUILD_CHAIN_FLAG_NO_ROOT) { + if (sk_X509_num(chain) > 0) { + /* See if last cert is self signed */ + x = sk_X509_value(chain, sk_X509_num(chain) - 1); + X509_check_purpose(x, -1, 0); + if (x->ex_flags & EXFLAG_SS) { + x = sk_X509_pop(chain); + X509_free(x); + } + } + } + cpk->chain = chain; + if (rv == 0) + rv = 1; + err: + if (flags & SSL_BUILD_CHAIN_FLAG_CHECK) + X509_STORE_free(chain_store); + + return rv; +} + +int ssl_cert_set_cert_store(CERT *c, X509_STORE *store, int chain, int ref) +{ + X509_STORE **pstore; + if (chain) + pstore = &c->chain_store; + else + pstore = &c->verify_store; + if (*pstore) + X509_STORE_free(*pstore); + *pstore = store; + if (ref && store) + CRYPTO_add(&store->references, 1, CRYPTO_LOCK_X509_STORE); + return 1; +} diff --git a/thirdparty/openssl/ssl/ssl_ciph.c b/thirdparty/openssl/ssl/ssl_ciph.c new file mode 100644 index 0000000000..302464e643 --- /dev/null +++ b/thirdparty/openssl/ssl/ssl_ciph.c @@ -0,0 +1,2077 @@ +/* ssl/ssl_ciph.c */ +/* 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. + * ECC cipher suite support in OpenSSL originally developed by + * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. + */ +/* ==================================================================== + * 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 <stdio.h> +#include <openssl/objects.h> +#ifndef OPENSSL_NO_COMP +# include <openssl/comp.h> +#endif +#ifndef OPENSSL_NO_ENGINE +# include <openssl/engine.h> +#endif +#include "ssl_locl.h" + +#define SSL_ENC_DES_IDX 0 +#define SSL_ENC_3DES_IDX 1 +#define SSL_ENC_RC4_IDX 2 +#define SSL_ENC_RC2_IDX 3 +#define SSL_ENC_IDEA_IDX 4 +#define SSL_ENC_NULL_IDX 5 +#define SSL_ENC_AES128_IDX 6 +#define SSL_ENC_AES256_IDX 7 +#define SSL_ENC_CAMELLIA128_IDX 8 +#define SSL_ENC_CAMELLIA256_IDX 9 +#define SSL_ENC_GOST89_IDX 10 +#define SSL_ENC_SEED_IDX 11 +#define SSL_ENC_AES128GCM_IDX 12 +#define SSL_ENC_AES256GCM_IDX 13 +#define SSL_ENC_NUM_IDX 14 + +static const EVP_CIPHER *ssl_cipher_methods[SSL_ENC_NUM_IDX] = { + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL +}; + +#define SSL_COMP_NULL_IDX 0 +#define SSL_COMP_ZLIB_IDX 1 +#define SSL_COMP_NUM_IDX 2 + +static STACK_OF(SSL_COMP) *ssl_comp_methods = NULL; + +#define SSL_MD_MD5_IDX 0 +#define SSL_MD_SHA1_IDX 1 +#define SSL_MD_GOST94_IDX 2 +#define SSL_MD_GOST89MAC_IDX 3 +#define SSL_MD_SHA256_IDX 4 +#define SSL_MD_SHA384_IDX 5 +/* + * Constant SSL_MAX_DIGEST equal to size of digests array should be defined + * in the ssl_locl.h + */ +#define SSL_MD_NUM_IDX SSL_MAX_DIGEST +static const EVP_MD *ssl_digest_methods[SSL_MD_NUM_IDX] = { + NULL, NULL, NULL, NULL, NULL, NULL +}; + +/* + * PKEY_TYPE for GOST89MAC is known in advance, but, because implementation + * is engine-provided, we'll fill it only if corresponding EVP_PKEY_METHOD is + * found + */ +static int ssl_mac_pkey_id[SSL_MD_NUM_IDX] = { + EVP_PKEY_HMAC, EVP_PKEY_HMAC, EVP_PKEY_HMAC, NID_undef, + EVP_PKEY_HMAC, EVP_PKEY_HMAC +}; + +static int ssl_mac_secret_size[SSL_MD_NUM_IDX] = { + 0, 0, 0, 0, 0, 0 +}; + +static int ssl_handshake_digest_flag[SSL_MD_NUM_IDX] = { + SSL_HANDSHAKE_MAC_MD5, SSL_HANDSHAKE_MAC_SHA, + SSL_HANDSHAKE_MAC_GOST94, 0, SSL_HANDSHAKE_MAC_SHA256, + SSL_HANDSHAKE_MAC_SHA384 +}; + +#define CIPHER_ADD 1 +#define CIPHER_KILL 2 +#define CIPHER_DEL 3 +#define CIPHER_ORD 4 +#define CIPHER_SPECIAL 5 + +typedef struct cipher_order_st { + const SSL_CIPHER *cipher; + int active; + int dead; + struct cipher_order_st *next, *prev; +} CIPHER_ORDER; + +static const SSL_CIPHER cipher_aliases[] = { + /* "ALL" doesn't include eNULL (must be specifically enabled) */ + {0, SSL_TXT_ALL, 0, 0, 0, ~SSL_eNULL, 0, 0, 0, 0, 0, 0}, + /* "COMPLEMENTOFALL" */ + {0, SSL_TXT_CMPALL, 0, 0, 0, SSL_eNULL, 0, 0, 0, 0, 0, 0}, + + /* + * "COMPLEMENTOFDEFAULT" (does *not* include ciphersuites not found in + * ALL!) + */ + {0, SSL_TXT_CMPDEF, 0, 0, 0, 0, 0, 0, SSL_NOT_DEFAULT, 0, 0, 0}, + + /* + * key exchange aliases (some of those using only a single bit here + * combine multiple key exchange algs according to the RFCs, e.g. kEDH + * combines DHE_DSS and DHE_RSA) + */ + {0, SSL_TXT_kRSA, 0, SSL_kRSA, 0, 0, 0, 0, 0, 0, 0, 0}, + + {0, SSL_TXT_kDHr, 0, SSL_kDHr, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_kDHd, 0, SSL_kDHd, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_kDH, 0, SSL_kDHr | SSL_kDHd, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_kEDH, 0, SSL_kEDH, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_kDHE, 0, SSL_kEDH, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_DH, 0, SSL_kDHr | SSL_kDHd | SSL_kEDH, 0, 0, 0, 0, 0, 0, 0, + 0}, + + {0, SSL_TXT_kKRB5, 0, SSL_kKRB5, 0, 0, 0, 0, 0, 0, 0, 0}, + + {0, SSL_TXT_kECDHr, 0, SSL_kECDHr, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_kECDHe, 0, SSL_kECDHe, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_kECDH, 0, SSL_kECDHr | SSL_kECDHe, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_kEECDH, 0, SSL_kEECDH, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_kECDHE, 0, SSL_kEECDH, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_ECDH, 0, SSL_kECDHr | SSL_kECDHe | SSL_kEECDH, 0, 0, 0, 0, 0, + 0, 0, 0}, + + {0, SSL_TXT_kPSK, 0, SSL_kPSK, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_kSRP, 0, SSL_kSRP, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_kGOST, 0, SSL_kGOST, 0, 0, 0, 0, 0, 0, 0, 0}, + + /* server authentication aliases */ + {0, SSL_TXT_aRSA, 0, 0, SSL_aRSA, 0, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_aDSS, 0, 0, SSL_aDSS, 0, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_DSS, 0, 0, SSL_aDSS, 0, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_aKRB5, 0, 0, SSL_aKRB5, 0, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_aNULL, 0, 0, SSL_aNULL, 0, 0, 0, 0, 0, 0, 0}, + /* no such ciphersuites supported! */ + {0, SSL_TXT_aDH, 0, 0, SSL_aDH, 0, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_aECDH, 0, 0, SSL_aECDH, 0, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_aECDSA, 0, 0, SSL_aECDSA, 0, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_ECDSA, 0, 0, SSL_aECDSA, 0, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_aPSK, 0, 0, SSL_aPSK, 0, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_aGOST94, 0, 0, SSL_aGOST94, 0, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_aGOST01, 0, 0, SSL_aGOST01, 0, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_aGOST, 0, 0, SSL_aGOST94 | SSL_aGOST01, 0, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_aSRP, 0, 0, SSL_aSRP, 0, 0, 0, 0, 0, 0, 0}, + + /* aliases combining key exchange and server authentication */ + {0, SSL_TXT_EDH, 0, SSL_kEDH, ~SSL_aNULL, 0, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_DHE, 0, SSL_kEDH, ~SSL_aNULL, 0, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_EECDH, 0, SSL_kEECDH, ~SSL_aNULL, 0, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_ECDHE, 0, SSL_kEECDH, ~SSL_aNULL, 0, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_NULL, 0, 0, 0, SSL_eNULL, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_KRB5, 0, SSL_kKRB5, SSL_aKRB5, 0, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_RSA, 0, SSL_kRSA, SSL_aRSA, 0, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_ADH, 0, SSL_kEDH, SSL_aNULL, 0, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_AECDH, 0, SSL_kEECDH, SSL_aNULL, 0, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_PSK, 0, SSL_kPSK, SSL_aPSK, 0, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_SRP, 0, SSL_kSRP, 0, 0, 0, 0, 0, 0, 0, 0}, + + /* symmetric encryption aliases */ + {0, SSL_TXT_DES, 0, 0, 0, SSL_DES, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_3DES, 0, 0, 0, SSL_3DES, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_RC4, 0, 0, 0, SSL_RC4, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_RC2, 0, 0, 0, SSL_RC2, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_IDEA, 0, 0, 0, SSL_IDEA, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_SEED, 0, 0, 0, SSL_SEED, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_eNULL, 0, 0, 0, SSL_eNULL, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_AES128, 0, 0, 0, SSL_AES128 | SSL_AES128GCM, 0, 0, 0, 0, 0, + 0}, + {0, SSL_TXT_AES256, 0, 0, 0, SSL_AES256 | SSL_AES256GCM, 0, 0, 0, 0, 0, + 0}, + {0, SSL_TXT_AES, 0, 0, 0, SSL_AES, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_AES_GCM, 0, 0, 0, SSL_AES128GCM | SSL_AES256GCM, 0, 0, 0, 0, + 0, 0}, + {0, SSL_TXT_CAMELLIA128, 0, 0, 0, SSL_CAMELLIA128, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_CAMELLIA256, 0, 0, 0, SSL_CAMELLIA256, 0, 0, 0, 0, 0, 0}, + {0, SSL_TXT_CAMELLIA, 0, 0, 0, SSL_CAMELLIA128 | SSL_CAMELLIA256, 0, 0, 0, + 0, 0, 0}, + + /* MAC aliases */ + {0, SSL_TXT_MD5, 0, 0, 0, 0, SSL_MD5, 0, 0, 0, 0, 0}, + {0, SSL_TXT_SHA1, 0, 0, 0, 0, SSL_SHA1, 0, 0, 0, 0, 0}, + {0, SSL_TXT_SHA, 0, 0, 0, 0, SSL_SHA1, 0, 0, 0, 0, 0}, + {0, SSL_TXT_GOST94, 0, 0, 0, 0, SSL_GOST94, 0, 0, 0, 0, 0}, + {0, SSL_TXT_GOST89MAC, 0, 0, 0, 0, SSL_GOST89MAC, 0, 0, 0, 0, 0}, + {0, SSL_TXT_SHA256, 0, 0, 0, 0, SSL_SHA256, 0, 0, 0, 0, 0}, + {0, SSL_TXT_SHA384, 0, 0, 0, 0, SSL_SHA384, 0, 0, 0, 0, 0}, + + /* protocol version aliases */ + {0, SSL_TXT_SSLV2, 0, 0, 0, 0, 0, SSL_SSLV2, 0, 0, 0, 0}, + {0, SSL_TXT_SSLV3, 0, 0, 0, 0, 0, SSL_SSLV3, 0, 0, 0, 0}, + {0, SSL_TXT_TLSV1, 0, 0, 0, 0, 0, SSL_TLSV1, 0, 0, 0, 0}, + {0, SSL_TXT_TLSV1_2, 0, 0, 0, 0, 0, SSL_TLSV1_2, 0, 0, 0, 0}, + + /* export flag */ + {0, SSL_TXT_EXP, 0, 0, 0, 0, 0, 0, SSL_EXPORT, 0, 0, 0}, + {0, SSL_TXT_EXPORT, 0, 0, 0, 0, 0, 0, SSL_EXPORT, 0, 0, 0}, + + /* strength classes */ + {0, SSL_TXT_EXP40, 0, 0, 0, 0, 0, 0, SSL_EXP40, 0, 0, 0}, + {0, SSL_TXT_EXP56, 0, 0, 0, 0, 0, 0, SSL_EXP56, 0, 0, 0}, + {0, SSL_TXT_LOW, 0, 0, 0, 0, 0, 0, SSL_LOW, 0, 0, 0}, + {0, SSL_TXT_MEDIUM, 0, 0, 0, 0, 0, 0, SSL_MEDIUM, 0, 0, 0}, + {0, SSL_TXT_HIGH, 0, 0, 0, 0, 0, 0, SSL_HIGH, 0, 0, 0}, + /* FIPS 140-2 approved ciphersuite */ + {0, SSL_TXT_FIPS, 0, 0, 0, ~SSL_eNULL, 0, 0, SSL_FIPS, 0, 0, 0}, + /* "DHE-" aliases to "EDH-" labels (for forward compatibility) */ + {0, SSL3_TXT_DHE_DSS_DES_40_CBC_SHA, 0, + SSL_kDHE, SSL_aDSS, SSL_DES, SSL_SHA1, SSL_SSLV3, SSL_EXPORT | SSL_EXP40, + 0, 0, 0,}, + {0, SSL3_TXT_DHE_DSS_DES_64_CBC_SHA, 0, + SSL_kDHE, SSL_aDSS, SSL_DES, SSL_SHA1, SSL_SSLV3, SSL_NOT_EXP | SSL_LOW, + 0, 0, 0,}, + {0, SSL3_TXT_DHE_DSS_DES_192_CBC3_SHA, 0, + SSL_kDHE, SSL_aDSS, SSL_3DES, SSL_SHA1, SSL_SSLV3, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, 0, 0, 0,}, + {0, SSL3_TXT_DHE_RSA_DES_40_CBC_SHA, 0, + SSL_kDHE, SSL_aRSA, SSL_DES, SSL_SHA1, SSL_SSLV3, SSL_EXPORT | SSL_EXP40, + 0, 0, 0,}, + {0, SSL3_TXT_DHE_RSA_DES_64_CBC_SHA, 0, + SSL_kDHE, SSL_aRSA, SSL_DES, SSL_SHA1, SSL_SSLV3, SSL_NOT_EXP | SSL_LOW, + 0, 0, 0,}, + {0, SSL3_TXT_DHE_RSA_DES_192_CBC3_SHA, 0, + SSL_kDHE, SSL_aRSA, SSL_3DES, SSL_SHA1, SSL_SSLV3, + SSL_NOT_EXP | SSL_HIGH | SSL_FIPS, 0, 0, 0,}, +}; + +/* + * Search for public key algorithm with given name and return its pkey_id if + * it is available. Otherwise return 0 + */ +#ifdef OPENSSL_NO_ENGINE + +static int get_optional_pkey_id(const char *pkey_name) +{ + const EVP_PKEY_ASN1_METHOD *ameth; + int pkey_id = 0; + ameth = EVP_PKEY_asn1_find_str(NULL, pkey_name, -1); + if (ameth && EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, + ameth) > 0) { + return pkey_id; + } + return 0; +} + +#else + +static int get_optional_pkey_id(const char *pkey_name) +{ + const EVP_PKEY_ASN1_METHOD *ameth; + ENGINE *tmpeng = NULL; + int pkey_id = 0; + ameth = EVP_PKEY_asn1_find_str(&tmpeng, pkey_name, -1); + if (ameth) { + if (EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, + ameth) <= 0) + pkey_id = 0; + } + if (tmpeng) + ENGINE_finish(tmpeng); + return pkey_id; +} + +#endif + +void ssl_load_ciphers(void) +{ + ssl_cipher_methods[SSL_ENC_DES_IDX] = EVP_get_cipherbyname(SN_des_cbc); + ssl_cipher_methods[SSL_ENC_3DES_IDX] = + EVP_get_cipherbyname(SN_des_ede3_cbc); + ssl_cipher_methods[SSL_ENC_RC4_IDX] = EVP_get_cipherbyname(SN_rc4); + ssl_cipher_methods[SSL_ENC_RC2_IDX] = EVP_get_cipherbyname(SN_rc2_cbc); +#ifndef OPENSSL_NO_IDEA + ssl_cipher_methods[SSL_ENC_IDEA_IDX] = EVP_get_cipherbyname(SN_idea_cbc); +#else + ssl_cipher_methods[SSL_ENC_IDEA_IDX] = NULL; +#endif + ssl_cipher_methods[SSL_ENC_AES128_IDX] = + EVP_get_cipherbyname(SN_aes_128_cbc); + ssl_cipher_methods[SSL_ENC_AES256_IDX] = + EVP_get_cipherbyname(SN_aes_256_cbc); + ssl_cipher_methods[SSL_ENC_CAMELLIA128_IDX] = + EVP_get_cipherbyname(SN_camellia_128_cbc); + ssl_cipher_methods[SSL_ENC_CAMELLIA256_IDX] = + EVP_get_cipherbyname(SN_camellia_256_cbc); + ssl_cipher_methods[SSL_ENC_GOST89_IDX] = + EVP_get_cipherbyname(SN_gost89_cnt); + ssl_cipher_methods[SSL_ENC_SEED_IDX] = EVP_get_cipherbyname(SN_seed_cbc); + + ssl_cipher_methods[SSL_ENC_AES128GCM_IDX] = + EVP_get_cipherbyname(SN_aes_128_gcm); + ssl_cipher_methods[SSL_ENC_AES256GCM_IDX] = + EVP_get_cipherbyname(SN_aes_256_gcm); + + ssl_digest_methods[SSL_MD_MD5_IDX] = EVP_get_digestbyname(SN_md5); + ssl_mac_secret_size[SSL_MD_MD5_IDX] = + EVP_MD_size(ssl_digest_methods[SSL_MD_MD5_IDX]); + OPENSSL_assert(ssl_mac_secret_size[SSL_MD_MD5_IDX] >= 0); + ssl_digest_methods[SSL_MD_SHA1_IDX] = EVP_get_digestbyname(SN_sha1); + ssl_mac_secret_size[SSL_MD_SHA1_IDX] = + EVP_MD_size(ssl_digest_methods[SSL_MD_SHA1_IDX]); + OPENSSL_assert(ssl_mac_secret_size[SSL_MD_SHA1_IDX] >= 0); + ssl_digest_methods[SSL_MD_GOST94_IDX] = + EVP_get_digestbyname(SN_id_GostR3411_94); + if (ssl_digest_methods[SSL_MD_GOST94_IDX]) { + ssl_mac_secret_size[SSL_MD_GOST94_IDX] = + EVP_MD_size(ssl_digest_methods[SSL_MD_GOST94_IDX]); + OPENSSL_assert(ssl_mac_secret_size[SSL_MD_GOST94_IDX] >= 0); + } + ssl_digest_methods[SSL_MD_GOST89MAC_IDX] = + EVP_get_digestbyname(SN_id_Gost28147_89_MAC); + ssl_mac_pkey_id[SSL_MD_GOST89MAC_IDX] = get_optional_pkey_id("gost-mac"); + if (ssl_mac_pkey_id[SSL_MD_GOST89MAC_IDX]) { + ssl_mac_secret_size[SSL_MD_GOST89MAC_IDX] = 32; + } + + ssl_digest_methods[SSL_MD_SHA256_IDX] = EVP_get_digestbyname(SN_sha256); + ssl_mac_secret_size[SSL_MD_SHA256_IDX] = + EVP_MD_size(ssl_digest_methods[SSL_MD_SHA256_IDX]); + ssl_digest_methods[SSL_MD_SHA384_IDX] = EVP_get_digestbyname(SN_sha384); + ssl_mac_secret_size[SSL_MD_SHA384_IDX] = + EVP_MD_size(ssl_digest_methods[SSL_MD_SHA384_IDX]); +} + +#ifndef OPENSSL_NO_COMP + +static int sk_comp_cmp(const SSL_COMP *const *a, const SSL_COMP *const *b) +{ + return ((*a)->id - (*b)->id); +} + +static void load_builtin_compressions(void) +{ + int got_write_lock = 0; + + CRYPTO_r_lock(CRYPTO_LOCK_SSL); + if (ssl_comp_methods == NULL) { + CRYPTO_r_unlock(CRYPTO_LOCK_SSL); + CRYPTO_w_lock(CRYPTO_LOCK_SSL); + got_write_lock = 1; + + if (ssl_comp_methods == NULL) { + SSL_COMP *comp = NULL; + + MemCheck_off(); + ssl_comp_methods = sk_SSL_COMP_new(sk_comp_cmp); + if (ssl_comp_methods != NULL) { + comp = (SSL_COMP *)OPENSSL_malloc(sizeof(SSL_COMP)); + if (comp != NULL) { + comp->method = COMP_zlib(); + if (comp->method && comp->method->type == NID_undef) + OPENSSL_free(comp); + else { + comp->id = SSL_COMP_ZLIB_IDX; + comp->name = comp->method->name; + sk_SSL_COMP_push(ssl_comp_methods, comp); + } + } + sk_SSL_COMP_sort(ssl_comp_methods); + } + MemCheck_on(); + } + } + + if (got_write_lock) + CRYPTO_w_unlock(CRYPTO_LOCK_SSL); + else + CRYPTO_r_unlock(CRYPTO_LOCK_SSL); +} +#endif + +int ssl_cipher_get_evp(const SSL_SESSION *s, const EVP_CIPHER **enc, + const EVP_MD **md, int *mac_pkey_type, + int *mac_secret_size, SSL_COMP **comp) +{ + int i; + const SSL_CIPHER *c; + + c = s->cipher; + if (c == NULL) + return (0); + if (comp != NULL) { + SSL_COMP ctmp; +#ifndef OPENSSL_NO_COMP + load_builtin_compressions(); +#endif + + *comp = NULL; + ctmp.id = s->compress_meth; + if (ssl_comp_methods != NULL) { + i = sk_SSL_COMP_find(ssl_comp_methods, &ctmp); + if (i >= 0) + *comp = sk_SSL_COMP_value(ssl_comp_methods, i); + else + *comp = NULL; + } + } + + if ((enc == NULL) || (md == NULL)) + return (0); + + switch (c->algorithm_enc) { + case SSL_DES: + i = SSL_ENC_DES_IDX; + break; + case SSL_3DES: + i = SSL_ENC_3DES_IDX; + break; + case SSL_RC4: + i = SSL_ENC_RC4_IDX; + break; + case SSL_RC2: + i = SSL_ENC_RC2_IDX; + break; + case SSL_IDEA: + i = SSL_ENC_IDEA_IDX; + break; + case SSL_eNULL: + i = SSL_ENC_NULL_IDX; + break; + case SSL_AES128: + i = SSL_ENC_AES128_IDX; + break; + case SSL_AES256: + i = SSL_ENC_AES256_IDX; + break; + case SSL_CAMELLIA128: + i = SSL_ENC_CAMELLIA128_IDX; + break; + case SSL_CAMELLIA256: + i = SSL_ENC_CAMELLIA256_IDX; + break; + case SSL_eGOST2814789CNT: + i = SSL_ENC_GOST89_IDX; + break; + case SSL_SEED: + i = SSL_ENC_SEED_IDX; + break; + case SSL_AES128GCM: + i = SSL_ENC_AES128GCM_IDX; + break; + case SSL_AES256GCM: + i = SSL_ENC_AES256GCM_IDX; + break; + default: + i = -1; + break; + } + + if ((i < 0) || (i >= SSL_ENC_NUM_IDX)) + *enc = NULL; + else { + if (i == SSL_ENC_NULL_IDX) + *enc = EVP_enc_null(); + else + *enc = ssl_cipher_methods[i]; + } + + switch (c->algorithm_mac) { + case SSL_MD5: + i = SSL_MD_MD5_IDX; + break; + case SSL_SHA1: + i = SSL_MD_SHA1_IDX; + break; + case SSL_SHA256: + i = SSL_MD_SHA256_IDX; + break; + case SSL_SHA384: + i = SSL_MD_SHA384_IDX; + break; + case SSL_GOST94: + i = SSL_MD_GOST94_IDX; + break; + case SSL_GOST89MAC: + i = SSL_MD_GOST89MAC_IDX; + break; + default: + i = -1; + break; + } + if ((i < 0) || (i >= SSL_MD_NUM_IDX)) { + *md = NULL; + if (mac_pkey_type != NULL) + *mac_pkey_type = NID_undef; + if (mac_secret_size != NULL) + *mac_secret_size = 0; + if (c->algorithm_mac == SSL_AEAD) + mac_pkey_type = NULL; + } else { + *md = ssl_digest_methods[i]; + if (mac_pkey_type != NULL) + *mac_pkey_type = ssl_mac_pkey_id[i]; + if (mac_secret_size != NULL) + *mac_secret_size = ssl_mac_secret_size[i]; + } + + if ((*enc != NULL) && + (*md != NULL || (EVP_CIPHER_flags(*enc) & EVP_CIPH_FLAG_AEAD_CIPHER)) + && (!mac_pkey_type || *mac_pkey_type != NID_undef)) { + const EVP_CIPHER *evp; + + if (s->ssl_version >> 8 != TLS1_VERSION_MAJOR || + s->ssl_version < TLS1_VERSION) + return 1; + +#ifdef OPENSSL_FIPS + if (FIPS_mode()) + return 1; +#endif + + if (c->algorithm_enc == SSL_RC4 && + c->algorithm_mac == SSL_MD5 && + (evp = EVP_get_cipherbyname("RC4-HMAC-MD5"))) + *enc = evp, *md = NULL; + else if (c->algorithm_enc == SSL_AES128 && + c->algorithm_mac == SSL_SHA1 && + (evp = EVP_get_cipherbyname("AES-128-CBC-HMAC-SHA1"))) + *enc = evp, *md = NULL; + else if (c->algorithm_enc == SSL_AES256 && + c->algorithm_mac == SSL_SHA1 && + (evp = EVP_get_cipherbyname("AES-256-CBC-HMAC-SHA1"))) + *enc = evp, *md = NULL; + else if (c->algorithm_enc == SSL_AES128 && + c->algorithm_mac == SSL_SHA256 && + (evp = EVP_get_cipherbyname("AES-128-CBC-HMAC-SHA256"))) + *enc = evp, *md = NULL; + else if (c->algorithm_enc == SSL_AES256 && + c->algorithm_mac == SSL_SHA256 && + (evp = EVP_get_cipherbyname("AES-256-CBC-HMAC-SHA256"))) + *enc = evp, *md = NULL; + return (1); + } else + return (0); +} + +int ssl_get_handshake_digest(int idx, long *mask, const EVP_MD **md) +{ + if (idx < 0 || idx >= SSL_MD_NUM_IDX) { + return 0; + } + *mask = ssl_handshake_digest_flag[idx]; + if (*mask) + *md = ssl_digest_methods[idx]; + else + *md = NULL; + return 1; +} + +#define ITEM_SEP(a) \ + (((a) == ':') || ((a) == ' ') || ((a) == ';') || ((a) == ',')) + +static void ll_append_tail(CIPHER_ORDER **head, CIPHER_ORDER *curr, + CIPHER_ORDER **tail) +{ + if (curr == *tail) + return; + if (curr == *head) + *head = curr->next; + if (curr->prev != NULL) + curr->prev->next = curr->next; + if (curr->next != NULL) + curr->next->prev = curr->prev; + (*tail)->next = curr; + curr->prev = *tail; + curr->next = NULL; + *tail = curr; +} + +static void ll_append_head(CIPHER_ORDER **head, CIPHER_ORDER *curr, + CIPHER_ORDER **tail) +{ + if (curr == *head) + return; + if (curr == *tail) + *tail = curr->prev; + if (curr->next != NULL) + curr->next->prev = curr->prev; + if (curr->prev != NULL) + curr->prev->next = curr->next; + (*head)->prev = curr; + curr->next = *head; + curr->prev = NULL; + *head = curr; +} + +static void ssl_cipher_get_disabled(unsigned long *mkey, unsigned long *auth, + unsigned long *enc, unsigned long *mac, + unsigned long *ssl) +{ + *mkey = 0; + *auth = 0; + *enc = 0; + *mac = 0; + *ssl = 0; + +#ifdef OPENSSL_NO_RSA + *mkey |= SSL_kRSA; + *auth |= SSL_aRSA; +#endif +#ifdef OPENSSL_NO_DSA + *auth |= SSL_aDSS; +#endif +#ifdef OPENSSL_NO_DH + *mkey |= SSL_kDHr | SSL_kDHd | SSL_kEDH; + *auth |= SSL_aDH; +#endif +#ifdef OPENSSL_NO_KRB5 + *mkey |= SSL_kKRB5; + *auth |= SSL_aKRB5; +#endif +#ifdef OPENSSL_NO_ECDSA + *auth |= SSL_aECDSA; +#endif +#ifdef OPENSSL_NO_ECDH + *mkey |= SSL_kECDHe | SSL_kECDHr; + *auth |= SSL_aECDH; +#endif +#ifdef OPENSSL_NO_PSK + *mkey |= SSL_kPSK; + *auth |= SSL_aPSK; +#endif +#ifdef OPENSSL_NO_SRP + *mkey |= SSL_kSRP; +#endif + /* + * Check for presence of GOST 34.10 algorithms, and if they do not + * present, disable appropriate auth and key exchange + */ + if (!get_optional_pkey_id("gost94")) { + *auth |= SSL_aGOST94; + } + if (!get_optional_pkey_id("gost2001")) { + *auth |= SSL_aGOST01; + } + /* + * Disable GOST key exchange if no GOST signature algs are available * + */ + if ((*auth & (SSL_aGOST94 | SSL_aGOST01)) == (SSL_aGOST94 | SSL_aGOST01)) { + *mkey |= SSL_kGOST; + } +#ifdef SSL_FORBID_ENULL + *enc |= SSL_eNULL; +#endif + + *enc |= (ssl_cipher_methods[SSL_ENC_DES_IDX] == NULL) ? SSL_DES : 0; + *enc |= (ssl_cipher_methods[SSL_ENC_3DES_IDX] == NULL) ? SSL_3DES : 0; + *enc |= (ssl_cipher_methods[SSL_ENC_RC4_IDX] == NULL) ? SSL_RC4 : 0; + *enc |= (ssl_cipher_methods[SSL_ENC_RC2_IDX] == NULL) ? SSL_RC2 : 0; + *enc |= (ssl_cipher_methods[SSL_ENC_IDEA_IDX] == NULL) ? SSL_IDEA : 0; + *enc |= (ssl_cipher_methods[SSL_ENC_AES128_IDX] == NULL) ? SSL_AES128 : 0; + *enc |= (ssl_cipher_methods[SSL_ENC_AES256_IDX] == NULL) ? SSL_AES256 : 0; + *enc |= + (ssl_cipher_methods[SSL_ENC_AES128GCM_IDX] == + NULL) ? SSL_AES128GCM : 0; + *enc |= + (ssl_cipher_methods[SSL_ENC_AES256GCM_IDX] == + NULL) ? SSL_AES256GCM : 0; + *enc |= + (ssl_cipher_methods[SSL_ENC_CAMELLIA128_IDX] == + NULL) ? SSL_CAMELLIA128 : 0; + *enc |= + (ssl_cipher_methods[SSL_ENC_CAMELLIA256_IDX] == + NULL) ? SSL_CAMELLIA256 : 0; + *enc |= + (ssl_cipher_methods[SSL_ENC_GOST89_IDX] == + NULL) ? SSL_eGOST2814789CNT : 0; + *enc |= (ssl_cipher_methods[SSL_ENC_SEED_IDX] == NULL) ? SSL_SEED : 0; + + *mac |= (ssl_digest_methods[SSL_MD_MD5_IDX] == NULL) ? SSL_MD5 : 0; + *mac |= (ssl_digest_methods[SSL_MD_SHA1_IDX] == NULL) ? SSL_SHA1 : 0; + *mac |= (ssl_digest_methods[SSL_MD_SHA256_IDX] == NULL) ? SSL_SHA256 : 0; + *mac |= (ssl_digest_methods[SSL_MD_SHA384_IDX] == NULL) ? SSL_SHA384 : 0; + *mac |= (ssl_digest_methods[SSL_MD_GOST94_IDX] == NULL) ? SSL_GOST94 : 0; + *mac |= (ssl_digest_methods[SSL_MD_GOST89MAC_IDX] == NULL + || ssl_mac_pkey_id[SSL_MD_GOST89MAC_IDX] == + NID_undef) ? SSL_GOST89MAC : 0; + +} + +static void ssl_cipher_collect_ciphers(const SSL_METHOD *ssl_method, + int num_of_ciphers, + unsigned long disabled_mkey, + unsigned long disabled_auth, + unsigned long disabled_enc, + unsigned long disabled_mac, + unsigned long disabled_ssl, + CIPHER_ORDER *co_list, + CIPHER_ORDER **head_p, + CIPHER_ORDER **tail_p) +{ + int i, co_list_num; + const SSL_CIPHER *c; + + /* + * We have num_of_ciphers descriptions compiled in, depending on the + * method selected (SSLv2 and/or SSLv3, TLSv1 etc). + * These will later be sorted in a linked list with at most num + * entries. + */ + + /* Get the initial list of ciphers */ + co_list_num = 0; /* actual count of ciphers */ + for (i = 0; i < num_of_ciphers; i++) { + c = ssl_method->get_cipher(i); + /* drop those that use any of that is not available */ + if ((c != NULL) && c->valid && +#ifdef OPENSSL_FIPS + (!FIPS_mode() || (c->algo_strength & SSL_FIPS)) && +#endif + !(c->algorithm_mkey & disabled_mkey) && + !(c->algorithm_auth & disabled_auth) && + !(c->algorithm_enc & disabled_enc) && + !(c->algorithm_mac & disabled_mac) && + !(c->algorithm_ssl & disabled_ssl)) { + co_list[co_list_num].cipher = c; + co_list[co_list_num].next = NULL; + co_list[co_list_num].prev = NULL; + co_list[co_list_num].active = 0; + co_list_num++; +#ifdef KSSL_DEBUG + fprintf(stderr, "\t%d: %s %lx %lx %lx\n", i, c->name, c->id, + c->algorithm_mkey, c->algorithm_auth); +#endif /* KSSL_DEBUG */ + /* + * if (!sk_push(ca_list,(char *)c)) goto err; + */ + } + } + + /* + * Prepare linked list from list entries + */ + if (co_list_num > 0) { + co_list[0].prev = NULL; + + if (co_list_num > 1) { + co_list[0].next = &co_list[1]; + + for (i = 1; i < co_list_num - 1; i++) { + co_list[i].prev = &co_list[i - 1]; + co_list[i].next = &co_list[i + 1]; + } + + co_list[co_list_num - 1].prev = &co_list[co_list_num - 2]; + } + + co_list[co_list_num - 1].next = NULL; + + *head_p = &co_list[0]; + *tail_p = &co_list[co_list_num - 1]; + } +} + +static void ssl_cipher_collect_aliases(const SSL_CIPHER **ca_list, + int num_of_group_aliases, + unsigned long disabled_mkey, + unsigned long disabled_auth, + unsigned long disabled_enc, + unsigned long disabled_mac, + unsigned long disabled_ssl, + CIPHER_ORDER *head) +{ + CIPHER_ORDER *ciph_curr; + const SSL_CIPHER **ca_curr; + int i; + unsigned long mask_mkey = ~disabled_mkey; + unsigned long mask_auth = ~disabled_auth; + unsigned long mask_enc = ~disabled_enc; + unsigned long mask_mac = ~disabled_mac; + unsigned long mask_ssl = ~disabled_ssl; + + /* + * First, add the real ciphers as already collected + */ + ciph_curr = head; + ca_curr = ca_list; + while (ciph_curr != NULL) { + *ca_curr = ciph_curr->cipher; + ca_curr++; + ciph_curr = ciph_curr->next; + } + + /* + * Now we add the available ones from the cipher_aliases[] table. + * They represent either one or more algorithms, some of which + * in any affected category must be supported (set in enabled_mask), + * or represent a cipher strength value (will be added in any case because algorithms=0). + */ + for (i = 0; i < num_of_group_aliases; i++) { + unsigned long algorithm_mkey = cipher_aliases[i].algorithm_mkey; + unsigned long algorithm_auth = cipher_aliases[i].algorithm_auth; + unsigned long algorithm_enc = cipher_aliases[i].algorithm_enc; + unsigned long algorithm_mac = cipher_aliases[i].algorithm_mac; + unsigned long algorithm_ssl = cipher_aliases[i].algorithm_ssl; + + if (algorithm_mkey) + if ((algorithm_mkey & mask_mkey) == 0) + continue; + + if (algorithm_auth) + if ((algorithm_auth & mask_auth) == 0) + continue; + + if (algorithm_enc) + if ((algorithm_enc & mask_enc) == 0) + continue; + + if (algorithm_mac) + if ((algorithm_mac & mask_mac) == 0) + continue; + + if (algorithm_ssl) + if ((algorithm_ssl & mask_ssl) == 0) + continue; + + *ca_curr = (SSL_CIPHER *)(cipher_aliases + i); + ca_curr++; + } + + *ca_curr = NULL; /* end of list */ +} + +static void ssl_cipher_apply_rule(unsigned long cipher_id, + unsigned long alg_mkey, + unsigned long alg_auth, + unsigned long alg_enc, + unsigned long alg_mac, + unsigned long alg_ssl, + unsigned long algo_strength, int rule, + int strength_bits, CIPHER_ORDER **head_p, + CIPHER_ORDER **tail_p) +{ + CIPHER_ORDER *head, *tail, *curr, *next, *last; + const SSL_CIPHER *cp; + int reverse = 0; + +#ifdef CIPHER_DEBUG + fprintf(stderr, + "Applying rule %d with %08lx/%08lx/%08lx/%08lx/%08lx %08lx (%d)\n", + rule, alg_mkey, alg_auth, alg_enc, alg_mac, alg_ssl, + algo_strength, strength_bits); +#endif + + if (rule == CIPHER_DEL) + reverse = 1; /* needed to maintain sorting between + * currently deleted ciphers */ + + head = *head_p; + tail = *tail_p; + + if (reverse) { + next = tail; + last = head; + } else { + next = head; + last = tail; + } + + curr = NULL; + for (;;) { + if (curr == last) + break; + + curr = next; + + if (curr == NULL) + break; + + next = reverse ? curr->prev : curr->next; + + cp = curr->cipher; + + /* + * Selection criteria is either the value of strength_bits + * or the algorithms used. + */ + if (strength_bits >= 0) { + if (strength_bits != cp->strength_bits) + continue; + } else { +#ifdef CIPHER_DEBUG + fprintf(stderr, + "\nName: %s:\nAlgo = %08lx/%08lx/%08lx/%08lx/%08lx Algo_strength = %08lx\n", + cp->name, cp->algorithm_mkey, cp->algorithm_auth, + cp->algorithm_enc, cp->algorithm_mac, cp->algorithm_ssl, + cp->algo_strength); +#endif +#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL + if (cipher_id && cipher_id != cp->id) + continue; +#endif + if (alg_mkey && !(alg_mkey & cp->algorithm_mkey)) + continue; + if (alg_auth && !(alg_auth & cp->algorithm_auth)) + continue; + if (alg_enc && !(alg_enc & cp->algorithm_enc)) + continue; + if (alg_mac && !(alg_mac & cp->algorithm_mac)) + continue; + if (alg_ssl && !(alg_ssl & cp->algorithm_ssl)) + continue; + if ((algo_strength & SSL_EXP_MASK) + && !(algo_strength & SSL_EXP_MASK & cp->algo_strength)) + continue; + if ((algo_strength & SSL_STRONG_MASK) + && !(algo_strength & SSL_STRONG_MASK & cp->algo_strength)) + continue; + if ((algo_strength & SSL_NOT_DEFAULT) + && !(cp->algo_strength & SSL_NOT_DEFAULT)) + continue; + } + +#ifdef CIPHER_DEBUG + fprintf(stderr, "Action = %d\n", rule); +#endif + + /* add the cipher if it has not been added yet. */ + if (rule == CIPHER_ADD) { + /* reverse == 0 */ + if (!curr->active) { + ll_append_tail(&head, curr, &tail); + curr->active = 1; + } + } + /* Move the added cipher to this location */ + else if (rule == CIPHER_ORD) { + /* reverse == 0 */ + if (curr->active) { + ll_append_tail(&head, curr, &tail); + } + } else if (rule == CIPHER_DEL) { + /* reverse == 1 */ + if (curr->active) { + /* + * most recently deleted ciphersuites get best positions for + * any future CIPHER_ADD (note that the CIPHER_DEL loop works + * in reverse to maintain the order) + */ + ll_append_head(&head, curr, &tail); + curr->active = 0; + } + } else if (rule == CIPHER_KILL) { + /* reverse == 0 */ + if (head == curr) + head = curr->next; + else + curr->prev->next = curr->next; + if (tail == curr) + tail = curr->prev; + curr->active = 0; + if (curr->next != NULL) + curr->next->prev = curr->prev; + if (curr->prev != NULL) + curr->prev->next = curr->next; + curr->next = NULL; + curr->prev = NULL; + } + } + + *head_p = head; + *tail_p = tail; +} + +static int ssl_cipher_strength_sort(CIPHER_ORDER **head_p, + CIPHER_ORDER **tail_p) +{ + int max_strength_bits, i, *number_uses; + CIPHER_ORDER *curr; + + /* + * This routine sorts the ciphers with descending strength. The sorting + * must keep the pre-sorted sequence, so we apply the normal sorting + * routine as '+' movement to the end of the list. + */ + max_strength_bits = 0; + curr = *head_p; + while (curr != NULL) { + if (curr->active && (curr->cipher->strength_bits > max_strength_bits)) + max_strength_bits = curr->cipher->strength_bits; + curr = curr->next; + } + + number_uses = OPENSSL_malloc((max_strength_bits + 1) * sizeof(int)); + if (!number_uses) { + SSLerr(SSL_F_SSL_CIPHER_STRENGTH_SORT, ERR_R_MALLOC_FAILURE); + return (0); + } + memset(number_uses, 0, (max_strength_bits + 1) * sizeof(int)); + + /* + * Now find the strength_bits values actually used + */ + curr = *head_p; + while (curr != NULL) { + if (curr->active) + number_uses[curr->cipher->strength_bits]++; + curr = curr->next; + } + /* + * Go through the list of used strength_bits values in descending + * order. + */ + for (i = max_strength_bits; i >= 0; i--) + if (number_uses[i] > 0) + ssl_cipher_apply_rule(0, 0, 0, 0, 0, 0, 0, CIPHER_ORD, i, head_p, + tail_p); + + OPENSSL_free(number_uses); + return (1); +} + +static int ssl_cipher_process_rulestr(const char *rule_str, + CIPHER_ORDER **head_p, + CIPHER_ORDER **tail_p, + const SSL_CIPHER **ca_list) +{ + unsigned long alg_mkey, alg_auth, alg_enc, alg_mac, alg_ssl, + algo_strength; + const char *l, *buf; + int j, multi, found, rule, retval, ok, buflen; + unsigned long cipher_id = 0; + char ch; + + retval = 1; + l = rule_str; + for (;;) { + ch = *l; + + if (ch == '\0') + break; /* done */ + if (ch == '-') { + rule = CIPHER_DEL; + l++; + } else if (ch == '+') { + rule = CIPHER_ORD; + l++; + } else if (ch == '!') { + rule = CIPHER_KILL; + l++; + } else if (ch == '@') { + rule = CIPHER_SPECIAL; + l++; + } else { + rule = CIPHER_ADD; + } + + if (ITEM_SEP(ch)) { + l++; + continue; + } + + alg_mkey = 0; + alg_auth = 0; + alg_enc = 0; + alg_mac = 0; + alg_ssl = 0; + algo_strength = 0; + + for (;;) { + ch = *l; + buf = l; + buflen = 0; +#ifndef CHARSET_EBCDIC + while (((ch >= 'A') && (ch <= 'Z')) || + ((ch >= '0') && (ch <= '9')) || + ((ch >= 'a') && (ch <= 'z')) || (ch == '-') || (ch == '.')) +#else + while (isalnum(ch) || (ch == '-') || (ch == '.')) +#endif + { + ch = *(++l); + buflen++; + } + + if (buflen == 0) { + /* + * We hit something we cannot deal with, + * it is no command or separator nor + * alphanumeric, so we call this an error. + */ + SSLerr(SSL_F_SSL_CIPHER_PROCESS_RULESTR, + SSL_R_INVALID_COMMAND); + retval = found = 0; + l++; + break; + } + + if (rule == CIPHER_SPECIAL) { + found = 0; /* unused -- avoid compiler warning */ + break; /* special treatment */ + } + + /* check for multi-part specification */ + if (ch == '+') { + multi = 1; + l++; + } else + multi = 0; + + /* + * Now search for the cipher alias in the ca_list. Be careful + * with the strncmp, because the "buflen" limitation + * will make the rule "ADH:SOME" and the cipher + * "ADH-MY-CIPHER" look like a match for buflen=3. + * So additionally check whether the cipher name found + * has the correct length. We can save a strlen() call: + * just checking for the '\0' at the right place is + * sufficient, we have to strncmp() anyway. (We cannot + * use strcmp(), because buf is not '\0' terminated.) + */ + j = found = 0; + cipher_id = 0; + while (ca_list[j]) { + if (!strncmp(buf, ca_list[j]->name, buflen) && + (ca_list[j]->name[buflen] == '\0')) { + found = 1; + break; + } else + j++; + } + + if (!found) + break; /* ignore this entry */ + + if (ca_list[j]->algorithm_mkey) { + if (alg_mkey) { + alg_mkey &= ca_list[j]->algorithm_mkey; + if (!alg_mkey) { + found = 0; + break; + } + } else + alg_mkey = ca_list[j]->algorithm_mkey; + } + + if (ca_list[j]->algorithm_auth) { + if (alg_auth) { + alg_auth &= ca_list[j]->algorithm_auth; + if (!alg_auth) { + found = 0; + break; + } + } else + alg_auth = ca_list[j]->algorithm_auth; + } + + if (ca_list[j]->algorithm_enc) { + if (alg_enc) { + alg_enc &= ca_list[j]->algorithm_enc; + if (!alg_enc) { + found = 0; + break; + } + } else + alg_enc = ca_list[j]->algorithm_enc; + } + + if (ca_list[j]->algorithm_mac) { + if (alg_mac) { + alg_mac &= ca_list[j]->algorithm_mac; + if (!alg_mac) { + found = 0; + break; + } + } else + alg_mac = ca_list[j]->algorithm_mac; + } + + if (ca_list[j]->algo_strength & SSL_EXP_MASK) { + if (algo_strength & SSL_EXP_MASK) { + algo_strength &= + (ca_list[j]->algo_strength & SSL_EXP_MASK) | + ~SSL_EXP_MASK; + if (!(algo_strength & SSL_EXP_MASK)) { + found = 0; + break; + } + } else + algo_strength |= ca_list[j]->algo_strength & SSL_EXP_MASK; + } + + if (ca_list[j]->algo_strength & SSL_STRONG_MASK) { + if (algo_strength & SSL_STRONG_MASK) { + algo_strength &= + (ca_list[j]->algo_strength & SSL_STRONG_MASK) | + ~SSL_STRONG_MASK; + if (!(algo_strength & SSL_STRONG_MASK)) { + found = 0; + break; + } + } else + algo_strength |= + ca_list[j]->algo_strength & SSL_STRONG_MASK; + } + + if (ca_list[j]->algo_strength & SSL_NOT_DEFAULT) { + algo_strength |= SSL_NOT_DEFAULT; + } + + if (ca_list[j]->valid) { + /* + * explicit ciphersuite found; its protocol version does not + * become part of the search pattern! + */ + + cipher_id = ca_list[j]->id; + } else { + /* + * not an explicit ciphersuite; only in this case, the + * protocol version is considered part of the search pattern + */ + + if (ca_list[j]->algorithm_ssl) { + if (alg_ssl) { + alg_ssl &= ca_list[j]->algorithm_ssl; + if (!alg_ssl) { + found = 0; + break; + } + } else + alg_ssl = ca_list[j]->algorithm_ssl; + } + } + + if (!multi) + break; + } + + /* + * Ok, we have the rule, now apply it + */ + if (rule == CIPHER_SPECIAL) { /* special command */ + ok = 0; + if ((buflen == 8) && !strncmp(buf, "STRENGTH", 8)) + ok = ssl_cipher_strength_sort(head_p, tail_p); + else + SSLerr(SSL_F_SSL_CIPHER_PROCESS_RULESTR, + SSL_R_INVALID_COMMAND); + if (ok == 0) + retval = 0; + /* + * We do not support any "multi" options + * together with "@", so throw away the + * rest of the command, if any left, until + * end or ':' is found. + */ + while ((*l != '\0') && !ITEM_SEP(*l)) + l++; + } else if (found) { + ssl_cipher_apply_rule(cipher_id, + alg_mkey, alg_auth, alg_enc, alg_mac, + alg_ssl, algo_strength, rule, -1, head_p, + tail_p); + } else { + while ((*l != '\0') && !ITEM_SEP(*l)) + l++; + } + if (*l == '\0') + break; /* done */ + } + + return (retval); +} + +#ifndef OPENSSL_NO_EC +static int check_suiteb_cipher_list(const SSL_METHOD *meth, CERT *c, + const char **prule_str) +{ + unsigned int suiteb_flags = 0, suiteb_comb2 = 0; + if (strncmp(*prule_str, "SUITEB128ONLY", 13) == 0) { + suiteb_flags = SSL_CERT_FLAG_SUITEB_128_LOS_ONLY; + } else if (strncmp(*prule_str, "SUITEB128C2", 11) == 0) { + suiteb_comb2 = 1; + suiteb_flags = SSL_CERT_FLAG_SUITEB_128_LOS; + } else if (strncmp(*prule_str, "SUITEB128", 9) == 0) { + suiteb_flags = SSL_CERT_FLAG_SUITEB_128_LOS; + } else if (strncmp(*prule_str, "SUITEB192", 9) == 0) { + suiteb_flags = SSL_CERT_FLAG_SUITEB_192_LOS; + } + + if (suiteb_flags) { + c->cert_flags &= ~SSL_CERT_FLAG_SUITEB_128_LOS; + c->cert_flags |= suiteb_flags; + } else + suiteb_flags = c->cert_flags & SSL_CERT_FLAG_SUITEB_128_LOS; + + if (!suiteb_flags) + return 1; + /* Check version: if TLS 1.2 ciphers allowed we can use Suite B */ + + if (!(meth->ssl3_enc->enc_flags & SSL_ENC_FLAG_TLS1_2_CIPHERS)) { + if (meth->ssl3_enc->enc_flags & SSL_ENC_FLAG_DTLS) + SSLerr(SSL_F_CHECK_SUITEB_CIPHER_LIST, + SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE); + else + SSLerr(SSL_F_CHECK_SUITEB_CIPHER_LIST, + SSL_R_ONLY_TLS_1_2_ALLOWED_IN_SUITEB_MODE); + return 0; + } +# ifndef OPENSSL_NO_ECDH + switch (suiteb_flags) { + case SSL_CERT_FLAG_SUITEB_128_LOS: + if (suiteb_comb2) + *prule_str = "ECDHE-ECDSA-AES256-GCM-SHA384"; + else + *prule_str = + "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384"; + break; + case SSL_CERT_FLAG_SUITEB_128_LOS_ONLY: + *prule_str = "ECDHE-ECDSA-AES128-GCM-SHA256"; + break; + case SSL_CERT_FLAG_SUITEB_192_LOS: + *prule_str = "ECDHE-ECDSA-AES256-GCM-SHA384"; + break; + } + /* Set auto ECDH parameter determination */ + c->ecdh_tmp_auto = 1; + return 1; +# else + SSLerr(SSL_F_CHECK_SUITEB_CIPHER_LIST, + SSL_R_ECDH_REQUIRED_FOR_SUITEB_MODE); + return 0; +# endif +} +#endif + +STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method, STACK_OF(SSL_CIPHER) + **cipher_list, STACK_OF(SSL_CIPHER) + **cipher_list_by_id, + const char *rule_str, CERT *c) +{ + int ok, num_of_ciphers, num_of_alias_max, num_of_group_aliases; + unsigned long disabled_mkey, disabled_auth, disabled_enc, disabled_mac, + disabled_ssl; + STACK_OF(SSL_CIPHER) *cipherstack, *tmp_cipher_list; + const char *rule_p; + CIPHER_ORDER *co_list = NULL, *head = NULL, *tail = NULL, *curr; + const SSL_CIPHER **ca_list = NULL; + + /* + * Return with error if nothing to do. + */ + if (rule_str == NULL || cipher_list == NULL || cipher_list_by_id == NULL) + return NULL; +#ifndef OPENSSL_NO_EC + if (!check_suiteb_cipher_list(ssl_method, c, &rule_str)) + return NULL; +#endif + + /* + * To reduce the work to do we only want to process the compiled + * in algorithms, so we first get the mask of disabled ciphers. + */ + ssl_cipher_get_disabled(&disabled_mkey, &disabled_auth, &disabled_enc, + &disabled_mac, &disabled_ssl); + + /* + * Now we have to collect the available ciphers from the compiled + * in ciphers. We cannot get more than the number compiled in, so + * it is used for allocation. + */ + num_of_ciphers = ssl_method->num_ciphers(); +#ifdef KSSL_DEBUG + fprintf(stderr, "ssl_create_cipher_list() for %d ciphers\n", + num_of_ciphers); +#endif /* KSSL_DEBUG */ + co_list = + (CIPHER_ORDER *)OPENSSL_malloc(sizeof(CIPHER_ORDER) * num_of_ciphers); + if (co_list == NULL) { + SSLerr(SSL_F_SSL_CREATE_CIPHER_LIST, ERR_R_MALLOC_FAILURE); + return (NULL); /* Failure */ + } + + ssl_cipher_collect_ciphers(ssl_method, num_of_ciphers, + disabled_mkey, disabled_auth, disabled_enc, + disabled_mac, disabled_ssl, co_list, &head, + &tail); + + /* Now arrange all ciphers by preference: */ + + /* + * Everything else being equal, prefer ephemeral ECDH over other key + * exchange mechanisms + */ + ssl_cipher_apply_rule(0, SSL_kEECDH, 0, 0, 0, 0, 0, CIPHER_ADD, -1, &head, + &tail); + ssl_cipher_apply_rule(0, SSL_kEECDH, 0, 0, 0, 0, 0, CIPHER_DEL, -1, &head, + &tail); + + /* AES is our preferred symmetric cipher */ + ssl_cipher_apply_rule(0, 0, 0, SSL_AES, 0, 0, 0, CIPHER_ADD, -1, &head, + &tail); + + /* Temporarily enable everything else for sorting */ + ssl_cipher_apply_rule(0, 0, 0, 0, 0, 0, 0, CIPHER_ADD, -1, &head, &tail); + + /* Low priority for MD5 */ + ssl_cipher_apply_rule(0, 0, 0, 0, SSL_MD5, 0, 0, CIPHER_ORD, -1, &head, + &tail); + + /* + * Move anonymous ciphers to the end. Usually, these will remain + * disabled. (For applications that allow them, they aren't too bad, but + * we prefer authenticated ciphers.) + */ + ssl_cipher_apply_rule(0, 0, SSL_aNULL, 0, 0, 0, 0, CIPHER_ORD, -1, &head, + &tail); + + /* Move ciphers without forward secrecy to the end */ + ssl_cipher_apply_rule(0, 0, SSL_aECDH, 0, 0, 0, 0, CIPHER_ORD, -1, &head, + &tail); + /* + * ssl_cipher_apply_rule(0, 0, SSL_aDH, 0, 0, 0, 0, CIPHER_ORD, -1, + * &head, &tail); + */ + ssl_cipher_apply_rule(0, SSL_kRSA, 0, 0, 0, 0, 0, CIPHER_ORD, -1, &head, + &tail); + ssl_cipher_apply_rule(0, SSL_kPSK, 0, 0, 0, 0, 0, CIPHER_ORD, -1, &head, + &tail); + ssl_cipher_apply_rule(0, SSL_kKRB5, 0, 0, 0, 0, 0, CIPHER_ORD, -1, &head, + &tail); + + /* RC4 is sort-of broken -- move the the end */ + ssl_cipher_apply_rule(0, 0, 0, SSL_RC4, 0, 0, 0, CIPHER_ORD, -1, &head, + &tail); + + /* + * Now sort by symmetric encryption strength. The above ordering remains + * in force within each class + */ + if (!ssl_cipher_strength_sort(&head, &tail)) { + OPENSSL_free(co_list); + return NULL; + } + + /* Now disable everything (maintaining the ordering!) */ + ssl_cipher_apply_rule(0, 0, 0, 0, 0, 0, 0, CIPHER_DEL, -1, &head, &tail); + + /* + * We also need cipher aliases for selecting based on the rule_str. + * There might be two types of entries in the rule_str: 1) names + * of ciphers themselves 2) aliases for groups of ciphers. + * For 1) we need the available ciphers and for 2) the cipher + * groups of cipher_aliases added together in one list (otherwise + * we would be happy with just the cipher_aliases table). + */ + num_of_group_aliases = sizeof(cipher_aliases) / sizeof(SSL_CIPHER); + num_of_alias_max = num_of_ciphers + num_of_group_aliases + 1; + ca_list = OPENSSL_malloc(sizeof(SSL_CIPHER *) * num_of_alias_max); + if (ca_list == NULL) { + OPENSSL_free(co_list); + SSLerr(SSL_F_SSL_CREATE_CIPHER_LIST, ERR_R_MALLOC_FAILURE); + return (NULL); /* Failure */ + } + ssl_cipher_collect_aliases(ca_list, num_of_group_aliases, + disabled_mkey, disabled_auth, disabled_enc, + disabled_mac, disabled_ssl, head); + + /* + * If the rule_string begins with DEFAULT, apply the default rule + * before using the (possibly available) additional rules. + */ + ok = 1; + rule_p = rule_str; + if (strncmp(rule_str, "DEFAULT", 7) == 0) { + ok = ssl_cipher_process_rulestr(SSL_DEFAULT_CIPHER_LIST, + &head, &tail, ca_list); + rule_p += 7; + if (*rule_p == ':') + rule_p++; + } + + if (ok && (strlen(rule_p) > 0)) + ok = ssl_cipher_process_rulestr(rule_p, &head, &tail, ca_list); + + OPENSSL_free((void *)ca_list); /* Not needed anymore */ + + if (!ok) { /* Rule processing failure */ + OPENSSL_free(co_list); + return (NULL); + } + + /* + * Allocate new "cipherstack" for the result, return with error + * if we cannot get one. + */ + if ((cipherstack = sk_SSL_CIPHER_new_null()) == NULL) { + OPENSSL_free(co_list); + return (NULL); + } + + /* + * The cipher selection for the list is done. The ciphers are added + * to the resulting precedence to the STACK_OF(SSL_CIPHER). + */ + for (curr = head; curr != NULL; curr = curr->next) { +#ifdef OPENSSL_FIPS + if (curr->active + && (!FIPS_mode() || curr->cipher->algo_strength & SSL_FIPS)) +#else + if (curr->active) +#endif + { + sk_SSL_CIPHER_push(cipherstack, curr->cipher); +#ifdef CIPHER_DEBUG + fprintf(stderr, "<%s>\n", curr->cipher->name); +#endif + } + } + OPENSSL_free(co_list); /* Not needed any longer */ + + tmp_cipher_list = sk_SSL_CIPHER_dup(cipherstack); + if (tmp_cipher_list == NULL) { + sk_SSL_CIPHER_free(cipherstack); + return NULL; + } + if (*cipher_list != NULL) + sk_SSL_CIPHER_free(*cipher_list); + *cipher_list = cipherstack; + if (*cipher_list_by_id != NULL) + sk_SSL_CIPHER_free(*cipher_list_by_id); + *cipher_list_by_id = tmp_cipher_list; + (void)sk_SSL_CIPHER_set_cmp_func(*cipher_list_by_id, + ssl_cipher_ptr_id_cmp); + + sk_SSL_CIPHER_sort(*cipher_list_by_id); + return (cipherstack); +} + +char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, int len) +{ + int is_export, pkl, kl; + const char *ver, *exp_str; + const char *kx, *au, *enc, *mac; + unsigned long alg_mkey, alg_auth, alg_enc, alg_mac, alg_ssl, alg2; +#ifdef KSSL_DEBUG + static const char *format = + "%-23s %s Kx=%-8s Au=%-4s Enc=%-9s Mac=%-4s%s AL=%lx/%lx/%lx/%lx/%lx\n"; +#else + static const char *format = + "%-23s %s Kx=%-8s Au=%-4s Enc=%-9s Mac=%-4s%s\n"; +#endif /* KSSL_DEBUG */ + + alg_mkey = cipher->algorithm_mkey; + alg_auth = cipher->algorithm_auth; + alg_enc = cipher->algorithm_enc; + alg_mac = cipher->algorithm_mac; + alg_ssl = cipher->algorithm_ssl; + + alg2 = cipher->algorithm2; + + is_export = SSL_C_IS_EXPORT(cipher); + pkl = SSL_C_EXPORT_PKEYLENGTH(cipher); + kl = SSL_C_EXPORT_KEYLENGTH(cipher); + exp_str = is_export ? " export" : ""; + + if (alg_ssl & SSL_SSLV2) + ver = "SSLv2"; + else if (alg_ssl & SSL_SSLV3) + ver = "SSLv3"; + else if (alg_ssl & SSL_TLSV1_2) + ver = "TLSv1.2"; + else + ver = "unknown"; + + switch (alg_mkey) { + case SSL_kRSA: + kx = is_export ? (pkl == 512 ? "RSA(512)" : "RSA(1024)") : "RSA"; + break; + case SSL_kDHr: + kx = "DH/RSA"; + break; + case SSL_kDHd: + kx = "DH/DSS"; + break; + case SSL_kKRB5: + kx = "KRB5"; + break; + case SSL_kEDH: + kx = is_export ? (pkl == 512 ? "DH(512)" : "DH(1024)") : "DH"; + break; + case SSL_kECDHr: + kx = "ECDH/RSA"; + break; + case SSL_kECDHe: + kx = "ECDH/ECDSA"; + break; + case SSL_kEECDH: + kx = "ECDH"; + break; + case SSL_kPSK: + kx = "PSK"; + break; + case SSL_kSRP: + kx = "SRP"; + break; + case SSL_kGOST: + kx = "GOST"; + break; + default: + kx = "unknown"; + } + + switch (alg_auth) { + case SSL_aRSA: + au = "RSA"; + break; + case SSL_aDSS: + au = "DSS"; + break; + case SSL_aDH: + au = "DH"; + break; + case SSL_aKRB5: + au = "KRB5"; + break; + case SSL_aECDH: + au = "ECDH"; + break; + case SSL_aNULL: + au = "None"; + break; + case SSL_aECDSA: + au = "ECDSA"; + break; + case SSL_aPSK: + au = "PSK"; + break; + case SSL_aSRP: + au = "SRP"; + break; + case SSL_aGOST94: + au = "GOST94"; + break; + case SSL_aGOST01: + au = "GOST01"; + break; + default: + au = "unknown"; + break; + } + + switch (alg_enc) { + case SSL_DES: + enc = (is_export && kl == 5) ? "DES(40)" : "DES(56)"; + break; + case SSL_3DES: + enc = "3DES(168)"; + break; + case SSL_RC4: + enc = is_export ? (kl == 5 ? "RC4(40)" : "RC4(56)") + : ((alg2 & SSL2_CF_8_BYTE_ENC) ? "RC4(64)" : "RC4(128)"); + break; + case SSL_RC2: + enc = is_export ? (kl == 5 ? "RC2(40)" : "RC2(56)") : "RC2(128)"; + break; + case SSL_IDEA: + enc = "IDEA(128)"; + break; + case SSL_eNULL: + enc = "None"; + break; + case SSL_AES128: + enc = "AES(128)"; + break; + case SSL_AES256: + enc = "AES(256)"; + break; + case SSL_AES128GCM: + enc = "AESGCM(128)"; + break; + case SSL_AES256GCM: + enc = "AESGCM(256)"; + break; + case SSL_CAMELLIA128: + enc = "Camellia(128)"; + break; + case SSL_CAMELLIA256: + enc = "Camellia(256)"; + break; + case SSL_SEED: + enc = "SEED(128)"; + break; + case SSL_eGOST2814789CNT: + enc = "GOST89(256)"; + break; + default: + enc = "unknown"; + break; + } + + switch (alg_mac) { + case SSL_MD5: + mac = "MD5"; + break; + case SSL_SHA1: + mac = "SHA1"; + break; + case SSL_SHA256: + mac = "SHA256"; + break; + case SSL_SHA384: + mac = "SHA384"; + break; + case SSL_AEAD: + mac = "AEAD"; + break; + case SSL_GOST89MAC: + mac = "GOST89"; + break; + case SSL_GOST94: + mac = "GOST94"; + break; + default: + mac = "unknown"; + break; + } + + if (buf == NULL) { + len = 128; + buf = OPENSSL_malloc(len); + if (buf == NULL) + return ("OPENSSL_malloc Error"); + } else if (len < 128) + return ("Buffer too small"); + +#ifdef KSSL_DEBUG + BIO_snprintf(buf, len, format, cipher->name, ver, kx, au, enc, mac, + exp_str, alg_mkey, alg_auth, alg_enc, alg_mac, alg_ssl); +#else + BIO_snprintf(buf, len, format, cipher->name, ver, kx, au, enc, mac, + exp_str); +#endif /* KSSL_DEBUG */ + return (buf); +} + +char *SSL_CIPHER_get_version(const SSL_CIPHER *c) +{ + int i; + + if (c == NULL) + return ("(NONE)"); + i = (int)(c->id >> 24L); + if (i == 3) + return ("TLSv1/SSLv3"); + else if (i == 2) + return ("SSLv2"); + else + return ("unknown"); +} + +/* return the actual cipher being used */ +const char *SSL_CIPHER_get_name(const SSL_CIPHER *c) +{ + if (c != NULL) + return (c->name); + return ("(NONE)"); +} + +/* number of bits for symmetric cipher */ +int SSL_CIPHER_get_bits(const SSL_CIPHER *c, int *alg_bits) +{ + int ret = 0; + + if (c != NULL) { + if (alg_bits != NULL) + *alg_bits = c->alg_bits; + ret = c->strength_bits; + } + return (ret); +} + +unsigned long SSL_CIPHER_get_id(const SSL_CIPHER *c) +{ + return c->id; +} + +SSL_COMP *ssl3_comp_find(STACK_OF(SSL_COMP) *sk, int n) +{ + SSL_COMP *ctmp; + int i, nn; + + if ((n == 0) || (sk == NULL)) + return (NULL); + nn = sk_SSL_COMP_num(sk); + for (i = 0; i < nn; i++) { + ctmp = sk_SSL_COMP_value(sk, i); + if (ctmp->id == n) + return (ctmp); + } + return (NULL); +} + +#ifdef OPENSSL_NO_COMP +void *SSL_COMP_get_compression_methods(void) +{ + return NULL; +} + +int SSL_COMP_add_compression_method(int id, void *cm) +{ + return 1; +} + +const char *SSL_COMP_get_name(const void *comp) +{ + return NULL; +} +#else +STACK_OF(SSL_COMP) *SSL_COMP_get_compression_methods(void) +{ + load_builtin_compressions(); + return (ssl_comp_methods); +} + +STACK_OF(SSL_COMP) *SSL_COMP_set0_compression_methods(STACK_OF(SSL_COMP) + *meths) +{ + STACK_OF(SSL_COMP) *old_meths = ssl_comp_methods; + ssl_comp_methods = meths; + return old_meths; +} + +static void cmeth_free(SSL_COMP *cm) +{ + OPENSSL_free(cm); +} + +void SSL_COMP_free_compression_methods(void) +{ + STACK_OF(SSL_COMP) *old_meths = ssl_comp_methods; + ssl_comp_methods = NULL; + sk_SSL_COMP_pop_free(old_meths, cmeth_free); +} + +int SSL_COMP_add_compression_method(int id, COMP_METHOD *cm) +{ + SSL_COMP *comp; + + if (cm == NULL || cm->type == NID_undef) + return 1; + + /*- + * According to draft-ietf-tls-compression-04.txt, the + * compression number ranges should be the following: + * + * 0 to 63: methods defined by the IETF + * 64 to 192: external party methods assigned by IANA + * 193 to 255: reserved for private use + */ + if (id < 193 || id > 255) { + SSLerr(SSL_F_SSL_COMP_ADD_COMPRESSION_METHOD, + SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE); + return 0; + } + + MemCheck_off(); + comp = (SSL_COMP *)OPENSSL_malloc(sizeof(SSL_COMP)); + comp->id = id; + comp->method = cm; + load_builtin_compressions(); + if (ssl_comp_methods && sk_SSL_COMP_find(ssl_comp_methods, comp) >= 0) { + OPENSSL_free(comp); + MemCheck_on(); + SSLerr(SSL_F_SSL_COMP_ADD_COMPRESSION_METHOD, + SSL_R_DUPLICATE_COMPRESSION_ID); + return (1); + } else if ((ssl_comp_methods == NULL) + || !sk_SSL_COMP_push(ssl_comp_methods, comp)) { + OPENSSL_free(comp); + MemCheck_on(); + SSLerr(SSL_F_SSL_COMP_ADD_COMPRESSION_METHOD, ERR_R_MALLOC_FAILURE); + return (1); + } else { + MemCheck_on(); + return (0); + } +} + +const char *SSL_COMP_get_name(const COMP_METHOD *comp) +{ + if (comp) + return comp->name; + return NULL; +} +#endif +/* For a cipher return the index corresponding to the certificate type */ +int ssl_cipher_get_cert_index(const SSL_CIPHER *c) +{ + unsigned long alg_k, alg_a; + + alg_k = c->algorithm_mkey; + alg_a = c->algorithm_auth; + + if (alg_k & (SSL_kECDHr | SSL_kECDHe)) { + /* + * we don't need to look at SSL_kEECDH since no certificate is needed + * for anon ECDH and for authenticated EECDH, the check for the auth + * algorithm will set i correctly NOTE: For ECDH-RSA, we need an ECC + * not an RSA cert but for EECDH-RSA we need an RSA cert. Placing the + * checks for SSL_kECDH before RSA checks ensures the correct cert is + * chosen. + */ + return SSL_PKEY_ECC; + } else if (alg_a & SSL_aECDSA) + return SSL_PKEY_ECC; + else if (alg_k & SSL_kDHr) + return SSL_PKEY_DH_RSA; + else if (alg_k & SSL_kDHd) + return SSL_PKEY_DH_DSA; + else if (alg_a & SSL_aDSS) + return SSL_PKEY_DSA_SIGN; + else if (alg_a & SSL_aRSA) + return SSL_PKEY_RSA_ENC; + else if (alg_a & SSL_aKRB5) + /* VRS something else here? */ + return -1; + else if (alg_a & SSL_aGOST94) + return SSL_PKEY_GOST94; + else if (alg_a & SSL_aGOST01) + return SSL_PKEY_GOST01; + return -1; +} + +const SSL_CIPHER *ssl_get_cipher_by_char(SSL *ssl, const unsigned char *ptr) +{ + const SSL_CIPHER *c; + c = ssl->method->get_cipher_by_char(ptr); + if (c == NULL || c->valid == 0) + return NULL; + return c; +} + +const SSL_CIPHER *SSL_CIPHER_find(SSL *ssl, const unsigned char *ptr) +{ + return ssl->method->get_cipher_by_char(ptr); +} diff --git a/thirdparty/openssl/ssl/ssl_conf.c b/thirdparty/openssl/ssl/ssl_conf.c new file mode 100644 index 0000000000..8d3709d2b6 --- /dev/null +++ b/thirdparty/openssl/ssl/ssl_conf.c @@ -0,0 +1,691 @@ +/* + * ! \file ssl/ssl_conf.c \brief SSL configuration functions + */ +/* ==================================================================== + * Copyright (c) 2012 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). + * + */ + +#ifdef REF_CHECK +# include <assert.h> +#endif +#include <stdio.h> +#include "ssl_locl.h" +#include <openssl/conf.h> +#include <openssl/objects.h> +#ifndef OPENSSL_NO_DH +# include <openssl/dh.h> +#endif + +/* + * structure holding name tables. This is used for pemitted elements in lists + * such as TLSv1 and single command line switches such as no_tls1 + */ + +typedef struct { + const char *name; + int namelen; + unsigned int name_flags; + unsigned long option_value; +} ssl_flag_tbl; + +/* Sense of name is inverted e.g. "TLSv1" will clear SSL_OP_NO_TLSv1 */ +#define SSL_TFLAG_INV 0x1 +/* Flags refers to cert_flags not options */ +#define SSL_TFLAG_CERT 0x2 +/* Option can only be used for clients */ +#define SSL_TFLAG_CLIENT SSL_CONF_FLAG_CLIENT +/* Option can only be used for servers */ +#define SSL_TFLAG_SERVER SSL_CONF_FLAG_SERVER +#define SSL_TFLAG_BOTH (SSL_TFLAG_CLIENT|SSL_TFLAG_SERVER) + +#define SSL_FLAG_TBL(str, flag) \ + {str, (int)(sizeof(str) - 1), SSL_TFLAG_BOTH, flag} +#define SSL_FLAG_TBL_SRV(str, flag) \ + {str, (int)(sizeof(str) - 1), SSL_TFLAG_SERVER, flag} +#define SSL_FLAG_TBL_CLI(str, flag) \ + {str, (int)(sizeof(str) - 1), SSL_TFLAG_CLIENT, flag} +#define SSL_FLAG_TBL_INV(str, flag) \ + {str, (int)(sizeof(str) - 1), SSL_TFLAG_INV|SSL_TFLAG_BOTH, flag} +#define SSL_FLAG_TBL_SRV_INV(str, flag) \ + {str, (int)(sizeof(str) - 1), SSL_TFLAG_INV|SSL_TFLAG_SERVER, flag} +#define SSL_FLAG_TBL_CERT(str, flag) \ + {str, (int)(sizeof(str) - 1), SSL_TFLAG_CERT|SSL_TFLAG_BOTH, flag} + +/* + * Opaque structure containing SSL configuration context. + */ + +struct ssl_conf_ctx_st { + /* + * Various flags indicating (among other things) which options we will + * recognise. + */ + unsigned int flags; + /* Prefix and length of commands */ + char *prefix; + size_t prefixlen; + /* SSL_CTX or SSL structure to perform operations on */ + SSL_CTX *ctx; + SSL *ssl; + /* Pointer to SSL or SSL_CTX options field or NULL if none */ + unsigned long *poptions; + /* Pointer to SSL or SSL_CTX cert_flags or NULL if none */ + unsigned int *pcert_flags; + /* Current flag table being worked on */ + const ssl_flag_tbl *tbl; + /* Size of table */ + size_t ntbl; +}; + +static int ssl_match_option(SSL_CONF_CTX *cctx, const ssl_flag_tbl *tbl, + const char *name, int namelen, int onoff) +{ + /* If name not relevant for context skip */ + if (!(cctx->flags & tbl->name_flags & SSL_TFLAG_BOTH)) + return 0; + if (namelen == -1) { + if (strcmp(tbl->name, name)) + return 0; + } else if (tbl->namelen != namelen + || strncasecmp(tbl->name, name, namelen)) + return 0; + if (cctx->poptions) { + if (tbl->name_flags & SSL_TFLAG_INV) + onoff ^= 1; + if (tbl->name_flags & SSL_TFLAG_CERT) { + if (onoff) + *cctx->pcert_flags |= tbl->option_value; + else + *cctx->pcert_flags &= ~tbl->option_value; + } else { + if (onoff) + *cctx->poptions |= tbl->option_value; + else + *cctx->poptions &= ~tbl->option_value; + } + } + return 1; +} + +static int ssl_set_option_list(const char *elem, int len, void *usr) +{ + SSL_CONF_CTX *cctx = usr; + size_t i; + const ssl_flag_tbl *tbl; + int onoff = 1; + /* + * len == -1 indicates not being called in list context, just for single + * command line switches, so don't allow +, -. + */ + if (elem == NULL) + return 0; + if (len != -1) { + if (*elem == '+') { + elem++; + len--; + onoff = 1; + } else if (*elem == '-') { + elem++; + len--; + onoff = 0; + } + } + for (i = 0, tbl = cctx->tbl; i < cctx->ntbl; i++, tbl++) { + if (ssl_match_option(cctx, tbl, elem, len, onoff)) + return 1; + } + return 0; +} + +/* Single command line switches with no argument e.g. -no_ssl3 */ +static int ctrl_str_option(SSL_CONF_CTX *cctx, const char *cmd) +{ + static const ssl_flag_tbl ssl_option_single[] = { + SSL_FLAG_TBL("no_ssl2", SSL_OP_NO_SSLv2), + SSL_FLAG_TBL("no_ssl3", SSL_OP_NO_SSLv3), + SSL_FLAG_TBL("no_tls1", SSL_OP_NO_TLSv1), + SSL_FLAG_TBL("no_tls1_1", SSL_OP_NO_TLSv1_1), + SSL_FLAG_TBL("no_tls1_2", SSL_OP_NO_TLSv1_2), + SSL_FLAG_TBL("bugs", SSL_OP_ALL), + SSL_FLAG_TBL("no_comp", SSL_OP_NO_COMPRESSION), + SSL_FLAG_TBL_SRV("ecdh_single", SSL_OP_SINGLE_ECDH_USE), +#ifndef OPENSSL_NO_TLSEXT + SSL_FLAG_TBL("no_ticket", SSL_OP_NO_TICKET), +#endif + SSL_FLAG_TBL_SRV("serverpref", SSL_OP_CIPHER_SERVER_PREFERENCE), + SSL_FLAG_TBL("legacy_renegotiation", + SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION), + SSL_FLAG_TBL_SRV("legacy_server_connect", + SSL_OP_LEGACY_SERVER_CONNECT), + SSL_FLAG_TBL_SRV("no_resumption_on_reneg", + SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION), + SSL_FLAG_TBL_SRV_INV("no_legacy_server_connect", + SSL_OP_LEGACY_SERVER_CONNECT), + SSL_FLAG_TBL_CERT("strict", SSL_CERT_FLAG_TLS_STRICT), +#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL + SSL_FLAG_TBL_CERT("debug_broken_protocol", + SSL_CERT_FLAG_BROKEN_PROTOCOL), +#endif + }; + cctx->tbl = ssl_option_single; + cctx->ntbl = sizeof(ssl_option_single) / sizeof(ssl_flag_tbl); + return ssl_set_option_list(cmd, -1, cctx); +} + +/* Set supported signature algorithms */ +static int cmd_SignatureAlgorithms(SSL_CONF_CTX *cctx, const char *value) +{ + int rv; + if (cctx->ssl) + rv = SSL_set1_sigalgs_list(cctx->ssl, value); + /* NB: ctx == NULL performs syntax checking only */ + else + rv = SSL_CTX_set1_sigalgs_list(cctx->ctx, value); + return rv > 0; +} + +/* Set supported client signature algorithms */ +static int cmd_ClientSignatureAlgorithms(SSL_CONF_CTX *cctx, + const char *value) +{ + int rv; + if (cctx->ssl) + rv = SSL_set1_client_sigalgs_list(cctx->ssl, value); + /* NB: ctx == NULL performs syntax checking only */ + else + rv = SSL_CTX_set1_client_sigalgs_list(cctx->ctx, value); + return rv > 0; +} + +static int cmd_Curves(SSL_CONF_CTX *cctx, const char *value) +{ + int rv; + if (cctx->ssl) + rv = SSL_set1_curves_list(cctx->ssl, value); + /* NB: ctx == NULL performs syntax checking only */ + else + rv = SSL_CTX_set1_curves_list(cctx->ctx, value); + return rv > 0; +} + +#ifndef OPENSSL_NO_ECDH +/* ECDH temporary parameters */ +static int cmd_ECDHParameters(SSL_CONF_CTX *cctx, const char *value) +{ + int onoff = -1, rv = 1; + if (!(cctx->flags & SSL_CONF_FLAG_SERVER)) + return -2; + if (cctx->flags & SSL_CONF_FLAG_FILE) { + if (*value == '+') { + onoff = 1; + value++; + } + if (*value == '-') { + onoff = 0; + value++; + } + if (!strcasecmp(value, "automatic")) { + if (onoff == -1) + onoff = 1; + } else if (onoff != -1) + return 0; + } else if (cctx->flags & SSL_CONF_FLAG_CMDLINE) { + if (!strcmp(value, "auto")) + onoff = 1; + } + + if (onoff != -1) { + if (cctx->ctx) + rv = SSL_CTX_set_ecdh_auto(cctx->ctx, onoff); + else if (cctx->ssl) + rv = SSL_set_ecdh_auto(cctx->ssl, onoff); + } else { + EC_KEY *ecdh; + int nid; + nid = EC_curve_nist2nid(value); + if (nid == NID_undef) + nid = OBJ_sn2nid(value); + if (nid == 0) + return 0; + ecdh = EC_KEY_new_by_curve_name(nid); + if (!ecdh) + return 0; + if (cctx->ctx) + rv = SSL_CTX_set_tmp_ecdh(cctx->ctx, ecdh); + else if (cctx->ssl) + rv = SSL_set_tmp_ecdh(cctx->ssl, ecdh); + EC_KEY_free(ecdh); + } + + return rv > 0; +} +#endif +static int cmd_CipherString(SSL_CONF_CTX *cctx, const char *value) +{ + int rv = 1; + if (cctx->ctx) + rv = SSL_CTX_set_cipher_list(cctx->ctx, value); + if (cctx->ssl) + rv = SSL_set_cipher_list(cctx->ssl, value); + return rv > 0; +} + +static int cmd_Protocol(SSL_CONF_CTX *cctx, const char *value) +{ + static const ssl_flag_tbl ssl_protocol_list[] = { + SSL_FLAG_TBL_INV("ALL", SSL_OP_NO_SSL_MASK), + SSL_FLAG_TBL_INV("SSLv2", SSL_OP_NO_SSLv2), + SSL_FLAG_TBL_INV("SSLv3", SSL_OP_NO_SSLv3), + SSL_FLAG_TBL_INV("TLSv1", SSL_OP_NO_TLSv1), + SSL_FLAG_TBL_INV("TLSv1.1", SSL_OP_NO_TLSv1_1), + SSL_FLAG_TBL_INV("TLSv1.2", SSL_OP_NO_TLSv1_2) + }; + int ret; + int sslv2off; + + if (!(cctx->flags & SSL_CONF_FLAG_FILE)) + return -2; + cctx->tbl = ssl_protocol_list; + cctx->ntbl = sizeof(ssl_protocol_list) / sizeof(ssl_flag_tbl); + + sslv2off = *cctx->poptions & SSL_OP_NO_SSLv2; + ret = CONF_parse_list(value, ',', 1, ssl_set_option_list, cctx); + /* Never turn on SSLv2 through configuration */ + *cctx->poptions |= sslv2off; + return ret; +} + +static int cmd_Options(SSL_CONF_CTX *cctx, const char *value) +{ + static const ssl_flag_tbl ssl_option_list[] = { + SSL_FLAG_TBL_INV("SessionTicket", SSL_OP_NO_TICKET), + SSL_FLAG_TBL_INV("EmptyFragments", + SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS), + SSL_FLAG_TBL("Bugs", SSL_OP_ALL), + SSL_FLAG_TBL_INV("Compression", SSL_OP_NO_COMPRESSION), + SSL_FLAG_TBL_SRV("ServerPreference", SSL_OP_CIPHER_SERVER_PREFERENCE), + SSL_FLAG_TBL_SRV("NoResumptionOnRenegotiation", + SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION), + SSL_FLAG_TBL_SRV("DHSingle", SSL_OP_SINGLE_DH_USE), + SSL_FLAG_TBL_SRV("ECDHSingle", SSL_OP_SINGLE_ECDH_USE), + SSL_FLAG_TBL("UnsafeLegacyRenegotiation", + SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION), + }; + if (!(cctx->flags & SSL_CONF_FLAG_FILE)) + return -2; + if (value == NULL) + return -3; + cctx->tbl = ssl_option_list; + cctx->ntbl = sizeof(ssl_option_list) / sizeof(ssl_flag_tbl); + return CONF_parse_list(value, ',', 1, ssl_set_option_list, cctx); +} + +static int cmd_Certificate(SSL_CONF_CTX *cctx, const char *value) +{ + int rv = 1; + if (!(cctx->flags & SSL_CONF_FLAG_CERTIFICATE)) + return -2; + if (cctx->ctx) + rv = SSL_CTX_use_certificate_chain_file(cctx->ctx, value); + if (cctx->ssl) + rv = SSL_use_certificate_file(cctx->ssl, value, SSL_FILETYPE_PEM); + return rv > 0; +} + +static int cmd_PrivateKey(SSL_CONF_CTX *cctx, const char *value) +{ + int rv = 1; + if (!(cctx->flags & SSL_CONF_FLAG_CERTIFICATE)) + return -2; + if (cctx->ctx) + rv = SSL_CTX_use_PrivateKey_file(cctx->ctx, value, SSL_FILETYPE_PEM); + if (cctx->ssl) + rv = SSL_use_PrivateKey_file(cctx->ssl, value, SSL_FILETYPE_PEM); + return rv > 0; +} + +static int cmd_ServerInfoFile(SSL_CONF_CTX *cctx, const char *value) +{ + int rv = 1; + if (!(cctx->flags & SSL_CONF_FLAG_CERTIFICATE)) + return -2; + if (!(cctx->flags & SSL_CONF_FLAG_SERVER)) + return -2; + if (cctx->ctx) + rv = SSL_CTX_use_serverinfo_file(cctx->ctx, value); + return rv > 0; +} + +#ifndef OPENSSL_NO_DH +static int cmd_DHParameters(SSL_CONF_CTX *cctx, const char *value) +{ + int rv = 0; + DH *dh = NULL; + BIO *in = NULL; + if (!(cctx->flags & SSL_CONF_FLAG_CERTIFICATE)) + return -2; + if (cctx->ctx || cctx->ssl) { + in = BIO_new(BIO_s_file_internal()); + if (!in) + goto end; + if (BIO_read_filename(in, value) <= 0) + goto end; + dh = PEM_read_bio_DHparams(in, NULL, NULL, NULL); + if (!dh) + goto end; + } else + return 1; + if (cctx->ctx) + rv = SSL_CTX_set_tmp_dh(cctx->ctx, dh); + if (cctx->ssl) + rv = SSL_set_tmp_dh(cctx->ssl, dh); + end: + if (dh) + DH_free(dh); + if (in) + BIO_free(in); + return rv > 0; +} +#endif +typedef struct { + int (*cmd) (SSL_CONF_CTX *cctx, const char *value); + const char *str_file; + const char *str_cmdline; + unsigned int value_type; +} ssl_conf_cmd_tbl; + +/* Table of supported parameters */ + +#define SSL_CONF_CMD(name, cmdopt, type) \ + {cmd_##name, #name, cmdopt, type} + +#define SSL_CONF_CMD_STRING(name, cmdopt) \ + SSL_CONF_CMD(name, cmdopt, SSL_CONF_TYPE_STRING) + +static const ssl_conf_cmd_tbl ssl_conf_cmds[] = { + SSL_CONF_CMD_STRING(SignatureAlgorithms, "sigalgs"), + SSL_CONF_CMD_STRING(ClientSignatureAlgorithms, "client_sigalgs"), + SSL_CONF_CMD_STRING(Curves, "curves"), +#ifndef OPENSSL_NO_ECDH + SSL_CONF_CMD_STRING(ECDHParameters, "named_curve"), +#endif + SSL_CONF_CMD_STRING(CipherString, "cipher"), + SSL_CONF_CMD_STRING(Protocol, NULL), + SSL_CONF_CMD_STRING(Options, NULL), + SSL_CONF_CMD(Certificate, "cert", SSL_CONF_TYPE_FILE), + SSL_CONF_CMD(PrivateKey, "key", SSL_CONF_TYPE_FILE), + SSL_CONF_CMD(ServerInfoFile, NULL, SSL_CONF_TYPE_FILE), +#ifndef OPENSSL_NO_DH + SSL_CONF_CMD(DHParameters, "dhparam", SSL_CONF_TYPE_FILE) +#endif +}; + +static int ssl_conf_cmd_skip_prefix(SSL_CONF_CTX *cctx, const char **pcmd) +{ + if (!pcmd || !*pcmd) + return 0; + /* If a prefix is set, check and skip */ + if (cctx->prefix) { + if (strlen(*pcmd) <= cctx->prefixlen) + return 0; + if (cctx->flags & SSL_CONF_FLAG_CMDLINE && + strncmp(*pcmd, cctx->prefix, cctx->prefixlen)) + return 0; + if (cctx->flags & SSL_CONF_FLAG_FILE && + strncasecmp(*pcmd, cctx->prefix, cctx->prefixlen)) + return 0; + *pcmd += cctx->prefixlen; + } else if (cctx->flags & SSL_CONF_FLAG_CMDLINE) { + if (**pcmd != '-' || !(*pcmd)[1]) + return 0; + *pcmd += 1; + } + return 1; +} + +static const ssl_conf_cmd_tbl *ssl_conf_cmd_lookup(SSL_CONF_CTX *cctx, + const char *cmd) +{ + const ssl_conf_cmd_tbl *t; + size_t i; + if (cmd == NULL) + return NULL; + + /* Look for matching parameter name in table */ + for (i = 0, t = ssl_conf_cmds; + i < sizeof(ssl_conf_cmds) / sizeof(ssl_conf_cmd_tbl); i++, t++) { + if (cctx->flags & SSL_CONF_FLAG_CMDLINE) { + if (t->str_cmdline && !strcmp(t->str_cmdline, cmd)) + return t; + } + if (cctx->flags & SSL_CONF_FLAG_FILE) { + if (t->str_file && !strcasecmp(t->str_file, cmd)) + return t; + } + } + return NULL; +} + +int SSL_CONF_cmd(SSL_CONF_CTX *cctx, const char *cmd, const char *value) +{ + const ssl_conf_cmd_tbl *runcmd; + if (cmd == NULL) { + SSLerr(SSL_F_SSL_CONF_CMD, SSL_R_INVALID_NULL_CMD_NAME); + return 0; + } + + if (!ssl_conf_cmd_skip_prefix(cctx, &cmd)) + return -2; + + runcmd = ssl_conf_cmd_lookup(cctx, cmd); + + if (runcmd) { + int rv; + if (value == NULL) + return -3; + rv = runcmd->cmd(cctx, value); + if (rv > 0) + return 2; + if (rv == -2) + return -2; + if (cctx->flags & SSL_CONF_FLAG_SHOW_ERRORS) { + SSLerr(SSL_F_SSL_CONF_CMD, SSL_R_BAD_VALUE); + ERR_add_error_data(4, "cmd=", cmd, ", value=", value); + } + return 0; + } + + if (cctx->flags & SSL_CONF_FLAG_CMDLINE) { + if (ctrl_str_option(cctx, cmd)) + return 1; + } + + if (cctx->flags & SSL_CONF_FLAG_SHOW_ERRORS) { + SSLerr(SSL_F_SSL_CONF_CMD, SSL_R_UNKNOWN_CMD_NAME); + ERR_add_error_data(2, "cmd=", cmd); + } + + return -2; +} + +int SSL_CONF_cmd_argv(SSL_CONF_CTX *cctx, int *pargc, char ***pargv) +{ + int rv; + const char *arg = NULL, *argn; + if (pargc && *pargc == 0) + return 0; + if (!pargc || *pargc > 0) + arg = **pargv; + if (arg == NULL) + return 0; + if (!pargc || *pargc > 1) + argn = (*pargv)[1]; + else + argn = NULL; + cctx->flags &= ~SSL_CONF_FLAG_FILE; + cctx->flags |= SSL_CONF_FLAG_CMDLINE; + rv = SSL_CONF_cmd(cctx, arg, argn); + if (rv > 0) { + /* Success: update pargc, pargv */ + (*pargv) += rv; + if (pargc) + (*pargc) -= rv; + return rv; + } + /* Unknown switch: indicate no arguments processed */ + if (rv == -2) + return 0; + /* Some error occurred processing command, return fatal error */ + if (rv == 0) + return -1; + return rv; +} + +int SSL_CONF_cmd_value_type(SSL_CONF_CTX *cctx, const char *cmd) +{ + if (ssl_conf_cmd_skip_prefix(cctx, &cmd)) { + const ssl_conf_cmd_tbl *runcmd; + runcmd = ssl_conf_cmd_lookup(cctx, cmd); + if (runcmd) + return runcmd->value_type; + } + return SSL_CONF_TYPE_UNKNOWN; +} + +SSL_CONF_CTX *SSL_CONF_CTX_new(void) +{ + SSL_CONF_CTX *ret; + ret = OPENSSL_malloc(sizeof(SSL_CONF_CTX)); + if (ret) { + ret->flags = 0; + ret->prefix = NULL; + ret->prefixlen = 0; + ret->ssl = NULL; + ret->ctx = NULL; + ret->poptions = NULL; + ret->pcert_flags = NULL; + ret->tbl = NULL; + ret->ntbl = 0; + } + return ret; +} + +int SSL_CONF_CTX_finish(SSL_CONF_CTX *cctx) +{ + return 1; +} + +void SSL_CONF_CTX_free(SSL_CONF_CTX *cctx) +{ + if (cctx) { + if (cctx->prefix) + OPENSSL_free(cctx->prefix); + OPENSSL_free(cctx); + } +} + +unsigned int SSL_CONF_CTX_set_flags(SSL_CONF_CTX *cctx, unsigned int flags) +{ + cctx->flags |= flags; + return cctx->flags; +} + +unsigned int SSL_CONF_CTX_clear_flags(SSL_CONF_CTX *cctx, unsigned int flags) +{ + cctx->flags &= ~flags; + return cctx->flags; +} + +int SSL_CONF_CTX_set1_prefix(SSL_CONF_CTX *cctx, const char *pre) +{ + char *tmp = NULL; + if (pre) { + tmp = BUF_strdup(pre); + if (tmp == NULL) + return 0; + } + if (cctx->prefix) + OPENSSL_free(cctx->prefix); + cctx->prefix = tmp; + if (tmp) + cctx->prefixlen = strlen(tmp); + else + cctx->prefixlen = 0; + return 1; +} + +void SSL_CONF_CTX_set_ssl(SSL_CONF_CTX *cctx, SSL *ssl) +{ + cctx->ssl = ssl; + cctx->ctx = NULL; + if (ssl) { + cctx->poptions = &ssl->options; + cctx->pcert_flags = &ssl->cert->cert_flags; + } else { + cctx->poptions = NULL; + cctx->pcert_flags = NULL; + } +} + +void SSL_CONF_CTX_set_ssl_ctx(SSL_CONF_CTX *cctx, SSL_CTX *ctx) +{ + cctx->ctx = ctx; + cctx->ssl = NULL; + if (ctx) { + cctx->poptions = &ctx->options; + cctx->pcert_flags = &ctx->cert->cert_flags; + } else { + cctx->poptions = NULL; + cctx->pcert_flags = NULL; + } +} diff --git a/thirdparty/openssl/ssl/ssl_err.c b/thirdparty/openssl/ssl/ssl_err.c new file mode 100644 index 0000000000..704088dc46 --- /dev/null +++ b/thirdparty/openssl/ssl/ssl_err.c @@ -0,0 +1,837 @@ +/* ssl/ssl_err.c */ +/* ==================================================================== + * Copyright (c) 1999-2015 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). + * + */ + +/* + * NOTE: this file was auto generated by the mkerr.pl script: any changes + * made to it will be overwritten when the script next updates this file, + * only reason strings will be preserved. + */ + +#include <stdio.h> +#include <openssl/err.h> +#include <openssl/ssl.h> + +/* BEGIN ERROR CODES */ +#ifndef OPENSSL_NO_ERR + +# define ERR_FUNC(func) ERR_PACK(ERR_LIB_SSL,func,0) +# define ERR_REASON(reason) ERR_PACK(ERR_LIB_SSL,0,reason) + +static ERR_STRING_DATA SSL_str_functs[] = { + {ERR_FUNC(SSL_F_CHECK_SUITEB_CIPHER_LIST), "CHECK_SUITEB_CIPHER_LIST"}, + {ERR_FUNC(SSL_F_CLIENT_CERTIFICATE), "CLIENT_CERTIFICATE"}, + {ERR_FUNC(SSL_F_CLIENT_FINISHED), "CLIENT_FINISHED"}, + {ERR_FUNC(SSL_F_CLIENT_HELLO), "CLIENT_HELLO"}, + {ERR_FUNC(SSL_F_CLIENT_MASTER_KEY), "CLIENT_MASTER_KEY"}, + {ERR_FUNC(SSL_F_D2I_SSL_SESSION), "d2i_SSL_SESSION"}, + {ERR_FUNC(SSL_F_DO_DTLS1_WRITE), "do_dtls1_write"}, + {ERR_FUNC(SSL_F_DO_SSL3_WRITE), "DO_SSL3_WRITE"}, + {ERR_FUNC(SSL_F_DTLS1_ACCEPT), "dtls1_accept"}, + {ERR_FUNC(SSL_F_DTLS1_ADD_CERT_TO_BUF), "DTLS1_ADD_CERT_TO_BUF"}, + {ERR_FUNC(SSL_F_DTLS1_BUFFER_RECORD), "DTLS1_BUFFER_RECORD"}, + {ERR_FUNC(SSL_F_DTLS1_CHECK_TIMEOUT_NUM), "dtls1_check_timeout_num"}, + {ERR_FUNC(SSL_F_DTLS1_CLIENT_HELLO), "dtls1_client_hello"}, + {ERR_FUNC(SSL_F_DTLS1_CONNECT), "dtls1_connect"}, + {ERR_FUNC(SSL_F_DTLS1_GET_HELLO_VERIFY), "DTLS1_GET_HELLO_VERIFY"}, + {ERR_FUNC(SSL_F_DTLS1_GET_MESSAGE), "dtls1_get_message"}, + {ERR_FUNC(SSL_F_DTLS1_GET_MESSAGE_FRAGMENT), + "DTLS1_GET_MESSAGE_FRAGMENT"}, + {ERR_FUNC(SSL_F_DTLS1_GET_RECORD), "dtls1_get_record"}, + {ERR_FUNC(SSL_F_DTLS1_HANDLE_TIMEOUT), "dtls1_handle_timeout"}, + {ERR_FUNC(SSL_F_DTLS1_HEARTBEAT), "dtls1_heartbeat"}, + {ERR_FUNC(SSL_F_DTLS1_OUTPUT_CERT_CHAIN), "dtls1_output_cert_chain"}, + {ERR_FUNC(SSL_F_DTLS1_PREPROCESS_FRAGMENT), "DTLS1_PREPROCESS_FRAGMENT"}, + {ERR_FUNC(SSL_F_DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE), + "DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE"}, + {ERR_FUNC(SSL_F_DTLS1_PROCESS_RECORD), "DTLS1_PROCESS_RECORD"}, + {ERR_FUNC(SSL_F_DTLS1_READ_BYTES), "dtls1_read_bytes"}, + {ERR_FUNC(SSL_F_DTLS1_READ_FAILED), "dtls1_read_failed"}, + {ERR_FUNC(SSL_F_DTLS1_SEND_CERTIFICATE_REQUEST), + "dtls1_send_certificate_request"}, + {ERR_FUNC(SSL_F_DTLS1_SEND_CLIENT_CERTIFICATE), + "dtls1_send_client_certificate"}, + {ERR_FUNC(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE), + "dtls1_send_client_key_exchange"}, + {ERR_FUNC(SSL_F_DTLS1_SEND_CLIENT_VERIFY), "dtls1_send_client_verify"}, + {ERR_FUNC(SSL_F_DTLS1_SEND_HELLO_VERIFY_REQUEST), + "DTLS1_SEND_HELLO_VERIFY_REQUEST"}, + {ERR_FUNC(SSL_F_DTLS1_SEND_SERVER_CERTIFICATE), + "dtls1_send_server_certificate"}, + {ERR_FUNC(SSL_F_DTLS1_SEND_SERVER_HELLO), "dtls1_send_server_hello"}, + {ERR_FUNC(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE), + "dtls1_send_server_key_exchange"}, + {ERR_FUNC(SSL_F_DTLS1_WRITE_APP_DATA_BYTES), + "dtls1_write_app_data_bytes"}, + {ERR_FUNC(SSL_F_GET_CLIENT_FINISHED), "GET_CLIENT_FINISHED"}, + {ERR_FUNC(SSL_F_GET_CLIENT_HELLO), "GET_CLIENT_HELLO"}, + {ERR_FUNC(SSL_F_GET_CLIENT_MASTER_KEY), "GET_CLIENT_MASTER_KEY"}, + {ERR_FUNC(SSL_F_GET_SERVER_FINISHED), "GET_SERVER_FINISHED"}, + {ERR_FUNC(SSL_F_GET_SERVER_HELLO), "GET_SERVER_HELLO"}, + {ERR_FUNC(SSL_F_GET_SERVER_STATIC_DH_KEY), "GET_SERVER_STATIC_DH_KEY"}, + {ERR_FUNC(SSL_F_GET_SERVER_VERIFY), "GET_SERVER_VERIFY"}, + {ERR_FUNC(SSL_F_I2D_SSL_SESSION), "i2d_SSL_SESSION"}, + {ERR_FUNC(SSL_F_READ_N), "READ_N"}, + {ERR_FUNC(SSL_F_REQUEST_CERTIFICATE), "REQUEST_CERTIFICATE"}, + {ERR_FUNC(SSL_F_SERVER_FINISH), "SERVER_FINISH"}, + {ERR_FUNC(SSL_F_SERVER_HELLO), "SERVER_HELLO"}, + {ERR_FUNC(SSL_F_SERVER_VERIFY), "SERVER_VERIFY"}, + {ERR_FUNC(SSL_F_SSL23_ACCEPT), "ssl23_accept"}, + {ERR_FUNC(SSL_F_SSL23_CLIENT_HELLO), "SSL23_CLIENT_HELLO"}, + {ERR_FUNC(SSL_F_SSL23_CONNECT), "ssl23_connect"}, + {ERR_FUNC(SSL_F_SSL23_GET_CLIENT_HELLO), "SSL23_GET_CLIENT_HELLO"}, + {ERR_FUNC(SSL_F_SSL23_GET_SERVER_HELLO), "SSL23_GET_SERVER_HELLO"}, + {ERR_FUNC(SSL_F_SSL23_PEEK), "ssl23_peek"}, + {ERR_FUNC(SSL_F_SSL23_READ), "ssl23_read"}, + {ERR_FUNC(SSL_F_SSL23_WRITE), "ssl23_write"}, + {ERR_FUNC(SSL_F_SSL2_ACCEPT), "ssl2_accept"}, + {ERR_FUNC(SSL_F_SSL2_CONNECT), "ssl2_connect"}, + {ERR_FUNC(SSL_F_SSL2_ENC_INIT), "ssl2_enc_init"}, + {ERR_FUNC(SSL_F_SSL2_GENERATE_KEY_MATERIAL), + "ssl2_generate_key_material"}, + {ERR_FUNC(SSL_F_SSL2_PEEK), "ssl2_peek"}, + {ERR_FUNC(SSL_F_SSL2_READ), "ssl2_read"}, + {ERR_FUNC(SSL_F_SSL2_READ_INTERNAL), "SSL2_READ_INTERNAL"}, + {ERR_FUNC(SSL_F_SSL2_SET_CERTIFICATE), "ssl2_set_certificate"}, + {ERR_FUNC(SSL_F_SSL2_WRITE), "ssl2_write"}, + {ERR_FUNC(SSL_F_SSL3_ACCEPT), "ssl3_accept"}, + {ERR_FUNC(SSL_F_SSL3_ADD_CERT_TO_BUF), "SSL3_ADD_CERT_TO_BUF"}, + {ERR_FUNC(SSL_F_SSL3_CALLBACK_CTRL), "ssl3_callback_ctrl"}, + {ERR_FUNC(SSL_F_SSL3_CHANGE_CIPHER_STATE), "ssl3_change_cipher_state"}, + {ERR_FUNC(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM), + "ssl3_check_cert_and_algorithm"}, + {ERR_FUNC(SSL_F_SSL3_CHECK_CLIENT_HELLO), "ssl3_check_client_hello"}, + {ERR_FUNC(SSL_F_SSL3_CHECK_FINISHED), "SSL3_CHECK_FINISHED"}, + {ERR_FUNC(SSL_F_SSL3_CLIENT_HELLO), "ssl3_client_hello"}, + {ERR_FUNC(SSL_F_SSL3_CONNECT), "ssl3_connect"}, + {ERR_FUNC(SSL_F_SSL3_CTRL), "ssl3_ctrl"}, + {ERR_FUNC(SSL_F_SSL3_CTX_CTRL), "ssl3_ctx_ctrl"}, + {ERR_FUNC(SSL_F_SSL3_DIGEST_CACHED_RECORDS), + "ssl3_digest_cached_records"}, + {ERR_FUNC(SSL_F_SSL3_DO_CHANGE_CIPHER_SPEC), + "ssl3_do_change_cipher_spec"}, + {ERR_FUNC(SSL_F_SSL3_ENC), "ssl3_enc"}, + {ERR_FUNC(SSL_F_SSL3_GENERATE_KEY_BLOCK), "SSL3_GENERATE_KEY_BLOCK"}, + {ERR_FUNC(SSL_F_SSL3_GENERATE_MASTER_SECRET), + "ssl3_generate_master_secret"}, + {ERR_FUNC(SSL_F_SSL3_GET_CERTIFICATE_REQUEST), + "ssl3_get_certificate_request"}, + {ERR_FUNC(SSL_F_SSL3_GET_CERT_STATUS), "ssl3_get_cert_status"}, + {ERR_FUNC(SSL_F_SSL3_GET_CERT_VERIFY), "ssl3_get_cert_verify"}, + {ERR_FUNC(SSL_F_SSL3_GET_CLIENT_CERTIFICATE), + "ssl3_get_client_certificate"}, + {ERR_FUNC(SSL_F_SSL3_GET_CLIENT_HELLO), "ssl3_get_client_hello"}, + {ERR_FUNC(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE), + "ssl3_get_client_key_exchange"}, + {ERR_FUNC(SSL_F_SSL3_GET_FINISHED), "ssl3_get_finished"}, + {ERR_FUNC(SSL_F_SSL3_GET_KEY_EXCHANGE), "ssl3_get_key_exchange"}, + {ERR_FUNC(SSL_F_SSL3_GET_MESSAGE), "ssl3_get_message"}, + {ERR_FUNC(SSL_F_SSL3_GET_NEW_SESSION_TICKET), + "ssl3_get_new_session_ticket"}, + {ERR_FUNC(SSL_F_SSL3_GET_NEXT_PROTO), "ssl3_get_next_proto"}, + {ERR_FUNC(SSL_F_SSL3_GET_RECORD), "SSL3_GET_RECORD"}, + {ERR_FUNC(SSL_F_SSL3_GET_SERVER_CERTIFICATE), + "ssl3_get_server_certificate"}, + {ERR_FUNC(SSL_F_SSL3_GET_SERVER_DONE), "ssl3_get_server_done"}, + {ERR_FUNC(SSL_F_SSL3_GET_SERVER_HELLO), "ssl3_get_server_hello"}, + {ERR_FUNC(SSL_F_SSL3_HANDSHAKE_MAC), "ssl3_handshake_mac"}, + {ERR_FUNC(SSL_F_SSL3_NEW_SESSION_TICKET), "SSL3_NEW_SESSION_TICKET"}, + {ERR_FUNC(SSL_F_SSL3_OUTPUT_CERT_CHAIN), "ssl3_output_cert_chain"}, + {ERR_FUNC(SSL_F_SSL3_PEEK), "ssl3_peek"}, + {ERR_FUNC(SSL_F_SSL3_READ_BYTES), "ssl3_read_bytes"}, + {ERR_FUNC(SSL_F_SSL3_READ_N), "ssl3_read_n"}, + {ERR_FUNC(SSL_F_SSL3_SEND_CERTIFICATE_REQUEST), + "ssl3_send_certificate_request"}, + {ERR_FUNC(SSL_F_SSL3_SEND_CLIENT_CERTIFICATE), + "ssl3_send_client_certificate"}, + {ERR_FUNC(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE), + "ssl3_send_client_key_exchange"}, + {ERR_FUNC(SSL_F_SSL3_SEND_CLIENT_VERIFY), "ssl3_send_client_verify"}, + {ERR_FUNC(SSL_F_SSL3_SEND_SERVER_CERTIFICATE), + "ssl3_send_server_certificate"}, + {ERR_FUNC(SSL_F_SSL3_SEND_SERVER_HELLO), "ssl3_send_server_hello"}, + {ERR_FUNC(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE), + "ssl3_send_server_key_exchange"}, + {ERR_FUNC(SSL_F_SSL3_SETUP_KEY_BLOCK), "ssl3_setup_key_block"}, + {ERR_FUNC(SSL_F_SSL3_SETUP_READ_BUFFER), "ssl3_setup_read_buffer"}, + {ERR_FUNC(SSL_F_SSL3_SETUP_WRITE_BUFFER), "ssl3_setup_write_buffer"}, + {ERR_FUNC(SSL_F_SSL3_WRITE_BYTES), "ssl3_write_bytes"}, + {ERR_FUNC(SSL_F_SSL3_WRITE_PENDING), "ssl3_write_pending"}, + {ERR_FUNC(SSL_F_SSL_ADD_CERT_CHAIN), "ssl_add_cert_chain"}, + {ERR_FUNC(SSL_F_SSL_ADD_CERT_TO_BUF), "SSL_ADD_CERT_TO_BUF"}, + {ERR_FUNC(SSL_F_SSL_ADD_CLIENTHELLO_RENEGOTIATE_EXT), + "ssl_add_clienthello_renegotiate_ext"}, + {ERR_FUNC(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT), + "ssl_add_clienthello_tlsext"}, + {ERR_FUNC(SSL_F_SSL_ADD_CLIENTHELLO_USE_SRTP_EXT), + "ssl_add_clienthello_use_srtp_ext"}, + {ERR_FUNC(SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK), + "SSL_add_dir_cert_subjects_to_stack"}, + {ERR_FUNC(SSL_F_SSL_ADD_FILE_CERT_SUBJECTS_TO_STACK), + "SSL_add_file_cert_subjects_to_stack"}, + {ERR_FUNC(SSL_F_SSL_ADD_SERVERHELLO_RENEGOTIATE_EXT), + "ssl_add_serverhello_renegotiate_ext"}, + {ERR_FUNC(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT), + "ssl_add_serverhello_tlsext"}, + {ERR_FUNC(SSL_F_SSL_ADD_SERVERHELLO_USE_SRTP_EXT), + "ssl_add_serverhello_use_srtp_ext"}, + {ERR_FUNC(SSL_F_SSL_BAD_METHOD), "ssl_bad_method"}, + {ERR_FUNC(SSL_F_SSL_BUILD_CERT_CHAIN), "ssl_build_cert_chain"}, + {ERR_FUNC(SSL_F_SSL_BYTES_TO_CIPHER_LIST), "ssl_bytes_to_cipher_list"}, + {ERR_FUNC(SSL_F_SSL_CERT_DUP), "ssl_cert_dup"}, + {ERR_FUNC(SSL_F_SSL_CERT_INST), "ssl_cert_inst"}, + {ERR_FUNC(SSL_F_SSL_CERT_INSTANTIATE), "SSL_CERT_INSTANTIATE"}, + {ERR_FUNC(SSL_F_SSL_CERT_NEW), "ssl_cert_new"}, + {ERR_FUNC(SSL_F_SSL_CHECK_PRIVATE_KEY), "SSL_check_private_key"}, + {ERR_FUNC(SSL_F_SSL_CHECK_SERVERHELLO_TLSEXT), + "SSL_CHECK_SERVERHELLO_TLSEXT"}, + {ERR_FUNC(SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG), + "ssl_check_srvr_ecc_cert_and_alg"}, + {ERR_FUNC(SSL_F_SSL_CIPHER_PROCESS_RULESTR), + "SSL_CIPHER_PROCESS_RULESTR"}, + {ERR_FUNC(SSL_F_SSL_CIPHER_STRENGTH_SORT), "SSL_CIPHER_STRENGTH_SORT"}, + {ERR_FUNC(SSL_F_SSL_CLEAR), "SSL_clear"}, + {ERR_FUNC(SSL_F_SSL_COMP_ADD_COMPRESSION_METHOD), + "SSL_COMP_add_compression_method"}, + {ERR_FUNC(SSL_F_SSL_CONF_CMD), "SSL_CONF_cmd"}, + {ERR_FUNC(SSL_F_SSL_CREATE_CIPHER_LIST), "ssl_create_cipher_list"}, + {ERR_FUNC(SSL_F_SSL_CTRL), "SSL_ctrl"}, + {ERR_FUNC(SSL_F_SSL_CTX_CHECK_PRIVATE_KEY), "SSL_CTX_check_private_key"}, + {ERR_FUNC(SSL_F_SSL_CTX_MAKE_PROFILES), "SSL_CTX_MAKE_PROFILES"}, + {ERR_FUNC(SSL_F_SSL_CTX_NEW), "SSL_CTX_new"}, + {ERR_FUNC(SSL_F_SSL_CTX_SET_CIPHER_LIST), "SSL_CTX_set_cipher_list"}, + {ERR_FUNC(SSL_F_SSL_CTX_SET_CLIENT_CERT_ENGINE), + "SSL_CTX_set_client_cert_engine"}, + {ERR_FUNC(SSL_F_SSL_CTX_SET_PURPOSE), "SSL_CTX_set_purpose"}, + {ERR_FUNC(SSL_F_SSL_CTX_SET_SESSION_ID_CONTEXT), + "SSL_CTX_set_session_id_context"}, + {ERR_FUNC(SSL_F_SSL_CTX_SET_SSL_VERSION), "SSL_CTX_set_ssl_version"}, + {ERR_FUNC(SSL_F_SSL_CTX_SET_TRUST), "SSL_CTX_set_trust"}, + {ERR_FUNC(SSL_F_SSL_CTX_USE_CERTIFICATE), "SSL_CTX_use_certificate"}, + {ERR_FUNC(SSL_F_SSL_CTX_USE_CERTIFICATE_ASN1), + "SSL_CTX_use_certificate_ASN1"}, + {ERR_FUNC(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE), + "SSL_CTX_use_certificate_chain_file"}, + {ERR_FUNC(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE), + "SSL_CTX_use_certificate_file"}, + {ERR_FUNC(SSL_F_SSL_CTX_USE_PRIVATEKEY), "SSL_CTX_use_PrivateKey"}, + {ERR_FUNC(SSL_F_SSL_CTX_USE_PRIVATEKEY_ASN1), + "SSL_CTX_use_PrivateKey_ASN1"}, + {ERR_FUNC(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE), + "SSL_CTX_use_PrivateKey_file"}, + {ERR_FUNC(SSL_F_SSL_CTX_USE_PSK_IDENTITY_HINT), + "SSL_CTX_use_psk_identity_hint"}, + {ERR_FUNC(SSL_F_SSL_CTX_USE_RSAPRIVATEKEY), "SSL_CTX_use_RSAPrivateKey"}, + {ERR_FUNC(SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_ASN1), + "SSL_CTX_use_RSAPrivateKey_ASN1"}, + {ERR_FUNC(SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_FILE), + "SSL_CTX_use_RSAPrivateKey_file"}, + {ERR_FUNC(SSL_F_SSL_CTX_USE_SERVERINFO), "SSL_CTX_use_serverinfo"}, + {ERR_FUNC(SSL_F_SSL_CTX_USE_SERVERINFO_FILE), + "SSL_CTX_use_serverinfo_file"}, + {ERR_FUNC(SSL_F_SSL_DO_HANDSHAKE), "SSL_do_handshake"}, + {ERR_FUNC(SSL_F_SSL_GET_NEW_SESSION), "ssl_get_new_session"}, + {ERR_FUNC(SSL_F_SSL_GET_PREV_SESSION), "ssl_get_prev_session"}, + {ERR_FUNC(SSL_F_SSL_GET_SERVER_CERT_INDEX), "SSL_GET_SERVER_CERT_INDEX"}, + {ERR_FUNC(SSL_F_SSL_GET_SERVER_SEND_CERT), "SSL_GET_SERVER_SEND_CERT"}, + {ERR_FUNC(SSL_F_SSL_GET_SERVER_SEND_PKEY), "ssl_get_server_send_pkey"}, + {ERR_FUNC(SSL_F_SSL_GET_SIGN_PKEY), "ssl_get_sign_pkey"}, + {ERR_FUNC(SSL_F_SSL_INIT_WBIO_BUFFER), "ssl_init_wbio_buffer"}, + {ERR_FUNC(SSL_F_SSL_LOAD_CLIENT_CA_FILE), "SSL_load_client_CA_file"}, + {ERR_FUNC(SSL_F_SSL_NEW), "SSL_new"}, + {ERR_FUNC(SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT), + "ssl_parse_clienthello_renegotiate_ext"}, + {ERR_FUNC(SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT), + "ssl_parse_clienthello_tlsext"}, + {ERR_FUNC(SSL_F_SSL_PARSE_CLIENTHELLO_USE_SRTP_EXT), + "ssl_parse_clienthello_use_srtp_ext"}, + {ERR_FUNC(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT), + "ssl_parse_serverhello_renegotiate_ext"}, + {ERR_FUNC(SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT), + "ssl_parse_serverhello_tlsext"}, + {ERR_FUNC(SSL_F_SSL_PARSE_SERVERHELLO_USE_SRTP_EXT), + "ssl_parse_serverhello_use_srtp_ext"}, + {ERR_FUNC(SSL_F_SSL_PEEK), "SSL_peek"}, + {ERR_FUNC(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT), + "ssl_prepare_clienthello_tlsext"}, + {ERR_FUNC(SSL_F_SSL_PREPARE_SERVERHELLO_TLSEXT), + "ssl_prepare_serverhello_tlsext"}, + {ERR_FUNC(SSL_F_SSL_READ), "SSL_read"}, + {ERR_FUNC(SSL_F_SSL_RSA_PRIVATE_DECRYPT), "SSL_RSA_PRIVATE_DECRYPT"}, + {ERR_FUNC(SSL_F_SSL_RSA_PUBLIC_ENCRYPT), "SSL_RSA_PUBLIC_ENCRYPT"}, + {ERR_FUNC(SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT), + "SSL_SCAN_CLIENTHELLO_TLSEXT"}, + {ERR_FUNC(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT), + "SSL_SCAN_SERVERHELLO_TLSEXT"}, + {ERR_FUNC(SSL_F_SSL_SESSION_DUP), "ssl_session_dup"}, + {ERR_FUNC(SSL_F_SSL_SESSION_NEW), "SSL_SESSION_new"}, + {ERR_FUNC(SSL_F_SSL_SESSION_PRINT_FP), "SSL_SESSION_print_fp"}, + {ERR_FUNC(SSL_F_SSL_SESSION_SET1_ID_CONTEXT), + "SSL_SESSION_set1_id_context"}, + {ERR_FUNC(SSL_F_SSL_SESS_CERT_NEW), "ssl_sess_cert_new"}, + {ERR_FUNC(SSL_F_SSL_SET_CERT), "SSL_SET_CERT"}, + {ERR_FUNC(SSL_F_SSL_SET_CIPHER_LIST), "SSL_set_cipher_list"}, + {ERR_FUNC(SSL_F_SSL_SET_FD), "SSL_set_fd"}, + {ERR_FUNC(SSL_F_SSL_SET_PKEY), "SSL_SET_PKEY"}, + {ERR_FUNC(SSL_F_SSL_SET_PURPOSE), "SSL_set_purpose"}, + {ERR_FUNC(SSL_F_SSL_SET_RFD), "SSL_set_rfd"}, + {ERR_FUNC(SSL_F_SSL_SET_SESSION), "SSL_set_session"}, + {ERR_FUNC(SSL_F_SSL_SET_SESSION_ID_CONTEXT), + "SSL_set_session_id_context"}, + {ERR_FUNC(SSL_F_SSL_SET_SESSION_TICKET_EXT), + "SSL_set_session_ticket_ext"}, + {ERR_FUNC(SSL_F_SSL_SET_TRUST), "SSL_set_trust"}, + {ERR_FUNC(SSL_F_SSL_SET_WFD), "SSL_set_wfd"}, + {ERR_FUNC(SSL_F_SSL_SHUTDOWN), "SSL_shutdown"}, + {ERR_FUNC(SSL_F_SSL_SRP_CTX_INIT), "SSL_SRP_CTX_init"}, + {ERR_FUNC(SSL_F_SSL_UNDEFINED_CONST_FUNCTION), + "ssl_undefined_const_function"}, + {ERR_FUNC(SSL_F_SSL_UNDEFINED_FUNCTION), "ssl_undefined_function"}, + {ERR_FUNC(SSL_F_SSL_UNDEFINED_VOID_FUNCTION), + "ssl_undefined_void_function"}, + {ERR_FUNC(SSL_F_SSL_USE_CERTIFICATE), "SSL_use_certificate"}, + {ERR_FUNC(SSL_F_SSL_USE_CERTIFICATE_ASN1), "SSL_use_certificate_ASN1"}, + {ERR_FUNC(SSL_F_SSL_USE_CERTIFICATE_FILE), "SSL_use_certificate_file"}, + {ERR_FUNC(SSL_F_SSL_USE_PRIVATEKEY), "SSL_use_PrivateKey"}, + {ERR_FUNC(SSL_F_SSL_USE_PRIVATEKEY_ASN1), "SSL_use_PrivateKey_ASN1"}, + {ERR_FUNC(SSL_F_SSL_USE_PRIVATEKEY_FILE), "SSL_use_PrivateKey_file"}, + {ERR_FUNC(SSL_F_SSL_USE_PSK_IDENTITY_HINT), "SSL_use_psk_identity_hint"}, + {ERR_FUNC(SSL_F_SSL_USE_RSAPRIVATEKEY), "SSL_use_RSAPrivateKey"}, + {ERR_FUNC(SSL_F_SSL_USE_RSAPRIVATEKEY_ASN1), + "SSL_use_RSAPrivateKey_ASN1"}, + {ERR_FUNC(SSL_F_SSL_USE_RSAPRIVATEKEY_FILE), + "SSL_use_RSAPrivateKey_file"}, + {ERR_FUNC(SSL_F_SSL_VERIFY_CERT_CHAIN), "ssl_verify_cert_chain"}, + {ERR_FUNC(SSL_F_SSL_WRITE), "SSL_write"}, + {ERR_FUNC(SSL_F_TLS12_CHECK_PEER_SIGALG), "tls12_check_peer_sigalg"}, + {ERR_FUNC(SSL_F_TLS1_CERT_VERIFY_MAC), "tls1_cert_verify_mac"}, + {ERR_FUNC(SSL_F_TLS1_CHANGE_CIPHER_STATE), "tls1_change_cipher_state"}, + {ERR_FUNC(SSL_F_TLS1_CHECK_SERVERHELLO_TLSEXT), + "TLS1_CHECK_SERVERHELLO_TLSEXT"}, + {ERR_FUNC(SSL_F_TLS1_ENC), "tls1_enc"}, + {ERR_FUNC(SSL_F_TLS1_EXPORT_KEYING_MATERIAL), + "tls1_export_keying_material"}, + {ERR_FUNC(SSL_F_TLS1_GET_CURVELIST), "TLS1_GET_CURVELIST"}, + {ERR_FUNC(SSL_F_TLS1_HEARTBEAT), "tls1_heartbeat"}, + {ERR_FUNC(SSL_F_TLS1_PREPARE_CLIENTHELLO_TLSEXT), + "TLS1_PREPARE_CLIENTHELLO_TLSEXT"}, + {ERR_FUNC(SSL_F_TLS1_PREPARE_SERVERHELLO_TLSEXT), + "TLS1_PREPARE_SERVERHELLO_TLSEXT"}, + {ERR_FUNC(SSL_F_TLS1_PRF), "tls1_prf"}, + {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "tls1_setup_key_block"}, + {ERR_FUNC(SSL_F_TLS1_SET_SERVER_SIGALGS), "tls1_set_server_sigalgs"}, + {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"}, + {0, NULL} +}; + +static ERR_STRING_DATA SSL_str_reasons[] = { + {ERR_REASON(SSL_R_APP_DATA_IN_HANDSHAKE), "app data in handshake"}, + {ERR_REASON(SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT), + "attempt to reuse session in different context"}, + {ERR_REASON(SSL_R_BAD_ALERT_RECORD), "bad alert record"}, + {ERR_REASON(SSL_R_BAD_AUTHENTICATION_TYPE), "bad authentication type"}, + {ERR_REASON(SSL_R_BAD_CHANGE_CIPHER_SPEC), "bad change cipher spec"}, + {ERR_REASON(SSL_R_BAD_CHECKSUM), "bad checksum"}, + {ERR_REASON(SSL_R_BAD_DATA), "bad data"}, + {ERR_REASON(SSL_R_BAD_DATA_RETURNED_BY_CALLBACK), + "bad data returned by callback"}, + {ERR_REASON(SSL_R_BAD_DECOMPRESSION), "bad decompression"}, + {ERR_REASON(SSL_R_BAD_DH_G_LENGTH), "bad dh g length"}, + {ERR_REASON(SSL_R_BAD_DH_G_VALUE), "bad dh g value"}, + {ERR_REASON(SSL_R_BAD_DH_PUB_KEY_LENGTH), "bad dh pub key length"}, + {ERR_REASON(SSL_R_BAD_DH_PUB_KEY_VALUE), "bad dh pub key value"}, + {ERR_REASON(SSL_R_BAD_DH_P_LENGTH), "bad dh p length"}, + {ERR_REASON(SSL_R_BAD_DH_P_VALUE), "bad dh p value"}, + {ERR_REASON(SSL_R_BAD_DIGEST_LENGTH), "bad digest length"}, + {ERR_REASON(SSL_R_BAD_DSA_SIGNATURE), "bad dsa signature"}, + {ERR_REASON(SSL_R_BAD_ECC_CERT), "bad ecc cert"}, + {ERR_REASON(SSL_R_BAD_ECDSA_SIGNATURE), "bad ecdsa signature"}, + {ERR_REASON(SSL_R_BAD_ECPOINT), "bad ecpoint"}, + {ERR_REASON(SSL_R_BAD_HANDSHAKE_LENGTH), "bad handshake length"}, + {ERR_REASON(SSL_R_BAD_HELLO_REQUEST), "bad hello request"}, + {ERR_REASON(SSL_R_BAD_LENGTH), "bad length"}, + {ERR_REASON(SSL_R_BAD_MAC_DECODE), "bad mac decode"}, + {ERR_REASON(SSL_R_BAD_MAC_LENGTH), "bad mac length"}, + {ERR_REASON(SSL_R_BAD_MESSAGE_TYPE), "bad message type"}, + {ERR_REASON(SSL_R_BAD_PACKET_LENGTH), "bad packet length"}, + {ERR_REASON(SSL_R_BAD_PROTOCOL_VERSION_NUMBER), + "bad protocol version number"}, + {ERR_REASON(SSL_R_BAD_PSK_IDENTITY_HINT_LENGTH), + "bad psk identity hint length"}, + {ERR_REASON(SSL_R_BAD_RESPONSE_ARGUMENT), "bad response argument"}, + {ERR_REASON(SSL_R_BAD_RSA_DECRYPT), "bad rsa decrypt"}, + {ERR_REASON(SSL_R_BAD_RSA_ENCRYPT), "bad rsa encrypt"}, + {ERR_REASON(SSL_R_BAD_RSA_E_LENGTH), "bad rsa e length"}, + {ERR_REASON(SSL_R_BAD_RSA_MODULUS_LENGTH), "bad rsa modulus length"}, + {ERR_REASON(SSL_R_BAD_RSA_SIGNATURE), "bad rsa signature"}, + {ERR_REASON(SSL_R_BAD_SIGNATURE), "bad signature"}, + {ERR_REASON(SSL_R_BAD_SRP_A_LENGTH), "bad srp a length"}, + {ERR_REASON(SSL_R_BAD_SRP_B_LENGTH), "bad srp b length"}, + {ERR_REASON(SSL_R_BAD_SRP_G_LENGTH), "bad srp g length"}, + {ERR_REASON(SSL_R_BAD_SRP_N_LENGTH), "bad srp n length"}, + {ERR_REASON(SSL_R_BAD_SRP_PARAMETERS), "bad srp parameters"}, + {ERR_REASON(SSL_R_BAD_SRP_S_LENGTH), "bad srp s length"}, + {ERR_REASON(SSL_R_BAD_SRTP_MKI_VALUE), "bad srtp mki value"}, + {ERR_REASON(SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST), + "bad srtp protection profile list"}, + {ERR_REASON(SSL_R_BAD_SSL_FILETYPE), "bad ssl filetype"}, + {ERR_REASON(SSL_R_BAD_SSL_SESSION_ID_LENGTH), + "bad ssl session id length"}, + {ERR_REASON(SSL_R_BAD_STATE), "bad state"}, + {ERR_REASON(SSL_R_BAD_VALUE), "bad value"}, + {ERR_REASON(SSL_R_BAD_WRITE_RETRY), "bad write retry"}, + {ERR_REASON(SSL_R_BIO_NOT_SET), "bio not set"}, + {ERR_REASON(SSL_R_BLOCK_CIPHER_PAD_IS_WRONG), + "block cipher pad is wrong"}, + {ERR_REASON(SSL_R_BN_LIB), "bn lib"}, + {ERR_REASON(SSL_R_CA_DN_LENGTH_MISMATCH), "ca dn length mismatch"}, + {ERR_REASON(SSL_R_CA_DN_TOO_LONG), "ca dn too long"}, + {ERR_REASON(SSL_R_CCS_RECEIVED_EARLY), "ccs received early"}, + {ERR_REASON(SSL_R_CERTIFICATE_VERIFY_FAILED), + "certificate verify failed"}, + {ERR_REASON(SSL_R_CERT_CB_ERROR), "cert cb error"}, + {ERR_REASON(SSL_R_CERT_LENGTH_MISMATCH), "cert length mismatch"}, + {ERR_REASON(SSL_R_CHALLENGE_IS_DIFFERENT), "challenge is different"}, + {ERR_REASON(SSL_R_CIPHER_CODE_WRONG_LENGTH), "cipher code wrong length"}, + {ERR_REASON(SSL_R_CIPHER_OR_HASH_UNAVAILABLE), + "cipher or hash unavailable"}, + {ERR_REASON(SSL_R_CIPHER_TABLE_SRC_ERROR), "cipher table src error"}, + {ERR_REASON(SSL_R_CLIENTHELLO_TLSEXT), "clienthello tlsext"}, + {ERR_REASON(SSL_R_COMPRESSED_LENGTH_TOO_LONG), + "compressed length too long"}, + {ERR_REASON(SSL_R_COMPRESSION_DISABLED), "compression disabled"}, + {ERR_REASON(SSL_R_COMPRESSION_FAILURE), "compression failure"}, + {ERR_REASON(SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE), + "compression id not within private range"}, + {ERR_REASON(SSL_R_COMPRESSION_LIBRARY_ERROR), + "compression library error"}, + {ERR_REASON(SSL_R_CONNECTION_ID_IS_DIFFERENT), + "connection id is different"}, + {ERR_REASON(SSL_R_CONNECTION_TYPE_NOT_SET), "connection type not set"}, + {ERR_REASON(SSL_R_COOKIE_MISMATCH), "cookie mismatch"}, + {ERR_REASON(SSL_R_DATA_BETWEEN_CCS_AND_FINISHED), + "data between ccs and finished"}, + {ERR_REASON(SSL_R_DATA_LENGTH_TOO_LONG), "data length too long"}, + {ERR_REASON(SSL_R_DECRYPTION_FAILED), "decryption failed"}, + {ERR_REASON(SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC), + "decryption failed or bad record mac"}, + {ERR_REASON(SSL_R_DH_KEY_TOO_SMALL), "dh key too small"}, + {ERR_REASON(SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG), + "dh public value length is wrong"}, + {ERR_REASON(SSL_R_DIGEST_CHECK_FAILED), "digest check failed"}, + {ERR_REASON(SSL_R_DTLS_MESSAGE_TOO_BIG), "dtls message too big"}, + {ERR_REASON(SSL_R_DUPLICATE_COMPRESSION_ID), "duplicate compression id"}, + {ERR_REASON(SSL_R_ECC_CERT_NOT_FOR_KEY_AGREEMENT), + "ecc cert not for key agreement"}, + {ERR_REASON(SSL_R_ECC_CERT_NOT_FOR_SIGNING), "ecc cert not for signing"}, + {ERR_REASON(SSL_R_ECC_CERT_SHOULD_HAVE_RSA_SIGNATURE), + "ecc cert should have rsa signature"}, + {ERR_REASON(SSL_R_ECC_CERT_SHOULD_HAVE_SHA1_SIGNATURE), + "ecc cert should have sha1 signature"}, + {ERR_REASON(SSL_R_ECDH_REQUIRED_FOR_SUITEB_MODE), + "ecdh required for suiteb mode"}, + {ERR_REASON(SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER), + "ecgroup too large for cipher"}, + {ERR_REASON(SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST), + "empty srtp protection profile list"}, + {ERR_REASON(SSL_R_ENCRYPTED_LENGTH_TOO_LONG), + "encrypted length too long"}, + {ERR_REASON(SSL_R_ERROR_GENERATING_TMP_RSA_KEY), + "error generating tmp rsa key"}, + {ERR_REASON(SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST), + "error in received cipher list"}, + {ERR_REASON(SSL_R_EXCESSIVE_MESSAGE_SIZE), "excessive message size"}, + {ERR_REASON(SSL_R_EXTRA_DATA_IN_MESSAGE), "extra data in message"}, + {ERR_REASON(SSL_R_GOT_A_FIN_BEFORE_A_CCS), "got a fin before a ccs"}, + {ERR_REASON(SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS), + "got next proto before a ccs"}, + {ERR_REASON(SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION), + "got next proto without seeing extension"}, + {ERR_REASON(SSL_R_HTTPS_PROXY_REQUEST), "https proxy request"}, + {ERR_REASON(SSL_R_HTTP_REQUEST), "http request"}, + {ERR_REASON(SSL_R_ILLEGAL_PADDING), "illegal padding"}, + {ERR_REASON(SSL_R_ILLEGAL_SUITEB_DIGEST), "illegal Suite B digest"}, + {ERR_REASON(SSL_R_INAPPROPRIATE_FALLBACK), "inappropriate fallback"}, + {ERR_REASON(SSL_R_INCONSISTENT_COMPRESSION), "inconsistent compression"}, + {ERR_REASON(SSL_R_INVALID_CHALLENGE_LENGTH), "invalid challenge length"}, + {ERR_REASON(SSL_R_INVALID_COMMAND), "invalid command"}, + {ERR_REASON(SSL_R_INVALID_COMPRESSION_ALGORITHM), + "invalid compression algorithm"}, + {ERR_REASON(SSL_R_INVALID_NULL_CMD_NAME), "invalid null cmd name"}, + {ERR_REASON(SSL_R_INVALID_PURPOSE), "invalid purpose"}, + {ERR_REASON(SSL_R_INVALID_SERVERINFO_DATA), "invalid serverinfo data"}, + {ERR_REASON(SSL_R_INVALID_SRP_USERNAME), "invalid srp username"}, + {ERR_REASON(SSL_R_INVALID_STATUS_RESPONSE), "invalid status response"}, + {ERR_REASON(SSL_R_INVALID_TICKET_KEYS_LENGTH), + "invalid ticket keys length"}, + {ERR_REASON(SSL_R_INVALID_TRUST), "invalid trust"}, + {ERR_REASON(SSL_R_KEY_ARG_TOO_LONG), "key arg too long"}, + {ERR_REASON(SSL_R_KRB5), "krb5"}, + {ERR_REASON(SSL_R_KRB5_C_CC_PRINC), "krb5 client cc principal (no tkt?)"}, + {ERR_REASON(SSL_R_KRB5_C_GET_CRED), "krb5 client get cred"}, + {ERR_REASON(SSL_R_KRB5_C_INIT), "krb5 client init"}, + {ERR_REASON(SSL_R_KRB5_C_MK_REQ), "krb5 client mk_req (expired tkt?)"}, + {ERR_REASON(SSL_R_KRB5_S_BAD_TICKET), "krb5 server bad ticket"}, + {ERR_REASON(SSL_R_KRB5_S_INIT), "krb5 server init"}, + {ERR_REASON(SSL_R_KRB5_S_RD_REQ), "krb5 server rd_req (keytab perms?)"}, + {ERR_REASON(SSL_R_KRB5_S_TKT_EXPIRED), "krb5 server tkt expired"}, + {ERR_REASON(SSL_R_KRB5_S_TKT_NYV), "krb5 server tkt not yet valid"}, + {ERR_REASON(SSL_R_KRB5_S_TKT_SKEW), "krb5 server tkt skew"}, + {ERR_REASON(SSL_R_LENGTH_MISMATCH), "length mismatch"}, + {ERR_REASON(SSL_R_LENGTH_TOO_SHORT), "length too short"}, + {ERR_REASON(SSL_R_LIBRARY_BUG), "library bug"}, + {ERR_REASON(SSL_R_LIBRARY_HAS_NO_CIPHERS), "library has no ciphers"}, + {ERR_REASON(SSL_R_MESSAGE_TOO_LONG), "message too long"}, + {ERR_REASON(SSL_R_MISSING_DH_DSA_CERT), "missing dh dsa cert"}, + {ERR_REASON(SSL_R_MISSING_DH_KEY), "missing dh key"}, + {ERR_REASON(SSL_R_MISSING_DH_RSA_CERT), "missing dh rsa cert"}, + {ERR_REASON(SSL_R_MISSING_DSA_SIGNING_CERT), "missing dsa signing cert"}, + {ERR_REASON(SSL_R_MISSING_ECDH_CERT), "missing ecdh cert"}, + {ERR_REASON(SSL_R_MISSING_ECDSA_SIGNING_CERT), + "missing ecdsa signing cert"}, + {ERR_REASON(SSL_R_MISSING_EXPORT_TMP_DH_KEY), + "missing export tmp dh key"}, + {ERR_REASON(SSL_R_MISSING_EXPORT_TMP_RSA_KEY), + "missing export tmp rsa key"}, + {ERR_REASON(SSL_R_MISSING_RSA_CERTIFICATE), "missing rsa certificate"}, + {ERR_REASON(SSL_R_MISSING_RSA_ENCRYPTING_CERT), + "missing rsa encrypting cert"}, + {ERR_REASON(SSL_R_MISSING_RSA_SIGNING_CERT), "missing rsa signing cert"}, + {ERR_REASON(SSL_R_MISSING_SRP_PARAM), "can't find SRP server param"}, + {ERR_REASON(SSL_R_MISSING_TMP_DH_KEY), "missing tmp dh key"}, + {ERR_REASON(SSL_R_MISSING_TMP_ECDH_KEY), "missing tmp ecdh key"}, + {ERR_REASON(SSL_R_MISSING_TMP_RSA_KEY), "missing tmp rsa key"}, + {ERR_REASON(SSL_R_MISSING_TMP_RSA_PKEY), "missing tmp rsa pkey"}, + {ERR_REASON(SSL_R_MISSING_VERIFY_MESSAGE), "missing verify message"}, + {ERR_REASON(SSL_R_MULTIPLE_SGC_RESTARTS), "multiple sgc restarts"}, + {ERR_REASON(SSL_R_NON_SSLV2_INITIAL_PACKET), "non sslv2 initial packet"}, + {ERR_REASON(SSL_R_NO_CERTIFICATES_RETURNED), "no certificates returned"}, + {ERR_REASON(SSL_R_NO_CERTIFICATE_ASSIGNED), "no certificate assigned"}, + {ERR_REASON(SSL_R_NO_CERTIFICATE_RETURNED), "no certificate returned"}, + {ERR_REASON(SSL_R_NO_CERTIFICATE_SET), "no certificate set"}, + {ERR_REASON(SSL_R_NO_CERTIFICATE_SPECIFIED), "no certificate specified"}, + {ERR_REASON(SSL_R_NO_CIPHERS_AVAILABLE), "no ciphers available"}, + {ERR_REASON(SSL_R_NO_CIPHERS_PASSED), "no ciphers passed"}, + {ERR_REASON(SSL_R_NO_CIPHERS_SPECIFIED), "no ciphers specified"}, + {ERR_REASON(SSL_R_NO_CIPHER_LIST), "no cipher list"}, + {ERR_REASON(SSL_R_NO_CIPHER_MATCH), "no cipher match"}, + {ERR_REASON(SSL_R_NO_CLIENT_CERT_METHOD), "no client cert method"}, + {ERR_REASON(SSL_R_NO_CLIENT_CERT_RECEIVED), "no client cert received"}, + {ERR_REASON(SSL_R_NO_COMPRESSION_SPECIFIED), "no compression specified"}, + {ERR_REASON(SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER), + "Peer haven't sent GOST certificate, required for selected ciphersuite"}, + {ERR_REASON(SSL_R_NO_METHOD_SPECIFIED), "no method specified"}, + {ERR_REASON(SSL_R_NO_PEM_EXTENSIONS), "no pem extensions"}, + {ERR_REASON(SSL_R_NO_PRIVATEKEY), "no privatekey"}, + {ERR_REASON(SSL_R_NO_PRIVATE_KEY_ASSIGNED), "no private key assigned"}, + {ERR_REASON(SSL_R_NO_PROTOCOLS_AVAILABLE), "no protocols available"}, + {ERR_REASON(SSL_R_NO_PUBLICKEY), "no publickey"}, + {ERR_REASON(SSL_R_NO_RENEGOTIATION), "no renegotiation"}, + {ERR_REASON(SSL_R_NO_REQUIRED_DIGEST), + "digest requred for handshake isn't computed"}, + {ERR_REASON(SSL_R_NO_SHARED_CIPHER), "no shared cipher"}, + {ERR_REASON(SSL_R_NO_SHARED_SIGATURE_ALGORITHMS), + "no shared sigature algorithms"}, + {ERR_REASON(SSL_R_NO_SRTP_PROFILES), "no srtp profiles"}, + {ERR_REASON(SSL_R_NO_VERIFY_CALLBACK), "no verify callback"}, + {ERR_REASON(SSL_R_NULL_SSL_CTX), "null ssl ctx"}, + {ERR_REASON(SSL_R_NULL_SSL_METHOD_PASSED), "null ssl method passed"}, + {ERR_REASON(SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED), + "old session cipher not returned"}, + {ERR_REASON(SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED), + "old session compression algorithm not returned"}, + {ERR_REASON(SSL_R_ONLY_DTLS_1_2_ALLOWED_IN_SUITEB_MODE), + "only DTLS 1.2 allowed in Suite B mode"}, + {ERR_REASON(SSL_R_ONLY_TLS_1_2_ALLOWED_IN_SUITEB_MODE), + "only TLS 1.2 allowed in Suite B mode"}, + {ERR_REASON(SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE), + "only tls allowed in fips mode"}, + {ERR_REASON(SSL_R_OPAQUE_PRF_INPUT_TOO_LONG), + "opaque PRF input too long"}, + {ERR_REASON(SSL_R_PACKET_LENGTH_TOO_LONG), "packet length too long"}, + {ERR_REASON(SSL_R_PARSE_TLSEXT), "parse tlsext"}, + {ERR_REASON(SSL_R_PATH_TOO_LONG), "path too long"}, + {ERR_REASON(SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE), + "peer did not return a certificate"}, + {ERR_REASON(SSL_R_PEER_ERROR), "peer error"}, + {ERR_REASON(SSL_R_PEER_ERROR_CERTIFICATE), "peer error certificate"}, + {ERR_REASON(SSL_R_PEER_ERROR_NO_CERTIFICATE), + "peer error no certificate"}, + {ERR_REASON(SSL_R_PEER_ERROR_NO_CIPHER), "peer error no cipher"}, + {ERR_REASON(SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE), + "peer error unsupported certificate type"}, + {ERR_REASON(SSL_R_PEM_NAME_BAD_PREFIX), "pem name bad prefix"}, + {ERR_REASON(SSL_R_PEM_NAME_TOO_SHORT), "pem name too short"}, + {ERR_REASON(SSL_R_PRE_MAC_LENGTH_TOO_LONG), "pre mac length too long"}, + {ERR_REASON(SSL_R_PROBLEMS_MAPPING_CIPHER_FUNCTIONS), + "problems mapping cipher functions"}, + {ERR_REASON(SSL_R_PROTOCOL_IS_SHUTDOWN), "protocol is shutdown"}, + {ERR_REASON(SSL_R_PSK_IDENTITY_NOT_FOUND), "psk identity not found"}, + {ERR_REASON(SSL_R_PSK_NO_CLIENT_CB), "psk no client cb"}, + {ERR_REASON(SSL_R_PSK_NO_SERVER_CB), "psk no server cb"}, + {ERR_REASON(SSL_R_PUBLIC_KEY_ENCRYPT_ERROR), "public key encrypt error"}, + {ERR_REASON(SSL_R_PUBLIC_KEY_IS_NOT_RSA), "public key is not rsa"}, + {ERR_REASON(SSL_R_PUBLIC_KEY_NOT_RSA), "public key not rsa"}, + {ERR_REASON(SSL_R_READ_BIO_NOT_SET), "read bio not set"}, + {ERR_REASON(SSL_R_READ_TIMEOUT_EXPIRED), "read timeout expired"}, + {ERR_REASON(SSL_R_READ_WRONG_PACKET_TYPE), "read wrong packet type"}, + {ERR_REASON(SSL_R_RECORD_LENGTH_MISMATCH), "record length mismatch"}, + {ERR_REASON(SSL_R_RECORD_TOO_LARGE), "record too large"}, + {ERR_REASON(SSL_R_RECORD_TOO_SMALL), "record too small"}, + {ERR_REASON(SSL_R_RENEGOTIATE_EXT_TOO_LONG), "renegotiate ext too long"}, + {ERR_REASON(SSL_R_RENEGOTIATION_ENCODING_ERR), + "renegotiation encoding err"}, + {ERR_REASON(SSL_R_RENEGOTIATION_MISMATCH), "renegotiation mismatch"}, + {ERR_REASON(SSL_R_REQUIRED_CIPHER_MISSING), "required cipher missing"}, + {ERR_REASON(SSL_R_REQUIRED_COMPRESSSION_ALGORITHM_MISSING), + "required compresssion algorithm missing"}, + {ERR_REASON(SSL_R_REUSE_CERT_LENGTH_NOT_ZERO), + "reuse cert length not zero"}, + {ERR_REASON(SSL_R_REUSE_CERT_TYPE_NOT_ZERO), "reuse cert type not zero"}, + {ERR_REASON(SSL_R_REUSE_CIPHER_LIST_NOT_ZERO), + "reuse cipher list not zero"}, + {ERR_REASON(SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING), + "scsv received when renegotiating"}, + {ERR_REASON(SSL_R_SERVERHELLO_TLSEXT), "serverhello tlsext"}, + {ERR_REASON(SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED), + "session id context uninitialized"}, + {ERR_REASON(SSL_R_SHORT_READ), "short read"}, + {ERR_REASON(SSL_R_SHUTDOWN_WHILE_IN_INIT), "shutdown while in init"}, + {ERR_REASON(SSL_R_SIGNATURE_ALGORITHMS_ERROR), + "signature algorithms error"}, + {ERR_REASON(SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE), + "signature for non signing certificate"}, + {ERR_REASON(SSL_R_SRP_A_CALC), "error with the srp params"}, + {ERR_REASON(SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES), + "srtp could not allocate profiles"}, + {ERR_REASON(SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG), + "srtp protection profile list too long"}, + {ERR_REASON(SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE), + "srtp unknown protection profile"}, + {ERR_REASON(SSL_R_SSL23_DOING_SESSION_ID_REUSE), + "ssl23 doing session id reuse"}, + {ERR_REASON(SSL_R_SSL2_CONNECTION_ID_TOO_LONG), + "ssl2 connection id too long"}, + {ERR_REASON(SSL_R_SSL3_EXT_INVALID_ECPOINTFORMAT), + "ssl3 ext invalid ecpointformat"}, + {ERR_REASON(SSL_R_SSL3_EXT_INVALID_SERVERNAME), + "ssl3 ext invalid servername"}, + {ERR_REASON(SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE), + "ssl3 ext invalid servername type"}, + {ERR_REASON(SSL_R_SSL3_SESSION_ID_TOO_LONG), "ssl3 session id too long"}, + {ERR_REASON(SSL_R_SSL3_SESSION_ID_TOO_SHORT), + "ssl3 session id too short"}, + {ERR_REASON(SSL_R_SSLV3_ALERT_BAD_CERTIFICATE), + "sslv3 alert bad certificate"}, + {ERR_REASON(SSL_R_SSLV3_ALERT_BAD_RECORD_MAC), + "sslv3 alert bad record mac"}, + {ERR_REASON(SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED), + "sslv3 alert certificate expired"}, + {ERR_REASON(SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED), + "sslv3 alert certificate revoked"}, + {ERR_REASON(SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN), + "sslv3 alert certificate unknown"}, + {ERR_REASON(SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE), + "sslv3 alert decompression failure"}, + {ERR_REASON(SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE), + "sslv3 alert handshake failure"}, + {ERR_REASON(SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER), + "sslv3 alert illegal parameter"}, + {ERR_REASON(SSL_R_SSLV3_ALERT_NO_CERTIFICATE), + "sslv3 alert no certificate"}, + {ERR_REASON(SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE), + "sslv3 alert unexpected message"}, + {ERR_REASON(SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE), + "sslv3 alert unsupported certificate"}, + {ERR_REASON(SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION), + "ssl ctx has no default ssl version"}, + {ERR_REASON(SSL_R_SSL_HANDSHAKE_FAILURE), "ssl handshake failure"}, + {ERR_REASON(SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS), + "ssl library has no ciphers"}, + {ERR_REASON(SSL_R_SSL_SESSION_ID_CALLBACK_FAILED), + "ssl session id callback failed"}, + {ERR_REASON(SSL_R_SSL_SESSION_ID_CONFLICT), "ssl session id conflict"}, + {ERR_REASON(SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG), + "ssl session id context too long"}, + {ERR_REASON(SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH), + "ssl session id has bad length"}, + {ERR_REASON(SSL_R_SSL_SESSION_ID_IS_DIFFERENT), + "ssl session id is different"}, + {ERR_REASON(SSL_R_TLSV1_ALERT_ACCESS_DENIED), + "tlsv1 alert access denied"}, + {ERR_REASON(SSL_R_TLSV1_ALERT_DECODE_ERROR), "tlsv1 alert decode error"}, + {ERR_REASON(SSL_R_TLSV1_ALERT_DECRYPTION_FAILED), + "tlsv1 alert decryption failed"}, + {ERR_REASON(SSL_R_TLSV1_ALERT_DECRYPT_ERROR), + "tlsv1 alert decrypt error"}, + {ERR_REASON(SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION), + "tlsv1 alert export restriction"}, + {ERR_REASON(SSL_R_TLSV1_ALERT_INAPPROPRIATE_FALLBACK), + "tlsv1 alert inappropriate fallback"}, + {ERR_REASON(SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY), + "tlsv1 alert insufficient security"}, + {ERR_REASON(SSL_R_TLSV1_ALERT_INTERNAL_ERROR), + "tlsv1 alert internal error"}, + {ERR_REASON(SSL_R_TLSV1_ALERT_NO_RENEGOTIATION), + "tlsv1 alert no renegotiation"}, + {ERR_REASON(SSL_R_TLSV1_ALERT_PROTOCOL_VERSION), + "tlsv1 alert protocol version"}, + {ERR_REASON(SSL_R_TLSV1_ALERT_RECORD_OVERFLOW), + "tlsv1 alert record overflow"}, + {ERR_REASON(SSL_R_TLSV1_ALERT_UNKNOWN_CA), "tlsv1 alert unknown ca"}, + {ERR_REASON(SSL_R_TLSV1_ALERT_USER_CANCELLED), + "tlsv1 alert user cancelled"}, + {ERR_REASON(SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE), + "tlsv1 bad certificate hash value"}, + {ERR_REASON(SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE), + "tlsv1 bad certificate status response"}, + {ERR_REASON(SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE), + "tlsv1 certificate unobtainable"}, + {ERR_REASON(SSL_R_TLSV1_UNRECOGNIZED_NAME), "tlsv1 unrecognized name"}, + {ERR_REASON(SSL_R_TLSV1_UNSUPPORTED_EXTENSION), + "tlsv1 unsupported extension"}, + {ERR_REASON(SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER), + "tls client cert req with anon cipher"}, + {ERR_REASON(SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT), + "peer does not accept heartbeats"}, + {ERR_REASON(SSL_R_TLS_HEARTBEAT_PENDING), + "heartbeat request already pending"}, + {ERR_REASON(SSL_R_TLS_ILLEGAL_EXPORTER_LABEL), + "tls illegal exporter label"}, + {ERR_REASON(SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST), + "tls invalid ecpointformat list"}, + {ERR_REASON(SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST), + "tls peer did not respond with certificate list"}, + {ERR_REASON(SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG), + "tls rsa encrypted value length is wrong"}, + {ERR_REASON(SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER), + "tried to use unsupported cipher"}, + {ERR_REASON(SSL_R_UNABLE_TO_DECODE_DH_CERTS), + "unable to decode dh certs"}, + {ERR_REASON(SSL_R_UNABLE_TO_DECODE_ECDH_CERTS), + "unable to decode ecdh certs"}, + {ERR_REASON(SSL_R_UNABLE_TO_EXTRACT_PUBLIC_KEY), + "unable to extract public key"}, + {ERR_REASON(SSL_R_UNABLE_TO_FIND_DH_PARAMETERS), + "unable to find dh parameters"}, + {ERR_REASON(SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS), + "unable to find ecdh parameters"}, + {ERR_REASON(SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS), + "unable to find public key parameters"}, + {ERR_REASON(SSL_R_UNABLE_TO_FIND_SSL_METHOD), + "unable to find ssl method"}, + {ERR_REASON(SSL_R_UNABLE_TO_LOAD_SSL2_MD5_ROUTINES), + "unable to load ssl2 md5 routines"}, + {ERR_REASON(SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES), + "unable to load ssl3 md5 routines"}, + {ERR_REASON(SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES), + "unable to load ssl3 sha1 routines"}, + {ERR_REASON(SSL_R_UNEXPECTED_MESSAGE), "unexpected message"}, + {ERR_REASON(SSL_R_UNEXPECTED_RECORD), "unexpected record"}, + {ERR_REASON(SSL_R_UNINITIALIZED), "uninitialized"}, + {ERR_REASON(SSL_R_UNKNOWN_ALERT_TYPE), "unknown alert type"}, + {ERR_REASON(SSL_R_UNKNOWN_CERTIFICATE_TYPE), "unknown certificate type"}, + {ERR_REASON(SSL_R_UNKNOWN_CIPHER_RETURNED), "unknown cipher returned"}, + {ERR_REASON(SSL_R_UNKNOWN_CIPHER_TYPE), "unknown cipher type"}, + {ERR_REASON(SSL_R_UNKNOWN_CMD_NAME), "unknown cmd name"}, + {ERR_REASON(SSL_R_UNKNOWN_DIGEST), "unknown digest"}, + {ERR_REASON(SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE), + "unknown key exchange type"}, + {ERR_REASON(SSL_R_UNKNOWN_PKEY_TYPE), "unknown pkey type"}, + {ERR_REASON(SSL_R_UNKNOWN_PROTOCOL), "unknown protocol"}, + {ERR_REASON(SSL_R_UNKNOWN_REMOTE_ERROR_TYPE), + "unknown remote error type"}, + {ERR_REASON(SSL_R_UNKNOWN_SSL_VERSION), "unknown ssl version"}, + {ERR_REASON(SSL_R_UNKNOWN_STATE), "unknown state"}, + {ERR_REASON(SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED), + "unsafe legacy renegotiation disabled"}, + {ERR_REASON(SSL_R_UNSUPPORTED_CIPHER), "unsupported cipher"}, + {ERR_REASON(SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM), + "unsupported compression algorithm"}, + {ERR_REASON(SSL_R_UNSUPPORTED_DIGEST_TYPE), "unsupported digest type"}, + {ERR_REASON(SSL_R_UNSUPPORTED_ELLIPTIC_CURVE), + "unsupported elliptic curve"}, + {ERR_REASON(SSL_R_UNSUPPORTED_PROTOCOL), "unsupported protocol"}, + {ERR_REASON(SSL_R_UNSUPPORTED_SSL_VERSION), "unsupported ssl version"}, + {ERR_REASON(SSL_R_UNSUPPORTED_STATUS_TYPE), "unsupported status type"}, + {ERR_REASON(SSL_R_USE_SRTP_NOT_NEGOTIATED), "use srtp not negotiated"}, + {ERR_REASON(SSL_R_WRITE_BIO_NOT_SET), "write bio not set"}, + {ERR_REASON(SSL_R_WRONG_CERTIFICATE_TYPE), "wrong certificate type"}, + {ERR_REASON(SSL_R_WRONG_CIPHER_RETURNED), "wrong cipher returned"}, + {ERR_REASON(SSL_R_WRONG_CURVE), "wrong curve"}, + {ERR_REASON(SSL_R_WRONG_MESSAGE_TYPE), "wrong message type"}, + {ERR_REASON(SSL_R_WRONG_NUMBER_OF_KEY_BITS), "wrong number of key bits"}, + {ERR_REASON(SSL_R_WRONG_SIGNATURE_LENGTH), "wrong signature length"}, + {ERR_REASON(SSL_R_WRONG_SIGNATURE_SIZE), "wrong signature size"}, + {ERR_REASON(SSL_R_WRONG_SIGNATURE_TYPE), "wrong signature type"}, + {ERR_REASON(SSL_R_WRONG_SSL_VERSION), "wrong ssl version"}, + {ERR_REASON(SSL_R_WRONG_VERSION_NUMBER), "wrong version number"}, + {ERR_REASON(SSL_R_X509_LIB), "x509 lib"}, + {ERR_REASON(SSL_R_X509_VERIFICATION_SETUP_PROBLEMS), + "x509 verification setup problems"}, + {0, NULL} +}; + +#endif + +void ERR_load_SSL_strings(void) +{ +#ifndef OPENSSL_NO_ERR + + if (ERR_func_error_string(SSL_str_functs[0].error) == NULL) { + ERR_load_strings(0, SSL_str_functs); + ERR_load_strings(0, SSL_str_reasons); + } +#endif +} diff --git a/thirdparty/openssl/ssl/ssl_err2.c b/thirdparty/openssl/ssl/ssl_err2.c new file mode 100644 index 0000000000..14e48221f4 --- /dev/null +++ b/thirdparty/openssl/ssl/ssl_err2.c @@ -0,0 +1,69 @@ +/* ssl/ssl_err2.c */ +/* 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.] + */ + +#include <stdio.h> +#include <openssl/err.h> +#include <openssl/ssl.h> + +void SSL_load_error_strings(void) +{ +#ifndef OPENSSL_NO_ERR + ERR_load_crypto_strings(); + ERR_load_SSL_strings(); +#endif +} diff --git a/thirdparty/openssl/ssl/ssl_lib.c b/thirdparty/openssl/ssl/ssl_lib.c new file mode 100644 index 0000000000..fd94325bb3 --- /dev/null +++ b/thirdparty/openssl/ssl/ssl_lib.c @@ -0,0 +1,3571 @@ +/* + * ! \file ssl/ssl_lib.c \brief Version independent SSL functions. + */ +/* 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. + * ECC cipher suite support in OpenSSL originally developed by + * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. + */ +/* ==================================================================== + * 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. + */ + +#ifdef REF_CHECK +# include <assert.h> +#endif +#include <stdio.h> +#include "ssl_locl.h" +#include "kssl_lcl.h" +#include <openssl/objects.h> +#include <openssl/lhash.h> +#include <openssl/x509v3.h> +#include <openssl/rand.h> +#include <openssl/ocsp.h> +#ifndef OPENSSL_NO_DH +# include <openssl/dh.h> +#endif +#ifndef OPENSSL_NO_ENGINE +# include <openssl/engine.h> +#endif + +const char *SSL_version_str = OPENSSL_VERSION_TEXT; + +SSL3_ENC_METHOD ssl3_undef_enc_method = { + /* + * evil casts, but these functions are only called if there's a library + * bug + */ + (int (*)(SSL *, int))ssl_undefined_function, + (int (*)(SSL *, unsigned char *, int))ssl_undefined_function, + ssl_undefined_function, + (int (*)(SSL *, unsigned char *, unsigned char *, int)) + ssl_undefined_function, + (int (*)(SSL *, int))ssl_undefined_function, + (int (*)(SSL *, const char *, int, unsigned char *)) + ssl_undefined_function, + 0, /* finish_mac_length */ + (int (*)(SSL *, int, unsigned char *))ssl_undefined_function, + NULL, /* client_finished_label */ + 0, /* client_finished_label_len */ + NULL, /* server_finished_label */ + 0, /* server_finished_label_len */ + (int (*)(int))ssl_undefined_function, + (int (*)(SSL *, unsigned char *, size_t, const char *, + size_t, const unsigned char *, size_t, + int use_context))ssl_undefined_function, +}; + +int SSL_clear(SSL *s) +{ + + if (s->method == NULL) { + SSLerr(SSL_F_SSL_CLEAR, SSL_R_NO_METHOD_SPECIFIED); + return (0); + } + + if (ssl_clear_bad_session(s)) { + SSL_SESSION_free(s->session); + s->session = NULL; + } + + s->error = 0; + s->hit = 0; + s->shutdown = 0; + +#if 0 + /* + * Disabled since version 1.10 of this file (early return not + * needed because SSL_clear is not called when doing renegotiation) + */ + /* + * This is set if we are doing dynamic renegotiation so keep + * the old cipher. It is sort of a SSL_clear_lite :-) + */ + if (s->renegotiate) + return (1); +#else + if (s->renegotiate) { + SSLerr(SSL_F_SSL_CLEAR, ERR_R_INTERNAL_ERROR); + return 0; + } +#endif + + s->type = 0; + + s->state = SSL_ST_BEFORE | ((s->server) ? SSL_ST_ACCEPT : SSL_ST_CONNECT); + + s->version = s->method->version; + s->client_version = s->version; + s->rwstate = SSL_NOTHING; + s->rstate = SSL_ST_READ_HEADER; +#if 0 + s->read_ahead = s->ctx->read_ahead; +#endif + + if (s->init_buf != NULL) { + BUF_MEM_free(s->init_buf); + s->init_buf = NULL; + } + + ssl_clear_cipher_ctx(s); + ssl_clear_hash_ctx(&s->read_hash); + ssl_clear_hash_ctx(&s->write_hash); + + s->first_packet = 0; +#ifndef OPENSSL_NO_TLSEXT + if (s->cert != NULL) { + if (s->cert->alpn_proposed) { + OPENSSL_free(s->cert->alpn_proposed); + s->cert->alpn_proposed = NULL; + } + s->cert->alpn_proposed_len = 0; + s->cert->alpn_sent = 0; + } +#endif +#if 1 + /* + * Check to see if we were changed into a different method, if so, revert + * back if we are not doing session-id reuse. + */ + if (!s->in_handshake && (s->session == NULL) + && (s->method != s->ctx->method)) { + s->method->ssl_free(s); + s->method = s->ctx->method; + if (!s->method->ssl_new(s)) + return (0); + } else +#endif + s->method->ssl_clear(s); + return (1); +} + +/** Used to change an SSL_CTXs default SSL method type */ +int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth) +{ + STACK_OF(SSL_CIPHER) *sk; + + ctx->method = meth; + + sk = ssl_create_cipher_list(ctx->method, &(ctx->cipher_list), + &(ctx->cipher_list_by_id), + meth->version == + SSL2_VERSION ? "SSLv2" : + SSL_DEFAULT_CIPHER_LIST, ctx->cert); + if ((sk == NULL) || (sk_SSL_CIPHER_num(sk) <= 0)) { + SSLerr(SSL_F_SSL_CTX_SET_SSL_VERSION, + SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS); + return (0); + } + return (1); +} + +SSL *SSL_new(SSL_CTX *ctx) +{ + SSL *s; + + if (ctx == NULL) { + SSLerr(SSL_F_SSL_NEW, SSL_R_NULL_SSL_CTX); + return (NULL); + } + if (ctx->method == NULL) { + SSLerr(SSL_F_SSL_NEW, SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION); + return (NULL); + } + + s = (SSL *)OPENSSL_malloc(sizeof(SSL)); + if (s == NULL) + goto err; + memset(s, 0, sizeof(SSL)); + +#ifndef OPENSSL_NO_KRB5 + s->kssl_ctx = kssl_ctx_new(); +#endif /* OPENSSL_NO_KRB5 */ + + s->options = ctx->options; + s->mode = ctx->mode; + s->max_cert_list = ctx->max_cert_list; + s->references = 1; + + if (ctx->cert != NULL) { + /* + * Earlier library versions used to copy the pointer to the CERT, not + * its contents; only when setting new parameters for the per-SSL + * copy, ssl_cert_new would be called (and the direct reference to + * the per-SSL_CTX settings would be lost, but those still were + * indirectly accessed for various purposes, and for that reason they + * used to be known as s->ctx->default_cert). Now we don't look at the + * SSL_CTX's CERT after having duplicated it once. + */ + + s->cert = ssl_cert_dup(ctx->cert); + if (s->cert == NULL) + goto err; + } else + s->cert = NULL; /* Cannot really happen (see SSL_CTX_new) */ + + s->read_ahead = ctx->read_ahead; + s->msg_callback = ctx->msg_callback; + s->msg_callback_arg = ctx->msg_callback_arg; + s->verify_mode = ctx->verify_mode; +#if 0 + s->verify_depth = ctx->verify_depth; +#endif + s->sid_ctx_length = ctx->sid_ctx_length; + OPENSSL_assert(s->sid_ctx_length <= sizeof s->sid_ctx); + memcpy(&s->sid_ctx, &ctx->sid_ctx, sizeof(s->sid_ctx)); + s->verify_callback = ctx->default_verify_callback; + s->generate_session_id = ctx->generate_session_id; + + s->param = X509_VERIFY_PARAM_new(); + if (!s->param) + goto err; + X509_VERIFY_PARAM_inherit(s->param, ctx->param); +#if 0 + s->purpose = ctx->purpose; + s->trust = ctx->trust; +#endif + s->quiet_shutdown = ctx->quiet_shutdown; + s->max_send_fragment = ctx->max_send_fragment; + + CRYPTO_add(&ctx->references, 1, CRYPTO_LOCK_SSL_CTX); + s->ctx = ctx; +#ifndef OPENSSL_NO_TLSEXT + s->tlsext_debug_cb = 0; + s->tlsext_debug_arg = NULL; + s->tlsext_ticket_expected = 0; + s->tlsext_status_type = -1; + s->tlsext_status_expected = 0; + s->tlsext_ocsp_ids = NULL; + s->tlsext_ocsp_exts = NULL; + s->tlsext_ocsp_resp = NULL; + s->tlsext_ocsp_resplen = -1; + CRYPTO_add(&ctx->references, 1, CRYPTO_LOCK_SSL_CTX); + s->initial_ctx = ctx; +# ifndef OPENSSL_NO_EC + if (ctx->tlsext_ecpointformatlist) { + s->tlsext_ecpointformatlist = + BUF_memdup(ctx->tlsext_ecpointformatlist, + ctx->tlsext_ecpointformatlist_length); + if (!s->tlsext_ecpointformatlist) + goto err; + s->tlsext_ecpointformatlist_length = + ctx->tlsext_ecpointformatlist_length; + } + if (ctx->tlsext_ellipticcurvelist) { + s->tlsext_ellipticcurvelist = + BUF_memdup(ctx->tlsext_ellipticcurvelist, + ctx->tlsext_ellipticcurvelist_length); + if (!s->tlsext_ellipticcurvelist) + goto err; + s->tlsext_ellipticcurvelist_length = + ctx->tlsext_ellipticcurvelist_length; + } +# endif +# ifndef OPENSSL_NO_NEXTPROTONEG + s->next_proto_negotiated = NULL; +# endif + + if (s->ctx->alpn_client_proto_list) { + s->alpn_client_proto_list = + OPENSSL_malloc(s->ctx->alpn_client_proto_list_len); + if (s->alpn_client_proto_list == NULL) + goto err; + memcpy(s->alpn_client_proto_list, s->ctx->alpn_client_proto_list, + s->ctx->alpn_client_proto_list_len); + s->alpn_client_proto_list_len = s->ctx->alpn_client_proto_list_len; + } +#endif + + s->verify_result = X509_V_OK; + + s->method = ctx->method; + + if (!s->method->ssl_new(s)) + goto err; + + s->server = (ctx->method->ssl_accept == ssl_undefined_function) ? 0 : 1; + + SSL_clear(s); + + CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL, s, &s->ex_data); + +#ifndef OPENSSL_NO_PSK + s->psk_client_callback = ctx->psk_client_callback; + s->psk_server_callback = ctx->psk_server_callback; +#endif + + return (s); + err: + if (s != NULL) + SSL_free(s); + SSLerr(SSL_F_SSL_NEW, ERR_R_MALLOC_FAILURE); + return (NULL); +} + +int SSL_CTX_set_session_id_context(SSL_CTX *ctx, const unsigned char *sid_ctx, + unsigned int sid_ctx_len) +{ + if (sid_ctx_len > sizeof ctx->sid_ctx) { + SSLerr(SSL_F_SSL_CTX_SET_SESSION_ID_CONTEXT, + SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG); + return 0; + } + ctx->sid_ctx_length = sid_ctx_len; + memcpy(ctx->sid_ctx, sid_ctx, sid_ctx_len); + + return 1; +} + +int SSL_set_session_id_context(SSL *ssl, const unsigned char *sid_ctx, + unsigned int sid_ctx_len) +{ + if (sid_ctx_len > SSL_MAX_SID_CTX_LENGTH) { + SSLerr(SSL_F_SSL_SET_SESSION_ID_CONTEXT, + SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG); + return 0; + } + ssl->sid_ctx_length = sid_ctx_len; + memcpy(ssl->sid_ctx, sid_ctx, sid_ctx_len); + + return 1; +} + +int SSL_CTX_set_generate_session_id(SSL_CTX *ctx, GEN_SESSION_CB cb) +{ + CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); + ctx->generate_session_id = cb; + CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); + return 1; +} + +int SSL_set_generate_session_id(SSL *ssl, GEN_SESSION_CB cb) +{ + CRYPTO_w_lock(CRYPTO_LOCK_SSL); + ssl->generate_session_id = cb; + CRYPTO_w_unlock(CRYPTO_LOCK_SSL); + return 1; +} + +int SSL_has_matching_session_id(const SSL *ssl, const unsigned char *id, + unsigned int id_len) +{ + /* + * A quick examination of SSL_SESSION_hash and SSL_SESSION_cmp shows how + * we can "construct" a session to give us the desired check - ie. to + * find if there's a session in the hash table that would conflict with + * any new session built out of this id/id_len and the ssl_version in use + * by this SSL. + */ + SSL_SESSION r, *p; + + if (id_len > sizeof r.session_id) + return 0; + + r.ssl_version = ssl->version; + r.session_id_length = id_len; + memcpy(r.session_id, id, id_len); + /* + * NB: SSLv2 always uses a fixed 16-byte session ID, so even if a + * callback is calling us to check the uniqueness of a shorter ID, it + * must be compared as a padded-out ID because that is what it will be + * converted to when the callback has finished choosing it. + */ + if ((r.ssl_version == SSL2_VERSION) && + (id_len < SSL2_SSL_SESSION_ID_LENGTH)) { + memset(r.session_id + id_len, 0, SSL2_SSL_SESSION_ID_LENGTH - id_len); + r.session_id_length = SSL2_SSL_SESSION_ID_LENGTH; + } + + CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX); + p = lh_SSL_SESSION_retrieve(ssl->ctx->sessions, &r); + CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); + return (p != NULL); +} + +int SSL_CTX_set_purpose(SSL_CTX *s, int purpose) +{ + return X509_VERIFY_PARAM_set_purpose(s->param, purpose); +} + +int SSL_set_purpose(SSL *s, int purpose) +{ + return X509_VERIFY_PARAM_set_purpose(s->param, purpose); +} + +int SSL_CTX_set_trust(SSL_CTX *s, int trust) +{ + return X509_VERIFY_PARAM_set_trust(s->param, trust); +} + +int SSL_set_trust(SSL *s, int trust) +{ + return X509_VERIFY_PARAM_set_trust(s->param, trust); +} + +int SSL_CTX_set1_param(SSL_CTX *ctx, X509_VERIFY_PARAM *vpm) +{ + return X509_VERIFY_PARAM_set1(ctx->param, vpm); +} + +int SSL_set1_param(SSL *ssl, X509_VERIFY_PARAM *vpm) +{ + return X509_VERIFY_PARAM_set1(ssl->param, vpm); +} + +X509_VERIFY_PARAM *SSL_CTX_get0_param(SSL_CTX *ctx) +{ + return ctx->param; +} + +X509_VERIFY_PARAM *SSL_get0_param(SSL *ssl) +{ + return ssl->param; +} + +void SSL_certs_clear(SSL *s) +{ + ssl_cert_clear_certs(s->cert); +} + +void SSL_free(SSL *s) +{ + int i; + + if (s == NULL) + return; + + i = CRYPTO_add(&s->references, -1, CRYPTO_LOCK_SSL); +#ifdef REF_PRINT + REF_PRINT("SSL", s); +#endif + if (i > 0) + return; +#ifdef REF_CHECK + if (i < 0) { + fprintf(stderr, "SSL_free, bad reference count\n"); + abort(); /* ok */ + } +#endif + + if (s->param) + X509_VERIFY_PARAM_free(s->param); + + CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL, s, &s->ex_data); + + if (s->bbio != NULL) { + /* If the buffering BIO is in place, pop it off */ + if (s->bbio == s->wbio) { + s->wbio = BIO_pop(s->wbio); + } + BIO_free(s->bbio); + s->bbio = NULL; + } + if (s->rbio != NULL) + BIO_free_all(s->rbio); + if ((s->wbio != NULL) && (s->wbio != s->rbio)) + BIO_free_all(s->wbio); + + if (s->init_buf != NULL) + BUF_MEM_free(s->init_buf); + + /* add extra stuff */ + if (s->cipher_list != NULL) + sk_SSL_CIPHER_free(s->cipher_list); + if (s->cipher_list_by_id != NULL) + sk_SSL_CIPHER_free(s->cipher_list_by_id); + + /* Make the next call work :-) */ + if (s->session != NULL) { + ssl_clear_bad_session(s); + SSL_SESSION_free(s->session); + } + + ssl_clear_cipher_ctx(s); + ssl_clear_hash_ctx(&s->read_hash); + ssl_clear_hash_ctx(&s->write_hash); + + if (s->cert != NULL) + ssl_cert_free(s->cert); + /* Free up if allocated */ + +#ifndef OPENSSL_NO_TLSEXT + if (s->tlsext_hostname) + OPENSSL_free(s->tlsext_hostname); + if (s->initial_ctx) + SSL_CTX_free(s->initial_ctx); +# ifndef OPENSSL_NO_EC + if (s->tlsext_ecpointformatlist) + OPENSSL_free(s->tlsext_ecpointformatlist); + if (s->tlsext_ellipticcurvelist) + OPENSSL_free(s->tlsext_ellipticcurvelist); +# endif /* OPENSSL_NO_EC */ + if (s->tlsext_opaque_prf_input) + OPENSSL_free(s->tlsext_opaque_prf_input); + if (s->tlsext_ocsp_exts) + sk_X509_EXTENSION_pop_free(s->tlsext_ocsp_exts, X509_EXTENSION_free); + if (s->tlsext_ocsp_ids) + sk_OCSP_RESPID_pop_free(s->tlsext_ocsp_ids, OCSP_RESPID_free); + if (s->tlsext_ocsp_resp) + OPENSSL_free(s->tlsext_ocsp_resp); + if (s->alpn_client_proto_list) + OPENSSL_free(s->alpn_client_proto_list); +#endif + + if (s->client_CA != NULL) + sk_X509_NAME_pop_free(s->client_CA, X509_NAME_free); + + if (s->method != NULL) + s->method->ssl_free(s); + + if (s->ctx) + SSL_CTX_free(s->ctx); + +#ifndef OPENSSL_NO_KRB5 + if (s->kssl_ctx != NULL) + kssl_ctx_free(s->kssl_ctx); +#endif /* OPENSSL_NO_KRB5 */ + +#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) + if (s->next_proto_negotiated) + OPENSSL_free(s->next_proto_negotiated); +#endif + +#ifndef OPENSSL_NO_SRTP + if (s->srtp_profiles) + sk_SRTP_PROTECTION_PROFILE_free(s->srtp_profiles); +#endif + + OPENSSL_free(s); +} + +void SSL_set_bio(SSL *s, BIO *rbio, BIO *wbio) +{ + /* + * If the output buffering BIO is still in place, remove it + */ + if (s->bbio != NULL) { + if (s->wbio == s->bbio) { + s->wbio = s->wbio->next_bio; + s->bbio->next_bio = NULL; + } + } + if ((s->rbio != NULL) && (s->rbio != rbio)) + BIO_free_all(s->rbio); + if ((s->wbio != NULL) && (s->wbio != wbio) && (s->rbio != s->wbio)) + BIO_free_all(s->wbio); + s->rbio = rbio; + s->wbio = wbio; +} + +BIO *SSL_get_rbio(const SSL *s) +{ + return (s->rbio); +} + +BIO *SSL_get_wbio(const SSL *s) +{ + return (s->wbio); +} + +int SSL_get_fd(const SSL *s) +{ + return (SSL_get_rfd(s)); +} + +int SSL_get_rfd(const SSL *s) +{ + int ret = -1; + BIO *b, *r; + + b = SSL_get_rbio(s); + r = BIO_find_type(b, BIO_TYPE_DESCRIPTOR); + if (r != NULL) + BIO_get_fd(r, &ret); + return (ret); +} + +int SSL_get_wfd(const SSL *s) +{ + int ret = -1; + BIO *b, *r; + + b = SSL_get_wbio(s); + r = BIO_find_type(b, BIO_TYPE_DESCRIPTOR); + if (r != NULL) + BIO_get_fd(r, &ret); + return (ret); +} + +#ifndef OPENSSL_NO_SOCK +int SSL_set_fd(SSL *s, int fd) +{ + int ret = 0; + BIO *bio = NULL; + + bio = BIO_new(BIO_s_socket()); + + if (bio == NULL) { + SSLerr(SSL_F_SSL_SET_FD, ERR_R_BUF_LIB); + goto err; + } + BIO_set_fd(bio, fd, BIO_NOCLOSE); + SSL_set_bio(s, bio, bio); + ret = 1; + err: + return (ret); +} + +int SSL_set_wfd(SSL *s, int fd) +{ + int ret = 0; + BIO *bio = NULL; + + if ((s->rbio == NULL) || (BIO_method_type(s->rbio) != BIO_TYPE_SOCKET) + || ((int)BIO_get_fd(s->rbio, NULL) != fd)) { + bio = BIO_new(BIO_s_socket()); + + if (bio == NULL) { + SSLerr(SSL_F_SSL_SET_WFD, ERR_R_BUF_LIB); + goto err; + } + BIO_set_fd(bio, fd, BIO_NOCLOSE); + SSL_set_bio(s, SSL_get_rbio(s), bio); + } else + SSL_set_bio(s, SSL_get_rbio(s), SSL_get_rbio(s)); + ret = 1; + err: + return (ret); +} + +int SSL_set_rfd(SSL *s, int fd) +{ + int ret = 0; + BIO *bio = NULL; + + if ((s->wbio == NULL) || (BIO_method_type(s->wbio) != BIO_TYPE_SOCKET) + || ((int)BIO_get_fd(s->wbio, NULL) != fd)) { + bio = BIO_new(BIO_s_socket()); + + if (bio == NULL) { + SSLerr(SSL_F_SSL_SET_RFD, ERR_R_BUF_LIB); + goto err; + } + BIO_set_fd(bio, fd, BIO_NOCLOSE); + SSL_set_bio(s, bio, SSL_get_wbio(s)); + } else + SSL_set_bio(s, SSL_get_wbio(s), SSL_get_wbio(s)); + ret = 1; + err: + return (ret); +} +#endif + +/* return length of latest Finished message we sent, copy to 'buf' */ +size_t SSL_get_finished(const SSL *s, void *buf, size_t count) +{ + size_t ret = 0; + + if (s->s3 != NULL) { + ret = s->s3->tmp.finish_md_len; + if (count > ret) + count = ret; + memcpy(buf, s->s3->tmp.finish_md, count); + } + return ret; +} + +/* return length of latest Finished message we expected, copy to 'buf' */ +size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count) +{ + size_t ret = 0; + + if (s->s3 != NULL) { + ret = s->s3->tmp.peer_finish_md_len; + if (count > ret) + count = ret; + memcpy(buf, s->s3->tmp.peer_finish_md, count); + } + return ret; +} + +int SSL_get_verify_mode(const SSL *s) +{ + return (s->verify_mode); +} + +int SSL_get_verify_depth(const SSL *s) +{ + return X509_VERIFY_PARAM_get_depth(s->param); +} + +int (*SSL_get_verify_callback(const SSL *s)) (int, X509_STORE_CTX *) { + return (s->verify_callback); +} + +int SSL_CTX_get_verify_mode(const SSL_CTX *ctx) +{ + return (ctx->verify_mode); +} + +int SSL_CTX_get_verify_depth(const SSL_CTX *ctx) +{ + return X509_VERIFY_PARAM_get_depth(ctx->param); +} + +int (*SSL_CTX_get_verify_callback(const SSL_CTX *ctx)) (int, X509_STORE_CTX *) { + return (ctx->default_verify_callback); +} + +void SSL_set_verify(SSL *s, int mode, + int (*callback) (int ok, X509_STORE_CTX *ctx)) +{ + s->verify_mode = mode; + if (callback != NULL) + s->verify_callback = callback; +} + +void SSL_set_verify_depth(SSL *s, int depth) +{ + X509_VERIFY_PARAM_set_depth(s->param, depth); +} + +void SSL_set_read_ahead(SSL *s, int yes) +{ + s->read_ahead = yes; +} + +int SSL_get_read_ahead(const SSL *s) +{ + return (s->read_ahead); +} + +int SSL_pending(const SSL *s) +{ + /* + * SSL_pending cannot work properly if read-ahead is enabled + * (SSL_[CTX_]ctrl(..., SSL_CTRL_SET_READ_AHEAD, 1, NULL)), and it is + * impossible to fix since SSL_pending cannot report errors that may be + * observed while scanning the new data. (Note that SSL_pending() is + * often used as a boolean value, so we'd better not return -1.) + */ + return (s->method->ssl_pending(s)); +} + +X509 *SSL_get_peer_certificate(const SSL *s) +{ + X509 *r; + + if ((s == NULL) || (s->session == NULL)) + r = NULL; + else + r = s->session->peer; + + if (r == NULL) + return (r); + + CRYPTO_add(&r->references, 1, CRYPTO_LOCK_X509); + + return (r); +} + +STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *s) +{ + STACK_OF(X509) *r; + + if ((s == NULL) || (s->session == NULL) + || (s->session->sess_cert == NULL)) + r = NULL; + else + r = s->session->sess_cert->cert_chain; + + /* + * If we are a client, cert_chain includes the peer's own certificate; if + * we are a server, it does not. + */ + + return (r); +} + +/* + * Now in theory, since the calling process own 't' it should be safe to + * modify. We need to be able to read f without being hassled + */ +void SSL_copy_session_id(SSL *t, const SSL *f) +{ + CERT *tmp; + + /* Do we need to to SSL locking? */ + SSL_set_session(t, SSL_get_session(f)); + + /* + * what if we are setup as SSLv2 but want to talk SSLv3 or vice-versa + */ + if (t->method != f->method) { + t->method->ssl_free(t); /* cleanup current */ + t->method = f->method; /* change method */ + t->method->ssl_new(t); /* setup new */ + } + + tmp = t->cert; + if (f->cert != NULL) { + CRYPTO_add(&f->cert->references, 1, CRYPTO_LOCK_SSL_CERT); + t->cert = f->cert; + } else + t->cert = NULL; + if (tmp != NULL) + ssl_cert_free(tmp); + SSL_set_session_id_context(t, f->sid_ctx, f->sid_ctx_length); +} + +/* Fix this so it checks all the valid key/cert options */ +int SSL_CTX_check_private_key(const SSL_CTX *ctx) +{ + if ((ctx == NULL) || + (ctx->cert == NULL) || (ctx->cert->key->x509 == NULL)) { + SSLerr(SSL_F_SSL_CTX_CHECK_PRIVATE_KEY, + SSL_R_NO_CERTIFICATE_ASSIGNED); + return (0); + } + if (ctx->cert->key->privatekey == NULL) { + SSLerr(SSL_F_SSL_CTX_CHECK_PRIVATE_KEY, + SSL_R_NO_PRIVATE_KEY_ASSIGNED); + return (0); + } + return (X509_check_private_key + (ctx->cert->key->x509, ctx->cert->key->privatekey)); +} + +/* Fix this function so that it takes an optional type parameter */ +int SSL_check_private_key(const SSL *ssl) +{ + if (ssl == NULL) { + SSLerr(SSL_F_SSL_CHECK_PRIVATE_KEY, ERR_R_PASSED_NULL_PARAMETER); + return (0); + } + if (ssl->cert == NULL) { + SSLerr(SSL_F_SSL_CHECK_PRIVATE_KEY, SSL_R_NO_CERTIFICATE_ASSIGNED); + return 0; + } + if (ssl->cert->key->x509 == NULL) { + SSLerr(SSL_F_SSL_CHECK_PRIVATE_KEY, SSL_R_NO_CERTIFICATE_ASSIGNED); + return (0); + } + if (ssl->cert->key->privatekey == NULL) { + SSLerr(SSL_F_SSL_CHECK_PRIVATE_KEY, SSL_R_NO_PRIVATE_KEY_ASSIGNED); + return (0); + } + return (X509_check_private_key(ssl->cert->key->x509, + ssl->cert->key->privatekey)); +} + +int SSL_accept(SSL *s) +{ + if (s->handshake_func == 0) + /* Not properly initialized yet */ + SSL_set_accept_state(s); + + return (s->method->ssl_accept(s)); +} + +int SSL_connect(SSL *s) +{ + if (s->handshake_func == 0) + /* Not properly initialized yet */ + SSL_set_connect_state(s); + + return (s->method->ssl_connect(s)); +} + +long SSL_get_default_timeout(const SSL *s) +{ + return (s->method->get_timeout()); +} + +int SSL_read(SSL *s, void *buf, int num) +{ + if (s->handshake_func == 0) { + SSLerr(SSL_F_SSL_READ, SSL_R_UNINITIALIZED); + return -1; + } + + if (s->shutdown & SSL_RECEIVED_SHUTDOWN) { + s->rwstate = SSL_NOTHING; + return (0); + } + return (s->method->ssl_read(s, buf, num)); +} + +int SSL_peek(SSL *s, void *buf, int num) +{ + if (s->handshake_func == 0) { + SSLerr(SSL_F_SSL_PEEK, SSL_R_UNINITIALIZED); + return -1; + } + + if (s->shutdown & SSL_RECEIVED_SHUTDOWN) { + return (0); + } + return (s->method->ssl_peek(s, buf, num)); +} + +int SSL_write(SSL *s, const void *buf, int num) +{ + if (s->handshake_func == 0) { + SSLerr(SSL_F_SSL_WRITE, SSL_R_UNINITIALIZED); + return -1; + } + + if (s->shutdown & SSL_SENT_SHUTDOWN) { + s->rwstate = SSL_NOTHING; + SSLerr(SSL_F_SSL_WRITE, SSL_R_PROTOCOL_IS_SHUTDOWN); + return (-1); + } + return (s->method->ssl_write(s, buf, num)); +} + +int SSL_shutdown(SSL *s) +{ + /* + * Note that this function behaves differently from what one might + * expect. Return values are 0 for no success (yet), 1 for success; but + * calling it once is usually not enough, even if blocking I/O is used + * (see ssl3_shutdown). + */ + + if (s->handshake_func == 0) { + SSLerr(SSL_F_SSL_SHUTDOWN, SSL_R_UNINITIALIZED); + return -1; + } + + if (!SSL_in_init(s)) { + return s->method->ssl_shutdown(s); + } else { + SSLerr(SSL_F_SSL_SHUTDOWN, SSL_R_SHUTDOWN_WHILE_IN_INIT); + return -1; + } +} + +int SSL_renegotiate(SSL *s) +{ + if (s->renegotiate == 0) + s->renegotiate = 1; + + s->new_session = 1; + + return (s->method->ssl_renegotiate(s)); +} + +int SSL_renegotiate_abbreviated(SSL *s) +{ + if (s->renegotiate == 0) + s->renegotiate = 1; + + s->new_session = 0; + + return (s->method->ssl_renegotiate(s)); +} + +int SSL_renegotiate_pending(SSL *s) +{ + /* + * becomes true when negotiation is requested; false again once a + * handshake has finished + */ + return (s->renegotiate != 0); +} + +long SSL_ctrl(SSL *s, int cmd, long larg, void *parg) +{ + long l; + + switch (cmd) { + case SSL_CTRL_GET_READ_AHEAD: + return (s->read_ahead); + case SSL_CTRL_SET_READ_AHEAD: + l = s->read_ahead; + s->read_ahead = larg; + return (l); + + case SSL_CTRL_SET_MSG_CALLBACK_ARG: + s->msg_callback_arg = parg; + return 1; + + case SSL_CTRL_OPTIONS: + return (s->options |= larg); + case SSL_CTRL_CLEAR_OPTIONS: + return (s->options &= ~larg); + case SSL_CTRL_MODE: + return (s->mode |= larg); + case SSL_CTRL_CLEAR_MODE: + return (s->mode &= ~larg); + case SSL_CTRL_GET_MAX_CERT_LIST: + return (s->max_cert_list); + case SSL_CTRL_SET_MAX_CERT_LIST: + l = s->max_cert_list; + s->max_cert_list = larg; + return (l); + case SSL_CTRL_SET_MAX_SEND_FRAGMENT: + if (larg < 512 || larg > SSL3_RT_MAX_PLAIN_LENGTH) + return 0; + s->max_send_fragment = larg; + return 1; + case SSL_CTRL_GET_RI_SUPPORT: + if (s->s3) + return s->s3->send_connection_binding; + else + return 0; + case SSL_CTRL_CERT_FLAGS: + return (s->cert->cert_flags |= larg); + case SSL_CTRL_CLEAR_CERT_FLAGS: + return (s->cert->cert_flags &= ~larg); + + case SSL_CTRL_GET_RAW_CIPHERLIST: + if (parg) { + if (s->cert->ciphers_raw == NULL) + return 0; + *(unsigned char **)parg = s->cert->ciphers_raw; + return (int)s->cert->ciphers_rawlen; + } else + return ssl_put_cipher_by_char(s, NULL, NULL); + default: + return (s->method->ssl_ctrl(s, cmd, larg, parg)); + } +} + +long SSL_callback_ctrl(SSL *s, int cmd, void (*fp) (void)) +{ + switch (cmd) { + case SSL_CTRL_SET_MSG_CALLBACK: + s->msg_callback = (void (*) + (int write_p, int version, int content_type, + const void *buf, size_t len, SSL *ssl, + void *arg))(fp); + return 1; + + default: + return (s->method->ssl_callback_ctrl(s, cmd, fp)); + } +} + +LHASH_OF(SSL_SESSION) *SSL_CTX_sessions(SSL_CTX *ctx) +{ + return ctx->sessions; +} + +long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) +{ + long l; + /* For some cases with ctx == NULL perform syntax checks */ + if (ctx == NULL) { + switch (cmd) { +#ifndef OPENSSL_NO_EC + case SSL_CTRL_SET_CURVES_LIST: + return tls1_set_curves_list(NULL, NULL, parg); +#endif + case SSL_CTRL_SET_SIGALGS_LIST: + case SSL_CTRL_SET_CLIENT_SIGALGS_LIST: + return tls1_set_sigalgs_list(NULL, parg, 0); + default: + return 0; + } + } + + switch (cmd) { + case SSL_CTRL_GET_READ_AHEAD: + return (ctx->read_ahead); + case SSL_CTRL_SET_READ_AHEAD: + l = ctx->read_ahead; + ctx->read_ahead = larg; + return (l); + + case SSL_CTRL_SET_MSG_CALLBACK_ARG: + ctx->msg_callback_arg = parg; + return 1; + + case SSL_CTRL_GET_MAX_CERT_LIST: + return (ctx->max_cert_list); + case SSL_CTRL_SET_MAX_CERT_LIST: + l = ctx->max_cert_list; + ctx->max_cert_list = larg; + return (l); + + case SSL_CTRL_SET_SESS_CACHE_SIZE: + l = ctx->session_cache_size; + ctx->session_cache_size = larg; + return (l); + case SSL_CTRL_GET_SESS_CACHE_SIZE: + return (ctx->session_cache_size); + case SSL_CTRL_SET_SESS_CACHE_MODE: + l = ctx->session_cache_mode; + ctx->session_cache_mode = larg; + return (l); + case SSL_CTRL_GET_SESS_CACHE_MODE: + return (ctx->session_cache_mode); + + case SSL_CTRL_SESS_NUMBER: + return (lh_SSL_SESSION_num_items(ctx->sessions)); + case SSL_CTRL_SESS_CONNECT: + return (ctx->stats.sess_connect); + case SSL_CTRL_SESS_CONNECT_GOOD: + return (ctx->stats.sess_connect_good); + case SSL_CTRL_SESS_CONNECT_RENEGOTIATE: + return (ctx->stats.sess_connect_renegotiate); + case SSL_CTRL_SESS_ACCEPT: + return (ctx->stats.sess_accept); + case SSL_CTRL_SESS_ACCEPT_GOOD: + return (ctx->stats.sess_accept_good); + case SSL_CTRL_SESS_ACCEPT_RENEGOTIATE: + return (ctx->stats.sess_accept_renegotiate); + case SSL_CTRL_SESS_HIT: + return (ctx->stats.sess_hit); + case SSL_CTRL_SESS_CB_HIT: + return (ctx->stats.sess_cb_hit); + case SSL_CTRL_SESS_MISSES: + return (ctx->stats.sess_miss); + case SSL_CTRL_SESS_TIMEOUTS: + return (ctx->stats.sess_timeout); + case SSL_CTRL_SESS_CACHE_FULL: + return (ctx->stats.sess_cache_full); + case SSL_CTRL_OPTIONS: + return (ctx->options |= larg); + case SSL_CTRL_CLEAR_OPTIONS: + return (ctx->options &= ~larg); + case SSL_CTRL_MODE: + return (ctx->mode |= larg); + case SSL_CTRL_CLEAR_MODE: + return (ctx->mode &= ~larg); + case SSL_CTRL_SET_MAX_SEND_FRAGMENT: + if (larg < 512 || larg > SSL3_RT_MAX_PLAIN_LENGTH) + return 0; + ctx->max_send_fragment = larg; + return 1; + case SSL_CTRL_CERT_FLAGS: + return (ctx->cert->cert_flags |= larg); + case SSL_CTRL_CLEAR_CERT_FLAGS: + return (ctx->cert->cert_flags &= ~larg); + default: + return (ctx->method->ssl_ctx_ctrl(ctx, cmd, larg, parg)); + } +} + +long SSL_CTX_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp) (void)) +{ + switch (cmd) { + case SSL_CTRL_SET_MSG_CALLBACK: + ctx->msg_callback = (void (*) + (int write_p, int version, int content_type, + const void *buf, size_t len, SSL *ssl, + void *arg))(fp); + return 1; + + default: + return (ctx->method->ssl_ctx_callback_ctrl(ctx, cmd, fp)); + } +} + +int ssl_cipher_id_cmp(const SSL_CIPHER *a, const SSL_CIPHER *b) +{ + long l; + + l = a->id - b->id; + if (l == 0L) + return (0); + else + return ((l > 0) ? 1 : -1); +} + +int ssl_cipher_ptr_id_cmp(const SSL_CIPHER *const *ap, + const SSL_CIPHER *const *bp) +{ + long l; + + l = (*ap)->id - (*bp)->id; + if (l == 0L) + return (0); + else + return ((l > 0) ? 1 : -1); +} + +/** return a STACK of the ciphers available for the SSL and in order of + * preference */ +STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s) +{ + if (s != NULL) { + if (s->cipher_list != NULL) { + return (s->cipher_list); + } else if ((s->ctx != NULL) && (s->ctx->cipher_list != NULL)) { + return (s->ctx->cipher_list); + } + } + return (NULL); +} + +/** return a STACK of the ciphers available for the SSL and in order of + * algorithm id */ +STACK_OF(SSL_CIPHER) *ssl_get_ciphers_by_id(SSL *s) +{ + if (s != NULL) { + if (s->cipher_list_by_id != NULL) { + return (s->cipher_list_by_id); + } else if ((s->ctx != NULL) && (s->ctx->cipher_list_by_id != NULL)) { + return (s->ctx->cipher_list_by_id); + } + } + return (NULL); +} + +/** The old interface to get the same thing as SSL_get_ciphers() */ +const char *SSL_get_cipher_list(const SSL *s, int n) +{ + SSL_CIPHER *c; + STACK_OF(SSL_CIPHER) *sk; + + if (s == NULL) + return (NULL); + sk = SSL_get_ciphers(s); + if ((sk == NULL) || (sk_SSL_CIPHER_num(sk) <= n)) + return (NULL); + c = sk_SSL_CIPHER_value(sk, n); + if (c == NULL) + return (NULL); + return (c->name); +} + +/** specify the ciphers to be used by default by the SSL_CTX */ +int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str) +{ + STACK_OF(SSL_CIPHER) *sk; + + sk = ssl_create_cipher_list(ctx->method, &ctx->cipher_list, + &ctx->cipher_list_by_id, str, ctx->cert); + /* + * ssl_create_cipher_list may return an empty stack if it was unable to + * find a cipher matching the given rule string (for example if the rule + * string specifies a cipher which has been disabled). This is not an + * error as far as ssl_create_cipher_list is concerned, and hence + * ctx->cipher_list and ctx->cipher_list_by_id has been updated. + */ + if (sk == NULL) + return 0; + else if (sk_SSL_CIPHER_num(sk) == 0) { + SSLerr(SSL_F_SSL_CTX_SET_CIPHER_LIST, SSL_R_NO_CIPHER_MATCH); + return 0; + } + return 1; +} + +/** specify the ciphers to be used by the SSL */ +int SSL_set_cipher_list(SSL *s, const char *str) +{ + STACK_OF(SSL_CIPHER) *sk; + + sk = ssl_create_cipher_list(s->ctx->method, &s->cipher_list, + &s->cipher_list_by_id, str, s->cert); + /* see comment in SSL_CTX_set_cipher_list */ + if (sk == NULL) + return 0; + else if (sk_SSL_CIPHER_num(sk) == 0) { + SSLerr(SSL_F_SSL_SET_CIPHER_LIST, SSL_R_NO_CIPHER_MATCH); + return 0; + } + return 1; +} + +/* works well for SSLv2, not so good for SSLv3 */ +char *SSL_get_shared_ciphers(const SSL *s, char *buf, int len) +{ + char *p; + STACK_OF(SSL_CIPHER) *sk; + SSL_CIPHER *c; + int i; + + if ((s->session == NULL) || (s->session->ciphers == NULL) || (len < 2)) + return (NULL); + + p = buf; + sk = s->session->ciphers; + + if (sk_SSL_CIPHER_num(sk) == 0) + return NULL; + + for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) { + int n; + + c = sk_SSL_CIPHER_value(sk, i); + n = strlen(c->name); + if (n + 1 > len) { + if (p != buf) + --p; + *p = '\0'; + return buf; + } + strcpy(p, c->name); + p += n; + *(p++) = ':'; + len -= n + 1; + } + p[-1] = '\0'; + return (buf); +} + +int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk, + unsigned char *p, + int (*put_cb) (const SSL_CIPHER *, + unsigned char *)) +{ + int i, j = 0; + SSL_CIPHER *c; + CERT *ct = s->cert; + unsigned char *q; + int empty_reneg_info_scsv = !s->renegotiate; + /* Set disabled masks for this session */ + ssl_set_client_disabled(s); + + if (sk == NULL) + return (0); + q = p; + if (put_cb == NULL) + put_cb = s->method->put_cipher_by_char; + + for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) { + c = sk_SSL_CIPHER_value(sk, i); + /* Skip disabled ciphers */ + if (c->algorithm_ssl & ct->mask_ssl || + c->algorithm_mkey & ct->mask_k || c->algorithm_auth & ct->mask_a) + continue; +#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL + if (c->id == SSL3_CK_SCSV) { + if (!empty_reneg_info_scsv) + continue; + else + empty_reneg_info_scsv = 0; + } +#endif + j = put_cb(c, p); + p += j; + } + /* + * If p == q, no ciphers; caller indicates an error. Otherwise, add + * applicable SCSVs. + */ + if (p != q) { + if (empty_reneg_info_scsv) { + static SSL_CIPHER scsv = { + 0, NULL, SSL3_CK_SCSV, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + j = put_cb(&scsv, p); + p += j; +#ifdef OPENSSL_RI_DEBUG + fprintf(stderr, + "TLS_EMPTY_RENEGOTIATION_INFO_SCSV sent by client\n"); +#endif + } + if (s->mode & SSL_MODE_SEND_FALLBACK_SCSV) { + static SSL_CIPHER scsv = { + 0, NULL, SSL3_CK_FALLBACK_SCSV, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + j = put_cb(&scsv, p); + p += j; + } + } + + return (p - q); +} + +STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, unsigned char *p, + int num, + STACK_OF(SSL_CIPHER) **skp) +{ + const SSL_CIPHER *c; + STACK_OF(SSL_CIPHER) *sk; + int i, n; + + if (s->s3) + s->s3->send_connection_binding = 0; + + n = ssl_put_cipher_by_char(s, NULL, NULL); + if (n == 0 || (num % n) != 0) { + SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST, + SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST); + return (NULL); + } + if ((skp == NULL) || (*skp == NULL)) { + sk = sk_SSL_CIPHER_new_null(); /* change perhaps later */ + if(sk == NULL) { + SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST, ERR_R_MALLOC_FAILURE); + return NULL; + } + } else { + sk = *skp; + sk_SSL_CIPHER_zero(sk); + } + + if (s->cert->ciphers_raw) + OPENSSL_free(s->cert->ciphers_raw); + s->cert->ciphers_raw = BUF_memdup(p, num); + if (s->cert->ciphers_raw == NULL) { + SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST, ERR_R_MALLOC_FAILURE); + goto err; + } + s->cert->ciphers_rawlen = (size_t)num; + + for (i = 0; i < num; i += n) { + /* Check for TLS_EMPTY_RENEGOTIATION_INFO_SCSV */ + if (s->s3 && (n != 3 || !p[0]) && + (p[n - 2] == ((SSL3_CK_SCSV >> 8) & 0xff)) && + (p[n - 1] == (SSL3_CK_SCSV & 0xff))) { + /* SCSV fatal if renegotiating */ + if (s->renegotiate) { + SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST, + SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING); + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); + goto err; + } + s->s3->send_connection_binding = 1; + p += n; +#ifdef OPENSSL_RI_DEBUG + fprintf(stderr, "SCSV received by server\n"); +#endif + continue; + } + + /* Check for TLS_FALLBACK_SCSV */ + if ((n != 3 || !p[0]) && + (p[n - 2] == ((SSL3_CK_FALLBACK_SCSV >> 8) & 0xff)) && + (p[n - 1] == (SSL3_CK_FALLBACK_SCSV & 0xff))) { + /* + * The SCSV indicates that the client previously tried a higher + * version. Fail if the current version is an unexpected + * downgrade. + */ + if (!SSL_ctrl(s, SSL_CTRL_CHECK_PROTO_VERSION, 0, NULL)) { + SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST, + SSL_R_INAPPROPRIATE_FALLBACK); + if (s->s3) + ssl3_send_alert(s, SSL3_AL_FATAL, + SSL_AD_INAPPROPRIATE_FALLBACK); + goto err; + } + p += n; + continue; + } + + c = ssl_get_cipher_by_char(s, p); + p += n; + if (c != NULL) { + if (!sk_SSL_CIPHER_push(sk, c)) { + SSLerr(SSL_F_SSL_BYTES_TO_CIPHER_LIST, ERR_R_MALLOC_FAILURE); + goto err; + } + } + } + + if (skp != NULL) + *skp = sk; + return (sk); + err: + if ((skp == NULL) || (*skp == NULL)) + sk_SSL_CIPHER_free(sk); + return (NULL); +} + +#ifndef OPENSSL_NO_TLSEXT +/** return a servername extension value if provided in Client Hello, or NULL. + * So far, only host_name types are defined (RFC 3546). + */ + +const char *SSL_get_servername(const SSL *s, const int type) +{ + if (type != TLSEXT_NAMETYPE_host_name) + return NULL; + + return s->session && !s->tlsext_hostname ? + s->session->tlsext_hostname : s->tlsext_hostname; +} + +int SSL_get_servername_type(const SSL *s) +{ + if (s->session + && (!s->tlsext_hostname ? s->session-> + tlsext_hostname : s->tlsext_hostname)) + return TLSEXT_NAMETYPE_host_name; + return -1; +} + +/* + * SSL_select_next_proto implements the standard protocol selection. It is + * expected that this function is called from the callback set by + * SSL_CTX_set_next_proto_select_cb. The protocol data is assumed to be a + * vector of 8-bit, length prefixed byte strings. The length byte itself is + * not included in the length. A byte string of length 0 is invalid. No byte + * string may be truncated. The current, but experimental algorithm for + * selecting the protocol is: 1) If the server doesn't support NPN then this + * is indicated to the callback. In this case, the client application has to + * abort the connection or have a default application level protocol. 2) If + * the server supports NPN, but advertises an empty list then the client + * selects the first protcol in its list, but indicates via the API that this + * fallback case was enacted. 3) Otherwise, the client finds the first + * protocol in the server's list that it supports and selects this protocol. + * This is because it's assumed that the server has better information about + * which protocol a client should use. 4) If the client doesn't support any + * of the server's advertised protocols, then this is treated the same as + * case 2. It returns either OPENSSL_NPN_NEGOTIATED if a common protocol was + * found, or OPENSSL_NPN_NO_OVERLAP if the fallback case was reached. + */ +int SSL_select_next_proto(unsigned char **out, unsigned char *outlen, + const unsigned char *server, + unsigned int server_len, + const unsigned char *client, + unsigned int client_len) +{ + unsigned int i, j; + const unsigned char *result; + int status = OPENSSL_NPN_UNSUPPORTED; + + /* + * For each protocol in server preference order, see if we support it. + */ + for (i = 0; i < server_len;) { + for (j = 0; j < client_len;) { + if (server[i] == client[j] && + memcmp(&server[i + 1], &client[j + 1], server[i]) == 0) { + /* We found a match */ + result = &server[i]; + status = OPENSSL_NPN_NEGOTIATED; + goto found; + } + j += client[j]; + j++; + } + i += server[i]; + i++; + } + + /* There's no overlap between our protocols and the server's list. */ + result = client; + status = OPENSSL_NPN_NO_OVERLAP; + + found: + *out = (unsigned char *)result + 1; + *outlen = result[0]; + return status; +} + +# ifndef OPENSSL_NO_NEXTPROTONEG +/* + * SSL_get0_next_proto_negotiated sets *data and *len to point to the + * client's requested protocol for this connection and returns 0. If the + * client didn't request any protocol, then *data is set to NULL. Note that + * the client can request any protocol it chooses. The value returned from + * this function need not be a member of the list of supported protocols + * provided by the callback. + */ +void SSL_get0_next_proto_negotiated(const SSL *s, const unsigned char **data, + unsigned *len) +{ + *data = s->next_proto_negotiated; + if (!*data) { + *len = 0; + } else { + *len = s->next_proto_negotiated_len; + } +} + +/* + * SSL_CTX_set_next_protos_advertised_cb sets a callback that is called when + * a TLS server needs a list of supported protocols for Next Protocol + * Negotiation. The returned list must be in wire format. The list is + * returned by setting |out| to point to it and |outlen| to its length. This + * memory will not be modified, but one should assume that the SSL* keeps a + * reference to it. The callback should return SSL_TLSEXT_ERR_OK if it + * wishes to advertise. Otherwise, no such extension will be included in the + * ServerHello. + */ +void SSL_CTX_set_next_protos_advertised_cb(SSL_CTX *ctx, + int (*cb) (SSL *ssl, + const unsigned char + **out, + unsigned int *outlen, + void *arg), void *arg) +{ + ctx->next_protos_advertised_cb = cb; + ctx->next_protos_advertised_cb_arg = arg; +} + +/* + * SSL_CTX_set_next_proto_select_cb sets a callback that is called when a + * client needs to select a protocol from the server's provided list. |out| + * must be set to point to the selected protocol (which may be within |in|). + * The length of the protocol name must be written into |outlen|. The + * server's advertised protocols are provided in |in| and |inlen|. The + * callback can assume that |in| is syntactically valid. The client must + * select a protocol. It is fatal to the connection if this callback returns + * a value other than SSL_TLSEXT_ERR_OK. + */ +void SSL_CTX_set_next_proto_select_cb(SSL_CTX *ctx, + int (*cb) (SSL *s, unsigned char **out, + unsigned char *outlen, + const unsigned char *in, + unsigned int inlen, + void *arg), void *arg) +{ + ctx->next_proto_select_cb = cb; + ctx->next_proto_select_cb_arg = arg; +} +# endif + +/* + * SSL_CTX_set_alpn_protos sets the ALPN protocol list on |ctx| to |protos|. + * |protos| must be in wire-format (i.e. a series of non-empty, 8-bit + * length-prefixed strings). Returns 0 on success. + */ +int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const unsigned char *protos, + unsigned protos_len) +{ + if (ctx->alpn_client_proto_list) + OPENSSL_free(ctx->alpn_client_proto_list); + + ctx->alpn_client_proto_list = OPENSSL_malloc(protos_len); + if (!ctx->alpn_client_proto_list) + return 1; + memcpy(ctx->alpn_client_proto_list, protos, protos_len); + ctx->alpn_client_proto_list_len = protos_len; + + return 0; +} + +/* + * SSL_set_alpn_protos sets the ALPN protocol list on |ssl| to |protos|. + * |protos| must be in wire-format (i.e. a series of non-empty, 8-bit + * length-prefixed strings). Returns 0 on success. + */ +int SSL_set_alpn_protos(SSL *ssl, const unsigned char *protos, + unsigned protos_len) +{ + if (ssl->alpn_client_proto_list) + OPENSSL_free(ssl->alpn_client_proto_list); + + ssl->alpn_client_proto_list = OPENSSL_malloc(protos_len); + if (!ssl->alpn_client_proto_list) + return 1; + memcpy(ssl->alpn_client_proto_list, protos, protos_len); + ssl->alpn_client_proto_list_len = protos_len; + + return 0; +} + +/* + * SSL_CTX_set_alpn_select_cb sets a callback function on |ctx| that is + * called during ClientHello processing in order to select an ALPN protocol + * from the client's list of offered protocols. + */ +void SSL_CTX_set_alpn_select_cb(SSL_CTX *ctx, + int (*cb) (SSL *ssl, + const unsigned char **out, + unsigned char *outlen, + const unsigned char *in, + unsigned int inlen, + void *arg), void *arg) +{ + ctx->alpn_select_cb = cb; + ctx->alpn_select_cb_arg = arg; +} + +/* + * SSL_get0_alpn_selected gets the selected ALPN protocol (if any) from + * |ssl|. On return it sets |*data| to point to |*len| bytes of protocol name + * (not including the leading length-prefix byte). If the server didn't + * respond with a negotiated protocol then |*len| will be zero. + */ +void SSL_get0_alpn_selected(const SSL *ssl, const unsigned char **data, + unsigned *len) +{ + *data = NULL; + if (ssl->s3) + *data = ssl->s3->alpn_selected; + if (*data == NULL) + *len = 0; + else + *len = ssl->s3->alpn_selected_len; +} + +#endif /* !OPENSSL_NO_TLSEXT */ + +int SSL_export_keying_material(SSL *s, unsigned char *out, size_t olen, + const char *label, size_t llen, + const unsigned char *p, size_t plen, + int use_context) +{ + if (s->version < TLS1_VERSION) + return -1; + + return s->method->ssl3_enc->export_keying_material(s, out, olen, label, + llen, p, plen, + use_context); +} + +static unsigned long ssl_session_hash(const SSL_SESSION *a) +{ + unsigned long l; + + l = (unsigned long) + ((unsigned int)a->session_id[0]) | + ((unsigned int)a->session_id[1] << 8L) | + ((unsigned long)a->session_id[2] << 16L) | + ((unsigned long)a->session_id[3] << 24L); + return (l); +} + +/* + * NB: If this function (or indeed the hash function which uses a sort of + * coarser function than this one) is changed, ensure + * SSL_CTX_has_matching_session_id() is checked accordingly. It relies on + * being able to construct an SSL_SESSION that will collide with any existing + * session with a matching session ID. + */ +static int ssl_session_cmp(const SSL_SESSION *a, const SSL_SESSION *b) +{ + if (a->ssl_version != b->ssl_version) + return (1); + if (a->session_id_length != b->session_id_length) + return (1); + return (memcmp(a->session_id, b->session_id, a->session_id_length)); +} + +/* + * These wrapper functions should remain rather than redeclaring + * SSL_SESSION_hash and SSL_SESSION_cmp for void* types and casting each + * variable. The reason is that the functions aren't static, they're exposed + * via ssl.h. + */ +static IMPLEMENT_LHASH_HASH_FN(ssl_session, SSL_SESSION) +static IMPLEMENT_LHASH_COMP_FN(ssl_session, SSL_SESSION) + +SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth) +{ + SSL_CTX *ret = NULL; + + if (meth == NULL) { + SSLerr(SSL_F_SSL_CTX_NEW, SSL_R_NULL_SSL_METHOD_PASSED); + return (NULL); + } +#ifdef OPENSSL_FIPS + if (FIPS_mode() && (meth->version < TLS1_VERSION)) { + SSLerr(SSL_F_SSL_CTX_NEW, SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE); + return NULL; + } +#endif + + if (SSL_get_ex_data_X509_STORE_CTX_idx() < 0) { + SSLerr(SSL_F_SSL_CTX_NEW, SSL_R_X509_VERIFICATION_SETUP_PROBLEMS); + goto err; + } + ret = (SSL_CTX *)OPENSSL_malloc(sizeof(SSL_CTX)); + if (ret == NULL) + goto err; + + memset(ret, 0, sizeof(SSL_CTX)); + + ret->method = meth; + + ret->cert_store = NULL; + ret->session_cache_mode = SSL_SESS_CACHE_SERVER; + ret->session_cache_size = SSL_SESSION_CACHE_MAX_SIZE_DEFAULT; + ret->session_cache_head = NULL; + ret->session_cache_tail = NULL; + + /* We take the system default */ + ret->session_timeout = meth->get_timeout(); + + ret->new_session_cb = 0; + ret->remove_session_cb = 0; + ret->get_session_cb = 0; + ret->generate_session_id = 0; + + memset((char *)&ret->stats, 0, sizeof(ret->stats)); + + ret->references = 1; + ret->quiet_shutdown = 0; + +/* ret->cipher=NULL;*/ +/*- + ret->s2->challenge=NULL; + ret->master_key=NULL; + ret->key_arg=NULL; + ret->s2->conn_id=NULL; */ + + ret->info_callback = NULL; + + ret->app_verify_callback = 0; + ret->app_verify_arg = NULL; + + ret->max_cert_list = SSL_MAX_CERT_LIST_DEFAULT; + ret->read_ahead = 0; + ret->msg_callback = 0; + ret->msg_callback_arg = NULL; + ret->verify_mode = SSL_VERIFY_NONE; +#if 0 + ret->verify_depth = -1; /* Don't impose a limit (but x509_lu.c does) */ +#endif + ret->sid_ctx_length = 0; + ret->default_verify_callback = NULL; + if ((ret->cert = ssl_cert_new()) == NULL) + goto err; + + ret->default_passwd_callback = 0; + ret->default_passwd_callback_userdata = NULL; + ret->client_cert_cb = 0; + ret->app_gen_cookie_cb = 0; + ret->app_verify_cookie_cb = 0; + + ret->sessions = lh_SSL_SESSION_new(); + if (ret->sessions == NULL) + goto err; + ret->cert_store = X509_STORE_new(); + if (ret->cert_store == NULL) + goto err; + + ssl_create_cipher_list(ret->method, + &ret->cipher_list, &ret->cipher_list_by_id, + meth->version == + SSL2_VERSION ? "SSLv2" : SSL_DEFAULT_CIPHER_LIST, + ret->cert); + if (ret->cipher_list == NULL || sk_SSL_CIPHER_num(ret->cipher_list) <= 0) { + SSLerr(SSL_F_SSL_CTX_NEW, SSL_R_LIBRARY_HAS_NO_CIPHERS); + goto err2; + } + + ret->param = X509_VERIFY_PARAM_new(); + if (!ret->param) + goto err; + + if ((ret->rsa_md5 = EVP_get_digestbyname("ssl2-md5")) == NULL) { + SSLerr(SSL_F_SSL_CTX_NEW, SSL_R_UNABLE_TO_LOAD_SSL2_MD5_ROUTINES); + goto err2; + } + if ((ret->md5 = EVP_get_digestbyname("ssl3-md5")) == NULL) { + SSLerr(SSL_F_SSL_CTX_NEW, SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES); + goto err2; + } + if ((ret->sha1 = EVP_get_digestbyname("ssl3-sha1")) == NULL) { + SSLerr(SSL_F_SSL_CTX_NEW, SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES); + goto err2; + } + + if ((ret->client_CA = sk_X509_NAME_new_null()) == NULL) + goto err; + + CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL_CTX, ret, &ret->ex_data); + + ret->extra_certs = NULL; + /* No compression for DTLS */ + if (!(meth->ssl3_enc->enc_flags & SSL_ENC_FLAG_DTLS)) + ret->comp_methods = SSL_COMP_get_compression_methods(); + + ret->max_send_fragment = SSL3_RT_MAX_PLAIN_LENGTH; + +#ifndef OPENSSL_NO_TLSEXT + ret->tlsext_servername_callback = 0; + ret->tlsext_servername_arg = NULL; + /* Setup RFC4507 ticket keys */ + if ((RAND_pseudo_bytes(ret->tlsext_tick_key_name, 16) <= 0) + || (RAND_bytes(ret->tlsext_tick_hmac_key, 16) <= 0) + || (RAND_bytes(ret->tlsext_tick_aes_key, 16) <= 0)) + ret->options |= SSL_OP_NO_TICKET; + + ret->tlsext_status_cb = 0; + ret->tlsext_status_arg = NULL; + +# ifndef OPENSSL_NO_NEXTPROTONEG + ret->next_protos_advertised_cb = 0; + ret->next_proto_select_cb = 0; +# endif +#endif +#ifndef OPENSSL_NO_PSK + ret->psk_identity_hint = NULL; + ret->psk_client_callback = NULL; + ret->psk_server_callback = NULL; +#endif +#ifndef OPENSSL_NO_SRP + SSL_CTX_SRP_CTX_init(ret); +#endif +#ifndef OPENSSL_NO_BUF_FREELISTS + ret->freelist_max_len = SSL_MAX_BUF_FREELIST_LEN_DEFAULT; + ret->rbuf_freelist = OPENSSL_malloc(sizeof(SSL3_BUF_FREELIST)); + if (!ret->rbuf_freelist) + goto err; + ret->rbuf_freelist->chunklen = 0; + ret->rbuf_freelist->len = 0; + ret->rbuf_freelist->head = NULL; + ret->wbuf_freelist = OPENSSL_malloc(sizeof(SSL3_BUF_FREELIST)); + if (!ret->wbuf_freelist) { + OPENSSL_free(ret->rbuf_freelist); + goto err; + } + ret->wbuf_freelist->chunklen = 0; + ret->wbuf_freelist->len = 0; + ret->wbuf_freelist->head = NULL; +#endif +#ifndef OPENSSL_NO_ENGINE + ret->client_cert_engine = NULL; +# ifdef OPENSSL_SSL_CLIENT_ENGINE_AUTO +# define eng_strx(x) #x +# define eng_str(x) eng_strx(x) + /* Use specific client engine automatically... ignore errors */ + { + ENGINE *eng; + eng = ENGINE_by_id(eng_str(OPENSSL_SSL_CLIENT_ENGINE_AUTO)); + if (!eng) { + ERR_clear_error(); + ENGINE_load_builtin_engines(); + eng = ENGINE_by_id(eng_str(OPENSSL_SSL_CLIENT_ENGINE_AUTO)); + } + if (!eng || !SSL_CTX_set_client_cert_engine(ret, eng)) + ERR_clear_error(); + } +# endif +#endif + /* + * Default is to connect to non-RI servers. When RI is more widely + * deployed might change this. + */ + ret->options |= SSL_OP_LEGACY_SERVER_CONNECT; + + /* + * Disable SSLv2 by default, callers that want to enable SSLv2 will have to + * explicitly clear this option via either of SSL_CTX_clear_options() or + * SSL_clear_options(). + */ + ret->options |= SSL_OP_NO_SSLv2; + + return (ret); + err: + SSLerr(SSL_F_SSL_CTX_NEW, ERR_R_MALLOC_FAILURE); + err2: + if (ret != NULL) + SSL_CTX_free(ret); + return (NULL); +} + +#if 0 +static void SSL_COMP_free(SSL_COMP *comp) +{ + OPENSSL_free(comp); +} +#endif + +#ifndef OPENSSL_NO_BUF_FREELISTS +static void ssl_buf_freelist_free(SSL3_BUF_FREELIST *list) +{ + SSL3_BUF_FREELIST_ENTRY *ent, *next; + for (ent = list->head; ent; ent = next) { + next = ent->next; + OPENSSL_free(ent); + } + OPENSSL_free(list); +} +#endif + +void SSL_CTX_free(SSL_CTX *a) +{ + int i; + + if (a == NULL) + return; + + i = CRYPTO_add(&a->references, -1, CRYPTO_LOCK_SSL_CTX); +#ifdef REF_PRINT + REF_PRINT("SSL_CTX", a); +#endif + if (i > 0) + return; +#ifdef REF_CHECK + if (i < 0) { + fprintf(stderr, "SSL_CTX_free, bad reference count\n"); + abort(); /* ok */ + } +#endif + + if (a->param) + X509_VERIFY_PARAM_free(a->param); + + /* + * Free internal session cache. However: the remove_cb() may reference + * the ex_data of SSL_CTX, thus the ex_data store can only be removed + * after the sessions were flushed. + * As the ex_data handling routines might also touch the session cache, + * the most secure solution seems to be: empty (flush) the cache, then + * free ex_data, then finally free the cache. + * (See ticket [openssl.org #212].) + */ + if (a->sessions != NULL) + SSL_CTX_flush_sessions(a, 0); + + CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL_CTX, a, &a->ex_data); + + if (a->sessions != NULL) + lh_SSL_SESSION_free(a->sessions); + + if (a->cert_store != NULL) + X509_STORE_free(a->cert_store); + if (a->cipher_list != NULL) + sk_SSL_CIPHER_free(a->cipher_list); + if (a->cipher_list_by_id != NULL) + sk_SSL_CIPHER_free(a->cipher_list_by_id); + if (a->cert != NULL) + ssl_cert_free(a->cert); + if (a->client_CA != NULL) + sk_X509_NAME_pop_free(a->client_CA, X509_NAME_free); + if (a->extra_certs != NULL) + sk_X509_pop_free(a->extra_certs, X509_free); +#if 0 /* This should never be done, since it + * removes a global database */ + if (a->comp_methods != NULL) + sk_SSL_COMP_pop_free(a->comp_methods, SSL_COMP_free); +#else + a->comp_methods = NULL; +#endif + +#ifndef OPENSSL_NO_SRTP + if (a->srtp_profiles) + sk_SRTP_PROTECTION_PROFILE_free(a->srtp_profiles); +#endif + +#ifndef OPENSSL_NO_PSK + if (a->psk_identity_hint) + OPENSSL_free(a->psk_identity_hint); +#endif +#ifndef OPENSSL_NO_SRP + SSL_CTX_SRP_CTX_free(a); +#endif +#ifndef OPENSSL_NO_ENGINE + if (a->client_cert_engine) + ENGINE_finish(a->client_cert_engine); +#endif + +#ifndef OPENSSL_NO_BUF_FREELISTS + if (a->wbuf_freelist) + ssl_buf_freelist_free(a->wbuf_freelist); + if (a->rbuf_freelist) + ssl_buf_freelist_free(a->rbuf_freelist); +#endif +#ifndef OPENSSL_NO_TLSEXT +# ifndef OPENSSL_NO_EC + if (a->tlsext_ecpointformatlist) + OPENSSL_free(a->tlsext_ecpointformatlist); + if (a->tlsext_ellipticcurvelist) + OPENSSL_free(a->tlsext_ellipticcurvelist); +# endif /* OPENSSL_NO_EC */ + if (a->alpn_client_proto_list != NULL) + OPENSSL_free(a->alpn_client_proto_list); +#endif + + OPENSSL_free(a); +} + +void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, pem_password_cb *cb) +{ + ctx->default_passwd_callback = cb; +} + +void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *u) +{ + ctx->default_passwd_callback_userdata = u; +} + +void SSL_CTX_set_cert_verify_callback(SSL_CTX *ctx, + int (*cb) (X509_STORE_CTX *, void *), + void *arg) +{ + ctx->app_verify_callback = cb; + ctx->app_verify_arg = arg; +} + +void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, + int (*cb) (int, X509_STORE_CTX *)) +{ + ctx->verify_mode = mode; + ctx->default_verify_callback = cb; +} + +void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth) +{ + X509_VERIFY_PARAM_set_depth(ctx->param, depth); +} + +void SSL_CTX_set_cert_cb(SSL_CTX *c, int (*cb) (SSL *ssl, void *arg), + void *arg) +{ + ssl_cert_set_cert_cb(c->cert, cb, arg); +} + +void SSL_set_cert_cb(SSL *s, int (*cb) (SSL *ssl, void *arg), void *arg) +{ + ssl_cert_set_cert_cb(s->cert, cb, arg); +} + +void ssl_set_cert_masks(CERT *c, const SSL_CIPHER *cipher) +{ + CERT_PKEY *cpk; + int rsa_enc, rsa_tmp, rsa_sign, dh_tmp, dh_rsa, dh_dsa, dsa_sign; + int rsa_enc_export, dh_rsa_export, dh_dsa_export; + int rsa_tmp_export, dh_tmp_export, kl; + unsigned long mask_k, mask_a, emask_k, emask_a; +#ifndef OPENSSL_NO_ECDSA + int have_ecc_cert, ecdsa_ok, ecc_pkey_size; +#endif +#ifndef OPENSSL_NO_ECDH + int have_ecdh_tmp, ecdh_ok; +#endif +#ifndef OPENSSL_NO_EC + X509 *x = NULL; + EVP_PKEY *ecc_pkey = NULL; + int signature_nid = 0, pk_nid = 0, md_nid = 0; +#endif + if (c == NULL) + return; + + kl = SSL_C_EXPORT_PKEYLENGTH(cipher); + +#ifndef OPENSSL_NO_RSA + rsa_tmp = (c->rsa_tmp != NULL || c->rsa_tmp_cb != NULL); + rsa_tmp_export = (c->rsa_tmp_cb != NULL || + (rsa_tmp && RSA_size(c->rsa_tmp) * 8 <= kl)); +#else + rsa_tmp = rsa_tmp_export = 0; +#endif +#ifndef OPENSSL_NO_DH + dh_tmp = (c->dh_tmp != NULL || c->dh_tmp_cb != NULL); + dh_tmp_export = (c->dh_tmp_cb != NULL || + (dh_tmp && DH_size(c->dh_tmp) * 8 <= kl)); +#else + dh_tmp = dh_tmp_export = 0; +#endif + +#ifndef OPENSSL_NO_ECDH + have_ecdh_tmp = (c->ecdh_tmp || c->ecdh_tmp_cb || c->ecdh_tmp_auto); +#endif + cpk = &(c->pkeys[SSL_PKEY_RSA_ENC]); + rsa_enc = cpk->valid_flags & CERT_PKEY_VALID; + rsa_enc_export = (rsa_enc && EVP_PKEY_size(cpk->privatekey) * 8 <= kl); + cpk = &(c->pkeys[SSL_PKEY_RSA_SIGN]); + rsa_sign = cpk->valid_flags & CERT_PKEY_SIGN; + cpk = &(c->pkeys[SSL_PKEY_DSA_SIGN]); + dsa_sign = cpk->valid_flags & CERT_PKEY_SIGN; + cpk = &(c->pkeys[SSL_PKEY_DH_RSA]); + dh_rsa = cpk->valid_flags & CERT_PKEY_VALID; + dh_rsa_export = (dh_rsa && EVP_PKEY_size(cpk->privatekey) * 8 <= kl); + cpk = &(c->pkeys[SSL_PKEY_DH_DSA]); +/* FIX THIS EAY EAY EAY */ + dh_dsa = cpk->valid_flags & CERT_PKEY_VALID; + dh_dsa_export = (dh_dsa && EVP_PKEY_size(cpk->privatekey) * 8 <= kl); + cpk = &(c->pkeys[SSL_PKEY_ECC]); +#ifndef OPENSSL_NO_EC + have_ecc_cert = cpk->valid_flags & CERT_PKEY_VALID; +#endif + mask_k = 0; + mask_a = 0; + emask_k = 0; + emask_a = 0; + +#ifdef CIPHER_DEBUG + fprintf(stderr, + "rt=%d rte=%d dht=%d ecdht=%d re=%d ree=%d rs=%d ds=%d dhr=%d dhd=%d\n", + rsa_tmp, rsa_tmp_export, dh_tmp, have_ecdh_tmp, rsa_enc, + rsa_enc_export, rsa_sign, dsa_sign, dh_rsa, dh_dsa); +#endif + + cpk = &(c->pkeys[SSL_PKEY_GOST01]); + if (cpk->x509 != NULL && cpk->privatekey != NULL) { + mask_k |= SSL_kGOST; + mask_a |= SSL_aGOST01; + } + cpk = &(c->pkeys[SSL_PKEY_GOST94]); + if (cpk->x509 != NULL && cpk->privatekey != NULL) { + mask_k |= SSL_kGOST; + mask_a |= SSL_aGOST94; + } + + if (rsa_enc || (rsa_tmp && rsa_sign)) + mask_k |= SSL_kRSA; + if (rsa_enc_export || (rsa_tmp_export && (rsa_sign || rsa_enc))) + emask_k |= SSL_kRSA; + +#if 0 + /* The match needs to be both kEDH and aRSA or aDSA, so don't worry */ + if ((dh_tmp || dh_rsa || dh_dsa) && (rsa_enc || rsa_sign || dsa_sign)) + mask_k |= SSL_kEDH; + if ((dh_tmp_export || dh_rsa_export || dh_dsa_export) && + (rsa_enc || rsa_sign || dsa_sign)) + emask_k |= SSL_kEDH; +#endif + + if (dh_tmp_export) + emask_k |= SSL_kEDH; + + if (dh_tmp) + mask_k |= SSL_kEDH; + + if (dh_rsa) + mask_k |= SSL_kDHr; + if (dh_rsa_export) + emask_k |= SSL_kDHr; + + if (dh_dsa) + mask_k |= SSL_kDHd; + if (dh_dsa_export) + emask_k |= SSL_kDHd; + + if (mask_k & (SSL_kDHr | SSL_kDHd)) + mask_a |= SSL_aDH; + + if (rsa_enc || rsa_sign) { + mask_a |= SSL_aRSA; + emask_a |= SSL_aRSA; + } + + if (dsa_sign) { + mask_a |= SSL_aDSS; + emask_a |= SSL_aDSS; + } + + mask_a |= SSL_aNULL; + emask_a |= SSL_aNULL; + +#ifndef OPENSSL_NO_KRB5 + mask_k |= SSL_kKRB5; + mask_a |= SSL_aKRB5; + emask_k |= SSL_kKRB5; + emask_a |= SSL_aKRB5; +#endif + + /* + * An ECC certificate may be usable for ECDH and/or ECDSA cipher suites + * depending on the key usage extension. + */ +#ifndef OPENSSL_NO_EC + if (have_ecc_cert) { + cpk = &c->pkeys[SSL_PKEY_ECC]; + x = cpk->x509; + /* This call populates extension flags (ex_flags) */ + X509_check_purpose(x, -1, 0); +# ifndef OPENSSL_NO_ECDH + ecdh_ok = (x->ex_flags & EXFLAG_KUSAGE) ? + (x->ex_kusage & X509v3_KU_KEY_AGREEMENT) : 1; +# endif + ecdsa_ok = (x->ex_flags & EXFLAG_KUSAGE) ? + (x->ex_kusage & X509v3_KU_DIGITAL_SIGNATURE) : 1; + if (!(cpk->valid_flags & CERT_PKEY_SIGN)) + ecdsa_ok = 0; + ecc_pkey = X509_get_pubkey(x); + ecc_pkey_size = (ecc_pkey != NULL) ? EVP_PKEY_bits(ecc_pkey) : 0; + EVP_PKEY_free(ecc_pkey); + if ((x->sig_alg) && (x->sig_alg->algorithm)) { + signature_nid = OBJ_obj2nid(x->sig_alg->algorithm); + OBJ_find_sigid_algs(signature_nid, &md_nid, &pk_nid); + } +# ifndef OPENSSL_NO_ECDH + if (ecdh_ok) { + + if (pk_nid == NID_rsaEncryption || pk_nid == NID_rsa) { + mask_k |= SSL_kECDHr; + mask_a |= SSL_aECDH; + if (ecc_pkey_size <= 163) { + emask_k |= SSL_kECDHr; + emask_a |= SSL_aECDH; + } + } + + if (pk_nid == NID_X9_62_id_ecPublicKey) { + mask_k |= SSL_kECDHe; + mask_a |= SSL_aECDH; + if (ecc_pkey_size <= 163) { + emask_k |= SSL_kECDHe; + emask_a |= SSL_aECDH; + } + } + } +# endif +# ifndef OPENSSL_NO_ECDSA + if (ecdsa_ok) { + mask_a |= SSL_aECDSA; + emask_a |= SSL_aECDSA; + } +# endif + } +#endif + +#ifndef OPENSSL_NO_ECDH + if (have_ecdh_tmp) { + mask_k |= SSL_kEECDH; + emask_k |= SSL_kEECDH; + } +#endif + +#ifndef OPENSSL_NO_PSK + mask_k |= SSL_kPSK; + mask_a |= SSL_aPSK; + emask_k |= SSL_kPSK; + emask_a |= SSL_aPSK; +#endif + + c->mask_k = mask_k; + c->mask_a = mask_a; + c->export_mask_k = emask_k; + c->export_mask_a = emask_a; + c->valid = 1; +} + +/* This handy macro borrowed from crypto/x509v3/v3_purp.c */ +#define ku_reject(x, usage) \ + (((x)->ex_flags & EXFLAG_KUSAGE) && !((x)->ex_kusage & (usage))) + +#ifndef OPENSSL_NO_EC + +int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s) +{ + unsigned long alg_k, alg_a; + EVP_PKEY *pkey = NULL; + int keysize = 0; + int signature_nid = 0, md_nid = 0, pk_nid = 0; + const SSL_CIPHER *cs = s->s3->tmp.new_cipher; + + alg_k = cs->algorithm_mkey; + alg_a = cs->algorithm_auth; + + if (SSL_C_IS_EXPORT(cs)) { + /* ECDH key length in export ciphers must be <= 163 bits */ + pkey = X509_get_pubkey(x); + if (pkey == NULL) + return 0; + keysize = EVP_PKEY_bits(pkey); + EVP_PKEY_free(pkey); + if (keysize > 163) + return 0; + } + + /* This call populates the ex_flags field correctly */ + X509_check_purpose(x, -1, 0); + if ((x->sig_alg) && (x->sig_alg->algorithm)) { + signature_nid = OBJ_obj2nid(x->sig_alg->algorithm); + OBJ_find_sigid_algs(signature_nid, &md_nid, &pk_nid); + } + if (alg_k & SSL_kECDHe || alg_k & SSL_kECDHr) { + /* key usage, if present, must allow key agreement */ + if (ku_reject(x, X509v3_KU_KEY_AGREEMENT)) { + SSLerr(SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG, + SSL_R_ECC_CERT_NOT_FOR_KEY_AGREEMENT); + return 0; + } + if ((alg_k & SSL_kECDHe) && TLS1_get_version(s) < TLS1_2_VERSION) { + /* signature alg must be ECDSA */ + if (pk_nid != NID_X9_62_id_ecPublicKey) { + SSLerr(SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG, + SSL_R_ECC_CERT_SHOULD_HAVE_SHA1_SIGNATURE); + return 0; + } + } + if ((alg_k & SSL_kECDHr) && TLS1_get_version(s) < TLS1_2_VERSION) { + /* signature alg must be RSA */ + + if (pk_nid != NID_rsaEncryption && pk_nid != NID_rsa) { + SSLerr(SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG, + SSL_R_ECC_CERT_SHOULD_HAVE_RSA_SIGNATURE); + return 0; + } + } + } + if (alg_a & SSL_aECDSA) { + /* key usage, if present, must allow signing */ + if (ku_reject(x, X509v3_KU_DIGITAL_SIGNATURE)) { + SSLerr(SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG, + SSL_R_ECC_CERT_NOT_FOR_SIGNING); + return 0; + } + } + + return 1; /* all checks are ok */ +} + +#endif + +static int ssl_get_server_cert_index(const SSL *s) +{ + int idx; + idx = ssl_cipher_get_cert_index(s->s3->tmp.new_cipher); + if (idx == SSL_PKEY_RSA_ENC && !s->cert->pkeys[SSL_PKEY_RSA_ENC].x509) + idx = SSL_PKEY_RSA_SIGN; + if (idx == -1) + SSLerr(SSL_F_SSL_GET_SERVER_CERT_INDEX, ERR_R_INTERNAL_ERROR); + return idx; +} + +CERT_PKEY *ssl_get_server_send_pkey(const SSL *s) +{ + CERT *c; + int i; + + c = s->cert; + if (!s->s3 || !s->s3->tmp.new_cipher) + return NULL; + ssl_set_cert_masks(c, s->s3->tmp.new_cipher); + +#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL + /* + * Broken protocol test: return last used certificate: which may mismatch + * the one expected. + */ + if (c->cert_flags & SSL_CERT_FLAG_BROKEN_PROTOCOL) + return c->key; +#endif + + i = ssl_get_server_cert_index(s); + + /* This may or may not be an error. */ + if (i < 0) + return NULL; + + /* May be NULL. */ + return &c->pkeys[i]; +} + +EVP_PKEY *ssl_get_sign_pkey(SSL *s, const SSL_CIPHER *cipher, + const EVP_MD **pmd) +{ + unsigned long alg_a; + CERT *c; + int idx = -1; + + alg_a = cipher->algorithm_auth; + c = s->cert; + +#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL + /* + * Broken protocol test: use last key: which may mismatch the one + * expected. + */ + if (c->cert_flags & SSL_CERT_FLAG_BROKEN_PROTOCOL) + idx = c->key - c->pkeys; + else +#endif + + if ((alg_a & SSL_aDSS) && + (c->pkeys[SSL_PKEY_DSA_SIGN].privatekey != NULL)) + idx = SSL_PKEY_DSA_SIGN; + else if (alg_a & SSL_aRSA) { + if (c->pkeys[SSL_PKEY_RSA_SIGN].privatekey != NULL) + idx = SSL_PKEY_RSA_SIGN; + else if (c->pkeys[SSL_PKEY_RSA_ENC].privatekey != NULL) + idx = SSL_PKEY_RSA_ENC; + } else if ((alg_a & SSL_aECDSA) && + (c->pkeys[SSL_PKEY_ECC].privatekey != NULL)) + idx = SSL_PKEY_ECC; + if (idx == -1) { + SSLerr(SSL_F_SSL_GET_SIGN_PKEY, ERR_R_INTERNAL_ERROR); + return (NULL); + } + if (pmd) + *pmd = c->pkeys[idx].digest; + return c->pkeys[idx].privatekey; +} + +#ifndef OPENSSL_NO_TLSEXT +int ssl_get_server_cert_serverinfo(SSL *s, const unsigned char **serverinfo, + size_t *serverinfo_length) +{ + CERT *c = NULL; + int i = 0; + *serverinfo_length = 0; + + c = s->cert; + i = ssl_get_server_cert_index(s); + + if (i == -1) + return 0; + if (c->pkeys[i].serverinfo == NULL) + return 0; + + *serverinfo = c->pkeys[i].serverinfo; + *serverinfo_length = c->pkeys[i].serverinfo_length; + return 1; +} +#endif + +void ssl_update_cache(SSL *s, int mode) +{ + int i; + + /* + * If the session_id_length is 0, we are not supposed to cache it, and it + * would be rather hard to do anyway :-) + */ + if (s->session->session_id_length == 0) + return; + + i = s->session_ctx->session_cache_mode; + if ((i & mode) && (!s->hit) + && ((i & SSL_SESS_CACHE_NO_INTERNAL_STORE) + || SSL_CTX_add_session(s->session_ctx, s->session)) + && (s->session_ctx->new_session_cb != NULL)) { + CRYPTO_add(&s->session->references, 1, CRYPTO_LOCK_SSL_SESSION); + if (!s->session_ctx->new_session_cb(s, s->session)) + SSL_SESSION_free(s->session); + } + + /* auto flush every 255 connections */ + if ((!(i & SSL_SESS_CACHE_NO_AUTO_CLEAR)) && ((i & mode) == mode)) { + if ((((mode & SSL_SESS_CACHE_CLIENT) + ? s->session_ctx->stats.sess_connect_good + : s->session_ctx->stats.sess_accept_good) & 0xff) == 0xff) { + SSL_CTX_flush_sessions(s->session_ctx, (unsigned long)time(NULL)); + } + } +} + +const SSL_METHOD *SSL_CTX_get_ssl_method(SSL_CTX *ctx) +{ + return ctx->method; +} + +const SSL_METHOD *SSL_get_ssl_method(SSL *s) +{ + return (s->method); +} + +int SSL_set_ssl_method(SSL *s, const SSL_METHOD *meth) +{ + int conn = -1; + int ret = 1; + + if (s->method != meth) { + if (s->handshake_func != NULL) + conn = (s->handshake_func == s->method->ssl_connect); + + if (s->method->version == meth->version) + s->method = meth; + else { + s->method->ssl_free(s); + s->method = meth; + ret = s->method->ssl_new(s); + } + + if (conn == 1) + s->handshake_func = meth->ssl_connect; + else if (conn == 0) + s->handshake_func = meth->ssl_accept; + } + return (ret); +} + +int SSL_get_error(const SSL *s, int i) +{ + int reason; + unsigned long l; + BIO *bio; + + if (i > 0) + return (SSL_ERROR_NONE); + + /* + * Make things return SSL_ERROR_SYSCALL when doing SSL_do_handshake etc, + * where we do encode the error + */ + if ((l = ERR_peek_error()) != 0) { + if (ERR_GET_LIB(l) == ERR_LIB_SYS) + return (SSL_ERROR_SYSCALL); + else + return (SSL_ERROR_SSL); + } + + if ((i < 0) && SSL_want_read(s)) { + bio = SSL_get_rbio(s); + if (BIO_should_read(bio)) + return (SSL_ERROR_WANT_READ); + else if (BIO_should_write(bio)) + /* + * This one doesn't make too much sense ... We never try to write + * to the rbio, and an application program where rbio and wbio + * are separate couldn't even know what it should wait for. + * However if we ever set s->rwstate incorrectly (so that we have + * SSL_want_read(s) instead of SSL_want_write(s)) and rbio and + * wbio *are* the same, this test works around that bug; so it + * might be safer to keep it. + */ + return (SSL_ERROR_WANT_WRITE); + else if (BIO_should_io_special(bio)) { + reason = BIO_get_retry_reason(bio); + if (reason == BIO_RR_CONNECT) + return (SSL_ERROR_WANT_CONNECT); + else if (reason == BIO_RR_ACCEPT) + return (SSL_ERROR_WANT_ACCEPT); + else + return (SSL_ERROR_SYSCALL); /* unknown */ + } + } + + if ((i < 0) && SSL_want_write(s)) { + bio = SSL_get_wbio(s); + if (BIO_should_write(bio)) + return (SSL_ERROR_WANT_WRITE); + else if (BIO_should_read(bio)) + /* + * See above (SSL_want_read(s) with BIO_should_write(bio)) + */ + return (SSL_ERROR_WANT_READ); + else if (BIO_should_io_special(bio)) { + reason = BIO_get_retry_reason(bio); + if (reason == BIO_RR_CONNECT) + return (SSL_ERROR_WANT_CONNECT); + else if (reason == BIO_RR_ACCEPT) + return (SSL_ERROR_WANT_ACCEPT); + else + return (SSL_ERROR_SYSCALL); + } + } + if ((i < 0) && SSL_want_x509_lookup(s)) { + return (SSL_ERROR_WANT_X509_LOOKUP); + } + + if (i == 0) { + if (s->version == SSL2_VERSION) { + /* assume it is the socket being closed */ + return (SSL_ERROR_ZERO_RETURN); + } else { + if ((s->shutdown & SSL_RECEIVED_SHUTDOWN) && + (s->s3->warn_alert == SSL_AD_CLOSE_NOTIFY)) + return (SSL_ERROR_ZERO_RETURN); + } + } + return (SSL_ERROR_SYSCALL); +} + +int SSL_do_handshake(SSL *s) +{ + int ret = 1; + + if (s->handshake_func == NULL) { + SSLerr(SSL_F_SSL_DO_HANDSHAKE, SSL_R_CONNECTION_TYPE_NOT_SET); + return (-1); + } + + s->method->ssl_renegotiate_check(s); + + if (SSL_in_init(s) || SSL_in_before(s)) { + ret = s->handshake_func(s); + } + return (ret); +} + +/* + * For the next 2 functions, SSL_clear() sets shutdown and so one of these + * calls will reset it + */ +void SSL_set_accept_state(SSL *s) +{ + s->server = 1; + s->shutdown = 0; + s->state = SSL_ST_ACCEPT | SSL_ST_BEFORE; + s->handshake_func = s->method->ssl_accept; + /* clear the current cipher */ + ssl_clear_cipher_ctx(s); + ssl_clear_hash_ctx(&s->read_hash); + ssl_clear_hash_ctx(&s->write_hash); +} + +void SSL_set_connect_state(SSL *s) +{ + s->server = 0; + s->shutdown = 0; + s->state = SSL_ST_CONNECT | SSL_ST_BEFORE; + s->handshake_func = s->method->ssl_connect; + /* clear the current cipher */ + ssl_clear_cipher_ctx(s); + ssl_clear_hash_ctx(&s->read_hash); + ssl_clear_hash_ctx(&s->write_hash); +} + +int ssl_undefined_function(SSL *s) +{ + SSLerr(SSL_F_SSL_UNDEFINED_FUNCTION, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return (0); +} + +int ssl_undefined_void_function(void) +{ + SSLerr(SSL_F_SSL_UNDEFINED_VOID_FUNCTION, + ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return (0); +} + +int ssl_undefined_const_function(const SSL *s) +{ + SSLerr(SSL_F_SSL_UNDEFINED_CONST_FUNCTION, + ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return (0); +} + +SSL_METHOD *ssl_bad_method(int ver) +{ + SSLerr(SSL_F_SSL_BAD_METHOD, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return (NULL); +} + +const char *SSL_get_version(const SSL *s) +{ + if (s->version == TLS1_2_VERSION) + return ("TLSv1.2"); + else if (s->version == TLS1_1_VERSION) + return ("TLSv1.1"); + else if (s->version == TLS1_VERSION) + return ("TLSv1"); + else if (s->version == SSL3_VERSION) + return ("SSLv3"); + else if (s->version == SSL2_VERSION) + return ("SSLv2"); + else if (s->version == DTLS1_BAD_VER) + return ("DTLSv0.9"); + else if (s->version == DTLS1_VERSION) + return ("DTLSv1"); + else if (s->version == DTLS1_2_VERSION) + return ("DTLSv1.2"); + else + return ("unknown"); +} + +SSL *SSL_dup(SSL *s) +{ + STACK_OF(X509_NAME) *sk; + X509_NAME *xn; + SSL *ret; + int i; + + if ((ret = SSL_new(SSL_get_SSL_CTX(s))) == NULL) + return (NULL); + + ret->version = s->version; + ret->type = s->type; + ret->method = s->method; + + if (s->session != NULL) { + /* This copies session-id, SSL_METHOD, sid_ctx, and 'cert' */ + SSL_copy_session_id(ret, s); + } else { + /* + * No session has been established yet, so we have to expect that + * s->cert or ret->cert will be changed later -- they should not both + * point to the same object, and thus we can't use + * SSL_copy_session_id. + */ + + ret->method->ssl_free(ret); + ret->method = s->method; + ret->method->ssl_new(ret); + + if (s->cert != NULL) { + if (ret->cert != NULL) { + ssl_cert_free(ret->cert); + } + ret->cert = ssl_cert_dup(s->cert); + if (ret->cert == NULL) + goto err; + } + + SSL_set_session_id_context(ret, s->sid_ctx, s->sid_ctx_length); + } + + ret->options = s->options; + ret->mode = s->mode; + SSL_set_max_cert_list(ret, SSL_get_max_cert_list(s)); + SSL_set_read_ahead(ret, SSL_get_read_ahead(s)); + ret->msg_callback = s->msg_callback; + ret->msg_callback_arg = s->msg_callback_arg; + SSL_set_verify(ret, SSL_get_verify_mode(s), SSL_get_verify_callback(s)); + SSL_set_verify_depth(ret, SSL_get_verify_depth(s)); + ret->generate_session_id = s->generate_session_id; + + SSL_set_info_callback(ret, SSL_get_info_callback(s)); + + ret->debug = s->debug; + + /* copy app data, a little dangerous perhaps */ + if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_SSL, &ret->ex_data, &s->ex_data)) + goto err; + + /* setup rbio, and wbio */ + if (s->rbio != NULL) { + if (!BIO_dup_state(s->rbio, (char *)&ret->rbio)) + goto err; + } + if (s->wbio != NULL) { + if (s->wbio != s->rbio) { + if (!BIO_dup_state(s->wbio, (char *)&ret->wbio)) + goto err; + } else + ret->wbio = ret->rbio; + } + ret->rwstate = s->rwstate; + ret->in_handshake = s->in_handshake; + ret->handshake_func = s->handshake_func; + ret->server = s->server; + ret->renegotiate = s->renegotiate; + ret->new_session = s->new_session; + ret->quiet_shutdown = s->quiet_shutdown; + ret->shutdown = s->shutdown; + ret->state = s->state; /* SSL_dup does not really work at any state, + * though */ + ret->rstate = s->rstate; + ret->init_num = 0; /* would have to copy ret->init_buf, + * ret->init_msg, ret->init_num, + * ret->init_off */ + ret->hit = s->hit; + + X509_VERIFY_PARAM_inherit(ret->param, s->param); + + /* dup the cipher_list and cipher_list_by_id stacks */ + if (s->cipher_list != NULL) { + if ((ret->cipher_list = sk_SSL_CIPHER_dup(s->cipher_list)) == NULL) + goto err; + } + if (s->cipher_list_by_id != NULL) + if ((ret->cipher_list_by_id = sk_SSL_CIPHER_dup(s->cipher_list_by_id)) + == NULL) + goto err; + + /* Dup the client_CA list */ + if (s->client_CA != NULL) { + if ((sk = sk_X509_NAME_dup(s->client_CA)) == NULL) + goto err; + ret->client_CA = sk; + for (i = 0; i < sk_X509_NAME_num(sk); i++) { + xn = sk_X509_NAME_value(sk, i); + if (sk_X509_NAME_set(sk, i, X509_NAME_dup(xn)) == NULL) { + X509_NAME_free(xn); + goto err; + } + } + } + + if (0) { + err: + if (ret != NULL) + SSL_free(ret); + ret = NULL; + } + return (ret); +} + +void ssl_clear_cipher_ctx(SSL *s) +{ + if (s->enc_read_ctx != NULL) { + EVP_CIPHER_CTX_cleanup(s->enc_read_ctx); + OPENSSL_free(s->enc_read_ctx); + s->enc_read_ctx = NULL; + } + if (s->enc_write_ctx != NULL) { + EVP_CIPHER_CTX_cleanup(s->enc_write_ctx); + OPENSSL_free(s->enc_write_ctx); + s->enc_write_ctx = NULL; + } +#ifndef OPENSSL_NO_COMP + if (s->expand != NULL) { + COMP_CTX_free(s->expand); + s->expand = NULL; + } + if (s->compress != NULL) { + COMP_CTX_free(s->compress); + s->compress = NULL; + } +#endif +} + +X509 *SSL_get_certificate(const SSL *s) +{ + if (s->cert != NULL) + return (s->cert->key->x509); + else + return (NULL); +} + +EVP_PKEY *SSL_get_privatekey(const SSL *s) +{ + if (s->cert != NULL) + return (s->cert->key->privatekey); + else + return (NULL); +} + +X509 *SSL_CTX_get0_certificate(const SSL_CTX *ctx) +{ + if (ctx->cert != NULL) + return ctx->cert->key->x509; + else + return NULL; +} + +EVP_PKEY *SSL_CTX_get0_privatekey(const SSL_CTX *ctx) +{ + if (ctx->cert != NULL) + return ctx->cert->key->privatekey; + else + return NULL; +} + +const SSL_CIPHER *SSL_get_current_cipher(const SSL *s) +{ + if ((s->session != NULL) && (s->session->cipher != NULL)) + return (s->session->cipher); + return (NULL); +} + +#ifdef OPENSSL_NO_COMP +const void *SSL_get_current_compression(SSL *s) +{ + return NULL; +} + +const void *SSL_get_current_expansion(SSL *s) +{ + return NULL; +} +#else + +const COMP_METHOD *SSL_get_current_compression(SSL *s) +{ + if (s->compress != NULL) + return (s->compress->meth); + return (NULL); +} + +const COMP_METHOD *SSL_get_current_expansion(SSL *s) +{ + if (s->expand != NULL) + return (s->expand->meth); + return (NULL); +} +#endif + +int ssl_init_wbio_buffer(SSL *s, int push) +{ + BIO *bbio; + + if (s->bbio == NULL) { + bbio = BIO_new(BIO_f_buffer()); + if (bbio == NULL) + return (0); + s->bbio = bbio; + } else { + bbio = s->bbio; + if (s->bbio == s->wbio) + s->wbio = BIO_pop(s->wbio); + } + (void)BIO_reset(bbio); +/* if (!BIO_set_write_buffer_size(bbio,16*1024)) */ + if (!BIO_set_read_buffer_size(bbio, 1)) { + SSLerr(SSL_F_SSL_INIT_WBIO_BUFFER, ERR_R_BUF_LIB); + return (0); + } + if (push) { + if (s->wbio != bbio) + s->wbio = BIO_push(bbio, s->wbio); + } else { + if (s->wbio == bbio) + s->wbio = BIO_pop(bbio); + } + return (1); +} + +void ssl_free_wbio_buffer(SSL *s) +{ + if (s->bbio == NULL) + return; + + if (s->bbio == s->wbio) { + /* remove buffering */ + s->wbio = BIO_pop(s->wbio); +#ifdef REF_CHECK /* not the usual REF_CHECK, but this avoids + * adding one more preprocessor symbol */ + assert(s->wbio != NULL); +#endif + } + BIO_free(s->bbio); + s->bbio = NULL; +} + +void SSL_CTX_set_quiet_shutdown(SSL_CTX *ctx, int mode) +{ + ctx->quiet_shutdown = mode; +} + +int SSL_CTX_get_quiet_shutdown(const SSL_CTX *ctx) +{ + return (ctx->quiet_shutdown); +} + +void SSL_set_quiet_shutdown(SSL *s, int mode) +{ + s->quiet_shutdown = mode; +} + +int SSL_get_quiet_shutdown(const SSL *s) +{ + return (s->quiet_shutdown); +} + +void SSL_set_shutdown(SSL *s, int mode) +{ + s->shutdown = mode; +} + +int SSL_get_shutdown(const SSL *s) +{ + return (s->shutdown); +} + +int SSL_version(const SSL *s) +{ + return (s->version); +} + +SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl) +{ + return (ssl->ctx); +} + +SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX *ctx) +{ + CERT *ocert = ssl->cert; + if (ssl->ctx == ctx) + return ssl->ctx; +#ifndef OPENSSL_NO_TLSEXT + if (ctx == NULL) + ctx = ssl->initial_ctx; +#endif + ssl->cert = ssl_cert_dup(ctx->cert); + if (ocert) { + /* Preserve any already negotiated parameters */ + if (ssl->server) { + ssl->cert->peer_sigalgs = ocert->peer_sigalgs; + ssl->cert->peer_sigalgslen = ocert->peer_sigalgslen; + ocert->peer_sigalgs = NULL; + ssl->cert->ciphers_raw = ocert->ciphers_raw; + ssl->cert->ciphers_rawlen = ocert->ciphers_rawlen; + ocert->ciphers_raw = NULL; + } +#ifndef OPENSSL_NO_TLSEXT + ssl->cert->alpn_proposed = ocert->alpn_proposed; + ssl->cert->alpn_proposed_len = ocert->alpn_proposed_len; + ocert->alpn_proposed = NULL; + ssl->cert->alpn_sent = ocert->alpn_sent; +#endif + ssl_cert_free(ocert); + } + + /* + * Program invariant: |sid_ctx| has fixed size (SSL_MAX_SID_CTX_LENGTH), + * so setter APIs must prevent invalid lengths from entering the system. + */ + OPENSSL_assert(ssl->sid_ctx_length <= sizeof(ssl->sid_ctx)); + + /* + * If the session ID context matches that of the parent SSL_CTX, + * inherit it from the new SSL_CTX as well. If however the context does + * not match (i.e., it was set per-ssl with SSL_set_session_id_context), + * leave it unchanged. + */ + if ((ssl->ctx != NULL) && + (ssl->sid_ctx_length == ssl->ctx->sid_ctx_length) && + (memcmp(ssl->sid_ctx, ssl->ctx->sid_ctx, ssl->sid_ctx_length) == 0)) { + ssl->sid_ctx_length = ctx->sid_ctx_length; + memcpy(&ssl->sid_ctx, &ctx->sid_ctx, sizeof(ssl->sid_ctx)); + } + + CRYPTO_add(&ctx->references, 1, CRYPTO_LOCK_SSL_CTX); + if (ssl->ctx != NULL) + SSL_CTX_free(ssl->ctx); /* decrement reference count */ + ssl->ctx = ctx; + + return (ssl->ctx); +} + +#ifndef OPENSSL_NO_STDIO +int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx) +{ + return (X509_STORE_set_default_paths(ctx->cert_store)); +} + +int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, + const char *CApath) +{ + return (X509_STORE_load_locations(ctx->cert_store, CAfile, CApath)); +} +#endif + +void SSL_set_info_callback(SSL *ssl, + void (*cb) (const SSL *ssl, int type, int val)) +{ + ssl->info_callback = cb; +} + +/* + * One compiler (Diab DCC) doesn't like argument names in returned function + * pointer. + */ +void (*SSL_get_info_callback(const SSL *ssl)) (const SSL * /* ssl */ , + int /* type */ , + int /* val */ ) { + return ssl->info_callback; +} + +int SSL_state(const SSL *ssl) +{ + return (ssl->state); +} + +void SSL_set_state(SSL *ssl, int state) +{ + ssl->state = state; +} + +void SSL_set_verify_result(SSL *ssl, long arg) +{ + ssl->verify_result = arg; +} + +long SSL_get_verify_result(const SSL *ssl) +{ + return (ssl->verify_result); +} + +int SSL_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func) +{ + return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL, argl, argp, + new_func, dup_func, free_func); +} + +int SSL_set_ex_data(SSL *s, int idx, void *arg) +{ + return (CRYPTO_set_ex_data(&s->ex_data, idx, arg)); +} + +void *SSL_get_ex_data(const SSL *s, int idx) +{ + return (CRYPTO_get_ex_data(&s->ex_data, idx)); +} + +int SSL_CTX_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func) +{ + return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL_CTX, argl, argp, + new_func, dup_func, free_func); +} + +int SSL_CTX_set_ex_data(SSL_CTX *s, int idx, void *arg) +{ + return (CRYPTO_set_ex_data(&s->ex_data, idx, arg)); +} + +void *SSL_CTX_get_ex_data(const SSL_CTX *s, int idx) +{ + return (CRYPTO_get_ex_data(&s->ex_data, idx)); +} + +int ssl_ok(SSL *s) +{ + return (1); +} + +X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *ctx) +{ + return (ctx->cert_store); +} + +void SSL_CTX_set_cert_store(SSL_CTX *ctx, X509_STORE *store) +{ + if (ctx->cert_store != NULL) + X509_STORE_free(ctx->cert_store); + ctx->cert_store = store; +} + +int SSL_want(const SSL *s) +{ + return (s->rwstate); +} + +/** + * \brief Set the callback for generating temporary RSA keys. + * \param ctx the SSL context. + * \param cb the callback + */ + +#ifndef OPENSSL_NO_RSA +void SSL_CTX_set_tmp_rsa_callback(SSL_CTX *ctx, RSA *(*cb) (SSL *ssl, + int is_export, + int keylength)) +{ + SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_TMP_RSA_CB, (void (*)(void))cb); +} + +void SSL_set_tmp_rsa_callback(SSL *ssl, RSA *(*cb) (SSL *ssl, + int is_export, + int keylength)) +{ + SSL_callback_ctrl(ssl, SSL_CTRL_SET_TMP_RSA_CB, (void (*)(void))cb); +} +#endif + +#ifdef DOXYGEN +/** + * \brief The RSA temporary key callback function. + * \param ssl the SSL session. + * \param is_export \c TRUE if the temp RSA key is for an export ciphersuite. + * \param keylength if \c is_export is \c TRUE, then \c keylength is the size + * of the required key in bits. + * \return the temporary RSA key. + * \sa SSL_CTX_set_tmp_rsa_callback, SSL_set_tmp_rsa_callback + */ + +RSA *cb(SSL *ssl, int is_export, int keylength) +{ +} +#endif + +/** + * \brief Set the callback for generating temporary DH keys. + * \param ctx the SSL context. + * \param dh the callback + */ + +#ifndef OPENSSL_NO_DH +void SSL_CTX_set_tmp_dh_callback(SSL_CTX *ctx, + DH *(*dh) (SSL *ssl, int is_export, + int keylength)) +{ + SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_TMP_DH_CB, (void (*)(void))dh); +} + +void SSL_set_tmp_dh_callback(SSL *ssl, DH *(*dh) (SSL *ssl, int is_export, + int keylength)) +{ + SSL_callback_ctrl(ssl, SSL_CTRL_SET_TMP_DH_CB, (void (*)(void))dh); +} +#endif + +#ifndef OPENSSL_NO_ECDH +void SSL_CTX_set_tmp_ecdh_callback(SSL_CTX *ctx, + EC_KEY *(*ecdh) (SSL *ssl, int is_export, + int keylength)) +{ + SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_TMP_ECDH_CB, + (void (*)(void))ecdh); +} + +void SSL_set_tmp_ecdh_callback(SSL *ssl, + EC_KEY *(*ecdh) (SSL *ssl, int is_export, + int keylength)) +{ + SSL_callback_ctrl(ssl, SSL_CTRL_SET_TMP_ECDH_CB, (void (*)(void))ecdh); +} +#endif + +#ifndef OPENSSL_NO_PSK +int SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *identity_hint) +{ + if (identity_hint != NULL && strlen(identity_hint) > PSK_MAX_IDENTITY_LEN) { + SSLerr(SSL_F_SSL_CTX_USE_PSK_IDENTITY_HINT, + SSL_R_DATA_LENGTH_TOO_LONG); + return 0; + } + if (ctx->psk_identity_hint != NULL) + OPENSSL_free(ctx->psk_identity_hint); + if (identity_hint != NULL) { + ctx->psk_identity_hint = BUF_strdup(identity_hint); + if (ctx->psk_identity_hint == NULL) + return 0; + } else + ctx->psk_identity_hint = NULL; + return 1; +} + +int SSL_use_psk_identity_hint(SSL *s, const char *identity_hint) +{ + if (s == NULL) + return 0; + + if (s->session == NULL) + return 1; /* session not created yet, ignored */ + + if (identity_hint != NULL && strlen(identity_hint) > PSK_MAX_IDENTITY_LEN) { + SSLerr(SSL_F_SSL_USE_PSK_IDENTITY_HINT, SSL_R_DATA_LENGTH_TOO_LONG); + return 0; + } + if (s->session->psk_identity_hint != NULL) + OPENSSL_free(s->session->psk_identity_hint); + if (identity_hint != NULL) { + s->session->psk_identity_hint = BUF_strdup(identity_hint); + if (s->session->psk_identity_hint == NULL) + return 0; + } else + s->session->psk_identity_hint = NULL; + return 1; +} + +const char *SSL_get_psk_identity_hint(const SSL *s) +{ + if (s == NULL || s->session == NULL) + return NULL; + return (s->session->psk_identity_hint); +} + +const char *SSL_get_psk_identity(const SSL *s) +{ + if (s == NULL || s->session == NULL) + return NULL; + return (s->session->psk_identity); +} + +void SSL_set_psk_client_callback(SSL *s, + unsigned int (*cb) (SSL *ssl, + const char *hint, + char *identity, + unsigned int + max_identity_len, + unsigned char *psk, + unsigned int + max_psk_len)) +{ + s->psk_client_callback = cb; +} + +void SSL_CTX_set_psk_client_callback(SSL_CTX *ctx, + unsigned int (*cb) (SSL *ssl, + const char *hint, + char *identity, + unsigned int + max_identity_len, + unsigned char *psk, + unsigned int + max_psk_len)) +{ + ctx->psk_client_callback = cb; +} + +void SSL_set_psk_server_callback(SSL *s, + unsigned int (*cb) (SSL *ssl, + const char *identity, + unsigned char *psk, + unsigned int + max_psk_len)) +{ + s->psk_server_callback = cb; +} + +void SSL_CTX_set_psk_server_callback(SSL_CTX *ctx, + unsigned int (*cb) (SSL *ssl, + const char *identity, + unsigned char *psk, + unsigned int + max_psk_len)) +{ + ctx->psk_server_callback = cb; +} +#endif + +void SSL_CTX_set_msg_callback(SSL_CTX *ctx, + void (*cb) (int write_p, int version, + int content_type, const void *buf, + size_t len, SSL *ssl, void *arg)) +{ + SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_MSG_CALLBACK, (void (*)(void))cb); +} + +void SSL_set_msg_callback(SSL *ssl, + void (*cb) (int write_p, int version, + int content_type, const void *buf, + size_t len, SSL *ssl, void *arg)) +{ + SSL_callback_ctrl(ssl, SSL_CTRL_SET_MSG_CALLBACK, (void (*)(void))cb); +} + +/* + * Allocates new EVP_MD_CTX and sets pointer to it into given pointer + * vairable, freeing EVP_MD_CTX previously stored in that variable, if any. + * If EVP_MD pointer is passed, initializes ctx with this md Returns newly + * allocated ctx; + */ + +EVP_MD_CTX *ssl_replace_hash(EVP_MD_CTX **hash, const EVP_MD *md) +{ + ssl_clear_hash_ctx(hash); + *hash = EVP_MD_CTX_create(); + if (*hash == NULL || (md && EVP_DigestInit_ex(*hash, md, NULL) <= 0)) { + EVP_MD_CTX_destroy(*hash); + *hash = NULL; + return NULL; + } + return *hash; +} + +void ssl_clear_hash_ctx(EVP_MD_CTX **hash) +{ + + if (*hash) + EVP_MD_CTX_destroy(*hash); + *hash = NULL; +} + +void SSL_set_debug(SSL *s, int debug) +{ + s->debug = debug; +} + +int SSL_cache_hit(SSL *s) +{ + return s->hit; +} + +int SSL_is_server(SSL *s) +{ + return s->server; +} + +#if defined(_WINDLL) && defined(OPENSSL_SYS_WIN16) +# include "../crypto/bio/bss_file.c" +#endif + +IMPLEMENT_STACK_OF(SSL_CIPHER) +IMPLEMENT_STACK_OF(SSL_COMP) +IMPLEMENT_OBJ_BSEARCH_GLOBAL_CMP_FN(SSL_CIPHER, SSL_CIPHER, ssl_cipher_id); diff --git a/thirdparty/openssl/ssl/ssl_locl.h b/thirdparty/openssl/ssl/ssl_locl.h new file mode 100644 index 0000000000..747e718a52 --- /dev/null +++ b/thirdparty/openssl/ssl/ssl_locl.h @@ -0,0 +1,1484 @@ +/* ssl/ssl_locl.h */ +/* 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. + * ECC cipher suite support in OpenSSL originally developed by + * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. + */ +/* ==================================================================== + * 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. + */ + +#ifndef HEADER_SSL_LOCL_H +# define HEADER_SSL_LOCL_H +# include <stdlib.h> +# include <time.h> +# include <string.h> +# include <errno.h> + +# include "e_os.h" + +# include <openssl/buffer.h> +# ifndef OPENSSL_NO_COMP +# include <openssl/comp.h> +# endif +# include <openssl/bio.h> +# include <openssl/stack.h> +# ifndef OPENSSL_NO_RSA +# include <openssl/rsa.h> +# endif +# ifndef OPENSSL_NO_DSA +# include <openssl/dsa.h> +# endif +# include <openssl/err.h> +# include <openssl/ssl.h> +# include <openssl/symhacks.h> + +# ifdef OPENSSL_BUILD_SHLIBSSL +# undef OPENSSL_EXTERN +# define OPENSSL_EXTERN OPENSSL_EXPORT +# endif + +# undef PKCS1_CHECK + +# define c2l(c,l) (l = ((unsigned long)(*((c)++))) , \ + l|=(((unsigned long)(*((c)++)))<< 8), \ + l|=(((unsigned long)(*((c)++)))<<16), \ + l|=(((unsigned long)(*((c)++)))<<24)) + +/* NOTE - c is not incremented as per c2l */ +# define c2ln(c,l1,l2,n) { \ + c+=n; \ + l1=l2=0; \ + switch (n) { \ + case 8: l2 =((unsigned long)(*(--(c))))<<24; \ + case 7: l2|=((unsigned long)(*(--(c))))<<16; \ + case 6: l2|=((unsigned long)(*(--(c))))<< 8; \ + case 5: l2|=((unsigned long)(*(--(c)))); \ + case 4: l1 =((unsigned long)(*(--(c))))<<24; \ + case 3: l1|=((unsigned long)(*(--(c))))<<16; \ + case 2: l1|=((unsigned long)(*(--(c))))<< 8; \ + case 1: l1|=((unsigned long)(*(--(c)))); \ + } \ + } + +# define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \ + *((c)++)=(unsigned char)(((l)>> 8)&0xff), \ + *((c)++)=(unsigned char)(((l)>>16)&0xff), \ + *((c)++)=(unsigned char)(((l)>>24)&0xff)) + +# define n2l(c,l) (l =((unsigned long)(*((c)++)))<<24, \ + l|=((unsigned long)(*((c)++)))<<16, \ + l|=((unsigned long)(*((c)++)))<< 8, \ + l|=((unsigned long)(*((c)++)))) + +# define l2n(l,c) (*((c)++)=(unsigned char)(((l)>>24)&0xff), \ + *((c)++)=(unsigned char)(((l)>>16)&0xff), \ + *((c)++)=(unsigned char)(((l)>> 8)&0xff), \ + *((c)++)=(unsigned char)(((l) )&0xff)) + +# define l2n6(l,c) (*((c)++)=(unsigned char)(((l)>>40)&0xff), \ + *((c)++)=(unsigned char)(((l)>>32)&0xff), \ + *((c)++)=(unsigned char)(((l)>>24)&0xff), \ + *((c)++)=(unsigned char)(((l)>>16)&0xff), \ + *((c)++)=(unsigned char)(((l)>> 8)&0xff), \ + *((c)++)=(unsigned char)(((l) )&0xff)) + +# define l2n8(l,c) (*((c)++)=(unsigned char)(((l)>>56)&0xff), \ + *((c)++)=(unsigned char)(((l)>>48)&0xff), \ + *((c)++)=(unsigned char)(((l)>>40)&0xff), \ + *((c)++)=(unsigned char)(((l)>>32)&0xff), \ + *((c)++)=(unsigned char)(((l)>>24)&0xff), \ + *((c)++)=(unsigned char)(((l)>>16)&0xff), \ + *((c)++)=(unsigned char)(((l)>> 8)&0xff), \ + *((c)++)=(unsigned char)(((l) )&0xff)) + +# define n2l6(c,l) (l =((BN_ULLONG)(*((c)++)))<<40, \ + l|=((BN_ULLONG)(*((c)++)))<<32, \ + l|=((BN_ULLONG)(*((c)++)))<<24, \ + l|=((BN_ULLONG)(*((c)++)))<<16, \ + l|=((BN_ULLONG)(*((c)++)))<< 8, \ + l|=((BN_ULLONG)(*((c)++)))) + +/* NOTE - c is not incremented as per l2c */ +# define l2cn(l1,l2,c,n) { \ + c+=n; \ + switch (n) { \ + case 8: *(--(c))=(unsigned char)(((l2)>>24)&0xff); \ + case 7: *(--(c))=(unsigned char)(((l2)>>16)&0xff); \ + case 6: *(--(c))=(unsigned char)(((l2)>> 8)&0xff); \ + case 5: *(--(c))=(unsigned char)(((l2) )&0xff); \ + case 4: *(--(c))=(unsigned char)(((l1)>>24)&0xff); \ + case 3: *(--(c))=(unsigned char)(((l1)>>16)&0xff); \ + case 2: *(--(c))=(unsigned char)(((l1)>> 8)&0xff); \ + case 1: *(--(c))=(unsigned char)(((l1) )&0xff); \ + } \ + } + +# define n2s(c,s) ((s=(((unsigned int)(c[0]))<< 8)| \ + (((unsigned int)(c[1])) )),c+=2) +# define s2n(s,c) ((c[0]=(unsigned char)(((s)>> 8)&0xff), \ + c[1]=(unsigned char)(((s) )&0xff)),c+=2) + +# define n2l3(c,l) ((l =(((unsigned long)(c[0]))<<16)| \ + (((unsigned long)(c[1]))<< 8)| \ + (((unsigned long)(c[2])) )),c+=3) + +# define l2n3(l,c) ((c[0]=(unsigned char)(((l)>>16)&0xff), \ + c[1]=(unsigned char)(((l)>> 8)&0xff), \ + c[2]=(unsigned char)(((l) )&0xff)),c+=3) + +/* LOCAL STUFF */ + +# define SSL_DECRYPT 0 +# define SSL_ENCRYPT 1 + +# define TWO_BYTE_BIT 0x80 +# define SEC_ESC_BIT 0x40 +# define TWO_BYTE_MASK 0x7fff +# define THREE_BYTE_MASK 0x3fff + +# define INC32(a) ((a)=((a)+1)&0xffffffffL) +# define DEC32(a) ((a)=((a)-1)&0xffffffffL) +# define MAX_MAC_SIZE 20 /* up from 16 for SSLv3 */ + +/* + * Define the Bitmasks for SSL_CIPHER.algorithms. + * This bits are used packed as dense as possible. If new methods/ciphers + * etc will be added, the bits a likely to change, so this information + * is for internal library use only, even though SSL_CIPHER.algorithms + * can be publicly accessed. + * Use the according functions for cipher management instead. + * + * The bit mask handling in the selection and sorting scheme in + * ssl_create_cipher_list() has only limited capabilities, reflecting + * that the different entities within are mutually exclusive: + * ONLY ONE BIT PER MASK CAN BE SET AT A TIME. + */ + +/* Bits for algorithm_mkey (key exchange algorithm) */ +/* RSA key exchange */ +# define SSL_kRSA 0x00000001L +/* DH cert, RSA CA cert */ +# define SSL_kDHr 0x00000002L +/* DH cert, DSA CA cert */ +# define SSL_kDHd 0x00000004L +/* tmp DH key no DH cert */ +# define SSL_kEDH 0x00000008L +/* forward-compatible synonym */ +# define SSL_kDHE SSL_kEDH +/* Kerberos5 key exchange */ +# define SSL_kKRB5 0x00000010L +/* ECDH cert, RSA CA cert */ +# define SSL_kECDHr 0x00000020L +/* ECDH cert, ECDSA CA cert */ +# define SSL_kECDHe 0x00000040L +/* ephemeral ECDH */ +# define SSL_kEECDH 0x00000080L +/* forward-compatible synonym */ +# define SSL_kECDHE SSL_kEECDH +/* PSK */ +# define SSL_kPSK 0x00000100L +/* GOST key exchange */ +# define SSL_kGOST 0x00000200L +/* SRP */ +# define SSL_kSRP 0x00000400L + +/* Bits for algorithm_auth (server authentication) */ +/* RSA auth */ +# define SSL_aRSA 0x00000001L +/* DSS auth */ +# define SSL_aDSS 0x00000002L +/* no auth (i.e. use ADH or AECDH) */ +# define SSL_aNULL 0x00000004L +/* Fixed DH auth (kDHd or kDHr) */ +# define SSL_aDH 0x00000008L +/* Fixed ECDH auth (kECDHe or kECDHr) */ +# define SSL_aECDH 0x00000010L +/* KRB5 auth */ +# define SSL_aKRB5 0x00000020L +/* ECDSA auth*/ +# define SSL_aECDSA 0x00000040L +/* PSK auth */ +# define SSL_aPSK 0x00000080L +/* GOST R 34.10-94 signature auth */ +# define SSL_aGOST94 0x00000100L +/* GOST R 34.10-2001 signature auth */ +# define SSL_aGOST01 0x00000200L +/* SRP auth */ +# define SSL_aSRP 0x00000400L + +/* Bits for algorithm_enc (symmetric encryption) */ +# define SSL_DES 0x00000001L +# define SSL_3DES 0x00000002L +# define SSL_RC4 0x00000004L +# define SSL_RC2 0x00000008L +# define SSL_IDEA 0x00000010L +# define SSL_eNULL 0x00000020L +# define SSL_AES128 0x00000040L +# define SSL_AES256 0x00000080L +# define SSL_CAMELLIA128 0x00000100L +# define SSL_CAMELLIA256 0x00000200L +# define SSL_eGOST2814789CNT 0x00000400L +# define SSL_SEED 0x00000800L +# define SSL_AES128GCM 0x00001000L +# define SSL_AES256GCM 0x00002000L + +# define SSL_AES (SSL_AES128|SSL_AES256|SSL_AES128GCM|SSL_AES256GCM) +# define SSL_CAMELLIA (SSL_CAMELLIA128|SSL_CAMELLIA256) + +/* Bits for algorithm_mac (symmetric authentication) */ + +# define SSL_MD5 0x00000001L +# define SSL_SHA1 0x00000002L +# define SSL_GOST94 0x00000004L +# define SSL_GOST89MAC 0x00000008L +# define SSL_SHA256 0x00000010L +# define SSL_SHA384 0x00000020L +/* Not a real MAC, just an indication it is part of cipher */ +# define SSL_AEAD 0x00000040L + +/* Bits for algorithm_ssl (protocol version) */ +# define SSL_SSLV2 0x00000001UL +# define SSL_SSLV3 0x00000002UL +# define SSL_TLSV1 SSL_SSLV3/* for now */ +# define SSL_TLSV1_2 0x00000004UL + +/* Bits for algorithm2 (handshake digests and other extra flags) */ + +# define SSL_HANDSHAKE_MAC_MD5 0x10 +# define SSL_HANDSHAKE_MAC_SHA 0x20 +# define SSL_HANDSHAKE_MAC_GOST94 0x40 +# define SSL_HANDSHAKE_MAC_SHA256 0x80 +# define SSL_HANDSHAKE_MAC_SHA384 0x100 +# define SSL_HANDSHAKE_MAC_DEFAULT (SSL_HANDSHAKE_MAC_MD5 | SSL_HANDSHAKE_MAC_SHA) + +/* + * When adding new digest in the ssl_ciph.c and increment SSM_MD_NUM_IDX make + * sure to update this constant too + */ +# define SSL_MAX_DIGEST 6 + +# define TLS1_PRF_DGST_MASK (0xff << TLS1_PRF_DGST_SHIFT) + +# define TLS1_PRF_DGST_SHIFT 10 +# define TLS1_PRF_MD5 (SSL_HANDSHAKE_MAC_MD5 << TLS1_PRF_DGST_SHIFT) +# define TLS1_PRF_SHA1 (SSL_HANDSHAKE_MAC_SHA << TLS1_PRF_DGST_SHIFT) +# define TLS1_PRF_SHA256 (SSL_HANDSHAKE_MAC_SHA256 << TLS1_PRF_DGST_SHIFT) +# define TLS1_PRF_SHA384 (SSL_HANDSHAKE_MAC_SHA384 << TLS1_PRF_DGST_SHIFT) +# define TLS1_PRF_GOST94 (SSL_HANDSHAKE_MAC_GOST94 << TLS1_PRF_DGST_SHIFT) +# define TLS1_PRF (TLS1_PRF_MD5 | TLS1_PRF_SHA1) + +/* + * Stream MAC for GOST ciphersuites from cryptopro draft (currently this also + * goes into algorithm2) + */ +# define TLS1_STREAM_MAC 0x04 + +/* + * Export and cipher strength information. For each cipher we have to decide + * whether it is exportable or not. This information is likely to change + * over time, since the export control rules are no static technical issue. + * + * Independent of the export flag the cipher strength is sorted into classes. + * SSL_EXP40 was denoting the 40bit US export limit of past times, which now + * is at 56bit (SSL_EXP56). If the exportable cipher class is going to change + * again (eg. to 64bit) the use of "SSL_EXP*" becomes blurred even more, + * since SSL_EXP64 could be similar to SSL_LOW. + * For this reason SSL_MICRO and SSL_MINI macros are included to widen the + * namespace of SSL_LOW-SSL_HIGH to lower values. As development of speed + * and ciphers goes, another extension to SSL_SUPER and/or SSL_ULTRA would + * be possible. + */ +# define SSL_EXP_MASK 0x00000003L +# define SSL_STRONG_MASK 0x000001fcL + +# define SSL_NOT_EXP 0x00000001L +# define SSL_EXPORT 0x00000002L + +# define SSL_STRONG_NONE 0x00000004L +# define SSL_EXP40 0x00000008L +# define SSL_MICRO (SSL_EXP40) +# define SSL_EXP56 0x00000010L +# define SSL_MINI (SSL_EXP56) +# define SSL_LOW 0x00000020L +# define SSL_MEDIUM 0x00000040L +# define SSL_HIGH 0x00000080L +# define SSL_FIPS 0x00000100L +# define SSL_NOT_DEFAULT 0x00000200L + +/* we have used 000003ff - 22 bits left to go */ + +/*- + * Macros to check the export status and cipher strength for export ciphers. + * Even though the macros for EXPORT and EXPORT40/56 have similar names, + * their meaning is different: + * *_EXPORT macros check the 'exportable' status. + * *_EXPORT40/56 macros are used to check whether a certain cipher strength + * is given. + * Since the SSL_IS_EXPORT* and SSL_EXPORT* macros depend on the correct + * algorithm structure element to be passed (algorithms, algo_strength) and no + * typechecking can be done as they are all of type unsigned long, their + * direct usage is discouraged. + * Use the SSL_C_* macros instead. + */ +# define SSL_IS_EXPORT(a) ((a)&SSL_EXPORT) +# define SSL_IS_EXPORT56(a) ((a)&SSL_EXP56) +# define SSL_IS_EXPORT40(a) ((a)&SSL_EXP40) +# define SSL_C_IS_EXPORT(c) SSL_IS_EXPORT((c)->algo_strength) +# define SSL_C_IS_EXPORT56(c) SSL_IS_EXPORT56((c)->algo_strength) +# define SSL_C_IS_EXPORT40(c) SSL_IS_EXPORT40((c)->algo_strength) + +# define SSL_EXPORT_KEYLENGTH(a,s) (SSL_IS_EXPORT40(s) ? 5 : \ + (a) == SSL_DES ? 8 : 7) +# define SSL_EXPORT_PKEYLENGTH(a) (SSL_IS_EXPORT40(a) ? 512 : 1024) +# define SSL_C_EXPORT_KEYLENGTH(c) SSL_EXPORT_KEYLENGTH((c)->algorithm_enc, \ + (c)->algo_strength) +# define SSL_C_EXPORT_PKEYLENGTH(c) SSL_EXPORT_PKEYLENGTH((c)->algo_strength) + +/* Check if an SSL structure is using DTLS */ +# define SSL_IS_DTLS(s) (s->method->ssl3_enc->enc_flags & SSL_ENC_FLAG_DTLS) +/* See if we need explicit IV */ +# define SSL_USE_EXPLICIT_IV(s) \ + (s->method->ssl3_enc->enc_flags & SSL_ENC_FLAG_EXPLICIT_IV) +/* + * See if we use signature algorithms extension and signature algorithm + * before signatures. + */ +# define SSL_USE_SIGALGS(s) \ + (s->method->ssl3_enc->enc_flags & SSL_ENC_FLAG_SIGALGS) +/* + * Allow TLS 1.2 ciphersuites: applies to DTLS 1.2 as well as TLS 1.2: may + * apply to others in future. + */ +# define SSL_USE_TLS1_2_CIPHERS(s) \ + (s->method->ssl3_enc->enc_flags & SSL_ENC_FLAG_TLS1_2_CIPHERS) +/* + * Determine if a client can use TLS 1.2 ciphersuites: can't rely on method + * flags because it may not be set to correct version yet. + */ +# define SSL_CLIENT_USE_TLS1_2_CIPHERS(s) \ + ((SSL_IS_DTLS(s) && s->client_version <= DTLS1_2_VERSION) || \ + (!SSL_IS_DTLS(s) && s->client_version >= TLS1_2_VERSION)) + +/* Mostly for SSLv3 */ +# define SSL_PKEY_RSA_ENC 0 +# define SSL_PKEY_RSA_SIGN 1 +# define SSL_PKEY_DSA_SIGN 2 +# define SSL_PKEY_DH_RSA 3 +# define SSL_PKEY_DH_DSA 4 +# define SSL_PKEY_ECC 5 +# define SSL_PKEY_GOST94 6 +# define SSL_PKEY_GOST01 7 +# define SSL_PKEY_NUM 8 + +/*- + * SSL_kRSA <- RSA_ENC | (RSA_TMP & RSA_SIGN) | + * <- (EXPORT & (RSA_ENC | RSA_TMP) & RSA_SIGN) + * SSL_kDH <- DH_ENC & (RSA_ENC | RSA_SIGN | DSA_SIGN) + * SSL_kEDH <- RSA_ENC | RSA_SIGN | DSA_SIGN + * SSL_aRSA <- RSA_ENC | RSA_SIGN + * SSL_aDSS <- DSA_SIGN + */ + +/*- +#define CERT_INVALID 0 +#define CERT_PUBLIC_KEY 1 +#define CERT_PRIVATE_KEY 2 +*/ + +# ifndef OPENSSL_NO_EC +/* + * From ECC-TLS draft, used in encoding the curve type in ECParameters + */ +# define EXPLICIT_PRIME_CURVE_TYPE 1 +# define EXPLICIT_CHAR2_CURVE_TYPE 2 +# define NAMED_CURVE_TYPE 3 +# endif /* OPENSSL_NO_EC */ + +typedef struct cert_pkey_st { + X509 *x509; + EVP_PKEY *privatekey; + /* Digest to use when signing */ + const EVP_MD *digest; + /* Chain for this certificate */ + STACK_OF(X509) *chain; +# ifndef OPENSSL_NO_TLSEXT + /*- + * serverinfo data for this certificate. The data is in TLS Extension + * wire format, specifically it's a series of records like: + * uint16_t extension_type; // (RFC 5246, 7.4.1.4, Extension) + * uint16_t length; + * uint8_t data[length]; + */ + unsigned char *serverinfo; + size_t serverinfo_length; +# endif + /* + * Set if CERT_PKEY can be used with current SSL session: e.g. + * appropriate curve, signature algorithms etc. If zero it can't be used + * at all. + */ + int valid_flags; +} CERT_PKEY; +/* Retrieve Suite B flags */ +# define tls1_suiteb(s) (s->cert->cert_flags & SSL_CERT_FLAG_SUITEB_128_LOS) +/* Uses to check strict mode: suite B modes are always strict */ +# define SSL_CERT_FLAGS_CHECK_TLS_STRICT \ + (SSL_CERT_FLAG_SUITEB_128_LOS|SSL_CERT_FLAG_TLS_STRICT) + +typedef struct { + unsigned short ext_type; + /* + * Per-connection flags relating to this extension type: not used if + * part of an SSL_CTX structure. + */ + unsigned short ext_flags; + custom_ext_add_cb add_cb; + custom_ext_free_cb free_cb; + void *add_arg; + custom_ext_parse_cb parse_cb; + void *parse_arg; +} custom_ext_method; + +/* ext_flags values */ + +/* + * Indicates an extension has been received. Used to check for unsolicited or + * duplicate extensions. + */ +# define SSL_EXT_FLAG_RECEIVED 0x1 +/* + * Indicates an extension has been sent: used to enable sending of + * corresponding ServerHello extension. + */ +# define SSL_EXT_FLAG_SENT 0x2 + +typedef struct { + custom_ext_method *meths; + size_t meths_count; +} custom_ext_methods; + +typedef struct cert_st { + /* Current active set */ + /* + * ALWAYS points to an element of the pkeys array + * Probably it would make more sense to store + * an index, not a pointer. + */ + CERT_PKEY *key; + /* + * For servers the following masks are for the key and auth algorithms + * that are supported by the certs below. For clients they are masks of + * *disabled* algorithms based on the current session. + */ + int valid; + unsigned long mask_k; + unsigned long mask_a; + unsigned long export_mask_k; + unsigned long export_mask_a; + /* Client only */ + unsigned long mask_ssl; +# ifndef OPENSSL_NO_RSA + RSA *rsa_tmp; + RSA *(*rsa_tmp_cb) (SSL *ssl, int is_export, int keysize); +# endif +# ifndef OPENSSL_NO_DH + DH *dh_tmp; + DH *(*dh_tmp_cb) (SSL *ssl, int is_export, int keysize); +# endif +# ifndef OPENSSL_NO_ECDH + EC_KEY *ecdh_tmp; + /* Callback for generating ephemeral ECDH keys */ + EC_KEY *(*ecdh_tmp_cb) (SSL *ssl, int is_export, int keysize); + /* Select ECDH parameters automatically */ + int ecdh_tmp_auto; +# endif + /* Flags related to certificates */ + unsigned int cert_flags; + CERT_PKEY pkeys[SSL_PKEY_NUM]; + /* + * Certificate types (received or sent) in certificate request message. + * On receive this is only set if number of certificate types exceeds + * SSL3_CT_NUMBER. + */ + unsigned char *ctypes; + size_t ctype_num; + /* + * signature algorithms peer reports: e.g. supported signature algorithms + * extension for server or as part of a certificate request for client. + */ + unsigned char *peer_sigalgs; + /* Size of above array */ + size_t peer_sigalgslen; + /* + * suppported signature algorithms. When set on a client this is sent in + * the client hello as the supported signature algorithms extension. For + * servers it represents the signature algorithms we are willing to use. + */ + unsigned char *conf_sigalgs; + /* Size of above array */ + size_t conf_sigalgslen; + /* + * Client authentication signature algorithms, if not set then uses + * conf_sigalgs. On servers these will be the signature algorithms sent + * to the client in a cerificate request for TLS 1.2. On a client this + * represents the signature algortithms we are willing to use for client + * authentication. + */ + unsigned char *client_sigalgs; + /* Size of above array */ + size_t client_sigalgslen; + /* + * Signature algorithms shared by client and server: cached because these + * are used most often. + */ + TLS_SIGALGS *shared_sigalgs; + size_t shared_sigalgslen; + /* + * Certificate setup callback: if set is called whenever a certificate + * may be required (client or server). the callback can then examine any + * appropriate parameters and setup any certificates required. This + * allows advanced applications to select certificates on the fly: for + * example based on supported signature algorithms or curves. + */ + int (*cert_cb) (SSL *ssl, void *arg); + void *cert_cb_arg; + /* + * Optional X509_STORE for chain building or certificate validation If + * NULL the parent SSL_CTX store is used instead. + */ + X509_STORE *chain_store; + X509_STORE *verify_store; + /* Raw values of the cipher list from a client */ + unsigned char *ciphers_raw; + size_t ciphers_rawlen; + /* Custom extension methods for server and client */ + custom_ext_methods cli_ext; + custom_ext_methods srv_ext; + int references; /* >1 only if SSL_copy_session_id is used */ + /* non-optimal, but here due to compatibility */ + unsigned char *alpn_proposed; /* server */ + unsigned int alpn_proposed_len; + int alpn_sent; /* client */ +} CERT; + +typedef struct sess_cert_st { + STACK_OF(X509) *cert_chain; /* as received from peer (not for SSL2) */ + /* The 'peer_...' members are used only by clients. */ + int peer_cert_type; + CERT_PKEY *peer_key; /* points to an element of peer_pkeys (never + * NULL!) */ + CERT_PKEY peer_pkeys[SSL_PKEY_NUM]; + /* + * Obviously we don't have the private keys of these, so maybe we + * shouldn't even use the CERT_PKEY type here. + */ +# ifndef OPENSSL_NO_RSA + RSA *peer_rsa_tmp; /* not used for SSL 2 */ +# endif +# ifndef OPENSSL_NO_DH + DH *peer_dh_tmp; /* not used for SSL 2 */ +# endif +# ifndef OPENSSL_NO_ECDH + EC_KEY *peer_ecdh_tmp; +# endif + int references; /* actually always 1 at the moment */ +} SESS_CERT; +/* Structure containing decoded values of signature algorithms extension */ +struct tls_sigalgs_st { + /* NID of hash algorithm */ + int hash_nid; + /* NID of signature algorithm */ + int sign_nid; + /* Combined hash and signature NID */ + int signandhash_nid; + /* Raw values used in extension */ + unsigned char rsign; + unsigned char rhash; +}; + +/* + * #define MAC_DEBUG + */ + +/* + * #define ERR_DEBUG + */ +/* + * #define ABORT_DEBUG + */ +/* + * #define PKT_DEBUG 1 + */ +/* + * #define DES_DEBUG + */ +/* + * #define DES_OFB_DEBUG + */ +/* + * #define SSL_DEBUG + */ +/* + * #define RSA_DEBUG + */ +/* + * #define IDEA_DEBUG + */ + +# define FP_ICC (int (*)(const void *,const void *)) +# define ssl_put_cipher_by_char(ssl,ciph,ptr) \ + ((ssl)->method->put_cipher_by_char((ciph),(ptr))) + +/* + * This is for the SSLv3/TLSv1.0 differences in crypto/hash stuff It is a bit + * of a mess of functions, but hell, think of it as an opaque structure :-) + */ +typedef struct ssl3_enc_method { + int (*enc) (SSL *, int); + int (*mac) (SSL *, unsigned char *, int); + int (*setup_key_block) (SSL *); + int (*generate_master_secret) (SSL *, unsigned char *, unsigned char *, + int); + int (*change_cipher_state) (SSL *, int); + int (*final_finish_mac) (SSL *, const char *, int, unsigned char *); + int finish_mac_length; + int (*cert_verify_mac) (SSL *, int, unsigned char *); + const char *client_finished_label; + int client_finished_label_len; + const char *server_finished_label; + int server_finished_label_len; + int (*alert_value) (int); + int (*export_keying_material) (SSL *, unsigned char *, size_t, + const char *, size_t, + const unsigned char *, size_t, + int use_context); + /* Various flags indicating protocol version requirements */ + unsigned int enc_flags; + /* Handshake header length */ + unsigned int hhlen; + /* Set the handshake header */ + void (*set_handshake_header) (SSL *s, int type, unsigned long len); + /* Write out handshake message */ + int (*do_write) (SSL *s); +} SSL3_ENC_METHOD; + +# define SSL_HM_HEADER_LENGTH(s) s->method->ssl3_enc->hhlen +# define ssl_handshake_start(s) \ + (((unsigned char *)s->init_buf->data) + s->method->ssl3_enc->hhlen) +# define ssl_set_handshake_header(s, htype, len) \ + s->method->ssl3_enc->set_handshake_header(s, htype, len) +# define ssl_do_write(s) s->method->ssl3_enc->do_write(s) + +/* Values for enc_flags */ + +/* Uses explicit IV for CBC mode */ +# define SSL_ENC_FLAG_EXPLICIT_IV 0x1 +/* Uses signature algorithms extension */ +# define SSL_ENC_FLAG_SIGALGS 0x2 +/* Uses SHA256 default PRF */ +# define SSL_ENC_FLAG_SHA256_PRF 0x4 +/* Is DTLS */ +# define SSL_ENC_FLAG_DTLS 0x8 +/* + * Allow TLS 1.2 ciphersuites: applies to DTLS 1.2 as well as TLS 1.2: may + * apply to others in future. + */ +# define SSL_ENC_FLAG_TLS1_2_CIPHERS 0x10 + +# ifndef OPENSSL_NO_COMP +/* Used for holding the relevant compression methods loaded into SSL_CTX */ +typedef struct ssl3_comp_st { + int comp_id; /* The identifier byte for this compression + * type */ + char *name; /* Text name used for the compression type */ + COMP_METHOD *method; /* The method :-) */ +} SSL3_COMP; +# endif + +# ifndef OPENSSL_NO_BUF_FREELISTS +typedef struct ssl3_buf_freelist_st { + size_t chunklen; + unsigned int len; + struct ssl3_buf_freelist_entry_st *head; +} SSL3_BUF_FREELIST; + +typedef struct ssl3_buf_freelist_entry_st { + struct ssl3_buf_freelist_entry_st *next; +} SSL3_BUF_FREELIST_ENTRY; +# endif + +extern SSL3_ENC_METHOD ssl3_undef_enc_method; +OPENSSL_EXTERN const SSL_CIPHER ssl2_ciphers[]; +OPENSSL_EXTERN SSL_CIPHER ssl3_ciphers[]; + +SSL_METHOD *ssl_bad_method(int ver); + +extern SSL3_ENC_METHOD TLSv1_enc_data; +extern SSL3_ENC_METHOD TLSv1_1_enc_data; +extern SSL3_ENC_METHOD TLSv1_2_enc_data; +extern SSL3_ENC_METHOD SSLv3_enc_data; +extern SSL3_ENC_METHOD DTLSv1_enc_data; +extern SSL3_ENC_METHOD DTLSv1_2_enc_data; + +# define IMPLEMENT_tls_meth_func(version, func_name, s_accept, s_connect, \ + s_get_meth, enc_data) \ +const SSL_METHOD *func_name(void) \ + { \ + static const SSL_METHOD func_name##_data= { \ + version, \ + tls1_new, \ + tls1_clear, \ + tls1_free, \ + s_accept, \ + s_connect, \ + ssl3_read, \ + ssl3_peek, \ + ssl3_write, \ + ssl3_shutdown, \ + ssl3_renegotiate, \ + ssl3_renegotiate_check, \ + ssl3_get_message, \ + ssl3_read_bytes, \ + ssl3_write_bytes, \ + ssl3_dispatch_alert, \ + ssl3_ctrl, \ + ssl3_ctx_ctrl, \ + ssl3_get_cipher_by_char, \ + ssl3_put_cipher_by_char, \ + ssl3_pending, \ + ssl3_num_ciphers, \ + ssl3_get_cipher, \ + s_get_meth, \ + tls1_default_timeout, \ + &enc_data, \ + ssl_undefined_void_function, \ + ssl3_callback_ctrl, \ + ssl3_ctx_callback_ctrl, \ + }; \ + return &func_name##_data; \ + } + +# define IMPLEMENT_ssl3_meth_func(func_name, s_accept, s_connect, s_get_meth) \ +const SSL_METHOD *func_name(void) \ + { \ + static const SSL_METHOD func_name##_data= { \ + SSL3_VERSION, \ + ssl3_new, \ + ssl3_clear, \ + ssl3_free, \ + s_accept, \ + s_connect, \ + ssl3_read, \ + ssl3_peek, \ + ssl3_write, \ + ssl3_shutdown, \ + ssl3_renegotiate, \ + ssl3_renegotiate_check, \ + ssl3_get_message, \ + ssl3_read_bytes, \ + ssl3_write_bytes, \ + ssl3_dispatch_alert, \ + ssl3_ctrl, \ + ssl3_ctx_ctrl, \ + ssl3_get_cipher_by_char, \ + ssl3_put_cipher_by_char, \ + ssl3_pending, \ + ssl3_num_ciphers, \ + ssl3_get_cipher, \ + s_get_meth, \ + ssl3_default_timeout, \ + &SSLv3_enc_data, \ + ssl_undefined_void_function, \ + ssl3_callback_ctrl, \ + ssl3_ctx_callback_ctrl, \ + }; \ + return &func_name##_data; \ + } + +# define IMPLEMENT_ssl23_meth_func(func_name, s_accept, s_connect, s_get_meth) \ +const SSL_METHOD *func_name(void) \ + { \ + static const SSL_METHOD func_name##_data= { \ + TLS1_2_VERSION, \ + tls1_new, \ + tls1_clear, \ + tls1_free, \ + s_accept, \ + s_connect, \ + ssl23_read, \ + ssl23_peek, \ + ssl23_write, \ + ssl_undefined_function, \ + ssl_undefined_function, \ + ssl_ok, \ + ssl3_get_message, \ + ssl3_read_bytes, \ + ssl3_write_bytes, \ + ssl3_dispatch_alert, \ + ssl3_ctrl, \ + ssl3_ctx_ctrl, \ + ssl23_get_cipher_by_char, \ + ssl23_put_cipher_by_char, \ + ssl_undefined_const_function, \ + ssl23_num_ciphers, \ + ssl23_get_cipher, \ + s_get_meth, \ + ssl23_default_timeout, \ + &TLSv1_2_enc_data, \ + ssl_undefined_void_function, \ + ssl3_callback_ctrl, \ + ssl3_ctx_callback_ctrl, \ + }; \ + return &func_name##_data; \ + } + +# define IMPLEMENT_ssl2_meth_func(func_name, s_accept, s_connect, s_get_meth) \ +const SSL_METHOD *func_name(void) \ + { \ + static const SSL_METHOD func_name##_data= { \ + SSL2_VERSION, \ + ssl2_new, /* local */ \ + ssl2_clear, /* local */ \ + ssl2_free, /* local */ \ + s_accept, \ + s_connect, \ + ssl2_read, \ + ssl2_peek, \ + ssl2_write, \ + ssl2_shutdown, \ + ssl_ok, /* NULL - renegotiate */ \ + ssl_ok, /* NULL - check renegotiate */ \ + NULL, /* NULL - ssl_get_message */ \ + NULL, /* NULL - ssl_get_record */ \ + NULL, /* NULL - ssl_write_bytes */ \ + NULL, /* NULL - dispatch_alert */ \ + ssl2_ctrl, /* local */ \ + ssl2_ctx_ctrl, /* local */ \ + ssl2_get_cipher_by_char, \ + ssl2_put_cipher_by_char, \ + ssl2_pending, \ + ssl2_num_ciphers, \ + ssl2_get_cipher, \ + s_get_meth, \ + ssl2_default_timeout, \ + &ssl3_undef_enc_method, \ + ssl_undefined_void_function, \ + ssl2_callback_ctrl, /* local */ \ + ssl2_ctx_callback_ctrl, /* local */ \ + }; \ + return &func_name##_data; \ + } + +# define IMPLEMENT_dtls1_meth_func(version, func_name, s_accept, s_connect, \ + s_get_meth, enc_data) \ +const SSL_METHOD *func_name(void) \ + { \ + static const SSL_METHOD func_name##_data= { \ + version, \ + dtls1_new, \ + dtls1_clear, \ + dtls1_free, \ + s_accept, \ + s_connect, \ + ssl3_read, \ + ssl3_peek, \ + ssl3_write, \ + dtls1_shutdown, \ + ssl3_renegotiate, \ + ssl3_renegotiate_check, \ + dtls1_get_message, \ + dtls1_read_bytes, \ + dtls1_write_app_data_bytes, \ + dtls1_dispatch_alert, \ + dtls1_ctrl, \ + ssl3_ctx_ctrl, \ + ssl3_get_cipher_by_char, \ + ssl3_put_cipher_by_char, \ + ssl3_pending, \ + ssl3_num_ciphers, \ + dtls1_get_cipher, \ + s_get_meth, \ + dtls1_default_timeout, \ + &enc_data, \ + ssl_undefined_void_function, \ + ssl3_callback_ctrl, \ + ssl3_ctx_callback_ctrl, \ + }; \ + return &func_name##_data; \ + } + +struct openssl_ssl_test_functions { + int (*p_ssl_init_wbio_buffer) (SSL *s, int push); + int (*p_ssl3_setup_buffers) (SSL *s); + int (*p_tls1_process_heartbeat) (SSL *s); + int (*p_dtls1_process_heartbeat) (SSL *s); +}; + +# ifndef OPENSSL_UNIT_TEST + +void ssl_clear_cipher_ctx(SSL *s); +int ssl_clear_bad_session(SSL *s); +CERT *ssl_cert_new(void); +CERT *ssl_cert_dup(CERT *cert); +void ssl_cert_set_default_md(CERT *cert); +int ssl_cert_inst(CERT **o); +void ssl_cert_clear_certs(CERT *c); +void ssl_cert_free(CERT *c); +SESS_CERT *ssl_sess_cert_new(void); +void ssl_sess_cert_free(SESS_CERT *sc); +int ssl_set_peer_cert_type(SESS_CERT *c, int type); +int ssl_get_new_session(SSL *s, int session); +int ssl_get_prev_session(SSL *s, unsigned char *session, int len, + const unsigned char *limit); +SSL_SESSION *ssl_session_dup(SSL_SESSION *src, int ticket); +int ssl_cipher_id_cmp(const SSL_CIPHER *a, const SSL_CIPHER *b); +DECLARE_OBJ_BSEARCH_GLOBAL_CMP_FN(SSL_CIPHER, SSL_CIPHER, ssl_cipher_id); +int ssl_cipher_ptr_id_cmp(const SSL_CIPHER *const *ap, + const SSL_CIPHER *const *bp); +STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, unsigned char *p, + int num, + STACK_OF(SSL_CIPHER) **skp); +int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk, + unsigned char *p, + int (*put_cb) (const SSL_CIPHER *, + unsigned char *)); +STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *meth, + STACK_OF(SSL_CIPHER) **pref, + STACK_OF(SSL_CIPHER) **sorted, + const char *rule_str, CERT *c); +void ssl_update_cache(SSL *s, int mode); +int ssl_cipher_get_evp(const SSL_SESSION *s, const EVP_CIPHER **enc, + const EVP_MD **md, int *mac_pkey_type, + int *mac_secret_size, SSL_COMP **comp); +int ssl_get_handshake_digest(int i, long *mask, const EVP_MD **md); +int ssl_cipher_get_cert_index(const SSL_CIPHER *c); +const SSL_CIPHER *ssl_get_cipher_by_char(SSL *ssl, const unsigned char *ptr); +int ssl_cert_set0_chain(CERT *c, STACK_OF(X509) *chain); +int ssl_cert_set1_chain(CERT *c, STACK_OF(X509) *chain); +int ssl_cert_add0_chain_cert(CERT *c, X509 *x); +int ssl_cert_add1_chain_cert(CERT *c, X509 *x); +int ssl_cert_select_current(CERT *c, X509 *x); +int ssl_cert_set_current(CERT *c, long arg); +X509 *ssl_cert_get0_next_certificate(CERT *c, int first); +void ssl_cert_set_cert_cb(CERT *c, int (*cb) (SSL *ssl, void *arg), + void *arg); + +int ssl_verify_cert_chain(SSL *s, STACK_OF(X509) *sk); +int ssl_add_cert_chain(SSL *s, CERT_PKEY *cpk, unsigned long *l); +int ssl_build_cert_chain(CERT *c, X509_STORE *chain_store, int flags); +int ssl_cert_set_cert_store(CERT *c, X509_STORE *store, int chain, int ref); +int ssl_undefined_function(SSL *s); +int ssl_undefined_void_function(void); +int ssl_undefined_const_function(const SSL *s); +CERT_PKEY *ssl_get_server_send_pkey(const SSL *s); +# ifndef OPENSSL_NO_TLSEXT +int ssl_get_server_cert_serverinfo(SSL *s, const unsigned char **serverinfo, + size_t *serverinfo_length); +# endif +EVP_PKEY *ssl_get_sign_pkey(SSL *s, const SSL_CIPHER *c, const EVP_MD **pmd); +int ssl_cert_type(X509 *x, EVP_PKEY *pkey); +void ssl_set_cert_masks(CERT *c, const SSL_CIPHER *cipher); +STACK_OF(SSL_CIPHER) *ssl_get_ciphers_by_id(SSL *s); +int ssl_verify_alarm_type(long type); +void ssl_load_ciphers(void); +int ssl_fill_hello_random(SSL *s, int server, unsigned char *field, int len); + +int ssl2_enc_init(SSL *s, int client); +int ssl2_generate_key_material(SSL *s); +int ssl2_enc(SSL *s, int send_data); +void ssl2_mac(SSL *s, unsigned char *mac, int send_data); +const SSL_CIPHER *ssl2_get_cipher_by_char(const unsigned char *p); +int ssl2_put_cipher_by_char(const SSL_CIPHER *c, unsigned char *p); +int ssl2_part_read(SSL *s, unsigned long f, int i); +int ssl2_do_write(SSL *s); +int ssl2_set_certificate(SSL *s, int type, int len, + const unsigned char *data); +void ssl2_return_error(SSL *s, int reason); +void ssl2_write_error(SSL *s); +int ssl2_num_ciphers(void); +const SSL_CIPHER *ssl2_get_cipher(unsigned int u); +int ssl2_new(SSL *s); +void ssl2_free(SSL *s); +int ssl2_accept(SSL *s); +int ssl2_connect(SSL *s); +int ssl2_read(SSL *s, void *buf, int len); +int ssl2_peek(SSL *s, void *buf, int len); +int ssl2_write(SSL *s, const void *buf, int len); +int ssl2_shutdown(SSL *s); +void ssl2_clear(SSL *s); +long ssl2_ctrl(SSL *s, int cmd, long larg, void *parg); +long ssl2_ctx_ctrl(SSL_CTX *s, int cmd, long larg, void *parg); +long ssl2_callback_ctrl(SSL *s, int cmd, void (*fp) (void)); +long ssl2_ctx_callback_ctrl(SSL_CTX *s, int cmd, void (*fp) (void)); +int ssl2_pending(const SSL *s); +long ssl2_default_timeout(void); + +const SSL_CIPHER *ssl3_get_cipher_by_char(const unsigned char *p); +int ssl3_put_cipher_by_char(const SSL_CIPHER *c, unsigned char *p); +void ssl3_init_finished_mac(SSL *s); +int ssl3_send_server_certificate(SSL *s); +int ssl3_send_newsession_ticket(SSL *s); +int ssl3_send_cert_status(SSL *s); +int ssl3_get_finished(SSL *s, int state_a, int state_b); +int ssl3_setup_key_block(SSL *s); +int ssl3_send_change_cipher_spec(SSL *s, int state_a, int state_b); +int ssl3_change_cipher_state(SSL *s, int which); +void ssl3_cleanup_key_block(SSL *s); +int ssl3_do_write(SSL *s, int type); +int ssl3_send_alert(SSL *s, int level, int desc); +int ssl3_generate_master_secret(SSL *s, unsigned char *out, + unsigned char *p, int len); +int ssl3_get_req_cert_type(SSL *s, unsigned char *p); +long ssl3_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok); +int ssl3_send_finished(SSL *s, int a, int b, const char *sender, int slen); +int ssl3_num_ciphers(void); +const SSL_CIPHER *ssl3_get_cipher(unsigned int u); +int ssl3_renegotiate(SSL *ssl); +int ssl3_renegotiate_check(SSL *ssl); +int ssl3_dispatch_alert(SSL *s); +int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek); +int ssl3_write_bytes(SSL *s, int type, const void *buf, int len); +int ssl3_final_finish_mac(SSL *s, const char *sender, int slen, + unsigned char *p); +int ssl3_cert_verify_mac(SSL *s, int md_nid, unsigned char *p); +void ssl3_finish_mac(SSL *s, const unsigned char *buf, int len); +int ssl3_enc(SSL *s, int send_data); +int n_ssl3_mac(SSL *ssl, unsigned char *md, int send_data); +void ssl3_free_digest_list(SSL *s); +unsigned long ssl3_output_cert_chain(SSL *s, CERT_PKEY *cpk); +SSL_CIPHER *ssl3_choose_cipher(SSL *ssl, STACK_OF(SSL_CIPHER) *clnt, + STACK_OF(SSL_CIPHER) *srvr); +int ssl3_setup_buffers(SSL *s); +int ssl3_setup_read_buffer(SSL *s); +int ssl3_setup_write_buffer(SSL *s); +int ssl3_release_read_buffer(SSL *s); +int ssl3_release_write_buffer(SSL *s); +int ssl3_digest_cached_records(SSL *s); +int ssl3_new(SSL *s); +void ssl3_free(SSL *s); +int ssl3_accept(SSL *s); +int ssl3_connect(SSL *s); +int ssl3_read(SSL *s, void *buf, int len); +int ssl3_peek(SSL *s, void *buf, int len); +int ssl3_write(SSL *s, const void *buf, int len); +int ssl3_shutdown(SSL *s); +void ssl3_clear(SSL *s); +long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg); +long ssl3_ctx_ctrl(SSL_CTX *s, int cmd, long larg, void *parg); +long ssl3_callback_ctrl(SSL *s, int cmd, void (*fp) (void)); +long ssl3_ctx_callback_ctrl(SSL_CTX *s, int cmd, void (*fp) (void)); +int ssl3_pending(const SSL *s); + +void ssl3_record_sequence_update(unsigned char *seq); +int ssl3_do_change_cipher_spec(SSL *ssl); +long ssl3_default_timeout(void); + +void ssl3_set_handshake_header(SSL *s, int htype, unsigned long len); +int ssl3_handshake_write(SSL *s); + +int ssl23_num_ciphers(void); +const SSL_CIPHER *ssl23_get_cipher(unsigned int u); +int ssl23_read(SSL *s, void *buf, int len); +int ssl23_peek(SSL *s, void *buf, int len); +int ssl23_write(SSL *s, const void *buf, int len); +int ssl23_put_cipher_by_char(const SSL_CIPHER *c, unsigned char *p); +const SSL_CIPHER *ssl23_get_cipher_by_char(const unsigned char *p); +long ssl23_default_timeout(void); + +long tls1_default_timeout(void); +int dtls1_do_write(SSL *s, int type); +int ssl3_read_n(SSL *s, int n, int max, int extend); +int dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek); +int ssl3_do_compress(SSL *ssl); +int ssl3_do_uncompress(SSL *ssl); +int ssl3_write_pending(SSL *s, int type, const unsigned char *buf, + unsigned int len); +unsigned char *dtls1_set_message_header(SSL *s, + unsigned char *p, unsigned char mt, + unsigned long len, + unsigned long frag_off, + unsigned long frag_len); + +int dtls1_write_app_data_bytes(SSL *s, int type, const void *buf, int len); +int dtls1_write_bytes(SSL *s, int type, const void *buf, int len); + +int dtls1_send_change_cipher_spec(SSL *s, int a, int b); +int dtls1_read_failed(SSL *s, int code); +int dtls1_buffer_message(SSL *s, int ccs); +int dtls1_retransmit_message(SSL *s, unsigned short seq, + unsigned long frag_off, int *found); +int dtls1_get_queue_priority(unsigned short seq, int is_ccs); +int dtls1_retransmit_buffered_messages(SSL *s); +void dtls1_clear_record_buffer(SSL *s); +void dtls1_get_message_header(unsigned char *data, + struct hm_header_st *msg_hdr); +void dtls1_get_ccs_header(unsigned char *data, struct ccs_header_st *ccs_hdr); +void dtls1_reset_seq_numbers(SSL *s, int rw); +long dtls1_default_timeout(void); +struct timeval *dtls1_get_timeout(SSL *s, struct timeval *timeleft); +int dtls1_check_timeout_num(SSL *s); +int dtls1_handle_timeout(SSL *s); +const SSL_CIPHER *dtls1_get_cipher(unsigned int u); +void dtls1_start_timer(SSL *s); +void dtls1_stop_timer(SSL *s); +int dtls1_is_timer_expired(SSL *s); +void dtls1_double_timeout(SSL *s); +int dtls1_send_newsession_ticket(SSL *s); +unsigned int dtls1_min_mtu(SSL *s); +unsigned int dtls1_link_min_mtu(void); +void dtls1_hm_fragment_free(hm_fragment *frag); + +/* some client-only functions */ +int ssl3_client_hello(SSL *s); +int ssl3_get_server_hello(SSL *s); +int ssl3_get_certificate_request(SSL *s); +int ssl3_get_new_session_ticket(SSL *s); +int ssl3_get_cert_status(SSL *s); +int ssl3_get_server_done(SSL *s); +int ssl3_send_client_verify(SSL *s); +int ssl3_send_client_certificate(SSL *s); +int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey); +int ssl3_send_client_key_exchange(SSL *s); +int ssl3_get_key_exchange(SSL *s); +int ssl3_get_server_certificate(SSL *s); +int ssl3_check_cert_and_algorithm(SSL *s); +# ifndef OPENSSL_NO_TLSEXT +# ifndef OPENSSL_NO_NEXTPROTONEG +int ssl3_send_next_proto(SSL *s); +# endif +# endif + +int dtls1_client_hello(SSL *s); + +/* some server-only functions */ +int ssl3_get_client_hello(SSL *s); +int ssl3_send_server_hello(SSL *s); +int ssl3_send_hello_request(SSL *s); +int ssl3_send_server_key_exchange(SSL *s); +int ssl3_send_certificate_request(SSL *s); +int ssl3_send_server_done(SSL *s); +int ssl3_get_client_certificate(SSL *s); +int ssl3_get_client_key_exchange(SSL *s); +int ssl3_get_cert_verify(SSL *s); +# ifndef OPENSSL_NO_NEXTPROTONEG +int ssl3_get_next_proto(SSL *s); +# endif + +int ssl23_accept(SSL *s); +int ssl23_connect(SSL *s); +int ssl23_read_bytes(SSL *s, int n); +int ssl23_write_bytes(SSL *s); + +int tls1_new(SSL *s); +void tls1_free(SSL *s); +void tls1_clear(SSL *s); +long tls1_ctrl(SSL *s, int cmd, long larg, void *parg); +long tls1_callback_ctrl(SSL *s, int cmd, void (*fp) (void)); + +int dtls1_new(SSL *s); +int dtls1_accept(SSL *s); +int dtls1_connect(SSL *s); +void dtls1_free(SSL *s); +void dtls1_clear(SSL *s); +long dtls1_ctrl(SSL *s, int cmd, long larg, void *parg); +int dtls1_shutdown(SSL *s); + +long dtls1_get_message(SSL *s, int st1, int stn, int mt, long max, int *ok); +int dtls1_get_record(SSL *s); +int do_dtls1_write(SSL *s, int type, const unsigned char *buf, + unsigned int len, int create_empty_fragement); +int dtls1_dispatch_alert(SSL *s); + +int ssl_init_wbio_buffer(SSL *s, int push); +void ssl_free_wbio_buffer(SSL *s); + +int tls1_change_cipher_state(SSL *s, int which); +int tls1_setup_key_block(SSL *s); +int tls1_enc(SSL *s, int snd); +int tls1_final_finish_mac(SSL *s, + const char *str, int slen, unsigned char *p); +int tls1_cert_verify_mac(SSL *s, int md_nid, unsigned char *p); +int tls1_mac(SSL *ssl, unsigned char *md, int snd); +int tls1_generate_master_secret(SSL *s, unsigned char *out, + unsigned char *p, int len); +int tls1_export_keying_material(SSL *s, unsigned char *out, size_t olen, + const char *label, size_t llen, + const unsigned char *p, size_t plen, + int use_context); +int tls1_alert_code(int code); +int ssl3_alert_code(int code); +int ssl_ok(SSL *s); + +# ifndef OPENSSL_NO_ECDH +int ssl_check_srvr_ecc_cert_and_alg(X509 *x, SSL *s); +# endif + +SSL_COMP *ssl3_comp_find(STACK_OF(SSL_COMP) *sk, int n); + +# ifndef OPENSSL_NO_EC +int tls1_ec_curve_id2nid(int curve_id); +int tls1_ec_nid2curve_id(int nid); +int tls1_check_curve(SSL *s, const unsigned char *p, size_t len); +int tls1_shared_curve(SSL *s, int nmatch); +int tls1_set_curves(unsigned char **pext, size_t *pextlen, + int *curves, size_t ncurves); +int tls1_set_curves_list(unsigned char **pext, size_t *pextlen, + const char *str); +# ifndef OPENSSL_NO_ECDH +int tls1_check_ec_tmp_key(SSL *s, unsigned long id); +# endif /* OPENSSL_NO_ECDH */ +# endif /* OPENSSL_NO_EC */ + +# ifndef OPENSSL_NO_TLSEXT +int tls1_shared_list(SSL *s, + const unsigned char *l1, size_t l1len, + const unsigned char *l2, size_t l2len, int nmatch); +unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf, + unsigned char *limit, int *al); +unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf, + unsigned char *limit, int *al); +int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **data, + unsigned char *limit); +int tls1_set_server_sigalgs(SSL *s); +int ssl_check_clienthello_tlsext_late(SSL *s); +int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **data, + unsigned char *d, int n); +int ssl_prepare_clienthello_tlsext(SSL *s); +int ssl_prepare_serverhello_tlsext(SSL *s); + +# ifndef OPENSSL_NO_HEARTBEATS +int tls1_heartbeat(SSL *s); +int dtls1_heartbeat(SSL *s); +int tls1_process_heartbeat(SSL *s); +int dtls1_process_heartbeat(SSL *s); +# endif + +# ifdef OPENSSL_NO_SHA256 +# define tlsext_tick_md EVP_sha1 +# else +# define tlsext_tick_md EVP_sha256 +# endif +int tls1_process_ticket(SSL *s, unsigned char *session_id, int len, + const unsigned char *limit, SSL_SESSION **ret); + +int tls12_get_sigandhash(unsigned char *p, const EVP_PKEY *pk, + const EVP_MD *md); +int tls12_get_sigid(const EVP_PKEY *pk); +const EVP_MD *tls12_get_hash(unsigned char hash_alg); + +int tls1_set_sigalgs_list(CERT *c, const char *str, int client); +int tls1_set_sigalgs(CERT *c, const int *salg, size_t salglen, int client); +int tls1_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain, + int idx); +void tls1_set_cert_validity(SSL *s); + +# endif +EVP_MD_CTX *ssl_replace_hash(EVP_MD_CTX **hash, const EVP_MD *md); +void ssl_clear_hash_ctx(EVP_MD_CTX **hash); +int ssl_add_serverhello_renegotiate_ext(SSL *s, unsigned char *p, int *len, + int maxlen); +int ssl_parse_serverhello_renegotiate_ext(SSL *s, unsigned char *d, int len, + int *al); +int ssl_add_clienthello_renegotiate_ext(SSL *s, unsigned char *p, int *len, + int maxlen); +int ssl_parse_clienthello_renegotiate_ext(SSL *s, unsigned char *d, int len, + int *al); +long ssl_get_algorithm2(SSL *s); +int tls1_save_sigalgs(SSL *s, const unsigned char *data, int dsize); +int tls1_process_sigalgs(SSL *s); +size_t tls12_get_psigalgs(SSL *s, const unsigned char **psigs); +int tls12_check_peer_sigalg(const EVP_MD **pmd, SSL *s, + const unsigned char *sig, EVP_PKEY *pkey); +void ssl_set_client_disabled(SSL *s); + +int ssl_add_clienthello_use_srtp_ext(SSL *s, unsigned char *p, int *len, + int maxlen); +int ssl_parse_clienthello_use_srtp_ext(SSL *s, unsigned char *d, int len, + int *al); +int ssl_add_serverhello_use_srtp_ext(SSL *s, unsigned char *p, int *len, + int maxlen); +int ssl_parse_serverhello_use_srtp_ext(SSL *s, unsigned char *d, int len, + int *al); + +/* s3_cbc.c */ +void ssl3_cbc_copy_mac(unsigned char *out, + const SSL3_RECORD *rec, + unsigned md_size, unsigned orig_len); +int ssl3_cbc_remove_padding(const SSL *s, + SSL3_RECORD *rec, + unsigned block_size, unsigned mac_size); +int tls1_cbc_remove_padding(const SSL *s, + SSL3_RECORD *rec, + unsigned block_size, unsigned mac_size); +char ssl3_cbc_record_digest_supported(const EVP_MD_CTX *ctx); +int ssl3_cbc_digest_record(const EVP_MD_CTX *ctx, + unsigned char *md_out, + size_t *md_out_size, + const unsigned char header[13], + const unsigned char *data, + size_t data_plus_mac_size, + size_t data_plus_mac_plus_padding_size, + const unsigned char *mac_secret, + unsigned mac_secret_length, char is_sslv3); + +void tls_fips_digest_extra(const EVP_CIPHER_CTX *cipher_ctx, + EVP_MD_CTX *mac_ctx, const unsigned char *data, + size_t data_len, size_t orig_len); + +int srp_verify_server_param(SSL *s, int *al); + +/* t1_ext.c */ + +void custom_ext_init(custom_ext_methods *meths); + +int custom_ext_parse(SSL *s, int server, + unsigned int ext_type, + const unsigned char *ext_data, size_t ext_size, int *al); +int custom_ext_add(SSL *s, int server, + unsigned char **pret, unsigned char *limit, int *al); + +int custom_exts_copy(custom_ext_methods *dst, const custom_ext_methods *src); +void custom_exts_free(custom_ext_methods *exts); + +# else + +# define ssl_init_wbio_buffer SSL_test_functions()->p_ssl_init_wbio_buffer +# define ssl3_setup_buffers SSL_test_functions()->p_ssl3_setup_buffers +# define tls1_process_heartbeat SSL_test_functions()->p_tls1_process_heartbeat +# define dtls1_process_heartbeat SSL_test_functions()->p_dtls1_process_heartbeat + +# endif +#endif diff --git a/thirdparty/openssl/ssl/ssl_rsa.c b/thirdparty/openssl/ssl/ssl_rsa.c new file mode 100644 index 0000000000..82022470bf --- /dev/null +++ b/thirdparty/openssl/ssl/ssl_rsa.c @@ -0,0 +1,1043 @@ +/* ssl/ssl_rsa.c */ +/* 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.] + */ + +#include <stdio.h> +#include "ssl_locl.h" +#include <openssl/bio.h> +#include <openssl/objects.h> +#include <openssl/evp.h> +#include <openssl/x509.h> +#include <openssl/pem.h> + +static int ssl_set_cert(CERT *c, X509 *x509); +static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey); +int SSL_use_certificate(SSL *ssl, X509 *x) +{ + if (x == NULL) { + SSLerr(SSL_F_SSL_USE_CERTIFICATE, ERR_R_PASSED_NULL_PARAMETER); + return (0); + } + if (!ssl_cert_inst(&ssl->cert)) { + SSLerr(SSL_F_SSL_USE_CERTIFICATE, ERR_R_MALLOC_FAILURE); + return (0); + } + return (ssl_set_cert(ssl->cert, x)); +} + +#ifndef OPENSSL_NO_STDIO +int SSL_use_certificate_file(SSL *ssl, const char *file, int type) +{ + int j; + BIO *in; + int ret = 0; + X509 *x = NULL; + + in = BIO_new(BIO_s_file_internal()); + if (in == NULL) { + SSLerr(SSL_F_SSL_USE_CERTIFICATE_FILE, ERR_R_BUF_LIB); + goto end; + } + + if (BIO_read_filename(in, file) <= 0) { + SSLerr(SSL_F_SSL_USE_CERTIFICATE_FILE, ERR_R_SYS_LIB); + goto end; + } + if (type == SSL_FILETYPE_ASN1) { + j = ERR_R_ASN1_LIB; + x = d2i_X509_bio(in, NULL); + } else if (type == SSL_FILETYPE_PEM) { + j = ERR_R_PEM_LIB; + x = PEM_read_bio_X509(in, NULL, ssl->ctx->default_passwd_callback, + ssl->ctx->default_passwd_callback_userdata); + } else { + SSLerr(SSL_F_SSL_USE_CERTIFICATE_FILE, SSL_R_BAD_SSL_FILETYPE); + goto end; + } + + if (x == NULL) { + SSLerr(SSL_F_SSL_USE_CERTIFICATE_FILE, j); + goto end; + } + + ret = SSL_use_certificate(ssl, x); + end: + if (x != NULL) + X509_free(x); + if (in != NULL) + BIO_free(in); + return (ret); +} +#endif + +int SSL_use_certificate_ASN1(SSL *ssl, const unsigned char *d, int len) +{ + X509 *x; + int ret; + + x = d2i_X509(NULL, &d, (long)len); + if (x == NULL) { + SSLerr(SSL_F_SSL_USE_CERTIFICATE_ASN1, ERR_R_ASN1_LIB); + return (0); + } + + ret = SSL_use_certificate(ssl, x); + X509_free(x); + return (ret); +} + +#ifndef OPENSSL_NO_RSA +int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa) +{ + EVP_PKEY *pkey; + int ret; + + if (rsa == NULL) { + SSLerr(SSL_F_SSL_USE_RSAPRIVATEKEY, ERR_R_PASSED_NULL_PARAMETER); + return (0); + } + if (!ssl_cert_inst(&ssl->cert)) { + SSLerr(SSL_F_SSL_USE_RSAPRIVATEKEY, ERR_R_MALLOC_FAILURE); + return (0); + } + if ((pkey = EVP_PKEY_new()) == NULL) { + SSLerr(SSL_F_SSL_USE_RSAPRIVATEKEY, ERR_R_EVP_LIB); + return (0); + } + + RSA_up_ref(rsa); + if (EVP_PKEY_assign_RSA(pkey, rsa) <= 0) { + RSA_free(rsa); + return 0; + } + + ret = ssl_set_pkey(ssl->cert, pkey); + EVP_PKEY_free(pkey); + return (ret); +} +#endif + +static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey) +{ + int i; + /* + * Special case for DH: check two DH certificate types for a match. This + * means for DH certificates we must set the certificate first. + */ + if (pkey->type == EVP_PKEY_DH) { + X509 *x; + i = -1; + x = c->pkeys[SSL_PKEY_DH_RSA].x509; + if (x && X509_check_private_key(x, pkey)) + i = SSL_PKEY_DH_RSA; + x = c->pkeys[SSL_PKEY_DH_DSA].x509; + if (i == -1 && x && X509_check_private_key(x, pkey)) + i = SSL_PKEY_DH_DSA; + ERR_clear_error(); + } else + i = ssl_cert_type(NULL, pkey); + if (i < 0) { + SSLerr(SSL_F_SSL_SET_PKEY, SSL_R_UNKNOWN_CERTIFICATE_TYPE); + return (0); + } + + if (c->pkeys[i].x509 != NULL) { + EVP_PKEY *pktmp; + pktmp = X509_get_pubkey(c->pkeys[i].x509); + if (pktmp == NULL) { + SSLerr(SSL_F_SSL_SET_PKEY, ERR_R_MALLOC_FAILURE); + EVP_PKEY_free(pktmp); + return 0; + } + /* + * The return code from EVP_PKEY_copy_parameters is deliberately + * ignored. Some EVP_PKEY types cannot do this. + */ + EVP_PKEY_copy_parameters(pktmp, pkey); + EVP_PKEY_free(pktmp); + ERR_clear_error(); + +#ifndef OPENSSL_NO_RSA + /* + * Don't check the public/private key, this is mostly for smart + * cards. + */ + if ((pkey->type == EVP_PKEY_RSA) && + (RSA_flags(pkey->pkey.rsa) & RSA_METHOD_FLAG_NO_CHECK)) ; + else +#endif + if (!X509_check_private_key(c->pkeys[i].x509, pkey)) { + X509_free(c->pkeys[i].x509); + c->pkeys[i].x509 = NULL; + return 0; + } + } + + if (c->pkeys[i].privatekey != NULL) + EVP_PKEY_free(c->pkeys[i].privatekey); + CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY); + c->pkeys[i].privatekey = pkey; + c->key = &(c->pkeys[i]); + + c->valid = 0; + return (1); +} + +#ifndef OPENSSL_NO_RSA +# ifndef OPENSSL_NO_STDIO +int SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, int type) +{ + int j, ret = 0; + BIO *in; + RSA *rsa = NULL; + + in = BIO_new(BIO_s_file_internal()); + if (in == NULL) { + SSLerr(SSL_F_SSL_USE_RSAPRIVATEKEY_FILE, ERR_R_BUF_LIB); + goto end; + } + + if (BIO_read_filename(in, file) <= 0) { + SSLerr(SSL_F_SSL_USE_RSAPRIVATEKEY_FILE, ERR_R_SYS_LIB); + goto end; + } + if (type == SSL_FILETYPE_ASN1) { + j = ERR_R_ASN1_LIB; + rsa = d2i_RSAPrivateKey_bio(in, NULL); + } else if (type == SSL_FILETYPE_PEM) { + j = ERR_R_PEM_LIB; + rsa = PEM_read_bio_RSAPrivateKey(in, NULL, + ssl->ctx->default_passwd_callback, + ssl-> + ctx->default_passwd_callback_userdata); + } else { + SSLerr(SSL_F_SSL_USE_RSAPRIVATEKEY_FILE, SSL_R_BAD_SSL_FILETYPE); + goto end; + } + if (rsa == NULL) { + SSLerr(SSL_F_SSL_USE_RSAPRIVATEKEY_FILE, j); + goto end; + } + ret = SSL_use_RSAPrivateKey(ssl, rsa); + RSA_free(rsa); + end: + if (in != NULL) + BIO_free(in); + return (ret); +} +# endif + +int SSL_use_RSAPrivateKey_ASN1(SSL *ssl, unsigned char *d, long len) +{ + int ret; + const unsigned char *p; + RSA *rsa; + + p = d; + if ((rsa = d2i_RSAPrivateKey(NULL, &p, (long)len)) == NULL) { + SSLerr(SSL_F_SSL_USE_RSAPRIVATEKEY_ASN1, ERR_R_ASN1_LIB); + return (0); + } + + ret = SSL_use_RSAPrivateKey(ssl, rsa); + RSA_free(rsa); + return (ret); +} +#endif /* !OPENSSL_NO_RSA */ + +int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey) +{ + int ret; + + if (pkey == NULL) { + SSLerr(SSL_F_SSL_USE_PRIVATEKEY, ERR_R_PASSED_NULL_PARAMETER); + return (0); + } + if (!ssl_cert_inst(&ssl->cert)) { + SSLerr(SSL_F_SSL_USE_PRIVATEKEY, ERR_R_MALLOC_FAILURE); + return (0); + } + ret = ssl_set_pkey(ssl->cert, pkey); + return (ret); +} + +#ifndef OPENSSL_NO_STDIO +int SSL_use_PrivateKey_file(SSL *ssl, const char *file, int type) +{ + int j, ret = 0; + BIO *in; + EVP_PKEY *pkey = NULL; + + in = BIO_new(BIO_s_file_internal()); + if (in == NULL) { + SSLerr(SSL_F_SSL_USE_PRIVATEKEY_FILE, ERR_R_BUF_LIB); + goto end; + } + + if (BIO_read_filename(in, file) <= 0) { + SSLerr(SSL_F_SSL_USE_PRIVATEKEY_FILE, ERR_R_SYS_LIB); + goto end; + } + if (type == SSL_FILETYPE_PEM) { + j = ERR_R_PEM_LIB; + pkey = PEM_read_bio_PrivateKey(in, NULL, + ssl->ctx->default_passwd_callback, + ssl-> + ctx->default_passwd_callback_userdata); + } else if (type == SSL_FILETYPE_ASN1) { + j = ERR_R_ASN1_LIB; + pkey = d2i_PrivateKey_bio(in, NULL); + } else { + SSLerr(SSL_F_SSL_USE_PRIVATEKEY_FILE, SSL_R_BAD_SSL_FILETYPE); + goto end; + } + if (pkey == NULL) { + SSLerr(SSL_F_SSL_USE_PRIVATEKEY_FILE, j); + goto end; + } + ret = SSL_use_PrivateKey(ssl, pkey); + EVP_PKEY_free(pkey); + end: + if (in != NULL) + BIO_free(in); + return (ret); +} +#endif + +int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, const unsigned char *d, + long len) +{ + int ret; + const unsigned char *p; + EVP_PKEY *pkey; + + p = d; + if ((pkey = d2i_PrivateKey(type, NULL, &p, (long)len)) == NULL) { + SSLerr(SSL_F_SSL_USE_PRIVATEKEY_ASN1, ERR_R_ASN1_LIB); + return (0); + } + + ret = SSL_use_PrivateKey(ssl, pkey); + EVP_PKEY_free(pkey); + return (ret); +} + +int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) +{ + if (x == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE, ERR_R_PASSED_NULL_PARAMETER); + return (0); + } + if (!ssl_cert_inst(&ctx->cert)) { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE, ERR_R_MALLOC_FAILURE); + return (0); + } + return (ssl_set_cert(ctx->cert, x)); +} + +static int ssl_set_cert(CERT *c, X509 *x) +{ + EVP_PKEY *pkey; + int i; + + pkey = X509_get_pubkey(x); + if (pkey == NULL) { + SSLerr(SSL_F_SSL_SET_CERT, SSL_R_X509_LIB); + return (0); + } + + i = ssl_cert_type(x, pkey); + if (i < 0) { + SSLerr(SSL_F_SSL_SET_CERT, SSL_R_UNKNOWN_CERTIFICATE_TYPE); + EVP_PKEY_free(pkey); + return (0); + } + + if (c->pkeys[i].privatekey != NULL) { + /* + * The return code from EVP_PKEY_copy_parameters is deliberately + * ignored. Some EVP_PKEY types cannot do this. + */ + EVP_PKEY_copy_parameters(pkey, c->pkeys[i].privatekey); + ERR_clear_error(); + +#ifndef OPENSSL_NO_RSA + /* + * Don't check the public/private key, this is mostly for smart + * cards. + */ + if ((c->pkeys[i].privatekey->type == EVP_PKEY_RSA) && + (RSA_flags(c->pkeys[i].privatekey->pkey.rsa) & + RSA_METHOD_FLAG_NO_CHECK)) ; + else +#endif /* OPENSSL_NO_RSA */ + if (!X509_check_private_key(x, c->pkeys[i].privatekey)) { + /* + * don't fail for a cert/key mismatch, just free current private + * key (when switching to a different cert & key, first this + * function should be used, then ssl_set_pkey + */ + EVP_PKEY_free(c->pkeys[i].privatekey); + c->pkeys[i].privatekey = NULL; + /* clear error queue */ + ERR_clear_error(); + } + } + + EVP_PKEY_free(pkey); + + if (c->pkeys[i].x509 != NULL) + X509_free(c->pkeys[i].x509); + CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509); + c->pkeys[i].x509 = x; + c->key = &(c->pkeys[i]); + + c->valid = 0; + return (1); +} + +#ifndef OPENSSL_NO_STDIO +int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type) +{ + int j; + BIO *in; + int ret = 0; + X509 *x = NULL; + + in = BIO_new(BIO_s_file_internal()); + if (in == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_BUF_LIB); + goto end; + } + + if (BIO_read_filename(in, file) <= 0) { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_SYS_LIB); + goto end; + } + if (type == SSL_FILETYPE_ASN1) { + j = ERR_R_ASN1_LIB; + x = d2i_X509_bio(in, NULL); + } else if (type == SSL_FILETYPE_PEM) { + j = ERR_R_PEM_LIB; + x = PEM_read_bio_X509(in, NULL, ctx->default_passwd_callback, + ctx->default_passwd_callback_userdata); + } else { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, SSL_R_BAD_SSL_FILETYPE); + goto end; + } + + if (x == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, j); + goto end; + } + + ret = SSL_CTX_use_certificate(ctx, x); + end: + if (x != NULL) + X509_free(x); + if (in != NULL) + BIO_free(in); + return (ret); +} +#endif + +int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, + const unsigned char *d) +{ + X509 *x; + int ret; + + x = d2i_X509(NULL, &d, (long)len); + if (x == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_ASN1, ERR_R_ASN1_LIB); + return (0); + } + + ret = SSL_CTX_use_certificate(ctx, x); + X509_free(x); + return (ret); +} + +#ifndef OPENSSL_NO_RSA +int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa) +{ + int ret; + EVP_PKEY *pkey; + + if (rsa == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_RSAPRIVATEKEY, ERR_R_PASSED_NULL_PARAMETER); + return (0); + } + if (!ssl_cert_inst(&ctx->cert)) { + SSLerr(SSL_F_SSL_CTX_USE_RSAPRIVATEKEY, ERR_R_MALLOC_FAILURE); + return (0); + } + if ((pkey = EVP_PKEY_new()) == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_RSAPRIVATEKEY, ERR_R_EVP_LIB); + return (0); + } + + RSA_up_ref(rsa); + if (EVP_PKEY_assign_RSA(pkey, rsa) <= 0) { + RSA_free(rsa); + return 0; + } + + ret = ssl_set_pkey(ctx->cert, pkey); + EVP_PKEY_free(pkey); + return (ret); +} + +# ifndef OPENSSL_NO_STDIO +int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, const char *file, int type) +{ + int j, ret = 0; + BIO *in; + RSA *rsa = NULL; + + in = BIO_new(BIO_s_file_internal()); + if (in == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_FILE, ERR_R_BUF_LIB); + goto end; + } + + if (BIO_read_filename(in, file) <= 0) { + SSLerr(SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_FILE, ERR_R_SYS_LIB); + goto end; + } + if (type == SSL_FILETYPE_ASN1) { + j = ERR_R_ASN1_LIB; + rsa = d2i_RSAPrivateKey_bio(in, NULL); + } else if (type == SSL_FILETYPE_PEM) { + j = ERR_R_PEM_LIB; + rsa = PEM_read_bio_RSAPrivateKey(in, NULL, + ctx->default_passwd_callback, + ctx->default_passwd_callback_userdata); + } else { + SSLerr(SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_FILE, SSL_R_BAD_SSL_FILETYPE); + goto end; + } + if (rsa == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_FILE, j); + goto end; + } + ret = SSL_CTX_use_RSAPrivateKey(ctx, rsa); + RSA_free(rsa); + end: + if (in != NULL) + BIO_free(in); + return (ret); +} +# endif + +int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const unsigned char *d, + long len) +{ + int ret; + const unsigned char *p; + RSA *rsa; + + p = d; + if ((rsa = d2i_RSAPrivateKey(NULL, &p, (long)len)) == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_ASN1, ERR_R_ASN1_LIB); + return (0); + } + + ret = SSL_CTX_use_RSAPrivateKey(ctx, rsa); + RSA_free(rsa); + return (ret); +} +#endif /* !OPENSSL_NO_RSA */ + +int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey) +{ + if (pkey == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY, ERR_R_PASSED_NULL_PARAMETER); + return (0); + } + if (!ssl_cert_inst(&ctx->cert)) { + SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY, ERR_R_MALLOC_FAILURE); + return (0); + } + return (ssl_set_pkey(ctx->cert, pkey)); +} + +#ifndef OPENSSL_NO_STDIO +int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type) +{ + int j, ret = 0; + BIO *in; + EVP_PKEY *pkey = NULL; + + in = BIO_new(BIO_s_file_internal()); + if (in == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE, ERR_R_BUF_LIB); + goto end; + } + + if (BIO_read_filename(in, file) <= 0) { + SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE, ERR_R_SYS_LIB); + goto end; + } + if (type == SSL_FILETYPE_PEM) { + j = ERR_R_PEM_LIB; + pkey = PEM_read_bio_PrivateKey(in, NULL, + ctx->default_passwd_callback, + ctx->default_passwd_callback_userdata); + } else if (type == SSL_FILETYPE_ASN1) { + j = ERR_R_ASN1_LIB; + pkey = d2i_PrivateKey_bio(in, NULL); + } else { + SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE, SSL_R_BAD_SSL_FILETYPE); + goto end; + } + if (pkey == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE, j); + goto end; + } + ret = SSL_CTX_use_PrivateKey(ctx, pkey); + EVP_PKEY_free(pkey); + end: + if (in != NULL) + BIO_free(in); + return (ret); +} +#endif + +int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx, + const unsigned char *d, long len) +{ + int ret; + const unsigned char *p; + EVP_PKEY *pkey; + + p = d; + if ((pkey = d2i_PrivateKey(type, NULL, &p, (long)len)) == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_ASN1, ERR_R_ASN1_LIB); + return (0); + } + + ret = SSL_CTX_use_PrivateKey(ctx, pkey); + EVP_PKEY_free(pkey); + return (ret); +} + +#ifndef OPENSSL_NO_STDIO +/* + * Read a file that contains our certificate in "PEM" format, possibly + * followed by a sequence of CA certificates that should be sent to the peer + * in the Certificate message. + */ +int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file) +{ + BIO *in; + int ret = 0; + X509 *x = NULL; + + ERR_clear_error(); /* clear error stack for + * SSL_CTX_use_certificate() */ + + in = BIO_new(BIO_s_file_internal()); + if (in == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE, ERR_R_BUF_LIB); + goto end; + } + + if (BIO_read_filename(in, file) <= 0) { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE, ERR_R_SYS_LIB); + goto end; + } + + x = PEM_read_bio_X509_AUX(in, NULL, ctx->default_passwd_callback, + ctx->default_passwd_callback_userdata); + if (x == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE, ERR_R_PEM_LIB); + goto end; + } + + ret = SSL_CTX_use_certificate(ctx, x); + + if (ERR_peek_error() != 0) + ret = 0; /* Key/certificate mismatch doesn't imply + * ret==0 ... */ + if (ret) { + /* + * If we could set up our certificate, now proceed to the CA + * certificates. + */ + X509 *ca; + int r; + unsigned long err; + + SSL_CTX_clear_chain_certs(ctx); + + while ((ca = PEM_read_bio_X509(in, NULL, + ctx->default_passwd_callback, + ctx->default_passwd_callback_userdata)) + != NULL) { + r = SSL_CTX_add0_chain_cert(ctx, ca); + if (!r) { + X509_free(ca); + ret = 0; + goto end; + } + /* + * Note that we must not free r if it was successfully added to + * the chain (while we must free the main certificate, since its + * reference count is increased by SSL_CTX_use_certificate). + */ + } + /* When the while loop ends, it's usually just EOF. */ + err = ERR_peek_last_error(); + if (ERR_GET_LIB(err) == ERR_LIB_PEM + && ERR_GET_REASON(err) == PEM_R_NO_START_LINE) + ERR_clear_error(); + else + ret = 0; /* some real error */ + } + + end: + if (x != NULL) + X509_free(x); + if (in != NULL) + BIO_free(in); + return (ret); +} +#endif + +#ifndef OPENSSL_NO_TLSEXT +static int serverinfo_find_extension(const unsigned char *serverinfo, + size_t serverinfo_length, + unsigned int extension_type, + const unsigned char **extension_data, + size_t *extension_length) +{ + *extension_data = NULL; + *extension_length = 0; + if (serverinfo == NULL || serverinfo_length == 0) + return -1; + for (;;) { + unsigned int type = 0; + size_t len = 0; + + /* end of serverinfo */ + if (serverinfo_length == 0) + return 0; /* Extension not found */ + + /* read 2-byte type field */ + if (serverinfo_length < 2) + return -1; /* Error */ + type = (serverinfo[0] << 8) + serverinfo[1]; + serverinfo += 2; + serverinfo_length -= 2; + + /* read 2-byte len field */ + if (serverinfo_length < 2) + return -1; /* Error */ + len = (serverinfo[0] << 8) + serverinfo[1]; + serverinfo += 2; + serverinfo_length -= 2; + + if (len > serverinfo_length) + return -1; /* Error */ + + if (type == extension_type) { + *extension_data = serverinfo; + *extension_length = len; + return 1; /* Success */ + } + + serverinfo += len; + serverinfo_length -= len; + } + return 0; /* Error */ +} + +static int serverinfo_srv_parse_cb(SSL *s, unsigned int ext_type, + const unsigned char *in, + size_t inlen, int *al, void *arg) +{ + + if (inlen != 0) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + return 1; +} + +static int serverinfo_srv_add_cb(SSL *s, unsigned int ext_type, + const unsigned char **out, size_t *outlen, + int *al, void *arg) +{ + const unsigned char *serverinfo = NULL; + size_t serverinfo_length = 0; + + /* Is there serverinfo data for the chosen server cert? */ + if ((ssl_get_server_cert_serverinfo(s, &serverinfo, + &serverinfo_length)) != 0) { + /* Find the relevant extension from the serverinfo */ + int retval = serverinfo_find_extension(serverinfo, serverinfo_length, + ext_type, out, outlen); + if (retval == -1) { + *al = SSL_AD_DECODE_ERROR; + return -1; /* Error */ + } + if (retval == 0) + return 0; /* No extension found, don't send extension */ + return 1; /* Send extension */ + } + return 0; /* No serverinfo data found, don't send + * extension */ +} + +/* + * With a NULL context, this function just checks that the serverinfo data + * parses correctly. With a non-NULL context, it registers callbacks for + * the included extensions. + */ +static int serverinfo_process_buffer(const unsigned char *serverinfo, + size_t serverinfo_length, SSL_CTX *ctx) +{ + if (serverinfo == NULL || serverinfo_length == 0) + return 0; + for (;;) { + unsigned int ext_type = 0; + size_t len = 0; + + /* end of serverinfo */ + if (serverinfo_length == 0) + return 1; + + /* read 2-byte type field */ + if (serverinfo_length < 2) + return 0; + /* FIXME: check for types we understand explicitly? */ + + /* Register callbacks for extensions */ + ext_type = (serverinfo[0] << 8) + serverinfo[1]; + if (ctx) { + int have_ext_cbs = 0; + size_t i; + custom_ext_methods *exts = &ctx->cert->srv_ext; + custom_ext_method *meth = exts->meths; + + for (i = 0; i < exts->meths_count; i++, meth++) { + if (ext_type == meth->ext_type) { + have_ext_cbs = 1; + break; + } + } + + if (!have_ext_cbs && !SSL_CTX_add_server_custom_ext(ctx, ext_type, + serverinfo_srv_add_cb, + NULL, NULL, + serverinfo_srv_parse_cb, + NULL)) + return 0; + } + + serverinfo += 2; + serverinfo_length -= 2; + + /* read 2-byte len field */ + if (serverinfo_length < 2) + return 0; + len = (serverinfo[0] << 8) + serverinfo[1]; + serverinfo += 2; + serverinfo_length -= 2; + + if (len > serverinfo_length) + return 0; + + serverinfo += len; + serverinfo_length -= len; + } +} + +int SSL_CTX_use_serverinfo(SSL_CTX *ctx, const unsigned char *serverinfo, + size_t serverinfo_length) +{ + if (ctx == NULL || serverinfo == NULL || serverinfo_length == 0) { + SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + if (!serverinfo_process_buffer(serverinfo, serverinfo_length, NULL)) { + SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO, SSL_R_INVALID_SERVERINFO_DATA); + return 0; + } + if (!ssl_cert_inst(&ctx->cert)) { + SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO, ERR_R_MALLOC_FAILURE); + return 0; + } + if (ctx->cert->key == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO, ERR_R_INTERNAL_ERROR); + return 0; + } + ctx->cert->key->serverinfo = OPENSSL_realloc(ctx->cert->key->serverinfo, + serverinfo_length); + if (ctx->cert->key->serverinfo == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO, ERR_R_MALLOC_FAILURE); + return 0; + } + memcpy(ctx->cert->key->serverinfo, serverinfo, serverinfo_length); + ctx->cert->key->serverinfo_length = serverinfo_length; + + /* + * Now that the serverinfo is validated and stored, go ahead and + * register callbacks. + */ + if (!serverinfo_process_buffer(serverinfo, serverinfo_length, ctx)) { + SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO, SSL_R_INVALID_SERVERINFO_DATA); + return 0; + } + return 1; +} + +# ifndef OPENSSL_NO_STDIO +int SSL_CTX_use_serverinfo_file(SSL_CTX *ctx, const char *file) +{ + unsigned char *serverinfo = NULL; + size_t serverinfo_length = 0; + unsigned char *extension = 0; + long extension_length = 0; + char *name = NULL; + char *header = NULL; + char namePrefix[] = "SERVERINFO FOR "; + int ret = 0; + BIO *bin = NULL; + size_t num_extensions = 0; + + if (ctx == NULL || file == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, + ERR_R_PASSED_NULL_PARAMETER); + goto end; + } + + bin = BIO_new(BIO_s_file_internal()); + if (bin == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, ERR_R_BUF_LIB); + goto end; + } + if (BIO_read_filename(bin, file) <= 0) { + SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, ERR_R_SYS_LIB); + goto end; + } + + for (num_extensions = 0;; num_extensions++) { + if (PEM_read_bio(bin, &name, &header, &extension, &extension_length) + == 0) { + /* + * There must be at least one extension in this file + */ + if (num_extensions == 0) { + SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, + SSL_R_NO_PEM_EXTENSIONS); + goto end; + } else /* End of file, we're done */ + break; + } + /* Check that PEM name starts with "BEGIN SERVERINFO FOR " */ + if (strlen(name) < strlen(namePrefix)) { + SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, + SSL_R_PEM_NAME_TOO_SHORT); + goto end; + } + if (strncmp(name, namePrefix, strlen(namePrefix)) != 0) { + SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, + SSL_R_PEM_NAME_BAD_PREFIX); + goto end; + } + /* + * Check that the decoded PEM data is plausible (valid length field) + */ + if (extension_length < 4 + || (extension[2] << 8) + extension[3] != extension_length - 4) { + SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, SSL_R_BAD_DATA); + goto end; + } + /* Append the decoded extension to the serverinfo buffer */ + serverinfo = + OPENSSL_realloc(serverinfo, serverinfo_length + extension_length); + if (serverinfo == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_SERVERINFO_FILE, ERR_R_MALLOC_FAILURE); + goto end; + } + memcpy(serverinfo + serverinfo_length, extension, extension_length); + serverinfo_length += extension_length; + + OPENSSL_free(name); + name = NULL; + OPENSSL_free(header); + header = NULL; + OPENSSL_free(extension); + extension = NULL; + } + + ret = SSL_CTX_use_serverinfo(ctx, serverinfo, serverinfo_length); + end: + /* SSL_CTX_use_serverinfo makes a local copy of the serverinfo. */ + OPENSSL_free(name); + OPENSSL_free(header); + OPENSSL_free(extension); + OPENSSL_free(serverinfo); + if (bin != NULL) + BIO_free(bin); + return ret; +} +# endif /* OPENSSL_NO_STDIO */ +#endif /* OPENSSL_NO_TLSEXT */ diff --git a/thirdparty/openssl/ssl/ssl_sess.c b/thirdparty/openssl/ssl/ssl_sess.c new file mode 100644 index 0000000000..b182998343 --- /dev/null +++ b/thirdparty/openssl/ssl/ssl_sess.c @@ -0,0 +1,1273 @@ +/* ssl/ssl_sess.c */ +/* 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-2006 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 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 <stdio.h> +#include <openssl/lhash.h> +#include <openssl/rand.h> +#ifndef OPENSSL_NO_ENGINE +# include <openssl/engine.h> +#endif +#include "ssl_locl.h" + +static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *s); +static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *s); +static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lck); + +SSL_SESSION *SSL_get_session(const SSL *ssl) +/* aka SSL_get0_session; gets 0 objects, just returns a copy of the pointer */ +{ + return (ssl->session); +} + +SSL_SESSION *SSL_get1_session(SSL *ssl) +/* variant of SSL_get_session: caller really gets something */ +{ + SSL_SESSION *sess; + /* + * Need to lock this all up rather than just use CRYPTO_add so that + * somebody doesn't free ssl->session between when we check it's non-null + * and when we up the reference count. + */ + CRYPTO_w_lock(CRYPTO_LOCK_SSL_SESSION); + sess = ssl->session; + if (sess) + sess->references++; + CRYPTO_w_unlock(CRYPTO_LOCK_SSL_SESSION); + return (sess); +} + +int SSL_SESSION_get_ex_new_index(long argl, void *argp, + CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func) +{ + return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL_SESSION, argl, argp, + new_func, dup_func, free_func); +} + +int SSL_SESSION_set_ex_data(SSL_SESSION *s, int idx, void *arg) +{ + return (CRYPTO_set_ex_data(&s->ex_data, idx, arg)); +} + +void *SSL_SESSION_get_ex_data(const SSL_SESSION *s, int idx) +{ + return (CRYPTO_get_ex_data(&s->ex_data, idx)); +} + +SSL_SESSION *SSL_SESSION_new(void) +{ + SSL_SESSION *ss; + + ss = (SSL_SESSION *)OPENSSL_malloc(sizeof(SSL_SESSION)); + if (ss == NULL) { + SSLerr(SSL_F_SSL_SESSION_NEW, ERR_R_MALLOC_FAILURE); + return (0); + } + memset(ss, 0, sizeof(SSL_SESSION)); + + ss->verify_result = 1; /* avoid 0 (= X509_V_OK) just in case */ + ss->references = 1; + ss->timeout = 60 * 5 + 4; /* 5 minute timeout by default */ + ss->time = (unsigned long)time(NULL); + ss->prev = NULL; + ss->next = NULL; + ss->compress_meth = 0; +#ifndef OPENSSL_NO_TLSEXT + ss->tlsext_hostname = NULL; +# ifndef OPENSSL_NO_EC + ss->tlsext_ecpointformatlist_length = 0; + ss->tlsext_ecpointformatlist = NULL; + ss->tlsext_ellipticcurvelist_length = 0; + ss->tlsext_ellipticcurvelist = NULL; +# endif +#endif + CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL_SESSION, ss, &ss->ex_data); +#ifndef OPENSSL_NO_PSK + ss->psk_identity_hint = NULL; + ss->psk_identity = NULL; +#endif +#ifndef OPENSSL_NO_SRP + ss->srp_username = NULL; +#endif + return (ss); +} + +/* + * Create a new SSL_SESSION and duplicate the contents of |src| into it. If + * ticket == 0 then no ticket information is duplicated, otherwise it is. + */ +SSL_SESSION *ssl_session_dup(SSL_SESSION *src, int ticket) +{ + SSL_SESSION *dest; + + dest = OPENSSL_malloc(sizeof(*src)); + if (dest == NULL) { + goto err; + } + memcpy(dest, src, sizeof(*dest)); + + /* + * Set the various pointers to NULL so that we can call SSL_SESSION_free in + * the case of an error whilst halfway through constructing dest + */ +#ifndef OPENSSL_NO_PSK + dest->psk_identity_hint = NULL; + dest->psk_identity = NULL; +#endif + dest->ciphers = NULL; +#ifndef OPENSSL_NO_TLSEXT + dest->tlsext_hostname = NULL; +# ifndef OPENSSL_NO_EC + dest->tlsext_ecpointformatlist = NULL; + dest->tlsext_ellipticcurvelist = NULL; +# endif + dest->tlsext_tick = NULL; +#endif +#ifndef OPENSSL_NO_SRP + dest->srp_username = NULL; +#endif + memset(&dest->ex_data, 0, sizeof(dest->ex_data)); + + /* We deliberately don't copy the prev and next pointers */ + dest->prev = NULL; + dest->next = NULL; + + dest->references = 1; + + if (src->sess_cert != NULL) + CRYPTO_add(&src->sess_cert->references, 1, CRYPTO_LOCK_SSL_SESS_CERT); + + if (src->peer != NULL) + CRYPTO_add(&src->peer->references, 1, CRYPTO_LOCK_X509); + +#ifndef OPENSSL_NO_PSK + if (src->psk_identity_hint) { + dest->psk_identity_hint = BUF_strdup(src->psk_identity_hint); + if (dest->psk_identity_hint == NULL) { + goto err; + } + } + if (src->psk_identity) { + dest->psk_identity = BUF_strdup(src->psk_identity); + if (dest->psk_identity == NULL) { + goto err; + } + } +#endif + + if(src->ciphers != NULL) { + dest->ciphers = sk_SSL_CIPHER_dup(src->ciphers); + if (dest->ciphers == NULL) + goto err; + } + + if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_SSL_SESSION, + &dest->ex_data, &src->ex_data)) { + goto err; + } + +#ifndef OPENSSL_NO_TLSEXT + if (src->tlsext_hostname) { + dest->tlsext_hostname = BUF_strdup(src->tlsext_hostname); + if (dest->tlsext_hostname == NULL) { + goto err; + } + } +# ifndef OPENSSL_NO_EC + if (src->tlsext_ecpointformatlist) { + dest->tlsext_ecpointformatlist = + BUF_memdup(src->tlsext_ecpointformatlist, + src->tlsext_ecpointformatlist_length); + if (dest->tlsext_ecpointformatlist == NULL) + goto err; + } + if (src->tlsext_ellipticcurvelist) { + dest->tlsext_ellipticcurvelist = + BUF_memdup(src->tlsext_ellipticcurvelist, + src->tlsext_ellipticcurvelist_length); + if (dest->tlsext_ellipticcurvelist == NULL) + goto err; + } +# endif + + if (ticket != 0) { + dest->tlsext_tick = BUF_memdup(src->tlsext_tick, src->tlsext_ticklen); + if(dest->tlsext_tick == NULL) + goto err; + } else { + dest->tlsext_tick_lifetime_hint = 0; + dest->tlsext_ticklen = 0; + } +#endif + +#ifndef OPENSSL_NO_SRP + if (src->srp_username) { + dest->srp_username = BUF_strdup(src->srp_username); + if (dest->srp_username == NULL) { + goto err; + } + } +#endif + + return dest; +err: + SSLerr(SSL_F_SSL_SESSION_DUP, ERR_R_MALLOC_FAILURE); + SSL_SESSION_free(dest); + return NULL; +} + +const unsigned char *SSL_SESSION_get_id(const SSL_SESSION *s, + unsigned int *len) +{ + if (len) + *len = s->session_id_length; + return s->session_id; +} + +unsigned int SSL_SESSION_get_compress_id(const SSL_SESSION *s) +{ + return s->compress_meth; +} + +/* + * Even with SSLv2, we have 16 bytes (128 bits) of session ID space. + * SSLv3/TLSv1 has 32 bytes (256 bits). As such, filling the ID with random + * gunk repeatedly until we have no conflict is going to complete in one + * iteration pretty much "most" of the time (btw: understatement). So, if it + * takes us 10 iterations and we still can't avoid a conflict - well that's a + * reasonable point to call it quits. Either the RAND code is broken or + * someone is trying to open roughly very close to 2^128 (or 2^256) SSL + * sessions to our server. How you might store that many sessions is perhaps + * a more interesting question ... + */ + +#define MAX_SESS_ID_ATTEMPTS 10 +static int def_generate_session_id(const SSL *ssl, unsigned char *id, + unsigned int *id_len) +{ + unsigned int retry = 0; + do + if (RAND_pseudo_bytes(id, *id_len) <= 0) + return 0; + while (SSL_has_matching_session_id(ssl, id, *id_len) && + (++retry < MAX_SESS_ID_ATTEMPTS)) ; + if (retry < MAX_SESS_ID_ATTEMPTS) + return 1; + /* else - woops a session_id match */ + /* + * XXX We should also check the external cache -- but the probability of + * a collision is negligible, and we could not prevent the concurrent + * creation of sessions with identical IDs since we currently don't have + * means to atomically check whether a session ID already exists and make + * a reservation for it if it does not (this problem applies to the + * internal cache as well). + */ + return 0; +} + +int ssl_get_new_session(SSL *s, int session) +{ + /* This gets used by clients and servers. */ + + unsigned int tmp; + SSL_SESSION *ss = NULL; + GEN_SESSION_CB cb = def_generate_session_id; + + if ((ss = SSL_SESSION_new()) == NULL) + return (0); + + /* If the context has a default timeout, use it */ + if (s->session_ctx->session_timeout == 0) + ss->timeout = SSL_get_default_timeout(s); + else + ss->timeout = s->session_ctx->session_timeout; + + if (s->session != NULL) { + SSL_SESSION_free(s->session); + s->session = NULL; + } + + if (session) { + if (s->version == SSL2_VERSION) { + ss->ssl_version = SSL2_VERSION; + ss->session_id_length = SSL2_SSL_SESSION_ID_LENGTH; + } else if (s->version == SSL3_VERSION) { + ss->ssl_version = SSL3_VERSION; + ss->session_id_length = SSL3_SSL_SESSION_ID_LENGTH; + } else if (s->version == TLS1_VERSION) { + ss->ssl_version = TLS1_VERSION; + ss->session_id_length = SSL3_SSL_SESSION_ID_LENGTH; + } else if (s->version == TLS1_1_VERSION) { + ss->ssl_version = TLS1_1_VERSION; + ss->session_id_length = SSL3_SSL_SESSION_ID_LENGTH; + } else if (s->version == TLS1_2_VERSION) { + ss->ssl_version = TLS1_2_VERSION; + ss->session_id_length = SSL3_SSL_SESSION_ID_LENGTH; + } else if (s->version == DTLS1_BAD_VER) { + ss->ssl_version = DTLS1_BAD_VER; + ss->session_id_length = SSL3_SSL_SESSION_ID_LENGTH; + } else if (s->version == DTLS1_VERSION) { + ss->ssl_version = DTLS1_VERSION; + ss->session_id_length = SSL3_SSL_SESSION_ID_LENGTH; + } else if (s->version == DTLS1_2_VERSION) { + ss->ssl_version = DTLS1_2_VERSION; + ss->session_id_length = SSL3_SSL_SESSION_ID_LENGTH; + } else { + SSLerr(SSL_F_SSL_GET_NEW_SESSION, SSL_R_UNSUPPORTED_SSL_VERSION); + SSL_SESSION_free(ss); + return (0); + } +#ifndef OPENSSL_NO_TLSEXT + /*- + * If RFC5077 ticket, use empty session ID (as server). + * Note that: + * (a) ssl_get_prev_session() does lookahead into the + * ClientHello extensions to find the session ticket. + * When ssl_get_prev_session() fails, s3_srvr.c calls + * ssl_get_new_session() in ssl3_get_client_hello(). + * At that point, it has not yet parsed the extensions, + * however, because of the lookahead, it already knows + * whether a ticket is expected or not. + * + * (b) s3_clnt.c calls ssl_get_new_session() before parsing + * ServerHello extensions, and before recording the session + * ID received from the server, so this block is a noop. + */ + if (s->tlsext_ticket_expected) { + ss->session_id_length = 0; + goto sess_id_done; + } +#endif + /* Choose which callback will set the session ID */ + CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX); + if (s->generate_session_id) + cb = s->generate_session_id; + else if (s->session_ctx->generate_session_id) + cb = s->session_ctx->generate_session_id; + CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); + /* Choose a session ID */ + tmp = ss->session_id_length; + if (!cb(s, ss->session_id, &tmp)) { + /* The callback failed */ + SSLerr(SSL_F_SSL_GET_NEW_SESSION, + SSL_R_SSL_SESSION_ID_CALLBACK_FAILED); + SSL_SESSION_free(ss); + return (0); + } + /* + * Don't allow the callback to set the session length to zero. nor + * set it higher than it was. + */ + if (!tmp || (tmp > ss->session_id_length)) { + /* The callback set an illegal length */ + SSLerr(SSL_F_SSL_GET_NEW_SESSION, + SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH); + SSL_SESSION_free(ss); + return (0); + } + /* If the session length was shrunk and we're SSLv2, pad it */ + if ((tmp < ss->session_id_length) && (s->version == SSL2_VERSION)) + memset(ss->session_id + tmp, 0, ss->session_id_length - tmp); + else + ss->session_id_length = tmp; + /* Finally, check for a conflict */ + if (SSL_has_matching_session_id(s, ss->session_id, + ss->session_id_length)) { + SSLerr(SSL_F_SSL_GET_NEW_SESSION, SSL_R_SSL_SESSION_ID_CONFLICT); + SSL_SESSION_free(ss); + return (0); + } +#ifndef OPENSSL_NO_TLSEXT + sess_id_done: + if (s->tlsext_hostname) { + ss->tlsext_hostname = BUF_strdup(s->tlsext_hostname); + if (ss->tlsext_hostname == NULL) { + SSLerr(SSL_F_SSL_GET_NEW_SESSION, ERR_R_INTERNAL_ERROR); + SSL_SESSION_free(ss); + return 0; + } + } +#endif + } else { + ss->session_id_length = 0; + } + + if (s->sid_ctx_length > sizeof ss->sid_ctx) { + SSLerr(SSL_F_SSL_GET_NEW_SESSION, ERR_R_INTERNAL_ERROR); + SSL_SESSION_free(ss); + return 0; + } + memcpy(ss->sid_ctx, s->sid_ctx, s->sid_ctx_length); + ss->sid_ctx_length = s->sid_ctx_length; + s->session = ss; + ss->ssl_version = s->version; + ss->verify_result = X509_V_OK; + + return (1); +} + +/*- + * ssl_get_prev attempts to find an SSL_SESSION to be used to resume this + * connection. It is only called by servers. + * + * session_id: points at the session ID in the ClientHello. This code will + * read past the end of this in order to parse out the session ticket + * extension, if any. + * len: the length of the session ID. + * limit: a pointer to the first byte after the ClientHello. + * + * Returns: + * -1: error + * 0: a session may have been found. + * + * Side effects: + * - If a session is found then s->session is pointed at it (after freeing an + * existing session if need be) and s->verify_result is set from the session. + * - Both for new and resumed sessions, s->tlsext_ticket_expected is set to 1 + * if the server should issue a new session ticket (to 0 otherwise). + */ +int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len, + const unsigned char *limit) +{ + /* This is used only by servers. */ + + SSL_SESSION *ret = NULL; + int fatal = 0; + int try_session_cache = 1; +#ifndef OPENSSL_NO_TLSEXT + int r; +#endif + + if (session_id + len > limit) { + fatal = 1; + goto err; + } + + if (len == 0) + try_session_cache = 0; + +#ifndef OPENSSL_NO_TLSEXT + /* sets s->tlsext_ticket_expected */ + r = tls1_process_ticket(s, session_id, len, limit, &ret); + switch (r) { + case -1: /* Error during processing */ + fatal = 1; + goto err; + case 0: /* No ticket found */ + case 1: /* Zero length ticket found */ + break; /* Ok to carry on processing session id. */ + case 2: /* Ticket found but not decrypted. */ + case 3: /* Ticket decrypted, *ret has been set. */ + try_session_cache = 0; + break; + default: + abort(); + } +#endif + + if (try_session_cache && + ret == NULL && + !(s->session_ctx->session_cache_mode & + SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)) { + SSL_SESSION data; + data.ssl_version = s->version; + data.session_id_length = len; + if (len == 0) + return 0; + memcpy(data.session_id, session_id, len); + CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX); + ret = lh_SSL_SESSION_retrieve(s->session_ctx->sessions, &data); + if (ret != NULL) { + /* don't allow other threads to steal it: */ + CRYPTO_add(&ret->references, 1, CRYPTO_LOCK_SSL_SESSION); + } + CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); + if (ret == NULL) + s->session_ctx->stats.sess_miss++; + } + + if (try_session_cache && + ret == NULL && s->session_ctx->get_session_cb != NULL) { + int copy = 1; + + if ((ret = s->session_ctx->get_session_cb(s, session_id, len, ©))) { + s->session_ctx->stats.sess_cb_hit++; + + /* + * Increment reference count now if the session callback asks us + * to do so (note that if the session structures returned by the + * callback are shared between threads, it must handle the + * reference count itself [i.e. copy == 0], or things won't be + * thread-safe). + */ + if (copy) + CRYPTO_add(&ret->references, 1, CRYPTO_LOCK_SSL_SESSION); + + /* + * Add the externally cached session to the internal cache as + * well if and only if we are supposed to. + */ + if (! + (s->session_ctx->session_cache_mode & + SSL_SESS_CACHE_NO_INTERNAL_STORE)) + /* + * The following should not return 1, otherwise, things are + * very strange + */ + SSL_CTX_add_session(s->session_ctx, ret); + } + } + + if (ret == NULL) + goto err; + + /* Now ret is non-NULL and we own one of its reference counts. */ + + if (ret->sid_ctx_length != s->sid_ctx_length + || memcmp(ret->sid_ctx, s->sid_ctx, ret->sid_ctx_length)) { + /* + * We have the session requested by the client, but we don't want to + * use it in this context. + */ + goto err; /* treat like cache miss */ + } + + if ((s->verify_mode & SSL_VERIFY_PEER) && s->sid_ctx_length == 0) { + /* + * We can't be sure if this session is being used out of context, + * which is especially important for SSL_VERIFY_PEER. The application + * should have used SSL[_CTX]_set_session_id_context. For this error + * case, we generate an error instead of treating the event like a + * cache miss (otherwise it would be easy for applications to + * effectively disable the session cache by accident without anyone + * noticing). + */ + + SSLerr(SSL_F_SSL_GET_PREV_SESSION, + SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED); + fatal = 1; + goto err; + } + + if (ret->cipher == NULL) { + unsigned char buf[5], *p; + unsigned long l; + + p = buf; + l = ret->cipher_id; + l2n(l, p); + if ((ret->ssl_version >> 8) >= SSL3_VERSION_MAJOR) + ret->cipher = ssl_get_cipher_by_char(s, &(buf[2])); + else + ret->cipher = ssl_get_cipher_by_char(s, &(buf[1])); + if (ret->cipher == NULL) + goto err; + } + + if (ret->timeout < (long)(time(NULL) - ret->time)) { /* timeout */ + s->session_ctx->stats.sess_timeout++; + if (try_session_cache) { + /* session was from the cache, so remove it */ + SSL_CTX_remove_session(s->session_ctx, ret); + } + goto err; + } + + s->session_ctx->stats.sess_hit++; + + if (s->session != NULL) + SSL_SESSION_free(s->session); + s->session = ret; + s->verify_result = s->session->verify_result; + return 1; + + err: + if (ret != NULL) { + SSL_SESSION_free(ret); +#ifndef OPENSSL_NO_TLSEXT + if (!try_session_cache) { + /* + * The session was from a ticket, so we should issue a ticket for + * the new session + */ + s->tlsext_ticket_expected = 1; + } +#endif + } + if (fatal) + return -1; + else + return 0; +} + +int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *c) +{ + int ret = 0; + SSL_SESSION *s; + + /* + * add just 1 reference count for the SSL_CTX's session cache even though + * it has two ways of access: each session is in a doubly linked list and + * an lhash + */ + CRYPTO_add(&c->references, 1, CRYPTO_LOCK_SSL_SESSION); + /* + * if session c is in already in cache, we take back the increment later + */ + + CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); + s = lh_SSL_SESSION_insert(ctx->sessions, c); + + /* + * s != NULL iff we already had a session with the given PID. In this + * case, s == c should hold (then we did not really modify + * ctx->sessions), or we're in trouble. + */ + if (s != NULL && s != c) { + /* We *are* in trouble ... */ + SSL_SESSION_list_remove(ctx, s); + SSL_SESSION_free(s); + /* + * ... so pretend the other session did not exist in cache (we cannot + * handle two SSL_SESSION structures with identical session ID in the + * same cache, which could happen e.g. when two threads concurrently + * obtain the same session from an external cache) + */ + s = NULL; + } + + /* Put at the head of the queue unless it is already in the cache */ + if (s == NULL) + SSL_SESSION_list_add(ctx, c); + + if (s != NULL) { + /* + * existing cache entry -- decrement previously incremented reference + * count because it already takes into account the cache + */ + + SSL_SESSION_free(s); /* s == c */ + ret = 0; + } else { + /* + * new cache entry -- remove old ones if cache has become too large + */ + + ret = 1; + + if (SSL_CTX_sess_get_cache_size(ctx) > 0) { + while (SSL_CTX_sess_number(ctx) > + SSL_CTX_sess_get_cache_size(ctx)) { + if (!remove_session_lock(ctx, ctx->session_cache_tail, 0)) + break; + else + ctx->stats.sess_cache_full++; + } + } + } + CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); + return (ret); +} + +int SSL_CTX_remove_session(SSL_CTX *ctx, SSL_SESSION *c) +{ + return remove_session_lock(ctx, c, 1); +} + +static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lck) +{ + SSL_SESSION *r; + int ret = 0; + + if ((c != NULL) && (c->session_id_length != 0)) { + if (lck) + CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); + if ((r = lh_SSL_SESSION_retrieve(ctx->sessions, c)) == c) { + ret = 1; + r = lh_SSL_SESSION_delete(ctx->sessions, c); + SSL_SESSION_list_remove(ctx, c); + } + + if (lck) + CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); + + if (ret) { + r->not_resumable = 1; + if (ctx->remove_session_cb != NULL) + ctx->remove_session_cb(ctx, r); + SSL_SESSION_free(r); + } + } else + ret = 0; + return (ret); +} + +void SSL_SESSION_free(SSL_SESSION *ss) +{ + int i; + + if (ss == NULL) + return; + + i = CRYPTO_add(&ss->references, -1, CRYPTO_LOCK_SSL_SESSION); +#ifdef REF_PRINT + REF_PRINT("SSL_SESSION", ss); +#endif + if (i > 0) + return; +#ifdef REF_CHECK + if (i < 0) { + fprintf(stderr, "SSL_SESSION_free, bad reference count\n"); + abort(); /* ok */ + } +#endif + + CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL_SESSION, ss, &ss->ex_data); + + OPENSSL_cleanse(ss->key_arg, sizeof ss->key_arg); + OPENSSL_cleanse(ss->master_key, sizeof ss->master_key); + OPENSSL_cleanse(ss->session_id, sizeof ss->session_id); + if (ss->sess_cert != NULL) + ssl_sess_cert_free(ss->sess_cert); + if (ss->peer != NULL) + X509_free(ss->peer); + if (ss->ciphers != NULL) + sk_SSL_CIPHER_free(ss->ciphers); +#ifndef OPENSSL_NO_TLSEXT + if (ss->tlsext_hostname != NULL) + OPENSSL_free(ss->tlsext_hostname); + if (ss->tlsext_tick != NULL) + OPENSSL_free(ss->tlsext_tick); +# ifndef OPENSSL_NO_EC + ss->tlsext_ecpointformatlist_length = 0; + if (ss->tlsext_ecpointformatlist != NULL) + OPENSSL_free(ss->tlsext_ecpointformatlist); + ss->tlsext_ellipticcurvelist_length = 0; + if (ss->tlsext_ellipticcurvelist != NULL) + OPENSSL_free(ss->tlsext_ellipticcurvelist); +# endif /* OPENSSL_NO_EC */ +#endif +#ifndef OPENSSL_NO_PSK + if (ss->psk_identity_hint != NULL) + OPENSSL_free(ss->psk_identity_hint); + if (ss->psk_identity != NULL) + OPENSSL_free(ss->psk_identity); +#endif +#ifndef OPENSSL_NO_SRP + if (ss->srp_username != NULL) + OPENSSL_free(ss->srp_username); +#endif + OPENSSL_cleanse(ss, sizeof(*ss)); + OPENSSL_free(ss); +} + +int SSL_set_session(SSL *s, SSL_SESSION *session) +{ + int ret = 0; + const SSL_METHOD *meth; + + if (session != NULL) { + meth = s->ctx->method->get_ssl_method(session->ssl_version); + if (meth == NULL) + meth = s->method->get_ssl_method(session->ssl_version); + if (meth == NULL) { + SSLerr(SSL_F_SSL_SET_SESSION, SSL_R_UNABLE_TO_FIND_SSL_METHOD); + return (0); + } + + if (meth != s->method) { + if (!SSL_set_ssl_method(s, meth)) + return (0); + } +#ifndef OPENSSL_NO_KRB5 + if (s->kssl_ctx && !s->kssl_ctx->client_princ && + session->krb5_client_princ_len > 0) { + s->kssl_ctx->client_princ = + (char *)OPENSSL_malloc(session->krb5_client_princ_len + 1); + memcpy(s->kssl_ctx->client_princ, session->krb5_client_princ, + session->krb5_client_princ_len); + s->kssl_ctx->client_princ[session->krb5_client_princ_len] = '\0'; + } +#endif /* OPENSSL_NO_KRB5 */ + + /* CRYPTO_w_lock(CRYPTO_LOCK_SSL); */ + CRYPTO_add(&session->references, 1, CRYPTO_LOCK_SSL_SESSION); + if (s->session != NULL) + SSL_SESSION_free(s->session); + s->session = session; + s->verify_result = s->session->verify_result; + /* CRYPTO_w_unlock(CRYPTO_LOCK_SSL); */ + ret = 1; + } else { + if (s->session != NULL) { + SSL_SESSION_free(s->session); + s->session = NULL; + } + + meth = s->ctx->method; + if (meth != s->method) { + if (!SSL_set_ssl_method(s, meth)) + return (0); + } + ret = 1; + } + return (ret); +} + +long SSL_SESSION_set_timeout(SSL_SESSION *s, long t) +{ + if (s == NULL) + return (0); + s->timeout = t; + return (1); +} + +long SSL_SESSION_get_timeout(const SSL_SESSION *s) +{ + if (s == NULL) + return (0); + return (s->timeout); +} + +long SSL_SESSION_get_time(const SSL_SESSION *s) +{ + if (s == NULL) + return (0); + return (s->time); +} + +long SSL_SESSION_set_time(SSL_SESSION *s, long t) +{ + if (s == NULL) + return (0); + s->time = t; + return (t); +} + +X509 *SSL_SESSION_get0_peer(SSL_SESSION *s) +{ + return s->peer; +} + +int SSL_SESSION_set1_id_context(SSL_SESSION *s, const unsigned char *sid_ctx, + unsigned int sid_ctx_len) +{ + if (sid_ctx_len > SSL_MAX_SID_CTX_LENGTH) { + SSLerr(SSL_F_SSL_SESSION_SET1_ID_CONTEXT, + SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG); + return 0; + } + s->sid_ctx_length = sid_ctx_len; + memcpy(s->sid_ctx, sid_ctx, sid_ctx_len); + + return 1; +} + +long SSL_CTX_set_timeout(SSL_CTX *s, long t) +{ + long l; + if (s == NULL) + return (0); + l = s->session_timeout; + s->session_timeout = t; + return (l); +} + +long SSL_CTX_get_timeout(const SSL_CTX *s) +{ + if (s == NULL) + return (0); + return (s->session_timeout); +} + +#ifndef OPENSSL_NO_TLSEXT +int SSL_set_session_secret_cb(SSL *s, + int (*tls_session_secret_cb) (SSL *s, + void *secret, + int *secret_len, + STACK_OF(SSL_CIPHER) + *peer_ciphers, + SSL_CIPHER + **cipher, + void *arg), + void *arg) +{ + if (s == NULL) + return (0); + s->tls_session_secret_cb = tls_session_secret_cb; + s->tls_session_secret_cb_arg = arg; + return (1); +} + +int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb, + void *arg) +{ + if (s == NULL) + return (0); + s->tls_session_ticket_ext_cb = cb; + s->tls_session_ticket_ext_cb_arg = arg; + return (1); +} + +int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len) +{ + if (s->version >= TLS1_VERSION) { + if (s->tlsext_session_ticket) { + OPENSSL_free(s->tlsext_session_ticket); + s->tlsext_session_ticket = NULL; + } + + s->tlsext_session_ticket = + OPENSSL_malloc(sizeof(TLS_SESSION_TICKET_EXT) + ext_len); + if (!s->tlsext_session_ticket) { + SSLerr(SSL_F_SSL_SET_SESSION_TICKET_EXT, ERR_R_MALLOC_FAILURE); + return 0; + } + + if (ext_data) { + s->tlsext_session_ticket->length = ext_len; + s->tlsext_session_ticket->data = s->tlsext_session_ticket + 1; + memcpy(s->tlsext_session_ticket->data, ext_data, ext_len); + } else { + s->tlsext_session_ticket->length = 0; + s->tlsext_session_ticket->data = NULL; + } + + return 1; + } + + return 0; +} +#endif /* OPENSSL_NO_TLSEXT */ + +typedef struct timeout_param_st { + SSL_CTX *ctx; + long time; + LHASH_OF(SSL_SESSION) *cache; +} TIMEOUT_PARAM; + +static void timeout_doall_arg(SSL_SESSION *s, TIMEOUT_PARAM *p) +{ + if ((p->time == 0) || (p->time > (s->time + s->timeout))) { /* timeout */ + /* + * The reason we don't call SSL_CTX_remove_session() is to save on + * locking overhead + */ + (void)lh_SSL_SESSION_delete(p->cache, s); + SSL_SESSION_list_remove(p->ctx, s); + s->not_resumable = 1; + if (p->ctx->remove_session_cb != NULL) + p->ctx->remove_session_cb(p->ctx, s); + SSL_SESSION_free(s); + } +} + +static IMPLEMENT_LHASH_DOALL_ARG_FN(timeout, SSL_SESSION, TIMEOUT_PARAM) + +void SSL_CTX_flush_sessions(SSL_CTX *s, long t) +{ + unsigned long i; + TIMEOUT_PARAM tp; + + tp.ctx = s; + tp.cache = s->sessions; + if (tp.cache == NULL) + return; + tp.time = t; + CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); + i = CHECKED_LHASH_OF(SSL_SESSION, tp.cache)->down_load; + CHECKED_LHASH_OF(SSL_SESSION, tp.cache)->down_load = 0; + lh_SSL_SESSION_doall_arg(tp.cache, LHASH_DOALL_ARG_FN(timeout), + TIMEOUT_PARAM, &tp); + CHECKED_LHASH_OF(SSL_SESSION, tp.cache)->down_load = i; + CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); +} + +int ssl_clear_bad_session(SSL *s) +{ + if ((s->session != NULL) && + !(s->shutdown & SSL_SENT_SHUTDOWN) && + !(SSL_in_init(s) || SSL_in_before(s))) { + SSL_CTX_remove_session(s->ctx, s->session); + return (1); + } else + return (0); +} + +/* locked by SSL_CTX in the calling function */ +static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *s) +{ + if ((s->next == NULL) || (s->prev == NULL)) + return; + + if (s->next == (SSL_SESSION *)&(ctx->session_cache_tail)) { + /* last element in list */ + if (s->prev == (SSL_SESSION *)&(ctx->session_cache_head)) { + /* only one element in list */ + ctx->session_cache_head = NULL; + ctx->session_cache_tail = NULL; + } else { + ctx->session_cache_tail = s->prev; + s->prev->next = (SSL_SESSION *)&(ctx->session_cache_tail); + } + } else { + if (s->prev == (SSL_SESSION *)&(ctx->session_cache_head)) { + /* first element in list */ + ctx->session_cache_head = s->next; + s->next->prev = (SSL_SESSION *)&(ctx->session_cache_head); + } else { + /* middle of list */ + s->next->prev = s->prev; + s->prev->next = s->next; + } + } + s->prev = s->next = NULL; +} + +static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *s) +{ + if ((s->next != NULL) && (s->prev != NULL)) + SSL_SESSION_list_remove(ctx, s); + + if (ctx->session_cache_head == NULL) { + ctx->session_cache_head = s; + ctx->session_cache_tail = s; + s->prev = (SSL_SESSION *)&(ctx->session_cache_head); + s->next = (SSL_SESSION *)&(ctx->session_cache_tail); + } else { + s->next = ctx->session_cache_head; + s->next->prev = s; + s->prev = (SSL_SESSION *)&(ctx->session_cache_head); + ctx->session_cache_head = s; + } +} + +void SSL_CTX_sess_set_new_cb(SSL_CTX *ctx, + int (*cb) (struct ssl_st *ssl, + SSL_SESSION *sess)) +{ + ctx->new_session_cb = cb; +} + +int (*SSL_CTX_sess_get_new_cb(SSL_CTX *ctx)) (SSL *ssl, SSL_SESSION *sess) { + return ctx->new_session_cb; +} + +void SSL_CTX_sess_set_remove_cb(SSL_CTX *ctx, + void (*cb) (SSL_CTX *ctx, SSL_SESSION *sess)) +{ + ctx->remove_session_cb = cb; +} + +void (*SSL_CTX_sess_get_remove_cb(SSL_CTX *ctx)) (SSL_CTX *ctx, + SSL_SESSION *sess) { + return ctx->remove_session_cb; +} + +void SSL_CTX_sess_set_get_cb(SSL_CTX *ctx, + SSL_SESSION *(*cb) (struct ssl_st *ssl, + unsigned char *data, int len, + int *copy)) +{ + ctx->get_session_cb = cb; +} + +SSL_SESSION *(*SSL_CTX_sess_get_get_cb(SSL_CTX *ctx)) (SSL *ssl, + unsigned char *data, + int len, int *copy) { + return ctx->get_session_cb; +} + +void SSL_CTX_set_info_callback(SSL_CTX *ctx, + void (*cb) (const SSL *ssl, int type, int val)) +{ + ctx->info_callback = cb; +} + +void (*SSL_CTX_get_info_callback(SSL_CTX *ctx)) (const SSL *ssl, int type, + int val) { + return ctx->info_callback; +} + +void SSL_CTX_set_client_cert_cb(SSL_CTX *ctx, + int (*cb) (SSL *ssl, X509 **x509, + EVP_PKEY **pkey)) +{ + ctx->client_cert_cb = cb; +} + +int (*SSL_CTX_get_client_cert_cb(SSL_CTX *ctx)) (SSL *ssl, X509 **x509, + EVP_PKEY **pkey) { + return ctx->client_cert_cb; +} + +#ifndef OPENSSL_NO_ENGINE +int SSL_CTX_set_client_cert_engine(SSL_CTX *ctx, ENGINE *e) +{ + if (!ENGINE_init(e)) { + SSLerr(SSL_F_SSL_CTX_SET_CLIENT_CERT_ENGINE, ERR_R_ENGINE_LIB); + return 0; + } + if (!ENGINE_get_ssl_client_cert_function(e)) { + SSLerr(SSL_F_SSL_CTX_SET_CLIENT_CERT_ENGINE, + SSL_R_NO_CLIENT_CERT_METHOD); + ENGINE_finish(e); + return 0; + } + ctx->client_cert_engine = e; + return 1; +} +#endif + +void SSL_CTX_set_cookie_generate_cb(SSL_CTX *ctx, + int (*cb) (SSL *ssl, + unsigned char *cookie, + unsigned int *cookie_len)) +{ + ctx->app_gen_cookie_cb = cb; +} + +void SSL_CTX_set_cookie_verify_cb(SSL_CTX *ctx, + int (*cb) (SSL *ssl, unsigned char *cookie, + unsigned int cookie_len)) +{ + ctx->app_verify_cookie_cb = cb; +} + +IMPLEMENT_PEM_rw(SSL_SESSION, SSL_SESSION, PEM_STRING_SSL_SESSION, + SSL_SESSION) diff --git a/thirdparty/openssl/ssl/ssl_stat.c b/thirdparty/openssl/ssl/ssl_stat.c new file mode 100644 index 0000000000..1b9069f978 --- /dev/null +++ b/thirdparty/openssl/ssl/ssl_stat.c @@ -0,0 +1,1078 @@ +/* ssl/ssl_stat.c */ +/* 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 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 <stdio.h> +#include "ssl_locl.h" + +const char *SSL_state_string_long(const SSL *s) +{ + const char *str; + + switch (s->state) { + case SSL_ST_BEFORE: + str = "before SSL initialization"; + break; + case SSL_ST_ACCEPT: + str = "before accept initialization"; + break; + case SSL_ST_CONNECT: + str = "before connect initialization"; + break; + case SSL_ST_OK: + str = "SSL negotiation finished successfully"; + break; + case SSL_ST_RENEGOTIATE: + str = "SSL renegotiate ciphers"; + break; + case SSL_ST_BEFORE | SSL_ST_CONNECT: + str = "before/connect initialization"; + break; + case SSL_ST_OK | SSL_ST_CONNECT: + str = "ok/connect SSL initialization"; + break; + case SSL_ST_BEFORE | SSL_ST_ACCEPT: + str = "before/accept initialization"; + break; + case SSL_ST_OK | SSL_ST_ACCEPT: + str = "ok/accept SSL initialization"; + break; + case SSL_ST_ERR: + str = "error"; + break; +#ifndef OPENSSL_NO_SSL2 + case SSL2_ST_CLIENT_START_ENCRYPTION: + str = "SSLv2 client start encryption"; + break; + case SSL2_ST_SERVER_START_ENCRYPTION: + str = "SSLv2 server start encryption"; + break; + case SSL2_ST_SEND_CLIENT_HELLO_A: + str = "SSLv2 write client hello A"; + break; + case SSL2_ST_SEND_CLIENT_HELLO_B: + str = "SSLv2 write client hello B"; + break; + case SSL2_ST_GET_SERVER_HELLO_A: + str = "SSLv2 read server hello A"; + break; + case SSL2_ST_GET_SERVER_HELLO_B: + str = "SSLv2 read server hello B"; + break; + case SSL2_ST_SEND_CLIENT_MASTER_KEY_A: + str = "SSLv2 write client master key A"; + break; + case SSL2_ST_SEND_CLIENT_MASTER_KEY_B: + str = "SSLv2 write client master key B"; + break; + case SSL2_ST_SEND_CLIENT_FINISHED_A: + str = "SSLv2 write client finished A"; + break; + case SSL2_ST_SEND_CLIENT_FINISHED_B: + str = "SSLv2 write client finished B"; + break; + case SSL2_ST_SEND_CLIENT_CERTIFICATE_A: + str = "SSLv2 write client certificate A"; + break; + case SSL2_ST_SEND_CLIENT_CERTIFICATE_B: + str = "SSLv2 write client certificate B"; + break; + case SSL2_ST_SEND_CLIENT_CERTIFICATE_C: + str = "SSLv2 write client certificate C"; + break; + case SSL2_ST_SEND_CLIENT_CERTIFICATE_D: + str = "SSLv2 write client certificate D"; + break; + case SSL2_ST_GET_SERVER_VERIFY_A: + str = "SSLv2 read server verify A"; + break; + case SSL2_ST_GET_SERVER_VERIFY_B: + str = "SSLv2 read server verify B"; + break; + case SSL2_ST_GET_SERVER_FINISHED_A: + str = "SSLv2 read server finished A"; + break; + case SSL2_ST_GET_SERVER_FINISHED_B: + str = "SSLv2 read server finished B"; + break; + case SSL2_ST_GET_CLIENT_HELLO_A: + str = "SSLv2 read client hello A"; + break; + case SSL2_ST_GET_CLIENT_HELLO_B: + str = "SSLv2 read client hello B"; + break; + case SSL2_ST_GET_CLIENT_HELLO_C: + str = "SSLv2 read client hello C"; + break; + case SSL2_ST_SEND_SERVER_HELLO_A: + str = "SSLv2 write server hello A"; + break; + case SSL2_ST_SEND_SERVER_HELLO_B: + str = "SSLv2 write server hello B"; + break; + case SSL2_ST_GET_CLIENT_MASTER_KEY_A: + str = "SSLv2 read client master key A"; + break; + case SSL2_ST_GET_CLIENT_MASTER_KEY_B: + str = "SSLv2 read client master key B"; + break; + case SSL2_ST_SEND_SERVER_VERIFY_A: + str = "SSLv2 write server verify A"; + break; + case SSL2_ST_SEND_SERVER_VERIFY_B: + str = "SSLv2 write server verify B"; + break; + case SSL2_ST_SEND_SERVER_VERIFY_C: + str = "SSLv2 write server verify C"; + break; + case SSL2_ST_GET_CLIENT_FINISHED_A: + str = "SSLv2 read client finished A"; + break; + case SSL2_ST_GET_CLIENT_FINISHED_B: + str = "SSLv2 read client finished B"; + break; + case SSL2_ST_SEND_SERVER_FINISHED_A: + str = "SSLv2 write server finished A"; + break; + case SSL2_ST_SEND_SERVER_FINISHED_B: + str = "SSLv2 write server finished B"; + break; + case SSL2_ST_SEND_REQUEST_CERTIFICATE_A: + str = "SSLv2 write request certificate A"; + break; + case SSL2_ST_SEND_REQUEST_CERTIFICATE_B: + str = "SSLv2 write request certificate B"; + break; + case SSL2_ST_SEND_REQUEST_CERTIFICATE_C: + str = "SSLv2 write request certificate C"; + break; + case SSL2_ST_SEND_REQUEST_CERTIFICATE_D: + str = "SSLv2 write request certificate D"; + break; + case SSL2_ST_X509_GET_SERVER_CERTIFICATE: + str = "SSLv2 X509 read server certificate"; + break; + case SSL2_ST_X509_GET_CLIENT_CERTIFICATE: + str = "SSLv2 X509 read client certificate"; + break; +#endif + +#ifndef OPENSSL_NO_SSL3 +/* SSLv3 additions */ + case SSL3_ST_CW_CLNT_HELLO_A: + str = "SSLv3 write client hello A"; + break; + case SSL3_ST_CW_CLNT_HELLO_B: + str = "SSLv3 write client hello B"; + break; + case SSL3_ST_CR_SRVR_HELLO_A: + str = "SSLv3 read server hello A"; + break; + case SSL3_ST_CR_SRVR_HELLO_B: + str = "SSLv3 read server hello B"; + break; + case SSL3_ST_CR_CERT_A: + str = "SSLv3 read server certificate A"; + break; + case SSL3_ST_CR_CERT_B: + str = "SSLv3 read server certificate B"; + break; + case SSL3_ST_CR_KEY_EXCH_A: + str = "SSLv3 read server key exchange A"; + break; + case SSL3_ST_CR_KEY_EXCH_B: + str = "SSLv3 read server key exchange B"; + break; + case SSL3_ST_CR_CERT_REQ_A: + str = "SSLv3 read server certificate request A"; + break; + case SSL3_ST_CR_CERT_REQ_B: + str = "SSLv3 read server certificate request B"; + break; + case SSL3_ST_CR_SESSION_TICKET_A: + str = "SSLv3 read server session ticket A"; + break; + case SSL3_ST_CR_SESSION_TICKET_B: + str = "SSLv3 read server session ticket B"; + break; + case SSL3_ST_CR_SRVR_DONE_A: + str = "SSLv3 read server done A"; + break; + case SSL3_ST_CR_SRVR_DONE_B: + str = "SSLv3 read server done B"; + break; + case SSL3_ST_CW_CERT_A: + str = "SSLv3 write client certificate A"; + break; + case SSL3_ST_CW_CERT_B: + str = "SSLv3 write client certificate B"; + break; + case SSL3_ST_CW_CERT_C: + str = "SSLv3 write client certificate C"; + break; + case SSL3_ST_CW_CERT_D: + str = "SSLv3 write client certificate D"; + break; + case SSL3_ST_CW_KEY_EXCH_A: + str = "SSLv3 write client key exchange A"; + break; + case SSL3_ST_CW_KEY_EXCH_B: + str = "SSLv3 write client key exchange B"; + break; + case SSL3_ST_CW_CERT_VRFY_A: + str = "SSLv3 write certificate verify A"; + break; + case SSL3_ST_CW_CERT_VRFY_B: + str = "SSLv3 write certificate verify B"; + break; + + case SSL3_ST_CW_CHANGE_A: + case SSL3_ST_SW_CHANGE_A: + str = "SSLv3 write change cipher spec A"; + break; + case SSL3_ST_CW_CHANGE_B: + case SSL3_ST_SW_CHANGE_B: + str = "SSLv3 write change cipher spec B"; + break; + case SSL3_ST_CW_FINISHED_A: + case SSL3_ST_SW_FINISHED_A: + str = "SSLv3 write finished A"; + break; + case SSL3_ST_CW_FINISHED_B: + case SSL3_ST_SW_FINISHED_B: + str = "SSLv3 write finished B"; + break; + case SSL3_ST_CR_CHANGE_A: + case SSL3_ST_SR_CHANGE_A: + str = "SSLv3 read change cipher spec A"; + break; + case SSL3_ST_CR_CHANGE_B: + case SSL3_ST_SR_CHANGE_B: + str = "SSLv3 read change cipher spec B"; + break; + case SSL3_ST_CR_FINISHED_A: + case SSL3_ST_SR_FINISHED_A: + str = "SSLv3 read finished A"; + break; + case SSL3_ST_CR_FINISHED_B: + case SSL3_ST_SR_FINISHED_B: + str = "SSLv3 read finished B"; + break; + + case SSL3_ST_CW_FLUSH: + case SSL3_ST_SW_FLUSH: + str = "SSLv3 flush data"; + break; + + case SSL3_ST_SR_CLNT_HELLO_A: + str = "SSLv3 read client hello A"; + break; + case SSL3_ST_SR_CLNT_HELLO_B: + str = "SSLv3 read client hello B"; + break; + case SSL3_ST_SR_CLNT_HELLO_C: + str = "SSLv3 read client hello C"; + break; + case SSL3_ST_SW_HELLO_REQ_A: + str = "SSLv3 write hello request A"; + break; + case SSL3_ST_SW_HELLO_REQ_B: + str = "SSLv3 write hello request B"; + break; + case SSL3_ST_SW_HELLO_REQ_C: + str = "SSLv3 write hello request C"; + break; + case SSL3_ST_SW_SRVR_HELLO_A: + str = "SSLv3 write server hello A"; + break; + case SSL3_ST_SW_SRVR_HELLO_B: + str = "SSLv3 write server hello B"; + break; + case SSL3_ST_SW_CERT_A: + str = "SSLv3 write certificate A"; + break; + case SSL3_ST_SW_CERT_B: + str = "SSLv3 write certificate B"; + break; + case SSL3_ST_SW_KEY_EXCH_A: + str = "SSLv3 write key exchange A"; + break; + case SSL3_ST_SW_KEY_EXCH_B: + str = "SSLv3 write key exchange B"; + break; + case SSL3_ST_SW_CERT_REQ_A: + str = "SSLv3 write certificate request A"; + break; + case SSL3_ST_SW_CERT_REQ_B: + str = "SSLv3 write certificate request B"; + break; + case SSL3_ST_SW_SESSION_TICKET_A: + str = "SSLv3 write session ticket A"; + break; + case SSL3_ST_SW_SESSION_TICKET_B: + str = "SSLv3 write session ticket B"; + break; + case SSL3_ST_SW_SRVR_DONE_A: + str = "SSLv3 write server done A"; + break; + case SSL3_ST_SW_SRVR_DONE_B: + str = "SSLv3 write server done B"; + break; + case SSL3_ST_SR_CERT_A: + str = "SSLv3 read client certificate A"; + break; + case SSL3_ST_SR_CERT_B: + str = "SSLv3 read client certificate B"; + break; + case SSL3_ST_SR_KEY_EXCH_A: + str = "SSLv3 read client key exchange A"; + break; + case SSL3_ST_SR_KEY_EXCH_B: + str = "SSLv3 read client key exchange B"; + break; + case SSL3_ST_SR_CERT_VRFY_A: + str = "SSLv3 read certificate verify A"; + break; + case SSL3_ST_SR_CERT_VRFY_B: + str = "SSLv3 read certificate verify B"; + break; +#endif + +/* SSLv2/v3 compatibility states */ +/* client */ + case SSL23_ST_CW_CLNT_HELLO_A: + str = "SSLv2/v3 write client hello A"; + break; + case SSL23_ST_CW_CLNT_HELLO_B: + str = "SSLv2/v3 write client hello B"; + break; + case SSL23_ST_CR_SRVR_HELLO_A: + str = "SSLv2/v3 read server hello A"; + break; + case SSL23_ST_CR_SRVR_HELLO_B: + str = "SSLv2/v3 read server hello B"; + break; +/* server */ + case SSL23_ST_SR_CLNT_HELLO_A: + str = "SSLv2/v3 read client hello A"; + break; + case SSL23_ST_SR_CLNT_HELLO_B: + str = "SSLv2/v3 read client hello B"; + break; + +/* DTLS */ + case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A: + str = "DTLS1 read hello verify request A"; + break; + case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B: + str = "DTLS1 read hello verify request B"; + break; + case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A: + str = "DTLS1 write hello verify request A"; + break; + case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B: + str = "DTLS1 write hello verify request B"; + break; + + default: + str = "unknown state"; + break; + } + return (str); +} + +const char *SSL_rstate_string_long(const SSL *s) +{ + const char *str; + + switch (s->rstate) { + case SSL_ST_READ_HEADER: + str = "read header"; + break; + case SSL_ST_READ_BODY: + str = "read body"; + break; + case SSL_ST_READ_DONE: + str = "read done"; + break; + default: + str = "unknown"; + break; + } + return (str); +} + +const char *SSL_state_string(const SSL *s) +{ + const char *str; + + switch (s->state) { + case SSL_ST_BEFORE: + str = "PINIT "; + break; + case SSL_ST_ACCEPT: + str = "AINIT "; + break; + case SSL_ST_CONNECT: + str = "CINIT "; + break; + case SSL_ST_OK: + str = "SSLOK "; + break; + case SSL_ST_ERR: + str = "SSLERR"; + break; +#ifndef OPENSSL_NO_SSL2 + case SSL2_ST_CLIENT_START_ENCRYPTION: + str = "2CSENC"; + break; + case SSL2_ST_SERVER_START_ENCRYPTION: + str = "2SSENC"; + break; + case SSL2_ST_SEND_CLIENT_HELLO_A: + str = "2SCH_A"; + break; + case SSL2_ST_SEND_CLIENT_HELLO_B: + str = "2SCH_B"; + break; + case SSL2_ST_GET_SERVER_HELLO_A: + str = "2GSH_A"; + break; + case SSL2_ST_GET_SERVER_HELLO_B: + str = "2GSH_B"; + break; + case SSL2_ST_SEND_CLIENT_MASTER_KEY_A: + str = "2SCMKA"; + break; + case SSL2_ST_SEND_CLIENT_MASTER_KEY_B: + str = "2SCMKB"; + break; + case SSL2_ST_SEND_CLIENT_FINISHED_A: + str = "2SCF_A"; + break; + case SSL2_ST_SEND_CLIENT_FINISHED_B: + str = "2SCF_B"; + break; + case SSL2_ST_SEND_CLIENT_CERTIFICATE_A: + str = "2SCC_A"; + break; + case SSL2_ST_SEND_CLIENT_CERTIFICATE_B: + str = "2SCC_B"; + break; + case SSL2_ST_SEND_CLIENT_CERTIFICATE_C: + str = "2SCC_C"; + break; + case SSL2_ST_SEND_CLIENT_CERTIFICATE_D: + str = "2SCC_D"; + break; + case SSL2_ST_GET_SERVER_VERIFY_A: + str = "2GSV_A"; + break; + case SSL2_ST_GET_SERVER_VERIFY_B: + str = "2GSV_B"; + break; + case SSL2_ST_GET_SERVER_FINISHED_A: + str = "2GSF_A"; + break; + case SSL2_ST_GET_SERVER_FINISHED_B: + str = "2GSF_B"; + break; + case SSL2_ST_GET_CLIENT_HELLO_A: + str = "2GCH_A"; + break; + case SSL2_ST_GET_CLIENT_HELLO_B: + str = "2GCH_B"; + break; + case SSL2_ST_GET_CLIENT_HELLO_C: + str = "2GCH_C"; + break; + case SSL2_ST_SEND_SERVER_HELLO_A: + str = "2SSH_A"; + break; + case SSL2_ST_SEND_SERVER_HELLO_B: + str = "2SSH_B"; + break; + case SSL2_ST_GET_CLIENT_MASTER_KEY_A: + str = "2GCMKA"; + break; + case SSL2_ST_GET_CLIENT_MASTER_KEY_B: + str = "2GCMKA"; + break; + case SSL2_ST_SEND_SERVER_VERIFY_A: + str = "2SSV_A"; + break; + case SSL2_ST_SEND_SERVER_VERIFY_B: + str = "2SSV_B"; + break; + case SSL2_ST_SEND_SERVER_VERIFY_C: + str = "2SSV_C"; + break; + case SSL2_ST_GET_CLIENT_FINISHED_A: + str = "2GCF_A"; + break; + case SSL2_ST_GET_CLIENT_FINISHED_B: + str = "2GCF_B"; + break; + case SSL2_ST_SEND_SERVER_FINISHED_A: + str = "2SSF_A"; + break; + case SSL2_ST_SEND_SERVER_FINISHED_B: + str = "2SSF_B"; + break; + case SSL2_ST_SEND_REQUEST_CERTIFICATE_A: + str = "2SRC_A"; + break; + case SSL2_ST_SEND_REQUEST_CERTIFICATE_B: + str = "2SRC_B"; + break; + case SSL2_ST_SEND_REQUEST_CERTIFICATE_C: + str = "2SRC_C"; + break; + case SSL2_ST_SEND_REQUEST_CERTIFICATE_D: + str = "2SRC_D"; + break; + case SSL2_ST_X509_GET_SERVER_CERTIFICATE: + str = "2X9GSC"; + break; + case SSL2_ST_X509_GET_CLIENT_CERTIFICATE: + str = "2X9GCC"; + break; +#endif + +#ifndef OPENSSL_NO_SSL3 +/* SSLv3 additions */ + case SSL3_ST_SW_FLUSH: + case SSL3_ST_CW_FLUSH: + str = "3FLUSH"; + break; + case SSL3_ST_CW_CLNT_HELLO_A: + str = "3WCH_A"; + break; + case SSL3_ST_CW_CLNT_HELLO_B: + str = "3WCH_B"; + break; + case SSL3_ST_CR_SRVR_HELLO_A: + str = "3RSH_A"; + break; + case SSL3_ST_CR_SRVR_HELLO_B: + str = "3RSH_B"; + break; + case SSL3_ST_CR_CERT_A: + str = "3RSC_A"; + break; + case SSL3_ST_CR_CERT_B: + str = "3RSC_B"; + break; + case SSL3_ST_CR_KEY_EXCH_A: + str = "3RSKEA"; + break; + case SSL3_ST_CR_KEY_EXCH_B: + str = "3RSKEB"; + break; + case SSL3_ST_CR_CERT_REQ_A: + str = "3RCR_A"; + break; + case SSL3_ST_CR_CERT_REQ_B: + str = "3RCR_B"; + break; + case SSL3_ST_CR_SRVR_DONE_A: + str = "3RSD_A"; + break; + case SSL3_ST_CR_SRVR_DONE_B: + str = "3RSD_B"; + break; + case SSL3_ST_CW_CERT_A: + str = "3WCC_A"; + break; + case SSL3_ST_CW_CERT_B: + str = "3WCC_B"; + break; + case SSL3_ST_CW_CERT_C: + str = "3WCC_C"; + break; + case SSL3_ST_CW_CERT_D: + str = "3WCC_D"; + break; + case SSL3_ST_CW_KEY_EXCH_A: + str = "3WCKEA"; + break; + case SSL3_ST_CW_KEY_EXCH_B: + str = "3WCKEB"; + break; + case SSL3_ST_CW_CERT_VRFY_A: + str = "3WCV_A"; + break; + case SSL3_ST_CW_CERT_VRFY_B: + str = "3WCV_B"; + break; + + case SSL3_ST_SW_CHANGE_A: + case SSL3_ST_CW_CHANGE_A: + str = "3WCCSA"; + break; + case SSL3_ST_SW_CHANGE_B: + case SSL3_ST_CW_CHANGE_B: + str = "3WCCSB"; + break; + case SSL3_ST_SW_FINISHED_A: + case SSL3_ST_CW_FINISHED_A: + str = "3WFINA"; + break; + case SSL3_ST_SW_FINISHED_B: + case SSL3_ST_CW_FINISHED_B: + str = "3WFINB"; + break; + case SSL3_ST_SR_CHANGE_A: + case SSL3_ST_CR_CHANGE_A: + str = "3RCCSA"; + break; + case SSL3_ST_SR_CHANGE_B: + case SSL3_ST_CR_CHANGE_B: + str = "3RCCSB"; + break; + case SSL3_ST_SR_FINISHED_A: + case SSL3_ST_CR_FINISHED_A: + str = "3RFINA"; + break; + case SSL3_ST_SR_FINISHED_B: + case SSL3_ST_CR_FINISHED_B: + str = "3RFINB"; + break; + + case SSL3_ST_SW_HELLO_REQ_A: + str = "3WHR_A"; + break; + case SSL3_ST_SW_HELLO_REQ_B: + str = "3WHR_B"; + break; + case SSL3_ST_SW_HELLO_REQ_C: + str = "3WHR_C"; + break; + case SSL3_ST_SR_CLNT_HELLO_A: + str = "3RCH_A"; + break; + case SSL3_ST_SR_CLNT_HELLO_B: + str = "3RCH_B"; + break; + case SSL3_ST_SR_CLNT_HELLO_C: + str = "3RCH_C"; + break; + case SSL3_ST_SW_SRVR_HELLO_A: + str = "3WSH_A"; + break; + case SSL3_ST_SW_SRVR_HELLO_B: + str = "3WSH_B"; + break; + case SSL3_ST_SW_CERT_A: + str = "3WSC_A"; + break; + case SSL3_ST_SW_CERT_B: + str = "3WSC_B"; + break; + case SSL3_ST_SW_KEY_EXCH_A: + str = "3WSKEA"; + break; + case SSL3_ST_SW_KEY_EXCH_B: + str = "3WSKEB"; + break; + case SSL3_ST_SW_CERT_REQ_A: + str = "3WCR_A"; + break; + case SSL3_ST_SW_CERT_REQ_B: + str = "3WCR_B"; + break; + case SSL3_ST_SW_SRVR_DONE_A: + str = "3WSD_A"; + break; + case SSL3_ST_SW_SRVR_DONE_B: + str = "3WSD_B"; + break; + case SSL3_ST_SR_CERT_A: + str = "3RCC_A"; + break; + case SSL3_ST_SR_CERT_B: + str = "3RCC_B"; + break; + case SSL3_ST_SR_KEY_EXCH_A: + str = "3RCKEA"; + break; + case SSL3_ST_SR_KEY_EXCH_B: + str = "3RCKEB"; + break; + case SSL3_ST_SR_CERT_VRFY_A: + str = "3RCV_A"; + break; + case SSL3_ST_SR_CERT_VRFY_B: + str = "3RCV_B"; + break; +#endif + +/* SSLv2/v3 compatibility states */ +/* client */ + case SSL23_ST_CW_CLNT_HELLO_A: + str = "23WCHA"; + break; + case SSL23_ST_CW_CLNT_HELLO_B: + str = "23WCHB"; + break; + case SSL23_ST_CR_SRVR_HELLO_A: + str = "23RSHA"; + break; + case SSL23_ST_CR_SRVR_HELLO_B: + str = "23RSHA"; + break; +/* server */ + case SSL23_ST_SR_CLNT_HELLO_A: + str = "23RCHA"; + break; + case SSL23_ST_SR_CLNT_HELLO_B: + str = "23RCHB"; + break; + +/* DTLS */ + case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A: + str = "DRCHVA"; + break; + case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B: + str = "DRCHVB"; + break; + case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A: + str = "DWCHVA"; + break; + case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B: + str = "DWCHVB"; + break; + + default: + str = "UNKWN "; + break; + } + return (str); +} + +const char *SSL_alert_type_string_long(int value) +{ + value >>= 8; + if (value == SSL3_AL_WARNING) + return ("warning"); + else if (value == SSL3_AL_FATAL) + return ("fatal"); + else + return ("unknown"); +} + +const char *SSL_alert_type_string(int value) +{ + value >>= 8; + if (value == SSL3_AL_WARNING) + return ("W"); + else if (value == SSL3_AL_FATAL) + return ("F"); + else + return ("U"); +} + +const char *SSL_alert_desc_string(int value) +{ + const char *str; + + switch (value & 0xff) { + case SSL3_AD_CLOSE_NOTIFY: + str = "CN"; + break; + case SSL3_AD_UNEXPECTED_MESSAGE: + str = "UM"; + break; + case SSL3_AD_BAD_RECORD_MAC: + str = "BM"; + break; + case SSL3_AD_DECOMPRESSION_FAILURE: + str = "DF"; + break; + case SSL3_AD_HANDSHAKE_FAILURE: + str = "HF"; + break; + case SSL3_AD_NO_CERTIFICATE: + str = "NC"; + break; + case SSL3_AD_BAD_CERTIFICATE: + str = "BC"; + break; + case SSL3_AD_UNSUPPORTED_CERTIFICATE: + str = "UC"; + break; + case SSL3_AD_CERTIFICATE_REVOKED: + str = "CR"; + break; + case SSL3_AD_CERTIFICATE_EXPIRED: + str = "CE"; + break; + case SSL3_AD_CERTIFICATE_UNKNOWN: + str = "CU"; + break; + case SSL3_AD_ILLEGAL_PARAMETER: + str = "IP"; + break; + case TLS1_AD_DECRYPTION_FAILED: + str = "DC"; + break; + case TLS1_AD_RECORD_OVERFLOW: + str = "RO"; + break; + case TLS1_AD_UNKNOWN_CA: + str = "CA"; + break; + case TLS1_AD_ACCESS_DENIED: + str = "AD"; + break; + case TLS1_AD_DECODE_ERROR: + str = "DE"; + break; + case TLS1_AD_DECRYPT_ERROR: + str = "CY"; + break; + case TLS1_AD_EXPORT_RESTRICTION: + str = "ER"; + break; + case TLS1_AD_PROTOCOL_VERSION: + str = "PV"; + break; + case TLS1_AD_INSUFFICIENT_SECURITY: + str = "IS"; + break; + case TLS1_AD_INTERNAL_ERROR: + str = "IE"; + break; + case TLS1_AD_USER_CANCELLED: + str = "US"; + break; + case TLS1_AD_NO_RENEGOTIATION: + str = "NR"; + break; + case TLS1_AD_UNSUPPORTED_EXTENSION: + str = "UE"; + break; + case TLS1_AD_CERTIFICATE_UNOBTAINABLE: + str = "CO"; + break; + case TLS1_AD_UNRECOGNIZED_NAME: + str = "UN"; + break; + case TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE: + str = "BR"; + break; + case TLS1_AD_BAD_CERTIFICATE_HASH_VALUE: + str = "BH"; + break; + case TLS1_AD_UNKNOWN_PSK_IDENTITY: + str = "UP"; + break; + default: + str = "UK"; + break; + } + return (str); +} + +const char *SSL_alert_desc_string_long(int value) +{ + const char *str; + + switch (value & 0xff) { + case SSL3_AD_CLOSE_NOTIFY: + str = "close notify"; + break; + case SSL3_AD_UNEXPECTED_MESSAGE: + str = "unexpected_message"; + break; + case SSL3_AD_BAD_RECORD_MAC: + str = "bad record mac"; + break; + case SSL3_AD_DECOMPRESSION_FAILURE: + str = "decompression failure"; + break; + case SSL3_AD_HANDSHAKE_FAILURE: + str = "handshake failure"; + break; + case SSL3_AD_NO_CERTIFICATE: + str = "no certificate"; + break; + case SSL3_AD_BAD_CERTIFICATE: + str = "bad certificate"; + break; + case SSL3_AD_UNSUPPORTED_CERTIFICATE: + str = "unsupported certificate"; + break; + case SSL3_AD_CERTIFICATE_REVOKED: + str = "certificate revoked"; + break; + case SSL3_AD_CERTIFICATE_EXPIRED: + str = "certificate expired"; + break; + case SSL3_AD_CERTIFICATE_UNKNOWN: + str = "certificate unknown"; + break; + case SSL3_AD_ILLEGAL_PARAMETER: + str = "illegal parameter"; + break; + case TLS1_AD_DECRYPTION_FAILED: + str = "decryption failed"; + break; + case TLS1_AD_RECORD_OVERFLOW: + str = "record overflow"; + break; + case TLS1_AD_UNKNOWN_CA: + str = "unknown CA"; + break; + case TLS1_AD_ACCESS_DENIED: + str = "access denied"; + break; + case TLS1_AD_DECODE_ERROR: + str = "decode error"; + break; + case TLS1_AD_DECRYPT_ERROR: + str = "decrypt error"; + break; + case TLS1_AD_EXPORT_RESTRICTION: + str = "export restriction"; + break; + case TLS1_AD_PROTOCOL_VERSION: + str = "protocol version"; + break; + case TLS1_AD_INSUFFICIENT_SECURITY: + str = "insufficient security"; + break; + case TLS1_AD_INTERNAL_ERROR: + str = "internal error"; + break; + case TLS1_AD_USER_CANCELLED: + str = "user canceled"; + break; + case TLS1_AD_NO_RENEGOTIATION: + str = "no renegotiation"; + break; + case TLS1_AD_UNSUPPORTED_EXTENSION: + str = "unsupported extension"; + break; + case TLS1_AD_CERTIFICATE_UNOBTAINABLE: + str = "certificate unobtainable"; + break; + case TLS1_AD_UNRECOGNIZED_NAME: + str = "unrecognized name"; + break; + case TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE: + str = "bad certificate status response"; + break; + case TLS1_AD_BAD_CERTIFICATE_HASH_VALUE: + str = "bad certificate hash value"; + break; + case TLS1_AD_UNKNOWN_PSK_IDENTITY: + str = "unknown PSK identity"; + break; + default: + str = "unknown"; + break; + } + return (str); +} + +const char *SSL_rstate_string(const SSL *s) +{ + const char *str; + + switch (s->rstate) { + case SSL_ST_READ_HEADER: + str = "RH"; + break; + case SSL_ST_READ_BODY: + str = "RB"; + break; + case SSL_ST_READ_DONE: + str = "RD"; + break; + default: + str = "unknown"; + break; + } + return (str); +} diff --git a/thirdparty/openssl/ssl/ssl_task.c b/thirdparty/openssl/ssl/ssl_task.c new file mode 100644 index 0000000000..fb770753e2 --- /dev/null +++ b/thirdparty/openssl/ssl/ssl_task.c @@ -0,0 +1,397 @@ +/* ssl/ssl_task.c */ +/* 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.] + */ + +/* VMS */ +/*- + * DECnet object for servicing SSL. We accept the inbound and speak a + * simple protocol for multiplexing the 2 data streams (application and + * ssl data) over this logical link. + * + * Logical names: + * SSL_CIPHER Defines a list of cipher specifications the server + * will support in order of preference. + * SSL_SERVER_CERTIFICATE + * Points to PEM (privacy enhanced mail) file that + * contains the server certificate and private password. + * SYS$NET Logical created by netserver.exe as hook for completing + * DECnet logical link. + * + * Each NSP message sent over the DECnet link has the following structure: + * struct rpc_msg { + * char channel; + * char function; + * short length; + * char data[MAX_DATA]; + * } msg; + * + * The channel field designates the virtual data stream this message applies + * to and is one of: + * A - Application data (payload). + * R - Remote client connection that initiated the SSL connection. Encrypted + * data is sent over this connection. + * G - General data, reserved for future use. + * + * The data streams are half-duplex read/write and have following functions: + * G - Get, requests that up to msg.length bytes of data be returned. The + * data is returned in the next 'C' function response that matches the + * requesting channel. + * P - Put, requests that the first msg.length bytes of msg.data be appended + * to the designated stream. + * C - Confirms a get or put. Every get and put will get a confirm response, + * you cannot initiate another function on a channel until the previous + * operation has been confirmed. + * + * The 2 channels may interleave their operations, for example: + * Server msg Client msg + * A, Get, 4092 ----> + * <---- R, get, 4092 + * R, Confirm, {hello} ----> + * <---- R, put, {srv hello} + * R, Confirm, 0 ----> + * . (SSL handshake completed) + * . (read first app data). + * <---- A, confirm, {http data} + * A, Put, {http data} ----> + * <---- A, confirm, 0 + * + * The length field is not permitted to be larger that 4092 bytes. + * + * Author: Dave Jones + * Date: 22-JUL-1996 + */ +#include <stdlib.h> +#include <stdio.h> +#include <iodef.h> /* VMS IO$_ definitions */ +#include <descrip.h> /* VMS string descriptors */ +extern int SYS$QIOW(), SYS$ASSIGN(); +int LIB$INIT_TIMER(), LIB$SHOW_TIMER(); + +#include <string.h> /* from ssltest.c */ +#include <errno.h> + +#include "e_os.h" + +#include <openssl/buffer.h> +#include <openssl/x509.h> +#include <openssl/ssl.h> +#include <openssl/err.h> + +int MS_CALLBACK verify_callback(int ok, X509 *xs, X509 *xi, int depth, + int error); +BIO *bio_err = NULL; +BIO *bio_stdout = NULL; +BIO_METHOD *BIO_s_rtcp(); + +static char *cipher = NULL; +int verbose = 1; +#ifdef FIONBIO +static int s_nbio = 0; +#endif +#define TEST_SERVER_CERT "SSL_SERVER_CERTIFICATE" +/*************************************************************************/ +/* Should have member alignment inhibited */ +struct rpc_msg { + /* 'A'-app data. 'R'-remote client 'G'-global */ + char channel; + /* 'G'-get, 'P'-put, 'C'-confirm, 'X'-close */ + char function; + /* Amount of data returned or max to return */ + unsigned short int length; + /* variable data */ + char data[4092]; +}; +#define RPC_HDR_SIZE (sizeof(struct rpc_msg) - 4092) + +static $DESCRIPTOR(sysnet, "SYS$NET"); +typedef unsigned short io_channel; + +struct io_status { + unsigned short status; + unsigned short count; + unsigned long stsval; +}; +int doit(io_channel chan, SSL_CTX *s_ctx); +/*****************************************************************************/ +/* + * Decnet I/O routines. + */ +static int get(io_channel chan, char *buffer, int maxlen, int *length) +{ + int status; + struct io_status iosb; + status = SYS$QIOW(0, chan, IO$_READVBLK, &iosb, 0, 0, + buffer, maxlen, 0, 0, 0, 0); + if ((status & 1) == 1) + status = iosb.status; + if ((status & 1) == 1) + *length = iosb.count; + return status; +} + +static int put(io_channel chan, char *buffer, int length) +{ + int status; + struct io_status iosb; + status = SYS$QIOW(0, chan, IO$_WRITEVBLK, &iosb, 0, 0, + buffer, length, 0, 0, 0, 0); + if ((status & 1) == 1) + status = iosb.status; + return status; +} + +/***************************************************************************/ +/* + * Handle operations on the 'G' channel. + */ +static int general_request(io_channel chan, struct rpc_msg *msg, int length) +{ + return 48; +} + +/***************************************************************************/ +int main(int argc, char **argv) +{ + int status, length; + io_channel chan; + struct rpc_msg msg; + + char *CApath = NULL, *CAfile = NULL; + int badop = 0; + int ret = 1; + int client_auth = 0; + int server_auth = 0; + SSL_CTX *s_ctx = NULL; + /* + * Confirm logical link with initiating client. + */ + LIB$INIT_TIMER(); + status = SYS$ASSIGN(&sysnet, &chan, 0, 0, 0); + printf("status of assign to SYS$NET: %d\n", status); + /* + * Initialize standard out and error files. + */ + if (bio_err == NULL) + if ((bio_err = BIO_new(BIO_s_file())) != NULL) + BIO_set_fp(bio_err, stderr, BIO_NOCLOSE); + if (bio_stdout == NULL) + if ((bio_stdout = BIO_new(BIO_s_file())) != NULL) + BIO_set_fp(bio_stdout, stdout, BIO_NOCLOSE); + /* + * get the preferred cipher list and other initialization + */ + if (cipher == NULL) + cipher = getenv("SSL_CIPHER"); + printf("cipher list: %s\n", cipher ? cipher : "{undefined}"); + + SSL_load_error_strings(); + OpenSSL_add_all_algorithms(); + + /* + * DRM, this was the original, but there is no such thing as SSLv2() + * s_ctx=SSL_CTX_new(SSLv2()); + */ + s_ctx = SSL_CTX_new(SSLv2_server_method()); + + if (s_ctx == NULL) + goto end; + + SSL_CTX_use_certificate_file(s_ctx, TEST_SERVER_CERT, SSL_FILETYPE_PEM); + SSL_CTX_use_RSAPrivateKey_file(s_ctx, TEST_SERVER_CERT, SSL_FILETYPE_PEM); + printf("Loaded server certificate: '%s'\n", TEST_SERVER_CERT); + + /* + * Take commands from client until bad status. + */ + LIB$SHOW_TIMER(); + status = doit(chan, s_ctx); + LIB$SHOW_TIMER(); + /* + * do final cleanup and exit. + */ + end: + if (s_ctx != NULL) + SSL_CTX_free(s_ctx); + LIB$SHOW_TIMER(); + return 1; +} + +int doit(io_channel chan, SSL_CTX *s_ctx) +{ + int status, length, link_state; + struct rpc_msg msg; + + SSL *s_ssl = NULL; + BIO *c_to_s = NULL; + BIO *s_to_c = NULL; + BIO *c_bio = NULL; + BIO *s_bio = NULL; + int i; + int done = 0; + + s_ssl = SSL_new(s_ctx); + if (s_ssl == NULL) + goto err; + + c_to_s = BIO_new(BIO_s_rtcp()); + s_to_c = BIO_new(BIO_s_rtcp()); + if ((s_to_c == NULL) || (c_to_s == NULL)) + goto err; +/*- original, DRM 24-SEP-1997 + BIO_set_fd ( c_to_s, "", chan ); + BIO_set_fd ( s_to_c, "", chan ); +*/ + BIO_set_fd(c_to_s, 0, chan); + BIO_set_fd(s_to_c, 0, chan); + + c_bio = BIO_new(BIO_f_ssl()); + s_bio = BIO_new(BIO_f_ssl()); + if ((c_bio == NULL) || (s_bio == NULL)) + goto err; + + SSL_set_accept_state(s_ssl); + SSL_set_bio(s_ssl, c_to_s, s_to_c); + BIO_set_ssl(s_bio, s_ssl, BIO_CLOSE); + + /* We can always do writes */ + printf("Begin doit main loop\n"); + /* + * Link states: 0-idle, 1-read pending, 2-write pending, 3-closed. + */ + for (link_state = 0; link_state < 3;) { + /* + * Wait for remote end to request data action on A channel. + */ + while (link_state == 0) { + status = get(chan, (char *)&msg, sizeof(msg), &length); + if ((status & 1) == 0) { + printf("Error in main loop get: %d\n", status); + link_state = 3; + break; + } + if (length < RPC_HDR_SIZE) { + printf("Error in main loop get size: %d\n", length); + break; + link_state = 3; + } + if (msg.channel != 'A') { + printf("Error in main loop, unexpected channel: %c\n", + msg.channel); + break; + link_state = 3; + } + if (msg.function == 'G') { + link_state = 1; + } else if (msg.function == 'P') { + link_state = 2; /* write pending */ + } else if (msg.function == 'X') { + link_state = 3; + } else { + link_state = 3; + } + } + if (link_state == 1) { + i = BIO_read(s_bio, msg.data, msg.length); + if (i < 0) + link_state = 3; + else { + msg.channel = 'A'; + msg.function = 'C'; /* confirm */ + msg.length = i; + status = put(chan, (char *)&msg, i + RPC_HDR_SIZE); + if ((status & 1) == 0) + break; + link_state = 0; + } + } else if (link_state == 2) { + i = BIO_write(s_bio, msg.data, msg.length); + if (i < 0) + link_state = 3; + else { + msg.channel = 'A'; + msg.function = 'C'; /* confirm */ + msg.length = 0; + status = put(chan, (char *)&msg, RPC_HDR_SIZE); + if ((status & 1) == 0) + break; + link_state = 0; + } + } + } + fprintf(stdout, "DONE\n"); + err: + /* + * We have to set the BIO's to NULL otherwise they will be free()ed + * twice. Once when th s_ssl is SSL_free()ed and again when c_ssl is + * SSL_free()ed. This is a hack required because s_ssl and c_ssl are + * sharing the same BIO structure and SSL_set_bio() and SSL_free() + * automatically BIO_free non NULL entries. You should not normally do + * this or be required to do this + */ + s_ssl->rbio = NULL; + s_ssl->wbio = NULL; + + if (c_to_s != NULL) + BIO_free(c_to_s); + if (s_to_c != NULL) + BIO_free(s_to_c); + if (c_bio != NULL) + BIO_free(c_bio); + if (s_bio != NULL) + BIO_free(s_bio); + return (0); +} diff --git a/thirdparty/openssl/ssl/ssl_txt.c b/thirdparty/openssl/ssl/ssl_txt.c new file mode 100644 index 0000000000..45308d8b65 --- /dev/null +++ b/thirdparty/openssl/ssl/ssl_txt.c @@ -0,0 +1,262 @@ +/* ssl/ssl_txt.c */ +/* 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 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 <stdio.h> +#include <openssl/buffer.h> +#include "ssl_locl.h" + +#ifndef OPENSSL_NO_FP_API +int SSL_SESSION_print_fp(FILE *fp, const SSL_SESSION *x) +{ + BIO *b; + int ret; + + if ((b = BIO_new(BIO_s_file_internal())) == NULL) { + SSLerr(SSL_F_SSL_SESSION_PRINT_FP, ERR_R_BUF_LIB); + return (0); + } + BIO_set_fp(b, fp, BIO_NOCLOSE); + ret = SSL_SESSION_print(b, x); + BIO_free(b); + return (ret); +} +#endif + +int SSL_SESSION_print(BIO *bp, const SSL_SESSION *x) +{ + unsigned int i; + const char *s; + + if (x == NULL) + goto err; + if (BIO_puts(bp, "SSL-Session:\n") <= 0) + goto err; + if (x->ssl_version == SSL2_VERSION) + s = "SSLv2"; + else if (x->ssl_version == SSL3_VERSION) + s = "SSLv3"; + else if (x->ssl_version == TLS1_2_VERSION) + s = "TLSv1.2"; + else if (x->ssl_version == TLS1_1_VERSION) + s = "TLSv1.1"; + else if (x->ssl_version == TLS1_VERSION) + s = "TLSv1"; + else if (x->ssl_version == DTLS1_VERSION) + s = "DTLSv1"; + else if (x->ssl_version == DTLS1_2_VERSION) + s = "DTLSv1.2"; + else if (x->ssl_version == DTLS1_BAD_VER) + s = "DTLSv1-bad"; + else + s = "unknown"; + if (BIO_printf(bp, " Protocol : %s\n", s) <= 0) + goto err; + + if (x->cipher == NULL) { + if (((x->cipher_id) & 0xff000000) == 0x02000000) { + if (BIO_printf + (bp, " Cipher : %06lX\n", x->cipher_id & 0xffffff) <= 0) + goto err; + } else { + if (BIO_printf + (bp, " Cipher : %04lX\n", x->cipher_id & 0xffff) <= 0) + goto err; + } + } else { + if (BIO_printf + (bp, " Cipher : %s\n", + ((x->cipher == NULL) ? "unknown" : x->cipher->name)) <= 0) + goto err; + } + if (BIO_puts(bp, " Session-ID: ") <= 0) + goto err; + for (i = 0; i < x->session_id_length; i++) { + if (BIO_printf(bp, "%02X", x->session_id[i]) <= 0) + goto err; + } + if (BIO_puts(bp, "\n Session-ID-ctx: ") <= 0) + goto err; + for (i = 0; i < x->sid_ctx_length; i++) { + if (BIO_printf(bp, "%02X", x->sid_ctx[i]) <= 0) + goto err; + } + if (BIO_puts(bp, "\n Master-Key: ") <= 0) + goto err; + for (i = 0; i < (unsigned int)x->master_key_length; i++) { + if (BIO_printf(bp, "%02X", x->master_key[i]) <= 0) + goto err; + } + if (BIO_puts(bp, "\n Key-Arg : ") <= 0) + goto err; + if (x->key_arg_length == 0) { + if (BIO_puts(bp, "None") <= 0) + goto err; + } else + for (i = 0; i < x->key_arg_length; i++) { + if (BIO_printf(bp, "%02X", x->key_arg[i]) <= 0) + goto err; + } +#ifndef OPENSSL_NO_KRB5 + if (BIO_puts(bp, "\n Krb5 Principal: ") <= 0) + goto err; + if (x->krb5_client_princ_len == 0) { + if (BIO_puts(bp, "None") <= 0) + goto err; + } else + for (i = 0; i < x->krb5_client_princ_len; i++) { + if (BIO_printf(bp, "%02X", x->krb5_client_princ[i]) <= 0) + goto err; + } +#endif /* OPENSSL_NO_KRB5 */ +#ifndef OPENSSL_NO_PSK + if (BIO_puts(bp, "\n PSK identity: ") <= 0) + goto err; + if (BIO_printf(bp, "%s", x->psk_identity ? x->psk_identity : "None") <= 0) + goto err; + if (BIO_puts(bp, "\n PSK identity hint: ") <= 0) + goto err; + if (BIO_printf + (bp, "%s", x->psk_identity_hint ? x->psk_identity_hint : "None") <= 0) + goto err; +#endif +#ifndef OPENSSL_NO_SRP + if (BIO_puts(bp, "\n SRP username: ") <= 0) + goto err; + if (BIO_printf(bp, "%s", x->srp_username ? x->srp_username : "None") <= 0) + goto err; +#endif +#ifndef OPENSSL_NO_TLSEXT + if (x->tlsext_tick_lifetime_hint) { + if (BIO_printf(bp, + "\n TLS session ticket lifetime hint: %ld (seconds)", + x->tlsext_tick_lifetime_hint) <= 0) + goto err; + } + if (x->tlsext_tick) { + if (BIO_puts(bp, "\n TLS session ticket:\n") <= 0) + goto err; + if (BIO_dump_indent(bp, (char *)x->tlsext_tick, x->tlsext_ticklen, 4) + <= 0) + goto err; + } +#endif + +#ifndef OPENSSL_NO_COMP + if (x->compress_meth != 0) { + SSL_COMP *comp = NULL; + + ssl_cipher_get_evp(x, NULL, NULL, NULL, NULL, &comp); + if (comp == NULL) { + if (BIO_printf(bp, "\n Compression: %d", x->compress_meth) <= + 0) + goto err; + } else { + if (BIO_printf + (bp, "\n Compression: %d (%s)", comp->id, + comp->method->name) <= 0) + goto err; + } + } +#endif + if (x->time != 0L) { + if (BIO_printf(bp, "\n Start Time: %ld", x->time) <= 0) + goto err; + } + if (x->timeout != 0L) { + if (BIO_printf(bp, "\n Timeout : %ld (sec)", x->timeout) <= 0) + goto err; + } + if (BIO_puts(bp, "\n") <= 0) + goto err; + + if (BIO_puts(bp, " Verify return code: ") <= 0) + goto err; + if (BIO_printf(bp, "%ld (%s)\n", x->verify_result, + X509_verify_cert_error_string(x->verify_result)) <= 0) + goto err; + + return (1); + err: + return (0); +} diff --git a/thirdparty/openssl/ssl/ssl_utst.c b/thirdparty/openssl/ssl/ssl_utst.c new file mode 100644 index 0000000000..53bdde330d --- /dev/null +++ b/thirdparty/openssl/ssl/ssl_utst.c @@ -0,0 +1,72 @@ +/* ssl_utst.c */ +/* + * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 2014 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. + * ==================================================================== + * + */ + +#include "ssl_locl.h" + +#ifndef OPENSSL_NO_UNIT_TEST + +static const struct openssl_ssl_test_functions ssl_test_functions = { + ssl_init_wbio_buffer, + ssl3_setup_buffers, + tls1_process_heartbeat, + dtls1_process_heartbeat +}; + +const struct openssl_ssl_test_functions *SSL_test_functions(void) +{ + return &ssl_test_functions; +} + +#endif diff --git a/thirdparty/openssl/ssl/t1_clnt.c b/thirdparty/openssl/ssl/t1_clnt.c new file mode 100644 index 0000000000..746b4e6b7a --- /dev/null +++ b/thirdparty/openssl/ssl/t1_clnt.c @@ -0,0 +1,90 @@ +/* ssl/t1_clnt.c */ +/* 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.] + */ + +#include <stdio.h> +#include "ssl_locl.h" +#include <openssl/buffer.h> +#include <openssl/rand.h> +#include <openssl/objects.h> +#include <openssl/evp.h> + +static const SSL_METHOD *tls1_get_client_method(int ver); +static const SSL_METHOD *tls1_get_client_method(int ver) +{ + if (ver == TLS1_2_VERSION) + return TLSv1_2_client_method(); + if (ver == TLS1_1_VERSION) + return TLSv1_1_client_method(); + if (ver == TLS1_VERSION) + return TLSv1_client_method(); + return NULL; +} + +IMPLEMENT_tls_meth_func(TLS1_2_VERSION, TLSv1_2_client_method, + ssl_undefined_function, + ssl3_connect, + tls1_get_client_method, TLSv1_2_enc_data) + + IMPLEMENT_tls_meth_func(TLS1_1_VERSION, TLSv1_1_client_method, + ssl_undefined_function, + ssl3_connect, + tls1_get_client_method, TLSv1_1_enc_data) + + IMPLEMENT_tls_meth_func(TLS1_VERSION, TLSv1_client_method, + ssl_undefined_function, + ssl3_connect, tls1_get_client_method, TLSv1_enc_data) diff --git a/thirdparty/openssl/ssl/t1_enc.c b/thirdparty/openssl/ssl/t1_enc.c new file mode 100644 index 0000000000..514fcb3e4e --- /dev/null +++ b/thirdparty/openssl/ssl/t1_enc.c @@ -0,0 +1,1377 @@ +/* ssl/t1_enc.c */ +/* 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 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 <stdio.h> +#include "ssl_locl.h" +#ifndef OPENSSL_NO_COMP +# include <openssl/comp.h> +#endif +#include <openssl/evp.h> +#include <openssl/hmac.h> +#include <openssl/md5.h> +#include <openssl/rand.h> +#ifdef KSSL_DEBUG +# include <openssl/des.h> +#endif + +/* seed1 through seed5 are virtually concatenated */ +static int tls1_P_hash(const EVP_MD *md, const unsigned char *sec, + int sec_len, + const void *seed1, int seed1_len, + const void *seed2, int seed2_len, + const void *seed3, int seed3_len, + const void *seed4, int seed4_len, + const void *seed5, int seed5_len, + unsigned char *out, int olen) +{ + int chunk; + size_t j; + EVP_MD_CTX ctx, ctx_tmp, ctx_init; + EVP_PKEY *mac_key; + unsigned char A1[EVP_MAX_MD_SIZE]; + size_t A1_len; + int ret = 0; + + chunk = EVP_MD_size(md); + OPENSSL_assert(chunk >= 0); + + EVP_MD_CTX_init(&ctx); + EVP_MD_CTX_init(&ctx_tmp); + EVP_MD_CTX_init(&ctx_init); + EVP_MD_CTX_set_flags(&ctx_init, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); + mac_key = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, sec, sec_len); + if (!mac_key) + goto err; + if (!EVP_DigestSignInit(&ctx_init, NULL, md, NULL, mac_key)) + goto err; + if (!EVP_MD_CTX_copy_ex(&ctx, &ctx_init)) + goto err; + if (seed1 && !EVP_DigestSignUpdate(&ctx, seed1, seed1_len)) + goto err; + if (seed2 && !EVP_DigestSignUpdate(&ctx, seed2, seed2_len)) + goto err; + if (seed3 && !EVP_DigestSignUpdate(&ctx, seed3, seed3_len)) + goto err; + if (seed4 && !EVP_DigestSignUpdate(&ctx, seed4, seed4_len)) + goto err; + if (seed5 && !EVP_DigestSignUpdate(&ctx, seed5, seed5_len)) + goto err; + if (!EVP_DigestSignFinal(&ctx, A1, &A1_len)) + goto err; + + for (;;) { + /* Reinit mac contexts */ + if (!EVP_MD_CTX_copy_ex(&ctx, &ctx_init)) + goto err; + if (!EVP_DigestSignUpdate(&ctx, A1, A1_len)) + goto err; + if (olen > chunk && !EVP_MD_CTX_copy_ex(&ctx_tmp, &ctx)) + goto err; + if (seed1 && !EVP_DigestSignUpdate(&ctx, seed1, seed1_len)) + goto err; + if (seed2 && !EVP_DigestSignUpdate(&ctx, seed2, seed2_len)) + goto err; + if (seed3 && !EVP_DigestSignUpdate(&ctx, seed3, seed3_len)) + goto err; + if (seed4 && !EVP_DigestSignUpdate(&ctx, seed4, seed4_len)) + goto err; + if (seed5 && !EVP_DigestSignUpdate(&ctx, seed5, seed5_len)) + goto err; + + if (olen > chunk) { + if (!EVP_DigestSignFinal(&ctx, out, &j)) + goto err; + out += j; + olen -= j; + /* calc the next A1 value */ + if (!EVP_DigestSignFinal(&ctx_tmp, A1, &A1_len)) + goto err; + } else { /* last one */ + + if (!EVP_DigestSignFinal(&ctx, A1, &A1_len)) + goto err; + memcpy(out, A1, olen); + break; + } + } + ret = 1; + err: + EVP_PKEY_free(mac_key); + EVP_MD_CTX_cleanup(&ctx); + EVP_MD_CTX_cleanup(&ctx_tmp); + EVP_MD_CTX_cleanup(&ctx_init); + OPENSSL_cleanse(A1, sizeof(A1)); + return ret; +} + +/* seed1 through seed5 are virtually concatenated */ +static int tls1_PRF(long digest_mask, + const void *seed1, int seed1_len, + const void *seed2, int seed2_len, + const void *seed3, int seed3_len, + const void *seed4, int seed4_len, + const void *seed5, int seed5_len, + const unsigned char *sec, int slen, + unsigned char *out1, unsigned char *out2, int olen) +{ + int len, i, idx, count; + const unsigned char *S1; + long m; + const EVP_MD *md; + int ret = 0; + + /* Count number of digests and partition sec evenly */ + count = 0; + for (idx = 0; ssl_get_handshake_digest(idx, &m, &md); idx++) { + if ((m << TLS1_PRF_DGST_SHIFT) & digest_mask) + count++; + } + if (!count) { + /* Should never happen */ + SSLerr(SSL_F_TLS1_PRF, ERR_R_INTERNAL_ERROR); + goto err; + } + len = slen / count; + if (count == 1) + slen = 0; + S1 = sec; + memset(out1, 0, olen); + for (idx = 0; ssl_get_handshake_digest(idx, &m, &md); idx++) { + if ((m << TLS1_PRF_DGST_SHIFT) & digest_mask) { + if (!md) { + SSLerr(SSL_F_TLS1_PRF, SSL_R_UNSUPPORTED_DIGEST_TYPE); + goto err; + } + if (!tls1_P_hash(md, S1, len + (slen & 1), + seed1, seed1_len, seed2, seed2_len, seed3, + seed3_len, seed4, seed4_len, seed5, seed5_len, + out2, olen)) + goto err; + S1 += len; + for (i = 0; i < olen; i++) { + out1[i] ^= out2[i]; + } + } + } + ret = 1; + err: + return ret; +} + +static int tls1_generate_key_block(SSL *s, unsigned char *km, + unsigned char *tmp, int num) +{ + int ret; + ret = tls1_PRF(ssl_get_algorithm2(s), + TLS_MD_KEY_EXPANSION_CONST, + TLS_MD_KEY_EXPANSION_CONST_SIZE, s->s3->server_random, + SSL3_RANDOM_SIZE, s->s3->client_random, SSL3_RANDOM_SIZE, + NULL, 0, NULL, 0, s->session->master_key, + s->session->master_key_length, km, tmp, num); +#ifdef KSSL_DEBUG + fprintf(stderr, "tls1_generate_key_block() ==> %d byte master_key =\n\t", + s->session->master_key_length); + { + int i; + for (i = 0; i < s->session->master_key_length; i++) { + fprintf(stderr, "%02X", s->session->master_key[i]); + } + fprintf(stderr, "\n"); + } +#endif /* KSSL_DEBUG */ + return ret; +} + +int tls1_change_cipher_state(SSL *s, int which) +{ + static const unsigned char empty[] = ""; + unsigned char *p, *mac_secret; + unsigned char *exp_label; + unsigned char tmp1[EVP_MAX_KEY_LENGTH]; + unsigned char tmp2[EVP_MAX_KEY_LENGTH]; + unsigned char iv1[EVP_MAX_IV_LENGTH * 2]; + unsigned char iv2[EVP_MAX_IV_LENGTH * 2]; + unsigned char *ms, *key, *iv; + int client_write; + EVP_CIPHER_CTX *dd; + const EVP_CIPHER *c; +#ifndef OPENSSL_NO_COMP + const SSL_COMP *comp; +#endif + const EVP_MD *m; + int mac_type; + int *mac_secret_size; + EVP_MD_CTX *mac_ctx; + EVP_PKEY *mac_key; + int is_export, n, i, j, k, exp_label_len, cl; + int reuse_dd = 0; + + is_export = SSL_C_IS_EXPORT(s->s3->tmp.new_cipher); + c = s->s3->tmp.new_sym_enc; + m = s->s3->tmp.new_hash; + mac_type = s->s3->tmp.new_mac_pkey_type; +#ifndef OPENSSL_NO_COMP + comp = s->s3->tmp.new_compression; +#endif + +#ifdef KSSL_DEBUG + fprintf(stderr, "tls1_change_cipher_state(which= %d) w/\n", which); + fprintf(stderr, "\talg= %ld/%ld, comp= %p\n", + s->s3->tmp.new_cipher->algorithm_mkey, + s->s3->tmp.new_cipher->algorithm_auth, comp); + fprintf(stderr, "\tevp_cipher == %p ==? &d_cbc_ede_cipher3\n", c); + fprintf(stderr, "\tevp_cipher: nid, blksz= %d, %d, keylen=%d, ivlen=%d\n", + c->nid, c->block_size, c->key_len, c->iv_len); + fprintf(stderr, "\tkey_block: len= %d, data= ", + s->s3->tmp.key_block_length); + { + int i; + for (i = 0; i < s->s3->tmp.key_block_length; i++) + fprintf(stderr, "%02x", s->s3->tmp.key_block[i]); + fprintf(stderr, "\n"); + } +#endif /* KSSL_DEBUG */ + + if (which & SSL3_CC_READ) { + if (s->s3->tmp.new_cipher->algorithm2 & TLS1_STREAM_MAC) + s->mac_flags |= SSL_MAC_FLAG_READ_MAC_STREAM; + else + s->mac_flags &= ~SSL_MAC_FLAG_READ_MAC_STREAM; + + if (s->enc_read_ctx != NULL) + reuse_dd = 1; + else if ((s->enc_read_ctx = + OPENSSL_malloc(sizeof(EVP_CIPHER_CTX))) == NULL) + goto err; + else + /* + * make sure it's intialized in case we exit later with an error + */ + EVP_CIPHER_CTX_init(s->enc_read_ctx); + dd = s->enc_read_ctx; + mac_ctx = ssl_replace_hash(&s->read_hash, NULL); + if (mac_ctx == NULL) + goto err; +#ifndef OPENSSL_NO_COMP + if (s->expand != NULL) { + COMP_CTX_free(s->expand); + s->expand = NULL; + } + if (comp != NULL) { + s->expand = COMP_CTX_new(comp->method); + if (s->expand == NULL) { + SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE, + SSL_R_COMPRESSION_LIBRARY_ERROR); + goto err2; + } + if (s->s3->rrec.comp == NULL) + s->s3->rrec.comp = (unsigned char *) + OPENSSL_malloc(SSL3_RT_MAX_ENCRYPTED_LENGTH); + if (s->s3->rrec.comp == NULL) + goto err; + } +#endif + /* + * this is done by dtls1_reset_seq_numbers for DTLS + */ + if (!SSL_IS_DTLS(s)) + memset(&(s->s3->read_sequence[0]), 0, 8); + mac_secret = &(s->s3->read_mac_secret[0]); + mac_secret_size = &(s->s3->read_mac_secret_size); + } else { + if (s->s3->tmp.new_cipher->algorithm2 & TLS1_STREAM_MAC) + s->mac_flags |= SSL_MAC_FLAG_WRITE_MAC_STREAM; + else + s->mac_flags &= ~SSL_MAC_FLAG_WRITE_MAC_STREAM; + if (s->enc_write_ctx != NULL && !SSL_IS_DTLS(s)) + reuse_dd = 1; + else if ((s->enc_write_ctx = EVP_CIPHER_CTX_new()) == NULL) + goto err; + dd = s->enc_write_ctx; + if (SSL_IS_DTLS(s)) { + mac_ctx = EVP_MD_CTX_create(); + if (mac_ctx == NULL) + goto err; + s->write_hash = mac_ctx; + } else { + mac_ctx = ssl_replace_hash(&s->write_hash, NULL); + if (mac_ctx == NULL) + goto err; + } +#ifndef OPENSSL_NO_COMP + if (s->compress != NULL) { + COMP_CTX_free(s->compress); + s->compress = NULL; + } + if (comp != NULL) { + s->compress = COMP_CTX_new(comp->method); + if (s->compress == NULL) { + SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE, + SSL_R_COMPRESSION_LIBRARY_ERROR); + goto err2; + } + } +#endif + /* + * this is done by dtls1_reset_seq_numbers for DTLS + */ + if (!SSL_IS_DTLS(s)) + memset(&(s->s3->write_sequence[0]), 0, 8); + mac_secret = &(s->s3->write_mac_secret[0]); + mac_secret_size = &(s->s3->write_mac_secret_size); + } + + if (reuse_dd) + EVP_CIPHER_CTX_cleanup(dd); + + p = s->s3->tmp.key_block; + i = *mac_secret_size = s->s3->tmp.new_mac_secret_size; + + cl = EVP_CIPHER_key_length(c); + j = is_export ? (cl < SSL_C_EXPORT_KEYLENGTH(s->s3->tmp.new_cipher) ? + cl : SSL_C_EXPORT_KEYLENGTH(s->s3->tmp.new_cipher)) : cl; + /* Was j=(exp)?5:EVP_CIPHER_key_length(c); */ + /* If GCM mode only part of IV comes from PRF */ + if (EVP_CIPHER_mode(c) == EVP_CIPH_GCM_MODE) + k = EVP_GCM_TLS_FIXED_IV_LEN; + else + k = EVP_CIPHER_iv_length(c); + if ((which == SSL3_CHANGE_CIPHER_CLIENT_WRITE) || + (which == SSL3_CHANGE_CIPHER_SERVER_READ)) { + ms = &(p[0]); + n = i + i; + key = &(p[n]); + n += j + j; + iv = &(p[n]); + n += k + k; + exp_label = (unsigned char *)TLS_MD_CLIENT_WRITE_KEY_CONST; + exp_label_len = TLS_MD_CLIENT_WRITE_KEY_CONST_SIZE; + client_write = 1; + } else { + n = i; + ms = &(p[n]); + n += i + j; + key = &(p[n]); + n += j + k; + iv = &(p[n]); + n += k; + exp_label = (unsigned char *)TLS_MD_SERVER_WRITE_KEY_CONST; + exp_label_len = TLS_MD_SERVER_WRITE_KEY_CONST_SIZE; + client_write = 0; + } + + if (n > s->s3->tmp.key_block_length) { + SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE, ERR_R_INTERNAL_ERROR); + goto err2; + } + + memcpy(mac_secret, ms, i); + + if (!(EVP_CIPHER_flags(c) & EVP_CIPH_FLAG_AEAD_CIPHER)) { + mac_key = EVP_PKEY_new_mac_key(mac_type, NULL, + mac_secret, *mac_secret_size); + if (mac_key == NULL + || EVP_DigestSignInit(mac_ctx, NULL, m, NULL, mac_key) <= 0) { + EVP_PKEY_free(mac_key); + SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE, ERR_R_INTERNAL_ERROR); + goto err2; + } + EVP_PKEY_free(mac_key); + } +#ifdef TLS_DEBUG + printf("which = %04X\nmac key=", which); + { + int z; + for (z = 0; z < i; z++) + printf("%02X%c", ms[z], ((z + 1) % 16) ? ' ' : '\n'); + } +#endif + if (is_export) { + /* + * In here I set both the read and write key/iv to the same value + * since only the correct one will be used :-). + */ + if (!tls1_PRF(ssl_get_algorithm2(s), + exp_label, exp_label_len, + s->s3->client_random, SSL3_RANDOM_SIZE, + s->s3->server_random, SSL3_RANDOM_SIZE, + NULL, 0, NULL, 0, + key, j, tmp1, tmp2, EVP_CIPHER_key_length(c))) + goto err2; + key = tmp1; + + if (k > 0) { + if (!tls1_PRF(ssl_get_algorithm2(s), + TLS_MD_IV_BLOCK_CONST, TLS_MD_IV_BLOCK_CONST_SIZE, + s->s3->client_random, SSL3_RANDOM_SIZE, + s->s3->server_random, SSL3_RANDOM_SIZE, + NULL, 0, NULL, 0, empty, 0, iv1, iv2, k * 2)) + goto err2; + if (client_write) + iv = iv1; + else + iv = &(iv1[k]); + } + } + + s->session->key_arg_length = 0; +#ifdef KSSL_DEBUG + { + int i; + fprintf(stderr, "EVP_CipherInit_ex(dd,c,key=,iv=,which)\n"); + fprintf(stderr, "\tkey= "); + for (i = 0; i < c->key_len; i++) + fprintf(stderr, "%02x", key[i]); + fprintf(stderr, "\n"); + fprintf(stderr, "\t iv= "); + for (i = 0; i < c->iv_len; i++) + fprintf(stderr, "%02x", iv[i]); + fprintf(stderr, "\n"); + } +#endif /* KSSL_DEBUG */ + + if (EVP_CIPHER_mode(c) == EVP_CIPH_GCM_MODE) { + if (!EVP_CipherInit_ex(dd, c, NULL, key, NULL, (which & SSL3_CC_WRITE)) + || !EVP_CIPHER_CTX_ctrl(dd, EVP_CTRL_GCM_SET_IV_FIXED, k, iv)) { + SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE, ERR_R_INTERNAL_ERROR); + goto err2; + } + } else { + if (!EVP_CipherInit_ex(dd, c, NULL, key, iv, (which & SSL3_CC_WRITE))) { + SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE, ERR_R_INTERNAL_ERROR); + goto err2; + } + } + /* Needed for "composite" AEADs, such as RC4-HMAC-MD5 */ + if ((EVP_CIPHER_flags(c) & EVP_CIPH_FLAG_AEAD_CIPHER) && *mac_secret_size + && !EVP_CIPHER_CTX_ctrl(dd, EVP_CTRL_AEAD_SET_MAC_KEY, + *mac_secret_size, mac_secret)) { + SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE, ERR_R_INTERNAL_ERROR); + goto err2; + } +#ifdef OPENSSL_SSL_TRACE_CRYPTO + if (s->msg_callback) { + int wh = which & SSL3_CC_WRITE ? TLS1_RT_CRYPTO_WRITE : 0; + if (*mac_secret_size) + s->msg_callback(2, s->version, wh | TLS1_RT_CRYPTO_MAC, + mac_secret, *mac_secret_size, + s, s->msg_callback_arg); + if (c->key_len) + s->msg_callback(2, s->version, wh | TLS1_RT_CRYPTO_KEY, + key, c->key_len, s, s->msg_callback_arg); + if (k) { + if (EVP_CIPHER_mode(c) == EVP_CIPH_GCM_MODE) + wh |= TLS1_RT_CRYPTO_FIXED_IV; + else + wh |= TLS1_RT_CRYPTO_IV; + s->msg_callback(2, s->version, wh, iv, k, s, s->msg_callback_arg); + } + } +#endif + +#ifdef TLS_DEBUG + printf("which = %04X\nkey=", which); + { + int z; + for (z = 0; z < EVP_CIPHER_key_length(c); z++) + printf("%02X%c", key[z], ((z + 1) % 16) ? ' ' : '\n'); + } + printf("\niv="); + { + int z; + for (z = 0; z < k; z++) + printf("%02X%c", iv[z], ((z + 1) % 16) ? ' ' : '\n'); + } + printf("\n"); +#endif + + OPENSSL_cleanse(tmp1, sizeof(tmp1)); + OPENSSL_cleanse(tmp2, sizeof(tmp1)); + OPENSSL_cleanse(iv1, sizeof(iv1)); + OPENSSL_cleanse(iv2, sizeof(iv2)); + return (1); + err: + SSLerr(SSL_F_TLS1_CHANGE_CIPHER_STATE, ERR_R_MALLOC_FAILURE); + err2: + return (0); +} + +int tls1_setup_key_block(SSL *s) +{ + unsigned char *p1, *p2 = NULL; + const EVP_CIPHER *c; + const EVP_MD *hash; + int num; + SSL_COMP *comp; + int mac_type = NID_undef, mac_secret_size = 0; + int ret = 0; + +#ifdef KSSL_DEBUG + fprintf(stderr, "tls1_setup_key_block()\n"); +#endif /* KSSL_DEBUG */ + + if (s->s3->tmp.key_block_length != 0) + return (1); + + if (!ssl_cipher_get_evp + (s->session, &c, &hash, &mac_type, &mac_secret_size, &comp)) { + SSLerr(SSL_F_TLS1_SETUP_KEY_BLOCK, SSL_R_CIPHER_OR_HASH_UNAVAILABLE); + return (0); + } + + s->s3->tmp.new_sym_enc = c; + s->s3->tmp.new_hash = hash; + s->s3->tmp.new_mac_pkey_type = mac_type; + s->s3->tmp.new_mac_secret_size = mac_secret_size; + num = + EVP_CIPHER_key_length(c) + mac_secret_size + EVP_CIPHER_iv_length(c); + num *= 2; + + ssl3_cleanup_key_block(s); + + if ((p1 = (unsigned char *)OPENSSL_malloc(num)) == NULL) { + SSLerr(SSL_F_TLS1_SETUP_KEY_BLOCK, ERR_R_MALLOC_FAILURE); + goto err; + } + + s->s3->tmp.key_block_length = num; + s->s3->tmp.key_block = p1; + + if ((p2 = (unsigned char *)OPENSSL_malloc(num)) == NULL) { + SSLerr(SSL_F_TLS1_SETUP_KEY_BLOCK, ERR_R_MALLOC_FAILURE); + OPENSSL_free(p1); + goto err; + } +#ifdef TLS_DEBUG + printf("client random\n"); + { + int z; + for (z = 0; z < SSL3_RANDOM_SIZE; z++) + printf("%02X%c", s->s3->client_random[z], + ((z + 1) % 16) ? ' ' : '\n'); + } + printf("server random\n"); + { + int z; + for (z = 0; z < SSL3_RANDOM_SIZE; z++) + printf("%02X%c", s->s3->server_random[z], + ((z + 1) % 16) ? ' ' : '\n'); + } + printf("pre-master\n"); + { + int z; + for (z = 0; z < s->session->master_key_length; z++) + printf("%02X%c", s->session->master_key[z], + ((z + 1) % 16) ? ' ' : '\n'); + } +#endif + if (!tls1_generate_key_block(s, p1, p2, num)) + goto err; +#ifdef TLS_DEBUG + printf("\nkey block\n"); + { + int z; + for (z = 0; z < num; z++) + printf("%02X%c", p1[z], ((z + 1) % 16) ? ' ' : '\n'); + } +#endif + + if (!(s->options & SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) + && s->method->version <= TLS1_VERSION) { + /* + * enable vulnerability countermeasure for CBC ciphers with known-IV + * problem (http://www.openssl.org/~bodo/tls-cbc.txt) + */ + s->s3->need_empty_fragments = 1; + + if (s->session->cipher != NULL) { + if (s->session->cipher->algorithm_enc == SSL_eNULL) + s->s3->need_empty_fragments = 0; + +#ifndef OPENSSL_NO_RC4 + if (s->session->cipher->algorithm_enc == SSL_RC4) + s->s3->need_empty_fragments = 0; +#endif + } + } + + ret = 1; + err: + if (p2) { + OPENSSL_cleanse(p2, num); + OPENSSL_free(p2); + } + return (ret); +} + +/*- + * tls1_enc encrypts/decrypts the record in |s->wrec| / |s->rrec|, respectively. + * + * Returns: + * 0: (in non-constant time) if the record is publically invalid (i.e. too + * short etc). + * 1: if the record's padding is valid / the encryption was successful. + * -1: if the record's padding/AEAD-authenticator is invalid or, if sending, + * an internal error occured. + */ +int tls1_enc(SSL *s, int send) +{ + SSL3_RECORD *rec; + EVP_CIPHER_CTX *ds; + unsigned long l; + int bs, i, j, k, pad = 0, ret, mac_size = 0; + const EVP_CIPHER *enc; + + if (send) { + if (EVP_MD_CTX_md(s->write_hash)) { + int n = EVP_MD_CTX_size(s->write_hash); + OPENSSL_assert(n >= 0); + } + ds = s->enc_write_ctx; + rec = &(s->s3->wrec); + if (s->enc_write_ctx == NULL) + enc = NULL; + else { + int ivlen; + enc = EVP_CIPHER_CTX_cipher(s->enc_write_ctx); + /* For TLSv1.1 and later explicit IV */ + if (SSL_USE_EXPLICIT_IV(s) + && EVP_CIPHER_mode(enc) == EVP_CIPH_CBC_MODE) + ivlen = EVP_CIPHER_iv_length(enc); + else + ivlen = 0; + if (ivlen > 1) { + if (rec->data != rec->input) + /* + * we can't write into the input stream: Can this ever + * happen?? (steve) + */ + fprintf(stderr, + "%s:%d: rec->data != rec->input\n", + __FILE__, __LINE__); + else if (RAND_bytes(rec->input, ivlen) <= 0) + return -1; + } + } + } else { + if (EVP_MD_CTX_md(s->read_hash)) { + int n = EVP_MD_CTX_size(s->read_hash); + OPENSSL_assert(n >= 0); + } + ds = s->enc_read_ctx; + rec = &(s->s3->rrec); + if (s->enc_read_ctx == NULL) + enc = NULL; + else + enc = EVP_CIPHER_CTX_cipher(s->enc_read_ctx); + } + +#ifdef KSSL_DEBUG + fprintf(stderr, "tls1_enc(%d)\n", send); +#endif /* KSSL_DEBUG */ + + if ((s->session == NULL) || (ds == NULL) || (enc == NULL)) { + memmove(rec->data, rec->input, rec->length); + rec->input = rec->data; + ret = 1; + } else { + l = rec->length; + bs = EVP_CIPHER_block_size(ds->cipher); + + if (EVP_CIPHER_flags(ds->cipher) & EVP_CIPH_FLAG_AEAD_CIPHER) { + unsigned char buf[EVP_AEAD_TLS1_AAD_LEN], *seq; + + seq = send ? s->s3->write_sequence : s->s3->read_sequence; + + if (SSL_IS_DTLS(s)) { + unsigned char dtlsseq[9], *p = dtlsseq; + + s2n(send ? s->d1->w_epoch : s->d1->r_epoch, p); + memcpy(p, &seq[2], 6); + memcpy(buf, dtlsseq, 8); + } else { + memcpy(buf, seq, 8); + for (i = 7; i >= 0; i--) { /* increment */ + ++seq[i]; + if (seq[i] != 0) + break; + } + } + + buf[8] = rec->type; + buf[9] = (unsigned char)(s->version >> 8); + buf[10] = (unsigned char)(s->version); + buf[11] = rec->length >> 8; + buf[12] = rec->length & 0xff; + pad = EVP_CIPHER_CTX_ctrl(ds, EVP_CTRL_AEAD_TLS1_AAD, + EVP_AEAD_TLS1_AAD_LEN, buf); + if (pad <= 0) + return -1; + if (send) { + l += pad; + rec->length += pad; + } + } else if ((bs != 1) && send) { + i = bs - ((int)l % bs); + + /* Add weird padding of upto 256 bytes */ + + /* we need to add 'i' padding bytes of value j */ + j = i - 1; + if (s->options & SSL_OP_TLS_BLOCK_PADDING_BUG) { + if (s->s3->flags & TLS1_FLAGS_TLS_PADDING_BUG) + j++; + } + for (k = (int)l; k < (int)(l + i); k++) + rec->input[k] = j; + l += i; + rec->length += i; + } +#ifdef KSSL_DEBUG + { + unsigned long ui; + fprintf(stderr, + "EVP_Cipher(ds=%p,rec->data=%p,rec->input=%p,l=%ld) ==>\n", + ds, rec->data, rec->input, l); + fprintf(stderr, + "\tEVP_CIPHER_CTX: %d buf_len, %d key_len [%lu %lu], %d iv_len\n", + ds->buf_len, ds->cipher->key_len, DES_KEY_SZ, + DES_SCHEDULE_SZ, ds->cipher->iv_len); + fprintf(stderr, "\t\tIV: "); + for (i = 0; i < ds->cipher->iv_len; i++) + fprintf(stderr, "%02X", ds->iv[i]); + fprintf(stderr, "\n"); + fprintf(stderr, "\trec->input="); + for (ui = 0; ui < l; ui++) + fprintf(stderr, " %02x", rec->input[ui]); + fprintf(stderr, "\n"); + } +#endif /* KSSL_DEBUG */ + + if (!send) { + if (l == 0 || l % bs != 0) + return 0; + } + + i = EVP_Cipher(ds, rec->data, rec->input, l); + if ((EVP_CIPHER_flags(ds->cipher) & EVP_CIPH_FLAG_CUSTOM_CIPHER) + ? (i < 0) + : (i == 0)) + return -1; /* AEAD can fail to verify MAC */ + if (EVP_CIPHER_mode(enc) == EVP_CIPH_GCM_MODE && !send) { + rec->data += EVP_GCM_TLS_EXPLICIT_IV_LEN; + rec->input += EVP_GCM_TLS_EXPLICIT_IV_LEN; + rec->length -= EVP_GCM_TLS_EXPLICIT_IV_LEN; + } +#ifdef KSSL_DEBUG + { + unsigned long i; + fprintf(stderr, "\trec->data="); + for (i = 0; i < l; i++) + fprintf(stderr, " %02x", rec->data[i]); + fprintf(stderr, "\n"); + } +#endif /* KSSL_DEBUG */ + + ret = 1; + if (EVP_MD_CTX_md(s->read_hash) != NULL) + mac_size = EVP_MD_CTX_size(s->read_hash); + if ((bs != 1) && !send) + ret = tls1_cbc_remove_padding(s, rec, bs, mac_size); + if (pad && !send) + rec->length -= pad; + } + return ret; +} + +int tls1_cert_verify_mac(SSL *s, int md_nid, unsigned char *out) +{ + unsigned int ret; + EVP_MD_CTX ctx, *d = NULL; + int i; + + if (s->s3->handshake_buffer) + if (!ssl3_digest_cached_records(s)) + return 0; + + for (i = 0; i < SSL_MAX_DIGEST; i++) { + if (s->s3->handshake_dgst[i] + && EVP_MD_CTX_type(s->s3->handshake_dgst[i]) == md_nid) { + d = s->s3->handshake_dgst[i]; + break; + } + } + if (!d) { + SSLerr(SSL_F_TLS1_CERT_VERIFY_MAC, SSL_R_NO_REQUIRED_DIGEST); + return 0; + } + + EVP_MD_CTX_init(&ctx); + if (EVP_MD_CTX_copy_ex(&ctx, d) <=0 + || EVP_DigestFinal_ex(&ctx, out, &ret) <= 0) + ret = 0; + EVP_MD_CTX_cleanup(&ctx); + return ((int)ret); +} + +int tls1_final_finish_mac(SSL *s, + const char *str, int slen, unsigned char *out) +{ + unsigned int i; + EVP_MD_CTX ctx; + unsigned char buf[2 * EVP_MAX_MD_SIZE]; + unsigned char *q, buf2[12]; + int idx; + long mask; + int err = 0; + const EVP_MD *md; + + q = buf; + + if (s->s3->handshake_buffer) + if (!ssl3_digest_cached_records(s)) + return 0; + + EVP_MD_CTX_init(&ctx); + + for (idx = 0; ssl_get_handshake_digest(idx, &mask, &md); idx++) { + if (mask & ssl_get_algorithm2(s)) { + int hashsize = EVP_MD_size(md); + EVP_MD_CTX *hdgst = s->s3->handshake_dgst[idx]; + if (!hdgst || hashsize < 0 + || hashsize > (int)(sizeof buf - (size_t)(q - buf))) { + /* + * internal error: 'buf' is too small for this cipersuite! + */ + err = 1; + } else { + if (!EVP_MD_CTX_copy_ex(&ctx, hdgst) || + !EVP_DigestFinal_ex(&ctx, q, &i) || + (i != (unsigned int)hashsize)) + err = 1; + q += hashsize; + } + } + } + + if (!tls1_PRF(ssl_get_algorithm2(s), + str, slen, buf, (int)(q - buf), NULL, 0, NULL, 0, NULL, 0, + s->session->master_key, s->session->master_key_length, + out, buf2, sizeof buf2)) + err = 1; + EVP_MD_CTX_cleanup(&ctx); + + OPENSSL_cleanse(buf, (int)(q - buf)); + OPENSSL_cleanse(buf2, sizeof(buf2)); + if (err) + return 0; + else + return sizeof buf2; +} + +int tls1_mac(SSL *ssl, unsigned char *md, int send) +{ + SSL3_RECORD *rec; + unsigned char *seq; + EVP_MD_CTX *hash; + size_t md_size, orig_len; + int i; + EVP_MD_CTX hmac, *mac_ctx; + unsigned char header[13]; + int stream_mac = (send ? (ssl->mac_flags & SSL_MAC_FLAG_WRITE_MAC_STREAM) + : (ssl->mac_flags & SSL_MAC_FLAG_READ_MAC_STREAM)); + int t; + + if (send) { + rec = &(ssl->s3->wrec); + seq = &(ssl->s3->write_sequence[0]); + hash = ssl->write_hash; + } else { + rec = &(ssl->s3->rrec); + seq = &(ssl->s3->read_sequence[0]); + hash = ssl->read_hash; + } + + t = EVP_MD_CTX_size(hash); + OPENSSL_assert(t >= 0); + md_size = t; + + /* I should fix this up TLS TLS TLS TLS TLS XXXXXXXX */ + if (stream_mac) { + mac_ctx = hash; + } else { + if (!EVP_MD_CTX_copy(&hmac, hash)) + return -1; + mac_ctx = &hmac; + } + + if (SSL_IS_DTLS(ssl)) { + unsigned char dtlsseq[8], *p = dtlsseq; + + s2n(send ? ssl->d1->w_epoch : ssl->d1->r_epoch, p); + memcpy(p, &seq[2], 6); + + memcpy(header, dtlsseq, 8); + } else + memcpy(header, seq, 8); + + /* + * kludge: tls1_cbc_remove_padding passes padding length in rec->type + */ + orig_len = rec->length + md_size + ((unsigned int)rec->type >> 8); + rec->type &= 0xff; + + header[8] = rec->type; + header[9] = (unsigned char)(ssl->version >> 8); + header[10] = (unsigned char)(ssl->version); + header[11] = (rec->length) >> 8; + header[12] = (rec->length) & 0xff; + + if (!send && + EVP_CIPHER_CTX_mode(ssl->enc_read_ctx) == EVP_CIPH_CBC_MODE && + ssl3_cbc_record_digest_supported(mac_ctx)) { + /* + * This is a CBC-encrypted record. We must avoid leaking any + * timing-side channel information about how many blocks of data we + * are hashing because that gives an attacker a timing-oracle. + */ + /* Final param == not SSLv3 */ + if (ssl3_cbc_digest_record(mac_ctx, + md, &md_size, + header, rec->input, + rec->length + md_size, orig_len, + ssl->s3->read_mac_secret, + ssl->s3->read_mac_secret_size, 0) <= 0) { + if (!stream_mac) + EVP_MD_CTX_cleanup(&hmac); + return -1; + } + } else { + if (EVP_DigestSignUpdate(mac_ctx, header, sizeof(header)) <= 0 + || EVP_DigestSignUpdate(mac_ctx, rec->input, rec->length) <= 0 + || EVP_DigestSignFinal(mac_ctx, md, &md_size) <= 0) { + if (!stream_mac) + EVP_MD_CTX_cleanup(&hmac); + return -1; + } +#ifdef OPENSSL_FIPS + if (!send && FIPS_mode()) + tls_fips_digest_extra(ssl->enc_read_ctx, + mac_ctx, rec->input, rec->length, orig_len); +#endif + } + + if (!stream_mac) + EVP_MD_CTX_cleanup(&hmac); +#ifdef TLS_DEBUG + fprintf(stderr, "seq="); + { + int z; + for (z = 0; z < 8; z++) + fprintf(stderr, "%02X ", seq[z]); + fprintf(stderr, "\n"); + } + fprintf(stderr, "rec="); + { + unsigned int z; + for (z = 0; z < rec->length; z++) + fprintf(stderr, "%02X ", rec->data[z]); + fprintf(stderr, "\n"); + } +#endif + + if (!SSL_IS_DTLS(ssl)) { + for (i = 7; i >= 0; i--) { + ++seq[i]; + if (seq[i] != 0) + break; + } + } +#ifdef TLS_DEBUG + { + unsigned int z; + for (z = 0; z < md_size; z++) + fprintf(stderr, "%02X ", md[z]); + fprintf(stderr, "\n"); + } +#endif + return (md_size); +} + +int tls1_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p, + int len) +{ + unsigned char buff[SSL_MAX_MASTER_KEY_LENGTH]; + const void *co = NULL, *so = NULL; + int col = 0, sol = 0; + +#ifdef KSSL_DEBUG + fprintf(stderr, "tls1_generate_master_secret(%p,%p, %p, %d)\n", s, out, p, + len); +#endif /* KSSL_DEBUG */ + +#ifdef TLSEXT_TYPE_opaque_prf_input + if (s->s3->client_opaque_prf_input != NULL + && s->s3->server_opaque_prf_input != NULL + && s->s3->client_opaque_prf_input_len > 0 + && s->s3->client_opaque_prf_input_len == + s->s3->server_opaque_prf_input_len) { + co = s->s3->client_opaque_prf_input; + col = s->s3->server_opaque_prf_input_len; + so = s->s3->server_opaque_prf_input; + /* + * must be same as col (see + * draft-rescorla-tls-opaque-prf-input-00.txt, section 3.1) + */ + sol = s->s3->client_opaque_prf_input_len; + } +#endif + + tls1_PRF(ssl_get_algorithm2(s), + TLS_MD_MASTER_SECRET_CONST, TLS_MD_MASTER_SECRET_CONST_SIZE, + s->s3->client_random, SSL3_RANDOM_SIZE, + co, col, + s->s3->server_random, SSL3_RANDOM_SIZE, + so, sol, p, len, s->session->master_key, buff, sizeof buff); + OPENSSL_cleanse(buff, sizeof buff); +#ifdef SSL_DEBUG + fprintf(stderr, "Premaster Secret:\n"); + BIO_dump_fp(stderr, (char *)p, len); + fprintf(stderr, "Client Random:\n"); + BIO_dump_fp(stderr, (char *)s->s3->client_random, SSL3_RANDOM_SIZE); + fprintf(stderr, "Server Random:\n"); + BIO_dump_fp(stderr, (char *)s->s3->server_random, SSL3_RANDOM_SIZE); + fprintf(stderr, "Master Secret:\n"); + BIO_dump_fp(stderr, (char *)s->session->master_key, + SSL3_MASTER_SECRET_SIZE); +#endif + +#ifdef OPENSSL_SSL_TRACE_CRYPTO + if (s->msg_callback) { + s->msg_callback(2, s->version, TLS1_RT_CRYPTO_PREMASTER, + p, len, s, s->msg_callback_arg); + s->msg_callback(2, s->version, TLS1_RT_CRYPTO_CLIENT_RANDOM, + s->s3->client_random, SSL3_RANDOM_SIZE, + s, s->msg_callback_arg); + s->msg_callback(2, s->version, TLS1_RT_CRYPTO_SERVER_RANDOM, + s->s3->server_random, SSL3_RANDOM_SIZE, + s, s->msg_callback_arg); + s->msg_callback(2, s->version, TLS1_RT_CRYPTO_MASTER, + s->session->master_key, + SSL3_MASTER_SECRET_SIZE, s, s->msg_callback_arg); + } +#endif + +#ifdef KSSL_DEBUG + fprintf(stderr, "tls1_generate_master_secret() complete\n"); +#endif /* KSSL_DEBUG */ + return (SSL3_MASTER_SECRET_SIZE); +} + +int tls1_export_keying_material(SSL *s, unsigned char *out, size_t olen, + const char *label, size_t llen, + const unsigned char *context, + size_t contextlen, int use_context) +{ + unsigned char *buff; + unsigned char *val = NULL; + size_t vallen, currentvalpos; + int rv; + +#ifdef KSSL_DEBUG + fprintf(stderr, "tls1_export_keying_material(%p,%p,%lu,%s,%lu,%p,%lu)\n", + s, out, olen, label, llen, context, contextlen); +#endif /* KSSL_DEBUG */ + + buff = OPENSSL_malloc(olen); + if (buff == NULL) + goto err2; + + /* + * construct PRF arguments we construct the PRF argument ourself rather + * than passing separate values into the TLS PRF to ensure that the + * concatenation of values does not create a prohibited label. + */ + vallen = llen + SSL3_RANDOM_SIZE * 2; + if (use_context) { + vallen += 2 + contextlen; + } + + val = OPENSSL_malloc(vallen); + if (val == NULL) + goto err2; + currentvalpos = 0; + memcpy(val + currentvalpos, (unsigned char *)label, llen); + currentvalpos += llen; + memcpy(val + currentvalpos, s->s3->client_random, SSL3_RANDOM_SIZE); + currentvalpos += SSL3_RANDOM_SIZE; + memcpy(val + currentvalpos, s->s3->server_random, SSL3_RANDOM_SIZE); + currentvalpos += SSL3_RANDOM_SIZE; + + if (use_context) { + val[currentvalpos] = (contextlen >> 8) & 0xff; + currentvalpos++; + val[currentvalpos] = contextlen & 0xff; + currentvalpos++; + if ((contextlen > 0) || (context != NULL)) { + memcpy(val + currentvalpos, context, contextlen); + } + } + + /* + * disallow prohibited labels note that SSL3_RANDOM_SIZE > max(prohibited + * label len) = 15, so size of val > max(prohibited label len) = 15 and + * the comparisons won't have buffer overflow + */ + if (memcmp(val, TLS_MD_CLIENT_FINISH_CONST, + TLS_MD_CLIENT_FINISH_CONST_SIZE) == 0) + goto err1; + if (memcmp(val, TLS_MD_SERVER_FINISH_CONST, + TLS_MD_SERVER_FINISH_CONST_SIZE) == 0) + goto err1; + if (memcmp(val, TLS_MD_MASTER_SECRET_CONST, + TLS_MD_MASTER_SECRET_CONST_SIZE) == 0) + goto err1; + if (memcmp(val, TLS_MD_KEY_EXPANSION_CONST, + TLS_MD_KEY_EXPANSION_CONST_SIZE) == 0) + goto err1; + + rv = tls1_PRF(ssl_get_algorithm2(s), + val, vallen, + NULL, 0, + NULL, 0, + NULL, 0, + NULL, 0, + s->session->master_key, s->session->master_key_length, + out, buff, olen); + OPENSSL_cleanse(val, vallen); + OPENSSL_cleanse(buff, olen); + +#ifdef KSSL_DEBUG + fprintf(stderr, "tls1_export_keying_material() complete\n"); +#endif /* KSSL_DEBUG */ + goto ret; + err1: + SSLerr(SSL_F_TLS1_EXPORT_KEYING_MATERIAL, + SSL_R_TLS_ILLEGAL_EXPORTER_LABEL); + rv = 0; + goto ret; + err2: + SSLerr(SSL_F_TLS1_EXPORT_KEYING_MATERIAL, ERR_R_MALLOC_FAILURE); + rv = 0; + ret: + if (buff != NULL) + OPENSSL_free(buff); + if (val != NULL) + OPENSSL_free(val); + return (rv); +} + +int tls1_alert_code(int code) +{ + switch (code) { + case SSL_AD_CLOSE_NOTIFY: + return (SSL3_AD_CLOSE_NOTIFY); + case SSL_AD_UNEXPECTED_MESSAGE: + return (SSL3_AD_UNEXPECTED_MESSAGE); + case SSL_AD_BAD_RECORD_MAC: + return (SSL3_AD_BAD_RECORD_MAC); + case SSL_AD_DECRYPTION_FAILED: + return (TLS1_AD_DECRYPTION_FAILED); + case SSL_AD_RECORD_OVERFLOW: + return (TLS1_AD_RECORD_OVERFLOW); + case SSL_AD_DECOMPRESSION_FAILURE: + return (SSL3_AD_DECOMPRESSION_FAILURE); + case SSL_AD_HANDSHAKE_FAILURE: + return (SSL3_AD_HANDSHAKE_FAILURE); + case SSL_AD_NO_CERTIFICATE: + return (-1); + case SSL_AD_BAD_CERTIFICATE: + return (SSL3_AD_BAD_CERTIFICATE); + case SSL_AD_UNSUPPORTED_CERTIFICATE: + return (SSL3_AD_UNSUPPORTED_CERTIFICATE); + case SSL_AD_CERTIFICATE_REVOKED: + return (SSL3_AD_CERTIFICATE_REVOKED); + case SSL_AD_CERTIFICATE_EXPIRED: + return (SSL3_AD_CERTIFICATE_EXPIRED); + case SSL_AD_CERTIFICATE_UNKNOWN: + return (SSL3_AD_CERTIFICATE_UNKNOWN); + case SSL_AD_ILLEGAL_PARAMETER: + return (SSL3_AD_ILLEGAL_PARAMETER); + case SSL_AD_UNKNOWN_CA: + return (TLS1_AD_UNKNOWN_CA); + case SSL_AD_ACCESS_DENIED: + return (TLS1_AD_ACCESS_DENIED); + case SSL_AD_DECODE_ERROR: + return (TLS1_AD_DECODE_ERROR); + case SSL_AD_DECRYPT_ERROR: + return (TLS1_AD_DECRYPT_ERROR); + case SSL_AD_EXPORT_RESTRICTION: + return (TLS1_AD_EXPORT_RESTRICTION); + case SSL_AD_PROTOCOL_VERSION: + return (TLS1_AD_PROTOCOL_VERSION); + case SSL_AD_INSUFFICIENT_SECURITY: + return (TLS1_AD_INSUFFICIENT_SECURITY); + case SSL_AD_INTERNAL_ERROR: + return (TLS1_AD_INTERNAL_ERROR); + case SSL_AD_USER_CANCELLED: + return (TLS1_AD_USER_CANCELLED); + case SSL_AD_NO_RENEGOTIATION: + return (TLS1_AD_NO_RENEGOTIATION); + case SSL_AD_UNSUPPORTED_EXTENSION: + return (TLS1_AD_UNSUPPORTED_EXTENSION); + case SSL_AD_CERTIFICATE_UNOBTAINABLE: + return (TLS1_AD_CERTIFICATE_UNOBTAINABLE); + case SSL_AD_UNRECOGNIZED_NAME: + return (TLS1_AD_UNRECOGNIZED_NAME); + case SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE: + return (TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE); + case SSL_AD_BAD_CERTIFICATE_HASH_VALUE: + return (TLS1_AD_BAD_CERTIFICATE_HASH_VALUE); + case SSL_AD_UNKNOWN_PSK_IDENTITY: + return (TLS1_AD_UNKNOWN_PSK_IDENTITY); + case SSL_AD_INAPPROPRIATE_FALLBACK: + return (TLS1_AD_INAPPROPRIATE_FALLBACK); +#if 0 + /* not appropriate for TLS, not used for DTLS */ + case DTLS1_AD_MISSING_HANDSHAKE_MESSAGE: + return (DTLS1_AD_MISSING_HANDSHAKE_MESSAGE); +#endif + default: + return (-1); + } +} diff --git a/thirdparty/openssl/ssl/t1_ext.c b/thirdparty/openssl/ssl/t1_ext.c new file mode 100644 index 0000000000..724ddf76ac --- /dev/null +++ b/thirdparty/openssl/ssl/t1_ext.c @@ -0,0 +1,298 @@ +/* ssl/t1_ext.c */ +/* ==================================================================== + * Copyright (c) 2014 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). + * + */ + +/* Custom extension utility functions */ + +#include "ssl_locl.h" + +#ifndef OPENSSL_NO_TLSEXT + +/* Find a custom extension from the list. */ +static custom_ext_method *custom_ext_find(custom_ext_methods *exts, + unsigned int ext_type) +{ + size_t i; + custom_ext_method *meth = exts->meths; + for (i = 0; i < exts->meths_count; i++, meth++) { + if (ext_type == meth->ext_type) + return meth; + } + return NULL; +} + +/* + * Initialise custom extensions flags to indicate neither sent nor received. + */ +void custom_ext_init(custom_ext_methods *exts) +{ + size_t i; + custom_ext_method *meth = exts->meths; + for (i = 0; i < exts->meths_count; i++, meth++) + meth->ext_flags = 0; +} + +/* Pass received custom extension data to the application for parsing. */ +int custom_ext_parse(SSL *s, int server, + unsigned int ext_type, + const unsigned char *ext_data, size_t ext_size, int *al) +{ + custom_ext_methods *exts = server ? &s->cert->srv_ext : &s->cert->cli_ext; + custom_ext_method *meth; + meth = custom_ext_find(exts, ext_type); + /* If not found return success */ + if (!meth) + return 1; + if (!server) { + /* + * If it's ServerHello we can't have any extensions not sent in + * ClientHello. + */ + if (!(meth->ext_flags & SSL_EXT_FLAG_SENT)) { + *al = TLS1_AD_UNSUPPORTED_EXTENSION; + return 0; + } + } + /* If already present it's a duplicate */ + if (meth->ext_flags & SSL_EXT_FLAG_RECEIVED) { + *al = TLS1_AD_DECODE_ERROR; + return 0; + } + meth->ext_flags |= SSL_EXT_FLAG_RECEIVED; + /* If no parse function set return success */ + if (!meth->parse_cb) + return 1; + + return meth->parse_cb(s, ext_type, ext_data, ext_size, al, + meth->parse_arg); +} + +/* + * Request custom extension data from the application and add to the return + * buffer. + */ +int custom_ext_add(SSL *s, int server, + unsigned char **pret, unsigned char *limit, int *al) +{ + custom_ext_methods *exts = server ? &s->cert->srv_ext : &s->cert->cli_ext; + custom_ext_method *meth; + unsigned char *ret = *pret; + size_t i; + + for (i = 0; i < exts->meths_count; i++) { + const unsigned char *out = NULL; + size_t outlen = 0; + meth = exts->meths + i; + + if (server) { + /* + * For ServerHello only send extensions present in ClientHello. + */ + if (!(meth->ext_flags & SSL_EXT_FLAG_RECEIVED)) + continue; + /* If callback absent for server skip it */ + if (!meth->add_cb) + continue; + } + if (meth->add_cb) { + int cb_retval = 0; + cb_retval = meth->add_cb(s, meth->ext_type, + &out, &outlen, al, meth->add_arg); + if (cb_retval < 0) + return 0; /* error */ + if (cb_retval == 0) + continue; /* skip this extension */ + } + if (4 > limit - ret || outlen > (size_t)(limit - ret - 4)) + return 0; + s2n(meth->ext_type, ret); + s2n(outlen, ret); + if (outlen) { + memcpy(ret, out, outlen); + ret += outlen; + } + /* + * We can't send duplicates: code logic should prevent this. + */ + OPENSSL_assert(!(meth->ext_flags & SSL_EXT_FLAG_SENT)); + /* + * Indicate extension has been sent: this is both a sanity check to + * ensure we don't send duplicate extensions and indicates that it is + * not an error if the extension is present in ServerHello. + */ + meth->ext_flags |= SSL_EXT_FLAG_SENT; + if (meth->free_cb) + meth->free_cb(s, meth->ext_type, out, meth->add_arg); + } + *pret = ret; + return 1; +} + +/* Copy table of custom extensions */ +int custom_exts_copy(custom_ext_methods *dst, const custom_ext_methods *src) +{ + if (src->meths_count) { + dst->meths = + BUF_memdup(src->meths, + sizeof(custom_ext_method) * src->meths_count); + if (dst->meths == NULL) + return 0; + dst->meths_count = src->meths_count; + } + return 1; +} + +void custom_exts_free(custom_ext_methods *exts) +{ + if (exts->meths) + OPENSSL_free(exts->meths); +} + +/* Set callbacks for a custom extension. */ +static int custom_ext_meth_add(custom_ext_methods *exts, + unsigned int ext_type, + custom_ext_add_cb add_cb, + custom_ext_free_cb free_cb, + void *add_arg, + custom_ext_parse_cb parse_cb, void *parse_arg) +{ + custom_ext_method *meth; + /* + * Check application error: if add_cb is not set free_cb will never be + * called. + */ + if (!add_cb && free_cb) + return 0; + /* Don't add if extension supported internally. */ + if (SSL_extension_supported(ext_type)) + return 0; + /* Extension type must fit in 16 bits */ + if (ext_type > 0xffff) + return 0; + /* Search for duplicate */ + if (custom_ext_find(exts, ext_type)) + return 0; + exts->meths = OPENSSL_realloc(exts->meths, + (exts->meths_count + + 1) * sizeof(custom_ext_method)); + + if (!exts->meths) { + exts->meths_count = 0; + return 0; + } + + meth = exts->meths + exts->meths_count; + memset(meth, 0, sizeof(custom_ext_method)); + meth->parse_cb = parse_cb; + meth->add_cb = add_cb; + meth->free_cb = free_cb; + meth->ext_type = ext_type; + meth->add_arg = add_arg; + meth->parse_arg = parse_arg; + exts->meths_count++; + return 1; +} + +/* Application level functions to add custom extension callbacks */ +int SSL_CTX_add_client_custom_ext(SSL_CTX *ctx, unsigned int ext_type, + custom_ext_add_cb add_cb, + custom_ext_free_cb free_cb, + void *add_arg, + custom_ext_parse_cb parse_cb, + void *parse_arg) +{ + return custom_ext_meth_add(&ctx->cert->cli_ext, ext_type, + add_cb, free_cb, add_arg, parse_cb, parse_arg); +} + +int SSL_CTX_add_server_custom_ext(SSL_CTX *ctx, unsigned int ext_type, + custom_ext_add_cb add_cb, + custom_ext_free_cb free_cb, + void *add_arg, + custom_ext_parse_cb parse_cb, + void *parse_arg) +{ + return custom_ext_meth_add(&ctx->cert->srv_ext, ext_type, + add_cb, free_cb, add_arg, parse_cb, parse_arg); +} + +int SSL_extension_supported(unsigned int ext_type) +{ + switch (ext_type) { + /* Internally supported extensions. */ + case TLSEXT_TYPE_application_layer_protocol_negotiation: + case TLSEXT_TYPE_ec_point_formats: + case TLSEXT_TYPE_elliptic_curves: + case TLSEXT_TYPE_heartbeat: + case TLSEXT_TYPE_next_proto_neg: + case TLSEXT_TYPE_padding: + case TLSEXT_TYPE_renegotiate: + case TLSEXT_TYPE_server_name: + case TLSEXT_TYPE_session_ticket: + case TLSEXT_TYPE_signature_algorithms: + case TLSEXT_TYPE_srp: + case TLSEXT_TYPE_status_request: + case TLSEXT_TYPE_use_srtp: +# ifdef TLSEXT_TYPE_opaque_prf_input + case TLSEXT_TYPE_opaque_prf_input: +# endif +# ifdef TLSEXT_TYPE_encrypt_then_mac + case TLSEXT_TYPE_encrypt_then_mac: +# endif + return 1; + default: + return 0; + } +} +#endif diff --git a/thirdparty/openssl/ssl/t1_lib.c b/thirdparty/openssl/ssl/t1_lib.c new file mode 100644 index 0000000000..dd5bd0050d --- /dev/null +++ b/thirdparty/openssl/ssl/t1_lib.c @@ -0,0 +1,4439 @@ +/* ssl/t1_lib.c */ +/* 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). + * + */ + +#include <stdio.h> +#include <openssl/objects.h> +#include <openssl/evp.h> +#include <openssl/hmac.h> +#ifndef OPENSSL_NO_EC +#ifdef OPENSSL_NO_EC2M +# include <openssl/ec.h> +#endif +#endif +#include <openssl/ocsp.h> +#include <openssl/rand.h> +#include "ssl_locl.h" + +const char tls1_version_str[] = "TLSv1" OPENSSL_VERSION_PTEXT; + +#ifndef OPENSSL_NO_TLSEXT +static int tls_decrypt_ticket(SSL *s, const unsigned char *tick, int ticklen, + const unsigned char *sess_id, int sesslen, + SSL_SESSION **psess); +static int ssl_check_clienthello_tlsext_early(SSL *s); +int ssl_check_serverhello_tlsext(SSL *s); +#endif + +SSL3_ENC_METHOD TLSv1_enc_data = { + tls1_enc, + tls1_mac, + tls1_setup_key_block, + tls1_generate_master_secret, + tls1_change_cipher_state, + tls1_final_finish_mac, + TLS1_FINISH_MAC_LENGTH, + tls1_cert_verify_mac, + TLS_MD_CLIENT_FINISH_CONST, TLS_MD_CLIENT_FINISH_CONST_SIZE, + TLS_MD_SERVER_FINISH_CONST, TLS_MD_SERVER_FINISH_CONST_SIZE, + tls1_alert_code, + tls1_export_keying_material, + 0, + SSL3_HM_HEADER_LENGTH, + ssl3_set_handshake_header, + ssl3_handshake_write +}; + +SSL3_ENC_METHOD TLSv1_1_enc_data = { + tls1_enc, + tls1_mac, + tls1_setup_key_block, + tls1_generate_master_secret, + tls1_change_cipher_state, + tls1_final_finish_mac, + TLS1_FINISH_MAC_LENGTH, + tls1_cert_verify_mac, + TLS_MD_CLIENT_FINISH_CONST, TLS_MD_CLIENT_FINISH_CONST_SIZE, + TLS_MD_SERVER_FINISH_CONST, TLS_MD_SERVER_FINISH_CONST_SIZE, + tls1_alert_code, + tls1_export_keying_material, + SSL_ENC_FLAG_EXPLICIT_IV, + SSL3_HM_HEADER_LENGTH, + ssl3_set_handshake_header, + ssl3_handshake_write +}; + +SSL3_ENC_METHOD TLSv1_2_enc_data = { + tls1_enc, + tls1_mac, + tls1_setup_key_block, + tls1_generate_master_secret, + tls1_change_cipher_state, + tls1_final_finish_mac, + TLS1_FINISH_MAC_LENGTH, + tls1_cert_verify_mac, + TLS_MD_CLIENT_FINISH_CONST, TLS_MD_CLIENT_FINISH_CONST_SIZE, + TLS_MD_SERVER_FINISH_CONST, TLS_MD_SERVER_FINISH_CONST_SIZE, + tls1_alert_code, + tls1_export_keying_material, + SSL_ENC_FLAG_EXPLICIT_IV | SSL_ENC_FLAG_SIGALGS | SSL_ENC_FLAG_SHA256_PRF + | SSL_ENC_FLAG_TLS1_2_CIPHERS, + SSL3_HM_HEADER_LENGTH, + ssl3_set_handshake_header, + ssl3_handshake_write +}; + +long tls1_default_timeout(void) +{ + /* + * 2 hours, the 24 hours mentioned in the TLSv1 spec is way too long for + * http, the cache would over fill + */ + return (60 * 60 * 2); +} + +int tls1_new(SSL *s) +{ + if (!ssl3_new(s)) + return (0); + s->method->ssl_clear(s); + return (1); +} + +void tls1_free(SSL *s) +{ +#ifndef OPENSSL_NO_TLSEXT + if (s->tlsext_session_ticket) { + OPENSSL_free(s->tlsext_session_ticket); + } +#endif /* OPENSSL_NO_TLSEXT */ + ssl3_free(s); +} + +void tls1_clear(SSL *s) +{ + ssl3_clear(s); + s->version = s->method->version; +} + +#ifndef OPENSSL_NO_EC + +static int nid_list[] = { + NID_sect163k1, /* sect163k1 (1) */ + NID_sect163r1, /* sect163r1 (2) */ + NID_sect163r2, /* sect163r2 (3) */ + NID_sect193r1, /* sect193r1 (4) */ + NID_sect193r2, /* sect193r2 (5) */ + NID_sect233k1, /* sect233k1 (6) */ + NID_sect233r1, /* sect233r1 (7) */ + NID_sect239k1, /* sect239k1 (8) */ + NID_sect283k1, /* sect283k1 (9) */ + NID_sect283r1, /* sect283r1 (10) */ + NID_sect409k1, /* sect409k1 (11) */ + NID_sect409r1, /* sect409r1 (12) */ + NID_sect571k1, /* sect571k1 (13) */ + NID_sect571r1, /* sect571r1 (14) */ + NID_secp160k1, /* secp160k1 (15) */ + NID_secp160r1, /* secp160r1 (16) */ + NID_secp160r2, /* secp160r2 (17) */ + NID_secp192k1, /* secp192k1 (18) */ + NID_X9_62_prime192v1, /* secp192r1 (19) */ + NID_secp224k1, /* secp224k1 (20) */ + NID_secp224r1, /* secp224r1 (21) */ + NID_secp256k1, /* secp256k1 (22) */ + NID_X9_62_prime256v1, /* secp256r1 (23) */ + NID_secp384r1, /* secp384r1 (24) */ + NID_secp521r1, /* secp521r1 (25) */ + NID_brainpoolP256r1, /* brainpoolP256r1 (26) */ + NID_brainpoolP384r1, /* brainpoolP384r1 (27) */ + NID_brainpoolP512r1 /* brainpool512r1 (28) */ +}; + +static const unsigned char ecformats_default[] = { + TLSEXT_ECPOINTFORMAT_uncompressed, + TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime, + TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2 +}; + +/* The client's default curves / the server's 'auto' curves. */ +static const unsigned char eccurves_auto[] = { + /* Prefer P-256 which has the fastest and most secure implementations. */ + 0, 23, /* secp256r1 (23) */ + /* Other >= 256-bit prime curves. */ + 0, 25, /* secp521r1 (25) */ + 0, 28, /* brainpool512r1 (28) */ + 0, 27, /* brainpoolP384r1 (27) */ + 0, 24, /* secp384r1 (24) */ + 0, 26, /* brainpoolP256r1 (26) */ + 0, 22, /* secp256k1 (22) */ +# ifndef OPENSSL_NO_EC2M + /* >= 256-bit binary curves. */ + 0, 14, /* sect571r1 (14) */ + 0, 13, /* sect571k1 (13) */ + 0, 11, /* sect409k1 (11) */ + 0, 12, /* sect409r1 (12) */ + 0, 9, /* sect283k1 (9) */ + 0, 10, /* sect283r1 (10) */ +# endif +}; + +static const unsigned char eccurves_all[] = { + /* Prefer P-256 which has the fastest and most secure implementations. */ + 0, 23, /* secp256r1 (23) */ + /* Other >= 256-bit prime curves. */ + 0, 25, /* secp521r1 (25) */ + 0, 28, /* brainpool512r1 (28) */ + 0, 27, /* brainpoolP384r1 (27) */ + 0, 24, /* secp384r1 (24) */ + 0, 26, /* brainpoolP256r1 (26) */ + 0, 22, /* secp256k1 (22) */ +# ifndef OPENSSL_NO_EC2M + /* >= 256-bit binary curves. */ + 0, 14, /* sect571r1 (14) */ + 0, 13, /* sect571k1 (13) */ + 0, 11, /* sect409k1 (11) */ + 0, 12, /* sect409r1 (12) */ + 0, 9, /* sect283k1 (9) */ + 0, 10, /* sect283r1 (10) */ +# endif + /* + * Remaining curves disabled by default but still permitted if set + * via an explicit callback or parameters. + */ + 0, 20, /* secp224k1 (20) */ + 0, 21, /* secp224r1 (21) */ + 0, 18, /* secp192k1 (18) */ + 0, 19, /* secp192r1 (19) */ + 0, 15, /* secp160k1 (15) */ + 0, 16, /* secp160r1 (16) */ + 0, 17, /* secp160r2 (17) */ +# ifndef OPENSSL_NO_EC2M + 0, 8, /* sect239k1 (8) */ + 0, 6, /* sect233k1 (6) */ + 0, 7, /* sect233r1 (7) */ + 0, 4, /* sect193r1 (4) */ + 0, 5, /* sect193r2 (5) */ + 0, 1, /* sect163k1 (1) */ + 0, 2, /* sect163r1 (2) */ + 0, 3, /* sect163r2 (3) */ +# endif +}; + +static const unsigned char suiteb_curves[] = { + 0, TLSEXT_curve_P_256, + 0, TLSEXT_curve_P_384 +}; + +# ifdef OPENSSL_FIPS +/* Brainpool not allowed in FIPS mode */ +static const unsigned char fips_curves_default[] = { +# ifndef OPENSSL_NO_EC2M + 0, 14, /* sect571r1 (14) */ + 0, 13, /* sect571k1 (13) */ +# endif + 0, 25, /* secp521r1 (25) */ +# ifndef OPENSSL_NO_EC2M + 0, 11, /* sect409k1 (11) */ + 0, 12, /* sect409r1 (12) */ +# endif + 0, 24, /* secp384r1 (24) */ +# ifndef OPENSSL_NO_EC2M + 0, 9, /* sect283k1 (9) */ + 0, 10, /* sect283r1 (10) */ +# endif + 0, 22, /* secp256k1 (22) */ + 0, 23, /* secp256r1 (23) */ +# ifndef OPENSSL_NO_EC2M + 0, 8, /* sect239k1 (8) */ + 0, 6, /* sect233k1 (6) */ + 0, 7, /* sect233r1 (7) */ +# endif + 0, 20, /* secp224k1 (20) */ + 0, 21, /* secp224r1 (21) */ +# ifndef OPENSSL_NO_EC2M + 0, 4, /* sect193r1 (4) */ + 0, 5, /* sect193r2 (5) */ +# endif + 0, 18, /* secp192k1 (18) */ + 0, 19, /* secp192r1 (19) */ +# ifndef OPENSSL_NO_EC2M + 0, 1, /* sect163k1 (1) */ + 0, 2, /* sect163r1 (2) */ + 0, 3, /* sect163r2 (3) */ +# endif + 0, 15, /* secp160k1 (15) */ + 0, 16, /* secp160r1 (16) */ + 0, 17, /* secp160r2 (17) */ +}; +# endif + +int tls1_ec_curve_id2nid(int curve_id) +{ + /* ECC curves from RFC 4492 and RFC 7027 */ + if ((curve_id < 1) || ((unsigned int)curve_id > + sizeof(nid_list) / sizeof(nid_list[0]))) + return 0; + return nid_list[curve_id - 1]; +} + +int tls1_ec_nid2curve_id(int nid) +{ + /* ECC curves from RFC 4492 and RFC 7027 */ + switch (nid) { + case NID_sect163k1: /* sect163k1 (1) */ + return 1; + case NID_sect163r1: /* sect163r1 (2) */ + return 2; + case NID_sect163r2: /* sect163r2 (3) */ + return 3; + case NID_sect193r1: /* sect193r1 (4) */ + return 4; + case NID_sect193r2: /* sect193r2 (5) */ + return 5; + case NID_sect233k1: /* sect233k1 (6) */ + return 6; + case NID_sect233r1: /* sect233r1 (7) */ + return 7; + case NID_sect239k1: /* sect239k1 (8) */ + return 8; + case NID_sect283k1: /* sect283k1 (9) */ + return 9; + case NID_sect283r1: /* sect283r1 (10) */ + return 10; + case NID_sect409k1: /* sect409k1 (11) */ + return 11; + case NID_sect409r1: /* sect409r1 (12) */ + return 12; + case NID_sect571k1: /* sect571k1 (13) */ + return 13; + case NID_sect571r1: /* sect571r1 (14) */ + return 14; + case NID_secp160k1: /* secp160k1 (15) */ + return 15; + case NID_secp160r1: /* secp160r1 (16) */ + return 16; + case NID_secp160r2: /* secp160r2 (17) */ + return 17; + case NID_secp192k1: /* secp192k1 (18) */ + return 18; + case NID_X9_62_prime192v1: /* secp192r1 (19) */ + return 19; + case NID_secp224k1: /* secp224k1 (20) */ + return 20; + case NID_secp224r1: /* secp224r1 (21) */ + return 21; + case NID_secp256k1: /* secp256k1 (22) */ + return 22; + case NID_X9_62_prime256v1: /* secp256r1 (23) */ + return 23; + case NID_secp384r1: /* secp384r1 (24) */ + return 24; + case NID_secp521r1: /* secp521r1 (25) */ + return 25; + case NID_brainpoolP256r1: /* brainpoolP256r1 (26) */ + return 26; + case NID_brainpoolP384r1: /* brainpoolP384r1 (27) */ + return 27; + case NID_brainpoolP512r1: /* brainpool512r1 (28) */ + return 28; + default: + return 0; + } +} + +/* + * Get curves list, if "sess" is set return client curves otherwise + * preferred list. + * Sets |num_curves| to the number of curves in the list, i.e., + * the length of |pcurves| is 2 * num_curves. + * Returns 1 on success and 0 if the client curves list has invalid format. + * The latter indicates an internal error: we should not be accepting such + * lists in the first place. + * TODO(emilia): we should really be storing the curves list in explicitly + * parsed form instead. (However, this would affect binary compatibility + * so cannot happen in the 1.0.x series.) + */ +static int tls1_get_curvelist(SSL *s, int sess, + const unsigned char **pcurves, + size_t *num_curves) +{ + size_t pcurveslen = 0; + if (sess) { + *pcurves = s->session->tlsext_ellipticcurvelist; + pcurveslen = s->session->tlsext_ellipticcurvelist_length; + } else { + /* For Suite B mode only include P-256, P-384 */ + switch (tls1_suiteb(s)) { + case SSL_CERT_FLAG_SUITEB_128_LOS: + *pcurves = suiteb_curves; + pcurveslen = sizeof(suiteb_curves); + break; + + case SSL_CERT_FLAG_SUITEB_128_LOS_ONLY: + *pcurves = suiteb_curves; + pcurveslen = 2; + break; + + case SSL_CERT_FLAG_SUITEB_192_LOS: + *pcurves = suiteb_curves + 2; + pcurveslen = 2; + break; + default: + *pcurves = s->tlsext_ellipticcurvelist; + pcurveslen = s->tlsext_ellipticcurvelist_length; + } + if (!*pcurves) { +# ifdef OPENSSL_FIPS + if (FIPS_mode()) { + *pcurves = fips_curves_default; + pcurveslen = sizeof(fips_curves_default); + } else +# endif + { + if (!s->server || s->cert->ecdh_tmp_auto) { + *pcurves = eccurves_auto; + pcurveslen = sizeof(eccurves_auto); + } else { + *pcurves = eccurves_all; + pcurveslen = sizeof(eccurves_all); + } + } + } + } + /* We do not allow odd length arrays to enter the system. */ + if (pcurveslen & 1) { + SSLerr(SSL_F_TLS1_GET_CURVELIST, ERR_R_INTERNAL_ERROR); + *num_curves = 0; + return 0; + } else { + *num_curves = pcurveslen / 2; + return 1; + } +} + +/* Check a curve is one of our preferences */ +int tls1_check_curve(SSL *s, const unsigned char *p, size_t len) +{ + const unsigned char *curves; + size_t num_curves, i; + unsigned int suiteb_flags = tls1_suiteb(s); + if (len != 3 || p[0] != NAMED_CURVE_TYPE) + return 0; + /* Check curve matches Suite B preferences */ + if (suiteb_flags) { + unsigned long cid = s->s3->tmp.new_cipher->id; + if (p[1]) + return 0; + if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) { + if (p[2] != TLSEXT_curve_P_256) + return 0; + } else if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384) { + if (p[2] != TLSEXT_curve_P_384) + return 0; + } else /* Should never happen */ + return 0; + } + if (!tls1_get_curvelist(s, 0, &curves, &num_curves)) + return 0; + for (i = 0; i < num_curves; i++, curves += 2) { + if (p[1] == curves[0] && p[2] == curves[1]) + return 1; + } + return 0; +} + +/*- + * Return |nmatch|th shared curve or NID_undef if there is no match. + * For nmatch == -1, return number of matches + * For nmatch == -2, return the NID of the curve to use for + * an EC tmp key, or NID_undef if there is no match. + */ +int tls1_shared_curve(SSL *s, int nmatch) +{ + const unsigned char *pref, *supp; + size_t num_pref, num_supp, i, j; + int k; + /* Can't do anything on client side */ + if (s->server == 0) + return -1; + if (nmatch == -2) { + if (tls1_suiteb(s)) { + /* + * For Suite B ciphersuite determines curve: we already know + * these are acceptable due to previous checks. + */ + unsigned long cid = s->s3->tmp.new_cipher->id; + if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) + return NID_X9_62_prime256v1; /* P-256 */ + if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384) + return NID_secp384r1; /* P-384 */ + /* Should never happen */ + return NID_undef; + } + /* If not Suite B just return first preference shared curve */ + nmatch = 0; + } + /* + * Avoid truncation. tls1_get_curvelist takes an int + * but s->options is a long... + */ + if (!tls1_get_curvelist + (s, (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE) != 0, &supp, + &num_supp)) + /* In practice, NID_undef == 0 but let's be precise. */ + return nmatch == -1 ? 0 : NID_undef; + if (!tls1_get_curvelist + (s, !(s->options & SSL_OP_CIPHER_SERVER_PREFERENCE), &pref, + &num_pref)) + return nmatch == -1 ? 0 : NID_undef; + + /* + * If the client didn't send the elliptic_curves extension all of them + * are allowed. + */ + if (num_supp == 0 && (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE) != 0) { + supp = eccurves_all; + num_supp = sizeof(eccurves_all) / 2; + } else if (num_pref == 0 && + (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE) == 0) { + pref = eccurves_all; + num_pref = sizeof(eccurves_all) / 2; + } + + k = 0; + for (i = 0; i < num_pref; i++, pref += 2) { + const unsigned char *tsupp = supp; + for (j = 0; j < num_supp; j++, tsupp += 2) { + if (pref[0] == tsupp[0] && pref[1] == tsupp[1]) { + if (nmatch == k) { + int id = (pref[0] << 8) | pref[1]; + return tls1_ec_curve_id2nid(id); + } + k++; + } + } + } + if (nmatch == -1) + return k; + /* Out of range (nmatch > k). */ + return NID_undef; +} + +int tls1_set_curves(unsigned char **pext, size_t *pextlen, + int *curves, size_t ncurves) +{ + unsigned char *clist, *p; + size_t i; + /* + * Bitmap of curves included to detect duplicates: only works while curve + * ids < 32 + */ + unsigned long dup_list = 0; +# ifdef OPENSSL_NO_EC2M + EC_GROUP *curve; +# endif + + clist = OPENSSL_malloc(ncurves * 2); + if (!clist) + return 0; + for (i = 0, p = clist; i < ncurves; i++) { + unsigned long idmask; + int id; + id = tls1_ec_nid2curve_id(curves[i]); +# ifdef OPENSSL_FIPS + /* NB: 25 is last curve ID supported by FIPS module */ + if (FIPS_mode() && id > 25) { + OPENSSL_free(clist); + return 0; + } +# endif +# ifdef OPENSSL_NO_EC2M + curve = EC_GROUP_new_by_curve_name(curves[i]); + if (!curve || EC_METHOD_get_field_type(EC_GROUP_method_of(curve)) + == NID_X9_62_characteristic_two_field) { + if (curve) + EC_GROUP_free(curve); + OPENSSL_free(clist); + return 0; + } else + EC_GROUP_free(curve); +# endif + idmask = 1L << id; + if (!id || (dup_list & idmask)) { + OPENSSL_free(clist); + return 0; + } + dup_list |= idmask; + s2n(id, p); + } + if (*pext) + OPENSSL_free(*pext); + *pext = clist; + *pextlen = ncurves * 2; + return 1; +} + +# define MAX_CURVELIST 28 + +typedef struct { + size_t nidcnt; + int nid_arr[MAX_CURVELIST]; +} nid_cb_st; + +static int nid_cb(const char *elem, int len, void *arg) +{ + nid_cb_st *narg = arg; + size_t i; + int nid; + char etmp[20]; + if (elem == NULL) + return 0; + if (narg->nidcnt == MAX_CURVELIST) + return 0; + if (len > (int)(sizeof(etmp) - 1)) + return 0; + memcpy(etmp, elem, len); + etmp[len] = 0; + nid = EC_curve_nist2nid(etmp); + if (nid == NID_undef) + nid = OBJ_sn2nid(etmp); + if (nid == NID_undef) + nid = OBJ_ln2nid(etmp); + if (nid == NID_undef) + return 0; + for (i = 0; i < narg->nidcnt; i++) + if (narg->nid_arr[i] == nid) + return 0; + narg->nid_arr[narg->nidcnt++] = nid; + return 1; +} + +/* Set curves based on a colon separate list */ +int tls1_set_curves_list(unsigned char **pext, size_t *pextlen, + const char *str) +{ + nid_cb_st ncb; + ncb.nidcnt = 0; + if (!CONF_parse_list(str, ':', 1, nid_cb, &ncb)) + return 0; + if (pext == NULL) + return 1; + return tls1_set_curves(pext, pextlen, ncb.nid_arr, ncb.nidcnt); +} + +/* For an EC key set TLS id and required compression based on parameters */ +static int tls1_set_ec_id(unsigned char *curve_id, unsigned char *comp_id, + EC_KEY *ec) +{ + int is_prime, id; + const EC_GROUP *grp; + const EC_METHOD *meth; + if (!ec) + return 0; + /* Determine if it is a prime field */ + grp = EC_KEY_get0_group(ec); + if (!grp) + return 0; + meth = EC_GROUP_method_of(grp); + if (!meth) + return 0; + if (EC_METHOD_get_field_type(meth) == NID_X9_62_prime_field) + is_prime = 1; + else + is_prime = 0; + /* Determine curve ID */ + id = EC_GROUP_get_curve_name(grp); + id = tls1_ec_nid2curve_id(id); + /* If we have an ID set it, otherwise set arbitrary explicit curve */ + if (id) { + curve_id[0] = 0; + curve_id[1] = (unsigned char)id; + } else { + curve_id[0] = 0xff; + if (is_prime) + curve_id[1] = 0x01; + else + curve_id[1] = 0x02; + } + if (comp_id) { + if (EC_KEY_get0_public_key(ec) == NULL) + return 0; + if (EC_KEY_get_conv_form(ec) == POINT_CONVERSION_COMPRESSED) { + if (is_prime) + *comp_id = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime; + else + *comp_id = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2; + } else + *comp_id = TLSEXT_ECPOINTFORMAT_uncompressed; + } + return 1; +} + +/* Check an EC key is compatible with extensions */ +static int tls1_check_ec_key(SSL *s, + unsigned char *curve_id, unsigned char *comp_id) +{ + const unsigned char *pformats, *pcurves; + size_t num_formats, num_curves, i; + int j; + /* + * If point formats extension present check it, otherwise everything is + * supported (see RFC4492). + */ + if (comp_id && s->session->tlsext_ecpointformatlist) { + pformats = s->session->tlsext_ecpointformatlist; + num_formats = s->session->tlsext_ecpointformatlist_length; + for (i = 0; i < num_formats; i++, pformats++) { + if (*comp_id == *pformats) + break; + } + if (i == num_formats) + return 0; + } + if (!curve_id) + return 1; + /* Check curve is consistent with client and server preferences */ + for (j = 0; j <= 1; j++) { + if (!tls1_get_curvelist(s, j, &pcurves, &num_curves)) + return 0; + if (j == 1 && num_curves == 0) { + /* + * If we've not received any curves then skip this check. + * RFC 4492 does not require the supported elliptic curves extension + * so if it is not sent we can just choose any curve. + * It is invalid to send an empty list in the elliptic curves + * extension, so num_curves == 0 always means no extension. + */ + break; + } + for (i = 0; i < num_curves; i++, pcurves += 2) { + if (pcurves[0] == curve_id[0] && pcurves[1] == curve_id[1]) + break; + } + if (i == num_curves) + return 0; + /* For clients can only check sent curve list */ + if (!s->server) + return 1; + } + return 1; +} + +static void tls1_get_formatlist(SSL *s, const unsigned char **pformats, + size_t *num_formats) +{ + /* + * If we have a custom point format list use it otherwise use default + */ + if (s->tlsext_ecpointformatlist) { + *pformats = s->tlsext_ecpointformatlist; + *num_formats = s->tlsext_ecpointformatlist_length; + } else { + *pformats = ecformats_default; + /* For Suite B we don't support char2 fields */ + if (tls1_suiteb(s)) + *num_formats = sizeof(ecformats_default) - 1; + else + *num_formats = sizeof(ecformats_default); + } +} + +/* + * Check cert parameters compatible with extensions: currently just checks EC + * certificates have compatible curves and compression. + */ +static int tls1_check_cert_param(SSL *s, X509 *x, int set_ee_md) +{ + unsigned char comp_id, curve_id[2]; + EVP_PKEY *pkey; + int rv; + pkey = X509_get_pubkey(x); + if (!pkey) + return 0; + /* If not EC nothing to do */ + if (pkey->type != EVP_PKEY_EC) { + EVP_PKEY_free(pkey); + return 1; + } + rv = tls1_set_ec_id(curve_id, &comp_id, pkey->pkey.ec); + EVP_PKEY_free(pkey); + if (!rv) + return 0; + /* + * Can't check curve_id for client certs as we don't have a supported + * curves extension. + */ + rv = tls1_check_ec_key(s, s->server ? curve_id : NULL, &comp_id); + if (!rv) + return 0; + /* + * Special case for suite B. We *MUST* sign using SHA256+P-256 or + * SHA384+P-384, adjust digest if necessary. + */ + if (set_ee_md && tls1_suiteb(s)) { + int check_md; + size_t i; + CERT *c = s->cert; + if (curve_id[0]) + return 0; + /* Check to see we have necessary signing algorithm */ + if (curve_id[1] == TLSEXT_curve_P_256) + check_md = NID_ecdsa_with_SHA256; + else if (curve_id[1] == TLSEXT_curve_P_384) + check_md = NID_ecdsa_with_SHA384; + else + return 0; /* Should never happen */ + for (i = 0; i < c->shared_sigalgslen; i++) + if (check_md == c->shared_sigalgs[i].signandhash_nid) + break; + if (i == c->shared_sigalgslen) + return 0; + if (set_ee_md == 2) { + if (check_md == NID_ecdsa_with_SHA256) + c->pkeys[SSL_PKEY_ECC].digest = EVP_sha256(); + else + c->pkeys[SSL_PKEY_ECC].digest = EVP_sha384(); + } + } + return rv; +} + +# ifndef OPENSSL_NO_ECDH +/* Check EC temporary key is compatible with client extensions */ +int tls1_check_ec_tmp_key(SSL *s, unsigned long cid) +{ + unsigned char curve_id[2]; + EC_KEY *ec = s->cert->ecdh_tmp; +# ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL + /* Allow any curve: not just those peer supports */ + if (s->cert->cert_flags & SSL_CERT_FLAG_BROKEN_PROTOCOL) + return 1; +# endif + /* + * If Suite B, AES128 MUST use P-256 and AES256 MUST use P-384, no other + * curves permitted. + */ + if (tls1_suiteb(s)) { + /* Curve to check determined by ciphersuite */ + if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) + curve_id[1] = TLSEXT_curve_P_256; + else if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384) + curve_id[1] = TLSEXT_curve_P_384; + else + return 0; + curve_id[0] = 0; + /* Check this curve is acceptable */ + if (!tls1_check_ec_key(s, curve_id, NULL)) + return 0; + /* If auto or setting curve from callback assume OK */ + if (s->cert->ecdh_tmp_auto || s->cert->ecdh_tmp_cb) + return 1; + /* Otherwise check curve is acceptable */ + else { + unsigned char curve_tmp[2]; + if (!ec) + return 0; + if (!tls1_set_ec_id(curve_tmp, NULL, ec)) + return 0; + if (!curve_tmp[0] || curve_tmp[1] == curve_id[1]) + return 1; + return 0; + } + + } + if (s->cert->ecdh_tmp_auto) { + /* Need a shared curve */ + if (tls1_shared_curve(s, 0)) + return 1; + else + return 0; + } + if (!ec) { + if (s->cert->ecdh_tmp_cb) + return 1; + else + return 0; + } + if (!tls1_set_ec_id(curve_id, NULL, ec)) + return 0; +/* Set this to allow use of invalid curves for testing */ +# if 0 + return 1; +# else + return tls1_check_ec_key(s, curve_id, NULL); +# endif +} +# endif /* OPENSSL_NO_ECDH */ + +#else + +static int tls1_check_cert_param(SSL *s, X509 *x, int set_ee_md) +{ + return 1; +} + +#endif /* OPENSSL_NO_EC */ + +#ifndef OPENSSL_NO_TLSEXT + +/* + * List of supported signature algorithms and hashes. Should make this + * customisable at some point, for now include everything we support. + */ + +# ifdef OPENSSL_NO_RSA +# define tlsext_sigalg_rsa(md) /* */ +# else +# define tlsext_sigalg_rsa(md) md, TLSEXT_signature_rsa, +# endif + +# ifdef OPENSSL_NO_DSA +# define tlsext_sigalg_dsa(md) /* */ +# else +# define tlsext_sigalg_dsa(md) md, TLSEXT_signature_dsa, +# endif + +# ifdef OPENSSL_NO_ECDSA +# define tlsext_sigalg_ecdsa(md) + /* */ +# else +# define tlsext_sigalg_ecdsa(md) md, TLSEXT_signature_ecdsa, +# endif + +# define tlsext_sigalg(md) \ + tlsext_sigalg_rsa(md) \ + tlsext_sigalg_dsa(md) \ + tlsext_sigalg_ecdsa(md) + +static unsigned char tls12_sigalgs[] = { +# ifndef OPENSSL_NO_SHA512 + tlsext_sigalg(TLSEXT_hash_sha512) + tlsext_sigalg(TLSEXT_hash_sha384) +# endif +# ifndef OPENSSL_NO_SHA256 + tlsext_sigalg(TLSEXT_hash_sha256) + tlsext_sigalg(TLSEXT_hash_sha224) +# endif +# ifndef OPENSSL_NO_SHA + tlsext_sigalg(TLSEXT_hash_sha1) +# endif +}; + +# ifndef OPENSSL_NO_ECDSA +static unsigned char suiteb_sigalgs[] = { + tlsext_sigalg_ecdsa(TLSEXT_hash_sha256) + tlsext_sigalg_ecdsa(TLSEXT_hash_sha384) +}; +# endif +size_t tls12_get_psigalgs(SSL *s, const unsigned char **psigs) +{ + /* + * If Suite B mode use Suite B sigalgs only, ignore any other + * preferences. + */ +# ifndef OPENSSL_NO_EC + switch (tls1_suiteb(s)) { + case SSL_CERT_FLAG_SUITEB_128_LOS: + *psigs = suiteb_sigalgs; + return sizeof(suiteb_sigalgs); + + case SSL_CERT_FLAG_SUITEB_128_LOS_ONLY: + *psigs = suiteb_sigalgs; + return 2; + + case SSL_CERT_FLAG_SUITEB_192_LOS: + *psigs = suiteb_sigalgs + 2; + return 2; + } +# endif + /* If server use client authentication sigalgs if not NULL */ + if (s->server && s->cert->client_sigalgs) { + *psigs = s->cert->client_sigalgs; + return s->cert->client_sigalgslen; + } else if (s->cert->conf_sigalgs) { + *psigs = s->cert->conf_sigalgs; + return s->cert->conf_sigalgslen; + } else { + *psigs = tls12_sigalgs; + return sizeof(tls12_sigalgs); + } +} + +/* + * Check signature algorithm is consistent with sent supported signature + * algorithms and if so return relevant digest. + */ +int tls12_check_peer_sigalg(const EVP_MD **pmd, SSL *s, + const unsigned char *sig, EVP_PKEY *pkey) +{ + const unsigned char *sent_sigs; + size_t sent_sigslen, i; + int sigalg = tls12_get_sigid(pkey); + /* Should never happen */ + if (sigalg == -1) + return -1; + /* Check key type is consistent with signature */ + if (sigalg != (int)sig[1]) { + SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG, SSL_R_WRONG_SIGNATURE_TYPE); + return 0; + } +# ifndef OPENSSL_NO_EC + if (pkey->type == EVP_PKEY_EC) { + unsigned char curve_id[2], comp_id; + /* Check compression and curve matches extensions */ + if (!tls1_set_ec_id(curve_id, &comp_id, pkey->pkey.ec)) + return 0; + if (!s->server && !tls1_check_ec_key(s, curve_id, &comp_id)) { + SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG, SSL_R_WRONG_CURVE); + return 0; + } + /* If Suite B only P-384+SHA384 or P-256+SHA-256 allowed */ + if (tls1_suiteb(s)) { + if (curve_id[0]) + return 0; + if (curve_id[1] == TLSEXT_curve_P_256) { + if (sig[0] != TLSEXT_hash_sha256) { + SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG, + SSL_R_ILLEGAL_SUITEB_DIGEST); + return 0; + } + } else if (curve_id[1] == TLSEXT_curve_P_384) { + if (sig[0] != TLSEXT_hash_sha384) { + SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG, + SSL_R_ILLEGAL_SUITEB_DIGEST); + return 0; + } + } else + return 0; + } + } else if (tls1_suiteb(s)) + return 0; +# endif + + /* Check signature matches a type we sent */ + sent_sigslen = tls12_get_psigalgs(s, &sent_sigs); + for (i = 0; i < sent_sigslen; i += 2, sent_sigs += 2) { + if (sig[0] == sent_sigs[0] && sig[1] == sent_sigs[1]) + break; + } + /* Allow fallback to SHA1 if not strict mode */ + if (i == sent_sigslen + && (sig[0] != TLSEXT_hash_sha1 + || s->cert->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT)) { + SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG, SSL_R_WRONG_SIGNATURE_TYPE); + return 0; + } + *pmd = tls12_get_hash(sig[0]); + if (*pmd == NULL) { + SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG, SSL_R_UNKNOWN_DIGEST); + return 0; + } + /* + * Store the digest used so applications can retrieve it if they wish. + */ + if (s->session && s->session->sess_cert) + s->session->sess_cert->peer_key->digest = *pmd; + return 1; +} + +/* + * Get a mask of disabled algorithms: an algorithm is disabled if it isn't + * supported or doesn't appear in supported signature algorithms. Unlike + * ssl_cipher_get_disabled this applies to a specific session and not global + * settings. + */ +void ssl_set_client_disabled(SSL *s) +{ + CERT *c = s->cert; + const unsigned char *sigalgs; + size_t i, sigalgslen; + int have_rsa = 0, have_dsa = 0, have_ecdsa = 0; + c->mask_a = 0; + c->mask_k = 0; + /* Don't allow TLS 1.2 only ciphers if we don't suppport them */ + if (!SSL_CLIENT_USE_TLS1_2_CIPHERS(s)) + c->mask_ssl = SSL_TLSV1_2; + else + c->mask_ssl = 0; + /* + * Now go through all signature algorithms seeing if we support any for + * RSA, DSA, ECDSA. Do this for all versions not just TLS 1.2. + */ + sigalgslen = tls12_get_psigalgs(s, &sigalgs); + for (i = 0; i < sigalgslen; i += 2, sigalgs += 2) { + switch (sigalgs[1]) { +# ifndef OPENSSL_NO_RSA + case TLSEXT_signature_rsa: + have_rsa = 1; + break; +# endif +# ifndef OPENSSL_NO_DSA + case TLSEXT_signature_dsa: + have_dsa = 1; + break; +# endif +# ifndef OPENSSL_NO_ECDSA + case TLSEXT_signature_ecdsa: + have_ecdsa = 1; + break; +# endif + } + } + /* + * Disable auth and static DH if we don't include any appropriate + * signature algorithms. + */ + if (!have_rsa) { + c->mask_a |= SSL_aRSA; + c->mask_k |= SSL_kDHr | SSL_kECDHr; + } + if (!have_dsa) { + c->mask_a |= SSL_aDSS; + c->mask_k |= SSL_kDHd; + } + if (!have_ecdsa) { + c->mask_a |= SSL_aECDSA; + c->mask_k |= SSL_kECDHe; + } +# ifndef OPENSSL_NO_KRB5 + if (!kssl_tgt_is_available(s->kssl_ctx)) { + c->mask_a |= SSL_aKRB5; + c->mask_k |= SSL_kKRB5; + } +# endif +# ifndef OPENSSL_NO_PSK + /* with PSK there must be client callback set */ + if (!s->psk_client_callback) { + c->mask_a |= SSL_aPSK; + c->mask_k |= SSL_kPSK; + } +# endif /* OPENSSL_NO_PSK */ +# ifndef OPENSSL_NO_SRP + if (!(s->srp_ctx.srp_Mask & SSL_kSRP)) { + c->mask_a |= SSL_aSRP; + c->mask_k |= SSL_kSRP; + } +# endif + c->valid = 1; +} + +unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf, + unsigned char *limit, int *al) +{ + int extdatalen = 0; + unsigned char *orig = buf; + unsigned char *ret = buf; +# ifndef OPENSSL_NO_EC + /* See if we support any ECC ciphersuites */ + int using_ecc = 0; + if (s->version >= TLS1_VERSION || SSL_IS_DTLS(s)) { + int i; + unsigned long alg_k, alg_a; + STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(s); + + for (i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++) { + SSL_CIPHER *c = sk_SSL_CIPHER_value(cipher_stack, i); + + alg_k = c->algorithm_mkey; + alg_a = c->algorithm_auth; + if ((alg_k & (SSL_kEECDH | SSL_kECDHr | SSL_kECDHe) + || (alg_a & SSL_aECDSA))) { + using_ecc = 1; + break; + } + } + } +# endif + + /* don't add extensions for SSLv3 unless doing secure renegotiation */ + if (s->client_version == SSL3_VERSION && !s->s3->send_connection_binding) + return orig; + + ret += 2; + + if (ret >= limit) + return NULL; /* this really never occurs, but ... */ + + if (s->tlsext_hostname != NULL) { + /* Add TLS extension servername to the Client Hello message */ + unsigned long size_str; + long lenmax; + + /*- + * check for enough space. + * 4 for the servername type and entension length + * 2 for servernamelist length + * 1 for the hostname type + * 2 for hostname length + * + hostname length + */ + + if ((lenmax = limit - ret - 9) < 0 + || (size_str = + strlen(s->tlsext_hostname)) > (unsigned long)lenmax) + return NULL; + + /* extension type and length */ + s2n(TLSEXT_TYPE_server_name, ret); + s2n(size_str + 5, ret); + + /* length of servername list */ + s2n(size_str + 3, ret); + + /* hostname type, length and hostname */ + *(ret++) = (unsigned char)TLSEXT_NAMETYPE_host_name; + s2n(size_str, ret); + memcpy(ret, s->tlsext_hostname, size_str); + ret += size_str; + } + + /* Add RI if renegotiating */ + if (s->renegotiate) { + int el; + + if (!ssl_add_clienthello_renegotiate_ext(s, 0, &el, 0)) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return NULL; + } + + if ((limit - ret - 4 - el) < 0) + return NULL; + + s2n(TLSEXT_TYPE_renegotiate, ret); + s2n(el, ret); + + if (!ssl_add_clienthello_renegotiate_ext(s, ret, &el, el)) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return NULL; + } + + ret += el; + } +# ifndef OPENSSL_NO_SRP + /* Add SRP username if there is one */ + if (s->srp_ctx.login != NULL) { /* Add TLS extension SRP username to the + * Client Hello message */ + + int login_len = strlen(s->srp_ctx.login); + if (login_len > 255 || login_len == 0) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return NULL; + } + + /*- + * check for enough space. + * 4 for the srp type type and entension length + * 1 for the srp user identity + * + srp user identity length + */ + if ((limit - ret - 5 - login_len) < 0) + return NULL; + + /* fill in the extension */ + s2n(TLSEXT_TYPE_srp, ret); + s2n(login_len + 1, ret); + (*ret++) = (unsigned char)login_len; + memcpy(ret, s->srp_ctx.login, login_len); + ret += login_len; + } +# endif + +# ifndef OPENSSL_NO_EC + if (using_ecc) { + /* + * Add TLS extension ECPointFormats to the ClientHello message + */ + long lenmax; + const unsigned char *pcurves, *pformats; + size_t num_curves, num_formats, curves_list_len; + + tls1_get_formatlist(s, &pformats, &num_formats); + + if ((lenmax = limit - ret - 5) < 0) + return NULL; + if (num_formats > (size_t)lenmax) + return NULL; + if (num_formats > 255) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return NULL; + } + + s2n(TLSEXT_TYPE_ec_point_formats, ret); + /* The point format list has 1-byte length. */ + s2n(num_formats + 1, ret); + *(ret++) = (unsigned char)num_formats; + memcpy(ret, pformats, num_formats); + ret += num_formats; + + /* + * Add TLS extension EllipticCurves to the ClientHello message + */ + pcurves = s->tlsext_ellipticcurvelist; + if (!tls1_get_curvelist(s, 0, &pcurves, &num_curves)) + return NULL; + + if ((lenmax = limit - ret - 6) < 0) + return NULL; + if (num_curves > (size_t)lenmax / 2) + return NULL; + if (num_curves > 65532 / 2) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return NULL; + } + curves_list_len = 2 * num_curves; + s2n(TLSEXT_TYPE_elliptic_curves, ret); + s2n(curves_list_len + 2, ret); + s2n(curves_list_len, ret); + memcpy(ret, pcurves, curves_list_len); + ret += curves_list_len; + } +# endif /* OPENSSL_NO_EC */ + + if (!(SSL_get_options(s) & SSL_OP_NO_TICKET)) { + int ticklen; + if (!s->new_session && s->session && s->session->tlsext_tick) + ticklen = s->session->tlsext_ticklen; + else if (s->session && s->tlsext_session_ticket && + s->tlsext_session_ticket->data) { + ticklen = s->tlsext_session_ticket->length; + s->session->tlsext_tick = OPENSSL_malloc(ticklen); + if (!s->session->tlsext_tick) + return NULL; + memcpy(s->session->tlsext_tick, + s->tlsext_session_ticket->data, ticklen); + s->session->tlsext_ticklen = ticklen; + } else + ticklen = 0; + if (ticklen == 0 && s->tlsext_session_ticket && + s->tlsext_session_ticket->data == NULL) + goto skip_ext; + /* + * Check for enough room 2 for extension type, 2 for len rest for + * ticket + */ + if ((long)(limit - ret - 4 - ticklen) < 0) + return NULL; + s2n(TLSEXT_TYPE_session_ticket, ret); + s2n(ticklen, ret); + if (ticklen) { + memcpy(ret, s->session->tlsext_tick, ticklen); + ret += ticklen; + } + } + skip_ext: + + if (SSL_USE_SIGALGS(s)) { + size_t salglen; + const unsigned char *salg; + salglen = tls12_get_psigalgs(s, &salg); + if ((size_t)(limit - ret) < salglen + 6) + return NULL; + s2n(TLSEXT_TYPE_signature_algorithms, ret); + s2n(salglen + 2, ret); + s2n(salglen, ret); + memcpy(ret, salg, salglen); + ret += salglen; + } +# ifdef TLSEXT_TYPE_opaque_prf_input + if (s->s3->client_opaque_prf_input != NULL) { + size_t col = s->s3->client_opaque_prf_input_len; + + if ((long)(limit - ret - 6 - col < 0)) + return NULL; + if (col > 0xFFFD) /* can't happen */ + return NULL; + + s2n(TLSEXT_TYPE_opaque_prf_input, ret); + s2n(col + 2, ret); + s2n(col, ret); + memcpy(ret, s->s3->client_opaque_prf_input, col); + ret += col; + } +# endif + + if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp) { + int i; + long extlen, idlen, itmp; + OCSP_RESPID *id; + + idlen = 0; + for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++) { + id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i); + itmp = i2d_OCSP_RESPID(id, NULL); + if (itmp <= 0) + return NULL; + idlen += itmp + 2; + } + + if (s->tlsext_ocsp_exts) { + extlen = i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, NULL); + if (extlen < 0) + return NULL; + } else + extlen = 0; + + if ((long)(limit - ret - 7 - extlen - idlen) < 0) + return NULL; + s2n(TLSEXT_TYPE_status_request, ret); + if (extlen + idlen > 0xFFF0) + return NULL; + s2n(extlen + idlen + 5, ret); + *(ret++) = TLSEXT_STATUSTYPE_ocsp; + s2n(idlen, ret); + for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++) { + /* save position of id len */ + unsigned char *q = ret; + id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i); + /* skip over id len */ + ret += 2; + itmp = i2d_OCSP_RESPID(id, &ret); + /* write id len */ + s2n(itmp, q); + } + s2n(extlen, ret); + if (extlen > 0) + i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, &ret); + } +# ifndef OPENSSL_NO_HEARTBEATS + /* Add Heartbeat extension */ + if ((limit - ret - 4 - 1) < 0) + return NULL; + s2n(TLSEXT_TYPE_heartbeat, ret); + s2n(1, ret); + /*- + * Set mode: + * 1: peer may send requests + * 2: peer not allowed to send requests + */ + if (s->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_RECV_REQUESTS) + *(ret++) = SSL_TLSEXT_HB_DONT_SEND_REQUESTS; + else + *(ret++) = SSL_TLSEXT_HB_ENABLED; +# endif + +# ifndef OPENSSL_NO_NEXTPROTONEG + if (s->ctx->next_proto_select_cb && !s->s3->tmp.finish_md_len) { + /* + * The client advertises an emtpy extension to indicate its support + * for Next Protocol Negotiation + */ + if (limit - ret - 4 < 0) + return NULL; + s2n(TLSEXT_TYPE_next_proto_neg, ret); + s2n(0, ret); + } +# endif + + if (s->alpn_client_proto_list && !s->s3->tmp.finish_md_len) { + if ((size_t)(limit - ret) < 6 + s->alpn_client_proto_list_len) + return NULL; + s2n(TLSEXT_TYPE_application_layer_protocol_negotiation, ret); + s2n(2 + s->alpn_client_proto_list_len, ret); + s2n(s->alpn_client_proto_list_len, ret); + memcpy(ret, s->alpn_client_proto_list, s->alpn_client_proto_list_len); + ret += s->alpn_client_proto_list_len; + s->cert->alpn_sent = 1; + } +# ifndef OPENSSL_NO_SRTP + if (SSL_IS_DTLS(s) && SSL_get_srtp_profiles(s)) { + int el; + + ssl_add_clienthello_use_srtp_ext(s, 0, &el, 0); + + if ((limit - ret - 4 - el) < 0) + return NULL; + + s2n(TLSEXT_TYPE_use_srtp, ret); + s2n(el, ret); + + if (ssl_add_clienthello_use_srtp_ext(s, ret, &el, el)) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return NULL; + } + ret += el; + } +# endif + custom_ext_init(&s->cert->cli_ext); + /* Add custom TLS Extensions to ClientHello */ + if (!custom_ext_add(s, 0, &ret, limit, al)) + return NULL; + + /* + * Add padding to workaround bugs in F5 terminators. See + * https://tools.ietf.org/html/draft-agl-tls-padding-03 NB: because this + * code works out the length of all existing extensions it MUST always + * appear last. + */ + if (s->options & SSL_OP_TLSEXT_PADDING) { + int hlen = ret - (unsigned char *)s->init_buf->data; + /* + * The code in s23_clnt.c to build ClientHello messages includes the + * 5-byte record header in the buffer, while the code in s3_clnt.c + * does not. + */ + if (s->state == SSL23_ST_CW_CLNT_HELLO_A) + hlen -= 5; + if (hlen > 0xff && hlen < 0x200) { + hlen = 0x200 - hlen; + if (hlen >= 4) + hlen -= 4; + else + hlen = 0; + + s2n(TLSEXT_TYPE_padding, ret); + s2n(hlen, ret); + memset(ret, 0, hlen); + ret += hlen; + } + } + + if ((extdatalen = ret - orig - 2) == 0) + return orig; + + s2n(extdatalen, orig); + return ret; +} + +unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf, + unsigned char *limit, int *al) +{ + int extdatalen = 0; + unsigned char *orig = buf; + unsigned char *ret = buf; +# ifndef OPENSSL_NO_NEXTPROTONEG + int next_proto_neg_seen; +# endif +# ifndef OPENSSL_NO_EC + unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey; + unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth; + int using_ecc = (alg_k & (SSL_kEECDH | SSL_kECDHr | SSL_kECDHe)) + || (alg_a & SSL_aECDSA); + using_ecc = using_ecc && (s->session->tlsext_ecpointformatlist != NULL); +# endif + /* + * don't add extensions for SSLv3, unless doing secure renegotiation + */ + if (s->version == SSL3_VERSION && !s->s3->send_connection_binding) + return orig; + + ret += 2; + if (ret >= limit) + return NULL; /* this really never occurs, but ... */ + + if (!s->hit && s->servername_done == 1 + && s->session->tlsext_hostname != NULL) { + if ((long)(limit - ret - 4) < 0) + return NULL; + + s2n(TLSEXT_TYPE_server_name, ret); + s2n(0, ret); + } + + if (s->s3->send_connection_binding) { + int el; + + if (!ssl_add_serverhello_renegotiate_ext(s, 0, &el, 0)) { + SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return NULL; + } + + if ((limit - ret - 4 - el) < 0) + return NULL; + + s2n(TLSEXT_TYPE_renegotiate, ret); + s2n(el, ret); + + if (!ssl_add_serverhello_renegotiate_ext(s, ret, &el, el)) { + SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return NULL; + } + + ret += el; + } +# ifndef OPENSSL_NO_EC + if (using_ecc) { + const unsigned char *plist; + size_t plistlen; + /* + * Add TLS extension ECPointFormats to the ServerHello message + */ + long lenmax; + + tls1_get_formatlist(s, &plist, &plistlen); + + if ((lenmax = limit - ret - 5) < 0) + return NULL; + if (plistlen > (size_t)lenmax) + return NULL; + if (plistlen > 255) { + SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return NULL; + } + + s2n(TLSEXT_TYPE_ec_point_formats, ret); + s2n(plistlen + 1, ret); + *(ret++) = (unsigned char)plistlen; + memcpy(ret, plist, plistlen); + ret += plistlen; + + } + /* + * Currently the server should not respond with a SupportedCurves + * extension + */ +# endif /* OPENSSL_NO_EC */ + + if (s->tlsext_ticket_expected && !(SSL_get_options(s) & SSL_OP_NO_TICKET)) { + if ((long)(limit - ret - 4) < 0) + return NULL; + s2n(TLSEXT_TYPE_session_ticket, ret); + s2n(0, ret); + } + + if (s->tlsext_status_expected) { + if ((long)(limit - ret - 4) < 0) + return NULL; + s2n(TLSEXT_TYPE_status_request, ret); + s2n(0, ret); + } +# ifdef TLSEXT_TYPE_opaque_prf_input + if (s->s3->server_opaque_prf_input != NULL) { + size_t sol = s->s3->server_opaque_prf_input_len; + + if ((long)(limit - ret - 6 - sol) < 0) + return NULL; + if (sol > 0xFFFD) /* can't happen */ + return NULL; + + s2n(TLSEXT_TYPE_opaque_prf_input, ret); + s2n(sol + 2, ret); + s2n(sol, ret); + memcpy(ret, s->s3->server_opaque_prf_input, sol); + ret += sol; + } +# endif + +# ifndef OPENSSL_NO_SRTP + if (SSL_IS_DTLS(s) && s->srtp_profile) { + int el; + + ssl_add_serverhello_use_srtp_ext(s, 0, &el, 0); + + if ((limit - ret - 4 - el) < 0) + return NULL; + + s2n(TLSEXT_TYPE_use_srtp, ret); + s2n(el, ret); + + if (ssl_add_serverhello_use_srtp_ext(s, ret, &el, el)) { + SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return NULL; + } + ret += el; + } +# endif + + if (((s->s3->tmp.new_cipher->id & 0xFFFF) == 0x80 + || (s->s3->tmp.new_cipher->id & 0xFFFF) == 0x81) + && (SSL_get_options(s) & SSL_OP_CRYPTOPRO_TLSEXT_BUG)) { + const unsigned char cryptopro_ext[36] = { + 0xfd, 0xe8, /* 65000 */ + 0x00, 0x20, /* 32 bytes length */ + 0x30, 0x1e, 0x30, 0x08, 0x06, 0x06, 0x2a, 0x85, + 0x03, 0x02, 0x02, 0x09, 0x30, 0x08, 0x06, 0x06, + 0x2a, 0x85, 0x03, 0x02, 0x02, 0x16, 0x30, 0x08, + 0x06, 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x17 + }; + if (limit - ret < 36) + return NULL; + memcpy(ret, cryptopro_ext, 36); + ret += 36; + + } +# ifndef OPENSSL_NO_HEARTBEATS + /* Add Heartbeat extension if we've received one */ + if (s->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED) { + if ((limit - ret - 4 - 1) < 0) + return NULL; + s2n(TLSEXT_TYPE_heartbeat, ret); + s2n(1, ret); + /*- + * Set mode: + * 1: peer may send requests + * 2: peer not allowed to send requests + */ + if (s->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_RECV_REQUESTS) + *(ret++) = SSL_TLSEXT_HB_DONT_SEND_REQUESTS; + else + *(ret++) = SSL_TLSEXT_HB_ENABLED; + + } +# endif + +# ifndef OPENSSL_NO_NEXTPROTONEG + next_proto_neg_seen = s->s3->next_proto_neg_seen; + s->s3->next_proto_neg_seen = 0; + if (next_proto_neg_seen && s->ctx->next_protos_advertised_cb) { + const unsigned char *npa; + unsigned int npalen; + int r; + + r = s->ctx->next_protos_advertised_cb(s, &npa, &npalen, + s-> + ctx->next_protos_advertised_cb_arg); + if (r == SSL_TLSEXT_ERR_OK) { + if ((long)(limit - ret - 4 - npalen) < 0) + return NULL; + s2n(TLSEXT_TYPE_next_proto_neg, ret); + s2n(npalen, ret); + memcpy(ret, npa, npalen); + ret += npalen; + s->s3->next_proto_neg_seen = 1; + } + } +# endif + if (!custom_ext_add(s, 1, &ret, limit, al)) + return NULL; + + if (s->s3->alpn_selected) { + const unsigned char *selected = s->s3->alpn_selected; + unsigned len = s->s3->alpn_selected_len; + + if ((long)(limit - ret - 4 - 2 - 1 - len) < 0) + return NULL; + s2n(TLSEXT_TYPE_application_layer_protocol_negotiation, ret); + s2n(3 + len, ret); + s2n(1 + len, ret); + *ret++ = len; + memcpy(ret, selected, len); + ret += len; + } + + if ((extdatalen = ret - orig - 2) == 0) + return orig; + + s2n(extdatalen, orig); + return ret; +} + +# ifndef OPENSSL_NO_EC +/*- + * ssl_check_for_safari attempts to fingerprint Safari using OS X + * SecureTransport using the TLS extension block in |d|, of length |n|. + * Safari, since 10.6, sends exactly these extensions, in this order: + * SNI, + * elliptic_curves + * ec_point_formats + * + * We wish to fingerprint Safari because they broke ECDHE-ECDSA support in 10.8, + * but they advertise support. So enabling ECDHE-ECDSA ciphers breaks them. + * Sadly we cannot differentiate 10.6, 10.7 and 10.8.4 (which work), from + * 10.8..10.8.3 (which don't work). + */ +static void ssl_check_for_safari(SSL *s, const unsigned char *data, + const unsigned char *limit) +{ + unsigned short type, size; + static const unsigned char kSafariExtensionsBlock[] = { + 0x00, 0x0a, /* elliptic_curves extension */ + 0x00, 0x08, /* 8 bytes */ + 0x00, 0x06, /* 6 bytes of curve ids */ + 0x00, 0x17, /* P-256 */ + 0x00, 0x18, /* P-384 */ + 0x00, 0x19, /* P-521 */ + + 0x00, 0x0b, /* ec_point_formats */ + 0x00, 0x02, /* 2 bytes */ + 0x01, /* 1 point format */ + 0x00, /* uncompressed */ + }; + + /* The following is only present in TLS 1.2 */ + static const unsigned char kSafariTLS12ExtensionsBlock[] = { + 0x00, 0x0d, /* signature_algorithms */ + 0x00, 0x0c, /* 12 bytes */ + 0x00, 0x0a, /* 10 bytes */ + 0x05, 0x01, /* SHA-384/RSA */ + 0x04, 0x01, /* SHA-256/RSA */ + 0x02, 0x01, /* SHA-1/RSA */ + 0x04, 0x03, /* SHA-256/ECDSA */ + 0x02, 0x03, /* SHA-1/ECDSA */ + }; + + if (data >= (limit - 2)) + return; + data += 2; + + if (data > (limit - 4)) + return; + n2s(data, type); + n2s(data, size); + + if (type != TLSEXT_TYPE_server_name) + return; + + if (data + size > limit) + return; + data += size; + + if (TLS1_get_client_version(s) >= TLS1_2_VERSION) { + const size_t len1 = sizeof(kSafariExtensionsBlock); + const size_t len2 = sizeof(kSafariTLS12ExtensionsBlock); + + if (data + len1 + len2 != limit) + return; + if (memcmp(data, kSafariExtensionsBlock, len1) != 0) + return; + if (memcmp(data + len1, kSafariTLS12ExtensionsBlock, len2) != 0) + return; + } else { + const size_t len = sizeof(kSafariExtensionsBlock); + + if (data + len != limit) + return; + if (memcmp(data, kSafariExtensionsBlock, len) != 0) + return; + } + + s->s3->is_probably_safari = 1; +} +# endif /* !OPENSSL_NO_EC */ + +/* + * tls1_alpn_handle_client_hello is called to save the ALPN extension in a + * ClientHello. data: the contents of the extension, not including the type + * and length. data_len: the number of bytes in |data| al: a pointer to the + * alert value to send in the event of a non-zero return. returns: 0 on + * success. + */ +static int tls1_alpn_handle_client_hello(SSL *s, const unsigned char *data, + unsigned data_len, int *al) +{ + unsigned i; + unsigned proto_len; + + if (data_len < 2) + goto parse_error; + + /* + * data should contain a uint16 length followed by a series of 8-bit, + * length-prefixed strings. + */ + i = ((unsigned)data[0]) << 8 | ((unsigned)data[1]); + data_len -= 2; + data += 2; + if (data_len != i) + goto parse_error; + + if (data_len < 2) + goto parse_error; + + for (i = 0; i < data_len;) { + proto_len = data[i]; + i++; + + if (proto_len == 0) + goto parse_error; + + if (i + proto_len < i || i + proto_len > data_len) + goto parse_error; + + i += proto_len; + } + + if (s->cert->alpn_proposed != NULL) + OPENSSL_free(s->cert->alpn_proposed); + s->cert->alpn_proposed = OPENSSL_malloc(data_len); + if (s->cert->alpn_proposed == NULL) { + *al = SSL_AD_INTERNAL_ERROR; + return -1; + } + memcpy(s->cert->alpn_proposed, data, data_len); + s->cert->alpn_proposed_len = data_len; + return 0; + + parse_error: + *al = SSL_AD_DECODE_ERROR; + return -1; +} + +/* + * Process the ALPN extension in a ClientHello. + * ret: a pointer to the TLSEXT return value: SSL_TLSEXT_ERR_* + * al: a pointer to the alert value to send in the event of a failure. + * returns 1 on success, 0 on failure: al/ret set only on failure + */ +static int tls1_alpn_handle_client_hello_late(SSL *s, int *ret, int *al) +{ + const unsigned char *selected = NULL; + unsigned char selected_len = 0; + + if (s->ctx->alpn_select_cb != NULL && s->cert->alpn_proposed != NULL) { + int r = s->ctx->alpn_select_cb(s, &selected, &selected_len, + s->cert->alpn_proposed, + s->cert->alpn_proposed_len, + s->ctx->alpn_select_cb_arg); + + if (r == SSL_TLSEXT_ERR_OK) { + OPENSSL_free(s->s3->alpn_selected); + s->s3->alpn_selected = OPENSSL_malloc(selected_len); + if (s->s3->alpn_selected == NULL) { + *al = SSL_AD_INTERNAL_ERROR; + *ret = SSL_TLSEXT_ERR_ALERT_FATAL; + return 0; + } + memcpy(s->s3->alpn_selected, selected, selected_len); + s->s3->alpn_selected_len = selected_len; +# ifndef OPENSSL_NO_NEXTPROTONEG + /* ALPN takes precedence over NPN. */ + s->s3->next_proto_neg_seen = 0; +# endif + } + } + + return 1; +} + +static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, + unsigned char *limit, int *al) +{ + unsigned short type; + unsigned short size; + unsigned short len; + unsigned char *data = *p; + int renegotiate_seen = 0; + + s->servername_done = 0; + s->tlsext_status_type = -1; +# ifndef OPENSSL_NO_NEXTPROTONEG + s->s3->next_proto_neg_seen = 0; +# endif + + if (s->s3->alpn_selected) { + OPENSSL_free(s->s3->alpn_selected); + s->s3->alpn_selected = NULL; + } + s->s3->alpn_selected_len = 0; + if (s->cert->alpn_proposed) { + OPENSSL_free(s->cert->alpn_proposed); + s->cert->alpn_proposed = NULL; + } + s->cert->alpn_proposed_len = 0; +# ifndef OPENSSL_NO_HEARTBEATS + s->tlsext_heartbeat &= ~(SSL_TLSEXT_HB_ENABLED | + SSL_TLSEXT_HB_DONT_SEND_REQUESTS); +# endif + +# ifndef OPENSSL_NO_EC + if (s->options & SSL_OP_SAFARI_ECDHE_ECDSA_BUG) + ssl_check_for_safari(s, data, limit); +# endif /* !OPENSSL_NO_EC */ + + /* Clear any signature algorithms extension received */ + if (s->cert->peer_sigalgs) { + OPENSSL_free(s->cert->peer_sigalgs); + s->cert->peer_sigalgs = NULL; + } +# ifndef OPENSSL_NO_SRP + if (s->srp_ctx.login != NULL) { + OPENSSL_free(s->srp_ctx.login); + s->srp_ctx.login = NULL; + } +# endif + + s->srtp_profile = NULL; + + if (data == limit) + goto ri_check; + + if (data > (limit - 2)) + goto err; + + n2s(data, len); + + if (data + len != limit) + goto err; + + while (data <= (limit - 4)) { + n2s(data, type); + n2s(data, size); + + if (data + size > (limit)) + goto err; +# if 0 + fprintf(stderr, "Received extension type %d size %d\n", type, size); +# endif + if (s->tlsext_debug_cb) + s->tlsext_debug_cb(s, 0, type, data, size, s->tlsext_debug_arg); +/*- + * The servername extension is treated as follows: + * + * - Only the hostname type is supported with a maximum length of 255. + * - The servername is rejected if too long or if it contains zeros, + * in which case an fatal alert is generated. + * - The servername field is maintained together with the session cache. + * - When a session is resumed, the servername call back invoked in order + * to allow the application to position itself to the right context. + * - The servername is acknowledged if it is new for a session or when + * it is identical to a previously used for the same session. + * Applications can control the behaviour. They can at any time + * set a 'desirable' servername for a new SSL object. This can be the + * case for example with HTTPS when a Host: header field is received and + * a renegotiation is requested. In this case, a possible servername + * presented in the new client hello is only acknowledged if it matches + * the value of the Host: field. + * - Applications must use SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION + * if they provide for changing an explicit servername context for the + * session, i.e. when the session has been established with a servername + * extension. + * - On session reconnect, the servername extension may be absent. + * + */ + + if (type == TLSEXT_TYPE_server_name) { + unsigned char *sdata; + int servname_type; + int dsize; + + if (size < 2) + goto err; + n2s(data, dsize); + size -= 2; + if (dsize > size) + goto err; + + sdata = data; + while (dsize > 3) { + servname_type = *(sdata++); + n2s(sdata, len); + dsize -= 3; + + if (len > dsize) + goto err; + + if (s->servername_done == 0) + switch (servname_type) { + case TLSEXT_NAMETYPE_host_name: + if (!s->hit) { + if (s->session->tlsext_hostname) + goto err; + + if (len > TLSEXT_MAXLEN_host_name) { + *al = TLS1_AD_UNRECOGNIZED_NAME; + return 0; + } + if ((s->session->tlsext_hostname = + OPENSSL_malloc(len + 1)) == NULL) { + *al = TLS1_AD_INTERNAL_ERROR; + return 0; + } + memcpy(s->session->tlsext_hostname, sdata, len); + s->session->tlsext_hostname[len] = '\0'; + if (strlen(s->session->tlsext_hostname) != len) { + OPENSSL_free(s->session->tlsext_hostname); + s->session->tlsext_hostname = NULL; + *al = TLS1_AD_UNRECOGNIZED_NAME; + return 0; + } + s->servername_done = 1; + + } else + s->servername_done = s->session->tlsext_hostname + && strlen(s->session->tlsext_hostname) == len + && strncmp(s->session->tlsext_hostname, + (char *)sdata, len) == 0; + + break; + + default: + break; + } + + dsize -= len; + } + if (dsize != 0) + goto err; + + } +# ifndef OPENSSL_NO_SRP + else if (type == TLSEXT_TYPE_srp) { + if (size == 0 || ((len = data[0])) != (size - 1)) + goto err; + if (s->srp_ctx.login != NULL) + goto err; + if ((s->srp_ctx.login = OPENSSL_malloc(len + 1)) == NULL) + return -1; + memcpy(s->srp_ctx.login, &data[1], len); + s->srp_ctx.login[len] = '\0'; + + if (strlen(s->srp_ctx.login) != len) + goto err; + } +# endif + +# ifndef OPENSSL_NO_EC + else if (type == TLSEXT_TYPE_ec_point_formats) { + unsigned char *sdata = data; + int ecpointformatlist_length = *(sdata++); + + if (ecpointformatlist_length != size - 1 || + ecpointformatlist_length < 1) + goto err; + if (!s->hit) { + if (s->session->tlsext_ecpointformatlist) { + OPENSSL_free(s->session->tlsext_ecpointformatlist); + s->session->tlsext_ecpointformatlist = NULL; + } + s->session->tlsext_ecpointformatlist_length = 0; + if ((s->session->tlsext_ecpointformatlist = + OPENSSL_malloc(ecpointformatlist_length)) == NULL) { + *al = TLS1_AD_INTERNAL_ERROR; + return 0; + } + s->session->tlsext_ecpointformatlist_length = + ecpointformatlist_length; + memcpy(s->session->tlsext_ecpointformatlist, sdata, + ecpointformatlist_length); + } +# if 0 + fprintf(stderr, + "ssl_parse_clienthello_tlsext s->session->tlsext_ecpointformatlist (length=%i) ", + s->session->tlsext_ecpointformatlist_length); + sdata = s->session->tlsext_ecpointformatlist; + for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++) + fprintf(stderr, "%i ", *(sdata++)); + fprintf(stderr, "\n"); +# endif + } else if (type == TLSEXT_TYPE_elliptic_curves) { + unsigned char *sdata = data; + int ellipticcurvelist_length = (*(sdata++) << 8); + ellipticcurvelist_length += (*(sdata++)); + + if (ellipticcurvelist_length != size - 2 || + ellipticcurvelist_length < 1 || + /* Each NamedCurve is 2 bytes. */ + ellipticcurvelist_length & 1) + goto err; + + if (!s->hit) { + if (s->session->tlsext_ellipticcurvelist) + goto err; + + s->session->tlsext_ellipticcurvelist_length = 0; + if ((s->session->tlsext_ellipticcurvelist = + OPENSSL_malloc(ellipticcurvelist_length)) == NULL) { + *al = TLS1_AD_INTERNAL_ERROR; + return 0; + } + s->session->tlsext_ellipticcurvelist_length = + ellipticcurvelist_length; + memcpy(s->session->tlsext_ellipticcurvelist, sdata, + ellipticcurvelist_length); + } +# if 0 + fprintf(stderr, + "ssl_parse_clienthello_tlsext s->session->tlsext_ellipticcurvelist (length=%i) ", + s->session->tlsext_ellipticcurvelist_length); + sdata = s->session->tlsext_ellipticcurvelist; + for (i = 0; i < s->session->tlsext_ellipticcurvelist_length; i++) + fprintf(stderr, "%i ", *(sdata++)); + fprintf(stderr, "\n"); +# endif + } +# endif /* OPENSSL_NO_EC */ +# ifdef TLSEXT_TYPE_opaque_prf_input + else if (type == TLSEXT_TYPE_opaque_prf_input) { + unsigned char *sdata = data; + + if (size < 2) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + n2s(sdata, s->s3->client_opaque_prf_input_len); + if (s->s3->client_opaque_prf_input_len != size - 2) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + if (s->s3->client_opaque_prf_input != NULL) { + /* shouldn't really happen */ + OPENSSL_free(s->s3->client_opaque_prf_input); + } + + /* dummy byte just to get non-NULL */ + if (s->s3->client_opaque_prf_input_len == 0) + s->s3->client_opaque_prf_input = OPENSSL_malloc(1); + else + s->s3->client_opaque_prf_input = + BUF_memdup(sdata, s->s3->client_opaque_prf_input_len); + if (s->s3->client_opaque_prf_input == NULL) { + *al = TLS1_AD_INTERNAL_ERROR; + return 0; + } + } +# endif + else if (type == TLSEXT_TYPE_session_ticket) { + if (s->tls_session_ticket_ext_cb && + !s->tls_session_ticket_ext_cb(s, data, size, + s->tls_session_ticket_ext_cb_arg)) + { + *al = TLS1_AD_INTERNAL_ERROR; + return 0; + } + } else if (type == TLSEXT_TYPE_renegotiate) { + if (!ssl_parse_clienthello_renegotiate_ext(s, data, size, al)) + return 0; + renegotiate_seen = 1; + } else if (type == TLSEXT_TYPE_signature_algorithms) { + int dsize; + if (s->cert->peer_sigalgs || size < 2) + goto err; + n2s(data, dsize); + size -= 2; + if (dsize != size || dsize & 1 || !dsize) + goto err; + if (!tls1_save_sigalgs(s, data, dsize)) + goto err; + } else if (type == TLSEXT_TYPE_status_request) { + + if (size < 5) + goto err; + + s->tlsext_status_type = *data++; + size--; + if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp) { + const unsigned char *sdata; + int dsize; + /* Read in responder_id_list */ + n2s(data, dsize); + size -= 2; + if (dsize > size) + goto err; + while (dsize > 0) { + OCSP_RESPID *id; + int idsize; + if (dsize < 4) + goto err; + n2s(data, idsize); + dsize -= 2 + idsize; + size -= 2 + idsize; + if (dsize < 0) + goto err; + sdata = data; + data += idsize; + id = d2i_OCSP_RESPID(NULL, &sdata, idsize); + if (!id) + goto err; + if (data != sdata) { + OCSP_RESPID_free(id); + goto err; + } + if (!s->tlsext_ocsp_ids + && !(s->tlsext_ocsp_ids = + sk_OCSP_RESPID_new_null())) { + OCSP_RESPID_free(id); + *al = SSL_AD_INTERNAL_ERROR; + return 0; + } + if (!sk_OCSP_RESPID_push(s->tlsext_ocsp_ids, id)) { + OCSP_RESPID_free(id); + *al = SSL_AD_INTERNAL_ERROR; + return 0; + } + } + + /* Read in request_extensions */ + if (size < 2) + goto err; + n2s(data, dsize); + size -= 2; + if (dsize != size) + goto err; + sdata = data; + if (dsize > 0) { + if (s->tlsext_ocsp_exts) { + sk_X509_EXTENSION_pop_free(s->tlsext_ocsp_exts, + X509_EXTENSION_free); + } + + s->tlsext_ocsp_exts = + d2i_X509_EXTENSIONS(NULL, &sdata, dsize); + if (!s->tlsext_ocsp_exts || (data + dsize != sdata)) + goto err; + } + } + /* + * We don't know what to do with any other type * so ignore it. + */ + else + s->tlsext_status_type = -1; + } +# ifndef OPENSSL_NO_HEARTBEATS + else if (type == TLSEXT_TYPE_heartbeat) { + switch (data[0]) { + case 0x01: /* Client allows us to send HB requests */ + s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED; + break; + case 0x02: /* Client doesn't accept HB requests */ + s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED; + s->tlsext_heartbeat |= SSL_TLSEXT_HB_DONT_SEND_REQUESTS; + break; + default: + *al = SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + } +# endif +# ifndef OPENSSL_NO_NEXTPROTONEG + else if (type == TLSEXT_TYPE_next_proto_neg && + s->s3->tmp.finish_md_len == 0) { + /*- + * We shouldn't accept this extension on a + * renegotiation. + * + * s->new_session will be set on renegotiation, but we + * probably shouldn't rely that it couldn't be set on + * the initial renegotation too in certain cases (when + * there's some other reason to disallow resuming an + * earlier session -- the current code won't be doing + * anything like that, but this might change). + * + * A valid sign that there's been a previous handshake + * in this connection is if s->s3->tmp.finish_md_len > + * 0. (We are talking about a check that will happen + * in the Hello protocol round, well before a new + * Finished message could have been computed.) + */ + s->s3->next_proto_neg_seen = 1; + } +# endif + + else if (type == TLSEXT_TYPE_application_layer_protocol_negotiation && + s->s3->tmp.finish_md_len == 0) { + if (tls1_alpn_handle_client_hello(s, data, size, al) != 0) + return 0; + } + + /* session ticket processed earlier */ +# ifndef OPENSSL_NO_SRTP + else if (SSL_IS_DTLS(s) && SSL_get_srtp_profiles(s) + && type == TLSEXT_TYPE_use_srtp) { + if (ssl_parse_clienthello_use_srtp_ext(s, data, size, al)) + return 0; + } +# endif + + data += size; + } + + /* Spurious data on the end */ + if (data != limit) + goto err; + + *p = data; + + ri_check: + + /* Need RI if renegotiating */ + + if (!renegotiate_seen && s->renegotiate && + !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) { + *al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT, + SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED); + return 0; + } + + return 1; +err: + *al = SSL_AD_DECODE_ERROR; + return 0; +} + +/* + * Parse any custom extensions found. "data" is the start of the extension data + * and "limit" is the end of the record. TODO: add strict syntax checking. + */ + +static int ssl_scan_clienthello_custom_tlsext(SSL *s, + const unsigned char *data, + const unsigned char *limit, + int *al) +{ + unsigned short type, size, len; + /* If resumed session or no custom extensions nothing to do */ + if (s->hit || s->cert->srv_ext.meths_count == 0) + return 1; + + if (data >= limit - 2) + return 1; + n2s(data, len); + + if (data > limit - len) + return 1; + + while (data <= limit - 4) { + n2s(data, type); + n2s(data, size); + + if (data + size > limit) + return 1; + if (custom_ext_parse(s, 1 /* server */ , type, data, size, al) <= 0) + return 0; + + data += size; + } + + return 1; +} + +int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, + unsigned char *limit) +{ + int al = -1; + unsigned char *ptmp = *p; + /* + * Internally supported extensions are parsed first so SNI can be handled + * before custom extensions. An application processing SNI will typically + * switch the parent context using SSL_set_SSL_CTX and custom extensions + * need to be handled by the new SSL_CTX structure. + */ + if (ssl_scan_clienthello_tlsext(s, p, limit, &al) <= 0) { + ssl3_send_alert(s, SSL3_AL_FATAL, al); + return 0; + } + + if (ssl_check_clienthello_tlsext_early(s) <= 0) { + SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT, SSL_R_CLIENTHELLO_TLSEXT); + return 0; + } + + custom_ext_init(&s->cert->srv_ext); + if (ssl_scan_clienthello_custom_tlsext(s, ptmp, limit, &al) <= 0) { + ssl3_send_alert(s, SSL3_AL_FATAL, al); + return 0; + } + + return 1; +} + +# ifndef OPENSSL_NO_NEXTPROTONEG +/* + * ssl_next_proto_validate validates a Next Protocol Negotiation block. No + * elements of zero length are allowed and the set of elements must exactly + * fill the length of the block. + */ +static char ssl_next_proto_validate(unsigned char *d, unsigned len) +{ + unsigned int off = 0; + + while (off < len) { + if (d[off] == 0) + return 0; + off += d[off]; + off++; + } + + return off == len; +} +# endif + +static int ssl_scan_serverhello_tlsext(SSL *s, unsigned char **p, + unsigned char *d, int n, int *al) +{ + unsigned short length; + unsigned short type; + unsigned short size; + unsigned char *data = *p; + int tlsext_servername = 0; + int renegotiate_seen = 0; + +# ifndef OPENSSL_NO_NEXTPROTONEG + s->s3->next_proto_neg_seen = 0; +# endif + s->tlsext_ticket_expected = 0; + + if (s->s3->alpn_selected) { + OPENSSL_free(s->s3->alpn_selected); + s->s3->alpn_selected = NULL; + } +# ifndef OPENSSL_NO_HEARTBEATS + s->tlsext_heartbeat &= ~(SSL_TLSEXT_HB_ENABLED | + SSL_TLSEXT_HB_DONT_SEND_REQUESTS); +# endif + + if (data >= (d + n - 2)) + goto ri_check; + + n2s(data, length); + if (data + length != d + n) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + while (data <= (d + n - 4)) { + n2s(data, type); + n2s(data, size); + + if (data + size > (d + n)) + goto ri_check; + + if (s->tlsext_debug_cb) + s->tlsext_debug_cb(s, 1, type, data, size, s->tlsext_debug_arg); + + if (type == TLSEXT_TYPE_server_name) { + if (s->tlsext_hostname == NULL || size > 0) { + *al = TLS1_AD_UNRECOGNIZED_NAME; + return 0; + } + tlsext_servername = 1; + } +# ifndef OPENSSL_NO_EC + else if (type == TLSEXT_TYPE_ec_point_formats) { + unsigned char *sdata = data; + int ecpointformatlist_length = *(sdata++); + + if (ecpointformatlist_length != size - 1) { + *al = TLS1_AD_DECODE_ERROR; + return 0; + } + if (!s->hit) { + s->session->tlsext_ecpointformatlist_length = 0; + if (s->session->tlsext_ecpointformatlist != NULL) + OPENSSL_free(s->session->tlsext_ecpointformatlist); + if ((s->session->tlsext_ecpointformatlist = + OPENSSL_malloc(ecpointformatlist_length)) == NULL) { + *al = TLS1_AD_INTERNAL_ERROR; + return 0; + } + s->session->tlsext_ecpointformatlist_length = + ecpointformatlist_length; + memcpy(s->session->tlsext_ecpointformatlist, sdata, + ecpointformatlist_length); + } +# if 0 + fprintf(stderr, + "ssl_parse_serverhello_tlsext s->session->tlsext_ecpointformatlist "); + sdata = s->session->tlsext_ecpointformatlist; + for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++) + fprintf(stderr, "%i ", *(sdata++)); + fprintf(stderr, "\n"); +# endif + } +# endif /* OPENSSL_NO_EC */ + + else if (type == TLSEXT_TYPE_session_ticket) { + if (s->tls_session_ticket_ext_cb && + !s->tls_session_ticket_ext_cb(s, data, size, + s->tls_session_ticket_ext_cb_arg)) + { + *al = TLS1_AD_INTERNAL_ERROR; + return 0; + } + if ((SSL_get_options(s) & SSL_OP_NO_TICKET) + || (size > 0)) { + *al = TLS1_AD_UNSUPPORTED_EXTENSION; + return 0; + } + s->tlsext_ticket_expected = 1; + } +# ifdef TLSEXT_TYPE_opaque_prf_input + else if (type == TLSEXT_TYPE_opaque_prf_input) { + unsigned char *sdata = data; + + if (size < 2) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + n2s(sdata, s->s3->server_opaque_prf_input_len); + if (s->s3->server_opaque_prf_input_len != size - 2) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + if (s->s3->server_opaque_prf_input != NULL) { + /* shouldn't really happen */ + OPENSSL_free(s->s3->server_opaque_prf_input); + } + if (s->s3->server_opaque_prf_input_len == 0) { + /* dummy byte just to get non-NULL */ + s->s3->server_opaque_prf_input = OPENSSL_malloc(1); + } else { + s->s3->server_opaque_prf_input = + BUF_memdup(sdata, s->s3->server_opaque_prf_input_len); + } + + if (s->s3->server_opaque_prf_input == NULL) { + *al = TLS1_AD_INTERNAL_ERROR; + return 0; + } + } +# endif + else if (type == TLSEXT_TYPE_status_request) { + /* + * MUST be empty and only sent if we've requested a status + * request message. + */ + if ((s->tlsext_status_type == -1) || (size > 0)) { + *al = TLS1_AD_UNSUPPORTED_EXTENSION; + return 0; + } + /* Set flag to expect CertificateStatus message */ + s->tlsext_status_expected = 1; + } +# ifndef OPENSSL_NO_NEXTPROTONEG + else if (type == TLSEXT_TYPE_next_proto_neg && + s->s3->tmp.finish_md_len == 0) { + unsigned char *selected; + unsigned char selected_len; + + /* We must have requested it. */ + if (s->ctx->next_proto_select_cb == NULL) { + *al = TLS1_AD_UNSUPPORTED_EXTENSION; + return 0; + } + /* The data must be valid */ + if (!ssl_next_proto_validate(data, size)) { + *al = TLS1_AD_DECODE_ERROR; + return 0; + } + if (s-> + ctx->next_proto_select_cb(s, &selected, &selected_len, data, + size, + s->ctx->next_proto_select_cb_arg) != + SSL_TLSEXT_ERR_OK) { + *al = TLS1_AD_INTERNAL_ERROR; + return 0; + } + s->next_proto_negotiated = OPENSSL_malloc(selected_len); + if (!s->next_proto_negotiated) { + *al = TLS1_AD_INTERNAL_ERROR; + return 0; + } + memcpy(s->next_proto_negotiated, selected, selected_len); + s->next_proto_negotiated_len = selected_len; + s->s3->next_proto_neg_seen = 1; + } +# endif + + else if (type == TLSEXT_TYPE_application_layer_protocol_negotiation) { + unsigned len; + + /* We must have requested it. */ + if (!s->cert->alpn_sent) { + *al = TLS1_AD_UNSUPPORTED_EXTENSION; + return 0; + } + if (size < 4) { + *al = TLS1_AD_DECODE_ERROR; + return 0; + } + /*- + * The extension data consists of: + * uint16 list_length + * uint8 proto_length; + * uint8 proto[proto_length]; + */ + len = data[0]; + len <<= 8; + len |= data[1]; + if (len != (unsigned)size - 2) { + *al = TLS1_AD_DECODE_ERROR; + return 0; + } + len = data[2]; + if (len != (unsigned)size - 3) { + *al = TLS1_AD_DECODE_ERROR; + return 0; + } + if (s->s3->alpn_selected) + OPENSSL_free(s->s3->alpn_selected); + s->s3->alpn_selected = OPENSSL_malloc(len); + if (!s->s3->alpn_selected) { + *al = TLS1_AD_INTERNAL_ERROR; + return 0; + } + memcpy(s->s3->alpn_selected, data + 3, len); + s->s3->alpn_selected_len = len; + } + + else if (type == TLSEXT_TYPE_renegotiate) { + if (!ssl_parse_serverhello_renegotiate_ext(s, data, size, al)) + return 0; + renegotiate_seen = 1; + } +# ifndef OPENSSL_NO_HEARTBEATS + else if (type == TLSEXT_TYPE_heartbeat) { + switch (data[0]) { + case 0x01: /* Server allows us to send HB requests */ + s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED; + break; + case 0x02: /* Server doesn't accept HB requests */ + s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED; + s->tlsext_heartbeat |= SSL_TLSEXT_HB_DONT_SEND_REQUESTS; + break; + default: + *al = SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + } +# endif +# ifndef OPENSSL_NO_SRTP + else if (SSL_IS_DTLS(s) && type == TLSEXT_TYPE_use_srtp) { + if (ssl_parse_serverhello_use_srtp_ext(s, data, size, al)) + return 0; + } +# endif + /* + * If this extension type was not otherwise handled, but matches a + * custom_cli_ext_record, then send it to the c callback + */ + else if (custom_ext_parse(s, 0, type, data, size, al) <= 0) + return 0; + + data += size; + } + + if (data != d + n) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + if (!s->hit && tlsext_servername == 1) { + if (s->tlsext_hostname) { + if (s->session->tlsext_hostname == NULL) { + s->session->tlsext_hostname = BUF_strdup(s->tlsext_hostname); + if (!s->session->tlsext_hostname) { + *al = SSL_AD_UNRECOGNIZED_NAME; + return 0; + } + } else { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + } + } + + *p = data; + + ri_check: + + /* + * Determine if we need to see RI. Strictly speaking if we want to avoid + * an attack we should *always* see RI even on initial server hello + * because the client doesn't see any renegotiation during an attack. + * However this would mean we could not connect to any server which + * doesn't support RI so for the immediate future tolerate RI absence on + * initial connect only. + */ + if (!renegotiate_seen && !(s->options & SSL_OP_LEGACY_SERVER_CONNECT) + && !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) { + *al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT, + SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED); + return 0; + } + + return 1; +} + +int ssl_prepare_clienthello_tlsext(SSL *s) +{ + +# ifdef TLSEXT_TYPE_opaque_prf_input + { + int r = 1; + + if (s->ctx->tlsext_opaque_prf_input_callback != 0) { + r = s->ctx->tlsext_opaque_prf_input_callback(s, NULL, 0, + s-> + ctx->tlsext_opaque_prf_input_callback_arg); + if (!r) + return -1; + } + + if (s->tlsext_opaque_prf_input != NULL) { + if (s->s3->client_opaque_prf_input != NULL) { + /* shouldn't really happen */ + OPENSSL_free(s->s3->client_opaque_prf_input); + } + + if (s->tlsext_opaque_prf_input_len == 0) { + /* dummy byte just to get non-NULL */ + s->s3->client_opaque_prf_input = OPENSSL_malloc(1); + } else { + s->s3->client_opaque_prf_input = + BUF_memdup(s->tlsext_opaque_prf_input, + s->tlsext_opaque_prf_input_len); + } + if (s->s3->client_opaque_prf_input == NULL) { + SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT, + ERR_R_MALLOC_FAILURE); + return -1; + } + s->s3->client_opaque_prf_input_len = + s->tlsext_opaque_prf_input_len; + } + + if (r == 2) + /* + * at callback's request, insist on receiving an appropriate + * server opaque PRF input + */ + s->s3->server_opaque_prf_input_len = + s->tlsext_opaque_prf_input_len; + } +# endif + + s->cert->alpn_sent = 0; + return 1; +} + +int ssl_prepare_serverhello_tlsext(SSL *s) +{ + return 1; +} + +static int ssl_check_clienthello_tlsext_early(SSL *s) +{ + int ret = SSL_TLSEXT_ERR_NOACK; + int al = SSL_AD_UNRECOGNIZED_NAME; + +# ifndef OPENSSL_NO_EC + /* + * The handling of the ECPointFormats extension is done elsewhere, namely + * in ssl3_choose_cipher in s3_lib.c. + */ + /* + * The handling of the EllipticCurves extension is done elsewhere, namely + * in ssl3_choose_cipher in s3_lib.c. + */ +# endif + + if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0) + ret = + s->ctx->tlsext_servername_callback(s, &al, + s->ctx->tlsext_servername_arg); + else if (s->initial_ctx != NULL + && s->initial_ctx->tlsext_servername_callback != 0) + ret = + s->initial_ctx->tlsext_servername_callback(s, &al, + s-> + initial_ctx->tlsext_servername_arg); + +# ifdef TLSEXT_TYPE_opaque_prf_input + { + /* + * This sort of belongs into ssl_prepare_serverhello_tlsext(), but we + * might be sending an alert in response to the client hello, so this + * has to happen here in ssl_check_clienthello_tlsext_early(). + */ + + int r = 1; + + if (s->ctx->tlsext_opaque_prf_input_callback != 0) { + r = s->ctx->tlsext_opaque_prf_input_callback(s, NULL, 0, + s-> + ctx->tlsext_opaque_prf_input_callback_arg); + if (!r) { + ret = SSL_TLSEXT_ERR_ALERT_FATAL; + al = SSL_AD_INTERNAL_ERROR; + goto err; + } + } + + if (s->s3->server_opaque_prf_input != NULL) { + /* shouldn't really happen */ + OPENSSL_free(s->s3->server_opaque_prf_input); + } + s->s3->server_opaque_prf_input = NULL; + + if (s->tlsext_opaque_prf_input != NULL) { + if (s->s3->client_opaque_prf_input != NULL && + s->s3->client_opaque_prf_input_len == + s->tlsext_opaque_prf_input_len) { + /* + * can only use this extension if we have a server opaque PRF + * input of the same length as the client opaque PRF input! + */ + + if (s->tlsext_opaque_prf_input_len == 0) { + /* dummy byte just to get non-NULL */ + s->s3->server_opaque_prf_input = OPENSSL_malloc(1); + } else { + s->s3->server_opaque_prf_input = + BUF_memdup(s->tlsext_opaque_prf_input, + s->tlsext_opaque_prf_input_len); + } + if (s->s3->server_opaque_prf_input == NULL) { + ret = SSL_TLSEXT_ERR_ALERT_FATAL; + al = SSL_AD_INTERNAL_ERROR; + goto err; + } + s->s3->server_opaque_prf_input_len = + s->tlsext_opaque_prf_input_len; + } + } + + if (r == 2 && s->s3->server_opaque_prf_input == NULL) { + /* + * The callback wants to enforce use of the extension, but we + * can't do that with the client opaque PRF input; abort the + * handshake. + */ + ret = SSL_TLSEXT_ERR_ALERT_FATAL; + al = SSL_AD_HANDSHAKE_FAILURE; + } + } + + err: +# endif + switch (ret) { + case SSL_TLSEXT_ERR_ALERT_FATAL: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + return -1; + + case SSL_TLSEXT_ERR_ALERT_WARNING: + ssl3_send_alert(s, SSL3_AL_WARNING, al); + return 1; + + case SSL_TLSEXT_ERR_NOACK: + s->servername_done = 0; + default: + return 1; + } +} + +int tls1_set_server_sigalgs(SSL *s) +{ + int al; + size_t i; + /* Clear any shared sigtnature algorithms */ + if (s->cert->shared_sigalgs) { + OPENSSL_free(s->cert->shared_sigalgs); + s->cert->shared_sigalgs = NULL; + s->cert->shared_sigalgslen = 0; + } + /* Clear certificate digests and validity flags */ + for (i = 0; i < SSL_PKEY_NUM; i++) { + s->cert->pkeys[i].digest = NULL; + s->cert->pkeys[i].valid_flags = 0; + } + + /* If sigalgs received process it. */ + if (s->cert->peer_sigalgs) { + if (!tls1_process_sigalgs(s)) { + SSLerr(SSL_F_TLS1_SET_SERVER_SIGALGS, ERR_R_MALLOC_FAILURE); + al = SSL_AD_INTERNAL_ERROR; + goto err; + } + /* Fatal error is no shared signature algorithms */ + if (!s->cert->shared_sigalgs) { + SSLerr(SSL_F_TLS1_SET_SERVER_SIGALGS, + SSL_R_NO_SHARED_SIGATURE_ALGORITHMS); + al = SSL_AD_ILLEGAL_PARAMETER; + goto err; + } + } else + ssl_cert_set_default_md(s->cert); + return 1; + err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + return 0; +} + +int ssl_check_clienthello_tlsext_late(SSL *s) +{ + int ret = SSL_TLSEXT_ERR_OK; + int al; + + /* + * If status request then ask callback what to do. Note: this must be + * called after servername callbacks in case the certificate has changed, + * and must be called after the cipher has been chosen because this may + * influence which certificate is sent + */ + if ((s->tlsext_status_type != -1) && s->ctx && s->ctx->tlsext_status_cb) { + int r; + CERT_PKEY *certpkey; + certpkey = ssl_get_server_send_pkey(s); + /* If no certificate can't return certificate status */ + if (certpkey == NULL) { + s->tlsext_status_expected = 0; + return 1; + } + /* + * Set current certificate to one we will use so SSL_get_certificate + * et al can pick it up. + */ + s->cert->key = certpkey; + r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg); + switch (r) { + /* We don't want to send a status request response */ + case SSL_TLSEXT_ERR_NOACK: + s->tlsext_status_expected = 0; + break; + /* status request response should be sent */ + case SSL_TLSEXT_ERR_OK: + if (s->tlsext_ocsp_resp) + s->tlsext_status_expected = 1; + else + s->tlsext_status_expected = 0; + break; + /* something bad happened */ + case SSL_TLSEXT_ERR_ALERT_FATAL: + ret = SSL_TLSEXT_ERR_ALERT_FATAL; + al = SSL_AD_INTERNAL_ERROR; + goto err; + } + } else + s->tlsext_status_expected = 0; + + if (!tls1_alpn_handle_client_hello_late(s, &ret, &al)) { + goto err; + } + + err: + switch (ret) { + case SSL_TLSEXT_ERR_ALERT_FATAL: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + return -1; + + case SSL_TLSEXT_ERR_ALERT_WARNING: + ssl3_send_alert(s, SSL3_AL_WARNING, al); + return 1; + + default: + return 1; + } +} + +int ssl_check_serverhello_tlsext(SSL *s) +{ + int ret = SSL_TLSEXT_ERR_NOACK; + int al = SSL_AD_UNRECOGNIZED_NAME; + +# ifndef OPENSSL_NO_EC + /* + * If we are client and using an elliptic curve cryptography cipher + * suite, then if server returns an EC point formats lists extension it + * must contain uncompressed. + */ + unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey; + unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth; + if ((s->tlsext_ecpointformatlist != NULL) + && (s->tlsext_ecpointformatlist_length > 0) + && (s->session->tlsext_ecpointformatlist != NULL) + && (s->session->tlsext_ecpointformatlist_length > 0) + && ((alg_k & (SSL_kEECDH | SSL_kECDHr | SSL_kECDHe)) + || (alg_a & SSL_aECDSA))) { + /* we are using an ECC cipher */ + size_t i; + unsigned char *list; + int found_uncompressed = 0; + list = s->session->tlsext_ecpointformatlist; + for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++) { + if (*(list++) == TLSEXT_ECPOINTFORMAT_uncompressed) { + found_uncompressed = 1; + break; + } + } + if (!found_uncompressed) { + SSLerr(SSL_F_SSL_CHECK_SERVERHELLO_TLSEXT, + SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST); + return -1; + } + } + ret = SSL_TLSEXT_ERR_OK; +# endif /* OPENSSL_NO_EC */ + + if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0) + ret = + s->ctx->tlsext_servername_callback(s, &al, + s->ctx->tlsext_servername_arg); + else if (s->initial_ctx != NULL + && s->initial_ctx->tlsext_servername_callback != 0) + ret = + s->initial_ctx->tlsext_servername_callback(s, &al, + s-> + initial_ctx->tlsext_servername_arg); + +# ifdef TLSEXT_TYPE_opaque_prf_input + if (s->s3->server_opaque_prf_input_len > 0) { + /* + * This case may indicate that we, as a client, want to insist on + * using opaque PRF inputs. So first verify that we really have a + * value from the server too. + */ + + if (s->s3->server_opaque_prf_input == NULL) { + ret = SSL_TLSEXT_ERR_ALERT_FATAL; + al = SSL_AD_HANDSHAKE_FAILURE; + } + + /* + * Anytime the server *has* sent an opaque PRF input, we need to + * check that we have a client opaque PRF input of the same size. + */ + if (s->s3->client_opaque_prf_input == NULL || + s->s3->client_opaque_prf_input_len != + s->s3->server_opaque_prf_input_len) { + ret = SSL_TLSEXT_ERR_ALERT_FATAL; + al = SSL_AD_ILLEGAL_PARAMETER; + } + } +# endif + + OPENSSL_free(s->tlsext_ocsp_resp); + s->tlsext_ocsp_resp = NULL; + s->tlsext_ocsp_resplen = -1; + /* + * If we've requested certificate status and we wont get one tell the + * callback + */ + if ((s->tlsext_status_type != -1) && !(s->tlsext_status_expected) + && !(s->hit) && s->ctx && s->ctx->tlsext_status_cb) { + int r; + /* + * Call callback with resp == NULL and resplen == -1 so callback + * knows there is no response + */ + r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg); + if (r == 0) { + al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE; + ret = SSL_TLSEXT_ERR_ALERT_FATAL; + } + if (r < 0) { + al = SSL_AD_INTERNAL_ERROR; + ret = SSL_TLSEXT_ERR_ALERT_FATAL; + } + } + + switch (ret) { + case SSL_TLSEXT_ERR_ALERT_FATAL: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + return -1; + + case SSL_TLSEXT_ERR_ALERT_WARNING: + ssl3_send_alert(s, SSL3_AL_WARNING, al); + return 1; + + case SSL_TLSEXT_ERR_NOACK: + s->servername_done = 0; + default: + return 1; + } +} + +int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, + int n) +{ + int al = -1; + if (s->version < SSL3_VERSION) + return 1; + if (ssl_scan_serverhello_tlsext(s, p, d, n, &al) <= 0) { + ssl3_send_alert(s, SSL3_AL_FATAL, al); + return 0; + } + + if (ssl_check_serverhello_tlsext(s) <= 0) { + SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT, SSL_R_SERVERHELLO_TLSEXT); + return 0; + } + return 1; +} + +/*- + * Since the server cache lookup is done early on in the processing of the + * ClientHello, and other operations depend on the result, we need to handle + * any TLS session ticket extension at the same time. + * + * session_id: points at the session ID in the ClientHello. This code will + * read past the end of this in order to parse out the session ticket + * extension, if any. + * len: the length of the session ID. + * limit: a pointer to the first byte after the ClientHello. + * ret: (output) on return, if a ticket was decrypted, then this is set to + * point to the resulting session. + * + * If s->tls_session_secret_cb is set then we are expecting a pre-shared key + * ciphersuite, in which case we have no use for session tickets and one will + * never be decrypted, nor will s->tlsext_ticket_expected be set to 1. + * + * Returns: + * -1: fatal error, either from parsing or decrypting the ticket. + * 0: no ticket was found (or was ignored, based on settings). + * 1: a zero length extension was found, indicating that the client supports + * session tickets but doesn't currently have one to offer. + * 2: either s->tls_session_secret_cb was set, or a ticket was offered but + * couldn't be decrypted because of a non-fatal error. + * 3: a ticket was successfully decrypted and *ret was set. + * + * Side effects: + * Sets s->tlsext_ticket_expected to 1 if the server will have to issue + * a new session ticket to the client because the client indicated support + * (and s->tls_session_secret_cb is NULL) but the client either doesn't have + * a session ticket or we couldn't use the one it gave us, or if + * s->ctx->tlsext_ticket_key_cb asked to renew the client's ticket. + * Otherwise, s->tlsext_ticket_expected is set to 0. + */ +int tls1_process_ticket(SSL *s, unsigned char *session_id, int len, + const unsigned char *limit, SSL_SESSION **ret) +{ + /* Point after session ID in client hello */ + const unsigned char *p = session_id + len; + unsigned short i; + + *ret = NULL; + s->tlsext_ticket_expected = 0; + + /* + * If tickets disabled behave as if no ticket present to permit stateful + * resumption. + */ + if (SSL_get_options(s) & SSL_OP_NO_TICKET) + return 0; + if ((s->version <= SSL3_VERSION) || !limit) + return 0; + if (p >= limit) + return -1; + /* Skip past DTLS cookie */ + if (SSL_IS_DTLS(s)) { + i = *(p++); + p += i; + if (p >= limit) + return -1; + } + /* Skip past cipher list */ + n2s(p, i); + p += i; + if (p >= limit) + return -1; + /* Skip past compression algorithm list */ + i = *(p++); + p += i; + if (p > limit) + return -1; + /* Now at start of extensions */ + if ((p + 2) >= limit) + return 0; + n2s(p, i); + while ((p + 4) <= limit) { + unsigned short type, size; + n2s(p, type); + n2s(p, size); + if (p + size > limit) + return 0; + if (type == TLSEXT_TYPE_session_ticket) { + int r; + if (size == 0) { + /* + * The client will accept a ticket but doesn't currently have + * one. + */ + s->tlsext_ticket_expected = 1; + return 1; + } + if (s->tls_session_secret_cb) { + /* + * Indicate that the ticket couldn't be decrypted rather than + * generating the session from ticket now, trigger + * abbreviated handshake based on external mechanism to + * calculate the master secret later. + */ + return 2; + } + r = tls_decrypt_ticket(s, p, size, session_id, len, ret); + switch (r) { + case 2: /* ticket couldn't be decrypted */ + s->tlsext_ticket_expected = 1; + return 2; + case 3: /* ticket was decrypted */ + return r; + case 4: /* ticket decrypted but need to renew */ + s->tlsext_ticket_expected = 1; + return 3; + default: /* fatal error */ + return -1; + } + } + p += size; + } + return 0; +} + +/*- + * tls_decrypt_ticket attempts to decrypt a session ticket. + * + * etick: points to the body of the session ticket extension. + * eticklen: the length of the session tickets extenion. + * sess_id: points at the session ID. + * sesslen: the length of the session ID. + * psess: (output) on return, if a ticket was decrypted, then this is set to + * point to the resulting session. + * + * Returns: + * -1: fatal error, either from parsing or decrypting the ticket. + * 2: the ticket couldn't be decrypted. + * 3: a ticket was successfully decrypted and *psess was set. + * 4: same as 3, but the ticket needs to be renewed. + */ +static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, + int eticklen, const unsigned char *sess_id, + int sesslen, SSL_SESSION **psess) +{ + SSL_SESSION *sess; + unsigned char *sdec; + const unsigned char *p; + int slen, mlen, renew_ticket = 0; + unsigned char tick_hmac[EVP_MAX_MD_SIZE]; + HMAC_CTX hctx; + EVP_CIPHER_CTX ctx; + SSL_CTX *tctx = s->initial_ctx; + /* Need at least keyname + iv + some encrypted data */ + if (eticklen < 48) + return 2; + /* Initialize session ticket encryption and HMAC contexts */ + HMAC_CTX_init(&hctx); + EVP_CIPHER_CTX_init(&ctx); + if (tctx->tlsext_ticket_key_cb) { + unsigned char *nctick = (unsigned char *)etick; + int rv = tctx->tlsext_ticket_key_cb(s, nctick, nctick + 16, + &ctx, &hctx, 0); + if (rv < 0) + return -1; + if (rv == 0) + return 2; + if (rv == 2) + renew_ticket = 1; + } else { + /* Check key name matches */ + if (memcmp(etick, tctx->tlsext_tick_key_name, 16)) + return 2; + if (HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16, + tlsext_tick_md(), NULL) <= 0 + || EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, + tctx->tlsext_tick_aes_key, + etick + 16) <= 0) { + goto err; + } + } + /* + * Attempt to process session ticket, first conduct sanity and integrity + * checks on ticket. + */ + mlen = HMAC_size(&hctx); + if (mlen < 0) { + goto err; + } + eticklen -= mlen; + /* Check HMAC of encrypted ticket */ + if (HMAC_Update(&hctx, etick, eticklen) <= 0 + || HMAC_Final(&hctx, tick_hmac, NULL) <= 0) { + goto err; + } + HMAC_CTX_cleanup(&hctx); + if (CRYPTO_memcmp(tick_hmac, etick + eticklen, mlen)) { + EVP_CIPHER_CTX_cleanup(&ctx); + return 2; + } + /* Attempt to decrypt session data */ + /* Move p after IV to start of encrypted ticket, update length */ + p = etick + 16 + EVP_CIPHER_CTX_iv_length(&ctx); + eticklen -= 16 + EVP_CIPHER_CTX_iv_length(&ctx); + sdec = OPENSSL_malloc(eticklen); + if (sdec == NULL + || EVP_DecryptUpdate(&ctx, sdec, &slen, p, eticklen) <= 0) { + EVP_CIPHER_CTX_cleanup(&ctx); + OPENSSL_free(sdec); + return -1; + } + if (EVP_DecryptFinal(&ctx, sdec + slen, &mlen) <= 0) { + EVP_CIPHER_CTX_cleanup(&ctx); + OPENSSL_free(sdec); + return 2; + } + slen += mlen; + EVP_CIPHER_CTX_cleanup(&ctx); + p = sdec; + + sess = d2i_SSL_SESSION(NULL, &p, slen); + OPENSSL_free(sdec); + if (sess) { + /* + * The session ID, if non-empty, is used by some clients to detect + * that the ticket has been accepted. So we copy it to the session + * structure. If it is empty set length to zero as required by + * standard. + */ + if (sesslen) + memcpy(sess->session_id, sess_id, sesslen); + sess->session_id_length = sesslen; + *psess = sess; + if (renew_ticket) + return 4; + else + return 3; + } + ERR_clear_error(); + /* + * For session parse failure, indicate that we need to send a new ticket. + */ + return 2; +err: + EVP_CIPHER_CTX_cleanup(&ctx); + HMAC_CTX_cleanup(&hctx); + return -1; +} + +/* Tables to translate from NIDs to TLS v1.2 ids */ + +typedef struct { + int nid; + int id; +} tls12_lookup; + +static tls12_lookup tls12_md[] = { + {NID_md5, TLSEXT_hash_md5}, + {NID_sha1, TLSEXT_hash_sha1}, + {NID_sha224, TLSEXT_hash_sha224}, + {NID_sha256, TLSEXT_hash_sha256}, + {NID_sha384, TLSEXT_hash_sha384}, + {NID_sha512, TLSEXT_hash_sha512} +}; + +static tls12_lookup tls12_sig[] = { + {EVP_PKEY_RSA, TLSEXT_signature_rsa}, + {EVP_PKEY_DSA, TLSEXT_signature_dsa}, + {EVP_PKEY_EC, TLSEXT_signature_ecdsa} +}; + +static int tls12_find_id(int nid, tls12_lookup *table, size_t tlen) +{ + size_t i; + for (i = 0; i < tlen; i++) { + if (table[i].nid == nid) + return table[i].id; + } + return -1; +} + +static int tls12_find_nid(int id, tls12_lookup *table, size_t tlen) +{ + size_t i; + for (i = 0; i < tlen; i++) { + if ((table[i].id) == id) + return table[i].nid; + } + return NID_undef; +} + +int tls12_get_sigandhash(unsigned char *p, const EVP_PKEY *pk, + const EVP_MD *md) +{ + int sig_id, md_id; + if (!md) + return 0; + md_id = tls12_find_id(EVP_MD_type(md), tls12_md, + sizeof(tls12_md) / sizeof(tls12_lookup)); + if (md_id == -1) + return 0; + sig_id = tls12_get_sigid(pk); + if (sig_id == -1) + return 0; + p[0] = (unsigned char)md_id; + p[1] = (unsigned char)sig_id; + return 1; +} + +int tls12_get_sigid(const EVP_PKEY *pk) +{ + return tls12_find_id(pk->type, tls12_sig, + sizeof(tls12_sig) / sizeof(tls12_lookup)); +} + +const EVP_MD *tls12_get_hash(unsigned char hash_alg) +{ + switch (hash_alg) { +# ifndef OPENSSL_NO_MD5 + case TLSEXT_hash_md5: +# ifdef OPENSSL_FIPS + if (FIPS_mode()) + return NULL; +# endif + return EVP_md5(); +# endif +# ifndef OPENSSL_NO_SHA + case TLSEXT_hash_sha1: + return EVP_sha1(); +# endif +# ifndef OPENSSL_NO_SHA256 + case TLSEXT_hash_sha224: + return EVP_sha224(); + + case TLSEXT_hash_sha256: + return EVP_sha256(); +# endif +# ifndef OPENSSL_NO_SHA512 + case TLSEXT_hash_sha384: + return EVP_sha384(); + + case TLSEXT_hash_sha512: + return EVP_sha512(); +# endif + default: + return NULL; + + } +} + +static int tls12_get_pkey_idx(unsigned char sig_alg) +{ + switch (sig_alg) { +# ifndef OPENSSL_NO_RSA + case TLSEXT_signature_rsa: + return SSL_PKEY_RSA_SIGN; +# endif +# ifndef OPENSSL_NO_DSA + case TLSEXT_signature_dsa: + return SSL_PKEY_DSA_SIGN; +# endif +# ifndef OPENSSL_NO_ECDSA + case TLSEXT_signature_ecdsa: + return SSL_PKEY_ECC; +# endif + } + return -1; +} + +/* Convert TLS 1.2 signature algorithm extension values into NIDs */ +static void tls1_lookup_sigalg(int *phash_nid, int *psign_nid, + int *psignhash_nid, const unsigned char *data) +{ + int sign_nid = NID_undef, hash_nid = NID_undef; + if (!phash_nid && !psign_nid && !psignhash_nid) + return; + if (phash_nid || psignhash_nid) { + hash_nid = tls12_find_nid(data[0], tls12_md, + sizeof(tls12_md) / sizeof(tls12_lookup)); + if (phash_nid) + *phash_nid = hash_nid; + } + if (psign_nid || psignhash_nid) { + sign_nid = tls12_find_nid(data[1], tls12_sig, + sizeof(tls12_sig) / sizeof(tls12_lookup)); + if (psign_nid) + *psign_nid = sign_nid; + } + if (psignhash_nid) { + if (sign_nid == NID_undef || hash_nid == NID_undef + || OBJ_find_sigid_by_algs(psignhash_nid, hash_nid, + sign_nid) <= 0) + *psignhash_nid = NID_undef; + } +} + +/* Given preference and allowed sigalgs set shared sigalgs */ +static int tls12_do_shared_sigalgs(TLS_SIGALGS *shsig, + const unsigned char *pref, size_t preflen, + const unsigned char *allow, + size_t allowlen) +{ + const unsigned char *ptmp, *atmp; + size_t i, j, nmatch = 0; + for (i = 0, ptmp = pref; i < preflen; i += 2, ptmp += 2) { + /* Skip disabled hashes or signature algorithms */ + if (tls12_get_hash(ptmp[0]) == NULL) + continue; + if (tls12_get_pkey_idx(ptmp[1]) == -1) + continue; + for (j = 0, atmp = allow; j < allowlen; j += 2, atmp += 2) { + if (ptmp[0] == atmp[0] && ptmp[1] == atmp[1]) { + nmatch++; + if (shsig) { + shsig->rhash = ptmp[0]; + shsig->rsign = ptmp[1]; + tls1_lookup_sigalg(&shsig->hash_nid, + &shsig->sign_nid, + &shsig->signandhash_nid, ptmp); + shsig++; + } + break; + } + } + } + return nmatch; +} + +/* Set shared signature algorithms for SSL structures */ +static int tls1_set_shared_sigalgs(SSL *s) +{ + const unsigned char *pref, *allow, *conf; + size_t preflen, allowlen, conflen; + size_t nmatch; + TLS_SIGALGS *salgs = NULL; + CERT *c = s->cert; + unsigned int is_suiteb = tls1_suiteb(s); + if (c->shared_sigalgs) { + OPENSSL_free(c->shared_sigalgs); + c->shared_sigalgs = NULL; + c->shared_sigalgslen = 0; + } + /* If client use client signature algorithms if not NULL */ + if (!s->server && c->client_sigalgs && !is_suiteb) { + conf = c->client_sigalgs; + conflen = c->client_sigalgslen; + } else if (c->conf_sigalgs && !is_suiteb) { + conf = c->conf_sigalgs; + conflen = c->conf_sigalgslen; + } else + conflen = tls12_get_psigalgs(s, &conf); + if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE || is_suiteb) { + pref = conf; + preflen = conflen; + allow = c->peer_sigalgs; + allowlen = c->peer_sigalgslen; + } else { + allow = conf; + allowlen = conflen; + pref = c->peer_sigalgs; + preflen = c->peer_sigalgslen; + } + nmatch = tls12_do_shared_sigalgs(NULL, pref, preflen, allow, allowlen); + if (nmatch) { + salgs = OPENSSL_malloc(nmatch * sizeof(TLS_SIGALGS)); + if (!salgs) + return 0; + nmatch = tls12_do_shared_sigalgs(salgs, pref, preflen, allow, allowlen); + } else { + salgs = NULL; + } + c->shared_sigalgs = salgs; + c->shared_sigalgslen = nmatch; + return 1; +} + +/* Set preferred digest for each key type */ + +int tls1_save_sigalgs(SSL *s, const unsigned char *data, int dsize) +{ + CERT *c = s->cert; + /* Extension ignored for inappropriate versions */ + if (!SSL_USE_SIGALGS(s)) + return 1; + /* Should never happen */ + if (!c) + return 0; + + if (c->peer_sigalgs) + OPENSSL_free(c->peer_sigalgs); + c->peer_sigalgs = OPENSSL_malloc(dsize); + if (!c->peer_sigalgs) + return 0; + c->peer_sigalgslen = dsize; + memcpy(c->peer_sigalgs, data, dsize); + return 1; +} + +int tls1_process_sigalgs(SSL *s) +{ + int idx; + size_t i; + const EVP_MD *md; + CERT *c = s->cert; + TLS_SIGALGS *sigptr; + if (!tls1_set_shared_sigalgs(s)) + return 0; + +# ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL + if (s->cert->cert_flags & SSL_CERT_FLAG_BROKEN_PROTOCOL) { + /* + * Use first set signature preference to force message digest, + * ignoring any peer preferences. + */ + const unsigned char *sigs = NULL; + if (s->server) + sigs = c->conf_sigalgs; + else + sigs = c->client_sigalgs; + if (sigs) { + idx = tls12_get_pkey_idx(sigs[1]); + md = tls12_get_hash(sigs[0]); + c->pkeys[idx].digest = md; + c->pkeys[idx].valid_flags = CERT_PKEY_EXPLICIT_SIGN; + if (idx == SSL_PKEY_RSA_SIGN) { + c->pkeys[SSL_PKEY_RSA_ENC].valid_flags = + CERT_PKEY_EXPLICIT_SIGN; + c->pkeys[SSL_PKEY_RSA_ENC].digest = md; + } + } + } +# endif + + for (i = 0, sigptr = c->shared_sigalgs; + i < c->shared_sigalgslen; i++, sigptr++) { + idx = tls12_get_pkey_idx(sigptr->rsign); + if (idx > 0 && c->pkeys[idx].digest == NULL) { + md = tls12_get_hash(sigptr->rhash); + c->pkeys[idx].digest = md; + c->pkeys[idx].valid_flags = CERT_PKEY_EXPLICIT_SIGN; + if (idx == SSL_PKEY_RSA_SIGN) { + c->pkeys[SSL_PKEY_RSA_ENC].valid_flags = + CERT_PKEY_EXPLICIT_SIGN; + c->pkeys[SSL_PKEY_RSA_ENC].digest = md; + } + } + + } + /* + * In strict mode leave unset digests as NULL to indicate we can't use + * the certificate for signing. + */ + if (!(s->cert->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT)) { + /* + * Set any remaining keys to default values. NOTE: if alg is not + * supported it stays as NULL. + */ +# ifndef OPENSSL_NO_DSA + if (!c->pkeys[SSL_PKEY_DSA_SIGN].digest) + c->pkeys[SSL_PKEY_DSA_SIGN].digest = EVP_sha1(); +# endif +# ifndef OPENSSL_NO_RSA + if (!c->pkeys[SSL_PKEY_RSA_SIGN].digest) { + c->pkeys[SSL_PKEY_RSA_SIGN].digest = EVP_sha1(); + c->pkeys[SSL_PKEY_RSA_ENC].digest = EVP_sha1(); + } +# endif +# ifndef OPENSSL_NO_ECDSA + if (!c->pkeys[SSL_PKEY_ECC].digest) + c->pkeys[SSL_PKEY_ECC].digest = EVP_sha1(); +# endif + } + return 1; +} + +int SSL_get_sigalgs(SSL *s, int idx, + int *psign, int *phash, int *psignhash, + unsigned char *rsig, unsigned char *rhash) +{ + const unsigned char *psig = s->cert->peer_sigalgs; + if (psig == NULL) + return 0; + if (idx >= 0) { + idx <<= 1; + if (idx >= (int)s->cert->peer_sigalgslen) + return 0; + psig += idx; + if (rhash) + *rhash = psig[0]; + if (rsig) + *rsig = psig[1]; + tls1_lookup_sigalg(phash, psign, psignhash, psig); + } + return s->cert->peer_sigalgslen / 2; +} + +int SSL_get_shared_sigalgs(SSL *s, int idx, + int *psign, int *phash, int *psignhash, + unsigned char *rsig, unsigned char *rhash) +{ + TLS_SIGALGS *shsigalgs = s->cert->shared_sigalgs; + if (!shsigalgs || idx >= (int)s->cert->shared_sigalgslen) + return 0; + shsigalgs += idx; + if (phash) + *phash = shsigalgs->hash_nid; + if (psign) + *psign = shsigalgs->sign_nid; + if (psignhash) + *psignhash = shsigalgs->signandhash_nid; + if (rsig) + *rsig = shsigalgs->rsign; + if (rhash) + *rhash = shsigalgs->rhash; + return s->cert->shared_sigalgslen; +} + +# ifndef OPENSSL_NO_HEARTBEATS +int tls1_process_heartbeat(SSL *s) +{ + unsigned char *p = &s->s3->rrec.data[0], *pl; + unsigned short hbtype; + unsigned int payload; + unsigned int padding = 16; /* Use minimum padding */ + + if (s->msg_callback) + s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT, + &s->s3->rrec.data[0], s->s3->rrec.length, + s, s->msg_callback_arg); + + /* Read type and payload length first */ + if (1 + 2 + 16 > s->s3->rrec.length) + return 0; /* silently discard */ + hbtype = *p++; + n2s(p, payload); + if (1 + 2 + payload + 16 > s->s3->rrec.length) + return 0; /* silently discard per RFC 6520 sec. 4 */ + pl = p; + + if (hbtype == TLS1_HB_REQUEST) { + unsigned char *buffer, *bp; + int r; + + /* + * Allocate memory for the response, size is 1 bytes message type, + * plus 2 bytes payload length, plus payload, plus padding + */ + buffer = OPENSSL_malloc(1 + 2 + payload + padding); + if (buffer == NULL) + return -1; + bp = buffer; + + /* Enter response type, length and copy payload */ + *bp++ = TLS1_HB_RESPONSE; + s2n(payload, bp); + memcpy(bp, pl, payload); + bp += payload; + /* Random padding */ + if (RAND_pseudo_bytes(bp, padding) < 0) { + OPENSSL_free(buffer); + return -1; + } + + r = ssl3_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, + 3 + payload + padding); + + if (r >= 0 && s->msg_callback) + s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT, + buffer, 3 + payload + padding, + s, s->msg_callback_arg); + + OPENSSL_free(buffer); + + if (r < 0) + return r; + } else if (hbtype == TLS1_HB_RESPONSE) { + unsigned int seq; + + /* + * We only send sequence numbers (2 bytes unsigned int), and 16 + * random bytes, so we just try to read the sequence number + */ + n2s(pl, seq); + + if (payload == 18 && seq == s->tlsext_hb_seq) { + s->tlsext_hb_seq++; + s->tlsext_hb_pending = 0; + } + } + + return 0; +} + +int tls1_heartbeat(SSL *s) +{ + unsigned char *buf, *p; + int ret = -1; + unsigned int payload = 18; /* Sequence number + random bytes */ + unsigned int padding = 16; /* Use minimum padding */ + + /* Only send if peer supports and accepts HB requests... */ + if (!(s->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED) || + s->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_SEND_REQUESTS) { + SSLerr(SSL_F_TLS1_HEARTBEAT, SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT); + return -1; + } + + /* ...and there is none in flight yet... */ + if (s->tlsext_hb_pending) { + SSLerr(SSL_F_TLS1_HEARTBEAT, SSL_R_TLS_HEARTBEAT_PENDING); + return -1; + } + + /* ...and no handshake in progress. */ + if (SSL_in_init(s) || s->in_handshake) { + SSLerr(SSL_F_TLS1_HEARTBEAT, SSL_R_UNEXPECTED_MESSAGE); + return -1; + } + + /* + * Check if padding is too long, payload and padding must not exceed 2^14 + * - 3 = 16381 bytes in total. + */ + OPENSSL_assert(payload + padding <= 16381); + + /*- + * Create HeartBeat message, we just use a sequence number + * as payload to distuingish different messages and add + * some random stuff. + * - Message Type, 1 byte + * - Payload Length, 2 bytes (unsigned int) + * - Payload, the sequence number (2 bytes uint) + * - Payload, random bytes (16 bytes uint) + * - Padding + */ + buf = OPENSSL_malloc(1 + 2 + payload + padding); + p = buf; + /* Message Type */ + *p++ = TLS1_HB_REQUEST; + /* Payload length (18 bytes here) */ + s2n(payload, p); + /* Sequence number */ + s2n(s->tlsext_hb_seq, p); + /* 16 random bytes */ + if (RAND_pseudo_bytes(p, 16) < 0) { + SSLerr(SSL_F_TLS1_HEARTBEAT, ERR_R_INTERNAL_ERROR); + goto err; + } + p += 16; + /* Random padding */ + if (RAND_pseudo_bytes(p, padding) < 0) { + SSLerr(SSL_F_TLS1_HEARTBEAT, ERR_R_INTERNAL_ERROR); + goto err; + } + + ret = ssl3_write_bytes(s, TLS1_RT_HEARTBEAT, buf, 3 + payload + padding); + if (ret >= 0) { + if (s->msg_callback) + s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT, + buf, 3 + payload + padding, + s, s->msg_callback_arg); + + s->tlsext_hb_pending = 1; + } + +err: + OPENSSL_free(buf); + + return ret; +} +# endif + +# define MAX_SIGALGLEN (TLSEXT_hash_num * TLSEXT_signature_num * 2) + +typedef struct { + size_t sigalgcnt; + int sigalgs[MAX_SIGALGLEN]; +} sig_cb_st; + +static int sig_cb(const char *elem, int len, void *arg) +{ + sig_cb_st *sarg = arg; + size_t i; + char etmp[20], *p; + int sig_alg, hash_alg; + if (elem == NULL) + return 0; + if (sarg->sigalgcnt == MAX_SIGALGLEN) + return 0; + if (len > (int)(sizeof(etmp) - 1)) + return 0; + memcpy(etmp, elem, len); + etmp[len] = 0; + p = strchr(etmp, '+'); + if (!p) + return 0; + *p = 0; + p++; + if (!*p) + return 0; + + if (!strcmp(etmp, "RSA")) + sig_alg = EVP_PKEY_RSA; + else if (!strcmp(etmp, "DSA")) + sig_alg = EVP_PKEY_DSA; + else if (!strcmp(etmp, "ECDSA")) + sig_alg = EVP_PKEY_EC; + else + return 0; + + hash_alg = OBJ_sn2nid(p); + if (hash_alg == NID_undef) + hash_alg = OBJ_ln2nid(p); + if (hash_alg == NID_undef) + return 0; + + for (i = 0; i < sarg->sigalgcnt; i += 2) { + if (sarg->sigalgs[i] == sig_alg && sarg->sigalgs[i + 1] == hash_alg) + return 0; + } + sarg->sigalgs[sarg->sigalgcnt++] = hash_alg; + sarg->sigalgs[sarg->sigalgcnt++] = sig_alg; + return 1; +} + +/* + * Set suppored signature algorithms based on a colon separated list of the + * form sig+hash e.g. RSA+SHA512:DSA+SHA512 + */ +int tls1_set_sigalgs_list(CERT *c, const char *str, int client) +{ + sig_cb_st sig; + sig.sigalgcnt = 0; + if (!CONF_parse_list(str, ':', 1, sig_cb, &sig)) + return 0; + if (c == NULL) + return 1; + return tls1_set_sigalgs(c, sig.sigalgs, sig.sigalgcnt, client); +} + +int tls1_set_sigalgs(CERT *c, const int *psig_nids, size_t salglen, + int client) +{ + unsigned char *sigalgs, *sptr; + int rhash, rsign; + size_t i; + if (salglen & 1) + return 0; + sigalgs = OPENSSL_malloc(salglen); + if (sigalgs == NULL) + return 0; + for (i = 0, sptr = sigalgs; i < salglen; i += 2) { + rhash = tls12_find_id(*psig_nids++, tls12_md, + sizeof(tls12_md) / sizeof(tls12_lookup)); + rsign = tls12_find_id(*psig_nids++, tls12_sig, + sizeof(tls12_sig) / sizeof(tls12_lookup)); + + if (rhash == -1 || rsign == -1) + goto err; + *sptr++ = rhash; + *sptr++ = rsign; + } + + if (client) { + if (c->client_sigalgs) + OPENSSL_free(c->client_sigalgs); + c->client_sigalgs = sigalgs; + c->client_sigalgslen = salglen; + } else { + if (c->conf_sigalgs) + OPENSSL_free(c->conf_sigalgs); + c->conf_sigalgs = sigalgs; + c->conf_sigalgslen = salglen; + } + + return 1; + + err: + OPENSSL_free(sigalgs); + return 0; +} + +static int tls1_check_sig_alg(CERT *c, X509 *x, int default_nid) +{ + int sig_nid; + size_t i; + if (default_nid == -1) + return 1; + sig_nid = X509_get_signature_nid(x); + if (default_nid) + return sig_nid == default_nid ? 1 : 0; + for (i = 0; i < c->shared_sigalgslen; i++) + if (sig_nid == c->shared_sigalgs[i].signandhash_nid) + return 1; + return 0; +} + +/* Check to see if a certificate issuer name matches list of CA names */ +static int ssl_check_ca_name(STACK_OF(X509_NAME) *names, X509 *x) +{ + X509_NAME *nm; + int i; + nm = X509_get_issuer_name(x); + for (i = 0; i < sk_X509_NAME_num(names); i++) { + if (!X509_NAME_cmp(nm, sk_X509_NAME_value(names, i))) + return 1; + } + return 0; +} + +/* + * Check certificate chain is consistent with TLS extensions and is usable by + * server. This servers two purposes: it allows users to check chains before + * passing them to the server and it allows the server to check chains before + * attempting to use them. + */ + +/* Flags which need to be set for a certificate when stict mode not set */ + +# define CERT_PKEY_VALID_FLAGS \ + (CERT_PKEY_EE_SIGNATURE|CERT_PKEY_EE_PARAM) +/* Strict mode flags */ +# define CERT_PKEY_STRICT_FLAGS \ + (CERT_PKEY_VALID_FLAGS|CERT_PKEY_CA_SIGNATURE|CERT_PKEY_CA_PARAM \ + | CERT_PKEY_ISSUER_NAME|CERT_PKEY_CERT_TYPE) + +int tls1_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain, + int idx) +{ + int i; + int rv = 0; + int check_flags = 0, strict_mode; + CERT_PKEY *cpk = NULL; + CERT *c = s->cert; + unsigned int suiteb_flags = tls1_suiteb(s); + /* idx == -1 means checking server chains */ + if (idx != -1) { + /* idx == -2 means checking client certificate chains */ + if (idx == -2) { + cpk = c->key; + idx = cpk - c->pkeys; + } else + cpk = c->pkeys + idx; + x = cpk->x509; + pk = cpk->privatekey; + chain = cpk->chain; + strict_mode = c->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT; + /* If no cert or key, forget it */ + if (!x || !pk) + goto end; +# ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL + /* Allow any certificate to pass test */ + if (s->cert->cert_flags & SSL_CERT_FLAG_BROKEN_PROTOCOL) { + rv = CERT_PKEY_STRICT_FLAGS | CERT_PKEY_EXPLICIT_SIGN | + CERT_PKEY_VALID | CERT_PKEY_SIGN; + cpk->valid_flags = rv; + return rv; + } +# endif + } else { + if (!x || !pk) + return 0; + idx = ssl_cert_type(x, pk); + if (idx == -1) + return 0; + cpk = c->pkeys + idx; + if (c->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT) + check_flags = CERT_PKEY_STRICT_FLAGS; + else + check_flags = CERT_PKEY_VALID_FLAGS; + strict_mode = 1; + } + + if (suiteb_flags) { + int ok; + if (check_flags) + check_flags |= CERT_PKEY_SUITEB; + ok = X509_chain_check_suiteb(NULL, x, chain, suiteb_flags); + if (ok == X509_V_OK) + rv |= CERT_PKEY_SUITEB; + else if (!check_flags) + goto end; + } + + /* + * Check all signature algorithms are consistent with signature + * algorithms extension if TLS 1.2 or later and strict mode. + */ + if (TLS1_get_version(s) >= TLS1_2_VERSION && strict_mode) { + int default_nid; + unsigned char rsign = 0; + if (c->peer_sigalgs) + default_nid = 0; + /* If no sigalgs extension use defaults from RFC5246 */ + else { + switch (idx) { + case SSL_PKEY_RSA_ENC: + case SSL_PKEY_RSA_SIGN: + case SSL_PKEY_DH_RSA: + rsign = TLSEXT_signature_rsa; + default_nid = NID_sha1WithRSAEncryption; + break; + + case SSL_PKEY_DSA_SIGN: + case SSL_PKEY_DH_DSA: + rsign = TLSEXT_signature_dsa; + default_nid = NID_dsaWithSHA1; + break; + + case SSL_PKEY_ECC: + rsign = TLSEXT_signature_ecdsa; + default_nid = NID_ecdsa_with_SHA1; + break; + + default: + default_nid = -1; + break; + } + } + /* + * If peer sent no signature algorithms extension and we have set + * preferred signature algorithms check we support sha1. + */ + if (default_nid > 0 && c->conf_sigalgs) { + size_t j; + const unsigned char *p = c->conf_sigalgs; + for (j = 0; j < c->conf_sigalgslen; j += 2, p += 2) { + if (p[0] == TLSEXT_hash_sha1 && p[1] == rsign) + break; + } + if (j == c->conf_sigalgslen) { + if (check_flags) + goto skip_sigs; + else + goto end; + } + } + /* Check signature algorithm of each cert in chain */ + if (!tls1_check_sig_alg(c, x, default_nid)) { + if (!check_flags) + goto end; + } else + rv |= CERT_PKEY_EE_SIGNATURE; + rv |= CERT_PKEY_CA_SIGNATURE; + for (i = 0; i < sk_X509_num(chain); i++) { + if (!tls1_check_sig_alg(c, sk_X509_value(chain, i), default_nid)) { + if (check_flags) { + rv &= ~CERT_PKEY_CA_SIGNATURE; + break; + } else + goto end; + } + } + } + /* Else not TLS 1.2, so mark EE and CA signing algorithms OK */ + else if (check_flags) + rv |= CERT_PKEY_EE_SIGNATURE | CERT_PKEY_CA_SIGNATURE; + skip_sigs: + /* Check cert parameters are consistent */ + if (tls1_check_cert_param(s, x, check_flags ? 1 : 2)) + rv |= CERT_PKEY_EE_PARAM; + else if (!check_flags) + goto end; + if (!s->server) + rv |= CERT_PKEY_CA_PARAM; + /* In strict mode check rest of chain too */ + else if (strict_mode) { + rv |= CERT_PKEY_CA_PARAM; + for (i = 0; i < sk_X509_num(chain); i++) { + X509 *ca = sk_X509_value(chain, i); + if (!tls1_check_cert_param(s, ca, 0)) { + if (check_flags) { + rv &= ~CERT_PKEY_CA_PARAM; + break; + } else + goto end; + } + } + } + if (!s->server && strict_mode) { + STACK_OF(X509_NAME) *ca_dn; + int check_type = 0; + switch (pk->type) { + case EVP_PKEY_RSA: + check_type = TLS_CT_RSA_SIGN; + break; + case EVP_PKEY_DSA: + check_type = TLS_CT_DSS_SIGN; + break; + case EVP_PKEY_EC: + check_type = TLS_CT_ECDSA_SIGN; + break; + case EVP_PKEY_DH: + case EVP_PKEY_DHX: + { + int cert_type = X509_certificate_type(x, pk); + if (cert_type & EVP_PKS_RSA) + check_type = TLS_CT_RSA_FIXED_DH; + if (cert_type & EVP_PKS_DSA) + check_type = TLS_CT_DSS_FIXED_DH; + } + } + if (check_type) { + const unsigned char *ctypes; + int ctypelen; + if (c->ctypes) { + ctypes = c->ctypes; + ctypelen = (int)c->ctype_num; + } else { + ctypes = (unsigned char *)s->s3->tmp.ctype; + ctypelen = s->s3->tmp.ctype_num; + } + for (i = 0; i < ctypelen; i++) { + if (ctypes[i] == check_type) { + rv |= CERT_PKEY_CERT_TYPE; + break; + } + } + if (!(rv & CERT_PKEY_CERT_TYPE) && !check_flags) + goto end; + } else + rv |= CERT_PKEY_CERT_TYPE; + + ca_dn = s->s3->tmp.ca_names; + + if (!sk_X509_NAME_num(ca_dn)) + rv |= CERT_PKEY_ISSUER_NAME; + + if (!(rv & CERT_PKEY_ISSUER_NAME)) { + if (ssl_check_ca_name(ca_dn, x)) + rv |= CERT_PKEY_ISSUER_NAME; + } + if (!(rv & CERT_PKEY_ISSUER_NAME)) { + for (i = 0; i < sk_X509_num(chain); i++) { + X509 *xtmp = sk_X509_value(chain, i); + if (ssl_check_ca_name(ca_dn, xtmp)) { + rv |= CERT_PKEY_ISSUER_NAME; + break; + } + } + } + if (!check_flags && !(rv & CERT_PKEY_ISSUER_NAME)) + goto end; + } else + rv |= CERT_PKEY_ISSUER_NAME | CERT_PKEY_CERT_TYPE; + + if (!check_flags || (rv & check_flags) == check_flags) + rv |= CERT_PKEY_VALID; + + end: + + if (TLS1_get_version(s) >= TLS1_2_VERSION) { + if (cpk->valid_flags & CERT_PKEY_EXPLICIT_SIGN) + rv |= CERT_PKEY_EXPLICIT_SIGN | CERT_PKEY_SIGN; + else if (cpk->digest) + rv |= CERT_PKEY_SIGN; + } else + rv |= CERT_PKEY_SIGN | CERT_PKEY_EXPLICIT_SIGN; + + /* + * When checking a CERT_PKEY structure all flags are irrelevant if the + * chain is invalid. + */ + if (!check_flags) { + if (rv & CERT_PKEY_VALID) + cpk->valid_flags = rv; + else { + /* Preserve explicit sign flag, clear rest */ + cpk->valid_flags &= CERT_PKEY_EXPLICIT_SIGN; + return 0; + } + } + return rv; +} + +/* Set validity of certificates in an SSL structure */ +void tls1_set_cert_validity(SSL *s) +{ + tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_RSA_ENC); + tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_RSA_SIGN); + tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_DSA_SIGN); + tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_DH_RSA); + tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_DH_DSA); + tls1_check_chain(s, NULL, NULL, NULL, SSL_PKEY_ECC); +} + +/* User level utiity function to check a chain is suitable */ +int SSL_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain) +{ + return tls1_check_chain(s, x, pk, chain, -1); +} + +#endif diff --git a/thirdparty/openssl/ssl/t1_meth.c b/thirdparty/openssl/ssl/t1_meth.c new file mode 100644 index 0000000000..335d57b530 --- /dev/null +++ b/thirdparty/openssl/ssl/t1_meth.c @@ -0,0 +1,84 @@ +/* ssl/t1_meth.c */ +/* 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.] + */ + +#include <stdio.h> +#include <openssl/objects.h> +#include "ssl_locl.h" + +static const SSL_METHOD *tls1_get_method(int ver) +{ + if (ver == TLS1_2_VERSION) + return TLSv1_2_method(); + if (ver == TLS1_1_VERSION) + return TLSv1_1_method(); + if (ver == TLS1_VERSION) + return TLSv1_method(); + return NULL; +} + +IMPLEMENT_tls_meth_func(TLS1_2_VERSION, TLSv1_2_method, + ssl3_accept, + ssl3_connect, tls1_get_method, TLSv1_2_enc_data) + + IMPLEMENT_tls_meth_func(TLS1_1_VERSION, TLSv1_1_method, + ssl3_accept, + ssl3_connect, tls1_get_method, TLSv1_1_enc_data) + + IMPLEMENT_tls_meth_func(TLS1_VERSION, TLSv1_method, + ssl3_accept, + ssl3_connect, tls1_get_method, TLSv1_enc_data) diff --git a/thirdparty/openssl/ssl/t1_reneg.c b/thirdparty/openssl/ssl/t1_reneg.c new file mode 100644 index 0000000000..b9a35c7fc2 --- /dev/null +++ b/thirdparty/openssl/ssl/t1_reneg.c @@ -0,0 +1,292 @@ +/* ssl/t1_reneg.c */ +/* 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-2009 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 <stdio.h> +#include <openssl/objects.h> +#include "ssl_locl.h" + +/* Add the client's renegotiation binding */ +int ssl_add_clienthello_renegotiate_ext(SSL *s, unsigned char *p, int *len, + int maxlen) +{ + if (p) { + if ((s->s3->previous_client_finished_len + 1) > maxlen) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_RENEGOTIATE_EXT, + SSL_R_RENEGOTIATE_EXT_TOO_LONG); + return 0; + } + + /* Length byte */ + *p = s->s3->previous_client_finished_len; + p++; + + memcpy(p, s->s3->previous_client_finished, + s->s3->previous_client_finished_len); +#ifdef OPENSSL_RI_DEBUG + fprintf(stderr, "%s RI extension sent by client\n", + s->s3->previous_client_finished_len ? "Non-empty" : "Empty"); +#endif + } + + *len = s->s3->previous_client_finished_len + 1; + + return 1; +} + +/* + * Parse the client's renegotiation binding and abort if it's not right + */ +int ssl_parse_clienthello_renegotiate_ext(SSL *s, unsigned char *d, int len, + int *al) +{ + int ilen; + + /* Parse the length byte */ + if (len < 1) { + SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT, + SSL_R_RENEGOTIATION_ENCODING_ERR); + *al = SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + ilen = *d; + d++; + + /* Consistency check */ + if ((ilen + 1) != len) { + SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT, + SSL_R_RENEGOTIATION_ENCODING_ERR); + *al = SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + + /* Check that the extension matches */ + if (ilen != s->s3->previous_client_finished_len) { + SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT, + SSL_R_RENEGOTIATION_MISMATCH); + *al = SSL_AD_HANDSHAKE_FAILURE; + return 0; + } + + if (memcmp(d, s->s3->previous_client_finished, + s->s3->previous_client_finished_len)) { + SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT, + SSL_R_RENEGOTIATION_MISMATCH); + *al = SSL_AD_HANDSHAKE_FAILURE; + return 0; + } +#ifdef OPENSSL_RI_DEBUG + fprintf(stderr, "%s RI extension received by server\n", + ilen ? "Non-empty" : "Empty"); +#endif + + s->s3->send_connection_binding = 1; + + return 1; +} + +/* Add the server's renegotiation binding */ +int ssl_add_serverhello_renegotiate_ext(SSL *s, unsigned char *p, int *len, + int maxlen) +{ + if (p) { + if ((s->s3->previous_client_finished_len + + s->s3->previous_server_finished_len + 1) > maxlen) { + SSLerr(SSL_F_SSL_ADD_SERVERHELLO_RENEGOTIATE_EXT, + SSL_R_RENEGOTIATE_EXT_TOO_LONG); + return 0; + } + + /* Length byte */ + *p = s->s3->previous_client_finished_len + + s->s3->previous_server_finished_len; + p++; + + memcpy(p, s->s3->previous_client_finished, + s->s3->previous_client_finished_len); + p += s->s3->previous_client_finished_len; + + memcpy(p, s->s3->previous_server_finished, + s->s3->previous_server_finished_len); +#ifdef OPENSSL_RI_DEBUG + fprintf(stderr, "%s RI extension sent by server\n", + s->s3->previous_client_finished_len ? "Non-empty" : "Empty"); +#endif + } + + *len = s->s3->previous_client_finished_len + + s->s3->previous_server_finished_len + 1; + + return 1; +} + +/* + * Parse the server's renegotiation binding and abort if it's not right + */ +int ssl_parse_serverhello_renegotiate_ext(SSL *s, unsigned char *d, int len, + int *al) +{ + int expected_len = s->s3->previous_client_finished_len + + s->s3->previous_server_finished_len; + int ilen; + + /* Check for logic errors */ + OPENSSL_assert(!expected_len || s->s3->previous_client_finished_len); + OPENSSL_assert(!expected_len || s->s3->previous_server_finished_len); + + /* Parse the length byte */ + if (len < 1) { + SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT, + SSL_R_RENEGOTIATION_ENCODING_ERR); + *al = SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + ilen = *d; + d++; + + /* Consistency check */ + if (ilen + 1 != len) { + SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT, + SSL_R_RENEGOTIATION_ENCODING_ERR); + *al = SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + + /* Check that the extension matches */ + if (ilen != expected_len) { + SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT, + SSL_R_RENEGOTIATION_MISMATCH); + *al = SSL_AD_HANDSHAKE_FAILURE; + return 0; + } + + if (memcmp(d, s->s3->previous_client_finished, + s->s3->previous_client_finished_len)) { + SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT, + SSL_R_RENEGOTIATION_MISMATCH); + *al = SSL_AD_HANDSHAKE_FAILURE; + return 0; + } + d += s->s3->previous_client_finished_len; + + if (memcmp(d, s->s3->previous_server_finished, + s->s3->previous_server_finished_len)) { + SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT, + SSL_R_RENEGOTIATION_MISMATCH); + *al = SSL_AD_ILLEGAL_PARAMETER; + return 0; + } +#ifdef OPENSSL_RI_DEBUG + fprintf(stderr, "%s RI extension received by client\n", + ilen ? "Non-empty" : "Empty"); +#endif + s->s3->send_connection_binding = 1; + + return 1; +} diff --git a/thirdparty/openssl/ssl/t1_srvr.c b/thirdparty/openssl/ssl/t1_srvr.c new file mode 100644 index 0000000000..8c6b3dff2f --- /dev/null +++ b/thirdparty/openssl/ssl/t1_srvr.c @@ -0,0 +1,92 @@ +/* ssl/t1_srvr.c */ +/* 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.] + */ + +#include <stdio.h> +#include "ssl_locl.h" +#include <openssl/buffer.h> +#include <openssl/rand.h> +#include <openssl/objects.h> +#include <openssl/evp.h> +#include <openssl/x509.h> + +static const SSL_METHOD *tls1_get_server_method(int ver); +static const SSL_METHOD *tls1_get_server_method(int ver) +{ + if (ver == TLS1_2_VERSION) + return TLSv1_2_server_method(); + if (ver == TLS1_1_VERSION) + return TLSv1_1_server_method(); + if (ver == TLS1_VERSION) + return TLSv1_server_method(); + return NULL; +} + +IMPLEMENT_tls_meth_func(TLS1_2_VERSION, TLSv1_2_server_method, + ssl3_accept, + ssl_undefined_function, + tls1_get_server_method, TLSv1_2_enc_data) + + IMPLEMENT_tls_meth_func(TLS1_1_VERSION, TLSv1_1_server_method, + ssl3_accept, + ssl_undefined_function, + tls1_get_server_method, TLSv1_1_enc_data) + + IMPLEMENT_tls_meth_func(TLS1_VERSION, TLSv1_server_method, + ssl3_accept, + ssl_undefined_function, + tls1_get_server_method, TLSv1_enc_data) diff --git a/thirdparty/openssl/ssl/t1_trce.c b/thirdparty/openssl/ssl/t1_trce.c new file mode 100644 index 0000000000..c5e21df77a --- /dev/null +++ b/thirdparty/openssl/ssl/t1_trce.c @@ -0,0 +1,1266 @@ +/* ssl/t1_trce.c */ +/* + * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 2012 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 + * licensing@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. + * ==================================================================== + * + */ + +#include "ssl_locl.h" + +#ifndef OPENSSL_NO_SSL_TRACE + +/* Packet trace support for OpenSSL */ + +typedef struct { + int num; + const char *name; +} ssl_trace_tbl; + +# define ssl_trace_str(val, tbl) \ + do_ssl_trace_str(val, tbl, sizeof(tbl)/sizeof(ssl_trace_tbl)) + +# define ssl_trace_list(bio, indent, msg, msglen, value, table) \ + do_ssl_trace_list(bio, indent, msg, msglen, value, \ + table, sizeof(table)/sizeof(ssl_trace_tbl)) + +static const char *do_ssl_trace_str(int val, ssl_trace_tbl *tbl, size_t ntbl) +{ + size_t i; + for (i = 0; i < ntbl; i++, tbl++) { + if (tbl->num == val) + return tbl->name; + } + return "UNKNOWN"; +} + +static int do_ssl_trace_list(BIO *bio, int indent, + const unsigned char *msg, size_t msglen, + size_t vlen, ssl_trace_tbl *tbl, size_t ntbl) +{ + int val; + if (msglen % vlen) + return 0; + while (msglen) { + val = msg[0]; + if (vlen == 2) + val = (val << 8) | msg[1]; + BIO_indent(bio, indent, 80); + BIO_printf(bio, "%s (%d)\n", do_ssl_trace_str(val, tbl, ntbl), val); + msg += vlen; + msglen -= vlen; + } + return 1; +} + +/* Version number */ + +static ssl_trace_tbl ssl_version_tbl[] = { + {SSL2_VERSION, "SSL 2.0"}, + {SSL3_VERSION, "SSL 3.0"}, + {TLS1_VERSION, "TLS 1.0"}, + {TLS1_1_VERSION, "TLS 1.1"}, + {TLS1_2_VERSION, "TLS 1.2"}, + {DTLS1_VERSION, "DTLS 1.0"}, + {DTLS1_2_VERSION, "DTLS 1.2"}, + {DTLS1_BAD_VER, "DTLS 1.0 (bad)"} +}; + +static ssl_trace_tbl ssl_content_tbl[] = { + {SSL3_RT_CHANGE_CIPHER_SPEC, "ChangeCipherSpec"}, + {SSL3_RT_ALERT, "Alert"}, + {SSL3_RT_HANDSHAKE, "Handshake"}, + {SSL3_RT_APPLICATION_DATA, "ApplicationData"}, + {TLS1_RT_HEARTBEAT, "HeartBeat"} +}; + +/* Handshake types */ +static ssl_trace_tbl ssl_handshake_tbl[] = { + {SSL3_MT_HELLO_REQUEST, "HelloRequest"}, + {SSL3_MT_CLIENT_HELLO, "ClientHello"}, + {SSL3_MT_SERVER_HELLO, "ServerHello"}, + {DTLS1_MT_HELLO_VERIFY_REQUEST, "HelloVerifyRequest"}, + {SSL3_MT_NEWSESSION_TICKET, "NewSessionTicket"}, + {SSL3_MT_CERTIFICATE, "Certificate"}, + {SSL3_MT_SERVER_KEY_EXCHANGE, "ServerKeyExchange"}, + {SSL3_MT_CERTIFICATE_REQUEST, "CertificateRequest"}, + {SSL3_MT_CLIENT_KEY_EXCHANGE, "ClientKeyExchange"}, + {SSL3_MT_CERTIFICATE_STATUS, "CertificateStatus"}, + {SSL3_MT_SERVER_DONE, "ServerHelloDone"}, + {SSL3_MT_CERTIFICATE_VERIFY, "CertificateVerify"}, + {SSL3_MT_CLIENT_KEY_EXCHANGE, "ClientKeyExchange"}, + {SSL3_MT_FINISHED, "Finished"}, + {SSL3_MT_CERTIFICATE_STATUS, "CertificateStatus"} +}; + +/* Cipher suites */ +static ssl_trace_tbl ssl_ciphers_tbl[] = { + {0x0000, "SSL_NULL_WITH_NULL_NULL"}, + {0x0001, "SSL_RSA_WITH_NULL_MD5"}, + {0x0002, "SSL_RSA_WITH_NULL_SHA"}, + {0x0003, "SSL_RSA_EXPORT_WITH_RC4_40_MD5"}, + {0x0004, "SSL_RSA_WITH_RC4_128_MD5"}, + {0x0005, "SSL_RSA_WITH_RC4_128_SHA"}, + {0x0006, "SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5"}, + {0x0007, "SSL_RSA_WITH_IDEA_CBC_SHA"}, + {0x0008, "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA"}, + {0x0009, "SSL_RSA_WITH_DES_CBC_SHA"}, + {0x000A, "SSL_RSA_WITH_3DES_EDE_CBC_SHA"}, + {0x000B, "SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA"}, + {0x000C, "SSL_DH_DSS_WITH_DES_CBC_SHA"}, + {0x000D, "SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA"}, + {0x000E, "SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA"}, + {0x000F, "SSL_DH_RSA_WITH_DES_CBC_SHA"}, + {0x0010, "SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA"}, + {0x0011, "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"}, + {0x0012, "SSL_DHE_DSS_WITH_DES_CBC_SHA"}, + {0x0013, "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA"}, + {0x0014, "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA"}, + {0x0015, "SSL_DHE_RSA_WITH_DES_CBC_SHA"}, + {0x0016, "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA"}, + {0x0017, "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5"}, + {0x0018, "SSL_DH_anon_WITH_RC4_128_MD5"}, + {0x0019, "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA"}, + {0x001A, "SSL_DH_anon_WITH_DES_CBC_SHA"}, + {0x001B, "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA"}, + {0x001D, "SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA"}, + {0x001E, "SSL_FORTEZZA_KEA_WITH_RC4_128_SHA"}, + {0x001F, "TLS_KRB5_WITH_3DES_EDE_CBC_SHA"}, + {0x0020, "TLS_KRB5_WITH_RC4_128_SHA"}, + {0x0021, "TLS_KRB5_WITH_IDEA_CBC_SHA"}, + {0x0022, "TLS_KRB5_WITH_DES_CBC_MD5"}, + {0x0023, "TLS_KRB5_WITH_3DES_EDE_CBC_MD5"}, + {0x0024, "TLS_KRB5_WITH_RC4_128_MD5"}, + {0x0025, "TLS_KRB5_WITH_IDEA_CBC_MD5"}, + {0x0026, "TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA"}, + {0x0027, "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA"}, + {0x0028, "TLS_KRB5_EXPORT_WITH_RC4_40_SHA"}, + {0x0029, "TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5"}, + {0x002A, "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5"}, + {0x002B, "TLS_KRB5_EXPORT_WITH_RC4_40_MD5"}, + {0x002F, "TLS_RSA_WITH_AES_128_CBC_SHA"}, + {0x0030, "TLS_DH_DSS_WITH_AES_128_CBC_SHA"}, + {0x0031, "TLS_DH_RSA_WITH_AES_128_CBC_SHA"}, + {0x0032, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA"}, + {0x0033, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA"}, + {0x0034, "TLS_DH_anon_WITH_AES_128_CBC_SHA"}, + {0x0035, "TLS_RSA_WITH_AES_256_CBC_SHA"}, + {0x0036, "TLS_DH_DSS_WITH_AES_256_CBC_SHA"}, + {0x0037, "TLS_DH_RSA_WITH_AES_256_CBC_SHA"}, + {0x0038, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA"}, + {0x0039, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"}, + {0x003A, "TLS_DH_anon_WITH_AES_256_CBC_SHA"}, + {0x003B, "TLS_RSA_WITH_NULL_SHA256"}, + {0x003C, "TLS_RSA_WITH_AES_128_CBC_SHA256"}, + {0x003D, "TLS_RSA_WITH_AES_256_CBC_SHA256"}, + {0x003E, "TLS_DH_DSS_WITH_AES_128_CBC_SHA256"}, + {0x003F, "TLS_DH_RSA_WITH_AES_128_CBC_SHA256"}, + {0x0040, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256"}, + {0x0041, "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA"}, + {0x0042, "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA"}, + {0x0043, "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA"}, + {0x0044, "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA"}, + {0x0045, "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA"}, + {0x0046, "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA"}, + {0x0067, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256"}, + {0x0068, "TLS_DH_DSS_WITH_AES_256_CBC_SHA256"}, + {0x0069, "TLS_DH_RSA_WITH_AES_256_CBC_SHA256"}, + {0x006A, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256"}, + {0x006B, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256"}, + {0x006C, "TLS_DH_anon_WITH_AES_128_CBC_SHA256"}, + {0x006D, "TLS_DH_anon_WITH_AES_256_CBC_SHA256"}, + {0x0084, "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA"}, + {0x0085, "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA"}, + {0x0086, "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA"}, + {0x0087, "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA"}, + {0x0088, "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA"}, + {0x0089, "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA"}, + {0x008A, "TLS_PSK_WITH_RC4_128_SHA"}, + {0x008B, "TLS_PSK_WITH_3DES_EDE_CBC_SHA"}, + {0x008C, "TLS_PSK_WITH_AES_128_CBC_SHA"}, + {0x008D, "TLS_PSK_WITH_AES_256_CBC_SHA"}, + {0x008E, "TLS_DHE_PSK_WITH_RC4_128_SHA"}, + {0x008F, "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA"}, + {0x0090, "TLS_DHE_PSK_WITH_AES_128_CBC_SHA"}, + {0x0091, "TLS_DHE_PSK_WITH_AES_256_CBC_SHA"}, + {0x0092, "TLS_RSA_PSK_WITH_RC4_128_SHA"}, + {0x0093, "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA"}, + {0x0094, "TLS_RSA_PSK_WITH_AES_128_CBC_SHA"}, + {0x0095, "TLS_RSA_PSK_WITH_AES_256_CBC_SHA"}, + {0x0096, "TLS_RSA_WITH_SEED_CBC_SHA"}, + {0x0097, "TLS_DH_DSS_WITH_SEED_CBC_SHA"}, + {0x0098, "TLS_DH_RSA_WITH_SEED_CBC_SHA"}, + {0x0099, "TLS_DHE_DSS_WITH_SEED_CBC_SHA"}, + {0x009A, "TLS_DHE_RSA_WITH_SEED_CBC_SHA"}, + {0x009B, "TLS_DH_anon_WITH_SEED_CBC_SHA"}, + {0x009C, "TLS_RSA_WITH_AES_128_GCM_SHA256"}, + {0x009D, "TLS_RSA_WITH_AES_256_GCM_SHA384"}, + {0x009E, "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"}, + {0x009F, "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384"}, + {0x00A0, "TLS_DH_RSA_WITH_AES_128_GCM_SHA256"}, + {0x00A1, "TLS_DH_RSA_WITH_AES_256_GCM_SHA384"}, + {0x00A2, "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256"}, + {0x00A3, "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384"}, + {0x00A4, "TLS_DH_DSS_WITH_AES_128_GCM_SHA256"}, + {0x00A5, "TLS_DH_DSS_WITH_AES_256_GCM_SHA384"}, + {0x00A6, "TLS_DH_anon_WITH_AES_128_GCM_SHA256"}, + {0x00A7, "TLS_DH_anon_WITH_AES_256_GCM_SHA384"}, + {0x00A8, "TLS_PSK_WITH_AES_128_GCM_SHA256"}, + {0x00A9, "TLS_PSK_WITH_AES_256_GCM_SHA384"}, + {0x00AA, "TLS_DHE_PSK_WITH_AES_128_GCM_SHA256"}, + {0x00AB, "TLS_DHE_PSK_WITH_AES_256_GCM_SHA384"}, + {0x00AC, "TLS_RSA_PSK_WITH_AES_128_GCM_SHA256"}, + {0x00AD, "TLS_RSA_PSK_WITH_AES_256_GCM_SHA384"}, + {0x00AE, "TLS_PSK_WITH_AES_128_CBC_SHA256"}, + {0x00AF, "TLS_PSK_WITH_AES_256_CBC_SHA384"}, + {0x00B0, "TLS_PSK_WITH_NULL_SHA256"}, + {0x00B1, "TLS_PSK_WITH_NULL_SHA384"}, + {0x00B2, "TLS_DHE_PSK_WITH_AES_128_CBC_SHA256"}, + {0x00B3, "TLS_DHE_PSK_WITH_AES_256_CBC_SHA384"}, + {0x00B4, "TLS_DHE_PSK_WITH_NULL_SHA256"}, + {0x00B5, "TLS_DHE_PSK_WITH_NULL_SHA384"}, + {0x00B6, "TLS_RSA_PSK_WITH_AES_128_CBC_SHA256"}, + {0x00B7, "TLS_RSA_PSK_WITH_AES_256_CBC_SHA384"}, + {0x00B8, "TLS_RSA_PSK_WITH_NULL_SHA256"}, + {0x00B9, "TLS_RSA_PSK_WITH_NULL_SHA384"}, + {0x00BA, "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256"}, + {0x00BB, "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256"}, + {0x00BC, "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256"}, + {0x00BD, "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256"}, + {0x00BE, "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256"}, + {0x00BF, "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256"}, + {0x00C0, "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256"}, + {0x00C1, "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256"}, + {0x00C2, "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256"}, + {0x00C3, "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256"}, + {0x00C4, "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256"}, + {0x00C5, "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256"}, + {0x00FF, "TLS_EMPTY_RENEGOTIATION_INFO_SCSV"}, + {0xC001, "TLS_ECDH_ECDSA_WITH_NULL_SHA"}, + {0xC002, "TLS_ECDH_ECDSA_WITH_RC4_128_SHA"}, + {0xC003, "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA"}, + {0xC004, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA"}, + {0xC005, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA"}, + {0xC006, "TLS_ECDHE_ECDSA_WITH_NULL_SHA"}, + {0xC007, "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA"}, + {0xC008, "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA"}, + {0xC009, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA"}, + {0xC00A, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA"}, + {0xC00B, "TLS_ECDH_RSA_WITH_NULL_SHA"}, + {0xC00C, "TLS_ECDH_RSA_WITH_RC4_128_SHA"}, + {0xC00D, "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA"}, + {0xC00E, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA"}, + {0xC00F, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA"}, + {0xC010, "TLS_ECDHE_RSA_WITH_NULL_SHA"}, + {0xC011, "TLS_ECDHE_RSA_WITH_RC4_128_SHA"}, + {0xC012, "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA"}, + {0xC013, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"}, + {0xC014, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"}, + {0xC015, "TLS_ECDH_anon_WITH_NULL_SHA"}, + {0xC016, "TLS_ECDH_anon_WITH_RC4_128_SHA"}, + {0xC017, "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA"}, + {0xC018, "TLS_ECDH_anon_WITH_AES_128_CBC_SHA"}, + {0xC019, "TLS_ECDH_anon_WITH_AES_256_CBC_SHA"}, + {0xC01A, "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA"}, + {0xC01B, "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA"}, + {0xC01C, "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA"}, + {0xC01D, "TLS_SRP_SHA_WITH_AES_128_CBC_SHA"}, + {0xC01E, "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA"}, + {0xC01F, "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA"}, + {0xC020, "TLS_SRP_SHA_WITH_AES_256_CBC_SHA"}, + {0xC021, "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA"}, + {0xC022, "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA"}, + {0xC023, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"}, + {0xC024, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384"}, + {0xC025, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256"}, + {0xC026, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384"}, + {0xC027, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"}, + {0xC028, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384"}, + {0xC029, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256"}, + {0xC02A, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384"}, + {0xC02B, "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"}, + {0xC02C, "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"}, + {0xC02D, "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256"}, + {0xC02E, "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384"}, + {0xC02F, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"}, + {0xC030, "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"}, + {0xC031, "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256"}, + {0xC032, "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384"}, + {0xFEFE, "SSL_RSA_FIPS_WITH_DES_CBC_SHA"}, + {0xFEFF, "SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA"}, +}; + +/* Compression methods */ +static ssl_trace_tbl ssl_comp_tbl[] = { + {0x0000, "No Compression"}, + {0x0001, "Zlib Compression"} +}; + +/* Extensions */ +static ssl_trace_tbl ssl_exts_tbl[] = { + {TLSEXT_TYPE_server_name, "server_name"}, + {TLSEXT_TYPE_max_fragment_length, "max_fragment_length"}, + {TLSEXT_TYPE_client_certificate_url, "client_certificate_url"}, + {TLSEXT_TYPE_trusted_ca_keys, "trusted_ca_keys"}, + {TLSEXT_TYPE_truncated_hmac, "truncated_hmac"}, + {TLSEXT_TYPE_status_request, "status_request"}, + {TLSEXT_TYPE_user_mapping, "user_mapping"}, + {TLSEXT_TYPE_client_authz, "client_authz"}, + {TLSEXT_TYPE_server_authz, "server_authz"}, + {TLSEXT_TYPE_cert_type, "cert_type"}, + {TLSEXT_TYPE_elliptic_curves, "elliptic_curves"}, + {TLSEXT_TYPE_ec_point_formats, "ec_point_formats"}, + {TLSEXT_TYPE_srp, "srp"}, + {TLSEXT_TYPE_signature_algorithms, "signature_algorithms"}, + {TLSEXT_TYPE_use_srtp, "use_srtp"}, + {TLSEXT_TYPE_heartbeat, "heartbeat"}, + {TLSEXT_TYPE_session_ticket, "session_ticket"}, +# ifdef TLSEXT_TYPE_opaque_prf_input + {TLSEXT_TYPE_opaque_prf_input, "opaque_prf_input"}, +# endif + {TLSEXT_TYPE_renegotiate, "renegotiate"}, + {TLSEXT_TYPE_next_proto_neg, "next_proto_neg"}, + {TLSEXT_TYPE_padding, "padding"} +}; + +static ssl_trace_tbl ssl_curve_tbl[] = { + {1, "sect163k1 (K-163)"}, + {2, "sect163r1"}, + {3, "sect163r2 (B-163)"}, + {4, "sect193r1"}, + {5, "sect193r2"}, + {6, "sect233k1 (K-233)"}, + {7, "sect233r1 (B-233)"}, + {8, "sect239k1"}, + {9, "sect283k1 (K-283)"}, + {10, "sect283r1 (B-283)"}, + {11, "sect409k1 (K-409)"}, + {12, "sect409r1 (B-409)"}, + {13, "sect571k1 (K-571)"}, + {14, "sect571r1 (B-571)"}, + {15, "secp160k1"}, + {16, "secp160r1"}, + {17, "secp160r2"}, + {18, "secp192k1"}, + {19, "secp192r1 (P-192)"}, + {20, "secp224k1"}, + {21, "secp224r1 (P-224)"}, + {22, "secp256k1"}, + {23, "secp256r1 (P-256)"}, + {24, "secp384r1 (P-384)"}, + {25, "secp521r1 (P-521)"}, + {26, "brainpoolP256r1"}, + {27, "brainpoolP384r1"}, + {28, "brainpoolP512r1"}, + {0xFF01, "arbitrary_explicit_prime_curves"}, + {0xFF02, "arbitrary_explicit_char2_curves"} +}; + +static ssl_trace_tbl ssl_point_tbl[] = { + {0, "uncompressed"}, + {1, "ansiX962_compressed_prime"}, + {2, "ansiX962_compressed_char2"} +}; + +static ssl_trace_tbl ssl_md_tbl[] = { + {0, "none"}, + {1, "md5"}, + {2, "sha1"}, + {3, "sha224"}, + {4, "sha256"}, + {5, "sha384"}, + {6, "sha512"} +}; + +static ssl_trace_tbl ssl_sig_tbl[] = { + {0, "anonymous"}, + {1, "rsa"}, + {2, "dsa"}, + {3, "ecdsa"} +}; + +static ssl_trace_tbl ssl_hb_tbl[] = { + {1, "peer_allowed_to_send"}, + {2, "peer_not_allowed_to_send"} +}; + +static ssl_trace_tbl ssl_hb_type_tbl[] = { + {1, "heartbeat_request"}, + {2, "heartbeat_response"} +}; + +static ssl_trace_tbl ssl_ctype_tbl[] = { + {1, "rsa_sign"}, + {2, "dss_sign"}, + {3, "rsa_fixed_dh"}, + {4, "dss_fixed_dh"}, + {5, "rsa_ephemeral_dh"}, + {6, "dss_ephemeral_dh"}, + {20, "fortezza_dms"}, + {64, "ecdsa_sign"}, + {65, "rsa_fixed_ecdh"}, + {66, "ecdsa_fixed_ecdh"} +}; + +static ssl_trace_tbl ssl_crypto_tbl[] = { + {TLS1_RT_CRYPTO_PREMASTER, "Premaster Secret"}, + {TLS1_RT_CRYPTO_CLIENT_RANDOM, "Client Random"}, + {TLS1_RT_CRYPTO_SERVER_RANDOM, "Server Random"}, + {TLS1_RT_CRYPTO_MASTER, "Master Secret"}, + {TLS1_RT_CRYPTO_MAC | TLS1_RT_CRYPTO_WRITE, "Write Mac Secret"}, + {TLS1_RT_CRYPTO_MAC | TLS1_RT_CRYPTO_READ, "Read Mac Secret"}, + {TLS1_RT_CRYPTO_KEY | TLS1_RT_CRYPTO_WRITE, "Write Key"}, + {TLS1_RT_CRYPTO_KEY | TLS1_RT_CRYPTO_READ, "Read Key"}, + {TLS1_RT_CRYPTO_IV | TLS1_RT_CRYPTO_WRITE, "Write IV"}, + {TLS1_RT_CRYPTO_IV | TLS1_RT_CRYPTO_READ, "Read IV"}, + {TLS1_RT_CRYPTO_FIXED_IV | TLS1_RT_CRYPTO_WRITE, "Write IV (fixed part)"}, + {TLS1_RT_CRYPTO_FIXED_IV | TLS1_RT_CRYPTO_READ, "Read IV (fixed part)"} +}; + +static void ssl_print_hex(BIO *bio, int indent, const char *name, + const unsigned char *msg, size_t msglen) +{ + size_t i; + BIO_indent(bio, indent, 80); + BIO_printf(bio, "%s (len=%d): ", name, (int)msglen); + for (i = 0; i < msglen; i++) + BIO_printf(bio, "%02X", msg[i]); + BIO_puts(bio, "\n"); +} + +static int ssl_print_hexbuf(BIO *bio, int indent, + const char *name, size_t nlen, + const unsigned char **pmsg, size_t *pmsglen) +{ + size_t blen; + const unsigned char *p = *pmsg; + if (*pmsglen < nlen) + return 0; + blen = p[0]; + if (nlen > 1) + blen = (blen << 8) | p[1]; + if (*pmsglen < nlen + blen) + return 0; + p += nlen; + ssl_print_hex(bio, indent, name, p, blen); + *pmsg += blen + nlen; + *pmsglen -= blen + nlen; + return 1; +} + +static int ssl_print_version(BIO *bio, int indent, const char *name, + const unsigned char **pmsg, size_t *pmsglen) +{ + int vers; + if (*pmsglen < 2) + return 0; + vers = ((*pmsg)[0] << 8) | (*pmsg)[1]; + BIO_indent(bio, indent, 80); + BIO_printf(bio, "%s=0x%x (%s)\n", + name, vers, ssl_trace_str(vers, ssl_version_tbl)); + *pmsg += 2; + *pmsglen -= 2; + return 1; +} + +static int ssl_print_random(BIO *bio, int indent, + const unsigned char **pmsg, size_t *pmsglen) +{ + unsigned int tm; + const unsigned char *p = *pmsg; + if (*pmsglen < 32) + return 0; + tm = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; + p += 4; + BIO_indent(bio, indent, 80); + BIO_puts(bio, "Random:\n"); + BIO_indent(bio, indent + 2, 80); + BIO_printf(bio, "gmt_unix_time=0x%08X\n", tm); + ssl_print_hex(bio, indent + 2, "random_bytes", p, 28); + *pmsg += 32; + *pmsglen -= 32; + return 1; +} + +static int ssl_print_signature(BIO *bio, int indent, SSL *s, + const unsigned char **pmsg, size_t *pmsglen) +{ + if (*pmsglen < 2) + return 0; + if (SSL_USE_SIGALGS(s)) { + const unsigned char *p = *pmsg; + BIO_indent(bio, indent, 80); + BIO_printf(bio, "Signature Algorithm %s+%s (%d+%d)\n", + ssl_trace_str(p[0], ssl_md_tbl), + ssl_trace_str(p[1], ssl_sig_tbl), p[0], p[1]); + *pmsg += 2; + *pmsglen -= 2; + } + return ssl_print_hexbuf(bio, indent, "Signature", 2, pmsg, pmsglen); +} + +static int ssl_print_extension(BIO *bio, int indent, int server, int extype, + const unsigned char *ext, size_t extlen) +{ + size_t xlen; + BIO_indent(bio, indent, 80); + BIO_printf(bio, "extension_type=%s(%d), length=%d\n", + ssl_trace_str(extype, ssl_exts_tbl), extype, (int)extlen); + switch (extype) { + case TLSEXT_TYPE_ec_point_formats: + if (extlen < 1) + return 0; + xlen = ext[0]; + if (extlen != xlen + 1) + return 0; + return ssl_trace_list(bio, indent + 2, + ext + 1, xlen, 1, ssl_point_tbl); + + case TLSEXT_TYPE_elliptic_curves: + if (extlen < 2) + return 0; + xlen = (ext[0] << 8) | ext[1]; + if (extlen != xlen + 2) + return 0; + return ssl_trace_list(bio, indent + 2, + ext + 2, xlen, 2, ssl_curve_tbl); + + case TLSEXT_TYPE_signature_algorithms: + + if (extlen < 2) + return 0; + xlen = (ext[0] << 8) | ext[1]; + if (extlen != xlen + 2) + return 0; + if (xlen & 1) + return 0; + ext += 2; + while (xlen > 0) { + BIO_indent(bio, indent + 2, 80); + BIO_printf(bio, "%s+%s (%d+%d)\n", + ssl_trace_str(ext[0], ssl_md_tbl), + ssl_trace_str(ext[1], ssl_sig_tbl), ext[0], ext[1]); + xlen -= 2; + ext += 2; + } + break; + + case TLSEXT_TYPE_renegotiate: + if (extlen < 1) + return 0; + xlen = ext[0]; + if (xlen + 1 != extlen) + return 0; + ext++; + if (xlen) { + if (server) { + if (xlen & 1) + return 0; + xlen >>= 1; + } + ssl_print_hex(bio, indent + 4, "client_verify_data", ext, xlen); + if (server) { + ext += xlen; + ssl_print_hex(bio, indent + 4, + "server_verify_data", ext, xlen); + } + } else { + BIO_indent(bio, indent + 4, 80); + BIO_puts(bio, "<EMPTY>\n"); + } + break; + + case TLSEXT_TYPE_heartbeat: + if (extlen != 1) + return 0; + BIO_indent(bio, indent + 2, 80); + BIO_printf(bio, "HeartbeatMode: %s\n", + ssl_trace_str(ext[0], ssl_hb_tbl)); + break; + + case TLSEXT_TYPE_session_ticket: + if (extlen != 0) + ssl_print_hex(bio, indent + 4, "ticket", ext, extlen); + break; + + default: + BIO_dump_indent(bio, (char *)ext, extlen, indent + 2); + } + return 1; +} + +static int ssl_print_extensions(BIO *bio, int indent, int server, + const unsigned char *msg, size_t msglen) +{ + size_t extslen; + BIO_indent(bio, indent, 80); + if (msglen == 0) { + BIO_puts(bio, "No Extensions\n"); + return 1; + } + extslen = (msg[0] << 8) | msg[1]; + if (extslen != msglen - 2) + return 0; + msg += 2; + msglen = extslen; + BIO_printf(bio, "extensions, length = %d\n", (int)msglen); + while (msglen > 0) { + int extype; + size_t extlen; + if (msglen < 4) + return 0; + extype = (msg[0] << 8) | msg[1]; + extlen = (msg[2] << 8) | msg[3]; + if (msglen < extlen + 4) + return 0; + msg += 4; + if (!ssl_print_extension(bio, indent + 2, server, + extype, msg, extlen)) + return 0; + msg += extlen; + msglen -= extlen + 4; + } + return 1; +} + +static int ssl_print_client_hello(BIO *bio, SSL *ssl, int indent, + const unsigned char *msg, size_t msglen) +{ + size_t len; + unsigned int cs; + if (!ssl_print_version(bio, indent, "client_version", &msg, &msglen)) + return 0; + if (!ssl_print_random(bio, indent, &msg, &msglen)) + return 0; + if (!ssl_print_hexbuf(bio, indent, "session_id", 1, &msg, &msglen)) + return 0; + if (SSL_IS_DTLS(ssl)) { + if (!ssl_print_hexbuf(bio, indent, "cookie", 1, &msg, &msglen)) + return 0; + } + if (msglen < 2) + return 0; + len = (msg[0] << 8) | msg[1]; + msg += 2; + msglen -= 2; + BIO_indent(bio, indent, 80); + BIO_printf(bio, "cipher_suites (len=%d)\n", (int)len); + if (msglen < len || len & 1) + return 0; + while (len > 0) { + cs = (msg[0] << 8) | msg[1]; + BIO_indent(bio, indent + 2, 80); + BIO_printf(bio, "{0x%02X, 0x%02X} %s\n", + msg[0], msg[1], ssl_trace_str(cs, ssl_ciphers_tbl)); + msg += 2; + msglen -= 2; + len -= 2; + } + if (msglen < 1) + return 0; + len = msg[0]; + msg++; + msglen--; + if (msglen < len) + return 0; + BIO_indent(bio, indent, 80); + BIO_printf(bio, "compression_methods (len=%d)\n", (int)len); + while (len > 0) { + BIO_indent(bio, indent + 2, 80); + BIO_printf(bio, "%s (0x%02X)\n", + ssl_trace_str(msg[0], ssl_comp_tbl), msg[0]); + msg++; + msglen--; + len--; + } + if (!ssl_print_extensions(bio, indent, 0, msg, msglen)) + return 0; + return 1; +} + +static int dtls_print_hello_vfyrequest(BIO *bio, int indent, + const unsigned char *msg, + size_t msglen) +{ + if (!ssl_print_version(bio, indent, "server_version", &msg, &msglen)) + return 0; + if (!ssl_print_hexbuf(bio, indent, "cookie", 1, &msg, &msglen)) + return 0; + return 1; +} + +static int ssl_print_server_hello(BIO *bio, int indent, + const unsigned char *msg, size_t msglen) +{ + unsigned int cs; + if (!ssl_print_version(bio, indent, "server_version", &msg, &msglen)) + return 0; + if (!ssl_print_random(bio, indent, &msg, &msglen)) + return 0; + if (!ssl_print_hexbuf(bio, indent, "session_id", 1, &msg, &msglen)) + return 0; + if (msglen < 2) + return 0; + cs = (msg[0] << 8) | msg[1]; + BIO_indent(bio, indent, 80); + BIO_printf(bio, "cipher_suite {0x%02X, 0x%02X} %s\n", + msg[0], msg[1], ssl_trace_str(cs, ssl_ciphers_tbl)); + msg += 2; + msglen -= 2; + if (msglen < 1) + return 0; + BIO_indent(bio, indent, 80); + BIO_printf(bio, "compression_method: %s (0x%02X)\n", + ssl_trace_str(msg[0], ssl_comp_tbl), msg[0]); + msg++; + msglen--; + if (!ssl_print_extensions(bio, indent, 1, msg, msglen)) + return 0; + return 1; +} + +static int ssl_get_keyex(const char **pname, SSL *ssl) +{ + unsigned long alg_k = ssl->s3->tmp.new_cipher->algorithm_mkey; + if (alg_k & SSL_kRSA) { + *pname = "rsa"; + return SSL_kRSA; + } + if (alg_k & SSL_kDHr) { + *pname = "dh_rsa"; + return SSL_kDHr; + } + if (alg_k & SSL_kDHd) { + *pname = "dh_dss"; + return SSL_kDHd; + } + if (alg_k & SSL_kKRB5) { + *pname = "krb5"; + return SSL_kKRB5; + } + if (alg_k & SSL_kEDH) { + *pname = "edh"; + return SSL_kEDH; + } + if (alg_k & SSL_kEECDH) { + *pname = "EECDH"; + return SSL_kEECDH; + } + if (alg_k & SSL_kECDHr) { + *pname = "ECDH RSA"; + return SSL_kECDHr; + } + if (alg_k & SSL_kECDHe) { + *pname = "ECDH ECDSA"; + return SSL_kECDHe; + } + if (alg_k & SSL_kPSK) { + *pname = "PSK"; + return SSL_kPSK; + } + if (alg_k & SSL_kSRP) { + *pname = "SRP"; + return SSL_kSRP; + } + if (alg_k & SSL_kGOST) { + *pname = "GOST"; + return SSL_kGOST; + } + *pname = "UNKNOWN"; + return 0; +} + +static int ssl_print_client_keyex(BIO *bio, int indent, SSL *ssl, + const unsigned char *msg, size_t msglen) +{ + const char *algname; + int id; + id = ssl_get_keyex(&algname, ssl); + BIO_indent(bio, indent, 80); + BIO_printf(bio, "KeyExchangeAlgorithm=%s\n", algname); + switch (id) { + + case SSL_kRSA: + if (TLS1_get_version(ssl) == SSL3_VERSION) { + ssl_print_hex(bio, indent + 2, + "EncyptedPreMasterSecret", msg, msglen); + } else { + if (!ssl_print_hexbuf(bio, indent + 2, + "EncyptedPreMasterSecret", 2, + &msg, &msglen)) + return 0; + } + break; + + /* Implicit parameters only allowed for static DH */ + case SSL_kDHd: + case SSL_kDHr: + if (msglen == 0) { + BIO_indent(bio, indent + 2, 80); + BIO_puts(bio, "implicit\n"); + break; + } + case SSL_kEDH: + if (!ssl_print_hexbuf(bio, indent + 2, "dh_Yc", 2, &msg, &msglen)) + return 0; + break; + + case SSL_kECDHr: + case SSL_kECDHe: + if (msglen == 0) { + BIO_indent(bio, indent + 2, 80); + BIO_puts(bio, "implicit\n"); + break; + } + case SSL_kEECDH: + if (!ssl_print_hexbuf(bio, indent + 2, "ecdh_Yc", 1, &msg, &msglen)) + return 0; + break; + } + + return 1; +} + +static int ssl_print_server_keyex(BIO *bio, int indent, SSL *ssl, + const unsigned char *msg, size_t msglen) +{ + const char *algname; + int id; + id = ssl_get_keyex(&algname, ssl); + BIO_indent(bio, indent, 80); + BIO_printf(bio, "KeyExchangeAlgorithm=%s\n", algname); + switch (id) { + /* Should never happen */ + case SSL_kDHd: + case SSL_kDHr: + case SSL_kECDHr: + case SSL_kECDHe: + BIO_indent(bio, indent + 2, 80); + BIO_printf(bio, "Unexpected Message\n"); + break; + + case SSL_kRSA: + + if (!ssl_print_hexbuf(bio, indent + 2, "rsa_modulus", 2, + &msg, &msglen)) + return 0; + if (!ssl_print_hexbuf(bio, indent + 2, "rsa_exponent", 2, + &msg, &msglen)) + return 0; + break; + + case SSL_kEDH: + if (!ssl_print_hexbuf(bio, indent + 2, "dh_p", 2, &msg, &msglen)) + return 0; + if (!ssl_print_hexbuf(bio, indent + 2, "dh_g", 2, &msg, &msglen)) + return 0; + if (!ssl_print_hexbuf(bio, indent + 2, "dh_Ys", 2, &msg, &msglen)) + return 0; + break; + + case SSL_kEECDH: + if (msglen < 1) + return 0; + BIO_indent(bio, indent + 2, 80); + if (msg[0] == EXPLICIT_PRIME_CURVE_TYPE) + BIO_puts(bio, "explicit_prime\n"); + else if (msg[0] == EXPLICIT_CHAR2_CURVE_TYPE) + BIO_puts(bio, "explicit_char2\n"); + else if (msg[0] == NAMED_CURVE_TYPE) { + int curve; + if (msglen < 3) + return 0; + curve = (msg[1] << 8) | msg[2]; + BIO_printf(bio, "named_curve: %s (%d)\n", + ssl_trace_str(curve, ssl_curve_tbl), curve); + msg += 3; + msglen -= 3; + if (!ssl_print_hexbuf(bio, indent + 2, "point", 1, &msg, &msglen)) + return 0; + } + break; + } + return ssl_print_signature(bio, indent, ssl, &msg, &msglen); +} + +static int ssl_print_certificate(BIO *bio, int indent, + const unsigned char **pmsg, size_t *pmsglen) +{ + size_t msglen = *pmsglen; + size_t clen; + X509 *x; + const unsigned char *p = *pmsg, *q; + if (msglen < 3) + return 0; + clen = (p[0] << 16) | (p[1] << 8) | p[2]; + if (msglen < clen + 3) + return 0; + q = p + 3; + BIO_indent(bio, indent, 80); + BIO_printf(bio, "ASN.1Cert, length=%d", (int)clen); + x = d2i_X509(NULL, &q, clen); + if (!x) + BIO_puts(bio, "<UNPARSEABLE CERTIFICATE>\n"); + else { + BIO_puts(bio, "\n------details-----\n"); + X509_print_ex(bio, x, XN_FLAG_ONELINE, 0); + PEM_write_bio_X509(bio, x); + /* Print certificate stuff */ + BIO_puts(bio, "------------------\n"); + X509_free(x); + } + if (q != p + 3 + clen) { + BIO_puts(bio, "<TRAILING GARBAGE AFTER CERTIFICATE>\n"); + } + *pmsg += clen + 3; + *pmsglen -= clen + 3; + return 1; +} + +static int ssl_print_certificates(BIO *bio, int indent, + const unsigned char *msg, size_t msglen) +{ + size_t clen; + if (msglen < 3) + return 0; + clen = (msg[0] << 16) | (msg[1] << 8) | msg[2]; + if (msglen != clen + 3) + return 0; + msg += 3; + BIO_indent(bio, indent, 80); + BIO_printf(bio, "certificate_list, length=%d\n", (int)clen); + while (clen > 0) { + if (!ssl_print_certificate(bio, indent + 2, &msg, &clen)) + return 0; + } + return 1; +} + +static int ssl_print_cert_request(BIO *bio, int indent, SSL *s, + const unsigned char *msg, size_t msglen) +{ + size_t xlen; + if (msglen < 1) + return 0; + xlen = msg[0]; + if (msglen < xlen + 1) + return 0; + msg++; + BIO_indent(bio, indent, 80); + BIO_printf(bio, "certificate_types (len=%d)\n", (int)xlen); + if (!ssl_trace_list(bio, indent + 2, msg, xlen, 1, ssl_ctype_tbl)) + return 0; + msg += xlen; + msglen -= xlen + 1; + if (!SSL_USE_SIGALGS(s)) + goto skip_sig; + if (msglen < 2) + return 0; + xlen = (msg[0] << 8) | msg[1]; + if (msglen < xlen + 2 || (xlen & 1)) + return 0; + msg += 2; + BIO_indent(bio, indent, 80); + BIO_printf(bio, "signature_algorithms (len=%d)\n", (int)xlen); + while (xlen > 0) { + BIO_indent(bio, indent + 2, 80); + BIO_printf(bio, "%s+%s (%d+%d)\n", + ssl_trace_str(msg[0], ssl_md_tbl), + ssl_trace_str(msg[1], ssl_sig_tbl), msg[0], msg[1]); + xlen -= 2; + msg += 2; + } + msg += xlen; + msglen -= xlen + 2; + + skip_sig: + xlen = (msg[0] << 8) | msg[1]; + BIO_indent(bio, indent, 80); + if (msglen < xlen + 2) + return 0; + msg += 2; + msglen -= 2; + BIO_printf(bio, "certificate_authorities (len=%d)\n", (int)xlen); + while (xlen > 0) { + size_t dlen; + X509_NAME *nm; + const unsigned char *p; + if (xlen < 2) + return 0; + dlen = (msg[0] << 8) | msg[1]; + if (xlen < dlen + 2) + return 0; + msg += 2; + BIO_indent(bio, indent + 2, 80); + BIO_printf(bio, "DistinguishedName (len=%d): ", (int)dlen); + p = msg; + nm = d2i_X509_NAME(NULL, &p, dlen); + if (!nm) { + BIO_puts(bio, "<UNPARSEABLE DN>\n"); + } else { + X509_NAME_print_ex(bio, nm, 0, XN_FLAG_ONELINE); + BIO_puts(bio, "\n"); + X509_NAME_free(nm); + } + xlen -= dlen + 2; + msg += dlen; + } + return 1; +} + +static int ssl_print_ticket(BIO *bio, int indent, + const unsigned char *msg, size_t msglen) +{ + unsigned int tick_life; + if (msglen == 0) { + BIO_indent(bio, indent + 2, 80); + BIO_puts(bio, "No Ticket\n"); + return 1; + } + if (msglen < 4) + return 0; + tick_life = (msg[0] << 24) | (msg[1] << 16) | (msg[2] << 8) | msg[3]; + msglen -= 4; + msg += 4; + BIO_indent(bio, indent + 2, 80); + BIO_printf(bio, "ticket_lifetime_hint=%u\n", tick_life); + if (!ssl_print_hexbuf(bio, indent + 2, "ticket", 2, &msg, &msglen)) + return 0; + if (msglen) + return 0; + return 1; +} + +static int ssl_print_handshake(BIO *bio, SSL *ssl, + const unsigned char *msg, size_t msglen, + int indent) +{ + size_t hlen; + unsigned char htype; + if (msglen < 4) + return 0; + htype = msg[0]; + hlen = (msg[1] << 16) | (msg[2] << 8) | msg[3]; + BIO_indent(bio, indent, 80); + BIO_printf(bio, "%s, Length=%d\n", + ssl_trace_str(htype, ssl_handshake_tbl), (int)hlen); + msg += 4; + msglen -= 4; + if (SSL_IS_DTLS(ssl)) { + if (msglen < 8) + return 0; + BIO_indent(bio, indent, 80); + BIO_printf(bio, "message_seq=%d, fragment_offset=%d, " + "fragment_length=%d\n", + (msg[0] << 8) | msg[1], + (msg[2] << 16) | (msg[3] << 8) | msg[4], + (msg[5] << 16) | (msg[6] << 8) | msg[7]); + msg += 8; + msglen -= 8; + } + if (msglen < hlen) + return 0; + switch (htype) { + case SSL3_MT_CLIENT_HELLO: + if (!ssl_print_client_hello(bio, ssl, indent + 2, msg, msglen)) + return 0; + break; + + case DTLS1_MT_HELLO_VERIFY_REQUEST: + if (!dtls_print_hello_vfyrequest(bio, indent + 2, msg, msglen)) + return 0; + break; + + case SSL3_MT_SERVER_HELLO: + if (!ssl_print_server_hello(bio, indent + 2, msg, msglen)) + return 0; + break; + + case SSL3_MT_SERVER_KEY_EXCHANGE: + if (!ssl_print_server_keyex(bio, indent + 2, ssl, msg, msglen)) + return 0; + break; + + case SSL3_MT_CLIENT_KEY_EXCHANGE: + if (!ssl_print_client_keyex(bio, indent + 2, ssl, msg, msglen)) + return 0; + break; + + case SSL3_MT_CERTIFICATE: + if (!ssl_print_certificates(bio, indent + 2, msg, msglen)) + return 0; + break; + + case SSL3_MT_CERTIFICATE_VERIFY: + if (!ssl_print_signature(bio, indent + 2, ssl, &msg, &msglen)) + return 0; + break; + + case SSL3_MT_CERTIFICATE_REQUEST: + if (!ssl_print_cert_request(bio, indent + 2, ssl, msg, msglen)) + return 0; + break; + + case SSL3_MT_FINISHED: + ssl_print_hex(bio, indent + 2, "verify_data", msg, msglen); + break; + + case SSL3_MT_SERVER_DONE: + if (msglen != 0) + ssl_print_hex(bio, indent + 2, "unexpected value", msg, msglen); + break; + + case SSL3_MT_NEWSESSION_TICKET: + if (!ssl_print_ticket(bio, indent + 2, msg, msglen)) + return 0; + break; + + default: + BIO_indent(bio, indent + 2, 80); + BIO_puts(bio, "Unsupported, hex dump follows:\n"); + BIO_dump_indent(bio, (char *)msg, msglen, indent + 4); + } + return 1; +} + +static int ssl_print_heartbeat(BIO *bio, int indent, + const unsigned char *msg, size_t msglen) +{ + if (msglen < 3) + return 0; + BIO_indent(bio, indent, 80); + BIO_printf(bio, "HeartBeatMessageType: %s\n", + ssl_trace_str(msg[0], ssl_hb_type_tbl)); + msg++; + msglen--; + if (!ssl_print_hexbuf(bio, indent, "payload", 2, &msg, &msglen)) + return 0; + ssl_print_hex(bio, indent, "padding", msg, msglen); + return 1; +} + +const char *SSL_CIPHER_standard_name(const SSL_CIPHER *c) +{ + if (c->algorithm_ssl & SSL_SSLV2) + return NULL; + return ssl_trace_str(c->id & 0xFFFF, ssl_ciphers_tbl); +} + +void SSL_trace(int write_p, int version, int content_type, + const void *buf, size_t msglen, SSL *ssl, void *arg) +{ + const unsigned char *msg = buf; + BIO *bio = arg; + + if (write_p == 2) { + BIO_puts(bio, "Session "); + ssl_print_hex(bio, 0, + ssl_trace_str(content_type, ssl_crypto_tbl), + msg, msglen); + return; + } + switch (content_type) { + case SSL3_RT_HEADER: + { + int hvers = msg[1] << 8 | msg[2]; + BIO_puts(bio, write_p ? "Sent" : "Received"); + BIO_printf(bio, " Record\nHeader:\n Version = %s (0x%x)\n", + ssl_trace_str(hvers, ssl_version_tbl), hvers); + if (SSL_IS_DTLS(ssl)) { + BIO_printf(bio, + " epoch=%d, sequence_number=%04x%04x%04x\n", + (msg[3] << 8 | msg[4]), + (msg[5] << 8 | msg[6]), + (msg[7] << 8 | msg[8]), (msg[9] << 8 | msg[10])); +# if 0 + /* + * Just print handshake type so we can see what is going on + * during fragmentation. + */ + BIO_printf(bio, "(%s)\n", + ssl_trace_str(msg[msglen], ssl_handshake_tbl)); +# endif + } + + BIO_printf(bio, " Content Type = %s (%d)\n Length = %d", + ssl_trace_str(msg[0], ssl_content_tbl), msg[0], + msg[msglen - 2] << 8 | msg[msglen - 1]); + } + break; + case SSL3_RT_HANDSHAKE: + if (!ssl_print_handshake(bio, ssl, msg, msglen, 4)) + BIO_printf(bio, "Message length parse error!\n"); + break; + + case SSL3_RT_CHANGE_CIPHER_SPEC: + if (msglen == 1 && msg[0] == 1) + BIO_puts(bio, " change_cipher_spec (1)\n"); + else + ssl_print_hex(bio, 4, "unknown value", msg, msglen); + break; + + case SSL3_RT_ALERT: + if (msglen != 2) + BIO_puts(bio, " Illegal Alert Length\n"); + else { + BIO_printf(bio, " Level=%s(%d), description=%s(%d)\n", + SSL_alert_type_string_long(msg[0] << 8), + msg[0], SSL_alert_desc_string_long(msg[1]), msg[1]); + } + case TLS1_RT_HEARTBEAT: + ssl_print_heartbeat(bio, 4, msg, msglen); + break; + + } + + BIO_puts(bio, "\n"); +} + +#endif diff --git a/thirdparty/openssl/ssl/tls_srp.c b/thirdparty/openssl/ssl/tls_srp.c new file mode 100644 index 0000000000..bb719ba4cf --- /dev/null +++ b/thirdparty/openssl/ssl/tls_srp.c @@ -0,0 +1,542 @@ +/* ssl/tls_srp.c */ +/* + * Written by Christophe Renou (christophe.renou@edelweb.fr) with the + * precious help of Peter Sylvester (peter.sylvester@edelweb.fr) for the + * EdelKey project and contributed to the OpenSSL project 2004. + */ +/* ==================================================================== + * Copyright (c) 2004-2011 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 + * licensing@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 "ssl_locl.h" +#ifndef OPENSSL_NO_SRP + +# include <openssl/rand.h> +# include <openssl/srp.h> +# include <openssl/err.h> + +int SSL_CTX_SRP_CTX_free(struct ssl_ctx_st *ctx) +{ + if (ctx == NULL) + return 0; + OPENSSL_free(ctx->srp_ctx.login); + BN_free(ctx->srp_ctx.N); + BN_free(ctx->srp_ctx.g); + BN_free(ctx->srp_ctx.s); + BN_free(ctx->srp_ctx.B); + BN_free(ctx->srp_ctx.A); + BN_free(ctx->srp_ctx.a); + BN_free(ctx->srp_ctx.b); + BN_free(ctx->srp_ctx.v); + ctx->srp_ctx.TLS_ext_srp_username_callback = NULL; + ctx->srp_ctx.SRP_cb_arg = NULL; + ctx->srp_ctx.SRP_verify_param_callback = NULL; + ctx->srp_ctx.SRP_give_srp_client_pwd_callback = NULL; + ctx->srp_ctx.N = NULL; + ctx->srp_ctx.g = NULL; + ctx->srp_ctx.s = NULL; + ctx->srp_ctx.B = NULL; + ctx->srp_ctx.A = NULL; + ctx->srp_ctx.a = NULL; + ctx->srp_ctx.b = NULL; + ctx->srp_ctx.v = NULL; + ctx->srp_ctx.login = NULL; + ctx->srp_ctx.info = NULL; + ctx->srp_ctx.strength = SRP_MINIMAL_N; + ctx->srp_ctx.srp_Mask = 0; + return (1); +} + +int SSL_SRP_CTX_free(struct ssl_st *s) +{ + if (s == NULL) + return 0; + OPENSSL_free(s->srp_ctx.login); + BN_free(s->srp_ctx.N); + BN_free(s->srp_ctx.g); + BN_free(s->srp_ctx.s); + BN_free(s->srp_ctx.B); + BN_free(s->srp_ctx.A); + BN_free(s->srp_ctx.a); + BN_free(s->srp_ctx.b); + BN_free(s->srp_ctx.v); + s->srp_ctx.TLS_ext_srp_username_callback = NULL; + s->srp_ctx.SRP_cb_arg = NULL; + s->srp_ctx.SRP_verify_param_callback = NULL; + s->srp_ctx.SRP_give_srp_client_pwd_callback = NULL; + s->srp_ctx.N = NULL; + s->srp_ctx.g = NULL; + s->srp_ctx.s = NULL; + s->srp_ctx.B = NULL; + s->srp_ctx.A = NULL; + s->srp_ctx.a = NULL; + s->srp_ctx.b = NULL; + s->srp_ctx.v = NULL; + s->srp_ctx.login = NULL; + s->srp_ctx.info = NULL; + s->srp_ctx.strength = SRP_MINIMAL_N; + s->srp_ctx.srp_Mask = 0; + return (1); +} + +int SSL_SRP_CTX_init(struct ssl_st *s) +{ + SSL_CTX *ctx; + + if ((s == NULL) || ((ctx = s->ctx) == NULL)) + return 0; + s->srp_ctx.SRP_cb_arg = ctx->srp_ctx.SRP_cb_arg; + /* set client Hello login callback */ + s->srp_ctx.TLS_ext_srp_username_callback = + ctx->srp_ctx.TLS_ext_srp_username_callback; + /* set SRP N/g param callback for verification */ + s->srp_ctx.SRP_verify_param_callback = + ctx->srp_ctx.SRP_verify_param_callback; + /* set SRP client passwd callback */ + s->srp_ctx.SRP_give_srp_client_pwd_callback = + ctx->srp_ctx.SRP_give_srp_client_pwd_callback; + + s->srp_ctx.N = NULL; + s->srp_ctx.g = NULL; + s->srp_ctx.s = NULL; + s->srp_ctx.B = NULL; + s->srp_ctx.A = NULL; + s->srp_ctx.a = NULL; + s->srp_ctx.b = NULL; + s->srp_ctx.v = NULL; + s->srp_ctx.login = NULL; + s->srp_ctx.info = ctx->srp_ctx.info; + s->srp_ctx.strength = ctx->srp_ctx.strength; + + if (((ctx->srp_ctx.N != NULL) && + ((s->srp_ctx.N = BN_dup(ctx->srp_ctx.N)) == NULL)) || + ((ctx->srp_ctx.g != NULL) && + ((s->srp_ctx.g = BN_dup(ctx->srp_ctx.g)) == NULL)) || + ((ctx->srp_ctx.s != NULL) && + ((s->srp_ctx.s = BN_dup(ctx->srp_ctx.s)) == NULL)) || + ((ctx->srp_ctx.B != NULL) && + ((s->srp_ctx.B = BN_dup(ctx->srp_ctx.B)) == NULL)) || + ((ctx->srp_ctx.A != NULL) && + ((s->srp_ctx.A = BN_dup(ctx->srp_ctx.A)) == NULL)) || + ((ctx->srp_ctx.a != NULL) && + ((s->srp_ctx.a = BN_dup(ctx->srp_ctx.a)) == NULL)) || + ((ctx->srp_ctx.v != NULL) && + ((s->srp_ctx.v = BN_dup(ctx->srp_ctx.v)) == NULL)) || + ((ctx->srp_ctx.b != NULL) && + ((s->srp_ctx.b = BN_dup(ctx->srp_ctx.b)) == NULL))) { + SSLerr(SSL_F_SSL_SRP_CTX_INIT, ERR_R_BN_LIB); + goto err; + } + if ((ctx->srp_ctx.login != NULL) && + ((s->srp_ctx.login = BUF_strdup(ctx->srp_ctx.login)) == NULL)) { + SSLerr(SSL_F_SSL_SRP_CTX_INIT, ERR_R_INTERNAL_ERROR); + goto err; + } + s->srp_ctx.srp_Mask = ctx->srp_ctx.srp_Mask; + + return (1); + err: + OPENSSL_free(s->srp_ctx.login); + BN_free(s->srp_ctx.N); + BN_free(s->srp_ctx.g); + BN_free(s->srp_ctx.s); + BN_free(s->srp_ctx.B); + BN_free(s->srp_ctx.A); + BN_free(s->srp_ctx.a); + BN_free(s->srp_ctx.b); + BN_free(s->srp_ctx.v); + return (0); +} + +int SSL_CTX_SRP_CTX_init(struct ssl_ctx_st *ctx) +{ + if (ctx == NULL) + return 0; + + ctx->srp_ctx.SRP_cb_arg = NULL; + /* set client Hello login callback */ + ctx->srp_ctx.TLS_ext_srp_username_callback = NULL; + /* set SRP N/g param callback for verification */ + ctx->srp_ctx.SRP_verify_param_callback = NULL; + /* set SRP client passwd callback */ + ctx->srp_ctx.SRP_give_srp_client_pwd_callback = NULL; + + ctx->srp_ctx.N = NULL; + ctx->srp_ctx.g = NULL; + ctx->srp_ctx.s = NULL; + ctx->srp_ctx.B = NULL; + ctx->srp_ctx.A = NULL; + ctx->srp_ctx.a = NULL; + ctx->srp_ctx.b = NULL; + ctx->srp_ctx.v = NULL; + ctx->srp_ctx.login = NULL; + ctx->srp_ctx.srp_Mask = 0; + ctx->srp_ctx.info = NULL; + ctx->srp_ctx.strength = SRP_MINIMAL_N; + + return (1); +} + +/* server side */ +int SSL_srp_server_param_with_username(SSL *s, int *ad) +{ + unsigned char b[SSL_MAX_MASTER_KEY_LENGTH]; + int al; + + *ad = SSL_AD_UNKNOWN_PSK_IDENTITY; + if ((s->srp_ctx.TLS_ext_srp_username_callback != NULL) && + ((al = + s->srp_ctx.TLS_ext_srp_username_callback(s, ad, + s->srp_ctx.SRP_cb_arg)) != + SSL_ERROR_NONE)) + return al; + + *ad = SSL_AD_INTERNAL_ERROR; + if ((s->srp_ctx.N == NULL) || + (s->srp_ctx.g == NULL) || + (s->srp_ctx.s == NULL) || (s->srp_ctx.v == NULL)) + return SSL3_AL_FATAL; + + if (RAND_bytes(b, sizeof(b)) <= 0) + return SSL3_AL_FATAL; + s->srp_ctx.b = BN_bin2bn(b, sizeof(b), NULL); + OPENSSL_cleanse(b, sizeof(b)); + + /* Calculate: B = (kv + g^b) % N */ + + return ((s->srp_ctx.B = + SRP_Calc_B(s->srp_ctx.b, s->srp_ctx.N, s->srp_ctx.g, + s->srp_ctx.v)) != + NULL) ? SSL_ERROR_NONE : SSL3_AL_FATAL; +} + +/* + * If the server just has the raw password, make up a verifier entry on the + * fly + */ +int SSL_set_srp_server_param_pw(SSL *s, const char *user, const char *pass, + const char *grp) +{ + SRP_gN *GN = SRP_get_default_gN(grp); + if (GN == NULL) + return -1; + s->srp_ctx.N = BN_dup(GN->N); + s->srp_ctx.g = BN_dup(GN->g); + if (s->srp_ctx.v != NULL) { + BN_clear_free(s->srp_ctx.v); + s->srp_ctx.v = NULL; + } + if (s->srp_ctx.s != NULL) { + BN_clear_free(s->srp_ctx.s); + s->srp_ctx.s = NULL; + } + if (!SRP_create_verifier_BN + (user, pass, &s->srp_ctx.s, &s->srp_ctx.v, GN->N, GN->g)) + return -1; + + return 1; +} + +int SSL_set_srp_server_param(SSL *s, const BIGNUM *N, const BIGNUM *g, + BIGNUM *sa, BIGNUM *v, char *info) +{ + if (N != NULL) { + if (s->srp_ctx.N != NULL) { + if (!BN_copy(s->srp_ctx.N, N)) { + BN_free(s->srp_ctx.N); + s->srp_ctx.N = NULL; + } + } else + s->srp_ctx.N = BN_dup(N); + } + if (g != NULL) { + if (s->srp_ctx.g != NULL) { + if (!BN_copy(s->srp_ctx.g, g)) { + BN_free(s->srp_ctx.g); + s->srp_ctx.g = NULL; + } + } else + s->srp_ctx.g = BN_dup(g); + } + if (sa != NULL) { + if (s->srp_ctx.s != NULL) { + if (!BN_copy(s->srp_ctx.s, sa)) { + BN_free(s->srp_ctx.s); + s->srp_ctx.s = NULL; + } + } else + s->srp_ctx.s = BN_dup(sa); + } + if (v != NULL) { + if (s->srp_ctx.v != NULL) { + if (!BN_copy(s->srp_ctx.v, v)) { + BN_free(s->srp_ctx.v); + s->srp_ctx.v = NULL; + } + } else + s->srp_ctx.v = BN_dup(v); + } + s->srp_ctx.info = info; + + if (!(s->srp_ctx.N) || + !(s->srp_ctx.g) || !(s->srp_ctx.s) || !(s->srp_ctx.v)) + return -1; + + return 1; +} + +int SRP_generate_server_master_secret(SSL *s, unsigned char *master_key) +{ + BIGNUM *K = NULL, *u = NULL; + int ret = -1, tmp_len; + unsigned char *tmp = NULL; + + if (!SRP_Verify_A_mod_N(s->srp_ctx.A, s->srp_ctx.N)) + goto err; + if (!(u = SRP_Calc_u(s->srp_ctx.A, s->srp_ctx.B, s->srp_ctx.N))) + goto err; + if (! + (K = + SRP_Calc_server_key(s->srp_ctx.A, s->srp_ctx.v, u, s->srp_ctx.b, + s->srp_ctx.N))) + goto err; + + tmp_len = BN_num_bytes(K); + if ((tmp = OPENSSL_malloc(tmp_len)) == NULL) + goto err; + BN_bn2bin(K, tmp); + ret = + s->method->ssl3_enc->generate_master_secret(s, master_key, tmp, + tmp_len); + err: + if (tmp) { + OPENSSL_cleanse(tmp, tmp_len); + OPENSSL_free(tmp); + } + BN_clear_free(K); + BN_clear_free(u); + return ret; +} + +/* client side */ +int SRP_generate_client_master_secret(SSL *s, unsigned char *master_key) +{ + BIGNUM *x = NULL, *u = NULL, *K = NULL; + int ret = -1, tmp_len; + char *passwd = NULL; + unsigned char *tmp = NULL; + + /* + * Checks if b % n == 0 + */ + if (SRP_Verify_B_mod_N(s->srp_ctx.B, s->srp_ctx.N) == 0) + goto err; + if (!(u = SRP_Calc_u(s->srp_ctx.A, s->srp_ctx.B, s->srp_ctx.N))) + goto err; + if (s->srp_ctx.SRP_give_srp_client_pwd_callback == NULL) + goto err; + if (! + (passwd = + s->srp_ctx.SRP_give_srp_client_pwd_callback(s, + s->srp_ctx.SRP_cb_arg))) + goto err; + if (!(x = SRP_Calc_x(s->srp_ctx.s, s->srp_ctx.login, passwd))) + goto err; + if (! + (K = + SRP_Calc_client_key(s->srp_ctx.N, s->srp_ctx.B, s->srp_ctx.g, x, + s->srp_ctx.a, u))) + goto err; + + tmp_len = BN_num_bytes(K); + if ((tmp = OPENSSL_malloc(tmp_len)) == NULL) + goto err; + BN_bn2bin(K, tmp); + ret = + s->method->ssl3_enc->generate_master_secret(s, master_key, tmp, + tmp_len); + err: + if (tmp) { + OPENSSL_cleanse(tmp, tmp_len); + OPENSSL_free(tmp); + } + BN_clear_free(K); + BN_clear_free(x); + if (passwd) { + OPENSSL_cleanse(passwd, strlen(passwd)); + OPENSSL_free(passwd); + } + BN_clear_free(u); + return ret; +} + +int srp_verify_server_param(SSL *s, int *al) +{ + SRP_CTX *srp = &s->srp_ctx; + /* + * Sanity check parameters: we can quickly check B % N == 0 by checking B + * != 0 since B < N + */ + if (BN_ucmp(srp->g, srp->N) >= 0 || BN_ucmp(srp->B, srp->N) >= 0 + || BN_is_zero(srp->B)) { + *al = SSL3_AD_ILLEGAL_PARAMETER; + return 0; + } + + if (BN_num_bits(srp->N) < srp->strength) { + *al = TLS1_AD_INSUFFICIENT_SECURITY; + return 0; + } + + if (srp->SRP_verify_param_callback) { + if (srp->SRP_verify_param_callback(s, srp->SRP_cb_arg) <= 0) { + *al = TLS1_AD_INSUFFICIENT_SECURITY; + return 0; + } + } else if (!SRP_check_known_gN_param(srp->g, srp->N)) { + *al = TLS1_AD_INSUFFICIENT_SECURITY; + return 0; + } + + return 1; +} + +int SRP_Calc_A_param(SSL *s) +{ + unsigned char rnd[SSL_MAX_MASTER_KEY_LENGTH]; + + if (RAND_bytes(rnd, sizeof(rnd)) <= 0) + return -1; + s->srp_ctx.a = BN_bin2bn(rnd, sizeof(rnd), s->srp_ctx.a); + OPENSSL_cleanse(rnd, sizeof(rnd)); + + if (! + (s->srp_ctx.A = SRP_Calc_A(s->srp_ctx.a, s->srp_ctx.N, s->srp_ctx.g))) + return -1; + + return 1; +} + +BIGNUM *SSL_get_srp_g(SSL *s) +{ + if (s->srp_ctx.g != NULL) + return s->srp_ctx.g; + return s->ctx->srp_ctx.g; +} + +BIGNUM *SSL_get_srp_N(SSL *s) +{ + if (s->srp_ctx.N != NULL) + return s->srp_ctx.N; + return s->ctx->srp_ctx.N; +} + +char *SSL_get_srp_username(SSL *s) +{ + if (s->srp_ctx.login != NULL) + return s->srp_ctx.login; + return s->ctx->srp_ctx.login; +} + +char *SSL_get_srp_userinfo(SSL *s) +{ + if (s->srp_ctx.info != NULL) + return s->srp_ctx.info; + return s->ctx->srp_ctx.info; +} + +# define tls1_ctx_ctrl ssl3_ctx_ctrl +# define tls1_ctx_callback_ctrl ssl3_ctx_callback_ctrl + +int SSL_CTX_set_srp_username(SSL_CTX *ctx, char *name) +{ + return tls1_ctx_ctrl(ctx, SSL_CTRL_SET_TLS_EXT_SRP_USERNAME, 0, name); +} + +int SSL_CTX_set_srp_password(SSL_CTX *ctx, char *password) +{ + return tls1_ctx_ctrl(ctx, SSL_CTRL_SET_TLS_EXT_SRP_PASSWORD, 0, password); +} + +int SSL_CTX_set_srp_strength(SSL_CTX *ctx, int strength) +{ + return tls1_ctx_ctrl(ctx, SSL_CTRL_SET_TLS_EXT_SRP_STRENGTH, strength, + NULL); +} + +int SSL_CTX_set_srp_verify_param_callback(SSL_CTX *ctx, + int (*cb) (SSL *, void *)) +{ + return tls1_ctx_callback_ctrl(ctx, SSL_CTRL_SET_SRP_VERIFY_PARAM_CB, + (void (*)(void))cb); +} + +int SSL_CTX_set_srp_cb_arg(SSL_CTX *ctx, void *arg) +{ + return tls1_ctx_ctrl(ctx, SSL_CTRL_SET_SRP_ARG, 0, arg); +} + +int SSL_CTX_set_srp_username_callback(SSL_CTX *ctx, + int (*cb) (SSL *, int *, void *)) +{ + return tls1_ctx_callback_ctrl(ctx, SSL_CTRL_SET_TLS_EXT_SRP_USERNAME_CB, + (void (*)(void))cb); +} + +int SSL_CTX_set_srp_client_pwd_callback(SSL_CTX *ctx, + char *(*cb) (SSL *, void *)) +{ + return tls1_ctx_callback_ctrl(ctx, SSL_CTRL_SET_SRP_GIVE_CLIENT_PWD_CB, + (void (*)(void))cb); +} + +#endif |