diff options
Diffstat (limited to 'drivers/builtin_openssl2/ssl')
54 files changed, 53536 insertions, 0 deletions
diff --git a/drivers/builtin_openssl2/ssl/bio_ssl.c b/drivers/builtin_openssl2/ssl/bio_ssl.c new file mode 100644 index 0000000000..e9552caee2 --- /dev/null +++ b/drivers/builtin_openssl2/ssl/bio_ssl.c @@ -0,0 +1,605 @@ +/* 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; + 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/drivers/builtin_openssl2/ssl/d1_both.c b/drivers/builtin_openssl2/ssl/d1_both.c new file mode 100644 index 0000000000..04aa23107e --- /dev/null +++ b/drivers/builtin_openssl2/ssl/d1_both.c @@ -0,0 +1,1617 @@ +/* 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 unsigned int g_probable_mtu[] = {1500 - 28, 512 - 28, 256 - 28}; + +static unsigned int dtls1_guess_mtu(unsigned int curr_mtu); +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; + } + +static 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); + } + +/* 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; + int curr_mtu; + unsigned int len, frag_off, mac_size, blocksize; + + /* AHA! Figure out the MTU, and stick to the right size */ + if (s->d1->mtu < dtls1_min_mtu() && !(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->d1->mtu = 0; + s->d1->mtu = dtls1_guess_mtu(s->d1->mtu); + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SET_MTU, + s->d1->mtu, NULL); + } + } +#if 0 + mtu = s->d1->mtu; + + fprintf(stderr, "using MTU = %d\n", mtu); + + mtu -= (DTLS1_HM_HEADER_LENGTH + DTLS1_RT_HEADER_LENGTH); + + curr_mtu = mtu - BIO_wpending(SSL_get_wbio(s)); + + if ( curr_mtu > 0) + mtu = curr_mtu; + else if ( ( ret = BIO_flush(SSL_get_wbio(s))) <= 0) + return ret; + + if ( BIO_wpending(SSL_get_wbio(s)) + s->init_num >= mtu) + { + ret = BIO_flush(SSL_get_wbio(s)); + if ( ret <= 0) + return ret; + mtu = s->d1->mtu - (DTLS1_HM_HEADER_LENGTH + DTLS1_RT_HEADER_LENGTH); + } +#endif + + OPENSSL_assert(s->d1->mtu >= dtls1_min_mtu()); /* 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) + mac_size = EVP_MD_CTX_size(s->write_hash); + else + mac_size = 0; + + if (s->enc_write_ctx && + (EVP_CIPHER_mode( s->enc_write_ctx->cipher) & EVP_CIPH_CBC_MODE)) + blocksize = 2 * EVP_CIPHER_block_size(s->enc_write_ctx->cipher); + else + blocksize = 0; + + frag_off = 0; + while( s->init_num) + { + curr_mtu = s->d1->mtu - BIO_wpending(SSL_get_wbio(s)) - + DTLS1_RT_HEADER_LENGTH - mac_size - blocksize; + + 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) + return ret; + curr_mtu = s->d1->mtu - DTLS1_RT_HEADER_LENGTH - + mac_size - blocksize; + } + + if ( s->init_num > curr_mtu) + len = curr_mtu; + else + len = s->init_num; + + + /* XDTLS: this function is too long. split out the CCS part */ + if ( type == SSL3_RT_HANDSHAKE) + { + if ( s->init_off != 0) + { + OPENSSL_assert(s->init_off > DTLS1_HM_HEADER_LENGTH); + s->init_off -= DTLS1_HM_HEADER_LENGTH; + s->init_num += DTLS1_HM_HEADER_LENGTH; + + if ( s->init_num > curr_mtu) + len = curr_mtu; + else + len = s->init_num; + } + + 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]); + + OPENSSL_assert(len >= DTLS1_HM_HEADER_LENGTH); + } + + 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 ( BIO_ctrl(SSL_get_wbio(s), + BIO_CTRL_DGRAM_MTU_EXCEEDED, 0, NULL) > 0 ) + s->d1->mtu = BIO_ctrl(SSL_get_wbio(s), + BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL); + 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; + frag_off += (ret -= DTLS1_HM_HEADER_LENGTH); + } + } + 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; + + 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; + } + + +static int +dtls1_reassemble_fragment(SSL *s, 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, max_len; + + if ((msg_hdr->frag_off+frag_len) > msg_hdr->msg_len) + goto err; + + /* Determine maximum allowed message size. Depends on (user set) + * maximum certificate length, but 16k is minimum. + */ + if (DTLS1_HM_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH < s->max_cert_list) + max_len = s->max_cert_list; + else + max_len = DTLS1_HM_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH; + + if ((msg_hdr->frag_off+frag_len) > max_len) + goto err; + + /* 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. + */ + 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 (i<=0 || (unsigned long)i!=frag_len) + 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) + { + memset(seq64be,0,sizeof(seq64be)); + seq64be[6] = (unsigned char)(msg_hdr->seq>>8); + seq64be[7] = (unsigned char)(msg_hdr->seq); + + item = pitem_new(seq64be, frag); + if (item == NULL) + { + i = -1; + goto err; + } + + pqueue_insert(s->d1->buffered_messages, item); + } + + return DTLS1_HM_FRAGMENT_RETRY; + +err: + if (frag != NULL) dtls1_hm_fragment_free(frag); + if (item != NULL) OPENSSL_free(item); + *ok = 0; + return i; + } + + +static int +dtls1_process_out_of_seq_message(SSL *s, 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 && frag_len < msg_hdr->msg_len) + return dtls1_reassemble_fragment(s, msg_hdr, ok); + + 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 (i<=0 || (unsigned long)i!=frag_len) + goto err; + } + + memset(seq64be,0,sizeof(seq64be)); + seq64be[6] = (unsigned char)(msg_hdr->seq>>8); + seq64be[7] = (unsigned char)(msg_hdr->seq); + + item = pitem_new(seq64be, frag); + if ( item == NULL) + goto err; + + pqueue_insert(s->d1->buffered_messages, item); + } + + return DTLS1_HM_FRAGMENT_RETRY; + +err: + if ( frag != NULL) dtls1_hm_fragment_free(frag); + if ( item != NULL) OPENSSL_free(item); + *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); + + /* + * 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); + + len = msg_hdr.msg_len; + frag_off = msg_hdr.frag_off; + frag_len = msg_hdr.frag_len; + + 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; + + /* XDTLS: ressurect this when restart is in place */ + s->state=stn; + + 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); + /* XDTLS: fix this--message fragments cannot span multiple packets */ + 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; + + /* 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); + } + +int dtls1_send_finished(SSL *s, int a, int b, const char *sender, int slen) + { + unsigned char *p,*d; + int i; + unsigned long l; + + if (s->state == a) + { + d=(unsigned char *)s->init_buf->data; + p= &(d[DTLS1_HM_HEADER_LENGTH]); + + i=s->method->ssl3_enc->final_finish_mac(s, + sender,slen,s->s3->tmp.finish_md); + s->s3->tmp.finish_md_len = i; + memcpy(p, s->s3->tmp.finish_md, i); + p+=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 + + d = dtls1_set_message_header(s, d, SSL3_MT_FINISHED, l, 0, l); + s->init_num=(int)l+DTLS1_HM_HEADER_LENGTH; + s->init_off=0; + + /* buffer the message to handle re-xmits */ + dtls1_buffer_message(s, 0); + + s->state=b; + } + + /* SSL3_ST_SEND_xxxxxx_HELLO_B */ + return(dtls1_do_write(s,SSL3_RT_HANDSHAKE)); + } + +/* 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)); + } + +static int dtls1_add_cert_to_buf(BUF_MEM *buf, unsigned long *l, X509 *x) + { + int n; + unsigned char *p; + + n=i2d_X509(x,NULL); + if (!BUF_MEM_grow_clean(buf,(int)(n+(*l)+3))) + { + SSLerr(SSL_F_DTLS1_ADD_CERT_TO_BUF,ERR_R_BUF_LIB); + return 0; + } + p=(unsigned char *)&(buf->data[*l]); + l2n3(n,p); + i2d_X509(x,&p); + *l+=n+3; + + return 1; + } +unsigned long dtls1_output_cert_chain(SSL *s, X509 *x) + { + unsigned char *p; + int i; + unsigned long l= 3 + DTLS1_HM_HEADER_LENGTH; + BUF_MEM *buf; + + /* TLSv1 sends a chain with nothing in it, instead of an alert */ + buf=s->init_buf; + if (!BUF_MEM_grow_clean(buf,10)) + { + SSLerr(SSL_F_DTLS1_OUTPUT_CERT_CHAIN,ERR_R_BUF_LIB); + return(0); + } + if (x != NULL) + { + X509_STORE_CTX xs_ctx; + + if (!X509_STORE_CTX_init(&xs_ctx,s->ctx->cert_store,x,NULL)) + { + SSLerr(SSL_F_DTLS1_OUTPUT_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 (!dtls1_add_cert_to_buf(buf, &l, x)) + { + X509_STORE_CTX_cleanup(&xs_ctx); + return 0; + } + } + X509_STORE_CTX_cleanup(&xs_ctx); + } + /* Thawte special :-) */ + for (i=0; i<sk_X509_num(s->ctx->extra_certs); i++) + { + x=sk_X509_value(s->ctx->extra_certs,i); + if (!dtls1_add_cert_to_buf(buf, &l, x)) + return 0; + } + + l-= (3 + DTLS1_HM_HEADER_LENGTH); + + p=(unsigned char *)&(buf->data[DTLS1_HM_HEADER_LENGTH]); + l2n3(l,p); + l+=3; + p=(unsigned char *)&(buf->data[0]); + p = dtls1_set_message_header(s, p, SSL3_MT_CERTIFICATE, l, 0, l); + + l+=DTLS1_HM_HEADER_LENGTH; + return(l); + } + +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 + if (!SSL_in_init(s) && !s->tlsext_hb_pending) /* done, no need to send a retransmit */ +#else + if (!SSL_in_init(s)) /* done, no need to send a retransmit */ +#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); + + memcpy(frag->fragment, s->init_buf->data, s->init_num); + + if ( is_ccs) + { + OPENSSL_assert(s->d1->w_msg_hdr.msg_len + + ((s->version==DTLS1_VERSION)?DTLS1_CCS_HEADER_LENGTH:3) == (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_min_mtu(void) + { + return (g_probable_mtu[(sizeof(g_probable_mtu) / + sizeof(g_probable_mtu[0])) - 1]); + } + +static unsigned int +dtls1_guess_mtu(unsigned int curr_mtu) + { + unsigned int i; + + if ( curr_mtu == 0 ) + return g_probable_mtu[0] ; + + for ( i = 0; i < sizeof(g_probable_mtu)/sizeof(g_probable_mtu[0]); i++) + if ( curr_mtu > g_probable_mtu[i]) + return g_probable_mtu[i]; + + return curr_mtu; + } + +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 + if (BIO_dgram_is_sctp(SSL_get_wbio(s)) && + !(s->shutdown & SSL_SENT_SHUTDOWN)) + { + ret = BIO_dgram_sctp_wait_for_dry(SSL_get_wbio(s)); + 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 */ + 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); + bp = buffer; + + /* Enter response type, length and copy payload */ + *bp++ = TLS1_HB_RESPONSE; + s2n(payload, bp); + memcpy(bp, pl, payload); + bp += payload; + /* Random padding */ + RAND_pseudo_bytes(bp, padding); + + 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; + 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 */ + RAND_pseudo_bytes(p, 16); + p += 16; + /* Random padding */ + RAND_pseudo_bytes(p, padding); + + 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; + } + + OPENSSL_free(buf); + + return ret; + } +#endif diff --git a/drivers/builtin_openssl2/ssl/d1_clnt.c b/drivers/builtin_openssl2/ssl/d1_clnt.c new file mode 100644 index 0000000000..48e5e06bde --- /dev/null +++ b/drivers/builtin_openssl2/ssl/d1_clnt.c @@ -0,0 +1,1718 @@ +/* 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 == DTLS1_VERSION || ver == DTLS1_BAD_VER) + return(DTLSv1_client_method()); + else + return(NULL); + } + +IMPLEMENT_dtls1_meth_func(DTLSv1_client_method, + ssl_undefined_function, + dtls1_connect, + dtls1_get_client_method) + +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; + goto end; + } + + /* s->version=SSL3_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; } + + /* setup buffing BIO */ + if (!ssl_init_wbio_buffer(s,0)) { ret= -1; 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; + 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: + case SSL3_ST_CW_CLNT_HELLO_B: + + s->shutdown=0; + + /* every DTLS ClientHello resets Finished MAC */ + ssl3_init_finished_mac(s); + + dtls1_start_timer(s); + ret=dtls1_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); + + SSL_export_keying_material(s, sctpauthkey, + sizeof(sctpauthkey), labelbuffer, + sizeof(labelbuffer), NULL, 0, 0); + + BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY, + sizeof(sctpauthkey), sctpauthkey); +#endif + + s->state=SSL3_ST_CR_FINISHED_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: +#ifndef OPENSSL_NO_TLSEXT + ret=ssl3_check_finished(s); + if (ret <= 0) goto end; + if (ret == 2) + { + s->hit = 1; + if (s->tlsext_ticket_expected) + s->state=SSL3_ST_CR_SESSION_TICKET_A; + else + s->state=SSL3_ST_CR_FINISHED_A; + s->init_num=0; + break; + } +#endif + /* 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; + 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=dtls1_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=dtls1_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); + + SSL_export_keying_material(s, sctpauthkey, + sizeof(sctpauthkey), labelbuffer, + sizeof(labelbuffer), NULL, 0, 0); + + 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->s3->change_cipher_spec=0; + } + + s->init_num=0; + break; + + case SSL3_ST_CW_CERT_VRFY_A: + case SSL3_ST_CW_CERT_VRFY_B: + dtls1_start_timer(s); + ret=dtls1_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; + s->s3->change_cipher_spec=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; + goto end; + } + + if (!s->method->ssl3_enc->change_cipher_state(s, + SSL3_CHANGE_CIPHER_CLIENT_WRITE)) + { + ret= -1; + 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=dtls1_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; */ + + 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); + } + +int dtls1_client_hello(SSL *s) + { + unsigned char *buf; + unsigned char *p,*d; + unsigned int i,j; + unsigned long l; + SSL_COMP *comp; + + buf=(unsigned char *)s->init_buf->data; + if (s->state == SSL3_ST_CW_CLNT_HELLO_A) + { + SSL_SESSION *sess = s->session; + if ((s->session == NULL) || + (s->session->ssl_version != s->version) || +#ifdef OPENSSL_NO_TLSEXT + !sess->session_id_length || +#else + (!sess->session_id_length && !sess->tlsext_tick) || +#endif + (s->session->not_resumable)) + { + if (!ssl_get_new_session(s,0)) + goto err; + } + /* else use the pre-loaded session */ + + p=s->s3->client_random; + + /* if client_random is initialized, reuse it, we are + * required to use same upon reply to HelloVerify */ + for (i=0;p[i]=='\0' && i<sizeof(s->s3->client_random);i++) + ; + if (i==sizeof(s->s3->client_random)) + ssl_fill_hello_random(s, 0, p, + sizeof(s->s3->client_random)); + + /* Do the message type and length last */ + d=p= &(buf[DTLS1_HM_HEADER_LENGTH]); + + *(p++)=s->version>>8; + *(p++)=s->version&0xff; + s->client_version=s->version; + + /* 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 > sizeof s->session->session_id) + { + SSLerr(SSL_F_DTLS1_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); + goto err; + } + memcpy(p,s->session->session_id,i); + p+=i; + } + + /* cookie stuff */ + if ( s->d1->cookie_len > sizeof(s->d1->cookie)) + { + SSLerr(SSL_F_DTLS1_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_DTLS1_CLIENT_HELLO,SSL_R_NO_CIPHERS_AVAILABLE); + goto err; + } + s2n(i,p); + p+=i; + + /* COMPRESSION */ + if (s->ctx->comp_methods == NULL) + 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; + } + *(p++)=0; /* Add the NULL method */ + +#ifndef OPENSSL_NO_TLSEXT + if ((p = ssl_add_clienthello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL) + { + SSLerr(SSL_F_DTLS1_CLIENT_HELLO,ERR_R_INTERNAL_ERROR); + goto err; + } +#endif + + l=(p-d); + d=buf; + + d = dtls1_set_message_header(s, d, SSL3_MT_CLIENT_HELLO, l, 0, l); + + s->state=SSL3_ST_CW_CLNT_HELLO_B; + /* number of bytes to write */ + s->init_num=p-buf; + s->init_off=0; + + /* buffer the message to handle re-xmits */ + dtls1_buffer_message(s, 0); + } + + /* SSL3_ST_CW_CLNT_HELLO_B */ + return(dtls1_do_write(s,SSL3_RT_HANDSHAKE)); +err: + return(-1); + } + +static int dtls1_get_hello_verify(SSL *s) + { + int n, al, ok = 0; + unsigned char *data; + unsigned int cookie_len; + + 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); + + 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 ((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; + } + 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); + return -1; + } + +int dtls1_send_client_key_exchange(SSL *s) + { + unsigned char *p,*d; + 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) + { + d=(unsigned char *)s->init_buf->data; + p= &(d[DTLS1_HM_HEADER_LENGTH]); + + 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->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_DTLS1_SEND_CLIENT_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR); + 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 [incidentally] DTLS */ + 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_DTLS1_SEND_CLIENT_KEY_EXCHANGE,SSL_R_BAD_RSA_ENCRYPT); + goto err; + } + + /* Fix buf for TLS and [incidentally] DTLS */ + 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 + printf("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 + { + printf("kssl_cget_tkt rtn %d\n", krb5rc); + if (krb5rc && kssl_err.text) + printf("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_DTLS1_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; + } + + if (RAND_bytes(tmp_buf,sizeof tmp_buf) <= 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_DTLS1_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; + + if (s->session->sess_cert->peer_dh_tmp != NULL) + dh_srvr=s->session->sess_cert->peer_dh_tmp; + else + { + /* we get them from the cert */ + ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE); + SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE,SSL_R_UNABLE_TO_FIND_DH_PARAMETERS); + goto err; + } + + /* generate a new random key */ + if ((dh_clnt=DHparams_dup(dh_srvr)) == NULL) + { + SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB); + goto err; + } + if (!DH_generate_key(dh_clnt)) + { + SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE,ERR_R_DH_LIB); + 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 (n <= 0) + { + SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE,ERR_R_DH_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); + /* clean up */ + memset(p,0,n); + + /* 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); + + /* perhaps clean things up a bit EAY EAY EAY EAY*/ + } +#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; + + /* 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_DTLS1_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_DTLS1_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + if ((clnt_ecdh=EC_KEY_new()) == NULL) + { + SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!EC_KEY_set_group(clnt_ecdh, srvr_group)) + { + SSLerr(SSL_F_DTLS1_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_DTLS1_SEND_CLIENT_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE); + goto err; + } + if (!EC_KEY_set_private_key(clnt_ecdh, priv_key)) + { + SSLerr(SSL_F_DTLS1_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_DTLS1_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_DTLS1_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_DTLS1_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_DTLS1_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 */ + +#ifndef OPENSSL_NO_PSK + else if (alg_k & SSL_kPSK) + { + char identity[PSK_MAX_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_DTLS1_SEND_CLIENT_KEY_EXCHANGE, + SSL_R_PSK_NO_CLIENT_CB); + goto err; + } + + psk_len = s->psk_client_callback(s, s->ctx->psk_identity_hint, + identity, PSK_MAX_IDENTITY_LEN, + psk_or_pre_ms, sizeof(psk_or_pre_ms)); + if (psk_len > PSK_MAX_PSK_LEN) + { + SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE, + ERR_R_INTERNAL_ERROR); + goto psk_err; + } + else if (psk_len == 0) + { + SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE, + SSL_R_PSK_IDENTITY_NOT_FOUND); + 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_DTLS1_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_DTLS1_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); + n = strlen(identity); + s2n(n, p); + memcpy(p, identity, n); + n+=2; + psk_err = 0; + psk_err: + OPENSSL_cleanse(identity, PSK_MAX_IDENTITY_LEN); + 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_DTLS1_SEND_CLIENT_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR); + goto err; + } + + d = dtls1_set_message_header(s, d, + SSL3_MT_CLIENT_KEY_EXCHANGE, n, 0, n); + /* + *(d++)=SSL3_MT_CLIENT_KEY_EXCHANGE; + l2n3(n,d); + l2n(s->d1->handshake_write_seq,d); + s->d1->handshake_write_seq++; + */ + + s->state=SSL3_ST_CW_KEY_EXCH_B; + /* number of bytes to write */ + s->init_num=n+DTLS1_HM_HEADER_LENGTH; + s->init_off=0; + + /* buffer the message to handle re-xmits */ + dtls1_buffer_message(s, 0); + } + + /* SSL3_ST_CW_KEY_EXCH_B */ + return(dtls1_do_write(s,SSL3_RT_HANDSHAKE)); +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 + return(-1); + } + +int dtls1_send_client_verify(SSL *s) + { + unsigned char *p,*d; + unsigned char data[MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH]; + EVP_PKEY *pkey; +#ifndef OPENSSL_NO_RSA + unsigned u=0; +#endif + unsigned long n; +#if !defined(OPENSSL_NO_DSA) || !defined(OPENSSL_NO_ECDSA) + int j; +#endif + + if (s->state == SSL3_ST_CW_CERT_VRFY_A) + { + d=(unsigned char *)s->init_buf->data; + p= &(d[DTLS1_HM_HEADER_LENGTH]); + pkey=s->cert->key->privatekey; + + s->method->ssl3_enc->cert_verify_mac(s, + NID_sha1, + &(data[MD5_DIGEST_LENGTH])); + +#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_DTLS1_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_DTLS1_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_DTLS1_SEND_CLIENT_VERIFY, + ERR_R_ECDSA_LIB); + goto err; + } + s2n(j,p); + n=j+2; + } + else +#endif + { + SSLerr(SSL_F_DTLS1_SEND_CLIENT_VERIFY,ERR_R_INTERNAL_ERROR); + goto err; + } + + d = dtls1_set_message_header(s, d, + SSL3_MT_CERTIFICATE_VERIFY, n, 0, n) ; + + s->init_num=(int)n+DTLS1_HM_HEADER_LENGTH; + s->init_off=0; + + /* buffer the message to handle re-xmits */ + dtls1_buffer_message(s, 0); + + s->state = SSL3_ST_CW_CERT_VRFY_B; + } + + /* s->state = SSL3_ST_CW_CERT_VRFY_B */ + return(dtls1_do_write(s,SSL3_RT_HANDSHAKE)); +err: + return(-1); + } + +int dtls1_send_client_certificate(SSL *s) + { + X509 *x509=NULL; + EVP_PKEY *pkey=NULL; + int i; + unsigned long l; + + if (s->state == SSL3_ST_CW_CERT_A) + { + if ((s->cert == NULL) || + (s->cert->key->x509 == NULL) || + (s->cert->key->privatekey == NULL)) + s->state=SSL3_ST_CW_CERT_B; + else + s->state=SSL3_ST_CW_CERT_C; + } + + /* 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=0; + 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_DTLS1_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 == 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; + l=dtls1_output_cert_chain(s, + (s->s3->tmp.cert_req == 2)?NULL:s->cert->key->x509); + s->init_num=(int)l; + s->init_off=0; + + /* set header called by dtls1_output_cert_chain() */ + + /* buffer the message to handle re-xmits */ + dtls1_buffer_message(s, 0); + } + /* SSL3_ST_CW_CERT_D */ + return(dtls1_do_write(s,SSL3_RT_HANDSHAKE)); + } + + diff --git a/drivers/builtin_openssl2/ssl/d1_enc.c b/drivers/builtin_openssl2/ssl/d1_enc.c new file mode 100644 index 0000000000..712c4647f2 --- /dev/null +++ b/drivers/builtin_openssl2/ssl/d1_enc.c @@ -0,0 +1,260 @@ +/* ssl/d1_enc.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 "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 + +/* dtls1_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 dtls1_enc(SSL *s, int send) + { + SSL3_RECORD *rec; + EVP_CIPHER_CTX *ds; + unsigned long l; + int bs,i,j,k,mac_size=0; + const EVP_CIPHER *enc; + + if (send) + { + if (EVP_MD_CTX_md(s->write_hash)) + { + mac_size=EVP_MD_CTX_size(s->write_hash); + if (mac_size < 0) + return -1; + } + 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); + if ( rec->data != rec->input) + /* we can't write into the input stream */ + fprintf(stderr, "%s:%d: rec->data != rec->input\n", + __FILE__, __LINE__); + else if ( EVP_CIPHER_block_size(ds->cipher) > 1) + { + if (RAND_bytes(rec->input, EVP_CIPHER_block_size(ds->cipher)) <= 0) + return -1; + } + } + } + else + { + if (EVP_MD_CTX_md(s->read_hash)) + { + mac_size=EVP_MD_CTX_size(s->read_hash); + OPENSSL_assert(mac_size >= 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 + printf("dtls1_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; + } + else + { + l=rec->length; + bs=EVP_CIPHER_block_size(ds->cipher); + + 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; + printf("EVP_Cipher(ds=%p,rec->data=%p,rec->input=%p,l=%ld) ==>\n", + ds,rec->data,rec->input,l); + printf("\tEVP_CIPHER_CTX: %d buf_len, %d key_len [%d %d], %d iv_len\n", + ds->buf_len, ds->cipher->key_len, + DES_KEY_SZ, DES_SCHEDULE_SZ, + ds->cipher->iv_len); + printf("\t\tIV: "); + for (i=0; i<ds->cipher->iv_len; i++) printf("%02X", ds->iv[i]); + printf("\n"); + printf("\trec->input="); + for (ui=0; ui<l; ui++) printf(" %02x", rec->input[ui]); + printf("\n"); + } +#endif /* KSSL_DEBUG */ + + if (!send) + { + if (l == 0 || l%bs != 0) + return 0; + } + + EVP_Cipher(ds,rec->data,rec->input,l); + +#ifdef KSSL_DEBUG + { + unsigned long i; + printf("\trec->data="); + for (i=0; i<l; i++) + printf(" %02x", rec->data[i]); printf("\n"); + } +#endif /* KSSL_DEBUG */ + + if ((bs != 1) && !send) + return tls1_cbc_remove_padding(s, rec, bs, mac_size); + } + return(1); + } + diff --git a/drivers/builtin_openssl2/ssl/d1_lib.c b/drivers/builtin_openssl2/ssl/d1_lib.c new file mode 100644 index 0000000000..6bde16fa21 --- /dev/null +++ b/drivers/builtin_openssl2/ssl/d1_lib.c @@ -0,0 +1,486 @@ +/* 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_WIN32) || defined(OPENSSL_SYS_VMS) +#include <sys/timeb.h> +#endif + +static void get_current_time(struct timeval *t); +const char dtls1_version_str[]="DTLSv1" OPENSSL_VERSION_PTEXT; +int dtls1_listen(SSL *s, struct sockaddr *client); + +SSL3_ENC_METHOD DTLSv1_enc_data={ + dtls1_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, + }; + +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); + } + + 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; + OPENSSL_free(frag->fragment); + OPENSSL_free(frag); + pitem_free(item); + } + + while ( (item = pqueue_pop(s->d1->sent_messages)) != NULL) + { + frag = (hm_fragment *)item->data; + OPENSSL_free(frag->fragment); + OPENSSL_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; + + 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; + + 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->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->version=DTLS1_BAD_VER; + else + s->version=DTLS1_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; + + 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) + { + s->d1->timeout.num_alerts++; + + /* Reduce MTU after 2 unsuccessful retransmissions */ + if (s->d1->timeout.num_alerts > 2) + { + s->d1->mtu = BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_GET_FALLBACK_MTU, 0, NULL); + } + + 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) +{ +#ifdef OPENSSL_SYS_WIN32 + struct _timeb tb; + _ftime(&tb); + t->tv_sec = (long)tb.time; + t->tv_usec = (long)tb.millitm * 1000; +#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; + + 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; + } diff --git a/drivers/builtin_openssl2/ssl/d1_meth.c b/drivers/builtin_openssl2/ssl/d1_meth.c new file mode 100644 index 0000000000..5c4004bfe3 --- /dev/null +++ b/drivers/builtin_openssl2/ssl/d1_meth.c @@ -0,0 +1,77 @@ +/* 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 == DTLS1_VERSION) + return(DTLSv1_method()); + else + return(NULL); + } + +IMPLEMENT_dtls1_meth_func(DTLSv1_method, + dtls1_accept, + dtls1_connect, + dtls1_get_method) + diff --git a/drivers/builtin_openssl2/ssl/d1_pkt.c b/drivers/builtin_openssl2/ssl/d1_pkt.c new file mode 100644 index 0000000000..438c0913d2 --- /dev/null +++ b/drivers/builtin_openssl2/ssl/d1_pkt.c @@ -0,0 +1,1901 @@ +/* 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(0); + } + + 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); + OPENSSL_free(rdata); + pitem_free(item); + return(0); + } + + /* 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); + OPENSSL_free(rdata); + pitem_free(item); + return(0); + } + + 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); + dtls1_buffer_record(s, &(s->d1->processed_rcds), + s->s3->rrec.seq_num); + } + } + + /* 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 ( ! SSL_in_init(s)) /* if we're not (re)negotiating, + nothing buffered */ + 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; + dtls1_record_bitmap_update(s, &(s->d1->bitmap));/* Mark receipt of record. */ + 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. */ + dtls1_process_buffered_records(s); + + /* 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; + + /* 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); + if (n <= 0) return(n); /* error or non-blocking io */ + + /* 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 && + *p == 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) + { + dtls1_buffer_record(s, &(s->d1->unprocessed_rcds), rr->seq_num); + } + 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 */ + } + + 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. + */ + dtls1_buffer_record(s, &(s->d1->buffered_app_data), rr->seq_num); + 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 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 == 1) /* 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 == 2) /* 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; + SSL3_RECORD *wr; + SSL3_BUFFER *wb; + SSL_SESSION *sess; + int bs; + + /* 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; + + *(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; + + /* lets setup the record stuff. */ + + /* Make space for the explicit IV in case of CBC. + * (this is a bit of a boundary violation, but what the heck). + */ + if ( s->enc_write_ctx && + (EVP_CIPHER_mode( s->enc_write_ctx->cipher ) & EVP_CIPH_CBC_MODE)) + bs = EVP_CIPHER_block_size(s->enc_write_ctx->cipher); + else + bs = 0; + + wr->data=p + bs; /* 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 + bs]),1) < 0) + goto err; + wr->length+=mac_size; + } + + /* this is true regardless of mac size */ + wr->input=p; + wr->data=p; + + + /* ssl3_enc can only have an error on read */ + if (bs) /* bs != 0 in case of CBC */ + { + RAND_pseudo_bytes(p,bs); + /* master IV and last CBC residue stand for + * the rest of randomness */ + wr->length += bs; + } + + s->method->ssl3_enc->enc(s,1); + + /* 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); + + /* 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/drivers/builtin_openssl2/ssl/d1_srtp.c b/drivers/builtin_openssl2/ssl/d1_srtp.c new file mode 100644 index 0000000000..ab9c41922c --- /dev/null +++ b/drivers/builtin_openssl2/ssl/d1_srtp.c @@ -0,0 +1,494 @@ +/* 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" + +#ifndef OPENSSL_NO_SRTP + +#include "srtp.h" + + +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 find_profile_by_num(unsigned profile_num, + SRTP_PROTECTION_PROFILE **pptr) + { + SRTP_PROTECTION_PROFILE *p; + + p=srtp_known_profiles; + while(p->name) + { + if(p->id == profile_num) + { + *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))) + { + sk_SRTP_PROTECTION_PROFILE_push(profiles,p); + } + else + { + SSLerr(SSL_F_SSL_CTX_MAKE_PROFILES,SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE); + 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 *cprof,*sprof; + STACK_OF(SRTP_PROTECTION_PROFILE) *clnt=0,*srvr; + int ct; + int mki_len; + int i,j; + int id; + int ret; + + /* 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; + } + + + clnt=sk_SRTP_PROTECTION_PROFILE_new_null(); + + while(ct) + { + n2s(d,id); + ct-=2; + len-=2; + + if(!find_profile_by_num(id,&cprof)) + { + sk_SRTP_PROTECTION_PROFILE_push(clnt,cprof); + } + else + { + ; /* Ignore */ + } + } + + /* 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; + } + + srvr=SSL_get_srtp_profiles(s); + + /* Pick our most preferred profile. If no profiles have been + configured then the outer loop doesn't run + (sk_SRTP_PROTECTION_PROFILE_num() = -1) + and so we just return without doing anything */ + for(i=0;i<sk_SRTP_PROTECTION_PROFILE_num(srvr);i++) + { + sprof=sk_SRTP_PROTECTION_PROFILE_value(srvr,i); + + for(j=0;j<sk_SRTP_PROTECTION_PROFILE_num(clnt);j++) + { + cprof=sk_SRTP_PROTECTION_PROFILE_value(clnt,j); + + if(cprof->id==sprof->id) + { + s->srtp_profile=sprof; + *al=0; + ret=0; + goto done; + } + } + } + + ret=0; + +done: + if(clnt) sk_SRTP_PROTECTION_PROFILE_free(clnt); + + return ret; + } + +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/drivers/builtin_openssl2/ssl/d1_srvr.c b/drivers/builtin_openssl2/ssl/d1_srvr.c new file mode 100644 index 0000000000..1384ab0cbf --- /dev/null +++ b/drivers/builtin_openssl2/ssl/d1_srvr.c @@ -0,0 +1,1723 @@ +/* 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 == DTLS1_VERSION) + return(DTLSv1_server_method()); + else + return(NULL); + } + +IMPLEMENT_dtls1_meth_func(DTLSv1_server_method, + dtls1_accept, + ssl_undefined_function, + dtls1_get_server_method) + +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; + goto end; + } + if (!BUF_MEM_grow(buf,SSL3_RT_MAX_PLAIN_LENGTH)) + { + ret= -1; + goto end; + } + s->init_buf=buf; + } + + if (!ssl3_setup_buffers(s)) + { + ret= -1; + goto end; + } + + s->init_num=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; goto end; } + + ssl3_init_finished_mac(s); + s->state=SSL3_ST_SR_CLNT_HELLO_A; + s->ctx->stats.sess_accept++; + } + 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=dtls1_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=dtls1_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); + + SSL_export_keying_material(s, sctpauthkey, + sizeof(sctpauthkey), labelbuffer, + sizeof(labelbuffer), NULL, 0, 0); + + 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=dtls1_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 */ + if ((s->options & SSL_OP_EPHEMERAL_RSA) +#ifndef OPENSSL_NO_KRB5 + && !(alg_k & SSL_kKRB5) +#endif /* OPENSSL_NO_KRB5 */ + ) + /* option SSL_OP_EPHEMERAL_RSA sends temporary RSA key + * even when forbidden by protocol specs + * (handshake may fail as clients are not required to + * be able to handle this) */ + s->s3->tmp.use_rsa_tmp=1; + else + s->s3->tmp.use_rsa_tmp=0; + + /* only send if a DH key exchange or + * RSA but we have a sign only certificate */ + if (s->s3->tmp.use_rsa_tmp + /* 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_kEDH|SSL_kDHr|SSL_kDHd)) + || (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=dtls1_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=dtls1_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=dtls1_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: + /* Check for second client hello (MS SGC) */ + ret = ssl3_check_client_hello(s); + if (ret <= 0) + goto end; + if (ret == 2) + { + dtls1_stop_timer(s); + s->state = SSL3_ST_SR_CLNT_HELLO_C; + } + else { + /* could be sent for a DH cert, even if we + * have not asked for it :-) */ + 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); + + SSL_export_keying_material(s, sctpauthkey, + sizeof(sctpauthkey), labelbuffer, + sizeof(labelbuffer), NULL, 0, 0); + + 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 + { + 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: + + s->d1->change_cipher_spec_ok = 1; + /* we should decide if we expected this one */ + 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: + 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=dtls1_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; 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; + goto end; + } + + dtls1_reset_seq_numbers(s, SSL3_CC_WRITE); + break; + + case SSL3_ST_SW_FINISHED_A: + case SSL3_ST_SW_FINISHED_B: + ret=dtls1_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; */ + + 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_request(SSL *s) + { + unsigned char *p; + + if (s->state == SSL3_ST_SW_HELLO_REQ_A) + { + p=(unsigned char *)s->init_buf->data; + p = dtls1_set_message_header(s, p, SSL3_MT_HELLO_REQUEST, 0, 0, 0); + + s->state=SSL3_ST_SW_HELLO_REQ_B; + /* number of bytes to write */ + s->init_num=DTLS1_HM_HEADER_LENGTH; + s->init_off=0; + + /* no need to buffer this message, since there are no retransmit + * requests for it */ + } + + /* SSL3_ST_SW_HELLO_REQ_B */ + return(dtls1_do_write(s,SSL3_RT_HANDSHAKE)); + } + +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]); + *(p++) = s->version >> 8; + *(p++) = s->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); + 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)); + } + +int dtls1_send_server_hello(SSL *s) + { + unsigned char *buf; + unsigned char *p,*d; + int i; + unsigned int sl; + unsigned long l; + + if (s->state == SSL3_ST_SW_SRVR_HELLO_A) + { + buf=(unsigned char *)s->init_buf->data; + p=s->s3->server_random; + ssl_fill_hello_random(s, 1, p, SSL3_RANDOM_SIZE); + /* Do the message type and length last */ + d=p= &(buf[DTLS1_HM_HEADER_LENGTH]); + + *(p++)=s->version>>8; + *(p++)=s->version&0xff; + + /* Random stuff */ + memcpy(p,s->s3->server_random,SSL3_RANDOM_SIZE); + p+=SSL3_RANDOM_SIZE; + + /* now in theory we have 3 options to sending back the + * session id. If it is a re-use, we send back the + * old session-id, if it is a new session, we send + * back the new session-id or we send back a 0 length + * session-id if we want it to be single use. + * Currently I will not implement the '0' length session-id + * 12-Jan-98 - I'll now support the '0' length stuff. + */ + if (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER)) + s->session->session_id_length=0; + + sl=s->session->session_id_length; + if (sl > sizeof s->session->session_id) + { + SSLerr(SSL_F_DTLS1_SEND_SERVER_HELLO, ERR_R_INTERNAL_ERROR); + return -1; + } + *(p++)=sl; + memcpy(p,s->session->session_id,sl); + p+=sl; + + /* put the cipher */ + if (s->s3->tmp.new_cipher == NULL) + return -1; + 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 ((p = ssl_add_serverhello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL) + { + SSLerr(SSL_F_DTLS1_SEND_SERVER_HELLO,ERR_R_INTERNAL_ERROR); + return -1; + } +#endif + + /* do the header */ + l=(p-d); + d=buf; + + d = dtls1_set_message_header(s, d, SSL3_MT_SERVER_HELLO, l, 0, l); + + s->state=SSL3_ST_SW_SRVR_HELLO_B; + /* number of bytes to write */ + s->init_num=p-buf; + s->init_off=0; + + /* buffer the message to handle re-xmits */ + dtls1_buffer_message(s, 0); + } + + /* SSL3_ST_SW_SRVR_HELLO_B */ + return(dtls1_do_write(s,SSL3_RT_HANDSHAKE)); + } + +int dtls1_send_server_done(SSL *s) + { + unsigned char *p; + + if (s->state == SSL3_ST_SW_SRVR_DONE_A) + { + p=(unsigned char *)s->init_buf->data; + + /* do the header */ + p = dtls1_set_message_header(s, p, SSL3_MT_SERVER_DONE, 0, 0, 0); + + s->state=SSL3_ST_SW_SRVR_DONE_B; + /* number of bytes to write */ + s->init_num=DTLS1_HM_HEADER_LENGTH; + s->init_off=0; + + /* buffer the message to handle re-xmits */ + dtls1_buffer_message(s, 0); + } + + /* SSL3_ST_SW_SRVR_DONE_B */ + return(dtls1_do_write(s,SSL3_RT_HANDSHAKE)); + } + +int dtls1_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; + 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_DTLS1_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_DTLS1_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_DTLS1_SEND_SERVER_KEY_EXCHANGE,SSL_R_MISSING_TMP_DH_KEY); + goto f_err; + } + + if (s->s3->tmp.dh != NULL) + { + DH_free(dh); + SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR); + goto err; + } + + if ((dh=DHparams_dup(dhp)) == NULL) + { + SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_R_DH_LIB); + goto err; + } + + s->s3->tmp.dh=dh; + if ((dhp->pub_key == NULL || + dhp->priv_key == NULL || + (s->options & SSL_OP_SINGLE_DH_USE))) + { + if(!DH_generate_key(dh)) + { + SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE, + ERR_R_DH_LIB); + goto err; + } + } + else + { + dh->pub_key=BN_dup(dhp->pub_key); + dh->priv_key=BN_dup(dhp->priv_key); + if ((dh->pub_key == NULL) || + (dh->priv_key == NULL)) + { + SSLerr(SSL_F_DTLS1_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 ((ecdhp == NULL) && (s->cert->ecdh_tmp_cb != NULL)) + { + 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_DTLS1_SEND_SERVER_KEY_EXCHANGE,SSL_R_MISSING_TMP_ECDH_KEY); + goto f_err; + } + + if (s->s3->tmp.ecdh != NULL) + { + EC_KEY_free(s->s3->tmp.ecdh); + SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR); + goto err; + } + + /* Duplicate the ECDH structure. */ + if (ecdhp == NULL) + { + SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB); + goto err; + } + if ((ecdh = EC_KEY_dup(ecdhp)) == NULL) + { + SSLerr(SSL_F_DTLS1_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_DTLS1_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_DTLS1_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_DTLS1_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_DTLS1_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_DTLS1_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_DTLS1_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 */ + { + al=SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE); + goto f_err; + } + for (i=0; r[i] != NULL; i++) + { + nr[i]=BN_num_bytes(r[i]); + n+=2+nr[i]; + } + + if (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL) + && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK)) + { + if ((pkey=ssl_get_sign_pkey(s,s->s3->tmp.new_cipher, NULL)) + == 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+DTLS1_HM_HEADER_LENGTH+kn)) + { + SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_BUF); + goto err; + } + d=(unsigned char *)s->init_buf->data; + p= &(d[DTLS1_HM_HEADER_LENGTH]); + + for (i=0; r[i] != NULL; i++) + { + 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[DTLS1_HM_HEADER_LENGTH]) and p points to the space + * at the end. */ +#ifndef OPENSSL_NO_RSA + if (pkey->type == EVP_PKEY_RSA) + { + q=md_buf; + j=0; + for (num=2; num > 0; num--) + { + EVP_DigestInit_ex(&md_ctx,(num == 2) + ?s->ctx->md5:s->ctx->sha1, NULL); + EVP_DigestUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE); + EVP_DigestUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE); + EVP_DigestUpdate(&md_ctx,&(d[DTLS1_HM_HEADER_LENGTH]),n); + EVP_DigestFinal_ex(&md_ctx,q, + (unsigned int *)&i); + q+=i; + j+=i; + } + if (RSA_sign(NID_md5_sha1, md_buf, j, + &(p[2]), &u, pkey->pkey.rsa) <= 0) + { + SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_RSA); + goto err; + } + s2n(u,p); + n+=u+2; + } + else +#endif +#if !defined(OPENSSL_NO_DSA) + if (pkey->type == EVP_PKEY_DSA) + { + /* lets do DSS */ + EVP_SignInit_ex(&md_ctx,EVP_dss1(), NULL); + EVP_SignUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE); + EVP_SignUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE); + EVP_SignUpdate(&md_ctx,&(d[DTLS1_HM_HEADER_LENGTH]),n); + if (!EVP_SignFinal(&md_ctx,&(p[2]), + (unsigned int *)&i,pkey)) + { + SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_DSA); + goto err; + } + s2n(i,p); + n+=i+2; + } + else +#endif +#if !defined(OPENSSL_NO_ECDSA) + if (pkey->type == EVP_PKEY_EC) + { + /* let's do ECDSA */ + EVP_SignInit_ex(&md_ctx,EVP_ecdsa(), NULL); + EVP_SignUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE); + EVP_SignUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE); + EVP_SignUpdate(&md_ctx,&(d[DTLS1_HM_HEADER_LENGTH]),n); + if (!EVP_SignFinal(&md_ctx,&(p[2]), + (unsigned int *)&i,pkey)) + { + SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_ECDSA); + goto err; + } + s2n(i,p); + n+=i+2; + } + else +#endif + { + /* Is this error check actually needed? */ + al=SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNKNOWN_PKEY_TYPE); + goto f_err; + } + } + + d = dtls1_set_message_header(s, d, + SSL3_MT_SERVER_KEY_EXCHANGE, n, 0, n); + + /* we should now have things packed up, so lets send + * it off */ + s->init_num=n+DTLS1_HM_HEADER_LENGTH; + s->init_off=0; + + /* buffer the message to handle re-xmits */ + dtls1_buffer_message(s, 0); + } + + s->state = SSL3_ST_SW_KEY_EXCH_B; + EVP_MD_CTX_cleanup(&md_ctx); + return(dtls1_do_write(s,SSL3_RT_HANDSHAKE)); +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); + return(-1); + } + +int dtls1_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; + unsigned int msg_len; + + if (s->state == SSL3_ST_SW_CERT_REQ_A) + { + buf=s->init_buf; + + d=p=(unsigned char *)&(buf->data[DTLS1_HM_HEADER_LENGTH]); + + /* get the list of acceptable cert types */ + p++; + n=ssl3_get_req_cert_type(s,p); + d[0]=n; + p+=n; + n++; + + 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,DTLS1_HM_HEADER_LENGTH+n+j+2)) + { + SSLerr(SSL_F_DTLS1_SEND_CERTIFICATE_REQUEST,ERR_R_BUF_LIB); + goto err; + } + p=(unsigned char *)&(buf->data[DTLS1_HM_HEADER_LENGTH+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=(unsigned char *)&(buf->data[DTLS1_HM_HEADER_LENGTH+off]); + s2n(nl,p); + + d=(unsigned char *)buf->data; + *(d++)=SSL3_MT_CERTIFICATE_REQUEST; + l2n3(n,d); + s2n(s->d1->handshake_write_seq,d); + s->d1->handshake_write_seq++; + + /* we should now have things packed up, so lets send + * it off */ + + s->init_num=n+DTLS1_HM_HEADER_LENGTH; + s->init_off=0; +#ifdef NETSCAPE_HANG_BUG +/* XXX: what to do about this? */ + 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 + + /* XDTLS: set message header ? */ + msg_len = s->init_num - DTLS1_HM_HEADER_LENGTH; + dtls1_set_message_header(s, (void *)s->init_buf->data, + SSL3_MT_CERTIFICATE_REQUEST, msg_len, 0, msg_len); + + /* buffer the message to handle re-xmits */ + dtls1_buffer_message(s, 0); + + s->state = SSL3_ST_SW_CERT_REQ_B; + } + + /* SSL3_ST_SW_CERT_REQ_B */ + return(dtls1_do_write(s,SSL3_RT_HANDSHAKE)); +err: + return(-1); + } + +int dtls1_send_server_certificate(SSL *s) + { + unsigned long l; + X509 *x; + + if (s->state == SSL3_ST_SW_CERT_A) + { + x=ssl_get_server_send_cert(s); + if (x == NULL) + { + /* VRS: allow null cert if auth == KRB5 */ + if ((s->s3->tmp.new_cipher->algorithm_mkey != SSL_kKRB5) || + (s->s3->tmp.new_cipher->algorithm_auth != SSL_aKRB5)) + { + SSLerr(SSL_F_DTLS1_SEND_SERVER_CERTIFICATE,ERR_R_INTERNAL_ERROR); + return(0); + } + } + + l=dtls1_output_cert_chain(s,x); + s->state=SSL3_ST_SW_CERT_B; + s->init_num=(int)l; + s->init_off=0; + + /* buffer the message to handle re-xmits */ + dtls1_buffer_message(s, 0); + } + + /* SSL3_ST_SW_CERT_B */ + return(dtls1_do_write(s,SSL3_RT_HANDSHAKE)); + } + +#ifndef OPENSSL_NO_TLSEXT +int dtls1_send_newsession_ticket(SSL *s) + { + if (s->state == SSL3_ST_SW_SESSION_TICKET_A) + { + unsigned char *p, *senc, *macstart; + int len, slen; + unsigned int hlen, msg_len; + EVP_CIPHER_CTX ctx; + HMAC_CTX hctx; + SSL_CTX *tctx = s->initial_ctx; + unsigned char iv[EVP_MAX_IV_LENGTH]; + unsigned char key_name[16]; + + /* get session encoding length */ + slen = i2d_SSL_SESSION(s->session, NULL); + /* Some length values are 16 bits, so forget it if session is + * too long + */ + if (slen > 0xFF00) + return -1; + /* Grow buffer if need be: the length calculation is as + * follows 12 (DTLS handshake message header) + + * 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, + DTLS1_HM_HEADER_LENGTH + 22 + EVP_MAX_IV_LENGTH + + EVP_MAX_BLOCK_LENGTH + EVP_MAX_MD_SIZE + slen)) + return -1; + senc = OPENSSL_malloc(slen); + if (!senc) + return -1; + p = senc; + i2d_SSL_SESSION(s->session, &p); + + p=(unsigned char *)&(s->init_buf->data[DTLS1_HM_HEADER_LENGTH]); + EVP_CIPHER_CTX_init(&ctx); + HMAC_CTX_init(&hctx); + /* Initialize HMAC and cipher contexts. If callback present + * it does all the work otherwise use generated values + * from parent ctx. + */ + if (tctx->tlsext_ticket_key_cb) + { + if (tctx->tlsext_ticket_key_cb(s, key_name, iv, &ctx, + &hctx, 1) < 0) + { + OPENSSL_free(senc); + return -1; + } + } + else + { + RAND_pseudo_bytes(iv, 16); + EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, + tctx->tlsext_tick_aes_key, iv); + HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16, + tlsext_tick_md(), NULL); + memcpy(key_name, tctx->tlsext_tick_key_name, 16); + } + l2n(s->session->tlsext_tick_lifetime_hint, p); + /* Skip ticket length for now */ + p += 2; + /* Output key name */ + macstart = p; + memcpy(p, key_name, 16); + p += 16; + /* output IV */ + memcpy(p, iv, EVP_CIPHER_CTX_iv_length(&ctx)); + p += EVP_CIPHER_CTX_iv_length(&ctx); + /* Encrypt session data */ + EVP_EncryptUpdate(&ctx, p, &len, senc, slen); + p += len; + EVP_EncryptFinal(&ctx, p, &len); + p += len; + EVP_CIPHER_CTX_cleanup(&ctx); + + HMAC_Update(&hctx, macstart, p - macstart); + HMAC_Final(&hctx, p, &hlen); + HMAC_CTX_cleanup(&hctx); + + p += hlen; + /* Now write out lengths: p points to end of data written */ + /* Total length */ + len = p - (unsigned char *)(s->init_buf->data); + /* Ticket length */ + p=(unsigned char *)&(s->init_buf->data[DTLS1_HM_HEADER_LENGTH]) + 4; + s2n(len - DTLS1_HM_HEADER_LENGTH - 6, p); + + /* number of bytes to write */ + s->init_num= len; + s->state=SSL3_ST_SW_SESSION_TICKET_B; + s->init_off=0; + OPENSSL_free(senc); + + /* XDTLS: set message header ? */ + msg_len = s->init_num - DTLS1_HM_HEADER_LENGTH; + dtls1_set_message_header(s, (void *)s->init_buf->data, + SSL3_MT_NEWSESSION_TICKET, msg_len, 0, msg_len); + + /* buffer the message to handle re-xmits */ + dtls1_buffer_message(s, 0); + } + + /* SSL3_ST_SW_SESSION_TICKET_B */ + return(dtls1_do_write(s,SSL3_RT_HANDSHAKE)); + } +#endif diff --git a/drivers/builtin_openssl2/ssl/heartbeat_test.c b/drivers/builtin_openssl2/ssl/heartbeat_test.c new file mode 100644 index 0000000000..d8cc559981 --- /dev/null +++ b/drivers/builtin_openssl2/ssl/heartbeat_test.c @@ -0,0 +1,465 @@ +/* test/heartbeat_test.c */ +/* + * Unit test for TLS heartbeats. + * + * Acts as a regression test against the Heartbleed bug (CVE-2014-0160). + * + * Author: Mike Bland (mbland@acm.org, http://mike-bland.com/) + * Date: 2014-04-12 + * License: Creative Commons Attribution 4.0 International (CC By 4.0) + * http://creativecommons.org/licenses/by/4.0/deed.en_US + * + * OUTPUT + * ------ + * The program returns zero on success. It will print a message with a count + * of the number of failed tests and return nonzero if any tests fail. + * + * It will print the contents of the request and response buffers for each + * failing test. In a "fixed" version, all the tests should pass and there + * should be no output. + * + * In a "bleeding" version, you'll see: + * + * test_dtls1_heartbleed failed: + * expected payload len: 0 + * received: 1024 + * sent 26 characters + * "HEARTBLEED " + * received 1024 characters + * "HEARTBLEED \xde\xad\xbe\xef..." + * ** test_dtls1_heartbleed failed ** + * + * The contents of the returned buffer in the failing test will depend on the + * contents of memory on your machine. + * + * MORE INFORMATION + * ---------------- + * http://mike-bland.com/2014/04/12/heartbleed.html + * http://mike-bland.com/tags/heartbleed.html + */ + +#include "../ssl/ssl_locl.h" +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#if !defined(OPENSSL_NO_HEARTBEATS) && !defined(OPENSSL_SYS_WINDOWS) + +/* As per https://tools.ietf.org/html/rfc6520#section-4 */ +#define MIN_PADDING_SIZE 16 + +/* Maximum number of payload characters to print as test output */ +#define MAX_PRINTABLE_CHARACTERS 1024 + +typedef struct heartbeat_test_fixture + { + SSL_CTX *ctx; + SSL *s; + const char* test_case_name; + int (*process_heartbeat)(SSL* s); + unsigned char* payload; + int sent_payload_len; + int expected_return_value; + int return_payload_offset; + int expected_payload_len; + const char* expected_return_payload; + } HEARTBEAT_TEST_FIXTURE; + +static HEARTBEAT_TEST_FIXTURE set_up(const char* const test_case_name, + const SSL_METHOD* meth) + { + HEARTBEAT_TEST_FIXTURE fixture; + int setup_ok = 1; + memset(&fixture, 0, sizeof(fixture)); + fixture.test_case_name = test_case_name; + + fixture.ctx = SSL_CTX_new(meth); + if (!fixture.ctx) + { + fprintf(stderr, "Failed to allocate SSL_CTX for test: %s\n", + test_case_name); + setup_ok = 0; + goto fail; + } + + fixture.s = SSL_new(fixture.ctx); + if (!fixture.s) + { + fprintf(stderr, "Failed to allocate SSL for test: %s\n", test_case_name); + setup_ok = 0; + goto fail; + } + + if (!ssl_init_wbio_buffer(fixture.s, 1)) + { + fprintf(stderr, "Failed to set up wbio buffer for test: %s\n", + test_case_name); + setup_ok = 0; + goto fail; + } + + if (!ssl3_setup_buffers(fixture.s)) + { + fprintf(stderr, "Failed to setup buffers for test: %s\n", + test_case_name); + setup_ok = 0; + goto fail; + } + + /* Clear the memory for the return buffer, since this isn't automatically + * zeroed in opt mode and will cause spurious test failures that will change + * with each execution. + */ + memset(fixture.s->s3->wbuf.buf, 0, fixture.s->s3->wbuf.len); + + fail: + if (!setup_ok) + { + ERR_print_errors_fp(stderr); + exit(EXIT_FAILURE); + } + return fixture; + } + +static HEARTBEAT_TEST_FIXTURE set_up_dtls(const char* const test_case_name) + { + HEARTBEAT_TEST_FIXTURE fixture = set_up(test_case_name, + DTLSv1_server_method()); + fixture.process_heartbeat = dtls1_process_heartbeat; + + /* As per dtls1_get_record(), skipping the following from the beginning of + * the returned heartbeat message: + * type-1 byte; version-2 bytes; sequence number-8 bytes; length-2 bytes + * + * And then skipping the 1-byte type encoded by process_heartbeat for + * a total of 14 bytes, at which point we can grab the length and the + * payload we seek. + */ + fixture.return_payload_offset = 14; + return fixture; + } + +/* Needed by ssl3_write_bytes() */ +static int dummy_handshake(SSL* s) + { + return 1; + } + +static HEARTBEAT_TEST_FIXTURE set_up_tls(const char* const test_case_name) + { + HEARTBEAT_TEST_FIXTURE fixture = set_up(test_case_name, + TLSv1_server_method()); + fixture.process_heartbeat = tls1_process_heartbeat; + fixture.s->handshake_func = dummy_handshake; + + /* As per do_ssl3_write(), skipping the following from the beginning of + * the returned heartbeat message: + * type-1 byte; version-2 bytes; length-2 bytes + * + * And then skipping the 1-byte type encoded by process_heartbeat for + * a total of 6 bytes, at which point we can grab the length and the payload + * we seek. + */ + fixture.return_payload_offset = 6; + return fixture; + } + +static void tear_down(HEARTBEAT_TEST_FIXTURE fixture) + { + ERR_print_errors_fp(stderr); + SSL_free(fixture.s); + SSL_CTX_free(fixture.ctx); + } + +static void print_payload(const char* const prefix, + const unsigned char *payload, const int n) + { + const int end = n < MAX_PRINTABLE_CHARACTERS ? n + : MAX_PRINTABLE_CHARACTERS; + int i = 0; + + printf("%s %d character%s", prefix, n, n == 1 ? "" : "s"); + if (end != n) printf(" (first %d shown)", end); + printf("\n \""); + + for (; i != end; ++i) + { + const unsigned char c = payload[i]; + if (isprint(c)) fputc(c, stdout); + else printf("\\x%02x", c); + } + printf("\"\n"); + } + +static int execute_heartbeat(HEARTBEAT_TEST_FIXTURE fixture) + { + int result = 0; + SSL* s = fixture.s; + unsigned char *payload = fixture.payload; + unsigned char sent_buf[MAX_PRINTABLE_CHARACTERS + 1]; + int return_value; + unsigned const char *p; + int actual_payload_len; + + s->s3->rrec.data = payload; + s->s3->rrec.length = strlen((const char*)payload); + *payload++ = TLS1_HB_REQUEST; + s2n(fixture.sent_payload_len, payload); + + /* Make a local copy of the request, since it gets overwritten at some + * point */ + memcpy((char *)sent_buf, (const char*)payload, sizeof(sent_buf)); + + return_value = fixture.process_heartbeat(s); + + if (return_value != fixture.expected_return_value) + { + printf("%s failed: expected return value %d, received %d\n", + fixture.test_case_name, fixture.expected_return_value, + return_value); + result = 1; + } + + /* If there is any byte alignment, it will be stored in wbuf.offset. */ + p = &(s->s3->wbuf.buf[ + fixture.return_payload_offset + s->s3->wbuf.offset]); + actual_payload_len = 0; + n2s(p, actual_payload_len); + + if (actual_payload_len != fixture.expected_payload_len) + { + printf("%s failed:\n expected payload len: %d\n received: %d\n", + fixture.test_case_name, fixture.expected_payload_len, + actual_payload_len); + print_payload("sent", sent_buf, strlen((const char*)sent_buf)); + print_payload("received", p, actual_payload_len); + result = 1; + } + else + { + char* actual_payload = BUF_strndup((const char*)p, actual_payload_len); + if (strcmp(actual_payload, fixture.expected_return_payload) != 0) + { + printf("%s failed:\n expected payload: \"%s\"\n received: \"%s\"\n", + fixture.test_case_name, fixture.expected_return_payload, + actual_payload); + result = 1; + } + OPENSSL_free(actual_payload); + } + + if (result != 0) + { + printf("** %s failed **\n--------\n", fixture.test_case_name); + } + return result; + } + +static int honest_payload_size(unsigned char payload_buf[]) + { + /* Omit three-byte pad at the beginning for type and payload length */ + return strlen((const char*)&payload_buf[3]) - MIN_PADDING_SIZE; + } + +#define SETUP_HEARTBEAT_TEST_FIXTURE(type)\ + HEARTBEAT_TEST_FIXTURE fixture = set_up_##type(__func__);\ + int result = 0 + +#define EXECUTE_HEARTBEAT_TEST()\ + if (execute_heartbeat(fixture) != 0) result = 1;\ + tear_down(fixture);\ + return result + +static int test_dtls1_not_bleeding() + { + SETUP_HEARTBEAT_TEST_FIXTURE(dtls); + /* Three-byte pad at the beginning for type and payload length */ + unsigned char payload_buf[] = " Not bleeding, sixteen spaces of padding" + " "; + const int payload_buf_len = honest_payload_size(payload_buf); + + fixture.payload = &payload_buf[0]; + fixture.sent_payload_len = payload_buf_len; + fixture.expected_return_value = 0; + fixture.expected_payload_len = payload_buf_len; + fixture.expected_return_payload = "Not bleeding, sixteen spaces of padding"; + EXECUTE_HEARTBEAT_TEST(); + } + +static int test_dtls1_not_bleeding_empty_payload() + { + int payload_buf_len; + + SETUP_HEARTBEAT_TEST_FIXTURE(dtls); + /* Three-byte pad at the beginning for type and payload length, plus a NUL + * at the end */ + unsigned char payload_buf[4 + MIN_PADDING_SIZE]; + memset(payload_buf, ' ', sizeof(payload_buf)); + payload_buf[sizeof(payload_buf) - 1] = '\0'; + payload_buf_len = honest_payload_size(payload_buf); + + fixture.payload = &payload_buf[0]; + fixture.sent_payload_len = payload_buf_len; + fixture.expected_return_value = 0; + fixture.expected_payload_len = payload_buf_len; + fixture.expected_return_payload = ""; + EXECUTE_HEARTBEAT_TEST(); + } + +static int test_dtls1_heartbleed() + { + SETUP_HEARTBEAT_TEST_FIXTURE(dtls); + /* Three-byte pad at the beginning for type and payload length */ + unsigned char payload_buf[] = " HEARTBLEED "; + + fixture.payload = &payload_buf[0]; + fixture.sent_payload_len = MAX_PRINTABLE_CHARACTERS; + fixture.expected_return_value = 0; + fixture.expected_payload_len = 0; + fixture.expected_return_payload = ""; + EXECUTE_HEARTBEAT_TEST(); + } + +static int test_dtls1_heartbleed_empty_payload() + { + SETUP_HEARTBEAT_TEST_FIXTURE(dtls); + /* Excluding the NUL at the end, one byte short of type + payload length + + * minimum padding */ + unsigned char payload_buf[MIN_PADDING_SIZE + 3]; + memset(payload_buf, ' ', sizeof(payload_buf)); + payload_buf[sizeof(payload_buf) - 1] = '\0'; + + fixture.payload = &payload_buf[0]; + fixture.sent_payload_len = MAX_PRINTABLE_CHARACTERS; + fixture.expected_return_value = 0; + fixture.expected_payload_len = 0; + fixture.expected_return_payload = ""; + EXECUTE_HEARTBEAT_TEST(); + } + +static int test_dtls1_heartbleed_excessive_plaintext_length() + { + SETUP_HEARTBEAT_TEST_FIXTURE(dtls); + /* Excluding the NUL at the end, one byte in excess of maximum allowed + * heartbeat message length */ + unsigned char payload_buf[SSL3_RT_MAX_PLAIN_LENGTH + 2]; + memset(payload_buf, ' ', sizeof(payload_buf)); + payload_buf[sizeof(payload_buf) - 1] = '\0'; + + fixture.payload = &payload_buf[0]; + fixture.sent_payload_len = honest_payload_size(payload_buf); + fixture.expected_return_value = 0; + fixture.expected_payload_len = 0; + fixture.expected_return_payload = ""; + EXECUTE_HEARTBEAT_TEST(); + } + +static int test_tls1_not_bleeding() + { + SETUP_HEARTBEAT_TEST_FIXTURE(tls); + /* Three-byte pad at the beginning for type and payload length */ + unsigned char payload_buf[] = " Not bleeding, sixteen spaces of padding" + " "; + const int payload_buf_len = honest_payload_size(payload_buf); + + fixture.payload = &payload_buf[0]; + fixture.sent_payload_len = payload_buf_len; + fixture.expected_return_value = 0; + fixture.expected_payload_len = payload_buf_len; + fixture.expected_return_payload = "Not bleeding, sixteen spaces of padding"; + EXECUTE_HEARTBEAT_TEST(); + } + +static int test_tls1_not_bleeding_empty_payload() + { + int payload_buf_len; + + SETUP_HEARTBEAT_TEST_FIXTURE(tls); + /* Three-byte pad at the beginning for type and payload length, plus a NUL + * at the end */ + unsigned char payload_buf[4 + MIN_PADDING_SIZE]; + memset(payload_buf, ' ', sizeof(payload_buf)); + payload_buf[sizeof(payload_buf) - 1] = '\0'; + payload_buf_len = honest_payload_size(payload_buf); + + fixture.payload = &payload_buf[0]; + fixture.sent_payload_len = payload_buf_len; + fixture.expected_return_value = 0; + fixture.expected_payload_len = payload_buf_len; + fixture.expected_return_payload = ""; + EXECUTE_HEARTBEAT_TEST(); + } + +static int test_tls1_heartbleed() + { + SETUP_HEARTBEAT_TEST_FIXTURE(tls); + /* Three-byte pad at the beginning for type and payload length */ + unsigned char payload_buf[] = " HEARTBLEED "; + + fixture.payload = &payload_buf[0]; + fixture.sent_payload_len = MAX_PRINTABLE_CHARACTERS; + fixture.expected_return_value = 0; + fixture.expected_payload_len = 0; + fixture.expected_return_payload = ""; + EXECUTE_HEARTBEAT_TEST(); + } + +static int test_tls1_heartbleed_empty_payload() + { + SETUP_HEARTBEAT_TEST_FIXTURE(tls); + /* Excluding the NUL at the end, one byte short of type + payload length + + * minimum padding */ + unsigned char payload_buf[MIN_PADDING_SIZE + 3]; + memset(payload_buf, ' ', sizeof(payload_buf)); + payload_buf[sizeof(payload_buf) - 1] = '\0'; + + fixture.payload = &payload_buf[0]; + fixture.sent_payload_len = MAX_PRINTABLE_CHARACTERS; + fixture.expected_return_value = 0; + fixture.expected_payload_len = 0; + fixture.expected_return_payload = ""; + EXECUTE_HEARTBEAT_TEST(); + } + +#undef EXECUTE_HEARTBEAT_TEST +#undef SETUP_HEARTBEAT_TEST_FIXTURE + +int main(int argc, char *argv[]) + { + int num_failed; + + SSL_library_init(); + SSL_load_error_strings(); + + num_failed = test_dtls1_not_bleeding() + + test_dtls1_not_bleeding_empty_payload() + + test_dtls1_heartbleed() + + test_dtls1_heartbleed_empty_payload() + + /* The following test causes an assertion failure at + * ssl/d1_pkt.c:dtls1_write_bytes() in versions prior to 1.0.1g: */ + (OPENSSL_VERSION_NUMBER >= 0x1000107fL ? + test_dtls1_heartbleed_excessive_plaintext_length() : 0) + + test_tls1_not_bleeding() + + test_tls1_not_bleeding_empty_payload() + + test_tls1_heartbleed() + + test_tls1_heartbleed_empty_payload() + + 0; + + ERR_print_errors_fp(stderr); + + if (num_failed != 0) + { + printf("%d test%s failed\n", num_failed, num_failed != 1 ? "s" : ""); + return EXIT_FAILURE; + } + return EXIT_SUCCESS; + } + +#else /* OPENSSL_NO_HEARTBEATS*/ + +int main(int argc, char *argv[]) + { + return EXIT_SUCCESS; + } +#endif /* OPENSSL_NO_HEARTBEATS */ diff --git a/drivers/builtin_openssl2/ssl/install-ssl.com b/drivers/builtin_openssl2/ssl/install-ssl.com new file mode 100755 index 0000000000..afe6967f85 --- /dev/null +++ b/drivers/builtin_openssl2/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/drivers/builtin_openssl2/ssl/kssl.c b/drivers/builtin_openssl2/ssl/kssl.c new file mode 100644 index 0000000000..fd7c67bb1f --- /dev/null +++ b/drivers/builtin_openssl2/ssl/kssl.c @@ -0,0 +1,2221 @@ +/* ssl/kssl.c -*- mode: C; c-file-style: "eay" -*- */ +/* 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; + + printf("%s[%d] ", label, kdata->length); + for (i=0; i < (int)kdata->length; i++) + { + if (0 && isprint((int) kdata->data[i])) + printf( "%c ", kdata->data[i]); + else + printf( "%02x ", (unsigned char) kdata->data[i]); + } + printf("\n"); + } + + +/* Display contents of krb5_authdata struct, for debugging +*/ +void +print_krb5_authdata(char *label, krb5_authdata **adata) + { + if (adata == NULL) + { + printf("%s, authdata==0\n", label); + return; + } + printf("%s [%p]\n", label, (void *)adata); +#if 0 + { + int i; + printf("%s[at%d:%d] ", label, adata->ad_type, adata->length); + for (i=0; i < adata->length; i++) + { + printf((isprint(adata->contents[i]))? "%c ": "%02x", + adata->contents[i]); + } + printf("\n"); + } +#endif + } + + +/* Display contents of krb5_keyblock struct, for debugging +*/ +void +print_krb5_keyblock(char *label, krb5_keyblock *keyblk) + { + int i; + + if (keyblk == NULL) + { + printf("%s, keyblk==0\n", label); + return; + } +#ifdef KRB5_HEIMDAL + printf("%s\n\t[et%d:%d]: ", label, keyblk->keytype, + keyblk->keyvalue->length); + for (i=0; i < (int)keyblk->keyvalue->length; i++) + { + printf("%02x",(unsigned char *)(keyblk->keyvalue->contents)[i]); + } + printf("\n"); +#else + printf("%s\n\t[et%d:%d]: ", label, keyblk->enctype, keyblk->length); + for (i=0; i < (int)keyblk->length; i++) + { + printf("%02x",keyblk->contents[i]); + } + printf("\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; + + printf("%s principal Realm: ", label); + if (princ == NULL) return; + for (ui=0; ui < (int)princ->realm.length; ui++) putchar(princ->realm.data[ui]); + printf(" (nametype %d) has %d strings:\n", princ->type,princ->length); + for (i=0; i < (int)princ->length; i++) + { + printf("\t%d [%d]: ", i, princ->data[i].length); + for (uj=0; uj < (int)princ->data[i].length; uj++) { + putchar(princ->data[i].data[uj]); + } + printf("\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 + printf("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; + printf("Decrypted ticket fields:\n"); + printf("\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)); + printf("\tcaddrs: %p, authdata: %p\n", + krb5ticket->enc_part2->caddrs, + krb5ticket->enc_part2->authorization_data); + if (paddr) + { + printf("\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); + } + } + printf("\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, + 0 /* IGNORE_VNO */, + 0 /* IGNORE_ENCTYPE */, + &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 + printf("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; + printf("kssl_check_authent: authenticator[%d]:\n",authentp->length); + p = authentp->data; + for (ui=0; ui < authentp->length; ui++) printf("%02x ",p[ui]); + printf("\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; + printf("kssl_check_authent: decrypted authenticator[%d] =\n", outl); + for (padl=0; padl < outl; padl++) printf("%02x ",unenc_authent[padl]); + printf("\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 + printf("kssl_check_authent: returns %d for client time ", *atimep); + if (auth && auth->ctime && auth->ctime->length && auth->ctime->data) + printf("%.*s\n", auth->ctime->length, auth->ctime->data); + else printf("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 dont'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/drivers/builtin_openssl2/ssl/kssl_lcl.h b/drivers/builtin_openssl2/ssl/kssl_lcl.h new file mode 100644 index 0000000000..c039c91b4e --- /dev/null +++ b/drivers/builtin_openssl2/ssl/kssl_lcl.h @@ -0,0 +1,87 @@ +/* ssl/kssl.h -*- mode: C; c-file-style: "eay" -*- */ +/* 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/drivers/builtin_openssl2/ssl/s23_clnt.c b/drivers/builtin_openssl2/ssl/s23_clnt.c new file mode 100644 index 0000000000..2b93c639dd --- /dev/null +++ b/drivers/builtin_openssl2/ssl/s23_clnt.c @@ -0,0 +1,800 @@ +/* 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 + if (ver == SSL3_VERSION) + return(SSLv3_client_method()); + else 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; +#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 + } +#endif + + buf=(unsigned char *)s->init_buf->data; + if (s->state == SSL23_ST_CW_CLNT_HELLO_A) + { +#if 0 + /* don't reuse session-id's */ + if (!ssl_get_new_session(s,0)) + { + return(-1); + } +#endif + + 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 (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) */ +#if 0 + s->session->session_id_length=0; +#endif + 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)) == NULL) + { + 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_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) */ + + 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 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; + } + + 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_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; + + /* Since, if we are sending a ssl23 client hello, we are not + * reusing a session-id */ + if (!ssl_get_new_session(s,0)) + goto err; + + return(SSL_connect(s)); +err: + return(-1); + } diff --git a/drivers/builtin_openssl2/ssl/s23_lib.c b/drivers/builtin_openssl2/ssl/s23_lib.c new file mode 100644 index 0000000000..3bf728318a --- /dev/null +++ b/drivers/builtin_openssl2/ssl/s23_lib.c @@ -0,0 +1,187 @@ +/* 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 */ + 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/drivers/builtin_openssl2/ssl/s23_meth.c b/drivers/builtin_openssl2/ssl/s23_meth.c new file mode 100644 index 0000000000..40eae0f0be --- /dev/null +++ b/drivers/builtin_openssl2/ssl/s23_meth.c @@ -0,0 +1,92 @@ +/* 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/drivers/builtin_openssl2/ssl/s23_pkt.c b/drivers/builtin_openssl2/ssl/s23_pkt.c new file mode 100644 index 0000000000..4ca6a1b258 --- /dev/null +++ b/drivers/builtin_openssl2/ssl/s23_pkt.c @@ -0,0 +1,117 @@ +/* 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/drivers/builtin_openssl2/ssl/s23_srvr.c b/drivers/builtin_openssl2/ssl/s23_srvr.c new file mode 100644 index 0000000000..4877849013 --- /dev/null +++ b/drivers/builtin_openssl2/ssl/s23_srvr.c @@ -0,0 +1,638 @@ +/* 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 + if (ver == SSL3_VERSION) + return(SSLv3_server_method()); + else 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)) + { + 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) + { + char buf_space[11]; /* 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= &(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; + + } + } + else if ((p[0] == SSL3_RT_HANDSHAKE) && + (p[1] == SSL3_VERSION_MAJOR) && + (p[5] == SSL3_MT_CLIENT_HELLO) && + ((p[3] == 0 && p[4] < 5 /* silly record length? */) + || (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 assume TLS 1.0 to avoid protocol version downgrade + * attacks. */ + if (p[3] == 0 && p[4] < 6) + { +#if 0 + SSLerr(SSL_F_SSL23_GET_CLIENT_HELLO,SSL_R_RECORD_TOO_SMALL); + goto err; +#else + v[1] = TLS1_VERSION_MINOR; +#endif + } + /* 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.... + */ + else 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; + } + } + +#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]; + + 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; + } + + j=ssl23_read_bytes(s,n+2); + if (j <= 0) return(j); + + ssl3_finish_mac(s, s->packet+2, s->packet_length-2); + if (s->msg_callback) + s->msg_callback(0, SSL2_VERSION, 0, s->packet+2, s->packet_length-2, s, s->msg_callback_arg); /* CLIENT-HELLO */ + + 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) */ + + 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 (s->version == TLS1_2_VERSION) + s->method = TLSv1_2_server_method(); + else if (s->version == TLS1_1_VERSION) + s->method = TLSv1_1_server_method(); + else if (s->version == TLS1_VERSION) + s->method = TLSv1_server_method(); + else + s->method = SSLv3_server_method(); +#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/drivers/builtin_openssl2/ssl/s2_clnt.c b/drivers/builtin_openssl2/ssl/s2_clnt.c new file mode 100644 index 0000000000..03b6cf9673 --- /dev/null +++ b/drivers/builtin_openssl2/ssl/s2_clnt.c @@ -0,0 +1,1127 @@ +/* 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) + s->msg_callback(0, s->version, 0, buf, (size_t)len, s, s->msg_callback_arg); /* SERVER-HELLO */ + + /* 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 + { +#ifdef undef + /* 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) + s->msg_callback(0, s->version, 0, buf, (size_t)s->init_num, s, s->msg_callback_arg); /* REQUEST-CERTIFICATE */ + + /* 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) + s->msg_callback(0, s->version, 0, p, len, s, s->msg_callback_arg); /* SERVER-VERIFY */ + 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) + s->msg_callback(0, s->version, 0, buf, (size_t)s->init_num, s, s->msg_callback_arg); /* SERVER-FINISHED */ + + 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/drivers/builtin_openssl2/ssl/s2_enc.c b/drivers/builtin_openssl2/ssl/s2_enc.c new file mode 100644 index 0000000000..ff3395f459 --- /dev/null +++ b/drivers/builtin_openssl2/ssl/s2_enc.c @@ -0,0 +1,193 @@ +/* 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 */ +void 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; + + + 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; + + EVP_Cipher(ds,s->s2->mac_data,s->s2->mac_data,l); + } + +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/drivers/builtin_openssl2/ssl/s2_lib.c b/drivers/builtin_openssl2/ssl/s2_lib.c new file mode 100644 index 0000000000..9914604109 --- /dev/null +++ b/drivers/builtin_openssl2/ssl/s2_lib.c @@ -0,0 +1,556 @@ +/* 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_EXP|SSL_MEDIUM, + 0, + 128, + 128, + }, + +/* 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_EXPORT|SSL_EXP40, + SSL2_CF_5_BYTE_ENC, + 40, + 128, + }, + +/* 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_EXP|SSL_MEDIUM, + 0, + 128, + 128, + }, + +/* 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_EXPORT|SSL_EXP40, + SSL2_CF_5_BYTE_ENC, + 40, + 128, + }, + +#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_EXP|SSL_MEDIUM, + 0, + 128, + 128, + }, +#endif + +/* 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_EXP|SSL_LOW, + 0, + 56, + 56, + }, + +/* 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_EXP|SSL_HIGH, + 0, + 168, + 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_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; + 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); + if ((cp == NULL) || (cp->valid == 0)) + return NULL; + else + 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) 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) + s->msg_callback(1, s->version, 0, buf, 3, s, s->msg_callback_arg); /* ERROR */ + } + } + +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/drivers/builtin_openssl2/ssl/s2_meth.c b/drivers/builtin_openssl2/ssl/s2_meth.c new file mode 100644 index 0000000000..f0e8ca593d --- /dev/null +++ b/drivers/builtin_openssl2/ssl/s2_meth.c @@ -0,0 +1,84 @@ +/* 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 +#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 */ + +# if PEDANTIC +static void *dummy=&dummy; +# endif + +#endif diff --git a/drivers/builtin_openssl2/ssl/s2_pkt.c b/drivers/builtin_openssl2/ssl/s2_pkt.c new file mode 100644 index 0000000000..8bb6ab8baa --- /dev/null +++ b/drivers/builtin_openssl2/ssl/s2_pkt.c @@ -0,0 +1,743 @@ +/* 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)) + { + ssl2_enc(s,0); + 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]); + /* 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; + ssl2_enc(s,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/drivers/builtin_openssl2/ssl/s2_srvr.c b/drivers/builtin_openssl2/ssl/s2_srvr.c new file mode 100644 index 0000000000..2cba426bb7 --- /dev/null +++ b/drivers/builtin_openssl2/ssl/s2_srvr.c @@ -0,0 +1,1148 @@ +/* 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 <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; + + buf=s->init_buf; + if ((buf == NULL) && ((buf=BUF_MEM_new()) == NULL)) + { ret= -1; goto end; } + if (!BUF_MEM_grow(buf,(int) + SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER)) + { 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,ek; + unsigned long len; + unsigned char *p; + const SSL_CIPHER *cp; + const EVP_CIPHER *c; + const EVP_MD *md; + + 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) + { + 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) + s->msg_callback(0, s->version, 0, p, (size_t)len, s, s->msg_callback_arg); /* CLIENT-MASTER-KEY */ + 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); + } + 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); + + 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); + } + + if (s->session->cipher->algorithm2 & SSL2_CF_8_BYTE_ENC) + { + is_export=1; + ek=8; + } + else + ek=5; + + /* bad decrypt */ +#if 1 + /* If a bad decrypt, continue with protocol but with a + * random master secret (Bleichenbacher attack) */ + if ((i < 0) || + ((!is_export && (i != EVP_CIPHER_key_length(c))) + || (is_export && ((i != ek) || (s->s2->tmp.clear+(unsigned int)i != + (unsigned int)EVP_CIPHER_key_length(c)))))) + { + ERR_clear_error(); + if (is_export) + i=ek; + else + i=EVP_CIPHER_key_length(c); + if (RAND_pseudo_bytes(p,i) <= 0) + return 0; + } +#else + if (i < 0) + { + error=1; + SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_BAD_RSA_DECRYPT); + } + /* incorrect number of key bytes for non export cipher */ + else if ((!is_export && (i != EVP_CIPHER_key_length(c))) + || (is_export && ((i != ek) || (s->s2->tmp.clear+i != + EVP_CIPHER_key_length(c))))) + { + error=1; + SSLerr(SSL_F_GET_CLIENT_MASTER_KEY,SSL_R_WRONG_NUMBER_OF_KEY_BITS); + } + if (error) + { + ssl2_return_error(s,SSL2_PE_UNDEFINED_ERROR); + return(-1); + } +#endif + + if (is_export) i+=s->s2->tmp.clear; + + if (i > 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; + } + s->session->master_key_length=i; + memcpy(s->session->master_key,p,(unsigned int)i); + 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; + 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) + s->msg_callback(0, s->version, 0, p, (size_t)len, s, s->msg_callback_arg); /* CLIENT-HELLO */ + 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; + } + for (z=0; z<sk_SSL_CIPHER_num(prio); z++) + { + if (sk_SSL_CIPHER_find(allow,sk_SSL_CIPHER_value(prio,z)) < 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; + } + /* 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) + s->msg_callback(0, s->version, 0, p, len, s, s->msg_callback_arg); /* CLIENT-FINISHED */ + 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; + i=ssl2_read(s,(char *)&(p[s->init_num]),6-s->init_num); /* try to read 6 octets ... */ + if (i < 3-s->init_num) /* ... but don't call ssl2_part_read now if we got at least 3 + * (probably NO-CERTIFICATE-ERROR) */ + { + 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) + s->msg_callback(0, s->version, 0, p, 3, s, s->msg_callback_arg); /* ERROR */ + + /* 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) + s->msg_callback(0, s->version, 0, p, len, s, s->msg_callback_arg); /* CLIENT-CERTIFICATE */ + 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/drivers/builtin_openssl2/ssl/s3_both.c b/drivers/builtin_openssl2/ssl/s3_both.c new file mode 100644 index 0000000000..53b9390fdd --- /dev/null +++ b/drivers/builtin_openssl2/ssl/s3_both.c @@ -0,0 +1,853 @@ +/* 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,*d; + int i; + unsigned long l; + + if (s->state == a) + { + d=(unsigned char *)s->init_buf->data; + p= &(d[4]); + + 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); + p+=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 + + *(d++)=SSL3_MT_FINISHED; + l2n3(l,d); + s->init_num=(int)l+4; + s->init_off=0; + + s->state=b; + } + + /* SSL3_ST_SEND_xxxxxx_HELLO_B */ + return(ssl3_do_write(s,SSL3_RT_HANDSHAKE)); + } + +#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 + + n=s->method->ssl_get_message(s, + a, + b, + SSL3_MT_FINISHED, + 64, /* should actually be 36+4 :-) */ + &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)); + } + +static int ssl3_add_cert_to_buf(BUF_MEM *buf, unsigned long *l, X509 *x) + { + int n; + unsigned char *p; + + n=i2d_X509(x,NULL); + if (!BUF_MEM_grow_clean(buf,(int)(n+(*l)+3))) + { + SSLerr(SSL_F_SSL3_ADD_CERT_TO_BUF,ERR_R_BUF_LIB); + return(-1); + } + p=(unsigned char *)&(buf->data[*l]); + l2n3(n,p); + i2d_X509(x,&p); + *l+=n+3; + + return(0); + } + +unsigned long ssl3_output_cert_chain(SSL *s, X509 *x) + { + unsigned char *p; + int i; + unsigned long l=7; + BUF_MEM *buf; + int no_chain; + + if ((s->mode & SSL_MODE_NO_AUTO_CHAIN) || s->ctx->extra_certs) + no_chain = 1; + else + no_chain = 0; + + /* TLSv1 sends a chain with nothing in it, instead of an alert */ + buf=s->init_buf; + if (!BUF_MEM_grow_clean(buf,10)) + { + SSLerr(SSL_F_SSL3_OUTPUT_CERT_CHAIN,ERR_R_BUF_LIB); + return(0); + } + if (x != NULL) + { + if (no_chain) + { + if (ssl3_add_cert_to_buf(buf, &l, x)) + return(0); + } + else + { + X509_STORE_CTX xs_ctx; + + if (!X509_STORE_CTX_init(&xs_ctx,s->ctx->cert_store,x,NULL)) + { + SSLerr(SSL_F_SSL3_OUTPUT_CERT_CHAIN,ERR_R_X509_LIB); + 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 (ssl3_add_cert_to_buf(buf, &l, x)) + { + X509_STORE_CTX_cleanup(&xs_ctx); + return 0; + } + } + X509_STORE_CTX_cleanup(&xs_ctx); + } + } + /* Thawte special :-) */ + for (i=0; i<sk_X509_num(s->ctx->extra_certs); i++) + { + x=sk_X509_value(s->ctx->extra_certs,i); + if (ssl3_add_cert_to_buf(buf, &l, x)) + return(0); + } + + l-=7; + p=(unsigned char *)&(buf->data[4]); + l2n3(l,p); + l+=3; + p=(unsigned char *)&(buf->data[0]); + *(p++)=SSL3_MT_CERTIFICATE; + l2n3(l,p); + l+=4; + return(l); + } + +/* 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->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; + } + if ((mt < 0) && (*p == SSL3_MT_CLIENT_HELLO) && + (st1 == SSL3_ST_SR_CERT_A) && + (stn == SSL3_ST_SR_CERT_B)) + { + /* At this point we have got an MS SGC second client + * hello (maybe we should always allow the client to + * start a new handshake?). We need to restart the mac. + * Don't increment {num,total}_renegotiations because + * we have not completed the handshake. */ + ssl3_init_finished_mac(s); + } + + 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; + } +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_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER) + 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_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER) + 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/drivers/builtin_openssl2/ssl/s3_cbc.c b/drivers/builtin_openssl2/ssl/s3_cbc.c new file mode 100644 index 0000000000..443a31e746 --- /dev/null +++ b/drivers/builtin_openssl2/ssl/s3_cbc.c @@ -0,0 +1,790 @@ +/* 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 "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 + +/* Some utility functions are needed: + * + * These macros return the given value with the MSB copied to all the other + * bits. They use the fact that arithmetic shift shifts-in the sign bit. + * However, this is not ensured by the C standard so you may need to replace + * them with something else on odd CPUs. */ +#define DUPLICATE_MSB_TO_ALL(x) ( (unsigned)( (int)(x) >> (sizeof(int)*8-1) ) ) +#define DUPLICATE_MSB_TO_ALL_8(x) ((unsigned char)(DUPLICATE_MSB_TO_ALL(x))) + +/* constant_time_lt returns 0xff if a<b and 0x00 otherwise. */ +static unsigned constant_time_lt(unsigned a, unsigned b) + { + a -= b; + return DUPLICATE_MSB_TO_ALL(a); + } + +/* constant_time_ge returns 0xff if a>=b and 0x00 otherwise. */ +static unsigned constant_time_ge(unsigned a, unsigned b) + { + a -= b; + return DUPLICATE_MSB_TO_ALL(~a); + } + +/* constant_time_eq_8 returns 0xff if a==b and 0x00 otherwise. */ +static unsigned char constant_time_eq_8(unsigned a, unsigned b) + { + unsigned c = a ^ b; + c--; + return DUPLICATE_MSB_TO_ALL_8(c); + } + +/* 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 (int)((good & 1) | (~good & -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 (s->version >= TLS1_1_VERSION || s->version == DTLS1_BAD_VER) + { + /* 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 ((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(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. We + * AND the bottom 8 bits together and duplicate the result to all the + * bits. */ + good &= good >> 4; + good &= good >> 2; + good &= good >> 1; + good <<= sizeof(good)*8-1; + good = DUPLICATE_MSB_TO_ALL(good); + + padding_length = good & (padding_length+1); + rec->length -= padding_length; + rec->type |= padding_length<<8; /* kludge: pass padding length */ + + return (int)((good & 1) | (~good & -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(i, mac_start); + unsigned char mac_ended = constant_time_ge(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. ) */ +void 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: + MD5_Init((MD5_CTX*)md_state.c); + 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: + SHA1_Init((SHA_CTX*)md_state.c); + 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: + SHA224_Init((SHA256_CTX*)md_state.c); + 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: + SHA256_Init((SHA256_CTX*)md_state.c); + 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: + SHA384_Init((SHA512_CTX*)md_state.c); + 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: + SHA512_Init((SHA512_CTX*)md_state.c); + 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 = -1; + return; + } + + 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) + { + /* 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). */ + unsigned 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(j, c); + is_past_cp1 = is_block_a & constant_time_ge(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 = (b&~is_past_c) | (0x80&is_past_c); + /* 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 = (b&~is_block_b) | (is_block_b&length_bytes[j-(md_block_size-md_length_size)]); + } + 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); + EVP_DigestInit_ex(&md_ctx, ctx->digest, NULL /* engine */); + if (is_sslv3) + { + /* We repurpose |hmac_pad| to contain the SSLv3 pad2 block. */ + memset(hmac_pad, 0x5c, sslv3_pad_length); + + EVP_DigestUpdate(&md_ctx, mac_secret, mac_secret_length); + EVP_DigestUpdate(&md_ctx, hmac_pad, sslv3_pad_length); + EVP_DigestUpdate(&md_ctx, mac_out, md_size); + } + else + { + /* Complete the HMAC in the standard manner. */ + for (i = 0; i < md_block_size; i++) + hmac_pad[i] ^= 0x6a; + + EVP_DigestUpdate(&md_ctx, hmac_pad, md_block_size); + EVP_DigestUpdate(&md_ctx, mac_out, md_size); + } + 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); + } + +#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/drivers/builtin_openssl2/ssl/s3_clnt.c b/drivers/builtin_openssl2/ssl/s3_clnt.c new file mode 100644 index 0000000000..0457af8789 --- /dev/null +++ b/drivers/builtin_openssl2/ssl/s3_clnt.c @@ -0,0 +1,3381 @@ +/* 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 const SSL_METHOD *ssl3_get_client_method(int ver); +static int ca_dn_cmp(const X509_NAME * const *a,const X509_NAME * const *b); + +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) + +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); + 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; + 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; } + + /* setup buffing BIO */ + if (!ssl_init_wbio_buffer(s,0)) { ret= -1; 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; + 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 + ret=ssl3_check_finished(s); + if (ret <= 0) goto end; + if (ret == 2) + { + s->hit = 1; + if (s->tlsext_ticket_expected) + s->state=SSL3_ST_CR_SESSION_TICKET_A; + else + s->state=SSL3_ST_CR_FINISHED_A; + s->init_num=0; + break; + } +#endif + /* Check if it is anon DH/ECDH */ + /* 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; + 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); + 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; + s->s3->change_cipher_spec=0; + } + if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY) + { + s->state=SSL3_ST_CW_CHANGE_A; + s->s3->change_cipher_spec=0; + } + + 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; + s->s3->change_cipher_spec=0; + break; + + case SSL3_ST_CW_CHANGE_A: + case SSL3_ST_CW_CHANGE_B: + ret=ssl3_send_change_cipher_spec(s, + SSL3_ST_CW_CHANGE_A,SSL3_ST_CW_CHANGE_B); + if (ret <= 0) goto end; + +#if 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; + goto end; + } + + if (!s->method->ssl3_enc->change_cipher_state(s, + SSL3_CHANGE_CIPHER_CLIENT_WRITE)) + { + ret= -1; + 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: + + 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; */ + + 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; +#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 + (!sess->session_id_length && !sess->tlsext_tick) || +#endif + (sess->not_resumable)) + { + if (!ssl_get_new_session(s,0)) + goto err; + } + /* else use the pre-loaded session */ + + p=s->s3->client_random; + + if (ssl_fill_hello_random(s, 0, p, SSL3_RANDOM_SIZE) <= 0) + goto err; + + /* Do the message type and length last */ + d=p= &(buf[4]); + + /* 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; + } + + /* 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)) == NULL) + { + SSLerr(SSL_F_SSL3_CLIENT_HELLO,ERR_R_INTERNAL_ERROR); + goto err; + } +#endif + + l=(p-d); + d=buf; + *(d++)=SSL3_MT_CLIENT_HELLO; + l2n3(l,d); + + s->state=SSL3_ST_CW_CLNT_HELLO_B; + /* number of bytes to write */ + s->init_num=p-buf; + s->init_off=0; + } + + /* SSL3_ST_CW_CLNT_HELLO_B */ + return(ssl3_do_write(s,SSL3_RT_HANDSHAKE)); +err: + return(-1); + } + +int ssl3_get_server_hello(SSL *s) + { + STACK_OF(SSL_CIPHER) *sk; + const SSL_CIPHER *c; + unsigned char *p,*d; + int i,al,ok; + unsigned int j; + long n; +#ifndef OPENSSL_NO_COMP + SSL_COMP *comp; +#endif + + 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_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER) + { + 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 ((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; + + /* 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 want to resume the session based on external pre-shared secret */ + if (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, + NULL, &pref_cipher, + s->tls_session_secret_cb_arg)) + { + s->session->cipher = pref_cipher ? + pref_cipher : ssl_get_cipher_by_char(s, p+j); + } + } +#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->s3->flags |= SSL3_FLAGS_CCS_OK; + s->hit=1; + } + else /* a miss or crap from the other end */ + { + /* If we were trying for session-id reuse, make a new + * SSL_SESSION so we don't stuff up other people */ + s->hit=0; + if (s->session->session_id_length > 0) + { + if (!ssl_get_new_session(s,0)) + { + al=SSL_AD_INTERNAL_ERROR; + 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; + } + /* TLS v1.2 only ciphersuites require v1.2 or later */ + if ((c->algorithm_ssl & SSL_TLSV1_2) && + (TLS1_get_version(s) < TLS1_2_VERSION)) + { + al=SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_WRONG_CIPHER_RETURNED); + goto f_err; + } + 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 TLS v1.2: we may need them for + * client authentication. + */ + if (TLS1_get_version(s) < TLS1_2_VERSION && !ssl3_digest_cached_records(s)) + { + al = SSL_AD_INTERNAL_ERROR; + 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) + { + al=SSL_AD_INTERNAL_ERROR; + 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 (s->version >= SSL3_VERSION) + { + if (!ssl_parse_serverhello_tlsext(s,&p,d,n, &al)) + { + /* 'al' set by ssl_parse_serverhello_tlsext */ + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_PARSE_TLSEXT); + goto f_err; + } + if (ssl_check_serverhello_tlsext(s) <= 0) + { + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_SERVERHELLO_TLSEXT); + goto err; + } + } +#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: + 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 + printf("pkey,x = %p, %p\n", pkey,x); + printf("ssl_cert_type(x,pkey) = %d\n", ssl_cert_type(x,pkey)); + printf("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) + { + 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: + 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,i,j,param_len,ok; + long 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 + + /* 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); + + if (s->s3->tmp.message_type != SSL3_MT_SERVER_KEY_EXCHANGE) + { +#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 (s->s3->tmp.new_cipher->algorithm_mkey & 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(); + } + + param_len=0; + alg_k=s->s3->tmp.new_cipher->algorithm_mkey; + alg_a=s->s3->tmp.new_cipher->algorithm_auth; + EVP_MD_CTX_init(&md_ctx); + +#ifndef OPENSSL_NO_PSK + if (alg_k & SSL_kPSK) + { + char tmp_id_hint[PSK_MAX_IDENTITY_LEN+1]; + + al=SSL_AD_HANDSHAKE_FAILURE; + n2s(p,i); + param_len=i+2; + /* 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) + { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, + SSL_R_DATA_LENGTH_TOO_LONG); + goto f_err; + } + if (param_len > n) + { + al=SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, + SSL_R_BAD_PSK_IDENTITY_HINT_LENGTH); + goto f_err; + } + /* If received PSK identity hint contains NULL + * characters, the hint is truncated from the first + * NULL. p may not be ending with NULL, so create a + * NULL-terminated string. */ + memcpy(tmp_id_hint, p, i); + memset(tmp_id_hint+i, 0, PSK_MAX_IDENTITY_LEN+1-i); + if (s->ctx->psk_identity_hint != NULL) + OPENSSL_free(s->ctx->psk_identity_hint); + s->ctx->psk_identity_hint = BUF_strdup(tmp_id_hint); + if (s->ctx->psk_identity_hint == NULL) + { + 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) + { + n2s(p,i); + param_len=i+2; + if (param_len > n) + { + al=SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SRP_N_LENGTH); + goto f_err; + } + 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; + + n2s(p,i); + param_len+=i+2; + if (param_len > n) + { + al=SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SRP_G_LENGTH); + goto f_err; + } + 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; + + i = (unsigned int)(p[0]); + p++; + param_len+=i+1; + if (param_len > n) + { + al=SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SRP_S_LENGTH); + goto f_err; + } + 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; + + n2s(p,i); + param_len+=i+2; + if (param_len > n) + { + al=SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SRP_B_LENGTH); + goto f_err; + } + 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; + +/* 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) + { + if ((rsa=RSA_new()) == NULL) + { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_MALLOC_FAILURE); + goto err; + } + n2s(p,i); + param_len=i+2; + if (param_len > n) + { + al=SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_RSA_MODULUS_LENGTH); + goto f_err; + } + if (!(rsa->n=BN_bin2bn(p,i,rsa->n))) + { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_BN_LIB); + goto err; + } + p+=i; + + n2s(p,i); + param_len+=i+2; + if (param_len > n) + { + al=SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_RSA_E_LENGTH); + goto f_err; + } + 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; + } + 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; + } + n2s(p,i); + param_len=i+2; + if (param_len > n) + { + al=SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_DH_P_LENGTH); + goto f_err; + } + if (!(dh->p=BN_bin2bn(p,i,NULL))) + { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_BN_LIB); + goto err; + } + p+=i; + + n2s(p,i); + param_len+=i+2; + if (param_len > n) + { + al=SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_DH_G_LENGTH); + goto f_err; + } + if (!(dh->g=BN_bin2bn(p,i,NULL))) + { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_BN_LIB); + goto err; + } + p+=i; + + n2s(p,i); + param_len+=i+2; + if (param_len > n) + { + al=SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_DH_PUB_KEY_LENGTH); + goto f_err; + } + 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; + +#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. + */ + param_len=3; + if ((param_len > n) || + (*p != NAMED_CURVE_TYPE) || + ((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; + param_len += (1 + encoded_pt_len); + if ((param_len > n) || + (EC_POINT_oct2point(group, srvr_ecpoint, + p, encoded_pt_len, bn_ctx) == 0)) + { + al=SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_ECPOINT); + goto f_err; + } + + 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 (TLS1_get_version(s) >= TLS1_2_VERSION) + { + int sigalg = tls12_get_sigid(pkey); + /* Should never happen */ + if (sigalg == -1) + { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR); + goto err; + } + /* Check key type is consistent with signature */ + if (sigalg != (int)p[1]) + { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_WRONG_SIGNATURE_TYPE); + al=SSL_AD_DECODE_ERROR; + goto f_err; + } + md = tls12_get_hash(p[0]); + if (md == NULL) + { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_UNKNOWN_DIGEST); + al=SSL_AD_DECODE_ERROR; + goto f_err; + } +#ifdef SSL_DEBUG +fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md)); +#endif + p += 2; + n -= 2; + } + else + md = EVP_sha1(); + + n2s(p,i); + n-=2; + j=EVP_PKEY_size(pkey); + + if ((i != n) || (n > j) || (n <= 0)) + { + /* wrong packet length */ + al=SSL_AD_DECODE_ERROR; + 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 && TLS1_get_version(s) < TLS1_2_VERSION) + { + int num; + + 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); + EVP_DigestInit_ex(&md_ctx,(num == 2) + ?s->ctx->md5:s->ctx->sha1, NULL); + EVP_DigestUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE); + EVP_DigestUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE); + EVP_DigestUpdate(&md_ctx,param,param_len); + EVP_DigestFinal_ex(&md_ctx,q,(unsigned int *)&i); + q+=i; + j+=i; + } + i=RSA_verify(NID_md5_sha1, md_buf, j, p, n, + pkey->pkey.rsa); + if (i < 0) + { + al=SSL_AD_DECRYPT_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_RSA_DECRYPT); + goto f_err; + } + if (i == 0) + { + /* bad signature */ + al=SSL_AD_DECRYPT_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SIGNATURE); + goto f_err; + } + } + else +#endif + { + EVP_VerifyInit_ex(&md_ctx, md, NULL); + EVP_VerifyUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE); + EVP_VerifyUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE); + EVP_VerifyUpdate(&md_ctx,param,param_len); + if (EVP_VerifyFinal(&md_ctx,p,(int)n,pkey) <= 0) + { + /* bad signature */ + al=SSL_AD_DECRYPT_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_BAD_SIGNATURE); + goto f_err; + } + } + } + else + { + if (!(alg_a & SSL_aNULL) && !(alg_k & SSL_kPSK)) + /* aNULL or kPSK do not need public keys */ + { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR); + goto err; + } + /* still data left over */ + if (n != 0) + { + al=SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,SSL_R_EXTRA_DATA_IN_MESSAGE); + goto f_err; + } + } + EVP_PKEY_free(pkey); + EVP_MD_CTX_cleanup(&md_ctx); + return(1); +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); + 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 (ctype_num > SSL3_CT_NUMBER) + ctype_num=SSL3_CT_NUMBER; + for (i=0; i<ctype_num; i++) + s->s3->tmp.ctype[i]= p[i]; + p+=ctype_num; + if (TLS1_get_version(s) >= TLS1_2_VERSION) + { + 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; + } + if ((llen & 1) || !tls1_process_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; + } + 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; + } + + 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; +err: + 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; + + n=s->method->ssl_get_message(s, + SSL3_ST_CR_SESSION_TICKET_A, + SSL3_ST_CR_SESSION_TICKET_B, + -1, + 16384, + &ok); + + if (!ok) + return((int)n); + + if (s->s3->tmp.message_type == SSL3_MT_FINISHED) + { + s->s3->tmp.reuse_message=1; + return(1); + } + if (s->s3->tmp.message_type != SSL3_MT_NEWSESSION_TICKET) + { + al=SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_BAD_MESSAGE_TYPE); + goto f_err; + } + if (n < 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, s->session->tlsext_tick_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; + } + 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_ticklen = ticklen; + /* There are two ways to detect a resumed ticket sesion. + * One is to set an appropriate session ID and then the server + * must return a match in ServerHello. This allows the normal + * client session ID matching to work and we know much + * earlier that the ticket has been accepted. + * + * The other way is to set zero length session ID when the + * ticket is presented and rely on the handshake to determine + * session resumption. + * + * We choose the former approach because this fits in with + * assumptions elsewhere in OpenSSL. The session ID is set + * to the SHA256 (or SHA1 is SHA256 is disabled) hash of the + * ticket. + */ + EVP_Digest(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: + 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, + SSL3_MT_CERTIFICATE_STATUS, + 16384, + &ok); + + if (!ok) return((int)n); + 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; + } + if (s->tlsext_ocsp_resp) + OPENSSL_free(s->tlsext_ocsp_resp); + s->tlsext_ocsp_resp = BUF_memdup(p, resplen); + if (!s->tlsext_ocsp_resp) + { + 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); + return(-1); + } +#endif + +int ssl3_get_server_done(SSL *s) + { + int ok,ret=0; + long n; + + n=s->method->ssl_get_message(s, + SSL3_ST_CR_SRVR_DONE_A, + SSL3_ST_CR_SRVR_DONE_B, + SSL3_MT_SERVER_DONE, + 30, /* should be very small, like 0 :-) */ + &ok); + + if (!ok) return((int)n); + if (n > 0) + { + /* should contain no data */ + ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECODE_ERROR); + SSLerr(SSL_F_SSL3_GET_SERVER_DONE,SSL_R_LENGTH_MISMATCH); + return -1; + } + ret=1; + return(ret); + } + + +int ssl3_send_client_key_exchange(SSL *s) + { + unsigned char *p,*d; + 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) + { + d=(unsigned char *)s->init_buf->data; + p= &(d[4]); + + 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->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); + 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 + printf("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 + { + printf("kssl_cget_tkt rtn %d\n", krb5rc); + if (krb5rc && kssl_err.text) + printf("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; + + 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; + } + + if (s->session->sess_cert->peer_dh_tmp != NULL) + dh_srvr=s->session->sess_cert->peer_dh_tmp; + else + { + /* we get them from the cert */ + ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE); + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,SSL_R_UNABLE_TO_FIND_DH_PARAMETERS); + goto err; + } + + /* 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 (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); + + /* 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); + + /* perhaps clean things up a bit EAY EAY EAY EAY*/ + } +#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 we have send a certificate, and certificate key + + * parameters match those of server certificate, use + * certificate key for key exchange + */ + + /* Otherwise, generate ephemeral key pair */ + + EVP_PKEY_encrypt_init(pkey_ctx); + /* Generate session key */ + RAND_bytes(premaster_secret,32); + /* 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(); + EVP_DigestInit(ukm_hash,EVP_get_digestbynid(NID_id_GostR3411_94)); + EVP_DigestUpdate(ukm_hash,s->s3->client_random,SSL3_RANDOM_SIZE); + EVP_DigestUpdate(ukm_hash,s->s3->server_random,SSL3_RANDOM_SIZE); + EVP_DigestFinal_ex(ukm_hash, shared_ukm, &md_len); + EVP_MD_CTX_destroy(ukm_hash); + if (EVP_PKEY_CTX_ctrl(pkey_ctx,-1,EVP_PKEY_OP_ENCRYPT,EVP_PKEY_CTRL_SET_IV, + 8,shared_ukm)<0) { + SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, + SSL_R_LIBRARY_BUG); + goto err; + } + /* Make GOST keytransport blob message */ + /*Encapsulate it into sequence */ + *(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) + { + char identity[PSK_MAX_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; + } + + psk_len = s->psk_client_callback(s, s->ctx->psk_identity_hint, + identity, PSK_MAX_IDENTITY_LEN, + 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; + } + + /* 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); + n = strlen(identity); + s2n(n, p); + memcpy(p, identity, n); + n+=2; + psk_err = 0; + psk_err: + OPENSSL_cleanse(identity, PSK_MAX_IDENTITY_LEN); + 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; + } + + *(d++)=SSL3_MT_CLIENT_KEY_EXCHANGE; + l2n3(n,d); + + s->state=SSL3_ST_CW_KEY_EXCH_B; + /* number of bytes to write */ + s->init_num=n+4; + s->init_off=0; + } + + /* SSL3_ST_CW_KEY_EXCH_B */ + return(ssl3_do_write(s,SSL3_RT_HANDSHAKE)); +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 + return(-1); + } + +int ssl3_send_client_verify(SSL *s) + { + unsigned char *p,*d; + 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) + { + d=(unsigned char *)s->init_buf->data; + p= &(d[4]); + pkey=s->cert->key->privatekey; +/* Create context from key and test if sha1 is allowed as digest */ + pctx = EVP_PKEY_CTX_new(pkey,NULL); + EVP_PKEY_sign_init(pctx); + if (EVP_PKEY_CTX_set_signature_md(pctx, EVP_sha1())>0) + { + if (TLS1_get_version(s) < TLS1_2_VERSION) + 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 (TLS1_get_version(s) >= TLS1_2_VERSION) + { + 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; + } + *(d++)=SSL3_MT_CERTIFICATE_VERIFY; + l2n3(n,d); + + s->state=SSL3_ST_CW_CERT_VRFY_B; + s->init_num=(int)n+4; + s->init_off=0; + } + EVP_MD_CTX_cleanup(&mctx); + EVP_PKEY_CTX_free(pctx); + return(ssl3_do_write(s,SSL3_RT_HANDSHAKE)); +err: + EVP_MD_CTX_cleanup(&mctx); + EVP_PKEY_CTX_free(pctx); + return(-1); + } + +int ssl3_send_client_certificate(SSL *s) + { + X509 *x509=NULL; + EVP_PKEY *pkey=NULL; + int i; + unsigned long l; + + if (s->state == SSL3_ST_CW_CERT_A) + { + if ((s->cert == NULL) || + (s->cert->key->x509 == NULL) || + (s->cert->key->privatekey == NULL)) + s->state=SSL3_ST_CW_CERT_B; + else + s->state=SSL3_ST_CW_CERT_C; + } + + /* 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=0; + 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 == 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; + l=ssl3_output_cert_chain(s, + (s->s3->tmp.cert_req == 2)?NULL:s->cert->key->x509); + s->init_num=(int)l; + s->init_off=0; + } + /* SSL3_ST_CW_CERT_D */ + return(ssl3_do_write(s,SSL3_RT_HANDSHAKE)); + } + +#define has_bits(i,m) (((i)&(m)) == (m)) + +int ssl3_check_cert_and_algorithm(SSL *s) + { + int i,idx; + long alg_k,alg_a; + EVP_PKEY *pkey=NULL; + SESS_CERT *sc; +#ifndef OPENSSL_NO_RSA + RSA *rsa; +#endif +#ifndef OPENSSL_NO_DH + DH *dh; +#endif + + 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_aDH|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; + } + } +#endif + pkey=X509_get_pubkey(sc->peer_pkeys[idx].x509); + i=X509_certificate_type(sc->peer_pkeys[idx].x509,pkey); + EVP_PKEY_free(pkey); + + + /* Check that we have a certificate if we require one */ + if ((alg_a & SSL_aRSA) && !has_bits(i,EVP_PK_RSA|EVP_PKT_SIGN)) + { + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_RSA_SIGNING_CERT); + goto f_err; + } +#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) && + !(has_bits(i,EVP_PK_RSA|EVP_PKT_ENC) || (rsa != NULL))) + { + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_RSA_ENCRYPTING_CERT); + goto f_err; + } +#endif +#ifndef OPENSSL_NO_DH + if ((alg_k & SSL_kEDH) && + !(has_bits(i,EVP_PK_DH|EVP_PKT_EXCH) || (dh != NULL))) + { + SSLerr(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM,SSL_R_MISSING_DH_KEY); + goto f_err; + } + else if ((alg_k & SSL_kDHr) && !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 + else if ((alg_k & SSL_kDHd) && !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 +#endif + + if (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher) && !has_bits(i,EVP_PKT_EXP)) + { +#ifndef OPENSSL_NO_RSA + if (alg_k & SSL_kRSA) + { + if (rsa == NULL + || RSA_size(rsa)*8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) + { + 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_kEDH|SSL_kDHr|SSL_kDHd)) + { + if (dh == NULL + || DH_size(dh)*8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)) + { + 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,SSL_AD_HANDSHAKE_FAILURE); +err: + return(0); + } + +#if !defined(OPENSSL_NO_TLSEXT) && !defined(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_TLSEXT && !OPENSSL_NO_NEXTPROTONEG */ + +/* Check to see if handshake is full or resumed. Usually this is just a + * case of checking to see if a cache hit has occurred. In the case of + * session tickets we have to check the next message to be sure. + */ + +#ifndef OPENSSL_NO_TLSEXT +int ssl3_check_finished(SSL *s) + { + int ok; + long n; + /* If we have no ticket it cannot be a resumed session. */ + if (!s->session->tlsext_tick) + return 1; + /* this function is called when we really expect a Certificate + * message, so permit appropriate message length */ + n=s->method->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); + s->s3->tmp.reuse_message = 1; + if ((s->s3->tmp.message_type == SSL3_MT_FINISHED) + || (s->s3->tmp.message_type == SSL3_MT_NEWSESSION_TICKET)) + return 2; + + return 1; + } +#endif + +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/drivers/builtin_openssl2/ssl/s3_enc.c b/drivers/builtin_openssl2/ssl/s3_enc.c new file mode 100644 index 0000000000..e3cd4f062c --- /dev/null +++ b/drivers/builtin_openssl2/ssl/s3_enc.c @@ -0,0 +1,898 @@ +/* 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; + + ssl_replace_hash(&s->read_hash,m); +#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; + ssl_replace_hash(&s->write_hash,m); +#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)); + + 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 */ + } + + EVP_Cipher(ds,rec->data,rec->input,l); + + 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; + ret=ssl3_handshake_mac(s,NID_md5,sender,len,p); + p+=ret; + ret+=ssl3_handshake_mac(s,NID_sha1,sender,len,p); + 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); + EVP_DigestUpdate(&ctx,s->session->master_key, + s->session->master_key_length); + EVP_DigestUpdate(&ctx,ssl3_pad_1,npad); + EVP_DigestFinal_ex(&ctx,md_buf,&i); + + EVP_DigestInit_ex(&ctx,EVP_MD_CTX_md(&ctx), NULL); + EVP_DigestUpdate(&ctx,s->session->master_key, + s->session->master_key_length); + EVP_DigestUpdate(&ctx,ssl3_pad_2,npad); + EVP_DigestUpdate(&ctx,md_buf,i); + EVP_DigestFinal_ex(&ctx,p,&ret); + + 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; + + ssl3_cbc_digest_record( + hash, + md, &md_size, + header, rec->input, + rec->length + md_size, orig_len, + mac_sec, md_size, + 1 /* is SSLv3 */); + } + else + { + unsigned int md_size_u; + /* Chop the digest off the end :-) */ + EVP_MD_CTX_init(&md_ctx); + + EVP_MD_CTX_copy_ex( &md_ctx,hash); + EVP_DigestUpdate(&md_ctx,mac_sec,md_size); + EVP_DigestUpdate(&md_ctx,ssl3_pad_1,npad); + EVP_DigestUpdate(&md_ctx,seq,8); + rec_char=rec->type; + EVP_DigestUpdate(&md_ctx,&rec_char,1); + p=md; + s2n(rec->length,p); + EVP_DigestUpdate(&md_ctx,md,2); + EVP_DigestUpdate(&md_ctx,rec->input,rec->length); + EVP_DigestFinal_ex( &md_ctx,md,NULL); + + EVP_MD_CTX_copy_ex( &md_ctx,hash); + EVP_DigestUpdate(&md_ctx,mac_sec,md_size); + EVP_DigestUpdate(&md_ctx,ssl3_pad_2,npad); + EVP_DigestUpdate(&md_ctx,md,md_size); + EVP_DigestFinal_ex( &md_ctx,md,&md_size_u); + 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; + + EVP_MD_CTX_init(&ctx); + for (i=0; i<3; i++) + { + EVP_DigestInit_ex(&ctx,s->ctx->sha1, NULL); + EVP_DigestUpdate(&ctx,salt[i],strlen((const char *)salt[i])); + EVP_DigestUpdate(&ctx,p,len); + EVP_DigestUpdate(&ctx,&(s->s3->client_random[0]), + SSL3_RANDOM_SIZE); + EVP_DigestUpdate(&ctx,&(s->s3->server_random[0]), + SSL3_RANDOM_SIZE); + EVP_DigestFinal_ex(&ctx,buf,&n); + + EVP_DigestInit_ex(&ctx,s->ctx->md5, NULL); + EVP_DigestUpdate(&ctx,p,len); + EVP_DigestUpdate(&ctx,buf,n); + EVP_DigestFinal_ex(&ctx,out,&n); + out+=n; + ret+=n; + } + EVP_MD_CTX_cleanup(&ctx); + 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); + default: return(-1); + } + } + diff --git a/drivers/builtin_openssl2/ssl/s3_lib.c b/drivers/builtin_openssl2/ssl/s3_lib.c new file mode 100644 index 0000000000..c4ef2738d7 --- /dev/null +++ b/drivers/builtin_openssl2/ssl/s3_lib.c @@ -0,0 +1,4294 @@ +/* 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" +#ifndef OPENSSL_NO_TLSEXT +#ifndef OPENSSL_NO_EC +#include "../crypto/ec/ec_lcl.h" +#endif /* OPENSSL_NO_EC */ +#endif /* OPENSSL_NO_TLSEXT */ +#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 */ + { + 1, + SSL3_TXT_RSA_RC4_40_MD5, + SSL3_CK_RSA_RC4_40_MD5, + SSL_kRSA, + SSL_aRSA, + SSL_RC4, + SSL_MD5, + SSL_SSLV3, + SSL_EXPORT|SSL_EXP40, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 40, + 128, + }, + +/* 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 */ + { + 1, + SSL3_TXT_RSA_RC2_40_MD5, + SSL3_CK_RSA_RC2_40_MD5, + SSL_kRSA, + SSL_aRSA, + SSL_RC2, + SSL_MD5, + SSL_SSLV3, + SSL_EXPORT|SSL_EXP40, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 40, + 128, + }, + +/* 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 */ + { + 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_EXPORT|SSL_EXP40, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 40, + 56, + }, + +/* Cipher 09 */ + { + 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_EXP|SSL_LOW, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 56, + 56, + }, + +/* 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, + 168, + 168, + }, + +/* The DH ciphers */ +/* Cipher 0B */ + { + 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_EXPORT|SSL_EXP40, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 40, + 56, + }, + +/* Cipher 0C */ + { + 0, /* not implemented (non-ephemeral DH) */ + 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_EXP|SSL_LOW, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 56, + 56, + }, + +/* Cipher 0D */ + { + 0, /* not implemented (non-ephemeral DH) */ + 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, + 168, + 168, + }, + +/* Cipher 0E */ + { + 0, /* not implemented (non-ephemeral DH) */ + 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_EXPORT|SSL_EXP40, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 40, + 56, + }, + +/* Cipher 0F */ + { + 0, /* not implemented (non-ephemeral DH) */ + 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_EXP|SSL_LOW, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 56, + 56, + }, + +/* Cipher 10 */ + { + 0, /* not implemented (non-ephemeral DH) */ + 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, + 168, + 168, + }, + +/* The Ephemeral DH ciphers */ +/* Cipher 11 */ + { + 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_EXPORT|SSL_EXP40, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 40, + 56, + }, + +/* Cipher 12 */ + { + 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_EXP|SSL_LOW, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 56, + 56, + }, + +/* 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, + 168, + 168, + }, + +/* Cipher 14 */ + { + 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_EXPORT|SSL_EXP40, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 40, + 56, + }, + +/* Cipher 15 */ + { + 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_EXP|SSL_LOW, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 56, + 56, + }, + +/* 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, + 168, + 168, + }, + +/* Cipher 17 */ + { + 1, + SSL3_TXT_ADH_RC4_40_MD5, + SSL3_CK_ADH_RC4_40_MD5, + SSL_kEDH, + SSL_aNULL, + SSL_RC4, + SSL_MD5, + SSL_SSLV3, + SSL_EXPORT|SSL_EXP40, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 40, + 128, + }, + +/* 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_EXP|SSL_MEDIUM, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 128, + 128, + }, + +/* Cipher 19 */ + { + 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_EXPORT|SSL_EXP40, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 40, + 128, + }, + +/* Cipher 1A */ + { + 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_EXP|SSL_LOW, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 56, + 56, + }, + +/* 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_EXP|SSL_HIGH|SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 168, + 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 */ + { + 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_EXP|SSL_LOW, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 56, + 56, + }, + +/* 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, + 168, + 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 */ + { + 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_EXP|SSL_LOW, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 56, + 56, + }, + +/* 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, + 168, + 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 */ + { + 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_EXPORT|SSL_EXP40, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 40, + 56, + }, + +/* Cipher 27 */ + { + 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_EXPORT|SSL_EXP40, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 40, + 128, + }, + +/* Cipher 28 */ + { + 1, + SSL3_TXT_KRB5_RC4_40_SHA, + SSL3_CK_KRB5_RC4_40_SHA, + SSL_kKRB5, + SSL_aKRB5, + SSL_RC4, + SSL_SHA1, + SSL_SSLV3, + SSL_EXPORT|SSL_EXP40, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 40, + 128, + }, + +/* Cipher 29 */ + { + 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_EXPORT|SSL_EXP40, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 40, + 56, + }, + +/* Cipher 2A */ + { + 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_EXPORT|SSL_EXP40, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 40, + 128, + }, + +/* Cipher 2B */ + { + 1, + SSL3_TXT_KRB5_RC4_40_MD5, + SSL3_CK_KRB5_RC4_40_MD5, + SSL_kKRB5, + SSL_aKRB5, + SSL_RC4, + SSL_MD5, + SSL_SSLV3, + SSL_EXPORT|SSL_EXP40, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 40, + 128, + }, +#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 */ + { + 0, + 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 */ + { + 0, + 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_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 */ + { + 0, + 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 */ + { + 0, /* not implemented (non-ephemeral DH) */ + 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_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 */ + { + 0, /* not implemented (non-ephemeral DH) */ + 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 */ + { + 0, /* not implemented (non-ephemeral DH) */ + 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 */ + { + 0, /* not implemented (non-ephemeral DH) */ + 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 */ + { + 0, /* not implemented (non-ephemeral DH) */ + 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_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_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_EXPORT|SSL_EXP56, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 56, + 128, + }, +#endif + + /* Cipher 62 */ + { + 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_EXPORT|SSL_EXP56, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 56, + 56, + }, + + /* Cipher 63 */ + { + 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_EXPORT|SSL_EXP56, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 56, + 56, + }, + + /* Cipher 64 */ + { + 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_EXPORT|SSL_EXP56, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 56, + 128, + }, + + /* Cipher 65 */ + { + 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_EXPORT|SSL_EXP56, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 56, + 128, + }, + + /* 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 */ + { + 0, /* not implemented (non-ephemeral DH) */ + 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 */ + { + 0, /* not implemented (non-ephemeral DH) */ + 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_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_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 */ + { + 0, /* not implemented (non-ephemeral DH) */ + 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 */ + { + 0, /* not implemented (non-ephemeral DH) */ + 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_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, + 168, + 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 */ + { + 0, /* not implemented (non-ephemeral DH) */ + 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 */ + { + 0, /* not implemented (non-ephemeral DH) */ + 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_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 */ + { + 0, + 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 */ + { + 0, + 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 */ + { + 0, + 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 */ + { + 0, + 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_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_EXP|SSL_HIGH|SSL_FIPS, + SSL_HANDSHAKE_MAC_SHA384|TLS1_PRF_SHA384, + 256, + 256, + }, + +#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, + 168, + 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, + 168, + 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, + 168, + 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, + 168, + 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_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_EXP|SSL_HIGH|SSL_FIPS, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 168, + 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_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_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_aNULL, + SSL_3DES, + SSL_SHA1, + SSL_TLSV1, + SSL_NOT_EXP|SSL_HIGH, + SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 168, + 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, + 168, + 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, + 168, + 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_aNULL, + 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_aNULL, + 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, + }; + +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; + } + +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) + 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_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); + } + 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 + +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->options & SSL_OP_SINGLE_DH_USE)) + { + if (!DH_generate_key(dh)) + { + DH_free(dh); + 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) + { + if (s->tlsext_hostname != NULL) + OPENSSL_free(s->tlsext_hostname); + s->tlsext_hostname = NULL; + + ret = 1; + if (parg == NULL) + break; + if (strlen((char *)parg) > 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_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER) + 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 */ + 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 (!(ctx->options & SSL_OP_SINGLE_DH_USE)) + { + if (!DH_generate_key(new)) + { + SSLerr(SSL_F_SSL3_CTX_CTRL,ERR_R_DH_LIB); + DH_free(new); + 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 +#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: + *(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; + + 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 + if (cp == NULL || cp->valid == 0) + return NULL; + else + 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; +#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_EC) + unsigned int j; + int ec_ok, ec_nid; + unsigned char ec_search1 = 0, ec_search2 = 0; +#endif + 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 + printf("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); + printf("%p:%s\n",(void *)c,c->name); + } + printf("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); + printf("%p:%s\n",(void *)c,c->name); + } +#endif + + if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE) + { + prio = srvr; + allow = clnt; + } + else + { + prio = clnt; + allow = srvr; + } + + for (i=0; i<sk_SSL_CIPHER_num(prio); i++) + { + c=sk_SSL_CIPHER_value(prio,i); + + /* Skip TLS v1.2 only ciphersuites if lower than v1.2 */ + if ((c->algorithm_ssl & SSL_TLSV1_2) && + (TLS1_get_version(s) < TLS1_2_VERSION)) + 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 + mask_k=cert->mask_k | s->srp_ctx.srp_Mask; + emask_k=cert->export_mask_k | s->srp_ctx.srp_Mask; +#endif + +#ifdef KSSL_DEBUG +/* printf("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 + printf("%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 + printf("%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 + if ( + /* if we are considering an ECC cipher suite that uses our certificate */ + (alg_a & SSL_aECDSA || alg_a & SSL_aECDH) + /* and we have an ECC certificate */ + && (s->cert->pkeys[SSL_PKEY_ECC].x509 != NULL) + /* and the client specified a Supported Point Formats extension */ + && ((s->session->tlsext_ecpointformatlist_length > 0) && (s->session->tlsext_ecpointformatlist != NULL)) + /* and our certificate's point is compressed */ + && ( + (s->cert->pkeys[SSL_PKEY_ECC].x509->cert_info != NULL) + && (s->cert->pkeys[SSL_PKEY_ECC].x509->cert_info->key != NULL) + && (s->cert->pkeys[SSL_PKEY_ECC].x509->cert_info->key->public_key != NULL) + && (s->cert->pkeys[SSL_PKEY_ECC].x509->cert_info->key->public_key->data != NULL) + && ( + (*(s->cert->pkeys[SSL_PKEY_ECC].x509->cert_info->key->public_key->data) == POINT_CONVERSION_COMPRESSED) + || (*(s->cert->pkeys[SSL_PKEY_ECC].x509->cert_info->key->public_key->data) == POINT_CONVERSION_COMPRESSED + 1) + ) + ) + ) + { + ec_ok = 0; + /* if our certificate's curve is over a field type that the client does not support + * then do not allow this cipher suite to be negotiated */ + if ( + (s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec != NULL) + && (s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec->group != NULL) + && (s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec->group->meth != NULL) + && (EC_METHOD_get_field_type(s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec->group->meth) == NID_X9_62_prime_field) + ) + { + for (j = 0; j < s->session->tlsext_ecpointformatlist_length; j++) + { + if (s->session->tlsext_ecpointformatlist[j] == TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime) + { + ec_ok = 1; + break; + } + } + } + else if (EC_METHOD_get_field_type(s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec->group->meth) == NID_X9_62_characteristic_two_field) + { + for (j = 0; j < s->session->tlsext_ecpointformatlist_length; j++) + { + if (s->session->tlsext_ecpointformatlist[j] == TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2) + { + ec_ok = 1; + break; + } + } + } + ok = ok && ec_ok; + } + if ( + /* if we are considering an ECC cipher suite that uses our certificate */ + (alg_a & SSL_aECDSA || alg_a & SSL_aECDH) + /* and we have an ECC certificate */ + && (s->cert->pkeys[SSL_PKEY_ECC].x509 != NULL) + /* and the client specified an EllipticCurves extension */ + && ((s->session->tlsext_ellipticcurvelist_length > 0) && (s->session->tlsext_ellipticcurvelist != NULL)) + ) + { + ec_ok = 0; + if ( + (s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec != NULL) + && (s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec->group != NULL) + ) + { + ec_nid = EC_GROUP_get_curve_name(s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec->group); + if ((ec_nid == 0) + && (s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec->group->meth != NULL) + ) + { + if (EC_METHOD_get_field_type(s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec->group->meth) == NID_X9_62_prime_field) + { + ec_search1 = 0xFF; + ec_search2 = 0x01; + } + else if (EC_METHOD_get_field_type(s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec->group->meth) == NID_X9_62_characteristic_two_field) + { + ec_search1 = 0xFF; + ec_search2 = 0x02; + } + } + else + { + ec_search1 = 0x00; + ec_search2 = tls1_ec_nid2curve_id(ec_nid); + } + if ((ec_search1 != 0) || (ec_search2 != 0)) + { + for (j = 0; j < s->session->tlsext_ellipticcurvelist_length / 2; j++) + { + if ((s->session->tlsext_ellipticcurvelist[2*j] == ec_search1) && (s->session->tlsext_ellipticcurvelist[2*j+1] == ec_search2)) + { + ec_ok = 1; + break; + } + } + } + } + ok = ok && ec_ok; + } + if ( + /* if we are considering an ECC cipher suite that uses an ephemeral EC key */ + (alg_k & SSL_kEECDH) + /* and we have an ephemeral EC key */ + && (s->cert->ecdh_tmp != NULL) + /* and the client specified an EllipticCurves extension */ + && ((s->session->tlsext_ellipticcurvelist_length > 0) && (s->session->tlsext_ellipticcurvelist != NULL)) + ) + { + ec_ok = 0; + if (s->cert->ecdh_tmp->group != NULL) + { + ec_nid = EC_GROUP_get_curve_name(s->cert->ecdh_tmp->group); + if ((ec_nid == 0) + && (s->cert->ecdh_tmp->group->meth != NULL) + ) + { + if (EC_METHOD_get_field_type(s->cert->ecdh_tmp->group->meth) == NID_X9_62_prime_field) + { + ec_search1 = 0xFF; + ec_search2 = 0x01; + } + else if (EC_METHOD_get_field_type(s->cert->ecdh_tmp->group->meth) == NID_X9_62_characteristic_two_field) + { + ec_search1 = 0xFF; + ec_search2 = 0x02; + } + } + else + { + ec_search1 = 0x00; + ec_search2 = tls1_ec_nid2curve_id(ec_nid); + } + if ((ec_search1 != 0) || (ec_search2 != 0)) + { + for (j = 0; j < s->session->tlsext_ellipticcurvelist_length / 2; j++) + { + if ((s->session->tlsext_ellipticcurvelist[2*j] == ec_search1) && (s->session->tlsext_ellipticcurvelist[2*j+1] == ec_search2)) + { + ec_ok = 1; + break; + } + } + } + } + ok = ok && ec_ok; + } +#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; + unsigned long alg_k; + + 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 + p[ret++]=SSL3_CT_RSA_FIXED_DH; +# endif +# ifndef OPENSSL_NO_DSA + 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 + p[ret++]=SSL3_CT_RSA_SIGN; +#endif +#ifndef OPENSSL_NO_DSA + p[ret++]=SSL3_CT_DSS_SIGN; +#endif +#ifndef OPENSSL_NO_ECDH + if ((alg_k & (SSL_kECDHr|SSL_kECDHe)) && (s->version >= TLS1_VERSION)) + { + p[ret++]=TLS_CT_RSA_FIXED_ECDH; + 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) + { + p[ret++]=TLS_CT_ECDSA_SIGN; + } +#endif + return(ret); + } + +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 TLS v1.2 or later and default SHA1+MD5 algorithms switch + * to new SHA256 PRF and handshake macs + */ +long ssl_get_algorithm2(SSL *s) + { + long alg2 = s->s3->tmp.new_cipher->algorithm2; + if (s->method->version == TLS1_2_VERSION && + alg2 == (SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF)) + return SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256; + return alg2; + } + diff --git a/drivers/builtin_openssl2/ssl/s3_meth.c b/drivers/builtin_openssl2/ssl/s3_meth.c new file mode 100644 index 0000000000..cdddb17b62 --- /dev/null +++ b/drivers/builtin_openssl2/ssl/s3_meth.c @@ -0,0 +1,77 @@ +/* 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" + +static const SSL_METHOD *ssl3_get_method(int ver); +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) + + diff --git a/drivers/builtin_openssl2/ssl/s3_pkt.c b/drivers/builtin_openssl2/ssl/s3_pkt.c new file mode 100644 index 0000000000..59011e39c6 --- /dev/null +++ b/drivers/builtin_openssl2/ssl/s3_pkt.c @@ -0,0 +1,1557 @@ +/* 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> + +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_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER) + { + 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; + } + + if (!s->read_ahead) + /* ignore max parameter */ + max = n; + else + { + if (max < n) + max = n; + if (max > (int)(rb->len - rb->offset)) + max = rb->len - rb->offset; + } + + while (left < n) + { + /* Now we have len+left bytes at the front of s->s3->rbuf.buf + * and need to read in more until we have len+n (up to + * len+max if possible) */ + + 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_version(s) != DTLS1_VERSION && SSL_version(s) != DTLS1_BAD_VER) + 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_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER) + { + 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); + } + +/* 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; + + 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; + + /* 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) + /* 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) 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_; + unsigned int n,nw; + int i,tot; + + 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); + } + + + 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) + { + 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; + + 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 and TLS version 1.1 or later */ + if (s->enc_write_ctx && s->version >= TLS1_1_VERSION) + { + 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; + } + + /* ssl3_enc can only have an error on read */ + s->method->ssl3_enc->enc(s,1); + + /* record length after mac and block padding */ + s2n(wr->length,plen); + + /* we should now have + * wr->data pointing to the encrypted data, which is + * wr->length long */ + wr->type=type; /* not needed but helps for debugging */ + wr->length+=SSL3_RT_HEADER_LENGTH; + + if (create_empty_fragment) + { + /* we are in a recursive call; + * just return the length, don't write out anything here + */ + return wr->length; + } + + /* now let's set up wb */ + wb->left = prefix_len + wr->length; + + /* memorize arguments so that ssl3_write_pending can detect bad write retries later */ + 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; + if (s->mode & SSL_MODE_RELEASE_BUFFERS && + SSL_version(s) != DTLS1_VERSION && SSL_version(s) != DTLS1_BAD_VER) + ssl3_release_write_buffer(s); + s->rwstate=SSL_NOTHING; + return(s->s3->wpend_ret); + } + else if (i <= 0) { + if (s->version == DTLS1_VERSION || + s->version == DTLS1_BAD_VER) { + /* 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) && type) || + (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 == 1) /* 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 == 2) /* 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/drivers/builtin_openssl2/ssl/s3_srvr.c b/drivers/builtin_openssl2/ssl/s3_srvr.c new file mode 100644 index 0000000000..503bed3fe0 --- /dev/null +++ b/drivers/builtin_openssl2/ssl/s3_srvr.c @@ -0,0 +1,3594 @@ +/* ssl/s3_srvr.c -*- mode:C; c-file-style: "eay" -*- */ +/* 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 <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> + +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); + } + +#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 + +IMPLEMENT_ssl3_meth_func(SSLv3_server_method, + ssl3_accept, + ssl_undefined_function, + ssl3_get_server_method) + +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); + return -1; + } + 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)) + { + ret= -1; + goto end; + } + s->init_buf=buf; + } + + if (!ssl3_setup_buffers(s)) + { + ret= -1; + goto end; + } + + s->init_num=0; + s->s3->flags &= ~SSL3_FLAGS_SGC_RESTART_DONE; + + 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; 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; + 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; + if (s->rwstate != SSL_X509_LOOKUP) + { + ret=ssl3_get_client_hello(s); + if (ret <= 0) goto end; + } +#ifndef OPENSSL_NO_SRP + { + 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 = SSL_TLSEXT_ERR_ALERT_FATAL; + ret= -1; + 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) + && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_kPSK) + && !(s->s3->tmp.new_cipher->algorithm_auth & SSL_aKRB5)) + { + 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 */ + if ((s->options & SSL_OP_EPHEMERAL_RSA) +#ifndef OPENSSL_NO_KRB5 + && !(alg_k & SSL_kKRB5) +#endif /* OPENSSL_NO_KRB5 */ + ) + /* option SSL_OP_EPHEMERAL_RSA sends temporary RSA key + * even when forbidden by protocol specs + * (handshake may fail as clients are not required to + * be able to handle this) */ + s->s3->tmp.use_rsa_tmp=1; + else + 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 (s->s3->tmp.use_rsa_tmp + /* 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_kDHr|SSL_kDHd|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) + /* 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)) + 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: + /* Check for second client hello (MS SGC) */ + ret = ssl3_check_client_hello(s); + if (ret <= 0) + goto end; + if (ret == 2) + s->state = SSL3_ST_SR_CLNT_HELLO_C; + else { + 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 (TLS1_get_version(s) >= TLS1_2_VERSION) + { + s->state=SSL3_ST_SR_CERT_VRFY_A; + s->init_num=0; + if (!s->session->peer) + break; + /* For TLS v1.2 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); + return -1; + } + s->s3->flags |= TLS1_FLAGS_KEEP_HANDSHAKE; + if (!ssl3_digest_cached_records(s)) + 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)) + 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) + { + ret = -1; + goto end; + } + offset+=dgst_size; + } + } + break; + + case SSL3_ST_SR_CERT_VRFY_A: + case SSL3_ST_SR_CERT_VRFY_B: + + s->s3->flags |= SSL3_FLAGS_CCS_OK; + /* we should decide if we expected this one */ + ret=ssl3_get_cert_verify(s); + if (ret <= 0) goto end; + +#if 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: + 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: + 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; 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; + 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->flags |= SSL3_FLAGS_CCS_OK; + 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; */ + + 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) + { + unsigned char *p; + + if (s->state == SSL3_ST_SW_HELLO_REQ_A) + { + p=(unsigned char *)s->init_buf->data; + *(p++)=SSL3_MT_HELLO_REQUEST; + *(p++)=0; + *(p++)=0; + *(p++)=0; + + s->state=SSL3_ST_SW_HELLO_REQ_B; + /* number of bytes to write */ + s->init_num=4; + s->init_off=0; + } + + /* SSL3_ST_SW_HELLO_REQ_B */ + return(ssl3_do_write(s,SSL3_RT_HANDSHAKE)); + } + +int ssl3_check_client_hello(SSL *s) + { + int ok; + long n; + + /* this function is called when we really expect a Certificate message, + * so permit appropriate message length */ + 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); + s->s3->tmp.reuse_message = 1; + if (s->s3->tmp.message_type == SSL3_MT_CLIENT_HELLO) + { + /* We only allow the client to restart the handshake once per + * negotiation. */ + if (s->s3->flags & SSL3_FLAGS_SGC_RESTART_DONE) + { + SSLerr(SSL_F_SSL3_CHECK_CLIENT_HELLO, SSL_R_MULTIPLE_SGC_RESTARTS); + return -1; + } + /* Throw away what we have done so far in the current handshake, + * which will now be aborted. (A full SSL_clear would be too much.) */ +#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 + s->s3->flags |= SSL3_FLAGS_SGC_RESTART_DONE; + return 2; + } + return 1; +} + +int ssl3_get_client_hello(SSL *s) + { + int i,j,ok,al,ret= -1; + unsigned int cookie_len; + long n; + unsigned long id; + unsigned char *p,*d,*q; + SSL_CIPHER *c; +#ifndef OPENSSL_NO_COMP + SSL_COMP *comp=NULL; +#endif + STACK_OF(SSL_CIPHER) *ciphers=NULL; + + /* 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; + + /* 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 ((s->version == DTLS1_VERSION && s->client_version > s->version) || + (s->version != DTLS1_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); + 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++); + + 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); + if (i == 1) + { /* 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 (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER) + { + /* cookie stuff */ + cookie_len = *(p++); + + /* + * The ClientHello may contain a cookie even if the + * HelloVerify message has not been sent--make sure that it + * does not cause an overflow. + */ + if ( cookie_len > sizeof(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 */ + } + else if ( memcmp(s->d1->rcvd_cookie, s->d1->cookie, + s->d1->cookie_len) != 0) /* default verification */ + { + al=SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, + SSL_R_COOKIE_MISMATCH); + goto f_err; + } + + ret = 2; + } + + p += cookie_len; + } + + n2s(p,i); + if ((i == 0) && (j != 0)) + { + /* we need a cipher if we are not resuming a session */ + al=SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_CIPHERS_SPECIFIED); + goto f_err; + } + if ((p+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; + } + if ((i > 0) && (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) && (i > 0)) + { + j=0; + id=s->session->cipher->id; + +#ifdef CIPHER_DEBUG + printf("client sent %d ciphers\n",sk_num(ciphers)); +#endif + for (i=0; i<sk_SSL_CIPHER_num(ciphers); i++) + { + c=sk_SSL_CIPHER_value(ciphers,i); +#ifdef CIPHER_DEBUG + printf("client [%2d of %2d]:%s\n", + i,sk_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; + } + q=p; + 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, &al)) + { + /* 'al' set by ssl_parse_clienthello_tlsext */ + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PARSE_TLSEXT); + goto f_err; + } + } + if (ssl_check_clienthello_tlsext_early(s) <= 0) { + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT); + goto err; + } + + /* Check if we want to use external pre-shared secret for this + * handshake for not reused session only. We need to generate + * server_random before calling tls_session_secret_cb in order to allow + * SessionTicket processing to use it in key derivation. */ + { + unsigned char *pos; + pos=s->s3->server_random; + if (ssl_fill_hello_random(s, 1, pos, SSL3_RANDOM_SIZE) <= 0) + { + al=SSL_AD_INTERNAL_ERROR; + 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) + { + al=SSL_AD_INTERNAL_ERROR; + 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) + { + al=SSL_AD_INTERNAL_ERROR; + 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) + { + al=SSL_AD_INTERNAL_ERROR; + 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_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_CIPHERS_PASSED); + goto f_err; + } + ciphers=NULL; + c=ssl3_choose_cipher(s,s->session->ciphers, + SSL_get_ciphers(s)); + + if (c == NULL) + { + al=SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER); + goto f_err; + } + 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 (TLS1_get_version(s) < TLS1_2_VERSION || !(s->verify_mode & SSL_VERIFY_PEER)) + { + if (!ssl3_digest_cached_records(s)) + { + al = SSL_AD_INTERNAL_ERROR; + goto f_err; + } + } + + /* we now have the following setup. + * client_random + * cipher_list - our prefered list of ciphers + * ciphers - the clients prefered list of ciphers + * compression - basically ignored right now + * ssl version is set - sslv3 + * s->session - The ssl session has been setup. + * s->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; + } + } + + if (ret < 0) ret=1; + if (0) + { +f_err: + ssl3_send_alert(s,SSL3_AL_FATAL,al); + } +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; + 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) + return -1; +#endif + /* Do the message type and length last */ + d=p= &(buf[4]); + + *(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); + 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); + return -1; + } + if ((p = ssl_add_serverhello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL) + { + SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO,ERR_R_INTERNAL_ERROR); + return -1; + } +#endif + /* do the header */ + l=(p-d); + d=buf; + *(d++)=SSL3_MT_SERVER_HELLO; + l2n3(l,d); + + s->state=SSL3_ST_SW_SRVR_HELLO_B; + /* number of bytes to write */ + s->init_num=p-buf; + s->init_off=0; + } + + /* SSL3_ST_SW_SRVR_HELLO_B */ + return(ssl3_do_write(s,SSL3_RT_HANDSHAKE)); + } + +int ssl3_send_server_done(SSL *s) + { + unsigned char *p; + + if (s->state == SSL3_ST_SW_SRVR_DONE_A) + { + p=(unsigned char *)s->init_buf->data; + + /* do the header */ + *(p++)=SSL3_MT_SERVER_DONE; + *(p++)=0; + *(p++)=0; + *(p++)=0; + + s->state=SSL3_ST_SW_SRVR_DONE_B; + /* number of bytes to write */ + s->init_num=4; + s->init_off=0; + } + + /* SSL3_ST_SW_SRVR_DONE_B */ + return(ssl3_do_write(s,SSL3_RT_HANDSHAKE)); + } + +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 ((dhp->pub_key == NULL || + dhp->priv_key == NULL || + (s->options & SSL_OP_SINGLE_DH_USE))) + { + if(!DH_generate_key(dh)) + { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE, + ERR_R_DH_LIB); + goto err; + } + } + else + { + dh->pub_key=BN_dup(dhp->pub_key); + dh->priv_key=BN_dup(dhp->priv_key); + if ((dh->pub_key == NULL) || + (dh->priv_key == NULL)) + { + 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 ((ecdhp == NULL) && (s->cert->ecdh_tmp_cb != NULL)) + { + 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 ((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) + && !(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+4+kn)) + { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_BUF); + goto err; + } + d=(unsigned char *)s->init_buf->data; + p= &(d[4]); + + 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 + && TLS1_get_version(s) < TLS1_2_VERSION) + { + 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); + EVP_DigestInit_ex(&md_ctx,(num == 2) + ?s->ctx->md5:s->ctx->sha1, NULL); + EVP_DigestUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE); + EVP_DigestUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE); + EVP_DigestUpdate(&md_ctx,&(d[4]),n); + EVP_DigestFinal_ex(&md_ctx,q, + (unsigned int *)&i); + q+=i; + j+=i; + } + if (RSA_sign(NID_md5_sha1, md_buf, j, + &(p[2]), &u, pkey->pkey.rsa) <= 0) + { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_RSA); + goto err; + } + s2n(u,p); + n+=u+2; + } + else +#endif + if (md) + { + /* For TLS1.2 and later send signature + * algorithm */ + if (TLS1_get_version(s) >= TLS1_2_VERSION) + { + 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 + EVP_SignInit_ex(&md_ctx, md, NULL); + EVP_SignUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE); + EVP_SignUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE); + EVP_SignUpdate(&md_ctx,&(d[4]),n); + if (!EVP_SignFinal(&md_ctx,&(p[2]), + (unsigned int *)&i,pkey)) + { + SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_EVP); + goto err; + } + s2n(i,p); + n+=i+2; + if (TLS1_get_version(s) >= TLS1_2_VERSION) + 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; + } + } + + *(d++)=SSL3_MT_SERVER_KEY_EXCHANGE; + l2n3(n,d); + + /* we should now have things packed up, so lets send + * it off */ + s->init_num=n+4; + s->init_off=0; + } + + s->state = SSL3_ST_SW_KEY_EXCH_B; + EVP_MD_CTX_cleanup(&md_ctx); + return(ssl3_do_write(s,SSL3_RT_HANDSHAKE)); +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); + 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=(unsigned char *)&(buf->data[4]); + + /* get the list of acceptable cert types */ + p++; + n=ssl3_get_req_cert_type(s,p); + d[0]=n; + p+=n; + n++; + + if (TLS1_get_version(s) >= TLS1_2_VERSION) + { + nl = tls12_get_req_sig_algs(s, p + 2); + s2n(nl, p); + p += nl + 2; + n += nl + 2; + } + + off=n; + p+=2; + n+=2; + + sk=SSL_get_client_CA_list(s); + nl=0; + if (sk != NULL) + { + for (i=0; i<sk_X509_NAME_num(sk); i++) + { + name=sk_X509_NAME_value(sk,i); + j=i2d_X509_NAME(name,NULL); + if (!BUF_MEM_grow_clean(buf,4+n+j+2)) + { + SSLerr(SSL_F_SSL3_SEND_CERTIFICATE_REQUEST,ERR_R_BUF_LIB); + goto err; + } + p=(unsigned char *)&(buf->data[4+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=(unsigned char *)&(buf->data[4+off]); + s2n(nl,p); + + d=(unsigned char *)buf->data; + *(d++)=SSL3_MT_CERTIFICATE_REQUEST; + l2n3(n,d); + + /* we should now have things packed up, so lets send + * it off */ + + s->init_num=n+4; + s->init_off=0; +#ifdef NETSCAPE_HANG_BUG + 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(ssl3_do_write(s,SSL3_RT_HANDSHAKE)); +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; +#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) + { + /* 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)) + { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG); + goto err; + } + else + p-=2; + } + else + n=i; + } + + i=RSA_private_decrypt((int)n,p,p,rsa,RSA_PKCS1_PADDING); + + al = -1; + + if (i != SSL_MAX_MASTER_KEY_LENGTH) + { + al=SSL_AD_DECODE_ERROR; + /* SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_RSA_DECRYPT); */ + } + + if ((al == -1) && !((p[0] == (s->client_version>>8)) && (p[1] == (s->client_version & 0xff)))) + { + /* The premaster secret must contain the same version number as the + * ClientHello to detect version rollback attacks (strangely, the + * protocol does not offer such protection for DH ciphersuites). + * However, buggy clients exist that send the negotiated protocol + * version instead if the server does not support the requested + * protocol version. + * If SSL_OP_TLS_ROLLBACK_BUG is set, tolerate such clients. */ + if (!((s->options & SSL_OP_TLS_ROLLBACK_BUG) && + (p[0] == (s->version>>8)) && (p[1] == (s->version & 0xff)))) + { + al=SSL_AD_DECODE_ERROR; + /* SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_PROTOCOL_VERSION_NUMBER); */ + + /* The Klima-Pokorny-Rosa extension of Bleichenbacher's attack + * (http://eprint.iacr.org/2003/052/) exploits the version + * number check as a "bad version oracle" -- an alert would + * reveal that the plaintext corresponding to some ciphertext + * made up by the adversary is properly formatted except + * that the version number is wrong. To avoid such attacks, + * we should treat this just like any other decryption error. */ + } + } + + if (al != -1) + { + /* Some decryption failure -- use random value instead as countermeasure + * against Bleichenbacher's attack on PKCS #1 v1.5 RSA padding + * (see RFC 2246, section 7.4.7.1). */ + ERR_clear_error(); + i = SSL_MAX_MASTER_KEY_LENGTH; + p[0] = s->client_version >> 8; + p[1] = s->client_version & 0xff; + if (RAND_pseudo_bytes(p+2, i-2) <= 0) /* should be RAND_bytes, but we cannot work around a failure */ + goto err; + } + + s->session->master_key_length= + s->method->ssl3_enc->generate_master_secret(s, + s->session->master_key, + p,i); + OPENSSL_cleanse(p,i); + } + else +#endif +#ifndef OPENSSL_NO_DH + if (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd)) + { + n2s(p,i); + if (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 (n == 0L) /* the parameters are in the cert */ + { + al=SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_UNABLE_TO_DECODE_DH_CERTS); + goto f_err; + } + 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; + } + + 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; + + 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); + } + 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; + + 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 + printf("kssl_sget_tkt rtn %d [%d]\n", + krb5rc, kssl_err.reason); + if (kssl_err.text) + printf("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 + printf("kssl_check_authent rtn %d [%d]\n", + krb5rc, kssl_err.reason); + if (kssl_err.text) + printf("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); + goto err; + } + if (outl > SSL_MAX_MASTER_KEY_LENGTH) + { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_DATA_LENGTH_TOO_LONG); + goto err; + } + if (!EVP_DecryptFinal_ex(&ciph_ctx,&(pms[outl]),&padl)) + { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_DECRYPTION_FAILED); + goto err; + } + outl += padl; + if (outl > SSL_MAX_MASTER_KEY_LENGTH) + { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_DATA_LENGTH_TOO_LONG); + goto err; + } + 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); + goto err; + } + } + + 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; + */ + } + 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_strdup((char *)p); + 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 (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); + EVP_PKEY_decrypt_init(pkey_ctx); + /* If client certificate is present and is of the same type, maybe + * use it for key exchange. Don't mind errors from + * EVP_PKEY_derive_set_peer, because it is completely valid to use + * a client certificate for authorization only. */ + client_pub_pkey = X509_get_pubkey(s->session->peer); + if (client_pub_pkey) + { + if (EVP_PKEY_derive_set_peer(pkey_ctx, client_pub_pkey) <= 0) + ERR_clear_error(); + } + /* 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); + /* 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 + return(-1); + } + +int ssl3_get_cert_verify(SSL *s) + { + EVP_PKEY *pkey=NULL; + unsigned char *p; + int al,ok,ret=0; + long n; + int type=0,i,j; + X509 *peer; + const EVP_MD *md = NULL; + EVP_MD_CTX mctx; + EVP_MD_CTX_init(&mctx); + + n=s->method->ssl_get_message(s, + SSL3_ST_SR_CERT_VRFY_A, + SSL3_ST_SR_CERT_VRFY_B, + -1, + 516, /* Enough for 4096 bit RSA key with TLS v1.2 */ + &ok); + + if (!ok) return((int)n); + + if (s->session->peer != NULL) + { + peer=s->session->peer; + pkey=X509_get_pubkey(peer); + type=X509_certificate_type(peer,pkey); + } + else + { + peer=NULL; + pkey=NULL; + } + + if (s->s3->tmp.message_type != SSL3_MT_CERTIFICATE_VERIFY) + { + s->s3->tmp.reuse_message=1; + if ((peer != NULL) && (type & EVP_PKT_SIGN)) + { + al=SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_MISSING_VERIFY_MESSAGE); + goto f_err; + } + ret=1; + goto end; + } + + if (peer == NULL) + { + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_NO_CLIENT_CERT_RECEIVED); + al=SSL_AD_UNEXPECTED_MESSAGE; + goto f_err; + } + + if (!(type & EVP_PKT_SIGN)) + { + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE); + al=SSL_AD_ILLEGAL_PARAMETER; + goto f_err; + } + + if (s->s3->change_cipher_spec) + { + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_CCS_RECEIVED_EARLY); + al=SSL_AD_UNEXPECTED_MESSAGE; + goto f_err; + } + + /* we now have a signature that we need to verify */ + p=(unsigned char *)s->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 (TLS1_get_version(s) >= TLS1_2_VERSION) + { + int sigalg = tls12_get_sigid(pkey); + /* Should never happen */ + if (sigalg == -1) + { + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,ERR_R_INTERNAL_ERROR); + al=SSL_AD_INTERNAL_ERROR; + goto f_err; + } + /* Check key type is consistent with signature */ + if (sigalg != (int)p[1]) + { + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_WRONG_SIGNATURE_TYPE); + al=SSL_AD_DECODE_ERROR; + goto f_err; + } + md = tls12_get_hash(p[0]); + if (md == NULL) + { + SSLerr(SSL_F_SSL3_GET_CERT_VERIFY,SSL_R_UNKNOWN_DIGEST); + al=SSL_AD_DECODE_ERROR; + goto f_err; + } +#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 (TLS1_get_version(s) >= TLS1_2_VERSION) + { + 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); + EVP_PKEY_verify_init(pctx); + 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); + } +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_NO_CERTIFICATE_RETURNED); + 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: + 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) + { + unsigned long l; + X509 *x; + + if (s->state == SSL3_ST_SW_CERT_A) + { + x=ssl_get_server_send_cert(s); + if (x == 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); + return(0); + } + } + + l=ssl3_output_cert_chain(s,x); + s->state=SSL3_ST_SW_CERT_B; + s->init_num=(int)l; + s->init_off=0; + } + + /* SSL3_ST_SW_CERT_B */ + return(ssl3_do_write(s,SSL3_RT_HANDSHAKE)); + } + +#ifndef OPENSSL_NO_TLSEXT +/* send a new session ticket (not necessarily for a new session) */ +int ssl3_send_newsession_ticket(SSL *s) + { + if (s->state == SSL3_ST_SW_SESSION_TICKET_A) + { + unsigned char *p, *senc, *macstart; + const unsigned char *const_p; + int len, slen_full, slen; + SSL_SESSION *sess; + unsigned int hlen; + EVP_CIPHER_CTX ctx; + HMAC_CTX hctx; + SSL_CTX *tctx = s->initial_ctx; + unsigned char iv[EVP_MAX_IV_LENGTH]; + unsigned char key_name[16]; + + /* get session encoding length */ + slen_full = i2d_SSL_SESSION(s->session, NULL); + /* Some length values are 16 bits, so forget it if session is + * too long + */ + if (slen_full > 0xFF00) + return -1; + senc = OPENSSL_malloc(slen_full); + if (!senc) + return -1; + p = senc; + i2d_SSL_SESSION(s->session, &p); + + /* create a fresh copy (not shared with other threads) to clean up */ + const_p = senc; + sess = d2i_SSL_SESSION(NULL, &const_p, slen_full); + if (sess == NULL) + { + OPENSSL_free(senc); + return -1; + } + sess->session_id_length = 0; /* ID is irrelevant for the ticket */ + + slen = i2d_SSL_SESSION(sess, NULL); + if (slen > slen_full) /* shouldn't ever happen */ + { + OPENSSL_free(senc); + return -1; + } + p = senc; + i2d_SSL_SESSION(sess, &p); + SSL_SESSION_free(sess); + + /* Grow buffer if need be: the length calculation is as + * follows 1 (size of message name) + 3 (message length + * bytes) + 4 (ticket lifetime hint) + 2 (ticket length) + + * 16 (key name) + max_iv_len (iv length) + + * session_length + max_enc_block_size (max encrypted session + * length) + max_md_size (HMAC). + */ + if (!BUF_MEM_grow(s->init_buf, + 26 + EVP_MAX_IV_LENGTH + EVP_MAX_BLOCK_LENGTH + + EVP_MAX_MD_SIZE + slen)) + return -1; + + p=(unsigned char *)s->init_buf->data; + /* do the header */ + *(p++)=SSL3_MT_NEWSESSION_TICKET; + /* Skip message length for now */ + p += 3; + EVP_CIPHER_CTX_init(&ctx); + HMAC_CTX_init(&hctx); + /* Initialize HMAC and cipher contexts. If callback present + * it does all the work otherwise use generated values + * from parent ctx. + */ + if (tctx->tlsext_ticket_key_cb) + { + if (tctx->tlsext_ticket_key_cb(s, key_name, iv, &ctx, + &hctx, 1) < 0) + { + OPENSSL_free(senc); + return -1; + } + } + else + { + RAND_pseudo_bytes(iv, 16); + EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, + tctx->tlsext_tick_aes_key, iv); + HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16, + tlsext_tick_md(), NULL); + 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 */ + EVP_EncryptUpdate(&ctx, p, &len, senc, slen); + p += len; + EVP_EncryptFinal(&ctx, p, &len); + p += len; + EVP_CIPHER_CTX_cleanup(&ctx); + + HMAC_Update(&hctx, macstart, p - macstart); + HMAC_Final(&hctx, p, &hlen); + HMAC_CTX_cleanup(&hctx); + + p += hlen; + /* Now write out lengths: p points to end of data written */ + /* Total length */ + len = p - (unsigned char *)s->init_buf->data; + p=(unsigned char *)s->init_buf->data + 1; + l2n3(len - 4, p); /* Message length */ + p += 4; + s2n(len - 10, p); /* Ticket length */ + + /* number of bytes to write */ + s->init_num= len; + s->state=SSL3_ST_SW_SESSION_TICKET_B; + s->init_off=0; + OPENSSL_free(senc); + } + + /* SSL3_ST_SW_SESSION_TICKET_B */ + return(ssl3_do_write(s,SSL3_RT_HANDSHAKE)); + } + +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)) + 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); + return -1; + } + + n=s->method->ssl_get_message(s, + SSL3_ST_SR_NEXT_PROTO_A, + SSL3_ST_SR_NEXT_PROTO_B, + SSL3_MT_NEXT_PROTO, + 514, /* See the payload format below */ + &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); + return -1; + } + + if (n < 2) + 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) + return 0; + padding_len = p[proto_len + 1]; + if (proto_len + padding_len + 2 != s->init_num) + 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); + 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/drivers/builtin_openssl2/ssl/ssl-lib.com b/drivers/builtin_openssl2/ssl/ssl-lib.com new file mode 100644 index 0000000000..05bda755b5 --- /dev/null +++ b/drivers/builtin_openssl2/ssl/ssl-lib.com @@ -0,0 +1,1226 @@ +$! +$! 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,"+ - + "d1_meth,d1_srvr,d1_clnt,d1_lib,d1_pkt,"+ - + "d1_both,d1_enc,d1_srtp,"+ - + "ssl_lib,ssl_err2,ssl_cert,ssl_sess,"+ - + "ssl_ciph,ssl_stat,ssl_rsa,"+ - + "ssl_asn1,ssl_txt,ssl_algs,"+ - + "bio_ssl,ssl_err,kssl,tls_srp,t1_reneg" +$! +$ 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$ELEMENT(FILE_COUNTER,",",LIB_SSL) +$! +$! 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 - + CCDISABLEWARNINGS = CCDISABLEWARNINGS + "," + USER_CCDISABLEWARNINGS +$! +$! 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/drivers/builtin_openssl2/ssl/ssl_algs.c b/drivers/builtin_openssl2/ssl/ssl_algs.c new file mode 100644 index 0000000000..9c34d19725 --- /dev/null +++ b/drivers/builtin_openssl2/ssl/ssl_algs.c @@ -0,0 +1,150 @@ +/* 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 + +#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/drivers/builtin_openssl2/ssl/ssl_asn1.c b/drivers/builtin_openssl2/ssl/ssl_asn1.c new file mode 100644 index 0000000000..4775003710 --- /dev/null +++ b/drivers/builtin_openssl2/ssl/ssl_asn1.c @@ -0,0 +1,646 @@ +/* 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,v7=0,v8=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_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) + { + 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/drivers/builtin_openssl2/ssl/ssl_cert.c b/drivers/builtin_openssl2/ssl/ssl_cert.c new file mode 100644 index 0000000000..5123a89182 --- /dev/null +++ b/drivers/builtin_openssl2/ssl/ssl_cert.c @@ -0,0 +1,853 @@ +/*! \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; + + 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; + } + +static 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->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; +#endif + + for (i = 0; i < SSL_PKEY_NUM; i++) + { + if (cert->pkeys[i].x509 != NULL) + { + ret->pkeys[i].x509 = cert->pkeys[i].x509; + CRYPTO_add(&ret->pkeys[i].x509->references, 1, + CRYPTO_LOCK_X509); + } + + if (cert->pkeys[i].privatekey != NULL) + { + ret->pkeys[i].privatekey = cert->pkeys[i].privatekey; + CRYPTO_add(&ret->pkeys[i].privatekey->references, 1, + CRYPTO_LOCK_EVP_PKEY); + + switch(i) + { + /* If there was anything special to do for + * certain types of keys, we'd do it here. + * (Nothing at the moment, I think.) */ + + case SSL_PKEY_RSA_ENC: + case SSL_PKEY_RSA_SIGN: + /* We have an RSA key. */ + break; + + case SSL_PKEY_DSA_SIGN: + /* We have a DSA key. */ + break; + + case SSL_PKEY_DH_RSA: + case SSL_PKEY_DH_DSA: + /* We have a DH key. */ + break; + + case SSL_PKEY_ECC: + /* We have an ECC key */ + break; + + default: + /* Can't happen. */ + SSLerr(SSL_F_SSL_CERT_DUP, SSL_R_LIBRARY_BUG); + } + } + } + + /* ret->extra_certs *should* exist, but currently the own certificate + * chain is held inside SSL_CTX */ + + ret->references=1; + /* Set digests to defaults. NB: we don't copy existing values as they + * will be set during handshake. + */ + ssl_cert_set_default_md(ret); + + 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 + + for (i = 0; i < SSL_PKEY_NUM; i++) + { + if (ret->pkeys[i].x509 != NULL) + X509_free(ret->pkeys[i].x509); + if (ret->pkeys[i].privatekey != NULL) + EVP_PKEY_free(ret->pkeys[i].privatekey); + } + + return NULL; + } + + +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 + + for (i=0; i<SSL_PKEY_NUM; i++) + { + if (c->pkeys[i].x509 != NULL) + X509_free(c->pkeys[i].x509); + if (c->pkeys[i].privatekey != NULL) + EVP_PKEY_free(c->pkeys[i].privatekey); +#if 0 + if (c->pkeys[i].publickey != NULL) + EVP_PKEY_free(c->pkeys[i].publickey); +#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); + } + + +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_CTX ctx; + + if ((sk == NULL) || (sk_X509_num(sk) == 0)) + return(0); + + x=sk_X509_value(sk,0); + if(!X509_STORE_CTX_init(&ctx,s->ctx->cert_store,x,sk)) + { + SSLerr(SSL_F_SSL_VERIFY_CERT_CHAIN,ERR_R_X509_LIB); + return(0); + } +#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; + } + diff --git a/drivers/builtin_openssl2/ssl/ssl_ciph.c b/drivers/builtin_openssl2/ssl/ssl_ciph.c new file mode 100644 index 0000000000..0aba8e048c --- /dev/null +++ b/drivers/builtin_openssl2/ssl/ssl_ciph.c @@ -0,0 +1,1853 @@ +/* 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, SSL_kEDH|SSL_kEECDH,SSL_aNULL,~SSL_eNULL,0,0,0,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}, /* no such ciphersuites supported! */ + {0,SSL_TXT_kDHd,0, SSL_kDHd, 0,0,0,0,0,0,0,0}, /* no such ciphersuites supported! */ + {0,SSL_TXT_kDH,0, SSL_kDHr|SSL_kDHd,0,0,0,0,0,0,0,0}, /* no such ciphersuites supported! */ + {0,SSL_TXT_kEDH,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_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}, + {0,SSL_TXT_aDH,0, 0,SSL_aDH, 0,0,0,0,0,0,0}, /* no such ciphersuites supported! */ + {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}, + + /* 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_EECDH,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}, + }; +/* 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); + } + return pkey_id; + } + +#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) + { + EVP_PKEY_asn1_get0_info(&pkey_id, NULL,NULL,NULL,NULL,ameth); + } + 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; + 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 + *mkey |= SSL_kDHr|SSL_kDHd; /* no such ciphersuites supported! */ + *auth |= SSL_aDH; +#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 + printf("\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, *curr2, *last; + const SSL_CIPHER *cp; + int reverse = 0; + +#ifdef CIPHER_DEBUG + printf("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) + { + curr = tail; + last = head; + } + else + { + curr = head; + last = tail; + } + + curr2 = curr; + for (;;) + { + if ((curr == NULL) || (curr == last)) break; + curr = curr2; + curr2 = 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 + printf("\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 + + 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; + } + +#ifdef CIPHER_DEBUG + printf("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]->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); + } + +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) + { + 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; + + /* + * 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 + printf("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 + printf("<%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; + 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; + 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; + 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; + 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); + } + +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 diff --git a/drivers/builtin_openssl2/ssl/ssl_err.c b/drivers/builtin_openssl2/ssl/ssl_err.c new file mode 100644 index 0000000000..49ab43e0e5 --- /dev/null +++ b/drivers/builtin_openssl2/ssl/ssl_err.c @@ -0,0 +1,610 @@ +/* ssl/ssl_err.c */ +/* ==================================================================== + * Copyright (c) 1999-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 + * 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_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_ENC), "DTLS1_ENC"}, +{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_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_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_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_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_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_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_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_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_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_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_HEARTBEAT), "SSL_F_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_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_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_PUB_KEY_LENGTH) ,"bad dh pub key length"}, +{ERR_REASON(SSL_R_BAD_DH_P_LENGTH) ,"bad dh p length"}, +{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_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_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_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_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_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_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_PURPOSE) ,"invalid purpose"}, +{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_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_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_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_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_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_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_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_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_CIPHER_RETURNED) ,"wrong cipher returned"}, +{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/drivers/builtin_openssl2/ssl/ssl_err2.c b/drivers/builtin_openssl2/ssl/ssl_err2.c new file mode 100644 index 0000000000..ea95a5f983 --- /dev/null +++ b/drivers/builtin_openssl2/ssl/ssl_err2.c @@ -0,0 +1,70 @@ +/* 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/drivers/builtin_openssl2/ssl/ssl_lib.c b/drivers/builtin_openssl2/ssl/ssl_lib.c new file mode 100644 index 0000000000..ef6258ca9f --- /dev/null +++ b/drivers/builtin_openssl2/ssl/ssl_lib.c @@ -0,0 +1,3269 @@ +/*! \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; + +#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); + 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; + + 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_NEXTPROTONEG + s->next_proto_negotiated = NULL; +# endif +#endif + + s->verify_result=X509_V_OK; + + s->method=ctx->method; + + if (!s->method->ssl_new(s)) + goto err; + + s->references=1; + 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) + { + if (s->cert != NULL) + ssl_cert_free(s->cert); + if (s->ctx != NULL) + SSL_CTX_free(s->ctx); /* decrement reference count */ + OPENSSL_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); + } + +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); +#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 ((s != NULL) && !SSL_in_init(s)) + return(s->method->ssl_shutdown(s)); + else + 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_MTU: +#ifndef OPENSSL_NO_DTLS1 + if (larg < (long)dtls1_min_mtu()) + return 0; +#endif + + if (SSL_version(s) == DTLS1_VERSION || + SSL_version(s) == DTLS1_BAD_VER) + { + s->d1->mtu = larg; + return larg; + } + return 0; + 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; + 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; + + 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; + 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); + /* 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); + /* 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; + unsigned char *q; +#ifndef OPENSSL_NO_KRB5 + int nokrb5 = !kssl_tgt_is_available(s->kssl_ctx); +#endif /* OPENSSL_NO_KRB5 */ + + if (sk == NULL) return(0); + q=p; + + for (i=0; i<sk_SSL_CIPHER_num(sk); i++) + { + c=sk_SSL_CIPHER_value(sk,i); + /* Skip TLS v1.2 only ciphersuites if lower than v1.2 */ + if ((c->algorithm_ssl & SSL_TLSV1_2) && + (TLS1_get_client_version(s) < TLS1_2_VERSION)) + continue; +#ifndef OPENSSL_NO_KRB5 + if (((c->algorithm_mkey & SSL_kKRB5) || (c->algorithm_auth & SSL_aKRB5)) && + nokrb5) + continue; +#endif /* OPENSSL_NO_KRB5 */ +#ifndef OPENSSL_NO_PSK + /* with PSK there must be client callback set */ + if (((c->algorithm_mkey & SSL_kPSK) || (c->algorithm_auth & SSL_aPSK)) && + s->psk_client_callback == NULL) + continue; +#endif /* OPENSSL_NO_PSK */ + j = put_cb ? put_cb(c,p) : ssl_put_cipher_by_char(s,c,p); + p+=j; + } + /* If p == q, no ciphers and caller indicates an error. Otherwise + * add SCSV if not renegotiating. + */ + if (p != q && !s->renegotiate) + { + static SSL_CIPHER scsv = + { + 0, NULL, SSL3_CK_SCSV, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + j = put_cb ? put_cb(&scsv,p) : ssl_put_cipher_by_char(s,&scsv,p); + p+=j; +#ifdef OPENSSL_RI_DEBUG + fprintf(stderr, "SCSV sent by client\n"); +#endif + } + + 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 ((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 */ + else + { + sk= *skp; + sk_SSL_CIPHER_zero(sk); + } + + for (i=0; i<num; i+=n) + { + /* Check for 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; + } + + 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; + } + +# ifndef OPENSSL_NO_NEXTPROTONEG +/* 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; + } + +/* 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 +#endif + +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); + 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->version != DTLS1_VERSION) + 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; + + 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 + + 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_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; + int have_ecc_cert, ecdh_ok, ecdsa_ok, ecc_pkey_size; +#ifndef OPENSSL_NO_ECDH + int have_ecdh_tmp; +#endif + X509 *x = NULL; + EVP_PKEY *ecc_pkey = NULL; + int signature_nid = 0, pk_nid = 0, md_nid = 0; + + 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 != NULL || c->ecdh_tmp_cb != NULL); +#endif + cpk= &(c->pkeys[SSL_PKEY_RSA_ENC]); + rsa_enc= (cpk->x509 != NULL && cpk->privatekey != NULL); + rsa_enc_export=(rsa_enc && EVP_PKEY_size(cpk->privatekey)*8 <= kl); + cpk= &(c->pkeys[SSL_PKEY_RSA_SIGN]); + rsa_sign=(cpk->x509 != NULL && cpk->privatekey != NULL); + cpk= &(c->pkeys[SSL_PKEY_DSA_SIGN]); + dsa_sign=(cpk->x509 != NULL && cpk->privatekey != NULL); + cpk= &(c->pkeys[SSL_PKEY_DH_RSA]); + dh_rsa= (cpk->x509 != NULL && cpk->privatekey != NULL); + 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->x509 != NULL && cpk->privatekey != NULL); + dh_dsa_export=(dh_dsa && EVP_PKEY_size(cpk->privatekey)*8 <= kl); + cpk= &(c->pkeys[SSL_PKEY_ECC]); + have_ecc_cert= (cpk->x509 != NULL && cpk->privatekey != NULL); + mask_k=0; + mask_a=0; + emask_k=0; + emask_a=0; + + + +#ifdef CIPHER_DEBUG + printf("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 (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. + */ + if (have_ecc_cert) + { + /* This call populates extension flags (ex_flags) */ + x = (c->pkeys[SSL_PKEY_ECC]).x509; + X509_check_purpose(x, -1, 0); + ecdh_ok = (x->ex_flags & EXFLAG_KUSAGE) ? + (x->ex_kusage & X509v3_KU_KEY_AGREEMENT) : 1; + ecdsa_ok = (x->ex_flags & EXFLAG_KUSAGE) ? + (x->ex_kusage & X509v3_KU_DIGITAL_SIGNATURE) : 1; + 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 + } + +#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 + +/* THIS NEEDS CLEANING UP */ +CERT_PKEY *ssl_get_server_send_pkey(const SSL *s) + { + unsigned long alg_k,alg_a; + CERT *c; + int i; + + c=s->cert; + ssl_set_cert_masks(c, s->s3->tmp.new_cipher); + + alg_k = s->s3->tmp.new_cipher->algorithm_mkey; + alg_a = s->s3->tmp.new_cipher->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. + */ + i=SSL_PKEY_ECC; + } + else if (alg_a & SSL_aECDSA) + { + i=SSL_PKEY_ECC; + } + else if (alg_k & SSL_kDHr) + i=SSL_PKEY_DH_RSA; + else if (alg_k & SSL_kDHd) + i=SSL_PKEY_DH_DSA; + else if (alg_a & SSL_aDSS) + i=SSL_PKEY_DSA_SIGN; + else if (alg_a & SSL_aRSA) + { + if (c->pkeys[SSL_PKEY_RSA_ENC].x509 == NULL) + i=SSL_PKEY_RSA_SIGN; + else + i=SSL_PKEY_RSA_ENC; + } + else if (alg_a & SSL_aKRB5) + { + /* VRS something else here? */ + return(NULL); + } + else if (alg_a & SSL_aGOST94) + i=SSL_PKEY_GOST94; + else if (alg_a & SSL_aGOST01) + i=SSL_PKEY_GOST01; + else /* if (alg_a & SSL_aNULL) */ + { + SSLerr(SSL_F_SSL_GET_SERVER_SEND_PKEY,ERR_R_INTERNAL_ERROR); + return(NULL); + } + + return c->pkeys + i; + } + +X509 *ssl_get_server_send_cert(const SSL *s) + { + CERT_PKEY *cpk; + cpk = ssl_get_server_send_pkey(s); + if (!cpk) + return NULL; + return cpk->x509; + } + +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; + + 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; + } + +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_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 + 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 + } + +/* Fix this function so that it takes an optional type parameter */ +X509 *SSL_get_certificate(const SSL *s) + { + if (s->cert != NULL) + return(s->cert->key->x509); + else + return(NULL); + } + +/* Fix this function so that it takes an optional type parameter */ +EVP_PKEY *SSL_get_privatekey(SSL *s) + { + if (s->cert != NULL) + return(s->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) + { + if (ssl->ctx == ctx) + return ssl->ctx; +#ifndef OPENSSL_NO_TLSEXT + if (ctx == NULL) + ctx = ssl->initial_ctx; +#endif + if (ssl->cert != NULL) + ssl_cert_free(ssl->cert); + ssl->cert = ssl_cert_dup(ctx->cert); + 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 (md) EVP_DigestInit_ex(*hash,md,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; + } + +#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/drivers/builtin_openssl2/ssl/ssl_locl.h b/drivers/builtin_openssl2/ssl/ssl_locl.h new file mode 100644 index 0000000000..e485907748 --- /dev/null +++ b/drivers/builtin_openssl2/ssl/ssl_locl.h @@ -0,0 +1,1177 @@ +/* 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) */ +#define SSL_kRSA 0x00000001L /* RSA key exchange */ +#define SSL_kDHr 0x00000002L /* DH cert, RSA CA cert */ /* no such ciphersuites supported! */ +#define SSL_kDHd 0x00000004L /* DH cert, DSA CA cert */ /* no such ciphersuite supported! */ +#define SSL_kEDH 0x00000008L /* tmp DH key no DH cert */ +#define SSL_kKRB5 0x00000010L /* Kerberos5 key exchange */ +#define SSL_kECDHr 0x00000020L /* ECDH cert, RSA CA cert */ +#define SSL_kECDHe 0x00000040L /* ECDH cert, ECDSA CA cert */ +#define SSL_kEECDH 0x00000080L /* ephemeral ECDH */ +#define SSL_kPSK 0x00000100L /* PSK */ +#define SSL_kGOST 0x00000200L /* GOST key exchange */ +#define SSL_kSRP 0x00000400L /* SRP */ + +/* Bits for algorithm_auth (server authentication) */ +#define SSL_aRSA 0x00000001L /* RSA auth */ +#define SSL_aDSS 0x00000002L /* DSS auth */ +#define SSL_aNULL 0x00000004L /* no auth (i.e. use ADH or AECDH) */ +#define SSL_aDH 0x00000008L /* Fixed DH auth (kDHd or kDHr) */ /* no such ciphersuites supported! */ +#define SSL_aECDH 0x00000010L /* Fixed ECDH auth (kECDHe or kECDHr) */ +#define SSL_aKRB5 0x00000020L /* KRB5 auth */ +#define SSL_aECDSA 0x00000040L /* ECDSA auth*/ +#define SSL_aPSK 0x00000080L /* PSK auth */ +#define SSL_aGOST94 0x00000100L /* GOST R 34.10-94 signature auth */ +#define SSL_aGOST01 0x00000200L /* GOST R 34.10-2001 signature auth */ + + +/* 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 0x00000001L +#define SSL_SSLV3 0x00000002L +#define SSL_TLSV1 SSL_SSLV3 /* for now */ +#define SSL_TLSV1_2 0x00000004L + + +/* 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 + +/* we have used 000001ff - 23 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) + + + + +/* 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; + } CERT_PKEY; + +typedef struct cert_st + { + /* Current active set */ + CERT_PKEY *key; /* ALWAYS points to an element of the pkeys array + * Probably it would make more sense to store + * an index, not a pointer. */ + + /* The following masks are for the key and auth + * algorithms that are supported by the certs below */ + int valid; + unsigned long mask_k; + unsigned long mask_a; + unsigned long export_mask_k; + unsigned long export_mask_a; +#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); +#endif + + CERT_PKEY pkeys[SSL_PKEY_NUM]; + + int references; /* >1 only if SSL_copy_session_id is used */ + } 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; + + +/*#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))) +#define ssl_get_cipher_by_char(ssl,ptr) \ + ((ssl)->method->get_cipher_by_char(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); + } SSL3_ENC_METHOD; + +#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 SSLv3_enc_data; +extern SSL3_ENC_METHOD DTLSv1_enc_data; + +#define SSL_IS_DTLS(s) (s->method->version == DTLS1_VERSION) + +#define IMPLEMENT_tls_meth_func(version, func_name, s_accept, s_connect, \ + s_get_meth) \ +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, \ + &TLSv1_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, \ + &ssl3_undef_enc_method, \ + 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(func_name, s_accept, s_connect, s_get_meth) \ +const SSL_METHOD *func_name(void) \ + { \ + static const SSL_METHOD func_name##_data= { \ + DTLS1_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, \ + &DTLSv1_enc_data, \ + ssl_undefined_void_function, \ + ssl3_callback_ctrl, \ + ssl3_ctx_callback_ctrl, \ + }; \ + return &func_name##_data; \ + } + +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); +int ssl_cert_inst(CERT **o); +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); +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); +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_verify_cert_chain(SSL *s,STACK_OF(X509) *sk); +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); +X509 *ssl_get_server_send_cert(const SSL *); +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); +void 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, X509 *x); +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 ); + +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_send_finished(SSL *s, int a, int b, const char *sender, int slen); +unsigned long dtls1_output_cert_chain(SSL *s, X509 *x); +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(void); + +/* 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 +int ssl3_check_finished(SSL *s); +# ifndef OPENSSL_NO_NEXTPROTONEG +int ssl3_send_next_proto(SSL *s); +# endif +#endif + +int dtls1_client_hello(SSL *s); +int dtls1_send_client_certificate(SSL *s); +int dtls1_send_client_key_exchange(SSL *s); +int dtls1_send_client_verify(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_check_client_hello(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 dtls1_send_hello_request(SSL *s); +int dtls1_send_server_hello(SSL *s); +int dtls1_send_server_certificate(SSL *s); +int dtls1_send_server_key_exchange(SSL *s); +int dtls1_send_certificate_request(SSL *s); +int dtls1_send_server_done(SSL *s); + + + +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 dtls1_enc(SSL *s, int snd); + +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); +#endif /* OPENSSL_NO_EC */ + +#ifndef OPENSSL_NO_TLSEXT +unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit); +unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned char *limit); +int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **data, unsigned char *d, int n, int *al); +int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **data, unsigned char *d, int n, int *al); +int ssl_prepare_clienthello_tlsext(SSL *s); +int ssl_prepare_serverhello_tlsext(SSL *s); +int ssl_check_clienthello_tlsext_early(SSL *s); +int ssl_check_clienthello_tlsext_late(SSL *s); +int ssl_check_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); + +#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_process_sigalgs(SSL *s, const unsigned char *data, int dsize); +int tls12_get_req_sig_algs(SSL *s, unsigned char *p); + +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); +void 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); + +#endif diff --git a/drivers/builtin_openssl2/ssl/ssl_rsa.c b/drivers/builtin_openssl2/ssl/ssl_rsa.c new file mode 100644 index 0000000000..60e7b66859 --- /dev/null +++ b/drivers/builtin_openssl2/ssl/ssl_rsa.c @@ -0,0 +1,783 @@ +/* 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); + EVP_PKEY_assign_RSA(pkey,rsa); + + 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; + + 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); + 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) + { + 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); + EVP_PKEY_assign_RSA(pkey,rsa); + + 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; + + if (ctx->extra_certs != NULL) + { + sk_X509_pop_free(ctx->extra_certs, X509_free); + ctx->extra_certs = NULL; + } + + while ((ca = PEM_read_bio_X509(in, NULL, + ctx->default_passwd_callback, + ctx->default_passwd_callback_userdata)) + != NULL) + { + r = SSL_CTX_add_extra_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 diff --git a/drivers/builtin_openssl2/ssl/ssl_sess.c b/drivers/builtin_openssl2/ssl/ssl_sess.c new file mode 100644 index 0000000000..ad40fadd02 --- /dev/null +++ b/drivers/builtin_openssl2/ssl/ssl_sess.c @@ -0,0 +1,1159 @@ +/* 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); + } + +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 + { + SSLerr(SSL_F_SSL_GET_NEW_SESSION,SSL_R_UNSUPPORTED_SSL_VERSION); + SSL_SESSION_free(ss); + return(0); + } +#ifndef OPENSSL_NO_TLSEXT + /* If RFC4507 ticket use empty session ID */ + 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; + } + } +#ifndef OPENSSL_NO_EC + if (s->tlsext_ecpointformatlist) + { + if (ss->tlsext_ecpointformatlist != NULL) OPENSSL_free(ss->tlsext_ecpointformatlist); + if ((ss->tlsext_ecpointformatlist = OPENSSL_malloc(s->tlsext_ecpointformatlist_length)) == NULL) + { + SSLerr(SSL_F_SSL_GET_NEW_SESSION, ERR_R_MALLOC_FAILURE); + SSL_SESSION_free(ss); + return 0; + } + ss->tlsext_ecpointformatlist_length = s->tlsext_ecpointformatlist_length; + memcpy(ss->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist_length); + } + if (s->tlsext_ellipticcurvelist) + { + if (ss->tlsext_ellipticcurvelist != NULL) OPENSSL_free(ss->tlsext_ellipticcurvelist); + if ((ss->tlsext_ellipticcurvelist = OPENSSL_malloc(s->tlsext_ellipticcurvelist_length)) == NULL) + { + SSLerr(SSL_F_SSL_GET_NEW_SESSION, ERR_R_MALLOC_FAILURE); + SSL_SESSION_free(ss); + return 0; + } + ss->tlsext_ellipticcurvelist_length = s->tlsext_ellipticcurvelist_length; + memcpy(ss->tlsext_ellipticcurvelist, s->tlsext_ellipticcurvelist, s->tlsext_ellipticcurvelist_length); + } +#endif +#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 (len > SSL_MAX_SSL_SESSION_ID_LENGTH) + goto err; + + if (len == 0) + try_session_cache = 0; + +#ifndef OPENSSL_NO_TLSEXT + r = tls1_process_ticket(s, session_id, len, limit, &ret); /* sets s->tlsext_ticket_expected */ + 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/drivers/builtin_openssl2/ssl/ssl_stat.c b/drivers/builtin_openssl2/ssl/ssl_stat.c new file mode 100644 index 0000000000..144b81e55f --- /dev/null +++ b/drivers/builtin_openssl2/ssl/ssl_stat.c @@ -0,0 +1,567 @@ +/* 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; +#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 + +#if !defined(OPENSSL_NO_SSL2) && !defined(OPENSSL_NO_SSL3) +/* 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; +#endif + +/* 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; +#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 + +#if !defined(OPENSSL_NO_SSL2) && !defined(OPENSSL_NO_SSL3) +/* 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; +#endif +/* 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/drivers/builtin_openssl2/ssl/ssl_task.c b/drivers/builtin_openssl2/ssl/ssl_task.c new file mode 100644 index 0000000000..b5ce44b47c --- /dev/null +++ b/drivers/builtin_openssl2/ssl/ssl_task.c @@ -0,0 +1,369 @@ +/* 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" +/*************************************************************************/ +struct rpc_msg { /* Should have member alignment inhibited */ + char channel; /* 'A'-app data. 'R'-remote client 'G'-global */ + char function; /* 'G'-get, 'P'-put, 'C'-confirm, 'X'-close */ + unsigned short int length; /* Amount of data returned or max to return */ + char data[4092]; /* variable data */ +}; +#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/drivers/builtin_openssl2/ssl/ssl_txt.c b/drivers/builtin_openssl2/ssl/ssl_txt.c new file mode 100644 index 0000000000..6479d52c0c --- /dev/null +++ b/drivers/builtin_openssl2/ssl/ssl_txt.c @@ -0,0 +1,248 @@ +/* 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_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/drivers/builtin_openssl2/ssl/ssltest.c b/drivers/builtin_openssl2/ssl/ssltest.c new file mode 100644 index 0000000000..4f80be8ee4 --- /dev/null +++ b/drivers/builtin_openssl2/ssl/ssltest.c @@ -0,0 +1,2583 @@ +/* ssl/ssltest.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-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 + * 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. + */ + +#define _BSD_SOURCE 1 /* Or gethostname won't be declared properly + on Linux and GNU platforms. */ + +#include <assert.h> +#include <errno.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#define USE_SOCKETS +#include "e_os.h" + +#ifdef OPENSSL_SYS_VMS +#define _XOPEN_SOURCE 500 /* Or isascii won't be declared properly on + VMS (at least with DECompHP C). */ +#endif + +#include <ctype.h> + +#include <openssl/bio.h> +#include <openssl/crypto.h> +#include <openssl/evp.h> +#include <openssl/x509.h> +#include <openssl/x509v3.h> +#include <openssl/ssl.h> +#ifndef OPENSSL_NO_ENGINE +#include <openssl/engine.h> +#endif +#include <openssl/err.h> +#include <openssl/rand.h> +#ifndef OPENSSL_NO_RSA +#include <openssl/rsa.h> +#endif +#ifndef OPENSSL_NO_DSA +#include <openssl/dsa.h> +#endif +#ifndef OPENSSL_NO_DH +#include <openssl/dh.h> +#endif +#ifndef OPENSSL_NO_SRP +#include <openssl/srp.h> +#endif +#include <openssl/bn.h> + +#define _XOPEN_SOURCE_EXTENDED 1 /* Or gethostname won't be declared properly + on Compaq platforms (at least with DEC C). + Do not try to put it earlier, or IPv6 includes + get screwed... + */ + +#ifdef OPENSSL_SYS_WINDOWS +#include <winsock.h> +#else +#include OPENSSL_UNISTD +#endif + +#ifdef OPENSSL_SYS_VMS +# define TEST_SERVER_CERT "SYS$DISK:[-.APPS]SERVER.PEM" +# define TEST_CLIENT_CERT "SYS$DISK:[-.APPS]CLIENT.PEM" +#elif defined(OPENSSL_SYS_WINCE) +# define TEST_SERVER_CERT "\\OpenSSL\\server.pem" +# define TEST_CLIENT_CERT "\\OpenSSL\\client.pem" +#elif defined(OPENSSL_SYS_NETWARE) +# define TEST_SERVER_CERT "\\openssl\\apps\\server.pem" +# define TEST_CLIENT_CERT "\\openssl\\apps\\client.pem" +#else +# define TEST_SERVER_CERT "../apps/server.pem" +# define TEST_CLIENT_CERT "../apps/client.pem" +#endif + +/* There is really no standard for this, so let's assign some tentative + numbers. In any case, these numbers are only for this test */ +#define COMP_RLE 255 +#define COMP_ZLIB 1 + +static int MS_CALLBACK verify_callback(int ok, X509_STORE_CTX *ctx); +#ifndef OPENSSL_NO_RSA +static RSA MS_CALLBACK *tmp_rsa_cb(SSL *s, int is_export,int keylength); +static void free_tmp_rsa(void); +#endif +static int MS_CALLBACK app_verify_callback(X509_STORE_CTX *ctx, void *arg); +#define APP_CALLBACK_STRING "Test Callback Argument" +struct app_verify_arg + { + char *string; + int app_verify; + int allow_proxy_certs; + char *proxy_auth; + char *proxy_cond; + }; + +#ifndef OPENSSL_NO_DH +static DH *get_dh512(void); +static DH *get_dh1024(void); +static DH *get_dh1024dsa(void); +#endif + + +static char *psk_key=NULL; /* by default PSK is not used */ +#ifndef OPENSSL_NO_PSK +static unsigned int psk_client_callback(SSL *ssl, const char *hint, char *identity, + unsigned int max_identity_len, unsigned char *psk, + unsigned int max_psk_len); +static unsigned int psk_server_callback(SSL *ssl, const char *identity, unsigned char *psk, + unsigned int max_psk_len); +#endif + +#ifndef OPENSSL_NO_SRP +/* SRP client */ +/* This is a context that we pass to all callbacks */ +typedef struct srp_client_arg_st + { + char *srppassin; + char *srplogin; + } SRP_CLIENT_ARG; + +#define PWD_STRLEN 1024 + +static char * MS_CALLBACK ssl_give_srp_client_pwd_cb(SSL *s, void *arg) + { + SRP_CLIENT_ARG *srp_client_arg = (SRP_CLIENT_ARG *)arg; + return BUF_strdup((char *)srp_client_arg->srppassin); + } + +/* SRP server */ +/* This is a context that we pass to SRP server callbacks */ +typedef struct srp_server_arg_st + { + char *expected_user; + char *pass; + } SRP_SERVER_ARG; + +static int MS_CALLBACK ssl_srp_server_param_cb(SSL *s, int *ad, void *arg) + { + SRP_SERVER_ARG * p = (SRP_SERVER_ARG *) arg; + + if (strcmp(p->expected_user, SSL_get_srp_username(s)) != 0) + { + fprintf(stderr, "User %s doesn't exist\n", SSL_get_srp_username(s)); + return SSL3_AL_FATAL; + } + if (SSL_set_srp_server_param_pw(s,p->expected_user,p->pass,"1024")<0) + { + *ad = SSL_AD_INTERNAL_ERROR; + return SSL3_AL_FATAL; + } + return SSL_ERROR_NONE; + } +#endif + +static BIO *bio_err=NULL; +static BIO *bio_stdout=NULL; + +static char *cipher=NULL; +static int verbose=0; +static int debug=0; +#if 0 +/* Not used yet. */ +#ifdef FIONBIO +static int s_nbio=0; +#endif +#endif + +static const char rnd_seed[] = "string to make the random number generator think it has entropy"; + +int doit_biopair(SSL *s_ssl,SSL *c_ssl,long bytes,clock_t *s_time,clock_t *c_time); +int doit(SSL *s_ssl,SSL *c_ssl,long bytes); +static int do_test_cipherlist(void); +static void sv_usage(void) + { + fprintf(stderr,"usage: ssltest [args ...]\n"); + fprintf(stderr,"\n"); +#ifdef OPENSSL_FIPS + fprintf(stderr,"-F - run test in FIPS mode\n"); +#endif + fprintf(stderr," -server_auth - check server certificate\n"); + fprintf(stderr," -client_auth - do client authentication\n"); + fprintf(stderr," -proxy - allow proxy certificates\n"); + fprintf(stderr," -proxy_auth <val> - set proxy policy rights\n"); + fprintf(stderr," -proxy_cond <val> - experssion to test proxy policy rights\n"); + fprintf(stderr," -v - more output\n"); + fprintf(stderr," -d - debug output\n"); + fprintf(stderr," -reuse - use session-id reuse\n"); + fprintf(stderr," -num <val> - number of connections to perform\n"); + fprintf(stderr," -bytes <val> - number of bytes to swap between client/server\n"); +#ifndef OPENSSL_NO_DH + fprintf(stderr," -dhe1024 - use 1024 bit key (safe prime) for DHE\n"); + fprintf(stderr," -dhe1024dsa - use 1024 bit key (with 160-bit subprime) for DHE\n"); + fprintf(stderr," -no_dhe - disable DHE\n"); +#endif +#ifndef OPENSSL_NO_ECDH + fprintf(stderr," -no_ecdhe - disable ECDHE\n"); +#endif +#ifndef OPENSSL_NO_PSK + fprintf(stderr," -psk arg - PSK in hex (without 0x)\n"); +#endif +#ifndef OPENSSL_NO_SRP + fprintf(stderr," -srpuser user - SRP username to use\n"); + fprintf(stderr," -srppass arg - password for 'user'\n"); +#endif +#ifndef OPENSSL_NO_SSL2 + fprintf(stderr," -ssl2 - use SSLv2\n"); +#endif +#ifndef OPENSSL_NO_SSL3 + fprintf(stderr," -ssl3 - use SSLv3\n"); +#endif +#ifndef OPENSSL_NO_TLS1 + fprintf(stderr," -tls1 - use TLSv1\n"); +#endif + fprintf(stderr," -CApath arg - PEM format directory of CA's\n"); + fprintf(stderr," -CAfile arg - PEM format file of CA's\n"); + fprintf(stderr," -cert arg - Server certificate file\n"); + fprintf(stderr," -key arg - Server key file (default: same as -cert)\n"); + fprintf(stderr," -c_cert arg - Client certificate file\n"); + fprintf(stderr," -c_key arg - Client key file (default: same as -c_cert)\n"); + fprintf(stderr," -cipher arg - The cipher list\n"); + fprintf(stderr," -bio_pair - Use BIO pairs\n"); + fprintf(stderr," -f - Test even cases that can't work\n"); + fprintf(stderr," -time - measure processor time used by client and server\n"); + fprintf(stderr," -zlib - use zlib compression\n"); + fprintf(stderr," -rle - use rle compression\n"); +#ifndef OPENSSL_NO_ECDH + fprintf(stderr," -named_curve arg - Elliptic curve name to use for ephemeral ECDH keys.\n" \ + " Use \"openssl ecparam -list_curves\" for all names\n" \ + " (default is sect163r2).\n"); +#endif + fprintf(stderr," -test_cipherlist - verifies the order of the ssl cipher lists\n"); + } + +static void print_details(SSL *c_ssl, const char *prefix) + { + const SSL_CIPHER *ciph; + X509 *cert; + + ciph=SSL_get_current_cipher(c_ssl); + BIO_printf(bio_stdout,"%s%s, cipher %s %s", + prefix, + SSL_get_version(c_ssl), + SSL_CIPHER_get_version(ciph), + SSL_CIPHER_get_name(ciph)); + cert=SSL_get_peer_certificate(c_ssl); + if (cert != NULL) + { + EVP_PKEY *pkey = X509_get_pubkey(cert); + if (pkey != NULL) + { + if (0) + ; +#ifndef OPENSSL_NO_RSA + else if (pkey->type == EVP_PKEY_RSA && pkey->pkey.rsa != NULL + && pkey->pkey.rsa->n != NULL) + { + BIO_printf(bio_stdout, ", %d bit RSA", + BN_num_bits(pkey->pkey.rsa->n)); + } +#endif +#ifndef OPENSSL_NO_DSA + else if (pkey->type == EVP_PKEY_DSA && pkey->pkey.dsa != NULL + && pkey->pkey.dsa->p != NULL) + { + BIO_printf(bio_stdout, ", %d bit DSA", + BN_num_bits(pkey->pkey.dsa->p)); + } +#endif + EVP_PKEY_free(pkey); + } + X509_free(cert); + } + /* The SSL API does not allow us to look at temporary RSA/DH keys, + * otherwise we should print their lengths too */ + BIO_printf(bio_stdout,"\n"); + } + +static void lock_dbg_cb(int mode, int type, const char *file, int line) + { + static int modes[CRYPTO_NUM_LOCKS]; /* = {0, 0, ... } */ + const char *errstr = NULL; + int rw; + + rw = mode & (CRYPTO_READ|CRYPTO_WRITE); + if (!((rw == CRYPTO_READ) || (rw == CRYPTO_WRITE))) + { + errstr = "invalid mode"; + goto err; + } + + if (type < 0 || type >= CRYPTO_NUM_LOCKS) + { + errstr = "type out of bounds"; + goto err; + } + + if (mode & CRYPTO_LOCK) + { + if (modes[type]) + { + errstr = "already locked"; + /* must not happen in a single-threaded program + * (would deadlock) */ + goto err; + } + + modes[type] = rw; + } + else if (mode & CRYPTO_UNLOCK) + { + if (!modes[type]) + { + errstr = "not locked"; + goto err; + } + + if (modes[type] != rw) + { + errstr = (rw == CRYPTO_READ) ? + "CRYPTO_r_unlock on write lock" : + "CRYPTO_w_unlock on read lock"; + } + + modes[type] = 0; + } + else + { + errstr = "invalid mode"; + goto err; + } + + err: + if (errstr) + { + /* we cannot use bio_err here */ + fprintf(stderr, "openssl (lock_dbg_cb): %s (mode=%d, type=%d) at %s:%d\n", + errstr, mode, type, file, line); + } + } + +#ifdef TLSEXT_TYPE_opaque_prf_input +struct cb_info_st { void *input; size_t len; int ret; }; +struct cb_info_st co1 = { "C", 1, 1 }; /* try to negotiate oqaque PRF input */ +struct cb_info_st co2 = { "C", 1, 2 }; /* insist on oqaque PRF input */ +struct cb_info_st so1 = { "S", 1, 1 }; /* try to negotiate oqaque PRF input */ +struct cb_info_st so2 = { "S", 1, 2 }; /* insist on oqaque PRF input */ + +int opaque_prf_input_cb(SSL *ssl, void *peerinput, size_t len, void *arg_) + { + struct cb_info_st *arg = arg_; + + if (arg == NULL) + return 1; + + if (!SSL_set_tlsext_opaque_prf_input(ssl, arg->input, arg->len)) + return 0; + return arg->ret; + } +#endif + +int main(int argc, char *argv[]) + { + char *CApath=NULL,*CAfile=NULL; + int badop=0; + int bio_pair=0; + int force=0; + int tls1=0,ssl2=0,ssl3=0,ret=1; + int client_auth=0; + int server_auth=0,i; + struct app_verify_arg app_verify_arg = + { APP_CALLBACK_STRING, 0, 0, NULL, NULL }; + char *server_cert=TEST_SERVER_CERT; + char *server_key=NULL; + char *client_cert=TEST_CLIENT_CERT; + char *client_key=NULL; +#ifndef OPENSSL_NO_ECDH + char *named_curve = NULL; +#endif + SSL_CTX *s_ctx=NULL; + SSL_CTX *c_ctx=NULL; + const SSL_METHOD *meth=NULL; + SSL *c_ssl,*s_ssl; + int number=1,reuse=0; + long bytes=256L; +#ifndef OPENSSL_NO_DH + DH *dh; + int dhe1024 = 0, dhe1024dsa = 0; +#endif +#ifndef OPENSSL_NO_ECDH + EC_KEY *ecdh = NULL; +#endif +#ifndef OPENSSL_NO_SRP + /* client */ + SRP_CLIENT_ARG srp_client_arg = {NULL,NULL}; + /* server */ + SRP_SERVER_ARG srp_server_arg = {NULL,NULL}; +#endif + int no_dhe = 0; + int no_ecdhe = 0; + int no_psk = 0; + int print_time = 0; + clock_t s_time = 0, c_time = 0; + int comp = 0; +#ifndef OPENSSL_NO_COMP + COMP_METHOD *cm = NULL; + STACK_OF(SSL_COMP) *ssl_comp_methods = NULL; +#endif + int test_cipherlist = 0; +#ifdef OPENSSL_FIPS + int fips_mode=0; +#endif + + verbose = 0; + debug = 0; + cipher = 0; + + bio_err=BIO_new_fp(stderr,BIO_NOCLOSE|BIO_FP_TEXT); + + CRYPTO_set_locking_callback(lock_dbg_cb); + + /* enable memory leak checking unless explicitly disabled */ + if (!((getenv("OPENSSL_DEBUG_MEMORY") != NULL) && (0 == strcmp(getenv("OPENSSL_DEBUG_MEMORY"), "off")))) + { + CRYPTO_malloc_debug_init(); + CRYPTO_set_mem_debug_options(V_CRYPTO_MDEBUG_ALL); + } + else + { + /* OPENSSL_DEBUG_MEMORY=off */ + CRYPTO_set_mem_debug_functions(0, 0, 0, 0, 0); + } + CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); + + RAND_seed(rnd_seed, sizeof rnd_seed); + + bio_stdout=BIO_new_fp(stdout,BIO_NOCLOSE|BIO_FP_TEXT); + + argc--; + argv++; + + while (argc >= 1) + { + if(!strcmp(*argv,"-F")) + { +#ifdef OPENSSL_FIPS + fips_mode=1; +#else + fprintf(stderr,"not compiled with FIPS support, so exitting without running.\n"); + EXIT(0); +#endif + } + else if (strcmp(*argv,"-server_auth") == 0) + server_auth=1; + else if (strcmp(*argv,"-client_auth") == 0) + client_auth=1; + else if (strcmp(*argv,"-proxy_auth") == 0) + { + if (--argc < 1) goto bad; + app_verify_arg.proxy_auth= *(++argv); + } + else if (strcmp(*argv,"-proxy_cond") == 0) + { + if (--argc < 1) goto bad; + app_verify_arg.proxy_cond= *(++argv); + } + else if (strcmp(*argv,"-v") == 0) + verbose=1; + else if (strcmp(*argv,"-d") == 0) + debug=1; + else if (strcmp(*argv,"-reuse") == 0) + reuse=1; + else if (strcmp(*argv,"-dhe1024") == 0) + { +#ifndef OPENSSL_NO_DH + dhe1024=1; +#else + fprintf(stderr,"ignoring -dhe1024, since I'm compiled without DH\n"); +#endif + } + else if (strcmp(*argv,"-dhe1024dsa") == 0) + { +#ifndef OPENSSL_NO_DH + dhe1024dsa=1; +#else + fprintf(stderr,"ignoring -dhe1024, since I'm compiled without DH\n"); +#endif + } + else if (strcmp(*argv,"-no_dhe") == 0) + no_dhe=1; + else if (strcmp(*argv,"-no_ecdhe") == 0) + no_ecdhe=1; + else if (strcmp(*argv,"-psk") == 0) + { + if (--argc < 1) goto bad; + psk_key=*(++argv); +#ifndef OPENSSL_NO_PSK + if (strspn(psk_key, "abcdefABCDEF1234567890") != strlen(psk_key)) + { + BIO_printf(bio_err,"Not a hex number '%s'\n",*argv); + goto bad; + } +#else + no_psk=1; +#endif + } +#ifndef OPENSSL_NO_SRP + else if (strcmp(*argv,"-srpuser") == 0) + { + if (--argc < 1) goto bad; + srp_server_arg.expected_user = srp_client_arg.srplogin= *(++argv); + tls1=1; + } + else if (strcmp(*argv,"-srppass") == 0) + { + if (--argc < 1) goto bad; + srp_server_arg.pass = srp_client_arg.srppassin= *(++argv); + tls1=1; + } +#endif + else if (strcmp(*argv,"-ssl2") == 0) + ssl2=1; + else if (strcmp(*argv,"-tls1") == 0) + tls1=1; + else if (strcmp(*argv,"-ssl3") == 0) + ssl3=1; + else if (strncmp(*argv,"-num",4) == 0) + { + if (--argc < 1) goto bad; + number= atoi(*(++argv)); + if (number == 0) number=1; + } + else if (strcmp(*argv,"-bytes") == 0) + { + if (--argc < 1) goto bad; + bytes= atol(*(++argv)); + if (bytes == 0L) bytes=1L; + i=strlen(argv[0]); + if (argv[0][i-1] == 'k') bytes*=1024L; + if (argv[0][i-1] == 'm') bytes*=1024L*1024L; + } + else if (strcmp(*argv,"-cert") == 0) + { + if (--argc < 1) goto bad; + server_cert= *(++argv); + } + else if (strcmp(*argv,"-s_cert") == 0) + { + if (--argc < 1) goto bad; + server_cert= *(++argv); + } + else if (strcmp(*argv,"-key") == 0) + { + if (--argc < 1) goto bad; + server_key= *(++argv); + } + else if (strcmp(*argv,"-s_key") == 0) + { + if (--argc < 1) goto bad; + server_key= *(++argv); + } + else if (strcmp(*argv,"-c_cert") == 0) + { + if (--argc < 1) goto bad; + client_cert= *(++argv); + } + else if (strcmp(*argv,"-c_key") == 0) + { + if (--argc < 1) goto bad; + client_key= *(++argv); + } + else if (strcmp(*argv,"-cipher") == 0) + { + if (--argc < 1) goto bad; + cipher= *(++argv); + } + else if (strcmp(*argv,"-CApath") == 0) + { + if (--argc < 1) goto bad; + CApath= *(++argv); + } + else if (strcmp(*argv,"-CAfile") == 0) + { + if (--argc < 1) goto bad; + CAfile= *(++argv); + } + else if (strcmp(*argv,"-bio_pair") == 0) + { + bio_pair = 1; + } + else if (strcmp(*argv,"-f") == 0) + { + force = 1; + } + else if (strcmp(*argv,"-time") == 0) + { + print_time = 1; + } + else if (strcmp(*argv,"-zlib") == 0) + { + comp = COMP_ZLIB; + } + else if (strcmp(*argv,"-rle") == 0) + { + comp = COMP_RLE; + } + else if (strcmp(*argv,"-named_curve") == 0) + { + if (--argc < 1) goto bad; +#ifndef OPENSSL_NO_ECDH + named_curve = *(++argv); +#else + fprintf(stderr,"ignoring -named_curve, since I'm compiled without ECDH\n"); + ++argv; +#endif + } + else if (strcmp(*argv,"-app_verify") == 0) + { + app_verify_arg.app_verify = 1; + } + else if (strcmp(*argv,"-proxy") == 0) + { + app_verify_arg.allow_proxy_certs = 1; + } + else if (strcmp(*argv,"-test_cipherlist") == 0) + { + test_cipherlist = 1; + } + else + { + fprintf(stderr,"unknown option %s\n",*argv); + badop=1; + break; + } + argc--; + argv++; + } + if (badop) + { +bad: + sv_usage(); + goto end; + } + + if (test_cipherlist == 1) + { + /* ensure that the cipher list are correctly sorted and exit */ + if (do_test_cipherlist() == 0) + EXIT(1); + ret = 0; + goto end; + } + + if (!ssl2 && !ssl3 && !tls1 && number > 1 && !reuse && !force) + { + fprintf(stderr, "This case cannot work. Use -f to perform " + "the test anyway (and\n-d to see what happens), " + "or add one of -ssl2, -ssl3, -tls1, -reuse\n" + "to avoid protocol mismatch.\n"); + EXIT(1); + } + +#ifdef OPENSSL_FIPS + if(fips_mode) + { + if(!FIPS_mode_set(1)) + { + ERR_load_crypto_strings(); + ERR_print_errors(BIO_new_fp(stderr,BIO_NOCLOSE)); + EXIT(1); + } + else + fprintf(stderr,"*** IN FIPS MODE ***\n"); + } +#endif + + if (print_time) + { + if (!bio_pair) + { + fprintf(stderr, "Using BIO pair (-bio_pair)\n"); + bio_pair = 1; + } + if (number < 50 && !force) + fprintf(stderr, "Warning: For accurate timings, use more connections (e.g. -num 1000)\n"); + } + +/* if (cipher == NULL) cipher=getenv("SSL_CIPHER"); */ + + SSL_library_init(); + SSL_load_error_strings(); + +#ifndef OPENSSL_NO_COMP + if (comp == COMP_ZLIB) cm = COMP_zlib(); + if (comp == COMP_RLE) cm = COMP_rle(); + if (cm != NULL) + { + if (cm->type != NID_undef) + { + if (SSL_COMP_add_compression_method(comp, cm) != 0) + { + fprintf(stderr, + "Failed to add compression method\n"); + ERR_print_errors_fp(stderr); + } + } + else + { + fprintf(stderr, + "Warning: %s compression not supported\n", + (comp == COMP_RLE ? "rle" : + (comp == COMP_ZLIB ? "zlib" : + "unknown"))); + ERR_print_errors_fp(stderr); + } + } + ssl_comp_methods = SSL_COMP_get_compression_methods(); + fprintf(stderr, "Available compression methods:\n"); + { + int j, n = sk_SSL_COMP_num(ssl_comp_methods); + if (n == 0) + fprintf(stderr, " NONE\n"); + else + for (j = 0; j < n; j++) + { + SSL_COMP *c = sk_SSL_COMP_value(ssl_comp_methods, j); + fprintf(stderr, " %d: %s\n", c->id, c->name); + } + } +#endif + +#if !defined(OPENSSL_NO_SSL2) && !defined(OPENSSL_NO_SSL3) + if (ssl2) + meth=SSLv2_method(); + else + if (tls1) + meth=TLSv1_method(); + else + if (ssl3) + meth=SSLv3_method(); + else + meth=SSLv23_method(); +#else +#ifdef OPENSSL_NO_SSL2 + if (tls1) + meth=TLSv1_method(); + else + if (ssl3) + meth=SSLv3_method(); + else + meth=SSLv23_method(); +#else + meth=SSLv2_method(); +#endif +#endif + + c_ctx=SSL_CTX_new(meth); + s_ctx=SSL_CTX_new(meth); + if ((c_ctx == NULL) || (s_ctx == NULL)) + { + ERR_print_errors(bio_err); + goto end; + } + + if (cipher != NULL) + { + SSL_CTX_set_cipher_list(c_ctx,cipher); + SSL_CTX_set_cipher_list(s_ctx,cipher); + } + +#ifndef OPENSSL_NO_DH + if (!no_dhe) + { + if (dhe1024dsa) + { + /* use SSL_OP_SINGLE_DH_USE to avoid small subgroup attacks */ + SSL_CTX_set_options(s_ctx, SSL_OP_SINGLE_DH_USE); + dh=get_dh1024dsa(); + } + else if (dhe1024) + dh=get_dh1024(); + else + dh=get_dh512(); + SSL_CTX_set_tmp_dh(s_ctx,dh); + DH_free(dh); + } +#else + (void)no_dhe; +#endif + +#ifndef OPENSSL_NO_ECDH + if (!no_ecdhe) + { + int nid; + + if (named_curve != NULL) + { + nid = OBJ_sn2nid(named_curve); + if (nid == 0) + { + BIO_printf(bio_err, "unknown curve name (%s)\n", named_curve); + goto end; + } + } + else +#ifdef OPENSSL_NO_EC2M + nid = NID_X9_62_prime256v1; +#else + nid = NID_sect163r2; +#endif + + ecdh = EC_KEY_new_by_curve_name(nid); + if (ecdh == NULL) + { + BIO_printf(bio_err, "unable to create curve\n"); + goto end; + } + + SSL_CTX_set_tmp_ecdh(s_ctx, ecdh); + SSL_CTX_set_options(s_ctx, SSL_OP_SINGLE_ECDH_USE); + EC_KEY_free(ecdh); + } +#else + (void)no_ecdhe; +#endif + +#ifndef OPENSSL_NO_RSA + SSL_CTX_set_tmp_rsa_callback(s_ctx,tmp_rsa_cb); +#endif + +#ifdef TLSEXT_TYPE_opaque_prf_input + SSL_CTX_set_tlsext_opaque_prf_input_callback(c_ctx, opaque_prf_input_cb); + SSL_CTX_set_tlsext_opaque_prf_input_callback(s_ctx, opaque_prf_input_cb); + SSL_CTX_set_tlsext_opaque_prf_input_callback_arg(c_ctx, &co1); /* or &co2 or NULL */ + SSL_CTX_set_tlsext_opaque_prf_input_callback_arg(s_ctx, &so1); /* or &so2 or NULL */ +#endif + + if (!SSL_CTX_use_certificate_file(s_ctx,server_cert,SSL_FILETYPE_PEM)) + { + ERR_print_errors(bio_err); + } + else if (!SSL_CTX_use_PrivateKey_file(s_ctx, + (server_key?server_key:server_cert), SSL_FILETYPE_PEM)) + { + ERR_print_errors(bio_err); + goto end; + } + + if (client_auth) + { + SSL_CTX_use_certificate_file(c_ctx,client_cert, + SSL_FILETYPE_PEM); + SSL_CTX_use_PrivateKey_file(c_ctx, + (client_key?client_key:client_cert), + SSL_FILETYPE_PEM); + } + + if ( (!SSL_CTX_load_verify_locations(s_ctx,CAfile,CApath)) || + (!SSL_CTX_set_default_verify_paths(s_ctx)) || + (!SSL_CTX_load_verify_locations(c_ctx,CAfile,CApath)) || + (!SSL_CTX_set_default_verify_paths(c_ctx))) + { + /* fprintf(stderr,"SSL_load_verify_locations\n"); */ + ERR_print_errors(bio_err); + /* goto end; */ + } + + if (client_auth) + { + BIO_printf(bio_err,"client authentication\n"); + SSL_CTX_set_verify(s_ctx, + SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, + verify_callback); + SSL_CTX_set_cert_verify_callback(s_ctx, app_verify_callback, &app_verify_arg); + } + if (server_auth) + { + BIO_printf(bio_err,"server authentication\n"); + SSL_CTX_set_verify(c_ctx,SSL_VERIFY_PEER, + verify_callback); + SSL_CTX_set_cert_verify_callback(c_ctx, app_verify_callback, &app_verify_arg); + } + + { + int session_id_context = 0; + SSL_CTX_set_session_id_context(s_ctx, (void *)&session_id_context, sizeof session_id_context); + } + + /* Use PSK only if PSK key is given */ + if (psk_key != NULL) + { + /* no_psk is used to avoid putting psk command to openssl tool */ + if (no_psk) + { + /* if PSK is not compiled in and psk key is + * given, do nothing and exit successfully */ + ret=0; + goto end; + } +#ifndef OPENSSL_NO_PSK + SSL_CTX_set_psk_client_callback(c_ctx, psk_client_callback); + SSL_CTX_set_psk_server_callback(s_ctx, psk_server_callback); + if (debug) + BIO_printf(bio_err,"setting PSK identity hint to s_ctx\n"); + if (!SSL_CTX_use_psk_identity_hint(s_ctx, "ctx server identity_hint")) + { + BIO_printf(bio_err,"error setting PSK identity hint to s_ctx\n"); + ERR_print_errors(bio_err); + goto end; + } +#endif + } +#ifndef OPENSSL_NO_SRP + if (srp_client_arg.srplogin) + { + if (!SSL_CTX_set_srp_username(c_ctx, srp_client_arg.srplogin)) + { + BIO_printf(bio_err,"Unable to set SRP username\n"); + goto end; + } + SSL_CTX_set_srp_cb_arg(c_ctx,&srp_client_arg); + SSL_CTX_set_srp_client_pwd_callback(c_ctx, ssl_give_srp_client_pwd_cb); + /*SSL_CTX_set_srp_strength(c_ctx, srp_client_arg.strength);*/ + } + + if (srp_server_arg.expected_user != NULL) + { + SSL_CTX_set_verify(s_ctx,SSL_VERIFY_NONE,verify_callback); + SSL_CTX_set_srp_cb_arg(s_ctx, &srp_server_arg); + SSL_CTX_set_srp_username_callback(s_ctx, ssl_srp_server_param_cb); + } +#endif + + c_ssl=SSL_new(c_ctx); + s_ssl=SSL_new(s_ctx); + +#ifndef OPENSSL_NO_KRB5 + if (c_ssl && c_ssl->kssl_ctx) + { + char localhost[MAXHOSTNAMELEN+2]; + + if (gethostname(localhost, sizeof localhost-1) == 0) + { + localhost[sizeof localhost-1]='\0'; + if(strlen(localhost) == sizeof localhost-1) + { + BIO_printf(bio_err,"localhost name too long\n"); + goto end; + } + kssl_ctx_setstring(c_ssl->kssl_ctx, KSSL_SERVER, + localhost); + } + } +#endif /* OPENSSL_NO_KRB5 */ + + for (i=0; i<number; i++) + { + if (!reuse) SSL_set_session(c_ssl,NULL); + if (bio_pair) + ret=doit_biopair(s_ssl,c_ssl,bytes,&s_time,&c_time); + else + ret=doit(s_ssl,c_ssl,bytes); + } + + if (!verbose) + { + print_details(c_ssl, ""); + } + if ((number > 1) || (bytes > 1L)) + BIO_printf(bio_stdout, "%d handshakes of %ld bytes done\n",number,bytes); + if (print_time) + { +#ifdef CLOCKS_PER_SEC + /* "To determine the time in seconds, the value returned + * by the clock function should be divided by the value + * of the macro CLOCKS_PER_SEC." + * -- ISO/IEC 9899 */ + BIO_printf(bio_stdout, "Approximate total server time: %6.2f s\n" + "Approximate total client time: %6.2f s\n", + (double)s_time/CLOCKS_PER_SEC, + (double)c_time/CLOCKS_PER_SEC); +#else + /* "`CLOCKS_PER_SEC' undeclared (first use this function)" + * -- cc on NeXTstep/OpenStep */ + BIO_printf(bio_stdout, + "Approximate total server time: %6.2f units\n" + "Approximate total client time: %6.2f units\n", + (double)s_time, + (double)c_time); +#endif + } + + SSL_free(s_ssl); + SSL_free(c_ssl); + +end: + if (s_ctx != NULL) SSL_CTX_free(s_ctx); + if (c_ctx != NULL) SSL_CTX_free(c_ctx); + + if (bio_stdout != NULL) BIO_free(bio_stdout); + +#ifndef OPENSSL_NO_RSA + free_tmp_rsa(); +#endif +#ifndef OPENSSL_NO_ENGINE + ENGINE_cleanup(); +#endif + CRYPTO_cleanup_all_ex_data(); + ERR_free_strings(); + ERR_remove_thread_state(NULL); + EVP_cleanup(); + CRYPTO_mem_leaks(bio_err); + if (bio_err != NULL) BIO_free(bio_err); + EXIT(ret); + return ret; + } + +int doit_biopair(SSL *s_ssl, SSL *c_ssl, long count, + clock_t *s_time, clock_t *c_time) + { + long cw_num = count, cr_num = count, sw_num = count, sr_num = count; + BIO *s_ssl_bio = NULL, *c_ssl_bio = NULL; + BIO *server = NULL, *server_io = NULL, *client = NULL, *client_io = NULL; + int ret = 1; + + size_t bufsiz = 256; /* small buffer for testing */ + + if (!BIO_new_bio_pair(&server, bufsiz, &server_io, bufsiz)) + goto err; + if (!BIO_new_bio_pair(&client, bufsiz, &client_io, bufsiz)) + goto err; + + s_ssl_bio = BIO_new(BIO_f_ssl()); + if (!s_ssl_bio) + goto err; + + c_ssl_bio = BIO_new(BIO_f_ssl()); + if (!c_ssl_bio) + goto err; + + SSL_set_connect_state(c_ssl); + SSL_set_bio(c_ssl, client, client); + (void)BIO_set_ssl(c_ssl_bio, c_ssl, BIO_NOCLOSE); + + SSL_set_accept_state(s_ssl); + SSL_set_bio(s_ssl, server, server); + (void)BIO_set_ssl(s_ssl_bio, s_ssl, BIO_NOCLOSE); + + do + { + /* c_ssl_bio: SSL filter BIO + * + * client: pseudo-I/O for SSL library + * + * client_io: client's SSL communication; usually to be + * relayed over some I/O facility, but in this + * test program, we're the server, too: + * + * server_io: server's SSL communication + * + * server: pseudo-I/O for SSL library + * + * s_ssl_bio: SSL filter BIO + * + * The client and the server each employ a "BIO pair": + * client + client_io, server + server_io. + * BIO pairs are symmetric. A BIO pair behaves similar + * to a non-blocking socketpair (but both endpoints must + * be handled by the same thread). + * [Here we could connect client and server to the ends + * of a single BIO pair, but then this code would be less + * suitable as an example for BIO pairs in general.] + * + * Useful functions for querying the state of BIO pair endpoints: + * + * BIO_ctrl_pending(bio) number of bytes we can read now + * BIO_ctrl_get_read_request(bio) number of bytes needed to fulfil + * other side's read attempt + * BIO_ctrl_get_write_guarantee(bio) number of bytes we can write now + * + * ..._read_request is never more than ..._write_guarantee; + * it depends on the application which one you should use. + */ + + /* We have non-blocking behaviour throughout this test program, but + * can be sure that there is *some* progress in each iteration; so + * we don't have to worry about ..._SHOULD_READ or ..._SHOULD_WRITE + * -- we just try everything in each iteration + */ + + { + /* CLIENT */ + + MS_STATIC char cbuf[1024*8]; + int i, r; + clock_t c_clock = clock(); + + memset(cbuf, 0, sizeof(cbuf)); + + if (debug) + if (SSL_in_init(c_ssl)) + printf("client waiting in SSL_connect - %s\n", + SSL_state_string_long(c_ssl)); + + if (cw_num > 0) + { + /* Write to server. */ + + if (cw_num > (long)sizeof cbuf) + i = sizeof cbuf; + else + i = (int)cw_num; + r = BIO_write(c_ssl_bio, cbuf, i); + if (r < 0) + { + if (!BIO_should_retry(c_ssl_bio)) + { + fprintf(stderr,"ERROR in CLIENT\n"); + goto err; + } + /* BIO_should_retry(...) can just be ignored here. + * The library expects us to call BIO_write with + * the same arguments again, and that's what we will + * do in the next iteration. */ + } + else if (r == 0) + { + fprintf(stderr,"SSL CLIENT STARTUP FAILED\n"); + goto err; + } + else + { + if (debug) + printf("client wrote %d\n", r); + cw_num -= r; + } + } + + if (cr_num > 0) + { + /* Read from server. */ + + r = BIO_read(c_ssl_bio, cbuf, sizeof(cbuf)); + if (r < 0) + { + if (!BIO_should_retry(c_ssl_bio)) + { + fprintf(stderr,"ERROR in CLIENT\n"); + goto err; + } + /* Again, "BIO_should_retry" can be ignored. */ + } + else if (r == 0) + { + fprintf(stderr,"SSL CLIENT STARTUP FAILED\n"); + goto err; + } + else + { + if (debug) + printf("client read %d\n", r); + cr_num -= r; + } + } + + /* c_time and s_time increments will typically be very small + * (depending on machine speed and clock tick intervals), + * but sampling over a large number of connections should + * result in fairly accurate figures. We cannot guarantee + * a lot, however -- if each connection lasts for exactly + * one clock tick, it will be counted only for the client + * or only for the server or even not at all. + */ + *c_time += (clock() - c_clock); + } + + { + /* SERVER */ + + MS_STATIC char sbuf[1024*8]; + int i, r; + clock_t s_clock = clock(); + + memset(sbuf, 0, sizeof(sbuf)); + + if (debug) + if (SSL_in_init(s_ssl)) + printf("server waiting in SSL_accept - %s\n", + SSL_state_string_long(s_ssl)); + + if (sw_num > 0) + { + /* Write to client. */ + + if (sw_num > (long)sizeof sbuf) + i = sizeof sbuf; + else + i = (int)sw_num; + r = BIO_write(s_ssl_bio, sbuf, i); + if (r < 0) + { + if (!BIO_should_retry(s_ssl_bio)) + { + fprintf(stderr,"ERROR in SERVER\n"); + goto err; + } + /* Ignore "BIO_should_retry". */ + } + else if (r == 0) + { + fprintf(stderr,"SSL SERVER STARTUP FAILED\n"); + goto err; + } + else + { + if (debug) + printf("server wrote %d\n", r); + sw_num -= r; + } + } + + if (sr_num > 0) + { + /* Read from client. */ + + r = BIO_read(s_ssl_bio, sbuf, sizeof(sbuf)); + if (r < 0) + { + if (!BIO_should_retry(s_ssl_bio)) + { + fprintf(stderr,"ERROR in SERVER\n"); + goto err; + } + /* blah, blah */ + } + else if (r == 0) + { + fprintf(stderr,"SSL SERVER STARTUP FAILED\n"); + goto err; + } + else + { + if (debug) + printf("server read %d\n", r); + sr_num -= r; + } + } + + *s_time += (clock() - s_clock); + } + + { + /* "I/O" BETWEEN CLIENT AND SERVER. */ + + size_t r1, r2; + BIO *io1 = server_io, *io2 = client_io; + /* we use the non-copying interface for io1 + * and the standard BIO_write/BIO_read interface for io2 + */ + + static int prev_progress = 1; + int progress = 0; + + /* io1 to io2 */ + do + { + size_t num; + int r; + + r1 = BIO_ctrl_pending(io1); + r2 = BIO_ctrl_get_write_guarantee(io2); + + num = r1; + if (r2 < num) + num = r2; + if (num) + { + char *dataptr; + + if (INT_MAX < num) /* yeah, right */ + num = INT_MAX; + + r = BIO_nread(io1, &dataptr, (int)num); + assert(r > 0); + assert(r <= (int)num); + /* possibly r < num (non-contiguous data) */ + num = r; + r = BIO_write(io2, dataptr, (int)num); + if (r != (int)num) /* can't happen */ + { + fprintf(stderr, "ERROR: BIO_write could not write " + "BIO_ctrl_get_write_guarantee() bytes"); + goto err; + } + progress = 1; + + if (debug) + printf((io1 == client_io) ? + "C->S relaying: %d bytes\n" : + "S->C relaying: %d bytes\n", + (int)num); + } + } + while (r1 && r2); + + /* io2 to io1 */ + { + size_t num; + int r; + + r1 = BIO_ctrl_pending(io2); + r2 = BIO_ctrl_get_read_request(io1); + /* here we could use ..._get_write_guarantee instead of + * ..._get_read_request, but by using the latter + * we test restartability of the SSL implementation + * more thoroughly */ + num = r1; + if (r2 < num) + num = r2; + if (num) + { + char *dataptr; + + if (INT_MAX < num) + num = INT_MAX; + + if (num > 1) + --num; /* test restartability even more thoroughly */ + + r = BIO_nwrite0(io1, &dataptr); + assert(r > 0); + if (r < (int)num) + num = r; + r = BIO_read(io2, dataptr, (int)num); + if (r != (int)num) /* can't happen */ + { + fprintf(stderr, "ERROR: BIO_read could not read " + "BIO_ctrl_pending() bytes"); + goto err; + } + progress = 1; + r = BIO_nwrite(io1, &dataptr, (int)num); + if (r != (int)num) /* can't happen */ + { + fprintf(stderr, "ERROR: BIO_nwrite() did not accept " + "BIO_nwrite0() bytes"); + goto err; + } + + if (debug) + printf((io2 == client_io) ? + "C->S relaying: %d bytes\n" : + "S->C relaying: %d bytes\n", + (int)num); + } + } /* no loop, BIO_ctrl_get_read_request now returns 0 anyway */ + + if (!progress && !prev_progress) + if (cw_num > 0 || cr_num > 0 || sw_num > 0 || sr_num > 0) + { + fprintf(stderr, "ERROR: got stuck\n"); + if (strcmp("SSLv2", SSL_get_version(c_ssl)) == 0) + { + fprintf(stderr, "This can happen for SSL2 because " + "CLIENT-FINISHED and SERVER-VERIFY are written \n" + "concurrently ..."); + if (strncmp("2SCF", SSL_state_string(c_ssl), 4) == 0 + && strncmp("2SSV", SSL_state_string(s_ssl), 4) == 0) + { + fprintf(stderr, " ok.\n"); + goto end; + } + } + fprintf(stderr, " ERROR.\n"); + goto err; + } + prev_progress = progress; + } + } + while (cw_num > 0 || cr_num > 0 || sw_num > 0 || sr_num > 0); + + if (verbose) + print_details(c_ssl, "DONE via BIO pair: "); +end: + ret = 0; + + err: + ERR_print_errors(bio_err); + + if (server) + BIO_free(server); + if (server_io) + BIO_free(server_io); + if (client) + BIO_free(client); + if (client_io) + BIO_free(client_io); + if (s_ssl_bio) + BIO_free(s_ssl_bio); + if (c_ssl_bio) + BIO_free(c_ssl_bio); + + return ret; + } + + +#define W_READ 1 +#define W_WRITE 2 +#define C_DONE 1 +#define S_DONE 2 + +int doit(SSL *s_ssl, SSL *c_ssl, long count) + { + MS_STATIC char cbuf[1024*8],sbuf[1024*8]; + long cw_num=count,cr_num=count; + long sw_num=count,sr_num=count; + int ret=1; + BIO *c_to_s=NULL; + BIO *s_to_c=NULL; + BIO *c_bio=NULL; + BIO *s_bio=NULL; + int c_r,c_w,s_r,s_w; + int i,j; + int done=0; + int c_write,s_write; + int do_server=0,do_client=0; + + memset(cbuf,0,sizeof(cbuf)); + memset(sbuf,0,sizeof(sbuf)); + + c_to_s=BIO_new(BIO_s_mem()); + s_to_c=BIO_new(BIO_s_mem()); + if ((s_to_c == NULL) || (c_to_s == NULL)) + { + ERR_print_errors(bio_err); + goto err; + } + + c_bio=BIO_new(BIO_f_ssl()); + s_bio=BIO_new(BIO_f_ssl()); + if ((c_bio == NULL) || (s_bio == NULL)) + { + ERR_print_errors(bio_err); + goto err; + } + + SSL_set_connect_state(c_ssl); + SSL_set_bio(c_ssl,s_to_c,c_to_s); + BIO_set_ssl(c_bio,c_ssl,BIO_NOCLOSE); + + 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_NOCLOSE); + + c_r=0; s_r=1; + c_w=1; s_w=0; + c_write=1,s_write=0; + + /* We can always do writes */ + for (;;) + { + do_server=0; + do_client=0; + + i=(int)BIO_pending(s_bio); + if ((i && s_r) || s_w) do_server=1; + + i=(int)BIO_pending(c_bio); + if ((i && c_r) || c_w) do_client=1; + + if (do_server && debug) + { + if (SSL_in_init(s_ssl)) + printf("server waiting in SSL_accept - %s\n", + SSL_state_string_long(s_ssl)); +/* else if (s_write) + printf("server:SSL_write()\n"); + else + printf("server:SSL_read()\n"); */ + } + + if (do_client && debug) + { + if (SSL_in_init(c_ssl)) + printf("client waiting in SSL_connect - %s\n", + SSL_state_string_long(c_ssl)); +/* else if (c_write) + printf("client:SSL_write()\n"); + else + printf("client:SSL_read()\n"); */ + } + + if (!do_client && !do_server) + { + fprintf(stdout,"ERROR IN STARTUP\n"); + ERR_print_errors(bio_err); + break; + } + if (do_client && !(done & C_DONE)) + { + if (c_write) + { + j = (cw_num > (long)sizeof(cbuf)) ? + (int)sizeof(cbuf) : (int)cw_num; + i=BIO_write(c_bio,cbuf,j); + if (i < 0) + { + c_r=0; + c_w=0; + if (BIO_should_retry(c_bio)) + { + if (BIO_should_read(c_bio)) + c_r=1; + if (BIO_should_write(c_bio)) + c_w=1; + } + else + { + fprintf(stderr,"ERROR in CLIENT\n"); + ERR_print_errors(bio_err); + goto err; + } + } + else if (i == 0) + { + fprintf(stderr,"SSL CLIENT STARTUP FAILED\n"); + goto err; + } + else + { + if (debug) + printf("client wrote %d\n",i); + /* ok */ + s_r=1; + c_write=0; + cw_num-=i; + } + } + else + { + i=BIO_read(c_bio,cbuf,sizeof(cbuf)); + if (i < 0) + { + c_r=0; + c_w=0; + if (BIO_should_retry(c_bio)) + { + if (BIO_should_read(c_bio)) + c_r=1; + if (BIO_should_write(c_bio)) + c_w=1; + } + else + { + fprintf(stderr,"ERROR in CLIENT\n"); + ERR_print_errors(bio_err); + goto err; + } + } + else if (i == 0) + { + fprintf(stderr,"SSL CLIENT STARTUP FAILED\n"); + goto err; + } + else + { + if (debug) + printf("client read %d\n",i); + cr_num-=i; + if (sw_num > 0) + { + s_write=1; + s_w=1; + } + if (cr_num <= 0) + { + s_write=1; + s_w=1; + done=S_DONE|C_DONE; + } + } + } + } + + if (do_server && !(done & S_DONE)) + { + if (!s_write) + { + i=BIO_read(s_bio,sbuf,sizeof(cbuf)); + if (i < 0) + { + s_r=0; + s_w=0; + if (BIO_should_retry(s_bio)) + { + if (BIO_should_read(s_bio)) + s_r=1; + if (BIO_should_write(s_bio)) + s_w=1; + } + else + { + fprintf(stderr,"ERROR in SERVER\n"); + ERR_print_errors(bio_err); + goto err; + } + } + else if (i == 0) + { + ERR_print_errors(bio_err); + fprintf(stderr,"SSL SERVER STARTUP FAILED in SSL_read\n"); + goto err; + } + else + { + if (debug) + printf("server read %d\n",i); + sr_num-=i; + if (cw_num > 0) + { + c_write=1; + c_w=1; + } + if (sr_num <= 0) + { + s_write=1; + s_w=1; + c_write=0; + } + } + } + else + { + j = (sw_num > (long)sizeof(sbuf)) ? + (int)sizeof(sbuf) : (int)sw_num; + i=BIO_write(s_bio,sbuf,j); + if (i < 0) + { + s_r=0; + s_w=0; + if (BIO_should_retry(s_bio)) + { + if (BIO_should_read(s_bio)) + s_r=1; + if (BIO_should_write(s_bio)) + s_w=1; + } + else + { + fprintf(stderr,"ERROR in SERVER\n"); + ERR_print_errors(bio_err); + goto err; + } + } + else if (i == 0) + { + ERR_print_errors(bio_err); + fprintf(stderr,"SSL SERVER STARTUP FAILED in SSL_write\n"); + goto err; + } + else + { + if (debug) + printf("server wrote %d\n",i); + sw_num-=i; + s_write=0; + c_r=1; + if (sw_num <= 0) + done|=S_DONE; + } + } + } + + if ((done & S_DONE) && (done & C_DONE)) break; + } + + if (verbose) + print_details(c_ssl, "DONE: "); + ret=0; +err: + /* We have to set the BIO's to NULL otherwise they will be + * OPENSSL_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 */ + if (s_ssl != NULL) + { + s_ssl->rbio=NULL; + s_ssl->wbio=NULL; + } + if (c_ssl != NULL) + { + c_ssl->rbio=NULL; + c_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_all(c_bio); + if (s_bio != NULL) BIO_free_all(s_bio); + return(ret); + } + +static int get_proxy_auth_ex_data_idx(void) + { + static volatile int idx = -1; + if (idx < 0) + { + CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); + if (idx < 0) + { + idx = X509_STORE_CTX_get_ex_new_index(0, + "SSLtest for verify callback", NULL,NULL,NULL); + } + CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); + } + return idx; + } + +static int MS_CALLBACK verify_callback(int ok, X509_STORE_CTX *ctx) + { + char *s,buf[256]; + + s=X509_NAME_oneline(X509_get_subject_name(ctx->current_cert),buf, + sizeof buf); + if (s != NULL) + { + if (ok) + fprintf(stderr,"depth=%d %s\n", + ctx->error_depth,buf); + else + { + fprintf(stderr,"depth=%d error=%d %s\n", + ctx->error_depth,ctx->error,buf); + } + } + + if (ok == 0) + { + fprintf(stderr,"Error string: %s\n", + X509_verify_cert_error_string(ctx->error)); + switch (ctx->error) + { + case X509_V_ERR_CERT_NOT_YET_VALID: + case X509_V_ERR_CERT_HAS_EXPIRED: + case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: + fprintf(stderr," ... ignored.\n"); + ok=1; + } + } + + if (ok == 1) + { + X509 *xs = ctx->current_cert; +#if 0 + X509 *xi = ctx->current_issuer; +#endif + + if (xs->ex_flags & EXFLAG_PROXY) + { + unsigned int *letters = + X509_STORE_CTX_get_ex_data(ctx, + get_proxy_auth_ex_data_idx()); + + if (letters) + { + int found_any = 0; + int i; + PROXY_CERT_INFO_EXTENSION *pci = + X509_get_ext_d2i(xs, NID_proxyCertInfo, + NULL, NULL); + + switch (OBJ_obj2nid(pci->proxyPolicy->policyLanguage)) + { + case NID_Independent: + /* Completely meaningless in this + program, as there's no way to + grant explicit rights to a + specific PrC. Basically, using + id-ppl-Independent is the perfect + way to grant no rights at all. */ + fprintf(stderr, " Independent proxy certificate"); + for (i = 0; i < 26; i++) + letters[i] = 0; + break; + case NID_id_ppl_inheritAll: + /* This is basically a NOP, we + simply let the current rights + stand as they are. */ + fprintf(stderr, " Proxy certificate inherits all"); + break; + default: + s = (char *) + pci->proxyPolicy->policy->data; + i = pci->proxyPolicy->policy->length; + + /* The algorithm works as follows: + it is assumed that previous + iterations or the initial granted + rights has already set some elements + of `letters'. What we need to do is + to clear those that weren't granted + by the current PrC as well. The + easiest way to do this is to add 1 + to all the elements whose letters + are given with the current policy. + That way, all elements that are set + by the current policy and were + already set by earlier policies and + through the original grant of rights + will get the value 2 or higher. + The last thing to do is to sweep + through `letters' and keep the + elements having the value 2 as set, + and clear all the others. */ + + fprintf(stderr, " Certificate proxy rights = %*.*s", i, i, s); + while(i-- > 0) + { + int c = *s++; + if (isascii(c) && isalpha(c)) + { + if (islower(c)) + c = toupper(c); + letters[c - 'A']++; + } + } + for (i = 0; i < 26; i++) + if (letters[i] < 2) + letters[i] = 0; + else + letters[i] = 1; + } + + found_any = 0; + fprintf(stderr, + ", resulting proxy rights = "); + for(i = 0; i < 26; i++) + if (letters[i]) + { + fprintf(stderr, "%c", i + 'A'); + found_any = 1; + } + if (!found_any) + fprintf(stderr, "none"); + fprintf(stderr, "\n"); + + PROXY_CERT_INFO_EXTENSION_free(pci); + } + } + } + + return(ok); + } + +static void process_proxy_debug(int indent, const char *format, ...) + { + static const char indentation[] = + ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" + ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"; /* That's 80 > */ + char my_format[256]; + va_list args; + + BIO_snprintf(my_format, sizeof(my_format), "%*.*s %s", + indent, indent, indentation, format); + + va_start(args, format); + vfprintf(stderr, my_format, args); + va_end(args); + } +/* Priority levels: + 0 [!]var, () + 1 & ^ + 2 | +*/ +static int process_proxy_cond_adders(unsigned int letters[26], + const char *cond, const char **cond_end, int *pos, int indent); +static int process_proxy_cond_val(unsigned int letters[26], + const char *cond, const char **cond_end, int *pos, int indent) + { + int c; + int ok = 1; + int negate = 0; + + while(isspace((int)*cond)) + { + cond++; (*pos)++; + } + c = *cond; + + if (debug) + process_proxy_debug(indent, + "Start process_proxy_cond_val at position %d: %s\n", + *pos, cond); + + while(c == '!') + { + negate = !negate; + cond++; (*pos)++; + while(isspace((int)*cond)) + { + cond++; (*pos)++; + } + c = *cond; + } + + if (c == '(') + { + cond++; (*pos)++; + ok = process_proxy_cond_adders(letters, cond, cond_end, pos, + indent + 1); + cond = *cond_end; + if (ok < 0) + goto end; + while(isspace((int)*cond)) + { + cond++; (*pos)++; + } + c = *cond; + if (c != ')') + { + fprintf(stderr, + "Weird condition character in position %d: " + "%c\n", *pos, c); + ok = -1; + goto end; + } + cond++; (*pos)++; + } + else if (isascii(c) && isalpha(c)) + { + if (islower(c)) + c = toupper(c); + ok = letters[c - 'A']; + cond++; (*pos)++; + } + else + { + fprintf(stderr, + "Weird condition character in position %d: " + "%c\n", *pos, c); + ok = -1; + goto end; + } + end: + *cond_end = cond; + if (ok >= 0 && negate) + ok = !ok; + + if (debug) + process_proxy_debug(indent, + "End process_proxy_cond_val at position %d: %s, returning %d\n", + *pos, cond, ok); + + return ok; + } +static int process_proxy_cond_multipliers(unsigned int letters[26], + const char *cond, const char **cond_end, int *pos, int indent) + { + int ok; + char c; + + if (debug) + process_proxy_debug(indent, + "Start process_proxy_cond_multipliers at position %d: %s\n", + *pos, cond); + + ok = process_proxy_cond_val(letters, cond, cond_end, pos, indent + 1); + cond = *cond_end; + if (ok < 0) + goto end; + + while(ok >= 0) + { + while(isspace((int)*cond)) + { + cond++; (*pos)++; + } + c = *cond; + + switch(c) + { + case '&': + case '^': + { + int save_ok = ok; + + cond++; (*pos)++; + ok = process_proxy_cond_val(letters, + cond, cond_end, pos, indent + 1); + cond = *cond_end; + if (ok < 0) + break; + + switch(c) + { + case '&': + ok &= save_ok; + break; + case '^': + ok ^= save_ok; + break; + default: + fprintf(stderr, "SOMETHING IS SERIOUSLY WRONG!" + " STOPPING\n"); + EXIT(1); + } + } + break; + default: + goto end; + } + } + end: + if (debug) + process_proxy_debug(indent, + "End process_proxy_cond_multipliers at position %d: %s, returning %d\n", + *pos, cond, ok); + + *cond_end = cond; + return ok; + } +static int process_proxy_cond_adders(unsigned int letters[26], + const char *cond, const char **cond_end, int *pos, int indent) + { + int ok; + char c; + + if (debug) + process_proxy_debug(indent, + "Start process_proxy_cond_adders at position %d: %s\n", + *pos, cond); + + ok = process_proxy_cond_multipliers(letters, cond, cond_end, pos, + indent + 1); + cond = *cond_end; + if (ok < 0) + goto end; + + while(ok >= 0) + { + while(isspace((int)*cond)) + { + cond++; (*pos)++; + } + c = *cond; + + switch(c) + { + case '|': + { + int save_ok = ok; + + cond++; (*pos)++; + ok = process_proxy_cond_multipliers(letters, + cond, cond_end, pos, indent + 1); + cond = *cond_end; + if (ok < 0) + break; + + switch(c) + { + case '|': + ok |= save_ok; + break; + default: + fprintf(stderr, "SOMETHING IS SERIOUSLY WRONG!" + " STOPPING\n"); + EXIT(1); + } + } + break; + default: + goto end; + } + } + end: + if (debug) + process_proxy_debug(indent, + "End process_proxy_cond_adders at position %d: %s, returning %d\n", + *pos, cond, ok); + + *cond_end = cond; + return ok; + } + +static int process_proxy_cond(unsigned int letters[26], + const char *cond, const char **cond_end) + { + int pos = 1; + return process_proxy_cond_adders(letters, cond, cond_end, &pos, 1); + } + +static int MS_CALLBACK app_verify_callback(X509_STORE_CTX *ctx, void *arg) + { + int ok=1; + struct app_verify_arg *cb_arg = arg; + unsigned int letters[26]; /* only used with proxy_auth */ + + if (cb_arg->app_verify) + { + char *s = NULL,buf[256]; + + fprintf(stderr, "In app_verify_callback, allowing cert. "); + fprintf(stderr, "Arg is: %s\n", cb_arg->string); + fprintf(stderr, "Finished printing do we have a context? 0x%p a cert? 0x%p\n", + (void *)ctx, (void *)ctx->cert); + if (ctx->cert) + s=X509_NAME_oneline(X509_get_subject_name(ctx->cert),buf,256); + if (s != NULL) + { + fprintf(stderr,"cert depth=%d %s\n",ctx->error_depth,buf); + } + return(1); + } + if (cb_arg->proxy_auth) + { + int found_any = 0, i; + char *sp; + + for(i = 0; i < 26; i++) + letters[i] = 0; + for(sp = cb_arg->proxy_auth; *sp; sp++) + { + int c = *sp; + if (isascii(c) && isalpha(c)) + { + if (islower(c)) + c = toupper(c); + letters[c - 'A'] = 1; + } + } + + fprintf(stderr, + " Initial proxy rights = "); + for(i = 0; i < 26; i++) + if (letters[i]) + { + fprintf(stderr, "%c", i + 'A'); + found_any = 1; + } + if (!found_any) + fprintf(stderr, "none"); + fprintf(stderr, "\n"); + + X509_STORE_CTX_set_ex_data(ctx, + get_proxy_auth_ex_data_idx(),letters); + } + if (cb_arg->allow_proxy_certs) + { + X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_ALLOW_PROXY_CERTS); + } + +#ifndef OPENSSL_NO_X509_VERIFY + ok = X509_verify_cert(ctx); +#endif + + if (cb_arg->proxy_auth) + { + if (ok > 0) + { + const char *cond_end = NULL; + + ok = process_proxy_cond(letters, + cb_arg->proxy_cond, &cond_end); + + if (ok < 0) + EXIT(3); + if (*cond_end) + { + fprintf(stderr, "Stopped processing condition before it's end.\n"); + ok = 0; + } + if (!ok) + fprintf(stderr, "Proxy rights check with condition '%s' proved invalid\n", + cb_arg->proxy_cond); + else + fprintf(stderr, "Proxy rights check with condition '%s' proved valid\n", + cb_arg->proxy_cond); + } + } + return(ok); + } + +#ifndef OPENSSL_NO_RSA +static RSA *rsa_tmp=NULL; + +static RSA MS_CALLBACK *tmp_rsa_cb(SSL *s, int is_export, int keylength) + { + BIGNUM *bn = NULL; + if (rsa_tmp == NULL) + { + bn = BN_new(); + rsa_tmp = RSA_new(); + if(!bn || !rsa_tmp || !BN_set_word(bn, RSA_F4)) + { + BIO_printf(bio_err, "Memory error..."); + goto end; + } + BIO_printf(bio_err,"Generating temp (%d bit) RSA key...",keylength); + (void)BIO_flush(bio_err); + if(!RSA_generate_key_ex(rsa_tmp,keylength,bn,NULL)) + { + BIO_printf(bio_err, "Error generating key."); + RSA_free(rsa_tmp); + rsa_tmp = NULL; + } +end: + BIO_printf(bio_err,"\n"); + (void)BIO_flush(bio_err); + } + if(bn) BN_free(bn); + return(rsa_tmp); + } + +static void free_tmp_rsa(void) + { + if (rsa_tmp != NULL) + { + RSA_free(rsa_tmp); + rsa_tmp = NULL; + } + } +#endif + +#ifndef OPENSSL_NO_DH +/* These DH parameters have been generated as follows: + * $ openssl dhparam -C -noout 512 + * $ openssl dhparam -C -noout 1024 + * $ openssl dhparam -C -noout -dsaparam 1024 + * (The third function has been renamed to avoid name conflicts.) + */ +static DH *get_dh512() + { + static unsigned char dh512_p[]={ + 0xCB,0xC8,0xE1,0x86,0xD0,0x1F,0x94,0x17,0xA6,0x99,0xF0,0xC6, + 0x1F,0x0D,0xAC,0xB6,0x25,0x3E,0x06,0x39,0xCA,0x72,0x04,0xB0, + 0x6E,0xDA,0xC0,0x61,0xE6,0x7A,0x77,0x25,0xE8,0x3B,0xB9,0x5F, + 0x9A,0xB6,0xB5,0xFE,0x99,0x0B,0xA1,0x93,0x4E,0x35,0x33,0xB8, + 0xE1,0xF1,0x13,0x4F,0x59,0x1A,0xD2,0x57,0xC0,0x26,0x21,0x33, + 0x02,0xC5,0xAE,0x23, + }; + static unsigned char dh512_g[]={ + 0x02, + }; + DH *dh; + + if ((dh=DH_new()) == NULL) return(NULL); + dh->p=BN_bin2bn(dh512_p,sizeof(dh512_p),NULL); + dh->g=BN_bin2bn(dh512_g,sizeof(dh512_g),NULL); + if ((dh->p == NULL) || (dh->g == NULL)) + { DH_free(dh); return(NULL); } + return(dh); + } + +static DH *get_dh1024() + { + static unsigned char dh1024_p[]={ + 0xF8,0x81,0x89,0x7D,0x14,0x24,0xC5,0xD1,0xE6,0xF7,0xBF,0x3A, + 0xE4,0x90,0xF4,0xFC,0x73,0xFB,0x34,0xB5,0xFA,0x4C,0x56,0xA2, + 0xEA,0xA7,0xE9,0xC0,0xC0,0xCE,0x89,0xE1,0xFA,0x63,0x3F,0xB0, + 0x6B,0x32,0x66,0xF1,0xD1,0x7B,0xB0,0x00,0x8F,0xCA,0x87,0xC2, + 0xAE,0x98,0x89,0x26,0x17,0xC2,0x05,0xD2,0xEC,0x08,0xD0,0x8C, + 0xFF,0x17,0x52,0x8C,0xC5,0x07,0x93,0x03,0xB1,0xF6,0x2F,0xB8, + 0x1C,0x52,0x47,0x27,0x1B,0xDB,0xD1,0x8D,0x9D,0x69,0x1D,0x52, + 0x4B,0x32,0x81,0xAA,0x7F,0x00,0xC8,0xDC,0xE6,0xD9,0xCC,0xC1, + 0x11,0x2D,0x37,0x34,0x6C,0xEA,0x02,0x97,0x4B,0x0E,0xBB,0xB1, + 0x71,0x33,0x09,0x15,0xFD,0xDD,0x23,0x87,0x07,0x5E,0x89,0xAB, + 0x6B,0x7C,0x5F,0xEC,0xA6,0x24,0xDC,0x53, + }; + static unsigned char dh1024_g[]={ + 0x02, + }; + DH *dh; + + if ((dh=DH_new()) == NULL) return(NULL); + dh->p=BN_bin2bn(dh1024_p,sizeof(dh1024_p),NULL); + dh->g=BN_bin2bn(dh1024_g,sizeof(dh1024_g),NULL); + if ((dh->p == NULL) || (dh->g == NULL)) + { DH_free(dh); return(NULL); } + return(dh); + } + +static DH *get_dh1024dsa() + { + static unsigned char dh1024_p[]={ + 0xC8,0x00,0xF7,0x08,0x07,0x89,0x4D,0x90,0x53,0xF3,0xD5,0x00, + 0x21,0x1B,0xF7,0x31,0xA6,0xA2,0xDA,0x23,0x9A,0xC7,0x87,0x19, + 0x3B,0x47,0xB6,0x8C,0x04,0x6F,0xFF,0xC6,0x9B,0xB8,0x65,0xD2, + 0xC2,0x5F,0x31,0x83,0x4A,0xA7,0x5F,0x2F,0x88,0x38,0xB6,0x55, + 0xCF,0xD9,0x87,0x6D,0x6F,0x9F,0xDA,0xAC,0xA6,0x48,0xAF,0xFC, + 0x33,0x84,0x37,0x5B,0x82,0x4A,0x31,0x5D,0xE7,0xBD,0x52,0x97, + 0xA1,0x77,0xBF,0x10,0x9E,0x37,0xEA,0x64,0xFA,0xCA,0x28,0x8D, + 0x9D,0x3B,0xD2,0x6E,0x09,0x5C,0x68,0xC7,0x45,0x90,0xFD,0xBB, + 0x70,0xC9,0x3A,0xBB,0xDF,0xD4,0x21,0x0F,0xC4,0x6A,0x3C,0xF6, + 0x61,0xCF,0x3F,0xD6,0x13,0xF1,0x5F,0xBC,0xCF,0xBC,0x26,0x9E, + 0xBC,0x0B,0xBD,0xAB,0x5D,0xC9,0x54,0x39, + }; + static unsigned char dh1024_g[]={ + 0x3B,0x40,0x86,0xE7,0xF3,0x6C,0xDE,0x67,0x1C,0xCC,0x80,0x05, + 0x5A,0xDF,0xFE,0xBD,0x20,0x27,0x74,0x6C,0x24,0xC9,0x03,0xF3, + 0xE1,0x8D,0xC3,0x7D,0x98,0x27,0x40,0x08,0xB8,0x8C,0x6A,0xE9, + 0xBB,0x1A,0x3A,0xD6,0x86,0x83,0x5E,0x72,0x41,0xCE,0x85,0x3C, + 0xD2,0xB3,0xFC,0x13,0xCE,0x37,0x81,0x9E,0x4C,0x1C,0x7B,0x65, + 0xD3,0xE6,0xA6,0x00,0xF5,0x5A,0x95,0x43,0x5E,0x81,0xCF,0x60, + 0xA2,0x23,0xFC,0x36,0xA7,0x5D,0x7A,0x4C,0x06,0x91,0x6E,0xF6, + 0x57,0xEE,0x36,0xCB,0x06,0xEA,0xF5,0x3D,0x95,0x49,0xCB,0xA7, + 0xDD,0x81,0xDF,0x80,0x09,0x4A,0x97,0x4D,0xA8,0x22,0x72,0xA1, + 0x7F,0xC4,0x70,0x56,0x70,0xE8,0x20,0x10,0x18,0x8F,0x2E,0x60, + 0x07,0xE7,0x68,0x1A,0x82,0x5D,0x32,0xA2, + }; + DH *dh; + + if ((dh=DH_new()) == NULL) return(NULL); + dh->p=BN_bin2bn(dh1024_p,sizeof(dh1024_p),NULL); + dh->g=BN_bin2bn(dh1024_g,sizeof(dh1024_g),NULL); + if ((dh->p == NULL) || (dh->g == NULL)) + { DH_free(dh); return(NULL); } + dh->length = 160; + return(dh); + } +#endif + +#ifndef OPENSSL_NO_PSK +/* convert the PSK key (psk_key) in ascii to binary (psk) */ +static int psk_key2bn(const char *pskkey, unsigned char *psk, + unsigned int max_psk_len) + { + int ret; + BIGNUM *bn = NULL; + + ret = BN_hex2bn(&bn, pskkey); + if (!ret) + { + BIO_printf(bio_err,"Could not convert PSK key '%s' to BIGNUM\n", pskkey); + if (bn) + BN_free(bn); + return 0; + } + if (BN_num_bytes(bn) > (int)max_psk_len) + { + BIO_printf(bio_err,"psk buffer of callback is too small (%d) for key (%d)\n", + max_psk_len, BN_num_bytes(bn)); + BN_free(bn); + return 0; + } + ret = BN_bn2bin(bn, psk); + BN_free(bn); + return ret; + } + +static unsigned int psk_client_callback(SSL *ssl, const char *hint, char *identity, + unsigned int max_identity_len, unsigned char *psk, + unsigned int max_psk_len) + { + int ret; + unsigned int psk_len = 0; + + ret = BIO_snprintf(identity, max_identity_len, "Client_identity"); + if (ret < 0) + goto out_err; + if (debug) + fprintf(stderr, "client: created identity '%s' len=%d\n", identity, ret); + ret = psk_key2bn(psk_key, psk, max_psk_len); + if (ret < 0) + goto out_err; + psk_len = ret; +out_err: + return psk_len; + } + +static unsigned int psk_server_callback(SSL *ssl, const char *identity, + unsigned char *psk, unsigned int max_psk_len) + { + unsigned int psk_len=0; + + if (strcmp(identity, "Client_identity") != 0) + { + BIO_printf(bio_err, "server: PSK error: client identity not found\n"); + return 0; + } + psk_len=psk_key2bn(psk_key, psk, max_psk_len); + return psk_len; + } +#endif + +static int do_test_cipherlist(void) + { + int i = 0; + const SSL_METHOD *meth; + const SSL_CIPHER *ci, *tci = NULL; + +#ifndef OPENSSL_NO_SSL2 + fprintf(stderr, "testing SSLv2 cipher list order: "); + meth = SSLv2_method(); + while ((ci = meth->get_cipher(i++)) != NULL) + { + if (tci != NULL) + if (ci->id >= tci->id) + { + fprintf(stderr, "failed %lx vs. %lx\n", ci->id, tci->id); + return 0; + } + tci = ci; + } + fprintf(stderr, "ok\n"); +#endif +#ifndef OPENSSL_NO_SSL3 + fprintf(stderr, "testing SSLv3 cipher list order: "); + meth = SSLv3_method(); + tci = NULL; + while ((ci = meth->get_cipher(i++)) != NULL) + { + if (tci != NULL) + if (ci->id >= tci->id) + { + fprintf(stderr, "failed %lx vs. %lx\n", ci->id, tci->id); + return 0; + } + tci = ci; + } + fprintf(stderr, "ok\n"); +#endif +#ifndef OPENSSL_NO_TLS1 + fprintf(stderr, "testing TLSv1 cipher list order: "); + meth = TLSv1_method(); + tci = NULL; + while ((ci = meth->get_cipher(i++)) != NULL) + { + if (tci != NULL) + if (ci->id >= tci->id) + { + fprintf(stderr, "failed %lx vs. %lx\n", ci->id, tci->id); + return 0; + } + tci = ci; + } + fprintf(stderr, "ok\n"); +#endif + + return 1; + } diff --git a/drivers/builtin_openssl2/ssl/t1_clnt.c b/drivers/builtin_openssl2/ssl/t1_clnt.c new file mode 100644 index 0000000000..578617ed84 --- /dev/null +++ b/drivers/builtin_openssl2/ssl/t1_clnt.c @@ -0,0 +1,92 @@ +/* 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) + +IMPLEMENT_tls_meth_func(TLS1_1_VERSION, TLSv1_1_client_method, + ssl_undefined_function, + ssl3_connect, + tls1_get_client_method) + +IMPLEMENT_tls_meth_func(TLS1_VERSION, TLSv1_client_method, + ssl_undefined_function, + ssl3_connect, + tls1_get_client_method) + diff --git a/drivers/builtin_openssl2/ssl/t1_enc.c b/drivers/builtin_openssl2/ssl/t1_enc.c new file mode 100644 index 0000000000..ac8c153996 --- /dev/null +++ b/drivers/builtin_openssl2/ssl/t1_enc.c @@ -0,0 +1,1250 @@ +/* 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; + 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_set_flags(&ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); + EVP_MD_CTX_set_flags(&ctx_tmp, 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,NULL,md, NULL, mac_key)) + goto err; + if (!EVP_DigestSignInit(&ctx_tmp,NULL,md, NULL, mac_key)) + 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_DigestSignInit(&ctx,NULL,md, NULL, mac_key)) + goto err; + if (!EVP_DigestSignInit(&ctx_tmp,NULL,md, NULL, mac_key)) + goto err; + if (!EVP_DigestSignUpdate(&ctx,A1,A1_len)) + goto err; + if (!EVP_DigestSignUpdate(&ctx_tmp,A1,A1_len)) + 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); + 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++; + } + 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 + printf("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++) + { + printf("%02X", s->session->master_key[i]); + } + printf("\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 + printf("tls1_change_cipher_state(which= %d) w/\n", which); + printf("\talg= %ld/%ld, comp= %p\n", + s->s3->tmp.new_cipher->algorithm_mkey, + s->s3->tmp.new_cipher->algorithm_auth, + comp); + printf("\tevp_cipher == %p ==? &d_cbc_ede_cipher3\n", c); + printf("\tevp_cipher: nid, blksz= %d, %d, keylen=%d, ivlen=%d\n", + c->nid,c->block_size,c->key_len,c->iv_len); + printf("\tkey_block: len= %d, data= ", s->s3->tmp.key_block_length); + { + int i; + for (i=0; i<s->s3->tmp.key_block_length; i++) + printf("%02x", s->s3->tmp.key_block[i]); printf("\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); +#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 DTLS1_VERSION */ + if (s->version != DTLS1_VERSION) + 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) + goto err; + s->write_hash = mac_ctx; + } + else + mac_ctx = ssl_replace_hash(&s->write_hash,NULL); +#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 DTLS1_VERSION */ + if (s->version != DTLS1_VERSION) + 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); + EVP_DigestSignInit(mac_ctx,NULL,m,NULL,mac_key); + 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; + printf("EVP_CipherInit_ex(dd,c,key=,iv=,which)\n"); + printf("\tkey= "); for (i=0; i<c->key_len; i++) printf("%02x", key[i]); + printf("\n"); + printf("\t iv= "); for (i=0; i<c->iv_len; i++) printf("%02x", iv[i]); + printf("\n"); + } +#endif /* KSSL_DEBUG */ + + if (EVP_CIPHER_mode(c) == EVP_CIPH_GCM_MODE) + { + 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); + } + else + EVP_CipherInit_ex(dd,c,NULL,key,iv,(which & SSL3_CC_WRITE)); + + /* 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); + +#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 + printf ("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); + 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 (s->version >= TLS1_1_VERSION + && 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 + printf("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[13],*seq; + + seq = send?s->s3->write_sequence:s->s3->read_sequence; + + if (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER) + { + 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,13,buf); + 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; + printf("EVP_Cipher(ds=%p,rec->data=%p,rec->input=%p,l=%ld) ==>\n", + ds,rec->data,rec->input,l); + printf("\tEVP_CIPHER_CTX: %d buf_len, %d key_len [%d %d], %d iv_len\n", + ds->buf_len, ds->cipher->key_len, + DES_KEY_SZ, DES_SCHEDULE_SZ, + ds->cipher->iv_len); + printf("\t\tIV: "); + for (i=0; i<ds->cipher->iv_len; i++) printf("%02X", ds->iv[i]); + printf("\n"); + printf("\trec->input="); + for (ui=0; ui<l; ui++) printf(" %02x", rec->input[ui]); + printf("\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; + printf("\trec->data="); + for (i=0; i<l; i++) + printf(" %02x", rec->data[i]); printf("\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); + EVP_MD_CTX_copy_ex(&ctx,d); + EVP_DigestFinal_ex(&ctx,out,&ret); + 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); + + 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->version == DTLS1_VERSION || ssl->version == DTLS1_BAD_VER) + { + 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. */ + 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 /* not SSLv3 */); + } + else + { + EVP_DigestSignUpdate(mac_ctx,header,sizeof(header)); + EVP_DigestSignUpdate(mac_ctx,rec->input,rec->length); + t=EVP_DigestSignFinal(mac_ctx,md,&md_size); + OPENSSL_assert(t > 0); +#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 +printf("seq="); +{int z; for (z=0; z<8; z++) printf("%02X ",seq[z]); printf("\n"); } +printf("rec="); +{unsigned int z; for (z=0; z<rec->length; z++) printf("%02X ",rec->data[z]); printf("\n"); } +#endif + + if (ssl->version != DTLS1_VERSION && ssl->version != DTLS1_BAD_VER) + { + 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++) printf("%02X ",md[z]); printf("\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 + printf ("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; + sol = s->s3->client_opaque_prf_input_len; /* must be same as col (see draft-rescorla-tls-opaque-prf-input-00.txt, section 3.1) */ + } +#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); +#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 KSSL_DEBUG + printf ("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 + printf ("tls1_export_keying_material(%p,%p,%d,%s,%d,%p,%d)\n", s, out, olen, label, llen, p, plen); +#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); + +#ifdef KSSL_DEBUG + printf ("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); +#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/drivers/builtin_openssl2/ssl/t1_lib.c b/drivers/builtin_openssl2/ssl/t1_lib.c new file mode 100644 index 0000000000..3b8d5153eb --- /dev/null +++ b/drivers/builtin_openssl2/ssl/t1_lib.c @@ -0,0 +1,2732 @@ +/* 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> +#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); +#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, + }; + +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) */ + }; + +static int pref_list[] = + { + NID_sect571r1, /* sect571r1 (14) */ + NID_sect571k1, /* sect571k1 (13) */ + NID_secp521r1, /* secp521r1 (25) */ + NID_sect409k1, /* sect409k1 (11) */ + NID_sect409r1, /* sect409r1 (12) */ + NID_secp384r1, /* secp384r1 (24) */ + NID_sect283k1, /* sect283k1 (9) */ + NID_sect283r1, /* sect283r1 (10) */ + NID_secp256k1, /* secp256k1 (22) */ + NID_X9_62_prime256v1, /* secp256r1 (23) */ + NID_sect239k1, /* sect239k1 (8) */ + NID_sect233k1, /* sect233k1 (6) */ + NID_sect233r1, /* sect233r1 (7) */ + NID_secp224k1, /* secp224k1 (20) */ + NID_secp224r1, /* secp224r1 (21) */ + NID_sect193r1, /* sect193r1 (4) */ + NID_sect193r2, /* sect193r2 (5) */ + NID_secp192k1, /* secp192k1 (18) */ + NID_X9_62_prime192v1, /* secp192r1 (19) */ + NID_sect163k1, /* sect163k1 (1) */ + NID_sect163r1, /* sect163r1 (2) */ + NID_sect163r2, /* sect163r2 (3) */ + NID_secp160k1, /* secp160k1 (15) */ + NID_secp160r1, /* secp160r1 (16) */ + NID_secp160r2, /* secp160r2 (17) */ + }; + +int tls1_ec_curve_id2nid(int curve_id) + { + /* ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005) */ + 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 draft-ietf-tls-ecc-12.txt (Oct. 17, 2005) */ + 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; + default: + return 0; + } + } +#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 +}; + +int tls12_get_req_sig_algs(SSL *s, unsigned char *p) + { + size_t slen = sizeof(tls12_sigalgs); + if (p) + memcpy(p, tls12_sigalgs, slen); + return (int)slen; + } + +unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit) + { + int extdatalen=0; + unsigned char *ret = p; + + /* don't add extensions for SSLv3 unless doing secure renegotiation */ + if (s->client_version == SSL3_VERSION + && !s->s3->send_connection_binding) + return p; + + 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 - p - 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 (s->tlsext_ecpointformatlist != NULL && + s->version != DTLS1_VERSION) + { + /* Add TLS extension ECPointFormats to the ClientHello message */ + long lenmax; + + if ((lenmax = limit - ret - 5) < 0) return NULL; + if (s->tlsext_ecpointformatlist_length > (unsigned long)lenmax) return NULL; + if (s->tlsext_ecpointformatlist_length > 255) + { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return NULL; + } + + s2n(TLSEXT_TYPE_ec_point_formats,ret); + s2n(s->tlsext_ecpointformatlist_length + 1,ret); + *(ret++) = (unsigned char) s->tlsext_ecpointformatlist_length; + memcpy(ret, s->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist_length); + ret+=s->tlsext_ecpointformatlist_length; + } + if (s->tlsext_ellipticcurvelist != NULL && + s->version != DTLS1_VERSION) + { + /* Add TLS extension EllipticCurves to the ClientHello message */ + long lenmax; + + if ((lenmax = limit - ret - 6) < 0) return NULL; + if (s->tlsext_ellipticcurvelist_length > (unsigned long)lenmax) return NULL; + if (s->tlsext_ellipticcurvelist_length > 65532) + { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return NULL; + } + + s2n(TLSEXT_TYPE_elliptic_curves,ret); + s2n(s->tlsext_ellipticcurvelist_length + 2, ret); + + /* NB: draft-ietf-tls-ecc-12.txt uses a one-byte prefix for + * elliptic_curve_list, but the examples use two bytes. + * http://www1.ietf.org/mail-archive/web/tls/current/msg00538.html + * resolves this to two bytes. + */ + s2n(s->tlsext_ellipticcurvelist_length, ret); + memcpy(ret, s->tlsext_ellipticcurvelist, s->tlsext_ellipticcurvelist_length); + ret+=s->tlsext_ellipticcurvelist_length; + } +#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 (TLS1_get_client_version(s) >= TLS1_2_VERSION) + { + if ((size_t)(limit - ret) < sizeof(tls12_sigalgs) + 6) + return NULL; + s2n(TLSEXT_TYPE_signature_algorithms,ret); + s2n(sizeof(tls12_sigalgs) + 2, ret); + s2n(sizeof(tls12_sigalgs), ret); + memcpy(ret, tls12_sigalgs, sizeof(tls12_sigalgs)); + ret += sizeof(tls12_sigalgs); + } + +#ifdef TLSEXT_TYPE_opaque_prf_input + if (s->s3->client_opaque_prf_input != NULL && + s->version != DTLS1_VERSION) + { + 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 && + s->version != DTLS1_VERSION) + { + 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 + +#ifndef OPENSSL_NO_SRTP + if(SSL_get_srtp_profiles(s)) + { + int el; + + ssl_add_clienthello_use_srtp_ext(s, 0, &el, 0); + + if((limit - p - 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 + /* 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-p-2)== 0) + return p; + + s2n(extdatalen,p); + return ret; + } + +unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned char *limit) + { + int extdatalen=0; + unsigned char *ret = p; +#ifndef OPENSSL_NO_NEXTPROTONEG + int next_proto_neg_seen; +#endif + + /* don't add extensions for SSLv3, unless doing secure renegotiation */ + if (s->version == SSL3_VERSION && !s->s3->send_connection_binding) + return p; + + 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 - p - 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 (s->tlsext_ecpointformatlist != NULL && + s->version != DTLS1_VERSION) + { + /* Add TLS extension ECPointFormats to the ServerHello message */ + long lenmax; + + if ((lenmax = limit - ret - 5) < 0) return NULL; + if (s->tlsext_ecpointformatlist_length > (unsigned long)lenmax) return NULL; + if (s->tlsext_ecpointformatlist_length > 255) + { + SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return NULL; + } + + s2n(TLSEXT_TYPE_ec_point_formats,ret); + s2n(s->tlsext_ecpointformatlist_length + 1,ret); + *(ret++) = (unsigned char) s->tlsext_ecpointformatlist_length; + memcpy(ret, s->tlsext_ecpointformatlist, s->tlsext_ecpointformatlist_length); + ret+=s->tlsext_ecpointformatlist_length; + + } + /* 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 && + s->version != DTLS1_VERSION) + { + 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(s->srtp_profile) + { + int el; + + ssl_add_serverhello_use_srtp_ext(s, 0, &el, 0); + + if((limit - p - 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 ((extdatalen = ret-p-2)== 0) + return p; + + s2n(extdatalen,p); + 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 *d, int n) { + 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 >= (d+n-2)) + return; + data += 2; + + if (data > (d+n-4)) + return; + n2s(data,type); + n2s(data,size); + + if (type != TLSEXT_TYPE_server_name) + return; + + if (data+size > d+n) + 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 != d+n) + 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 != d+n) + return; + if (memcmp(data, kSafariExtensionsBlock, len) != 0) + return; + } + + s->s3->is_probably_safari = 1; +} +#endif /* !OPENSSL_NO_EC */ + +int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al) + { + unsigned short type; + unsigned short size; + unsigned short len; + unsigned char *data = *p; + int renegotiate_seen = 0; + int sigalg_seen = 0; + + s->servername_done = 0; + s->tlsext_status_type = -1; +#ifndef OPENSSL_NO_NEXTPROTONEG + s->s3->next_proto_neg_seen = 0; +#endif + +#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, d, n); +#endif /* !OPENSSL_NO_EC */ + + if (data >= (d+n-2)) + goto ri_check; + n2s(data,len); + + if (data > (d+n-len)) + goto ri_check; + + while (data <= (d+n-4)) + { + n2s(data,type); + n2s(data,size); + + if (data+size > (d+n)) + goto ri_check; +#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) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + n2s(data,dsize); + size -= 2; + if (dsize > size ) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + sdata = data; + while (dsize > 3) + { + servname_type = *(sdata++); + n2s(sdata,len); + dsize -= 3; + + if (len > dsize) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + if (s->servername_done == 0) + switch (servname_type) + { + case TLSEXT_NAMETYPE_host_name: + if (!s->hit) + { + if(s->session->tlsext_hostname) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + 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) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + } +#ifndef OPENSSL_NO_SRP + else if (type == TLSEXT_TYPE_srp) + { + if (size <= 0 || ((len = data[0])) != (size -1)) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + if (s->srp_ctx.login != NULL) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + 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) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + } +#endif + +#ifndef OPENSSL_NO_EC + else if (type == TLSEXT_TYPE_ec_point_formats && + s->version != DTLS1_VERSION) + { + unsigned char *sdata = data; + int ecpointformatlist_length = *(sdata++); + + if (ecpointformatlist_length != size - 1) + { + *al = TLS1_AD_DECODE_ERROR; + return 0; + } + 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 && + s->version != DTLS1_VERSION) + { + unsigned char *sdata = data; + int ellipticcurvelist_length = (*(sdata++) << 8); + ellipticcurvelist_length += (*(sdata++)); + + if (ellipticcurvelist_length != size - 2 || + ellipticcurvelist_length < 1) + { + *al = TLS1_AD_DECODE_ERROR; + return 0; + } + if (!s->hit) + { + if(s->session->tlsext_ellipticcurvelist) + { + *al = TLS1_AD_DECODE_ERROR; + return 0; + } + 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 && + s->version != DTLS1_VERSION) + { + 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); + if (s->s3->client_opaque_prf_input_len == 0) + s->s3->client_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */ + 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 (sigalg_seen || size < 2) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + sigalg_seen = 1; + n2s(data,dsize); + size -= 2; + if (dsize != size || dsize & 1) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + if (!tls1_process_sigalgs(s, data, dsize)) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + } + else if (type == TLSEXT_TYPE_status_request && + s->version != DTLS1_VERSION) + { + + if (size < 5) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + 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 ) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + while (dsize > 0) + { + OCSP_RESPID *id; + int idsize; + if (dsize < 4) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + n2s(data, idsize); + dsize -= 2 + idsize; + size -= 2 + idsize; + if (dsize < 0) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + sdata = data; + data += idsize; + id = d2i_OCSP_RESPID(NULL, + &sdata, idsize); + if (!id) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + if (data != sdata) + { + OCSP_RESPID_free(id); + *al = SSL_AD_DECODE_ERROR; + return 0; + } + 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) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + n2s(data,dsize); + size -= 2; + if (dsize != size) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + 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)) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + } + } + /* 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 + + /* session ticket processed earlier */ +#ifndef OPENSSL_NO_SRTP + else if (type == TLSEXT_TYPE_use_srtp) + { + if(ssl_parse_clienthello_use_srtp_ext(s, data, size, + al)) + return 0; + } +#endif + + data+=size; + } + + *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_PARSE_CLIENTHELLO_TLSEXT, + SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED); + 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 + +int ssl_parse_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 + +#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 && + s->version != DTLS1_VERSION) + { + unsigned char *sdata = data; + int ecpointformatlist_length = *(sdata++); + + if (ecpointformatlist_length != size - 1 || + ecpointformatlist_length < 1) + { + *al = TLS1_AD_DECODE_ERROR; + return 0; + } + 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 && + s->version != DTLS1_VERSION) + { + 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) + s->s3->server_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */ + 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 && + s->version != DTLS1_VERSION) + { + /* 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_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 (type == TLSEXT_TYPE_use_srtp) + { + if(ssl_parse_serverhello_use_srtp_ext(s, data, size, + al)) + return 0; + } +#endif + + 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_PARSE_SERVERHELLO_TLSEXT, + SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED); + return 0; + } + + return 1; + } + + +int ssl_prepare_clienthello_tlsext(SSL *s) + { +#ifndef OPENSSL_NO_EC + /* If we are client and using an elliptic curve cryptography cipher suite, send the point formats + * and elliptic curves we support. + */ + int using_ecc = 0; + int i; + unsigned char *j; + 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; + } + } + using_ecc = using_ecc && (s->version >= TLS1_VERSION); + if (using_ecc) + { + if (s->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->tlsext_ecpointformatlist); + if ((s->tlsext_ecpointformatlist = OPENSSL_malloc(3)) == NULL) + { + SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE); + return -1; + } + s->tlsext_ecpointformatlist_length = 3; + s->tlsext_ecpointformatlist[0] = TLSEXT_ECPOINTFORMAT_uncompressed; + s->tlsext_ecpointformatlist[1] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime; + s->tlsext_ecpointformatlist[2] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2; + + /* we support all named elliptic curves in draft-ietf-tls-ecc-12 */ + if (s->tlsext_ellipticcurvelist != NULL) OPENSSL_free(s->tlsext_ellipticcurvelist); + s->tlsext_ellipticcurvelist_length = sizeof(pref_list)/sizeof(pref_list[0]) * 2; + if ((s->tlsext_ellipticcurvelist = OPENSSL_malloc(s->tlsext_ellipticcurvelist_length)) == NULL) + { + s->tlsext_ellipticcurvelist_length = 0; + SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE); + return -1; + } + for (i = 0, j = s->tlsext_ellipticcurvelist; (unsigned int)i < + sizeof(pref_list)/sizeof(pref_list[0]); i++) + { + int id = tls1_ec_nid2curve_id(pref_list[i]); + s2n(id,j); + } + } +#endif /* OPENSSL_NO_EC */ + +#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) + s->s3->client_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */ + 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 + + return 1; + } + +int ssl_prepare_serverhello_tlsext(SSL *s) + { +#ifndef OPENSSL_NO_EC + /* If we are server and using an ECC cipher suite, send the point formats we support + * if the client sent us an ECPointsFormat extension. Note that the server is not + * supposed to send an EllipticCurves extension. + */ + + 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); + + if (using_ecc) + { + if (s->tlsext_ecpointformatlist != NULL) OPENSSL_free(s->tlsext_ecpointformatlist); + if ((s->tlsext_ecpointformatlist = OPENSSL_malloc(3)) == NULL) + { + SSLerr(SSL_F_SSL_PREPARE_SERVERHELLO_TLSEXT,ERR_R_MALLOC_FAILURE); + return -1; + } + s->tlsext_ecpointformatlist_length = 3; + s->tlsext_ecpointformatlist[0] = TLSEXT_ECPOINTFORMAT_uncompressed; + s->tlsext_ecpointformatlist[1] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime; + s->tlsext_ecpointformatlist[2] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2; + } +#endif /* OPENSSL_NO_EC */ + + return 1; + } + +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) + s->s3->server_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */ + 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 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; + + 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 + + /* 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->ctx && s->ctx->tlsext_status_cb) + { + int r; + /* Set resp to NULL, resplen to -1 so callback knows + * there is no response. + */ + if (s->tlsext_ocsp_resp) + { + OPENSSL_free(s->tlsext_ocsp_resp); + s->tlsext_ocsp_resp = NULL; + } + s->tlsext_ocsp_resplen = -1; + 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; + } + } + +/* 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 (s->version == DTLS1_VERSION || s->version == DTLS1_BAD_VER) + { + 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; + HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16, + tlsext_tick_md(), NULL); + EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, + tctx->tlsext_tick_aes_key, etick + 16); + } + /* Attempt to process session ticket, first conduct sanity and + * integrity checks on ticket. + */ + mlen = HMAC_size(&hctx); + if (mlen < 0) + { + EVP_CIPHER_CTX_cleanup(&ctx); + return -1; + } + eticklen -= mlen; + /* Check HMAC of encrypted ticket */ + HMAC_Update(&hctx, etick, eticklen); + HMAC_Final(&hctx, tick_hmac, NULL); + HMAC_CTX_cleanup(&hctx); + if (CRYPTO_memcmp(tick_hmac, etick + eticklen, mlen)) + 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) + { + EVP_CIPHER_CTX_cleanup(&ctx); + return -1; + } + EVP_DecryptUpdate(&ctx, sdec, &slen, p, eticklen); + if (EVP_DecryptFinal(&ctx, sdec + slen, &mlen) <= 0) + 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; + } + +/* Tables to translate from NIDs to TLS v1.2 ids */ + +typedef struct + { + int nid; + int id; + } tls12_lookup; + +static tls12_lookup tls12_md[] = { +#ifndef OPENSSL_NO_MD5 + {NID_md5, TLSEXT_hash_md5}, +#endif +#ifndef OPENSSL_NO_SHA + {NID_sha1, TLSEXT_hash_sha1}, +#endif +#ifndef OPENSSL_NO_SHA256 + {NID_sha224, TLSEXT_hash_sha224}, + {NID_sha256, TLSEXT_hash_sha256}, +#endif +#ifndef OPENSSL_NO_SHA512 + {NID_sha384, TLSEXT_hash_sha384}, + {NID_sha512, TLSEXT_hash_sha512} +#endif +}; + +static tls12_lookup tls12_sig[] = { +#ifndef OPENSSL_NO_RSA + {EVP_PKEY_RSA, TLSEXT_signature_rsa}, +#endif +#ifndef OPENSSL_NO_DSA + {EVP_PKEY_DSA, TLSEXT_signature_dsa}, +#endif +#ifndef OPENSSL_NO_ECDSA + {EVP_PKEY_EC, TLSEXT_signature_ecdsa} +#endif +}; + +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; + } +#if 0 +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 -1; + } +#endif + +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_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; + + } + } + +/* Set preferred digest for each key type */ + +int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize) + { + int i, idx; + const EVP_MD *md; + CERT *c = s->cert; + /* Extension ignored for TLS versions below 1.2 */ + if (TLS1_get_version(s) < TLS1_2_VERSION) + return 1; + /* Should never happen */ + if (!c) + return 0; + + c->pkeys[SSL_PKEY_DSA_SIGN].digest = NULL; + c->pkeys[SSL_PKEY_RSA_SIGN].digest = NULL; + c->pkeys[SSL_PKEY_RSA_ENC].digest = NULL; + c->pkeys[SSL_PKEY_ECC].digest = NULL; + + for (i = 0; i < dsize; i += 2) + { + unsigned char hash_alg = data[i], sig_alg = data[i+1]; + + switch(sig_alg) + { +#ifndef OPENSSL_NO_RSA + case TLSEXT_signature_rsa: + idx = SSL_PKEY_RSA_SIGN; + break; +#endif +#ifndef OPENSSL_NO_DSA + case TLSEXT_signature_dsa: + idx = SSL_PKEY_DSA_SIGN; + break; +#endif +#ifndef OPENSSL_NO_ECDSA + case TLSEXT_signature_ecdsa: + idx = SSL_PKEY_ECC; + break; +#endif + default: + continue; + } + + if (c->pkeys[idx].digest == NULL) + { + md = tls12_get_hash(hash_alg); + if (md) + { + c->pkeys[idx].digest = md; + if (idx == SSL_PKEY_RSA_SIGN) + c->pkeys[SSL_PKEY_RSA_ENC].digest = md; + } + } + + } + + + /* 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; + } + +#endif + +#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); + bp = buffer; + + /* Enter response type, length and copy payload */ + *bp++ = TLS1_HB_RESPONSE; + s2n(payload, bp); + memcpy(bp, pl, payload); + bp += payload; + /* Random padding */ + RAND_pseudo_bytes(bp, padding); + + 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; + 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 */ + RAND_pseudo_bytes(p, 16); + p += 16; + /* Random padding */ + RAND_pseudo_bytes(p, padding); + + 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; + } + + OPENSSL_free(buf); + + return ret; + } +#endif diff --git a/drivers/builtin_openssl2/ssl/t1_meth.c b/drivers/builtin_openssl2/ssl/t1_meth.c new file mode 100644 index 0000000000..53c807de28 --- /dev/null +++ b/drivers/builtin_openssl2/ssl/t1_meth.c @@ -0,0 +1,88 @@ +/* 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) + +IMPLEMENT_tls_meth_func(TLS1_1_VERSION, TLSv1_1_method, + ssl3_accept, + ssl3_connect, + tls1_get_method) + +IMPLEMENT_tls_meth_func(TLS1_VERSION, TLSv1_method, + ssl3_accept, + ssl3_connect, + tls1_get_method) + diff --git a/drivers/builtin_openssl2/ssl/t1_reneg.c b/drivers/builtin_openssl2/ssl/t1_reneg.c new file mode 100644 index 0000000000..9c2cc3c712 --- /dev/null +++ b/drivers/builtin_openssl2/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/drivers/builtin_openssl2/ssl/t1_srvr.c b/drivers/builtin_openssl2/ssl/t1_srvr.c new file mode 100644 index 0000000000..f1d1565769 --- /dev/null +++ b/drivers/builtin_openssl2/ssl/t1_srvr.c @@ -0,0 +1,93 @@ +/* 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) + +IMPLEMENT_tls_meth_func(TLS1_1_VERSION, TLSv1_1_server_method, + ssl3_accept, + ssl_undefined_function, + tls1_get_server_method) + +IMPLEMENT_tls_meth_func(TLS1_VERSION, TLSv1_server_method, + ssl3_accept, + ssl_undefined_function, + tls1_get_server_method) + diff --git a/drivers/builtin_openssl2/ssl/tls_srp.c b/drivers/builtin_openssl2/ssl/tls_srp.c new file mode 100644 index 0000000000..2315a7c0a2 --- /dev/null +++ b/drivers/builtin_openssl2/ssl/tls_srp.c @@ -0,0 +1,507 @@ +/* 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_Calc_A_param(SSL *s) + { + unsigned char rnd[SSL_MAX_MASTER_KEY_LENGTH]; + + if (BN_num_bits(s->srp_ctx.N) < s->srp_ctx.strength) + return -1; + + if (s->srp_ctx.SRP_verify_param_callback ==NULL && + !SRP_check_known_gN_param(s->srp_ctx.g,s->srp_ctx.N)) + return -1 ; + + RAND_bytes(rnd, sizeof(rnd)); + 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; + + /* We can have a callback to verify SRP param!! */ + if (s->srp_ctx.SRP_verify_param_callback !=NULL) + return s->srp_ctx.SRP_verify_param_callback(s,s->srp_ctx.SRP_cb_arg); + + 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 |