diff options
author | Parménides GV <parmegv@sdf.org> | 2014-04-09 16:03:55 +0200 |
---|---|---|
committer | Parménides GV <parmegv@sdf.org> | 2014-04-09 16:07:34 +0200 |
commit | 1684c8f398922065a97e7da4dac4ac6a33cc5218 (patch) | |
tree | 76a4b11ae0d7b217c088f3c2b8fc7e69a7b8ae0d /app/openssl/ssl | |
parent | b9a2b085a8f508cd09e2639c70be845c992c4a3e (diff) |
Back to the standard "app" module.
This return to "app" instead of "bitmask_android" is due to this reading: https://developer.android.com/sdk/installing/studio-build.html#projectStructure
I'll have to tweak the final apk name in build.gradle.
Diffstat (limited to 'app/openssl/ssl')
55 files changed, 50122 insertions, 0 deletions
diff --git a/app/openssl/ssl/Android.mk b/app/openssl/ssl/Android.mk new file mode 100644 index 00000000..1319d5e1 --- /dev/null +++ b/app/openssl/ssl/Android.mk @@ -0,0 +1,78 @@ +LOCAL_PATH:= $(call my-dir) + +local_c_includes := \ + openssl \ + openssl/include \ + openssl/crypto + +local_src_files:= \ + s2_meth.c \ + s2_srvr.c \ + s2_clnt.c \ + s2_lib.c \ + s2_enc.c \ + s2_pkt.c \ + s3_meth.c \ + s3_srvr.c \ + s3_clnt.c \ + s3_lib.c \ + s3_enc.c \ + s3_pkt.c \ + s3_both.c \ + s23_meth.c \ + s23_srvr.c \ + s23_clnt.c \ + s23_lib.c \ + s23_pkt.c \ + t1_meth.c \ + t1_srvr.c \ + t1_clnt.c \ + t1_lib.c \ + t1_enc.c \ + t1_reneg.c \ + ssl_lib.c \ + ssl_err2.c \ + ssl_cert.c \ + ssl_sess.c \ + ssl_ciph.c \ + ssl_stat.c \ + ssl_rsa.c \ + ssl_asn1.c \ + ssl_txt.c \ + ssl_algs.c \ + bio_ssl.c \ + ssl_err.c \ + kssl.c + +####################################### +# target static library +include $(CLEAR_VARS) +include $(LOCAL_PATH)/../android-config.mk + +ifneq ($(TARGET_ARCH),x86) +LOCAL_NDK_VERSION := 5 +LOCAL_SDK_VERSION := 9 +endif +LOCAL_SRC_FILES += $(local_src_files) +LOCAL_C_INCLUDES += $(local_c_includes) +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE:= libssl_static +include $(BUILD_STATIC_LIBRARY) + +####################################### +# target shared library +include $(CLEAR_VARS) +include $(LOCAL_PATH)/../android-config.mk + +ifneq ($(TARGET_ARCH),x86) +LOCAL_NDK_VERSION := 5 +LOCAL_SDK_VERSION := 9 +endif +LOCAL_SRC_FILES += $(local_src_files) +LOCAL_C_INCLUDES += $(local_c_includes) +LOCAL_SHARED_LIBRARIES += libcrypto +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE:= libssl +include $(BUILD_SHARED_LIBRARY) + + diff --git a/app/openssl/ssl/bio_ssl.c b/app/openssl/ssl/bio_ssl.c new file mode 100644 index 00000000..eedac8a3 --- /dev/null +++ b/app/openssl/ssl/bio_ssl.c @@ -0,0 +1,603 @@ +/* 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) + { + 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); + 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/app/openssl/ssl/d1_both.c b/app/openssl/ssl/d1_both.c new file mode 100644 index 00000000..2180c6d4 --- /dev/null +++ b/app/openssl/ssl/d1_both.c @@ -0,0 +1,1410 @@ +/* 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_min_mtu(void); +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->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 ( ! (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); + } + + OPENSSL_assert(mtu > 0); /* should have something reasonable now */ + +#endif + + 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; + + /* write atleast DTLS1_HM_HEADER_LENGTH bytes */ + if ( len <= DTLS1_HM_HEADER_LENGTH) + len += DTLS1_HM_HEADER_LENGTH; + } + + 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 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) + { + goto err; + i = -1; + } + + 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; + + /* 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; + } + OPENSSL_assert(i == DTLS1_HM_HEADER_LENGTH); + + /* 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; + return dtls1_get_message_fragment(s, st1, stn, + max, ok); + } + 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 */ + OPENSSL_assert(i == (int)frag_len); + + *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; + } + + if ( ! SSL_in_init(s)) /* done, no need to send a retransmit */ + { + 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; + } + +static 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++); + } diff --git a/app/openssl/ssl/d1_clnt.c b/app/openssl/ssl/d1_clnt.c new file mode 100644 index 00000000..57766717 --- /dev/null +++ b/app/openssl/ssl/d1_clnt.c @@ -0,0 +1,1542 @@ +/* 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;; + + 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_RENEGOTIATE: + s->new_session=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; + + 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; + + /* 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; + else + { + dtls1_stop_timer(s); + if (s->hit) + 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; + 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: + 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; + /* 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 + { + 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; + 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; + } + + 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; + 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->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; + 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 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->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--; + 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 Time,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 (!s->session_creation_enabled) + { + ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE); + SSLerr(SSL_F_DTLS1_CLIENT_HELLO,SSL_R_SESSION_MAY_NOT_BE_CREATED); + goto err; + } + 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)) + { + Time=(unsigned long)time(NULL); /* Time */ + l2n(Time,p); + RAND_pseudo_bytes(p,sizeof(s->s3->client_random)-4); + } + + /* 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/app/openssl/ssl/d1_enc.c b/app/openssl/ssl/d1_enc.c new file mode 100644 index 00000000..becbab91 --- /dev/null +++ b/app/openssl/ssl/d1_enc.c @@ -0,0 +1,289 @@ +/* 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 + +int dtls1_enc(SSL *s, int send) + { + SSL3_RECORD *rec; + EVP_CIPHER_CTX *ds; + unsigned long l; + int bs,i,ii,j,k,n=0; + const EVP_CIPHER *enc; + + if (send) + { + if (EVP_MD_CTX_md(s->write_hash)) + { + n=EVP_MD_CTX_size(s->write_hash); + if (n < 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)) + { + n=EVP_MD_CTX_size(s->read_hash); + if (n < 0) + return -1; + } + 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 -1; + } + + 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) + { + ii=i=rec->data[l-1]; /* padding_length */ + i++; + if (s->options&SSL_OP_TLS_BLOCK_PADDING_BUG) + { + /* First packet is even in size, so check */ + if ((memcmp(s->s3->read_sequence, + "\0\0\0\0\0\0\0\0",8) == 0) && !(ii & 1)) + s->s3->flags|=TLS1_FLAGS_TLS_PADDING_BUG; + if (s->s3->flags & TLS1_FLAGS_TLS_PADDING_BUG) + i--; + } + /* TLS 1.0 does not bound the number of padding bytes by the block size. + * All of them must have value 'padding_length'. */ + if (i > (int)rec->length) + { + /* Incorrect padding. SSLerr() and ssl3_alert are done + * by caller: we don't want to reveal whether this is + * a decryption error or a MAC verification failure + * (see http://www.openssl.org/~bodo/tls-cbc.txt) + */ + return -1; + } + for (j=(int)(l-i); j<(int)l; j++) + { + if (rec->data[j] != ii) + { + /* Incorrect padding */ + return -1; + } + } + rec->length-=i; + + rec->data += bs; /* skip the implicit IV */ + rec->input += bs; + rec->length -= bs; + } + } + return(1); + } + diff --git a/app/openssl/ssl/d1_lib.c b/app/openssl/ssl/d1_lib.c new file mode 100644 index 00000000..48e8b6ff --- /dev/null +++ b/app/openssl/ssl/d1_lib.c @@ -0,0 +1,443 @@ +/* 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, + }; + +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) + { + frag = (hm_fragment *)item->data; + OPENSSL_free(frag->fragment); + OPENSSL_free(frag); + 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); + } + +void dtls1_clear(SSL *s) + { + pqueue unprocessed_rcds; + pqueue processed_rcds; + pqueue buffered_messages; + pqueue sent_messages; + pqueue buffered_app_data; + + 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; + + dtls1_clear_queues(s); + + memset(s->d1, 0, sizeof(*(s->d1))); + + if (s->server) + { + s->d1->cookie_len = sizeof(s->d1->cookie); + } + + 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) + { + /* 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->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_handle_timeout(SSL *s) + { + DTLS1_STATE *state; + + /* if no timer is expired, don't do anything */ + if (!dtls1_is_timer_expired(s)) + { + return 0; + } + + dtls1_double_timeout(s); + state = s->d1; + state->timeout.num_alerts++; + if ( state->timeout.num_alerts > DTLS1_TMO_ALERT_COUNT) + { + /* fail the connection, enough alerts have been sent */ + SSLerr(SSL_F_DTLS1_HANDLE_TIMEOUT,SSL_R_READ_TIMEOUT_EXPIRED); + return -1; + } + + state->timeout.read_timeouts++; + if ( state->timeout.read_timeouts > DTLS1_TMO_READ_COUNT) + { + state->timeout.read_timeouts = 1; + } + + 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/app/openssl/ssl/d1_meth.c b/app/openssl/ssl/d1_meth.c new file mode 100644 index 00000000..5c4004bf --- /dev/null +++ b/app/openssl/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/app/openssl/ssl/d1_pkt.c b/app/openssl/ssl/d1_pkt.c new file mode 100644 index 00000000..91562f35 --- /dev/null +++ b/app/openssl/ssl/d1_pkt.c @@ -0,0 +1,1800 @@ +/* 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); +static void dtls1_clear_timeouts(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; + + /* insert should not fail, since duplicates are dropped */ + if (pqueue_insert(queue->q, item) == NULL) + { + OPENSSL_free(rdata); + pitem_free(item); + return(0); + } + + 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); + } + + 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 clear=0; + int enc_err; + SSL_SESSION *sess; + SSL3_RECORD *rr; + unsigned int mac_size; + 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); + if (enc_err <= 0) + { + /* decryption failed, silently discard message */ + if (enc_err < 0) + { + 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) || + (s->read_hash == NULL)) + clear=1; + + if (!clear) + { + /* !clear => s->read_hash != NULL => mac_size != -1 */ + int t; + t=EVP_MD_CTX_size(s->read_hash); + OPENSSL_assert(t >= 0); + mac_size=t; + + if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+mac_size) + { +#if 0 /* OK only for stream ciphers (then rr->length is visible from ciphertext anyway) */ + al=SSL_AD_RECORD_OVERFLOW; + SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_PRE_MAC_LENGTH_TOO_LONG); + goto f_err; +#else + goto err; +#endif + } + /* check the MAC for rr->input (it's in mac_size bytes at the tail) */ + if (rr->length < mac_size) + { +#if 0 /* OK only for stream ciphers */ + al=SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_LENGTH_TOO_SHORT); + goto f_err; +#else + goto err; +#endif + } + rr->length-=mac_size; + i=s->method->ssl3_enc->mac(s,md,0); + if (i < 0 || memcmp(md,&(rr->data[rr->length]),mac_size) != 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; + } + + /* If we receive a valid record larger than the current buffer size, + * allocate some memory for it. + */ + if (rr->length > s->s3->rbuf.len - DTLS1_RT_HEADER_LENGTH) + { + unsigned char *pp; + unsigned int newlen = rr->length + DTLS1_RT_HEADER_LENGTH; + if ((pp=OPENSSL_realloc(s->s3->rbuf.buf, newlen))==NULL) + { + SSLerr(SSL_F_DTLS1_GET_RECORD,ERR_R_MALLOC_FAILURE); + return(-1); + } + p = pp + (p - s->s3->rbuf.buf); + s->s3->rbuf.buf=pp; + s->s3->rbuf.len=newlen; + s->packet= &(s->s3->rbuf.buf[0]); + } + + /* 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 */ + } + + /* 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 */ + } + + /* 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 */ + } + + dtls1_clear_timeouts(s); /* done waiting */ + 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. */ + + 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_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) + { + 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; + } + } + + /* 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; + } + } + 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; + } + /* 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) + { + 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) + { + 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++; + + 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) + { + 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->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; + + if (SSL_in_init(s) && !s->in_handshake) + { + 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; + unsigned int len_with_overhead = len + SSL3_RT_DEFAULT_WRITE_OVERHEAD; + + /* 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 (s->s3->wbuf.len < len_with_overhead) + { + if ((p=OPENSSL_realloc(s->s3->wbuf.buf, len_with_overhead)) == NULL) { + SSLerr(SSL_F_DO_DTLS1_WRITE,ERR_R_MALLOC_FAILURE); + goto err; + } + s->s3->wbuf.buf = p; + s->s3->wbuf.len = len_with_overhead; + } + + /* 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); + } + + +static void +dtls1_clear_timeouts(SSL *s) + { + memset(&(s->d1->timeout), 0x00, sizeof(struct dtls1_timeout_st)); + } diff --git a/app/openssl/ssl/d1_srvr.c b/app/openssl/ssl/d1_srvr.c new file mode 100644 index 00000000..a6a4c87e --- /dev/null +++ b/app/openssl/ssl/d1_srvr.c @@ -0,0 +1,1563 @@ +/* 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; + + 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; + + if (s->cert == NULL) + { + SSLerr(SSL_F_DTLS1_ACCEPT,SSL_R_NO_CERTIFICATE_SET); + return(-1); + } + + for (;;) + { + state=s->state; + + switch (s->state) + { + case SSL_ST_RENEGOTIATE: + s->new_session=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 :-) + */ + 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_start_timer(s); + ret=dtls1_send_hello_request(s); + if (ret <= 0) goto end; + s->s3->tmp.next_state=SSL3_ST_SW_HELLO_REQ_C; + s->state=SSL3_ST_SW_FLUSH; + s->init_num=0; + + ssl3_init_finished_mac(s); + break; + + case SSL3_ST_SW_HELLO_REQ_C: + s->state=SSL_ST_OK; + break; + + case SSL3_ST_SR_CLNT_HELLO_A: + case SSL3_ST_SR_CLNT_HELLO_B: + case SSL3_ST_SR_CLNT_HELLO_C: + + s->shutdown=0; + ret=ssl3_get_client_hello(s); + if (ret <= 0) goto end; + 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; + + case SSL3_ST_SW_SRVR_HELLO_A: + case SSL3_ST_SW_SRVR_HELLO_B: + s->new_session = 2; + dtls1_start_timer(s); + ret=dtls1_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 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; + } + 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; +#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: + 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) + { + 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; + dtls1_stop_timer(s); + if (ret == 2) + 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; + dtls1_stop_timer(s); + 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; + dtls1_stop_timer(s); + 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; + dtls1_stop_timer(s); + + 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; + 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; + 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); + +#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->new_session == 2) /* skipped if we just sent a HelloRequest */ + { + /* actually not necessarily a 'new' session unless + * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION is set */ + + 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--; + 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,Time; + + if (s->state == SSL3_ST_SW_SRVR_HELLO_A) + { + buf=(unsigned char *)s->init_buf->data; + p=s->s3->server_random; + Time=(unsigned long)time(NULL); /* Time */ + l2n(Time,p); + RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-sizeof(Time)); + /* 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) + { + 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); + 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[4]),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/app/openssl/ssl/dtls1.h b/app/openssl/ssl/dtls1.h new file mode 100644 index 00000000..2900d1d8 --- /dev/null +++ b/app/openssl/ssl/dtls1.h @@ -0,0 +1,267 @@ +/* ssl/dtls1.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). + * + */ + +#ifndef HEADER_DTLS1_H +#define HEADER_DTLS1_H + +#include <openssl/buffer.h> +#include <openssl/pqueue.h> +#ifdef OPENSSL_SYS_VMS +#include <resource.h> +#include <sys/timeb.h> +#endif +#ifdef OPENSSL_SYS_WIN32 +/* Needed for struct timeval */ +#include <winsock.h> +#elif defined(OPENSSL_SYS_NETWARE) && !defined(_WINSOCK2API_) +#include <sys/timeval.h> +#else +#include <sys/time.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define DTLS1_VERSION 0xFEFF +#define DTLS1_BAD_VER 0x0100 + +#if 0 +/* this alert description is not specified anywhere... */ +#define DTLS1_AD_MISSING_HANDSHAKE_MESSAGE 110 +#endif + +/* lengths of messages */ +#define DTLS1_COOKIE_LENGTH 256 + +#define DTLS1_RT_HEADER_LENGTH 13 + +#define DTLS1_HM_HEADER_LENGTH 12 + +#define DTLS1_HM_BAD_FRAGMENT -2 +#define DTLS1_HM_FRAGMENT_RETRY -3 + +#define DTLS1_CCS_HEADER_LENGTH 1 + +#ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE +#define DTLS1_AL_HEADER_LENGTH 7 +#else +#define DTLS1_AL_HEADER_LENGTH 2 +#endif + + +typedef struct dtls1_bitmap_st + { + unsigned long map; /* track 32 packets on 32-bit systems + and 64 - on 64-bit systems */ + unsigned char max_seq_num[8]; /* max record number seen so far, + 64-bit value in big-endian + encoding */ + } DTLS1_BITMAP; + +struct dtls1_retransmit_state + { + EVP_CIPHER_CTX *enc_write_ctx; /* cryptographic state */ + EVP_MD_CTX *write_hash; /* used for mac generation */ +#ifndef OPENSSL_NO_COMP + COMP_CTX *compress; /* compression */ +#else + char *compress; +#endif + SSL_SESSION *session; + unsigned short epoch; + }; + +struct hm_header_st + { + unsigned char type; + unsigned long msg_len; + unsigned short seq; + unsigned long frag_off; + unsigned long frag_len; + unsigned int is_ccs; + struct dtls1_retransmit_state saved_retransmit_state; + }; + +struct ccs_header_st + { + unsigned char type; + unsigned short seq; + }; + +struct dtls1_timeout_st + { + /* Number of read timeouts so far */ + unsigned int read_timeouts; + + /* Number of write timeouts so far */ + unsigned int write_timeouts; + + /* Number of alerts received so far */ + unsigned int num_alerts; + }; + +typedef struct record_pqueue_st + { + unsigned short epoch; + pqueue q; + } record_pqueue; + +typedef struct hm_fragment_st + { + struct hm_header_st msg_header; + unsigned char *fragment; + unsigned char *reassembly; + } hm_fragment; + +typedef struct dtls1_state_st + { + unsigned int send_cookie; + unsigned char cookie[DTLS1_COOKIE_LENGTH]; + unsigned char rcvd_cookie[DTLS1_COOKIE_LENGTH]; + unsigned int cookie_len; + + /* + * The current data and handshake epoch. This is initially + * undefined, and starts at zero once the initial handshake is + * completed + */ + unsigned short r_epoch; + unsigned short w_epoch; + + /* records being received in the current epoch */ + DTLS1_BITMAP bitmap; + + /* renegotiation starts a new set of sequence numbers */ + DTLS1_BITMAP next_bitmap; + + /* handshake message numbers */ + unsigned short handshake_write_seq; + unsigned short next_handshake_write_seq; + + unsigned short handshake_read_seq; + + /* save last sequence number for retransmissions */ + unsigned char last_write_sequence[8]; + + /* Received handshake records (processed and unprocessed) */ + record_pqueue unprocessed_rcds; + record_pqueue processed_rcds; + + /* Buffered handshake messages */ + pqueue buffered_messages; + + /* Buffered (sent) handshake records */ + pqueue sent_messages; + + /* Buffered application records. + * Only for records between CCS and Finished + * to prevent either protocol violation or + * unnecessary message loss. + */ + record_pqueue buffered_app_data; + + /* Is set when listening for new connections with dtls1_listen() */ + unsigned int listen; + + unsigned int mtu; /* max DTLS packet size */ + + struct hm_header_st w_msg_hdr; + struct hm_header_st r_msg_hdr; + + struct dtls1_timeout_st timeout; + + /* Indicates when the last handshake msg sent will timeout */ + struct timeval next_timeout; + + /* Timeout duration */ + unsigned short timeout_duration; + + /* storage for Alert/Handshake protocol data received but not + * yet processed by ssl3_read_bytes: */ + unsigned char alert_fragment[DTLS1_AL_HEADER_LENGTH]; + unsigned int alert_fragment_len; + unsigned char handshake_fragment[DTLS1_HM_HEADER_LENGTH]; + unsigned int handshake_fragment_len; + + unsigned int retransmitting; + unsigned int change_cipher_spec_ok; + + } DTLS1_STATE; + +typedef struct dtls1_record_data_st + { + unsigned char *packet; + unsigned int packet_length; + SSL3_BUFFER rbuf; + SSL3_RECORD rrec; + } DTLS1_RECORD_DATA; + + +/* Timeout multipliers (timeout slice is defined in apps/timeouts.h */ +#define DTLS1_TMO_READ_COUNT 2 +#define DTLS1_TMO_WRITE_COUNT 2 + +#define DTLS1_TMO_ALERT_COUNT 12 + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/app/openssl/ssl/kssl.c b/app/openssl/ssl/kssl.c new file mode 100644 index 00000000..b820e374 --- /dev/null +++ b/app/openssl/ssl/kssl.c @@ -0,0 +1,2205 @@ +/* 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; + } + + +#else /* !OPENSSL_NO_KRB5 */ + +#if defined(PEDANTIC) || defined(OPENSSL_SYS_VMS) +static void *dummy=&dummy; +#endif + +#endif /* !OPENSSL_NO_KRB5 */ + diff --git a/app/openssl/ssl/kssl.h b/app/openssl/ssl/kssl.h new file mode 100644 index 00000000..a3d20e1c --- /dev/null +++ b/app/openssl/ssl/kssl.h @@ -0,0 +1,179 @@ +/* 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). + * + */ + +/* +** 19990701 VRS Started. +*/ + +#ifndef KSSL_H +#define KSSL_H + +#include <openssl/opensslconf.h> + +#ifndef OPENSSL_NO_KRB5 + +#include <stdio.h> +#include <ctype.h> +#include <krb5.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** Depending on which KRB5 implementation used, some types from +** the other may be missing. Resolve that here and now +*/ +#ifdef KRB5_HEIMDAL +typedef unsigned char krb5_octet; +#define FAR +#else + +#ifndef FAR +#define FAR +#endif + +#endif + +/* Uncomment this to debug kssl problems or +** to trace usage of the Kerberos session key +** +** #define KSSL_DEBUG +*/ + +#ifndef KRB5SVC +#define KRB5SVC "host" +#endif + +#ifndef KRB5KEYTAB +#define KRB5KEYTAB "/etc/krb5.keytab" +#endif + +#ifndef KRB5SENDAUTH +#define KRB5SENDAUTH 1 +#endif + +#ifndef KRB5CHECKAUTH +#define KRB5CHECKAUTH 1 +#endif + +#ifndef KSSL_CLOCKSKEW +#define KSSL_CLOCKSKEW 300; +#endif + +#define KSSL_ERR_MAX 255 +typedef struct kssl_err_st { + int reason; + char text[KSSL_ERR_MAX+1]; + } KSSL_ERR; + + +/* Context for passing +** (1) Kerberos session key to SSL, and +** (2) Config data between application and SSL lib +*/ +typedef struct kssl_ctx_st + { + /* used by: disposition: */ + char *service_name; /* C,S default ok (kssl) */ + char *service_host; /* C input, REQUIRED */ + char *client_princ; /* S output from krb5 ticket */ + char *keytab_file; /* S NULL (/etc/krb5.keytab) */ + char *cred_cache; /* C NULL (default) */ + krb5_enctype enctype; + int length; + krb5_octet FAR *key; + } KSSL_CTX; + +#define KSSL_CLIENT 1 +#define KSSL_SERVER 2 +#define KSSL_SERVICE 3 +#define KSSL_KEYTAB 4 + +#define KSSL_CTX_OK 0 +#define KSSL_CTX_ERR 1 +#define KSSL_NOMEM 2 + +/* Public (for use by applications that use OpenSSL with Kerberos 5 support */ +krb5_error_code kssl_ctx_setstring(KSSL_CTX *kssl_ctx, int which, char *text); +KSSL_CTX *kssl_ctx_new(void); +KSSL_CTX *kssl_ctx_free(KSSL_CTX *kssl_ctx); +void kssl_ctx_show(KSSL_CTX *kssl_ctx); +krb5_error_code kssl_ctx_setprinc(KSSL_CTX *kssl_ctx, int which, + krb5_data *realm, krb5_data *entity, int nentities); +krb5_error_code kssl_cget_tkt(KSSL_CTX *kssl_ctx, krb5_data **enc_tktp, + krb5_data *authenp, KSSL_ERR *kssl_err); +krb5_error_code kssl_sget_tkt(KSSL_CTX *kssl_ctx, krb5_data *indata, + krb5_ticket_times *ttimes, KSSL_ERR *kssl_err); +krb5_error_code kssl_ctx_setkey(KSSL_CTX *kssl_ctx, krb5_keyblock *session); +void kssl_err_set(KSSL_ERR *kssl_err, int reason, char *text); +void kssl_krb5_free_data_contents(krb5_context context, krb5_data *data); +krb5_error_code kssl_build_principal_2(krb5_context context, + krb5_principal *princ, int rlen, const char *realm, + int slen, const char *svc, int hlen, const char *host); +krb5_error_code kssl_validate_times(krb5_timestamp atime, + krb5_ticket_times *ttimes); +krb5_error_code kssl_check_authent(KSSL_CTX *kssl_ctx, krb5_data *authentp, + krb5_timestamp *atimep, KSSL_ERR *kssl_err); +unsigned char *kssl_skip_confound(krb5_enctype enctype, unsigned char *authn); + +#ifdef __cplusplus +} +#endif +#endif /* OPENSSL_NO_KRB5 */ +#endif /* KSSL_H */ diff --git a/app/openssl/ssl/kssl_lcl.h b/app/openssl/ssl/kssl_lcl.h new file mode 100644 index 00000000..c039c91b --- /dev/null +++ b/app/openssl/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/app/openssl/ssl/s23_clnt.c b/app/openssl/ssl/s23_clnt.c new file mode 100644 index 00000000..f41fe3ab --- /dev/null +++ b/app/openssl/ssl/s23_clnt.c @@ -0,0 +1,703 @@ +/* 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 + 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; + } + +static int ssl23_client_hello(SSL *s) + { + unsigned char *buf; + unsigned char *p,*d; + int i,ch_len; + unsigned long Time,l; + int ssl2_compat; + int version = 0, version_major, version_minor; +#ifndef OPENSSL_NO_COMP + int j; + SSL_COMP *comp; +#endif + int ret; + + ssl2_compat = (s->options & SSL_OP_NO_SSLv2) ? 0 : 1; + + if (ssl2_compat && ssl23_no_ssl2_ciphers(s)) + ssl2_compat = 0; + + if (!(s->options & SSL_OP_NO_TLSv1)) + { + version = TLS1_VERSION; + } + else if (!(s->options & SSL_OP_NO_SSLv3)) + { + version = SSL3_VERSION; + } + else if (!(s->options & SSL_OP_NO_SSLv2)) + { + version = SSL2_VERSION; + } +#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; + Time=(unsigned long)time(NULL); /* Time */ + l2n(Time,p); + if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0) + return -1; + + if (version == TLS1_VERSION) + { + version_major = TLS1_VERSION_MAJOR; + version_minor = TLS1_VERSION_MINOR; + } + 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; + } + 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; + *(d++) = version_minor; /* arguably we should send the *lowest* suported version here + * (indicating, e.g., TLS 1.0 in "SSL 3.0 format") */ + 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] == SSL3_VERSION_MINOR || p[2] == TLS1_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)) + { + 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 + { + 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 (!s->session_creation_enabled) + { + if (!(s->client_version == SSL2_VERSION)) + ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE); + SSLerr(SSL_F_SSL23_GET_SERVER_HELLO,SSL_R_SESSION_MAY_NOT_BE_CREATED); + goto err; + } + if (!ssl_get_new_session(s,0)) + goto err; + + return(SSL_connect(s)); +err: + return(-1); + } diff --git a/app/openssl/ssl/s23_lib.c b/app/openssl/ssl/s23_lib.c new file mode 100644 index 00000000..3bf72831 --- /dev/null +++ b/app/openssl/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/app/openssl/ssl/s23_meth.c b/app/openssl/ssl/s23_meth.c new file mode 100644 index 00000000..c6099efc --- /dev/null +++ b/app/openssl/ssl/s23_meth.c @@ -0,0 +1,88 @@ +/* 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 +#endif + return(NULL); + } + +IMPLEMENT_ssl23_meth_func(SSLv23_method, + ssl23_accept, + ssl23_connect, + ssl23_get_method) + diff --git a/app/openssl/ssl/s23_pkt.c b/app/openssl/ssl/s23_pkt.c new file mode 100644 index 00000000..4ca6a1b2 --- /dev/null +++ b/app/openssl/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/app/openssl/ssl/s23_srvr.c b/app/openssl/ssl/s23_srvr.c new file mode 100644 index 00000000..e22879c8 --- /dev/null +++ b/app/openssl/ssl/s23_srvr.c @@ -0,0 +1,599 @@ +/* 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> + +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 + 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 (!(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 (!(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; + } + } + + 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]; + +/* The SSL2 protocol allows n to be larger, just pick + * a reasonable buffer size. */ +#if SSL3_RT_DEFAULT_PACKET_SIZE < 1024*4 - SSL3_RT_DEFAULT_WRITE_OVERHEAD +#error "SSL3_RT_DEFAULT_PACKET_SIZE is too small." +#endif + n=((p[0]&0x7f)<<8)|p[1]; + if (n > SSL3_RT_DEFAULT_PACKET_SIZE - 2) + { + 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_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/app/openssl/ssl/s2_clnt.c b/app/openssl/ssl/s2_clnt.c new file mode 100644 index 00000000..00ac158f --- /dev/null +++ b/app/openssl/ssl/s2_clnt.c @@ -0,0 +1,1125 @@ +/* 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); + } +#ifdef __APPLE_CC__ + /* The Rhapsody 5.5 (a.k.a. MacOS X) compiler bug + * workaround. <appro@fy.chalmers.se> */ + s->hit=(i=*(p++))?1:0; +#else + s->hit=(*(p++))?1:0; +#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 (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/app/openssl/ssl/s2_enc.c b/app/openssl/ssl/s2_enc.c new file mode 100644 index 00000000..ff3395f4 --- /dev/null +++ b/app/openssl/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/app/openssl/ssl/s2_lib.c b/app/openssl/ssl/s2_lib.c new file mode 100644 index 00000000..99146041 --- /dev/null +++ b/app/openssl/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/app/openssl/ssl/s2_meth.c b/app/openssl/ssl/s2_meth.c new file mode 100644 index 00000000..f0e8ca59 --- /dev/null +++ b/app/openssl/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/app/openssl/ssl/s2_pkt.c b/app/openssl/ssl/s2_pkt.c new file mode 100644 index 00000000..ac963b2d --- /dev/null +++ b/app/openssl/ssl/s2_pkt.c @@ -0,0 +1,744 @@ +/* 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 ( (memcmp(mac,s->s2->mac_data, + (unsigned int)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/app/openssl/ssl/s2_srvr.c b/app/openssl/ssl/s2_srvr.c new file mode 100644 index 00000000..bc885e8e --- /dev/null +++ b/app/openssl/ssl/s2_srvr.c @@ -0,0 +1,1142 @@ +/* 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); + 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); + + 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); + EVP_VerifyUpdate(&ctx,buf2,(unsigned int)i); + 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/app/openssl/ssl/s3_both.c b/app/openssl/ssl/s3_both.c new file mode 100644 index 00000000..508e3902 --- /dev/null +++ b/app/openssl/ssl/s3_both.c @@ -0,0 +1,867 @@ +/* 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); + 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 (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 (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; + STACK_OF(X509) *cert_chain; + + cert_chain = SSL_get_certificate_chain(s, x); + + if ((s->mode & SSL_MODE_NO_AUTO_CHAIN) || s->ctx->extra_certs || cert_chain) + 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); + } + + for (i=0; i<sk_X509_num(cert_chain); i++) + if (ssl3_add_cert_to_buf(buf, &l, sk_X509_value(cert_chain,i))) + 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) + { + if (SSL_get_mode(s) & SSL_MODE_SMALL_BUFFERS) + { + len = SSL3_RT_DEFAULT_PACKET_SIZE; + } + else + { + 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) + { + if (SSL_get_mode(s) & SSL_MODE_SMALL_BUFFERS) + { + len = SSL3_RT_DEFAULT_PACKET_SIZE; + } + else + { + len = s->max_send_fragment; + } + len += 0 + + 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/app/openssl/ssl/s3_clnt.c b/app/openssl/ssl/s3_clnt.c new file mode 100644 index 00000000..42bcd629 --- /dev/null +++ b/app/openssl/ssl/s3_clnt.c @@ -0,0 +1,3153 @@ +/* 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> +#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); +#if 0 /* Send app data in separate packet, otherwise, some particular site + * (only one site so far) closes the socket. + * Note: there is a very small chance that two TCP packets + * could be arriving at server combined into a single TCP packet, + * then trigger that site to break. We haven't encounter that though. + */ + if (SSL_get_mode(s) & SSL_MODE_HANDSHAKE_CUTTHROUGH) + { + /* Send app data along with CCS/Finished */ + s->s3->flags |= SSL3_FLAGS_DELAY_CLIENT_FINISHED; + } +#endif + + for (;;) + { + state=s->state; + + switch(s->state) + { + case SSL_ST_RENEGOTIATE: + s->new_session=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; + 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; + 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->next_proto_negotiated) + 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 + { + if ((SSL_get_mode(s) & SSL_MODE_HANDSHAKE_CUTTHROUGH) && SSL_get_cipher_bits(s, NULL) >= 128 + && s->s3->previous_server_finished_len == 0 /* no cutthrough on renegotiation (would complicate the state machine) */ + ) + { + if (s->s3->flags & SSL3_FLAGS_DELAY_CLIENT_FINISHED) + { + s->state=SSL3_ST_CUTTHROUGH_COMPLETE; + s->s3->flags|=SSL3_FLAGS_POP_BUFFER; + s->s3->delay_buf_pop_ret=0; + } + else + { + s->s3->tmp.next_state=SSL3_ST_CUTTHROUGH_COMPLETE; + } + } + 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: + + 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 SSL3_ST_CUTTHROUGH_COMPLETE: +#ifndef OPENSSL_NO_TLSEXT + /* Allow NewSessionTicket if ticket expected */ + if (s->tlsext_ticket_expected) + s->state=SSL3_ST_CR_SESSION_TICKET_A; + else +#endif + s->state=SSL3_ST_CR_FINISHED_A; + + /* SSL_write() will take care of flushing buffered data if + * DELAY_CLIENT_FINISHED is set. + */ + if (!(s->s3->flags & SSL3_FLAGS_DELAY_CLIENT_FINISHED)) + ssl_free_wbio_buffer(s); + ret = 1; + goto end; + /* 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->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 Time,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 (!s->session_creation_enabled) + { + ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE); + SSLerr(SSL_F_SSL3_CLIENT_HELLO,SSL_R_SESSION_MAY_NOT_BE_CREATED); + goto err; + } + if (!ssl_get_new_session(s,0)) + goto err; + } + /* else use the pre-loaded session */ + + p=s->s3->client_random; + Time=(unsigned long)time(NULL); /* Time */ + l2n(Time,p); + if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0) + goto err; + + /* Do the message type and length last */ + d=p= &(buf[4]); + + *(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 > (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; + } + 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->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 (!s->session_creation_enabled) + { + ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE); + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_SESSION_MAY_NOT_BE_CREATED); + goto err; + } + 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; + } + 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; + if (!ssl3_digest_cached_records(s)) + goto f_err; + + /* lets get the compression algorithm */ + /* COMPRESSION */ +#ifdef OPENSSL_NO_COMP + if (*(p++) != 0) + { + al=SSL_AD_ILLEGAL_PARAMETER; + SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM); + goto f_err; + } + /* If compression is disabled we'd better not try to resume a session + * using compression. + */ + if (s->session->compress_meth != 0) + { + 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 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; +#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_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) + { + 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) + { + int num; + + j=0; + q=md_buf; + 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,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 +#ifndef OPENSSL_NO_DSA + if (pkey->type == EVP_PKEY_DSA) + { + /* lets do DSS */ + EVP_VerifyInit_ex(&md_ctx,EVP_dss1(), 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 +#endif +#ifndef OPENSSL_NO_ECDSA + if (pkey->type == EVP_PKEY_EC) + { + /* let's do ECDSA */ + EVP_VerifyInit_ex(&md_ctx,EVP_ecdsa(), 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 +#endif + { + SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,ERR_R_INTERNAL_ERROR); + goto 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; + 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; + + /* 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 ((llen+ctype_num+2+1) != 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 = SSL3_AL_FATAL,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 = SSL3_AL_FATAL,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; + + /* 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_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; +#ifndef OPENSSL_NO_RSA + unsigned u=0; +#endif + unsigned long n; + int j; + + 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) + { + s->method->ssl3_enc->cert_verify_mac(s, + NID_sha1, + &(data[MD5_DIGEST_LENGTH])); + } + else + { + ERR_clear_error(); + } +#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_PKEY_CTX_free(pctx); + return(ssl3_do_write(s,SSL3_RT_HANDSHAKE)); +err: + 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->s3->tmp.new_cipher) == 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); + } + +/* 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 +# ifndef OPENSSL_NO_NEXTPROTONEG +int ssl3_send_next_proto(SSL *s) + { + unsigned int len, padding_len; + unsigned char *d; + + if (s->state == SSL3_ST_CW_NEXT_PROTO_A) + { + len = s->next_proto_negotiated_len; + padding_len = 32 - ((len + 2) % 32); + d = (unsigned char *)s->init_buf->data; + d[4] = len; + memcpy(d + 5, s->next_proto_negotiated, len); + d[5 + len] = padding_len; + memset(d + 6 + len, 0, padding_len); + *(d++)=SSL3_MT_NEXT_PROTO; + l2n3(2 + len + padding_len, d); + s->state = SSL3_ST_CW_NEXT_PROTO_B; + s->init_num = 4 + 2 + len + padding_len; + s->init_off = 0; + } + + return ssl3_do_write(s, SSL3_RT_HANDSHAKE); + } +# endif + +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/app/openssl/ssl/s3_enc.c b/app/openssl/ssl/s3_enc.c new file mode 100644 index 00000000..b1459707 --- /dev/null +++ b/app/openssl/ssl/s3_enc.c @@ -0,0 +1,849 @@ +/* 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_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; + } + +int ssl3_enc(SSL *s, int send) + { + SSL3_RECORD *rec; + EVP_CIPHER_CTX *ds; + unsigned long l; + int bs,i; + 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) + { + SSLerr(SSL_F_SSL3_ENC,SSL_R_BLOCK_CIPHER_PAD_IS_WRONG); + ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECRYPTION_FAILED); + return 0; + } + /* otherwise, rec->length >= bs */ + } + + EVP_Cipher(ds,rec->data,rec->input,l); + + if ((bs != 1) && !send) + { + i=rec->data[l-1]+1; + /* SSL 3.0 bounds the number of padding bytes by the block size; + * padding bytes (except the last one) are arbitrary */ + if (i > bs) + { + /* Incorrect padding. SSLerr() and ssl3_alert are done + * by caller: we don't want to reveal whether this is + * a decryption error or a MAC verification failure + * (see http://www.openssl.org/~bodo/tls-cbc.txt) */ + return -1; + } + /* now i <= bs <= rec->length */ + rec->length-=i; + } + } + 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) + { + 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 & s->s3->tmp.new_cipher->algorithm2) && md) + { + s->s3->handshake_dgst[i]=EVP_MD_CTX_create(); + 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; + } + } + /* 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_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; + unsigned int md_size; + 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; + + /* 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); + + 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/app/openssl/ssl/s3_lib.c b/app/openssl/ssl/s3_lib.c new file mode 100644 index 00000000..28ee4746 --- /dev/null +++ b/app/openssl/ssl/s3_lib.c @@ -0,0 +1,3357 @@ +/* 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, + }, + +#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 + { + 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_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_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_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 */ + +#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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_HANDSHAKE_MAC_DEFAULT|TLS1_PRF, + 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, + }; + +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; + + 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); + 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; + +#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 + + rp = s->s3->rbuf.buf; + wp = s->s3->wbuf.buf; + rlen = s->s3->rbuf.len; + wlen = s->s3->wbuf.len; + 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; + + 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 + } + +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; + +#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; + +#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; + + 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; + +#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); + 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); + + 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; + +#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) + { + 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 n,ret; + + clear_sys_error(); + if ((s->s3->flags & SSL3_FLAGS_POP_BUFFER) && (s->wbio == s->bbio)) + { + /* Deal with an application that calls SSL_read() when handshake data + * is yet to be written. + */ + if (BIO_wpending(s->wbio) > 0) + { + s->rwstate=SSL_WRITING; + n=BIO_flush(s->wbio); + if (n <= 0) return(n); + s->rwstate=SSL_NOTHING; + } + } + 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); + } + diff --git a/app/openssl/ssl/s3_meth.c b/app/openssl/ssl/s3_meth.c new file mode 100644 index 00000000..cdddb17b --- /dev/null +++ b/app/openssl/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/app/openssl/ssl/s3_pkt.c b/app/openssl/ssl/s3_pkt.c new file mode 100644 index 00000000..0d3874ae --- /dev/null +++ b/app/openssl/ssl/s3_pkt.c @@ -0,0 +1,1502 @@ +/* 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 <errno.h> +#define USE_SOCKETS +#include "ssl_locl.h" +#include <openssl/evp.h> +#include <openssl/buffer.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; + int mac_size; + int clear=0; + size_t extra; + int decryption_failed_or_bad_record_mac = 0; + unsigned char *mac = NULL; +#if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0 + long align=SSL3_ALIGN_PAYLOAD; +#else + long align=0; +#endif + + 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 (!(SSL_get_mode(s) & SSL_MODE_SMALL_BUFFERS) && + 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)) + /* 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 we receive a valid record larger than the current buffer size, + * allocate some memory for it. + */ + if (rr->length > s->s3->rbuf.len - SSL3_RT_HEADER_LENGTH - align) + { + if ((p=OPENSSL_realloc(s->s3->rbuf.buf, rr->length + SSL3_RT_HEADER_LENGTH + align))==NULL) + { + SSLerr(SSL_F_SSL3_GET_RECORD,ERR_R_MALLOC_FAILURE); + goto err; + } + s->s3->rbuf.buf=p; + s->s3->rbuf.len=rr->length + SSL3_RT_HEADER_LENGTH + align; + s->packet= &(s->s3->rbuf.buf[0]); + } + + 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); + if (enc_err <= 0) + { + if (enc_err == 0) + /* SSLerr() and ssl3_send_alert() have been called */ + goto err; + + /* Otherwise enc_err == -1, which indicates bad padding + * (rec->length has not been changed in this case). + * To minimize information leaked via timing, we will perform + * the MAC computation anyway. */ + decryption_failed_or_bad_record_mac = 1; + } + +#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)) + clear=1; + + if (!clear) + { + /* !clear => s->read_hash != NULL => mac_size != -1 */ + mac_size=EVP_MD_CTX_size(s->read_hash); + OPENSSL_assert(mac_size >= 0); + + if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+extra+mac_size) + { +#if 0 /* OK only for stream ciphers (then rr->length is visible from ciphertext anyway) */ + al=SSL_AD_RECORD_OVERFLOW; + SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_PRE_MAC_LENGTH_TOO_LONG); + goto f_err; +#else + decryption_failed_or_bad_record_mac = 1; +#endif + } + /* check the MAC for rr->input (it's in mac_size bytes at the tail) */ + if (rr->length >= (unsigned int)mac_size) + { + rr->length -= mac_size; + mac = &rr->data[rr->length]; + } + else + { + /* record (minus padding) is too short to contain a MAC */ +#if 0 /* OK only for stream ciphers */ + al=SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_LENGTH_TOO_SHORT); + goto f_err; +#else + decryption_failed_or_bad_record_mac = 1; + rr->length = 0; +#endif + } + i=s->method->ssl3_enc->mac(s,md,0); + if (i < 0 || mac == NULL || memcmp(md, mac, (size_t)mac_size) != 0) + { + decryption_failed_or_bad_record_mac = 1; + } + } + + if (decryption_failed_or_bad_record_mac) + { + /* 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 tot,n,nw; + int i; + unsigned int max_plain_length; + + s->rwstate=SSL_NOTHING; + 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; + } + } + + n=(len-tot); + for (;;) + { + if (type == SSL3_RT_APPLICATION_DATA && (SSL_get_mode(s) & SSL_MODE_SMALL_BUFFERS)) + max_plain_length = SSL3_RT_DEFAULT_PLAIN_LENGTH; + else + max_plain_length = s->max_send_fragment; + + if (n > max_plain_length) + nw = max_plain_length; + 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; + long align=0; + SSL3_RECORD *wr; + SSL3_BUFFER *wb=&(s->s3->wbuf); + SSL_SESSION *sess; + + if (wb->buf == NULL) + if (!ssl3_setup_write_buffer(s)) + return -1; + + /* first check if there is a SSL3_BUFFER still being written + * out. This will happen with non blocking IO */ + if (wb->left != 0) + return(ssl3_write_pending(s,type,buf,len)); + + /* If we have an alert to send, lets send it */ + if (s->s3->alert_dispatch) + { + i=s->method->ssl_dispatch_alert(s); + if (i <= 0) + return(i); + /* if it went, fall through and send more stuff */ + } + + 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)) + clear=1; + + if (clear) + 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; + } + + /* resize if necessary to hold the data. */ + if (len + SSL3_RT_DEFAULT_WRITE_OVERHEAD > wb->len) + { + if ((p=OPENSSL_realloc(wb->buf, len + SSL3_RT_DEFAULT_WRITE_OVERHEAD))==NULL) + { + SSLerr(SSL_F_DO_SSL3_WRITE,ERR_R_MALLOC_FAILURE); + goto err; + } + wb->buf = p; + wb->len = len + SSL3_RT_DEFAULT_WRITE_OVERHEAD; + } + + 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); + *(p++)=s->version&0xff; + + /* field where we are to write out packet length */ + plen=p; + p+=2; + + /* lets setup the record stuff. */ + wr->data=p; + 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]),1) < 0) + goto err; + wr->length+=mac_size; + wr->input=p; + wr->data=p; + } + + /* 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) + 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; + } + + 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; + } + } + 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; + } + + 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->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 just ignores unknown message types */ + if (s->version == TLS1_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; +#ifdef OPENSSL_NO_NEXTPROTONEG + const char *sender; + int slen; +#endif + + 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) + { + /* 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); + +#ifdef OPENSSL_NO_NEXTPROTONEG + /* 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; + } + + s->s3->tmp.peer_finish_md_len = s->method->ssl3_enc->final_finish_mac(s, + sender,slen,s->s3->tmp.peer_finish_md); +#endif + + 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/app/openssl/ssl/s3_srvr.c b/app/openssl/ssl/s3_srvr.c new file mode 100644 index 00000000..60591622 --- /dev/null +++ b/app/openssl/ssl/s3_srvr.c @@ -0,0 +1,3314 @@ +/* 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); + } + +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); + } + + for (;;) + { + state=s->state; + + switch (s->state) + { + case SSL_ST_RENEGOTIATE: + s->new_session=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; + + 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; + ret=ssl3_get_client_hello(s); + if (ret <= 0) goto end; + + s->new_session = 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 */ + 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 + || (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; + } + 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 + { + 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: + + /* 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: + ret=ssl3_get_finished(s,SSL3_ST_SR_FINISHED_A, + SSL3_ST_SR_FINISHED_B); + if (ret <= 0) goto end; +#ifndef OPENSSL_NO_TLSEXT + if (s->tlsext_ticket_expected) + s->state=SSL3_ST_SW_SESSION_TICKET_A; + else if (s->hit) + s->state=SSL_ST_OK; +#else + if (s->hit) + s->state=SSL_ST_OK; +#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->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->new_session == 2) /* skipped if we just sent a HelloRequest */ + { + /* actually not necessarily a 'new' session unless + * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION is set */ + + 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) + { + /* 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 + 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) + { + /* 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 session reuse during renegotiation + * (i.e. when s->new_session is true), option + * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION is new with 0.9.7. + * Maybe this optional behaviour should always have been the default, + * but we cannot safely change the default behaviour (or new applications + * might be written that become totally unsecure when compiled with + * an earlier library version) + */ + if ((s->new_session && (s->options & SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION))) + { + if (!s->session_creation_enabled) + { + ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE); + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_SESSION_MAY_NOT_BE_CREATED); + goto err; + } + 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 (!s->session_creation_enabled) + { + ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_HANDSHAKE_FAILURE); + SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_SESSION_MAY_NOT_BE_CREATED); + goto err; + } + 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(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 long Time; + unsigned char *pos; + Time=(unsigned long)time(NULL); /* Time */ + pos=s->s3->server_random; + l2n(Time,pos); + if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 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 (!ssl3_digest_cached_records(s)) + goto f_err; + + /* we now have the following setup. + * client_random + * cipher_list - our prefered list of ciphers + * ciphers - the clients prefered list of ciphers + * compression - basically ignored right now + * ssl version is set - sslv3 + * s->session - The ssl session has been setup. + * s->hit - session reuse flag + * s->tmp.new_cipher - the new cipher to use. + */ + + 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; +#ifdef OPENSSL_NO_TLSEXT + unsigned long Time; +#endif + + 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; + /* Generate server_random if it was not needed previously */ + Time=(unsigned long)time(NULL); /* Time */ + l2n(Time,p); + if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 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; + + /* 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. + * + * We also have an additional case where stateless session + * resumption is successful: we always send back the old + * session id. In this case s->hit is non zero: this can + * only happen if stateless session resumption is succesful + * if session caching is disabled so existing functionality + * is unaffected. + */ + 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; + 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 */ + { + 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; 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) + { + 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; 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[4]) + * 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[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 !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[4]),n); + if (!EVP_SignFinal(&md_ctx,&(p[2]), + (unsigned int *)&i,pkey)) + { + SSLerr(SSL_F_SSL3_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[4]),n); + if (!EVP_SignFinal(&md_ctx,&(p[2]), + (unsigned int *)&i,pkey)) + { + SSLerr(SSL_F_SSL3_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_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++; + + 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 + 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); + 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 + 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; + + /* 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 ((*p!=( V_ASN1_SEQUENCE| V_ASN1_CONSTRUCTED))) + { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED); + goto gerr; + } + if (p[1] == 0x81) + { + start = p+3; + inlen = p[2]; + } + else if (p[1] < 0x80) + { + start = p+2; + inlen = p[1]; + } + else + { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED); + goto gerr; + } + 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) +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; + + n=s->method->ssl_get_message(s, + SSL3_ST_SR_CERT_VRFY_A, + SSL3_ST_SR_CERT_VRFY_B, + -1, + 514, /* 514? */ + &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 + { + 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; + } + +#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: + 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; + } + } + 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 +int ssl3_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; + 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 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; + senc = OPENSSL_malloc(slen); + if (!senc) + return -1; + p = senc; + i2d_SSL_SESSION(s->session, &p); + + 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); + } + 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; + 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_NPN +/* 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; + unsigned 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/app/openssl/ssl/ssl.h b/app/openssl/ssl/ssl.h new file mode 100644 index 00000000..9cb2bf93 --- /dev/null +++ b/app/openssl/ssl/ssl.h @@ -0,0 +1,2382 @@ +/* ssl/ssl.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_H +#define HEADER_SSL_H + +#include <openssl/e_os2.h> + +#ifndef OPENSSL_NO_COMP +#include <openssl/comp.h> +#endif +#ifndef OPENSSL_NO_BIO +#include <openssl/bio.h> +#endif +#ifndef OPENSSL_NO_DEPRECATED +#ifndef OPENSSL_NO_X509 +#include <openssl/x509.h> +#endif +#include <openssl/crypto.h> +#include <openssl/lhash.h> +#include <openssl/buffer.h> +#endif +#include <openssl/pem.h> +#include <openssl/hmac.h> + +#include <openssl/kssl.h> +#include <openssl/safestack.h> +#include <openssl/symhacks.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* SSLeay version number for ASN.1 encoding of the session information */ +/* Version 0 - initial version + * Version 1 - added the optional peer certificate + */ +#define SSL_SESSION_ASN1_VERSION 0x0001 + +/* text strings for the ciphers */ +#define SSL_TXT_NULL_WITH_MD5 SSL2_TXT_NULL_WITH_MD5 +#define SSL_TXT_RC4_128_WITH_MD5 SSL2_TXT_RC4_128_WITH_MD5 +#define SSL_TXT_RC4_128_EXPORT40_WITH_MD5 SSL2_TXT_RC4_128_EXPORT40_WITH_MD5 +#define SSL_TXT_RC2_128_CBC_WITH_MD5 SSL2_TXT_RC2_128_CBC_WITH_MD5 +#define SSL_TXT_RC2_128_CBC_EXPORT40_WITH_MD5 SSL2_TXT_RC2_128_CBC_EXPORT40_WITH_MD5 +#define SSL_TXT_IDEA_128_CBC_WITH_MD5 SSL2_TXT_IDEA_128_CBC_WITH_MD5 +#define SSL_TXT_DES_64_CBC_WITH_MD5 SSL2_TXT_DES_64_CBC_WITH_MD5 +#define SSL_TXT_DES_64_CBC_WITH_SHA SSL2_TXT_DES_64_CBC_WITH_SHA +#define SSL_TXT_DES_192_EDE3_CBC_WITH_MD5 SSL2_TXT_DES_192_EDE3_CBC_WITH_MD5 +#define SSL_TXT_DES_192_EDE3_CBC_WITH_SHA SSL2_TXT_DES_192_EDE3_CBC_WITH_SHA + +/* VRS Additional Kerberos5 entries + */ +#define SSL_TXT_KRB5_DES_64_CBC_SHA SSL3_TXT_KRB5_DES_64_CBC_SHA +#define SSL_TXT_KRB5_DES_192_CBC3_SHA SSL3_TXT_KRB5_DES_192_CBC3_SHA +#define SSL_TXT_KRB5_RC4_128_SHA SSL3_TXT_KRB5_RC4_128_SHA +#define SSL_TXT_KRB5_IDEA_128_CBC_SHA SSL3_TXT_KRB5_IDEA_128_CBC_SHA +#define SSL_TXT_KRB5_DES_64_CBC_MD5 SSL3_TXT_KRB5_DES_64_CBC_MD5 +#define SSL_TXT_KRB5_DES_192_CBC3_MD5 SSL3_TXT_KRB5_DES_192_CBC3_MD5 +#define SSL_TXT_KRB5_RC4_128_MD5 SSL3_TXT_KRB5_RC4_128_MD5 +#define SSL_TXT_KRB5_IDEA_128_CBC_MD5 SSL3_TXT_KRB5_IDEA_128_CBC_MD5 + +#define SSL_TXT_KRB5_DES_40_CBC_SHA SSL3_TXT_KRB5_DES_40_CBC_SHA +#define SSL_TXT_KRB5_RC2_40_CBC_SHA SSL3_TXT_KRB5_RC2_40_CBC_SHA +#define SSL_TXT_KRB5_RC4_40_SHA SSL3_TXT_KRB5_RC4_40_SHA +#define SSL_TXT_KRB5_DES_40_CBC_MD5 SSL3_TXT_KRB5_DES_40_CBC_MD5 +#define SSL_TXT_KRB5_RC2_40_CBC_MD5 SSL3_TXT_KRB5_RC2_40_CBC_MD5 +#define SSL_TXT_KRB5_RC4_40_MD5 SSL3_TXT_KRB5_RC4_40_MD5 + +#define SSL_TXT_KRB5_DES_40_CBC_SHA SSL3_TXT_KRB5_DES_40_CBC_SHA +#define SSL_TXT_KRB5_DES_40_CBC_MD5 SSL3_TXT_KRB5_DES_40_CBC_MD5 +#define SSL_TXT_KRB5_DES_64_CBC_SHA SSL3_TXT_KRB5_DES_64_CBC_SHA +#define SSL_TXT_KRB5_DES_64_CBC_MD5 SSL3_TXT_KRB5_DES_64_CBC_MD5 +#define SSL_TXT_KRB5_DES_192_CBC3_SHA SSL3_TXT_KRB5_DES_192_CBC3_SHA +#define SSL_TXT_KRB5_DES_192_CBC3_MD5 SSL3_TXT_KRB5_DES_192_CBC3_MD5 +#define SSL_MAX_KRB5_PRINCIPAL_LENGTH 256 + +#define SSL_MAX_SSL_SESSION_ID_LENGTH 32 +#define SSL_MAX_SID_CTX_LENGTH 32 + +#define SSL_MIN_RSA_MODULUS_LENGTH_IN_BYTES (512/8) +#define SSL_MAX_KEY_ARG_LENGTH 8 +#define SSL_MAX_MASTER_KEY_LENGTH 48 + + +/* These are used to specify which ciphers to use and not to use */ + +#define SSL_TXT_EXP40 "EXPORT40" +#define SSL_TXT_EXP56 "EXPORT56" +#define SSL_TXT_LOW "LOW" +#define SSL_TXT_MEDIUM "MEDIUM" +#define SSL_TXT_HIGH "HIGH" +#define SSL_TXT_FIPS "FIPS" + +#define SSL_TXT_kFZA "kFZA" /* unused! */ +#define SSL_TXT_aFZA "aFZA" /* unused! */ +#define SSL_TXT_eFZA "eFZA" /* unused! */ +#define SSL_TXT_FZA "FZA" /* unused! */ + +#define SSL_TXT_aNULL "aNULL" +#define SSL_TXT_eNULL "eNULL" +#define SSL_TXT_NULL "NULL" + +#define SSL_TXT_kRSA "kRSA" +#define SSL_TXT_kDHr "kDHr" /* no such ciphersuites supported! */ +#define SSL_TXT_kDHd "kDHd" /* no such ciphersuites supported! */ +#define SSL_TXT_kDH "kDH" /* no such ciphersuites supported! */ +#define SSL_TXT_kEDH "kEDH" +#define SSL_TXT_kKRB5 "kKRB5" +#define SSL_TXT_kECDHr "kECDHr" +#define SSL_TXT_kECDHe "kECDHe" +#define SSL_TXT_kECDH "kECDH" +#define SSL_TXT_kEECDH "kEECDH" +#define SSL_TXT_kPSK "kPSK" +#define SSL_TXT_kGOST "kGOST" + +#define SSL_TXT_aRSA "aRSA" +#define SSL_TXT_aDSS "aDSS" +#define SSL_TXT_aDH "aDH" /* no such ciphersuites supported! */ +#define SSL_TXT_aECDH "aECDH" +#define SSL_TXT_aKRB5 "aKRB5" +#define SSL_TXT_aECDSA "aECDSA" +#define SSL_TXT_aPSK "aPSK" +#define SSL_TXT_aGOST94 "aGOST94" +#define SSL_TXT_aGOST01 "aGOST01" +#define SSL_TXT_aGOST "aGOST" + +#define SSL_TXT_DSS "DSS" +#define SSL_TXT_DH "DH" +#define SSL_TXT_EDH "EDH" /* same as "kEDH:-ADH" */ +#define SSL_TXT_ADH "ADH" +#define SSL_TXT_RSA "RSA" +#define SSL_TXT_ECDH "ECDH" +#define SSL_TXT_EECDH "EECDH" /* same as "kEECDH:-AECDH" */ +#define SSL_TXT_AECDH "AECDH" +#define SSL_TXT_ECDSA "ECDSA" +#define SSL_TXT_KRB5 "KRB5" +#define SSL_TXT_PSK "PSK" + +#define SSL_TXT_DES "DES" +#define SSL_TXT_3DES "3DES" +#define SSL_TXT_RC4 "RC4" +#define SSL_TXT_RC2 "RC2" +#define SSL_TXT_IDEA "IDEA" +#define SSL_TXT_SEED "SEED" +#define SSL_TXT_AES128 "AES128" +#define SSL_TXT_AES256 "AES256" +#define SSL_TXT_AES "AES" +#define SSL_TXT_CAMELLIA128 "CAMELLIA128" +#define SSL_TXT_CAMELLIA256 "CAMELLIA256" +#define SSL_TXT_CAMELLIA "CAMELLIA" + +#define SSL_TXT_MD5 "MD5" +#define SSL_TXT_SHA1 "SHA1" +#define SSL_TXT_SHA "SHA" /* same as "SHA1" */ +#define SSL_TXT_GOST94 "GOST94" +#define SSL_TXT_GOST89MAC "GOST89MAC" + +#define SSL_TXT_SSLV2 "SSLv2" +#define SSL_TXT_SSLV3 "SSLv3" +#define SSL_TXT_TLSV1 "TLSv1" + +#define SSL_TXT_EXP "EXP" +#define SSL_TXT_EXPORT "EXPORT" + +#define SSL_TXT_ALL "ALL" + +/* + * COMPLEMENTOF* definitions. These identifiers are used to (de-select) + * ciphers normally not being used. + * Example: "RC4" will activate all ciphers using RC4 including ciphers + * without authentication, which would normally disabled by DEFAULT (due + * the "!ADH" being part of default). Therefore "RC4:!COMPLEMENTOFDEFAULT" + * will make sure that it is also disabled in the specific selection. + * COMPLEMENTOF* identifiers are portable between version, as adjustments + * to the default cipher setup will also be included here. + * + * COMPLEMENTOFDEFAULT does not experience the same special treatment that + * DEFAULT gets, as only selection is being done and no sorting as needed + * for DEFAULT. + */ +#define SSL_TXT_CMPALL "COMPLEMENTOFALL" +#define SSL_TXT_CMPDEF "COMPLEMENTOFDEFAULT" + +/* The following cipher list is used by default. + * It also is substituted when an application-defined cipher list string + * starts with 'DEFAULT'. */ +#define SSL_DEFAULT_CIPHER_LIST "ALL:!aNULL:!eNULL:!SSLv2" +/* As of OpenSSL 1.0.0, ssl_create_cipher_list() in ssl/ssl_ciph.c always + * starts with a reasonable order, and all we have to do for DEFAULT is + * throwing out anonymous and unencrypted ciphersuites! + * (The latter are not actually enabled by ALL, but "ALL:RSA" would enable + * some of them.) + */ + +/* Used in SSL_set_shutdown()/SSL_get_shutdown(); */ +#define SSL_SENT_SHUTDOWN 1 +#define SSL_RECEIVED_SHUTDOWN 2 + +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if (defined(OPENSSL_NO_RSA) || defined(OPENSSL_NO_MD5)) && !defined(OPENSSL_NO_SSL2) +#define OPENSSL_NO_SSL2 +#endif + +#define SSL_FILETYPE_ASN1 X509_FILETYPE_ASN1 +#define SSL_FILETYPE_PEM X509_FILETYPE_PEM + +/* This is needed to stop compilers complaining about the + * 'struct ssl_st *' function parameters used to prototype callbacks + * in SSL_CTX. */ +typedef struct ssl_st *ssl_crock_st; +typedef struct tls_session_ticket_ext_st TLS_SESSION_TICKET_EXT; + +/* used to hold info on the particular ciphers used */ +typedef struct ssl_cipher_st + { + int valid; + const char *name; /* text name */ + unsigned long id; /* id, 4 bytes, first is version */ + + /* changed in 0.9.9: these four used to be portions of a single value 'algorithms' */ + unsigned long algorithm_mkey; /* key exchange algorithm */ + unsigned long algorithm_auth; /* server authentication */ + unsigned long algorithm_enc; /* symmetric encryption */ + unsigned long algorithm_mac; /* symmetric authentication */ + unsigned long algorithm_ssl; /* (major) protocol version */ + + unsigned long algo_strength; /* strength and export flags */ + unsigned long algorithm2; /* Extra flags */ + int strength_bits; /* Number of bits really used */ + int alg_bits; /* Number of bits for algorithm */ + } SSL_CIPHER; + +DECLARE_STACK_OF(SSL_CIPHER) + +typedef int (*tls_session_ticket_ext_cb_fn)(SSL *s, const unsigned char *data, int len, void *arg); +typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg); + +/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */ +typedef struct ssl_method_st + { + int version; + int (*ssl_new)(SSL *s); + void (*ssl_clear)(SSL *s); + void (*ssl_free)(SSL *s); + int (*ssl_accept)(SSL *s); + int (*ssl_connect)(SSL *s); + int (*ssl_read)(SSL *s,void *buf,int len); + int (*ssl_peek)(SSL *s,void *buf,int len); + int (*ssl_write)(SSL *s,const void *buf,int len); + int (*ssl_shutdown)(SSL *s); + int (*ssl_renegotiate)(SSL *s); + int (*ssl_renegotiate_check)(SSL *s); + long (*ssl_get_message)(SSL *s, int st1, int stn, int mt, long + max, int *ok); + int (*ssl_read_bytes)(SSL *s, int type, unsigned char *buf, int len, + int peek); + int (*ssl_write_bytes)(SSL *s, int type, const void *buf_, int len); + int (*ssl_dispatch_alert)(SSL *s); + long (*ssl_ctrl)(SSL *s,int cmd,long larg,void *parg); + long (*ssl_ctx_ctrl)(SSL_CTX *ctx,int cmd,long larg,void *parg); + const SSL_CIPHER *(*get_cipher_by_char)(const unsigned char *ptr); + int (*put_cipher_by_char)(const SSL_CIPHER *cipher,unsigned char *ptr); + int (*ssl_pending)(const SSL *s); + int (*num_ciphers)(void); + const SSL_CIPHER *(*get_cipher)(unsigned ncipher); + const struct ssl_method_st *(*get_ssl_method)(int version); + long (*get_timeout)(void); + struct ssl3_enc_method *ssl3_enc; /* Extra SSLv3/TLS stuff */ + int (*ssl_version)(void); + long (*ssl_callback_ctrl)(SSL *s, int cb_id, void (*fp)(void)); + long (*ssl_ctx_callback_ctrl)(SSL_CTX *s, int cb_id, void (*fp)(void)); + } SSL_METHOD; + +/* Lets make this into an ASN.1 type structure as follows + * SSL_SESSION_ID ::= SEQUENCE { + * version INTEGER, -- structure version number + * SSLversion INTEGER, -- SSL version number + * Cipher OCTET STRING, -- the 3 byte cipher ID + * Session_ID OCTET STRING, -- the Session ID + * Master_key OCTET STRING, -- the master key + * KRB5_principal OCTET STRING -- optional Kerberos principal + * Key_Arg [ 0 ] IMPLICIT OCTET STRING, -- the optional Key argument + * Time [ 1 ] EXPLICIT INTEGER, -- optional Start Time + * Timeout [ 2 ] EXPLICIT INTEGER, -- optional Timeout ins seconds + * Peer [ 3 ] EXPLICIT X509, -- optional Peer Certificate + * Session_ID_context [ 4 ] EXPLICIT OCTET STRING, -- the Session ID context + * Verify_result [ 5 ] EXPLICIT INTEGER, -- X509_V_... code for `Peer' + * HostName [ 6 ] EXPLICIT OCTET STRING, -- optional HostName from servername TLS extension + * ECPointFormatList [ 7 ] OCTET STRING, -- optional EC point format list from TLS extension + * PSK_identity_hint [ 8 ] EXPLICIT OCTET STRING, -- optional PSK identity hint + * PSK_identity [ 9 ] EXPLICIT OCTET STRING -- optional PSK identity + * } + * Look in ssl/ssl_asn1.c for more details + * I'm using EXPLICIT tags so I can read the damn things using asn1parse :-). + */ +typedef struct ssl_session_st + { + int ssl_version; /* what ssl version session info is + * being kept in here? */ + + /* only really used in SSLv2 */ + unsigned int key_arg_length; + unsigned char key_arg[SSL_MAX_KEY_ARG_LENGTH]; + int master_key_length; + unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH]; + /* session_id - valid? */ + unsigned int session_id_length; + unsigned char session_id[SSL_MAX_SSL_SESSION_ID_LENGTH]; + /* this is used to determine whether the session is being reused in + * the appropriate context. It is up to the application to set this, + * via SSL_new */ + unsigned int sid_ctx_length; + unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH]; + +#ifndef OPENSSL_NO_KRB5 + unsigned int krb5_client_princ_len; + unsigned char krb5_client_princ[SSL_MAX_KRB5_PRINCIPAL_LENGTH]; +#endif /* OPENSSL_NO_KRB5 */ +#ifndef OPENSSL_NO_PSK + char *psk_identity_hint; + char *psk_identity; +#endif + int not_resumable; + + /* The cert is the certificate used to establish this connection */ + struct sess_cert_st /* SESS_CERT */ *sess_cert; + + /* This is the cert for the other end. + * On clients, it will be the same as sess_cert->peer_key->x509 + * (the latter is not enough as sess_cert is not retained + * in the external representation of sessions, see ssl_asn1.c). */ + X509 *peer; + /* when app_verify_callback accepts a session where the peer's certificate + * is not ok, we must remember the error for session reuse: */ + long verify_result; /* only for servers */ + + int references; + long timeout; + long time; + + unsigned int compress_meth; /* Need to lookup the method */ + + const SSL_CIPHER *cipher; + unsigned long cipher_id; /* when ASN.1 loaded, this + * needs to be used to load + * the 'cipher' structure */ + + STACK_OF(SSL_CIPHER) *ciphers; /* shared ciphers? */ + + CRYPTO_EX_DATA ex_data; /* application specific data */ + + /* These are used to make removal of session-ids more + * efficient and to implement a maximum cache size. */ + struct ssl_session_st *prev,*next; +#ifndef OPENSSL_NO_TLSEXT + char *tlsext_hostname; +#ifndef OPENSSL_NO_EC + size_t tlsext_ecpointformatlist_length; + unsigned char *tlsext_ecpointformatlist; /* peer's list */ + size_t tlsext_ellipticcurvelist_length; + unsigned char *tlsext_ellipticcurvelist; /* peer's list */ +#endif /* OPENSSL_NO_EC */ + /* RFC4507 info */ + unsigned char *tlsext_tick; /* Session ticket */ + size_t tlsext_ticklen; /* Session ticket length */ + long tlsext_tick_lifetime_hint; /* Session lifetime hint in seconds */ +#endif + } SSL_SESSION; + + +#define SSL_OP_MICROSOFT_SESS_ID_BUG 0x00000001L +#define SSL_OP_NETSCAPE_CHALLENGE_BUG 0x00000002L +/* Allow initial connection to servers that don't support RI */ +#define SSL_OP_LEGACY_SERVER_CONNECT 0x00000004L +#define SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG 0x00000008L +#define SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG 0x00000010L +#define SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER 0x00000020L +#define SSL_OP_MSIE_SSLV2_RSA_PADDING 0x00000040L /* no effect since 0.9.7h and 0.9.8b */ +#define SSL_OP_SSLEAY_080_CLIENT_DH_BUG 0x00000080L +#define SSL_OP_TLS_D5_BUG 0x00000100L +#define SSL_OP_TLS_BLOCK_PADDING_BUG 0x00000200L + +/* Disable SSL 3.0/TLS 1.0 CBC vulnerability workaround that was added + * in OpenSSL 0.9.6d. Usually (depending on the application protocol) + * the workaround is not needed. Unfortunately some broken SSL/TLS + * implementations cannot handle it at all, which is why we include + * it in SSL_OP_ALL. */ +#define SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS 0x00000800L /* added in 0.9.6e */ + +/* SSL_OP_ALL: various bug workarounds that should be rather harmless. + * This used to be 0x000FFFFFL before 0.9.7. */ +#define SSL_OP_ALL 0x80000FFFL + +/* DTLS options */ +#define SSL_OP_NO_QUERY_MTU 0x00001000L +/* Turn on Cookie Exchange (on relevant for servers) */ +#define SSL_OP_COOKIE_EXCHANGE 0x00002000L +/* Don't use RFC4507 ticket extension */ +#define SSL_OP_NO_TICKET 0x00004000L +/* Use Cisco's "speshul" version of DTLS_BAD_VER (as client) */ +#define SSL_OP_CISCO_ANYCONNECT 0x00008000L + +/* As server, disallow session resumption on renegotiation */ +#define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION 0x00010000L +/* Don't use compression even if supported */ +#define SSL_OP_NO_COMPRESSION 0x00020000L +/* Permit unsafe legacy renegotiation */ +#define SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0x00040000L +/* If set, always create a new key when using tmp_ecdh parameters */ +#define SSL_OP_SINGLE_ECDH_USE 0x00080000L +/* If set, always create a new key when using tmp_dh parameters */ +#define SSL_OP_SINGLE_DH_USE 0x00100000L +/* Set to always use the tmp_rsa key when doing RSA operations, + * even when this violates protocol specs */ +#define SSL_OP_EPHEMERAL_RSA 0x00200000L +/* Set on servers to choose the cipher according to the server's + * preferences */ +#define SSL_OP_CIPHER_SERVER_PREFERENCE 0x00400000L +/* If set, a server will allow a client to issue a SSLv3.0 version number + * as latest version supported in the premaster secret, even when TLSv1.0 + * (version 3.1) was announced in the client hello. Normally this is + * forbidden to prevent version rollback attacks. */ +#define SSL_OP_TLS_ROLLBACK_BUG 0x00800000L + +#define SSL_OP_NO_SSLv2 0x01000000L +#define SSL_OP_NO_SSLv3 0x02000000L +#define SSL_OP_NO_TLSv1 0x04000000L + +/* The next flag deliberately changes the ciphertest, this is a check + * for the PKCS#1 attack */ +#define SSL_OP_PKCS1_CHECK_1 0x08000000L +#define SSL_OP_PKCS1_CHECK_2 0x10000000L +#define SSL_OP_NETSCAPE_CA_DN_BUG 0x20000000L +#define SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG 0x40000000L +/* Make server add server-hello extension from early version of + * cryptopro draft, when GOST ciphersuite is negotiated. + * Required for interoperability with CryptoPro CSP 3.x + */ +#define SSL_OP_CRYPTOPRO_TLSEXT_BUG 0x80000000L + +/* Allow SSL_write(..., n) to return r with 0 < r < n (i.e. report success + * when just a single record has been written): */ +#define SSL_MODE_ENABLE_PARTIAL_WRITE 0x00000001L +/* Make it possible to retry SSL_write() with changed buffer location + * (buffer contents must stay the same!); this is not the default to avoid + * the misconception that non-blocking SSL_write() behaves like + * non-blocking write(): */ +#define SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER 0x00000002L +/* Never bother the application with retries if the transport + * is blocking: */ +#define SSL_MODE_AUTO_RETRY 0x00000004L +/* Don't attempt to automatically build certificate chain */ +#define SSL_MODE_NO_AUTO_CHAIN 0x00000008L +/* Save RAM by releasing read and write buffers when they're empty. (SSL3 and + * TLS only.) "Released" buffers are put onto a free-list in the context + * or just freed (depending on the context's setting for freelist_max_len). */ +#define SSL_MODE_RELEASE_BUFFERS 0x00000010L +/* Use small read and write buffers: (a) lazy allocate read buffers for + * large incoming records, and (b) limit the size of outgoing records. */ +#define SSL_MODE_SMALL_BUFFERS 0x00000020L +/* When set, clients may send application data before receipt of CCS + * and Finished. This mode enables full-handshakes to 'complete' in + * one RTT. */ +#define SSL_MODE_HANDSHAKE_CUTTHROUGH 0x00000040L + +/* Note: SSL[_CTX]_set_{options,mode} use |= op on the previous value, + * they cannot be used to clear bits. */ + +#define SSL_CTX_set_options(ctx,op) \ + SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,(op),NULL) +#define SSL_CTX_clear_options(ctx,op) \ + SSL_CTX_ctrl((ctx),SSL_CTRL_CLEAR_OPTIONS,(op),NULL) +#define SSL_CTX_get_options(ctx) \ + SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,0,NULL) +#define SSL_set_options(ssl,op) \ + SSL_ctrl((ssl),SSL_CTRL_OPTIONS,(op),NULL) +#define SSL_clear_options(ssl,op) \ + SSL_ctrl((ssl),SSL_CTRL_CLEAR_OPTIONS,(op),NULL) +#define SSL_get_options(ssl) \ + SSL_ctrl((ssl),SSL_CTRL_OPTIONS,0,NULL) + +#define SSL_CTX_set_mode(ctx,op) \ + SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,(op),NULL) +#define SSL_CTX_clear_mode(ctx,op) \ + SSL_CTX_ctrl((ctx),SSL_CTRL_CLEAR_MODE,(op),NULL) +#define SSL_CTX_get_mode(ctx) \ + SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,0,NULL) +#define SSL_clear_mode(ssl,op) \ + SSL_ctrl((ssl),SSL_CTRL_CLEAR_MODE,(op),NULL) +#define SSL_set_mode(ssl,op) \ + SSL_ctrl((ssl),SSL_CTRL_MODE,(op),NULL) +#define SSL_get_mode(ssl) \ + SSL_ctrl((ssl),SSL_CTRL_MODE,0,NULL) +#define SSL_set_mtu(ssl, mtu) \ + SSL_ctrl((ssl),SSL_CTRL_SET_MTU,(mtu),NULL) + +#define SSL_get_secure_renegotiation_support(ssl) \ + SSL_ctrl((ssl), SSL_CTRL_GET_RI_SUPPORT, 0, NULL) + +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)); +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)); +#define SSL_CTX_set_msg_callback_arg(ctx, arg) SSL_CTX_ctrl((ctx), SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, (arg)) +#define SSL_set_msg_callback_arg(ssl, arg) SSL_ctrl((ssl), SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, (arg)) + + + +#if defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_WIN32) +#define SSL_MAX_CERT_LIST_DEFAULT 1024*30 /* 30k max cert list :-) */ +#else +#define SSL_MAX_CERT_LIST_DEFAULT 1024*100 /* 100k max cert list :-) */ +#endif + +#define SSL_SESSION_CACHE_MAX_SIZE_DEFAULT (1024*20) + +/* This callback type is used inside SSL_CTX, SSL, and in the functions that set + * them. It is used to override the generation of SSL/TLS session IDs in a + * server. Return value should be zero on an error, non-zero to proceed. Also, + * callbacks should themselves check if the id they generate is unique otherwise + * the SSL handshake will fail with an error - callbacks can do this using the + * 'ssl' value they're passed by; + * SSL_has_matching_session_id(ssl, id, *id_len) + * The length value passed in is set at the maximum size the session ID can be. + * In SSLv2 this is 16 bytes, whereas SSLv3/TLSv1 it is 32 bytes. The callback + * can alter this length to be less if desired, but under SSLv2 session IDs are + * supposed to be fixed at 16 bytes so the id will be padded after the callback + * returns in this case. It is also an error for the callback to set the size to + * zero. */ +typedef int (*GEN_SESSION_CB)(const SSL *ssl, unsigned char *id, + unsigned int *id_len); + +typedef struct ssl_comp_st + { + int id; + const char *name; +#ifndef OPENSSL_NO_COMP + COMP_METHOD *method; +#else + char *method; +#endif + } SSL_COMP; + +DECLARE_STACK_OF(SSL_COMP) +DECLARE_LHASH_OF(SSL_SESSION); + +struct ssl_ctx_st + { + const SSL_METHOD *method; + + STACK_OF(SSL_CIPHER) *cipher_list; + /* same as above but sorted for lookup */ + STACK_OF(SSL_CIPHER) *cipher_list_by_id; + + struct x509_store_st /* X509_STORE */ *cert_store; + LHASH_OF(SSL_SESSION) *sessions; + /* Most session-ids that will be cached, default is + * SSL_SESSION_CACHE_MAX_SIZE_DEFAULT. 0 is unlimited. */ + unsigned long session_cache_size; + struct ssl_session_st *session_cache_head; + struct ssl_session_st *session_cache_tail; + + /* This can have one of 2 values, ored together, + * SSL_SESS_CACHE_CLIENT, + * SSL_SESS_CACHE_SERVER, + * Default is SSL_SESSION_CACHE_SERVER, which means only + * SSL_accept which cache SSL_SESSIONS. */ + int session_cache_mode; + + /* If timeout is not 0, it is the default timeout value set + * when SSL_new() is called. This has been put in to make + * life easier to set things up */ + long session_timeout; + + /* If this callback is not null, it will be called each + * time a session id is added to the cache. If this function + * returns 1, it means that the callback will do a + * SSL_SESSION_free() when it has finished using it. Otherwise, + * on 0, it means the callback has finished with it. + * If remove_session_cb is not null, it will be called when + * a session-id is removed from the cache. After the call, + * OpenSSL will SSL_SESSION_free() it. */ + int (*new_session_cb)(struct ssl_st *ssl,SSL_SESSION *sess); + void (*remove_session_cb)(struct ssl_ctx_st *ctx,SSL_SESSION *sess); + SSL_SESSION *(*get_session_cb)(struct ssl_st *ssl, + unsigned char *data,int len,int *copy); + + struct + { + int sess_connect; /* SSL new conn - started */ + int sess_connect_renegotiate;/* SSL reneg - requested */ + int sess_connect_good; /* SSL new conne/reneg - finished */ + int sess_accept; /* SSL new accept - started */ + int sess_accept_renegotiate;/* SSL reneg - requested */ + int sess_accept_good; /* SSL accept/reneg - finished */ + int sess_miss; /* session lookup misses */ + int sess_timeout; /* reuse attempt on timeouted session */ + int sess_cache_full; /* session removed due to full cache */ + int sess_hit; /* session reuse actually done */ + int sess_cb_hit; /* session-id that was not + * in the cache was + * passed back via the callback. This + * indicates that the application is + * supplying session-id's from other + * processes - spooky :-) */ + } stats; + + int references; + + /* if defined, these override the X509_verify_cert() calls */ + int (*app_verify_callback)(X509_STORE_CTX *, void *); + void *app_verify_arg; + /* before OpenSSL 0.9.7, 'app_verify_arg' was ignored + * ('app_verify_callback' was called with just one argument) */ + + /* Default password callback. */ + pem_password_cb *default_passwd_callback; + + /* Default password callback user data. */ + void *default_passwd_callback_userdata; + + /* get client cert callback */ + int (*client_cert_cb)(SSL *ssl, X509 **x509, EVP_PKEY **pkey); + + /* cookie generate callback */ + int (*app_gen_cookie_cb)(SSL *ssl, unsigned char *cookie, + unsigned int *cookie_len); + + /* verify cookie callback */ + int (*app_verify_cookie_cb)(SSL *ssl, unsigned char *cookie, + unsigned int cookie_len); + + CRYPTO_EX_DATA ex_data; + + const EVP_MD *rsa_md5;/* For SSLv2 - name is 'ssl2-md5' */ + const EVP_MD *md5; /* For SSLv3/TLSv1 'ssl3-md5' */ + const EVP_MD *sha1; /* For SSLv3/TLSv1 'ssl3->sha1' */ + + STACK_OF(X509) *extra_certs; + STACK_OF(SSL_COMP) *comp_methods; /* stack of SSL_COMP, SSLv3/TLSv1 */ + + + /* Default values used when no per-SSL value is defined follow */ + + void (*info_callback)(const SSL *ssl,int type,int val); /* used if SSL's info_callback is NULL */ + + /* what we put in client cert requests */ + STACK_OF(X509_NAME) *client_CA; + + + /* Default values to use in SSL structures follow (these are copied by SSL_new) */ + + unsigned long options; + unsigned long mode; + long max_cert_list; + + struct cert_st /* CERT */ *cert; + int read_ahead; + + /* callback that allows applications to peek at protocol messages */ + void (*msg_callback)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg); + void *msg_callback_arg; + + int verify_mode; + unsigned int sid_ctx_length; + unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH]; + int (*default_verify_callback)(int ok,X509_STORE_CTX *ctx); /* called 'verify_callback' in the SSL */ + + /* Default generate session ID callback. */ + GEN_SESSION_CB generate_session_id; + + X509_VERIFY_PARAM *param; + +#if 0 + int purpose; /* Purpose setting */ + int trust; /* Trust setting */ +#endif + + int quiet_shutdown; + + /* Maximum amount of data to send in one fragment. + * actual record size can be more than this due to + * padding and MAC overheads. + */ + unsigned int max_send_fragment; + +#ifndef OPENSSL_ENGINE + /* Engine to pass requests for client certs to + */ + ENGINE *client_cert_engine; +#endif + +#ifndef OPENSSL_NO_TLSEXT + /* TLS extensions servername callback */ + int (*tlsext_servername_callback)(SSL*, int *, void *); + void *tlsext_servername_arg; + /* RFC 4507 session ticket keys */ + unsigned char tlsext_tick_key_name[16]; + unsigned char tlsext_tick_hmac_key[16]; + unsigned char tlsext_tick_aes_key[16]; + /* Callback to support customisation of ticket key setting */ + int (*tlsext_ticket_key_cb)(SSL *ssl, + unsigned char *name, unsigned char *iv, + EVP_CIPHER_CTX *ectx, + HMAC_CTX *hctx, int enc); + + /* certificate status request info */ + /* Callback for status request */ + int (*tlsext_status_cb)(SSL *ssl, void *arg); + void *tlsext_status_arg; + + /* draft-rescorla-tls-opaque-prf-input-00.txt information */ + int (*tlsext_opaque_prf_input_callback)(SSL *, void *peerinput, size_t len, void *arg); + void *tlsext_opaque_prf_input_callback_arg; + +# ifndef OPENSSL_NO_NEXTPROTONEG + /* Next protocol negotiation information */ + /* (for experimental NPN extension). */ + + /* For a server, this contains a callback function by which the set of + * advertised protocols can be provided. */ + int (*next_protos_advertised_cb)(SSL *s, const unsigned char **buf, + unsigned int *len, void *arg); + void *next_protos_advertised_cb_arg; + /* For a client, this contains a callback function that selects the + * next protocol from the list provided by the server. */ + int (*next_proto_select_cb)(SSL *s, unsigned char **out, + unsigned char *outlen, + const unsigned char *in, + unsigned int inlen, + void *arg); + void *next_proto_select_cb_arg; +# endif +#endif + +#ifndef OPENSSL_NO_PSK + char *psk_identity_hint; + 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); + unsigned int (*psk_server_callback)(SSL *ssl, const char *identity, + unsigned char *psk, unsigned int max_psk_len); +#endif + +#ifndef OPENSSL_NO_BUF_FREELISTS +#define SSL_MAX_BUF_FREELIST_LEN_DEFAULT 32 + unsigned int freelist_max_len; + struct ssl3_buf_freelist_st *wbuf_freelist; + struct ssl3_buf_freelist_st *rbuf_freelist; +#endif + }; + +#define SSL_SESS_CACHE_OFF 0x0000 +#define SSL_SESS_CACHE_CLIENT 0x0001 +#define SSL_SESS_CACHE_SERVER 0x0002 +#define SSL_SESS_CACHE_BOTH (SSL_SESS_CACHE_CLIENT|SSL_SESS_CACHE_SERVER) +#define SSL_SESS_CACHE_NO_AUTO_CLEAR 0x0080 +/* enough comments already ... see SSL_CTX_set_session_cache_mode(3) */ +#define SSL_SESS_CACHE_NO_INTERNAL_LOOKUP 0x0100 +#define SSL_SESS_CACHE_NO_INTERNAL_STORE 0x0200 +#define SSL_SESS_CACHE_NO_INTERNAL \ + (SSL_SESS_CACHE_NO_INTERNAL_LOOKUP|SSL_SESS_CACHE_NO_INTERNAL_STORE) + +LHASH_OF(SSL_SESSION) *SSL_CTX_sessions(SSL_CTX *ctx); +#define SSL_CTX_sess_number(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_NUMBER,0,NULL) +#define SSL_CTX_sess_connect(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CONNECT,0,NULL) +#define SSL_CTX_sess_connect_good(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CONNECT_GOOD,0,NULL) +#define SSL_CTX_sess_connect_renegotiate(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CONNECT_RENEGOTIATE,0,NULL) +#define SSL_CTX_sess_accept(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_ACCEPT,0,NULL) +#define SSL_CTX_sess_accept_renegotiate(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_ACCEPT_RENEGOTIATE,0,NULL) +#define SSL_CTX_sess_accept_good(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_ACCEPT_GOOD,0,NULL) +#define SSL_CTX_sess_hits(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_HIT,0,NULL) +#define SSL_CTX_sess_cb_hits(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CB_HIT,0,NULL) +#define SSL_CTX_sess_misses(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_MISSES,0,NULL) +#define SSL_CTX_sess_timeouts(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_TIMEOUTS,0,NULL) +#define SSL_CTX_sess_cache_full(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CACHE_FULL,0,NULL) + +void SSL_CTX_sess_set_new_cb(SSL_CTX *ctx, int (*new_session_cb)(struct ssl_st *ssl,SSL_SESSION *sess)); +int (*SSL_CTX_sess_get_new_cb(SSL_CTX *ctx))(struct ssl_st *ssl, SSL_SESSION *sess); +void SSL_CTX_sess_set_remove_cb(SSL_CTX *ctx, void (*remove_session_cb)(struct ssl_ctx_st *ctx,SSL_SESSION *sess)); +void (*SSL_CTX_sess_get_remove_cb(SSL_CTX *ctx))(struct ssl_ctx_st *ctx, SSL_SESSION *sess); +void SSL_CTX_sess_set_get_cb(SSL_CTX *ctx, SSL_SESSION *(*get_session_cb)(struct ssl_st *ssl, unsigned char *data,int len,int *copy)); +SSL_SESSION *(*SSL_CTX_sess_get_get_cb(SSL_CTX *ctx))(struct ssl_st *ssl, unsigned char *Data, int len, int *copy); +void SSL_CTX_set_info_callback(SSL_CTX *ctx, void (*cb)(const SSL *ssl,int type,int val)); +void (*SSL_CTX_get_info_callback(SSL_CTX *ctx))(const SSL *ssl,int type,int val); +void SSL_CTX_set_client_cert_cb(SSL_CTX *ctx, int (*client_cert_cb)(SSL *ssl, X509 **x509, EVP_PKEY **pkey)); +int (*SSL_CTX_get_client_cert_cb(SSL_CTX *ctx))(SSL *ssl, X509 **x509, EVP_PKEY **pkey); +#ifndef OPENSSL_NO_ENGINE +int SSL_CTX_set_client_cert_engine(SSL_CTX *ctx, ENGINE *e); +#endif +void SSL_CTX_set_cookie_generate_cb(SSL_CTX *ctx, int (*app_gen_cookie_cb)(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len)); +void SSL_CTX_set_cookie_verify_cb(SSL_CTX *ctx, int (*app_verify_cookie_cb)(SSL *ssl, unsigned char *cookie, unsigned int cookie_len)); +#ifndef OPENSSL_NO_NEXTPROTONEG +void SSL_CTX_set_next_protos_advertised_cb(SSL_CTX *s, + int (*cb) (SSL *ssl, + const unsigned char **out, + unsigned int *outlen, + void *arg), void *arg); +void SSL_CTX_set_next_proto_select_cb(SSL_CTX *s, + int (*cb) (SSL *ssl, unsigned char **out, + unsigned char *outlen, + const unsigned char *in, + unsigned int inlen, void *arg), + void *arg); + +int SSL_select_next_proto(unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned int inlen, + const unsigned char *client, unsigned int client_len); +void SSL_get0_next_proto_negotiated(const SSL *s, const unsigned char **data, + unsigned *len); + +#define OPENSSL_NPN_UNSUPPORTED 0 +#define OPENSSL_NPN_NEGOTIATED 1 +#define OPENSSL_NPN_NO_OVERLAP 2 + +#endif + +#ifndef OPENSSL_NO_PSK +/* the maximum length of the buffer given to callbacks containing the + * resulting identity/psk */ +#define PSK_MAX_IDENTITY_LEN 128 +#define PSK_MAX_PSK_LEN 256 +void SSL_CTX_set_psk_client_callback(SSL_CTX *ctx, + 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)); +void SSL_set_psk_client_callback(SSL *ssl, + 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)); +void SSL_CTX_set_psk_server_callback(SSL_CTX *ctx, + unsigned int (*psk_server_callback)(SSL *ssl, const char *identity, + unsigned char *psk, unsigned int max_psk_len)); +void SSL_set_psk_server_callback(SSL *ssl, + unsigned int (*psk_server_callback)(SSL *ssl, const char *identity, + unsigned char *psk, unsigned int max_psk_len)); +int SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *identity_hint); +int SSL_use_psk_identity_hint(SSL *s, const char *identity_hint); +const char *SSL_get_psk_identity_hint(const SSL *s); +const char *SSL_get_psk_identity(const SSL *s); +#endif + +#define SSL_NOTHING 1 +#define SSL_WRITING 2 +#define SSL_READING 3 +#define SSL_X509_LOOKUP 4 + +/* These will only be used when doing non-blocking IO */ +#define SSL_want_nothing(s) (SSL_want(s) == SSL_NOTHING) +#define SSL_want_read(s) (SSL_want(s) == SSL_READING) +#define SSL_want_write(s) (SSL_want(s) == SSL_WRITING) +#define SSL_want_x509_lookup(s) (SSL_want(s) == SSL_X509_LOOKUP) + +#define SSL_MAC_FLAG_READ_MAC_STREAM 1 +#define SSL_MAC_FLAG_WRITE_MAC_STREAM 2 + +struct ssl_st + { + /* protocol version + * (one of SSL2_VERSION, SSL3_VERSION, TLS1_VERSION, DTLS1_VERSION) + */ + int version; + int type; /* SSL_ST_CONNECT or SSL_ST_ACCEPT */ + + const SSL_METHOD *method; /* SSLv3 */ + + /* There are 2 BIO's even though they are normally both the + * same. This is so data can be read and written to different + * handlers */ + +#ifndef OPENSSL_NO_BIO + BIO *rbio; /* used by SSL_read */ + BIO *wbio; /* used by SSL_write */ + BIO *bbio; /* used during session-id reuse to concatenate + * messages */ +#else + char *rbio; /* used by SSL_read */ + char *wbio; /* used by SSL_write */ + char *bbio; +#endif + /* This holds a variable that indicates what we were doing + * when a 0 or -1 is returned. This is needed for + * non-blocking IO so we know what request needs re-doing when + * in SSL_accept or SSL_connect */ + int rwstate; + + /* true when we are actually in SSL_accept() or SSL_connect() */ + int in_handshake; + int (*handshake_func)(SSL *); + + /* Imagine that here's a boolean member "init" that is + * switched as soon as SSL_set_{accept/connect}_state + * is called for the first time, so that "state" and + * "handshake_func" are properly initialized. But as + * handshake_func is == 0 until then, we use this + * test instead of an "init" member. + */ + + int server; /* are we the server side? - mostly used by SSL_clear*/ + + int new_session;/* 1 if we are to use a new session. + * 2 if we are a server and are inside a handshake + * (i.e. not just sending a HelloRequest) + * NB: For servers, the 'new' session may actually be a previously + * cached session or even the previous session unless + * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION is set */ + int quiet_shutdown;/* don't send shutdown packets */ + int shutdown; /* we have shut things down, 0x01 sent, 0x02 + * for received */ + int state; /* where we are */ + int rstate; /* where we are when reading */ + + BUF_MEM *init_buf; /* buffer used during init */ + void *init_msg; /* pointer to handshake message body, set by ssl3_get_message() */ + int init_num; /* amount read/written */ + int init_off; /* amount read/written */ + + /* used internally to point at a raw packet */ + unsigned char *packet; + unsigned int packet_length; + + struct ssl2_state_st *s2; /* SSLv2 variables */ + struct ssl3_state_st *s3; /* SSLv3 variables */ + struct dtls1_state_st *d1; /* DTLSv1 variables */ + + int read_ahead; /* Read as many input bytes as possible + * (for non-blocking reads) */ + + /* callback that allows applications to peek at protocol messages */ + void (*msg_callback)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg); + void *msg_callback_arg; + + int hit; /* reusing a previous session */ + + X509_VERIFY_PARAM *param; + +#if 0 + int purpose; /* Purpose setting */ + int trust; /* Trust setting */ +#endif + + /* crypto */ + STACK_OF(SSL_CIPHER) *cipher_list; + STACK_OF(SSL_CIPHER) *cipher_list_by_id; + + /* These are the ones being used, the ones in SSL_SESSION are + * the ones to be 'copied' into these ones */ + int mac_flags; + EVP_CIPHER_CTX *enc_read_ctx; /* cryptographic state */ + EVP_MD_CTX *read_hash; /* used for mac generation */ +#ifndef OPENSSL_NO_COMP + COMP_CTX *expand; /* uncompress */ +#else + char *expand; +#endif + + EVP_CIPHER_CTX *enc_write_ctx; /* cryptographic state */ + EVP_MD_CTX *write_hash; /* used for mac generation */ +#ifndef OPENSSL_NO_COMP + COMP_CTX *compress; /* compression */ +#else + char *compress; +#endif + + /* session info */ + + /* client cert? */ + /* This is used to hold the server certificate used */ + struct cert_st /* CERT */ *cert; + + /* the session_id_context is used to ensure sessions are only reused + * in the appropriate context */ + unsigned int sid_ctx_length; + unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH]; + + /* This can also be in the session once a session is established */ + SSL_SESSION *session; + + /* This can be disabled to prevent the use of uncached sessions */ + int session_creation_enabled; + + /* Default generate session ID callback. */ + GEN_SESSION_CB generate_session_id; + + /* Used in SSL2 and SSL3 */ + int verify_mode; /* 0 don't care about verify failure. + * 1 fail if verify fails */ + int (*verify_callback)(int ok,X509_STORE_CTX *ctx); /* fail if callback returns 0 */ + + void (*info_callback)(const SSL *ssl,int type,int val); /* optional informational callback */ + + int error; /* error bytes to be written */ + int error_code; /* actual code */ + +#ifndef OPENSSL_NO_KRB5 + KSSL_CTX *kssl_ctx; /* Kerberos 5 context */ +#endif /* OPENSSL_NO_KRB5 */ + +#ifndef OPENSSL_NO_PSK + 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); + unsigned int (*psk_server_callback)(SSL *ssl, const char *identity, + unsigned char *psk, unsigned int max_psk_len); +#endif + + SSL_CTX *ctx; + /* set this flag to 1 and a sleep(1) is put into all SSL_read() + * and SSL_write() calls, good for nbio debuging :-) */ + int debug; + + /* extra application data */ + long verify_result; + CRYPTO_EX_DATA ex_data; + + /* for server side, keep the list of CA_dn we can use */ + STACK_OF(X509_NAME) *client_CA; + + int references; + unsigned long options; /* protocol behaviour */ + unsigned long mode; /* API behaviour */ + long max_cert_list; + int first_packet; + int client_version; /* what was passed, used for + * SSLv3/TLS rollback check */ + unsigned int max_send_fragment; +#ifndef OPENSSL_NO_TLSEXT + /* TLS extension debug callback */ + void (*tlsext_debug_cb)(SSL *s, int client_server, int type, + unsigned char *data, int len, + void *arg); + void *tlsext_debug_arg; + char *tlsext_hostname; + int servername_done; /* no further mod of servername + 0 : call the servername extension callback. + 1 : prepare 2, allow last ack just after in server callback. + 2 : don't call servername callback, no ack in server hello + */ + /* certificate status request info */ + /* Status type or -1 if no status type */ + int tlsext_status_type; + /* Expect OCSP CertificateStatus message */ + int tlsext_status_expected; + /* OCSP status request only */ + STACK_OF(OCSP_RESPID) *tlsext_ocsp_ids; + X509_EXTENSIONS *tlsext_ocsp_exts; + /* OCSP response received or to be sent */ + unsigned char *tlsext_ocsp_resp; + int tlsext_ocsp_resplen; + + /* RFC4507 session ticket expected to be received or sent */ + int tlsext_ticket_expected; +#ifndef OPENSSL_NO_EC + size_t tlsext_ecpointformatlist_length; + unsigned char *tlsext_ecpointformatlist; /* our list */ + size_t tlsext_ellipticcurvelist_length; + unsigned char *tlsext_ellipticcurvelist; /* our list */ +#endif /* OPENSSL_NO_EC */ + + /* draft-rescorla-tls-opaque-prf-input-00.txt information to be used for handshakes */ + void *tlsext_opaque_prf_input; + size_t tlsext_opaque_prf_input_len; + + /* TLS Session Ticket extension override */ + TLS_SESSION_TICKET_EXT *tlsext_session_ticket; + + /* TLS Session Ticket extension callback */ + tls_session_ticket_ext_cb_fn tls_session_ticket_ext_cb; + void *tls_session_ticket_ext_cb_arg; + + /* TLS pre-shared secret session resumption */ + tls_session_secret_cb_fn tls_session_secret_cb; + void *tls_session_secret_cb_arg; + + SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */ + +#ifndef OPENSSL_NO_NEXTPROTONEG + /* Next protocol negotiation. For the client, this is the protocol that + * we sent in NextProtocol and is set when handling ServerHello + * extensions. + * + * For a server, this is the client's selected_protocol from + * NextProtocol and is set when handling the NextProtocol message, + * before the Finished message. */ + unsigned char *next_proto_negotiated; + unsigned char next_proto_negotiated_len; +#endif + +#define session_ctx initial_ctx +#else +#define session_ctx ctx +#endif /* OPENSSL_NO_TLSEXT */ + }; + +#ifdef __cplusplus +} +#endif + +#include <openssl/ssl2.h> +#include <openssl/ssl3.h> +#include <openssl/tls1.h> /* This is mostly sslv3 with a few tweaks */ +#include <openssl/dtls1.h> /* Datagram TLS */ +#include <openssl/ssl23.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* compatibility */ +#define SSL_set_app_data(s,arg) (SSL_set_ex_data(s,0,(char *)arg)) +#define SSL_get_app_data(s) (SSL_get_ex_data(s,0)) +#define SSL_SESSION_set_app_data(s,a) (SSL_SESSION_set_ex_data(s,0,(char *)a)) +#define SSL_SESSION_get_app_data(s) (SSL_SESSION_get_ex_data(s,0)) +#define SSL_CTX_get_app_data(ctx) (SSL_CTX_get_ex_data(ctx,0)) +#define SSL_CTX_set_app_data(ctx,arg) (SSL_CTX_set_ex_data(ctx,0,(char *)arg)) + +/* The following are the possible values for ssl->state are are + * used to indicate where we are up to in the SSL connection establishment. + * The macros that follow are about the only things you should need to use + * and even then, only when using non-blocking IO. + * It can also be useful to work out where you were when the connection + * failed */ + +#define SSL_ST_CONNECT 0x1000 +#define SSL_ST_ACCEPT 0x2000 +#define SSL_ST_MASK 0x0FFF +#define SSL_ST_INIT (SSL_ST_CONNECT|SSL_ST_ACCEPT) +#define SSL_ST_BEFORE 0x4000 +#define SSL_ST_OK 0x03 +#define SSL_ST_RENEGOTIATE (0x04|SSL_ST_INIT) + +#define SSL_CB_LOOP 0x01 +#define SSL_CB_EXIT 0x02 +#define SSL_CB_READ 0x04 +#define SSL_CB_WRITE 0x08 +#define SSL_CB_ALERT 0x4000 /* used in callback */ +#define SSL_CB_READ_ALERT (SSL_CB_ALERT|SSL_CB_READ) +#define SSL_CB_WRITE_ALERT (SSL_CB_ALERT|SSL_CB_WRITE) +#define SSL_CB_ACCEPT_LOOP (SSL_ST_ACCEPT|SSL_CB_LOOP) +#define SSL_CB_ACCEPT_EXIT (SSL_ST_ACCEPT|SSL_CB_EXIT) +#define SSL_CB_CONNECT_LOOP (SSL_ST_CONNECT|SSL_CB_LOOP) +#define SSL_CB_CONNECT_EXIT (SSL_ST_CONNECT|SSL_CB_EXIT) +#define SSL_CB_HANDSHAKE_START 0x10 +#define SSL_CB_HANDSHAKE_DONE 0x20 + +/* Is the SSL_connection established? */ +#define SSL_get_state(a) SSL_state(a) +#define SSL_is_init_finished(a) (SSL_state(a) == SSL_ST_OK) +#define SSL_in_init(a) ((SSL_state(a)&SSL_ST_INIT) && \ + !SSL_cutthrough_complete(a)) +#define SSL_in_before(a) (SSL_state(a)&SSL_ST_BEFORE) +#define SSL_in_connect_init(a) (SSL_state(a)&SSL_ST_CONNECT) +#define SSL_in_accept_init(a) (SSL_state(a)&SSL_ST_ACCEPT) +int SSL_cutthrough_complete(const SSL *s); + +/* The following 2 states are kept in ssl->rstate when reads fail, + * you should not need these */ +#define SSL_ST_READ_HEADER 0xF0 +#define SSL_ST_READ_BODY 0xF1 +#define SSL_ST_READ_DONE 0xF2 + +/* Obtain latest Finished message + * -- that we sent (SSL_get_finished) + * -- that we expected from peer (SSL_get_peer_finished). + * Returns length (0 == no Finished so far), copies up to 'count' bytes. */ +size_t SSL_get_finished(const SSL *s, void *buf, size_t count); +size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count); + +/* use either SSL_VERIFY_NONE or SSL_VERIFY_PEER, the last 2 options + * are 'ored' with SSL_VERIFY_PEER if they are desired */ +#define SSL_VERIFY_NONE 0x00 +#define SSL_VERIFY_PEER 0x01 +#define SSL_VERIFY_FAIL_IF_NO_PEER_CERT 0x02 +#define SSL_VERIFY_CLIENT_ONCE 0x04 + +#define OpenSSL_add_ssl_algorithms() SSL_library_init() +#define SSLeay_add_ssl_algorithms() SSL_library_init() + +/* this is for backward compatibility */ +#if 0 /* NEW_SSLEAY */ +#define SSL_CTX_set_default_verify(a,b,c) SSL_CTX_set_verify(a,b,c) +#define SSL_set_pref_cipher(c,n) SSL_set_cipher_list(c,n) +#define SSL_add_session(a,b) SSL_CTX_add_session((a),(b)) +#define SSL_remove_session(a,b) SSL_CTX_remove_session((a),(b)) +#define SSL_flush_sessions(a,b) SSL_CTX_flush_sessions((a),(b)) +#endif +/* More backward compatibility */ +#define SSL_get_cipher(s) \ + SSL_CIPHER_get_name(SSL_get_current_cipher(s)) +#define SSL_get_cipher_bits(s,np) \ + SSL_CIPHER_get_bits(SSL_get_current_cipher(s),np) +#define SSL_get_cipher_version(s) \ + SSL_CIPHER_get_version(SSL_get_current_cipher(s)) +#define SSL_get_cipher_name(s) \ + SSL_CIPHER_get_name(SSL_get_current_cipher(s)) +#define SSL_get_time(a) SSL_SESSION_get_time(a) +#define SSL_set_time(a,b) SSL_SESSION_set_time((a),(b)) +#define SSL_get_timeout(a) SSL_SESSION_get_timeout(a) +#define SSL_set_timeout(a,b) SSL_SESSION_set_timeout((a),(b)) + +#define d2i_SSL_SESSION_bio(bp,s_id) ASN1_d2i_bio_of(SSL_SESSION,SSL_SESSION_new,d2i_SSL_SESSION,bp,s_id) +#define i2d_SSL_SESSION_bio(bp,s_id) ASN1_i2d_bio_of(SSL_SESSION,i2d_SSL_SESSION,bp,s_id) + +DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION) + +#define SSL_AD_REASON_OFFSET 1000 /* offset to get SSL_R_... value from SSL_AD_... */ + +/* These alert types are for SSLv3 and TLSv1 */ +#define SSL_AD_CLOSE_NOTIFY SSL3_AD_CLOSE_NOTIFY +#define SSL_AD_UNEXPECTED_MESSAGE SSL3_AD_UNEXPECTED_MESSAGE /* fatal */ +#define SSL_AD_BAD_RECORD_MAC SSL3_AD_BAD_RECORD_MAC /* fatal */ +#define SSL_AD_DECRYPTION_FAILED TLS1_AD_DECRYPTION_FAILED +#define SSL_AD_RECORD_OVERFLOW TLS1_AD_RECORD_OVERFLOW +#define SSL_AD_DECOMPRESSION_FAILURE SSL3_AD_DECOMPRESSION_FAILURE/* fatal */ +#define SSL_AD_HANDSHAKE_FAILURE SSL3_AD_HANDSHAKE_FAILURE/* fatal */ +#define SSL_AD_NO_CERTIFICATE SSL3_AD_NO_CERTIFICATE /* Not for TLS */ +#define SSL_AD_BAD_CERTIFICATE SSL3_AD_BAD_CERTIFICATE +#define SSL_AD_UNSUPPORTED_CERTIFICATE SSL3_AD_UNSUPPORTED_CERTIFICATE +#define SSL_AD_CERTIFICATE_REVOKED SSL3_AD_CERTIFICATE_REVOKED +#define SSL_AD_CERTIFICATE_EXPIRED SSL3_AD_CERTIFICATE_EXPIRED +#define SSL_AD_CERTIFICATE_UNKNOWN SSL3_AD_CERTIFICATE_UNKNOWN +#define SSL_AD_ILLEGAL_PARAMETER SSL3_AD_ILLEGAL_PARAMETER /* fatal */ +#define SSL_AD_UNKNOWN_CA TLS1_AD_UNKNOWN_CA /* fatal */ +#define SSL_AD_ACCESS_DENIED TLS1_AD_ACCESS_DENIED /* fatal */ +#define SSL_AD_DECODE_ERROR TLS1_AD_DECODE_ERROR /* fatal */ +#define SSL_AD_DECRYPT_ERROR TLS1_AD_DECRYPT_ERROR +#define SSL_AD_EXPORT_RESTRICTION TLS1_AD_EXPORT_RESTRICTION/* fatal */ +#define SSL_AD_PROTOCOL_VERSION TLS1_AD_PROTOCOL_VERSION /* fatal */ +#define SSL_AD_INSUFFICIENT_SECURITY TLS1_AD_INSUFFICIENT_SECURITY/* fatal */ +#define SSL_AD_INTERNAL_ERROR TLS1_AD_INTERNAL_ERROR /* fatal */ +#define SSL_AD_USER_CANCELLED TLS1_AD_USER_CANCELLED +#define SSL_AD_NO_RENEGOTIATION TLS1_AD_NO_RENEGOTIATION +#define SSL_AD_UNSUPPORTED_EXTENSION TLS1_AD_UNSUPPORTED_EXTENSION +#define SSL_AD_CERTIFICATE_UNOBTAINABLE TLS1_AD_CERTIFICATE_UNOBTAINABLE +#define SSL_AD_UNRECOGNIZED_NAME TLS1_AD_UNRECOGNIZED_NAME +#define SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE +#define SSL_AD_BAD_CERTIFICATE_HASH_VALUE TLS1_AD_BAD_CERTIFICATE_HASH_VALUE +#define SSL_AD_UNKNOWN_PSK_IDENTITY TLS1_AD_UNKNOWN_PSK_IDENTITY /* fatal */ + +#define SSL_ERROR_NONE 0 +#define SSL_ERROR_SSL 1 +#define SSL_ERROR_WANT_READ 2 +#define SSL_ERROR_WANT_WRITE 3 +#define SSL_ERROR_WANT_X509_LOOKUP 4 +#define SSL_ERROR_SYSCALL 5 /* look at error stack/return value/errno */ +#define SSL_ERROR_ZERO_RETURN 6 +#define SSL_ERROR_WANT_CONNECT 7 +#define SSL_ERROR_WANT_ACCEPT 8 + +#define SSL_CTRL_NEED_TMP_RSA 1 +#define SSL_CTRL_SET_TMP_RSA 2 +#define SSL_CTRL_SET_TMP_DH 3 +#define SSL_CTRL_SET_TMP_ECDH 4 +#define SSL_CTRL_SET_TMP_RSA_CB 5 +#define SSL_CTRL_SET_TMP_DH_CB 6 +#define SSL_CTRL_SET_TMP_ECDH_CB 7 + +#define SSL_CTRL_GET_SESSION_REUSED 8 +#define SSL_CTRL_GET_CLIENT_CERT_REQUEST 9 +#define SSL_CTRL_GET_NUM_RENEGOTIATIONS 10 +#define SSL_CTRL_CLEAR_NUM_RENEGOTIATIONS 11 +#define SSL_CTRL_GET_TOTAL_RENEGOTIATIONS 12 +#define SSL_CTRL_GET_FLAGS 13 +#define SSL_CTRL_EXTRA_CHAIN_CERT 14 + +#define SSL_CTRL_SET_MSG_CALLBACK 15 +#define SSL_CTRL_SET_MSG_CALLBACK_ARG 16 + +/* only applies to datagram connections */ +#define SSL_CTRL_SET_MTU 17 +/* Stats */ +#define SSL_CTRL_SESS_NUMBER 20 +#define SSL_CTRL_SESS_CONNECT 21 +#define SSL_CTRL_SESS_CONNECT_GOOD 22 +#define SSL_CTRL_SESS_CONNECT_RENEGOTIATE 23 +#define SSL_CTRL_SESS_ACCEPT 24 +#define SSL_CTRL_SESS_ACCEPT_GOOD 25 +#define SSL_CTRL_SESS_ACCEPT_RENEGOTIATE 26 +#define SSL_CTRL_SESS_HIT 27 +#define SSL_CTRL_SESS_CB_HIT 28 +#define SSL_CTRL_SESS_MISSES 29 +#define SSL_CTRL_SESS_TIMEOUTS 30 +#define SSL_CTRL_SESS_CACHE_FULL 31 +#define SSL_CTRL_OPTIONS 32 +#define SSL_CTRL_MODE 33 + +#define SSL_CTRL_GET_READ_AHEAD 40 +#define SSL_CTRL_SET_READ_AHEAD 41 +#define SSL_CTRL_SET_SESS_CACHE_SIZE 42 +#define SSL_CTRL_GET_SESS_CACHE_SIZE 43 +#define SSL_CTRL_SET_SESS_CACHE_MODE 44 +#define SSL_CTRL_GET_SESS_CACHE_MODE 45 + +#define SSL_CTRL_GET_MAX_CERT_LIST 50 +#define SSL_CTRL_SET_MAX_CERT_LIST 51 + +#define SSL_CTRL_SET_MAX_SEND_FRAGMENT 52 + +/* see tls1.h for macros based on these */ +#ifndef OPENSSL_NO_TLSEXT +#define SSL_CTRL_SET_TLSEXT_SERVERNAME_CB 53 +#define SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG 54 +#define SSL_CTRL_SET_TLSEXT_HOSTNAME 55 +#define SSL_CTRL_SET_TLSEXT_DEBUG_CB 56 +#define SSL_CTRL_SET_TLSEXT_DEBUG_ARG 57 +#define SSL_CTRL_GET_TLSEXT_TICKET_KEYS 58 +#define SSL_CTRL_SET_TLSEXT_TICKET_KEYS 59 +#define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT 60 +#define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB 61 +#define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB_ARG 62 +#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB 63 +#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG 64 +#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE 65 +#define SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS 66 +#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS 67 +#define SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS 68 +#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS 69 +#define SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP 70 +#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP 71 + +#define SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB 72 +#endif + +#define DTLS_CTRL_GET_TIMEOUT 73 +#define DTLS_CTRL_HANDLE_TIMEOUT 74 +#define DTLS_CTRL_LISTEN 75 + +#define SSL_CTRL_GET_RI_SUPPORT 76 +#define SSL_CTRL_CLEAR_OPTIONS 77 +#define SSL_CTRL_CLEAR_MODE 78 + +#define DTLSv1_get_timeout(ssl, arg) \ + SSL_ctrl(ssl,DTLS_CTRL_GET_TIMEOUT,0, (void *)arg) +#define DTLSv1_handle_timeout(ssl) \ + SSL_ctrl(ssl,DTLS_CTRL_HANDLE_TIMEOUT,0, NULL) +#define DTLSv1_listen(ssl, peer) \ + SSL_ctrl(ssl,DTLS_CTRL_LISTEN,0, (void *)peer) + +#define SSL_session_reused(ssl) \ + SSL_ctrl((ssl),SSL_CTRL_GET_SESSION_REUSED,0,NULL) +#define SSL_num_renegotiations(ssl) \ + SSL_ctrl((ssl),SSL_CTRL_GET_NUM_RENEGOTIATIONS,0,NULL) +#define SSL_clear_num_renegotiations(ssl) \ + SSL_ctrl((ssl),SSL_CTRL_CLEAR_NUM_RENEGOTIATIONS,0,NULL) +#define SSL_total_renegotiations(ssl) \ + SSL_ctrl((ssl),SSL_CTRL_GET_TOTAL_RENEGOTIATIONS,0,NULL) + +#define SSL_CTX_need_tmp_RSA(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_NEED_TMP_RSA,0,NULL) +#define SSL_CTX_set_tmp_rsa(ctx,rsa) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_RSA,0,(char *)rsa) +#define SSL_CTX_set_tmp_dh(ctx,dh) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_DH,0,(char *)dh) +#define SSL_CTX_set_tmp_ecdh(ctx,ecdh) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_ECDH,0,(char *)ecdh) + +#define SSL_need_tmp_RSA(ssl) \ + SSL_ctrl(ssl,SSL_CTRL_NEED_TMP_RSA,0,NULL) +#define SSL_set_tmp_rsa(ssl,rsa) \ + SSL_ctrl(ssl,SSL_CTRL_SET_TMP_RSA,0,(char *)rsa) +#define SSL_set_tmp_dh(ssl,dh) \ + SSL_ctrl(ssl,SSL_CTRL_SET_TMP_DH,0,(char *)dh) +#define SSL_set_tmp_ecdh(ssl,ecdh) \ + SSL_ctrl(ssl,SSL_CTRL_SET_TMP_ECDH,0,(char *)ecdh) + +#define SSL_CTX_add_extra_chain_cert(ctx,x509) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_EXTRA_CHAIN_CERT,0,(char *)x509) + +#ifndef OPENSSL_NO_BIO +BIO_METHOD *BIO_f_ssl(void); +BIO *BIO_new_ssl(SSL_CTX *ctx,int client); +BIO *BIO_new_ssl_connect(SSL_CTX *ctx); +BIO *BIO_new_buffer_ssl_connect(SSL_CTX *ctx); +int BIO_ssl_copy_session_id(BIO *to,BIO *from); +void BIO_ssl_shutdown(BIO *ssl_bio); + +#endif + +int SSL_CTX_set_cipher_list(SSL_CTX *,const char *str); +SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth); +void SSL_CTX_free(SSL_CTX *); +long SSL_CTX_set_timeout(SSL_CTX *ctx,long t); +long SSL_CTX_get_timeout(const SSL_CTX *ctx); +X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *); +void SSL_CTX_set_cert_store(SSL_CTX *,X509_STORE *); +int SSL_want(const SSL *s); +int SSL_clear(SSL *s); + +void SSL_CTX_flush_sessions(SSL_CTX *ctx,long tm); + +const SSL_CIPHER *SSL_get_current_cipher(const SSL *s); +int SSL_CIPHER_get_bits(const SSL_CIPHER *c,int *alg_bits); +char * SSL_CIPHER_get_version(const SSL_CIPHER *c); +const char * SSL_CIPHER_get_name(const SSL_CIPHER *c); +const char * SSL_CIPHER_authentication_method(const SSL_CIPHER *c); + +int SSL_get_fd(const SSL *s); +int SSL_get_rfd(const SSL *s); +int SSL_get_wfd(const SSL *s); +const char * SSL_get_cipher_list(const SSL *s,int n); +char * SSL_get_shared_ciphers(const SSL *s, char *buf, int len); +int SSL_get_read_ahead(const SSL * s); +int SSL_pending(const SSL *s); +const char * SSL_authentication_method(const SSL *c); +#ifndef OPENSSL_NO_SOCK +int SSL_set_fd(SSL *s, int fd); +int SSL_set_rfd(SSL *s, int fd); +int SSL_set_wfd(SSL *s, int fd); +#endif +#ifndef OPENSSL_NO_BIO +void SSL_set_bio(SSL *s, BIO *rbio,BIO *wbio); +BIO * SSL_get_rbio(const SSL *s); +BIO * SSL_get_wbio(const SSL *s); +#endif +int SSL_set_cipher_list(SSL *s, const char *str); +int SSL_set_cipher_lists(SSL *s, STACK_OF(SSL_CIPHER) *sk); +void SSL_set_read_ahead(SSL *s, int yes); +int SSL_get_verify_mode(const SSL *s); +int SSL_get_verify_depth(const SSL *s); +int (*SSL_get_verify_callback(const SSL *s))(int,X509_STORE_CTX *); +void SSL_set_verify(SSL *s, int mode, + int (*callback)(int ok,X509_STORE_CTX *ctx)); +void SSL_set_verify_depth(SSL *s, int depth); +#ifndef OPENSSL_NO_RSA +int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa); +#endif +int SSL_use_RSAPrivateKey_ASN1(SSL *ssl, unsigned char *d, long len); +int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey); +int SSL_use_PrivateKey_ASN1(int pk,SSL *ssl, const unsigned char *d, long len); +int SSL_use_certificate(SSL *ssl, X509 *x); +int SSL_use_certificate_ASN1(SSL *ssl, const unsigned char *d, int len); +int SSL_use_certificate_chain(SSL *ssl, STACK_OF(X509) *cert_chain); +STACK_OF(X509) * SSL_get_certificate_chain(SSL *ssl, X509 *x); + +#ifndef OPENSSL_NO_STDIO +int SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, int type); +int SSL_use_PrivateKey_file(SSL *ssl, const char *file, int type); +int SSL_use_certificate_file(SSL *ssl, const char *file, int type); +int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, const char *file, int type); +int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type); +int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type); +int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file); /* PEM type */ +STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file); +int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stackCAs, + const char *file); +#ifndef OPENSSL_SYS_VMS +#ifndef OPENSSL_SYS_MACINTOSH_CLASSIC /* XXXXX: Better scheme needed! [was: #ifndef MAC_OS_pre_X] */ +int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stackCAs, + const char *dir); +#endif +#endif + +#endif + +void SSL_load_error_strings(void ); +const char *SSL_state_string(const SSL *s); +const char *SSL_rstate_string(const SSL *s); +const char *SSL_state_string_long(const SSL *s); +const char *SSL_rstate_string_long(const SSL *s); +long SSL_SESSION_get_time(const SSL_SESSION *s); +long SSL_SESSION_set_time(SSL_SESSION *s, long t); +long SSL_SESSION_get_timeout(const SSL_SESSION *s); +long SSL_SESSION_set_timeout(SSL_SESSION *s, long t); +void SSL_copy_session_id(SSL *to,const SSL *from); + +SSL_SESSION *SSL_SESSION_new(void); +const unsigned char *SSL_SESSION_get_id(const SSL_SESSION *s, + unsigned int *len); +const char * SSL_SESSION_get_version(const SSL_SESSION *s); +#ifndef OPENSSL_NO_FP_API +int SSL_SESSION_print_fp(FILE *fp,const SSL_SESSION *ses); +#endif +#ifndef OPENSSL_NO_BIO +int SSL_SESSION_print(BIO *fp,const SSL_SESSION *ses); +#endif +void SSL_SESSION_free(SSL_SESSION *ses); +int i2d_SSL_SESSION(SSL_SESSION *in,unsigned char **pp); +int SSL_set_session(SSL *to, SSL_SESSION *session); +void SSL_set_session_creation_enabled(SSL *, int); +int SSL_CTX_add_session(SSL_CTX *s, SSL_SESSION *c); +int SSL_CTX_remove_session(SSL_CTX *,SSL_SESSION *c); +int SSL_CTX_set_generate_session_id(SSL_CTX *, GEN_SESSION_CB); +int SSL_set_generate_session_id(SSL *, GEN_SESSION_CB); +int SSL_has_matching_session_id(const SSL *ssl, const unsigned char *id, + unsigned int id_len); +SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a,const unsigned char **pp, + long length); + +#ifdef HEADER_X509_H +X509 * SSL_get_peer_certificate(const SSL *s); +#endif + +STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *s); + +int SSL_CTX_get_verify_mode(const SSL_CTX *ctx); +int SSL_CTX_get_verify_depth(const SSL_CTX *ctx); +int (*SSL_CTX_get_verify_callback(const SSL_CTX *ctx))(int,X509_STORE_CTX *); +void SSL_CTX_set_verify(SSL_CTX *ctx,int mode, + int (*callback)(int, X509_STORE_CTX *)); +void SSL_CTX_set_verify_depth(SSL_CTX *ctx,int depth); +void SSL_CTX_set_cert_verify_callback(SSL_CTX *ctx, int (*cb)(X509_STORE_CTX *,void *), void *arg); +#ifndef OPENSSL_NO_RSA +int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa); +#endif +int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const unsigned char *d, long len); +int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey); +int SSL_CTX_use_PrivateKey_ASN1(int pk,SSL_CTX *ctx, + const unsigned char *d, long len); +int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x); +int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, const unsigned char *d); + +void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, pem_password_cb *cb); +void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *u); + +int SSL_CTX_check_private_key(const SSL_CTX *ctx); +int SSL_check_private_key(const SSL *ctx); + +int SSL_CTX_set_session_id_context(SSL_CTX *ctx,const unsigned char *sid_ctx, + unsigned int sid_ctx_len); + +SSL * SSL_new(SSL_CTX *ctx); +int SSL_set_session_id_context(SSL *ssl,const unsigned char *sid_ctx, + unsigned int sid_ctx_len); + +int SSL_CTX_set_purpose(SSL_CTX *s, int purpose); +int SSL_set_purpose(SSL *s, int purpose); +int SSL_CTX_set_trust(SSL_CTX *s, int trust); +int SSL_set_trust(SSL *s, int trust); + +int SSL_CTX_set1_param(SSL_CTX *ctx, X509_VERIFY_PARAM *vpm); +int SSL_set1_param(SSL *ssl, X509_VERIFY_PARAM *vpm); + +void SSL_free(SSL *ssl); +int SSL_accept(SSL *ssl); +int SSL_connect(SSL *ssl); +int SSL_read(SSL *ssl,void *buf,int num); +int SSL_peek(SSL *ssl,void *buf,int num); +int SSL_write(SSL *ssl,const void *buf,int num); +long SSL_ctrl(SSL *ssl,int cmd, long larg, void *parg); +long SSL_callback_ctrl(SSL *, int, void (*)(void)); +long SSL_CTX_ctrl(SSL_CTX *ctx,int cmd, long larg, void *parg); +long SSL_CTX_callback_ctrl(SSL_CTX *, int, void (*)(void)); + +int SSL_get_error(const SSL *s,int ret_code); +const char *SSL_get_version(const SSL *s); + +/* This sets the 'default' SSL version that SSL_new() will create */ +int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth); + +#ifndef OPENSSL_NO_SSL2 +const SSL_METHOD *SSLv2_method(void); /* SSLv2 */ +const SSL_METHOD *SSLv2_server_method(void); /* SSLv2 */ +const SSL_METHOD *SSLv2_client_method(void); /* SSLv2 */ +#endif + +const SSL_METHOD *SSLv3_method(void); /* SSLv3 */ +const SSL_METHOD *SSLv3_server_method(void); /* SSLv3 */ +const SSL_METHOD *SSLv3_client_method(void); /* SSLv3 */ + +const SSL_METHOD *SSLv23_method(void); /* SSLv3 but can rollback to v2 */ +const SSL_METHOD *SSLv23_server_method(void); /* SSLv3 but can rollback to v2 */ +const SSL_METHOD *SSLv23_client_method(void); /* SSLv3 but can rollback to v2 */ + +const SSL_METHOD *TLSv1_method(void); /* TLSv1.0 */ +const SSL_METHOD *TLSv1_server_method(void); /* TLSv1.0 */ +const SSL_METHOD *TLSv1_client_method(void); /* TLSv1.0 */ + +const SSL_METHOD *DTLSv1_method(void); /* DTLSv1.0 */ +const SSL_METHOD *DTLSv1_server_method(void); /* DTLSv1.0 */ +const SSL_METHOD *DTLSv1_client_method(void); /* DTLSv1.0 */ + +STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s); + +int SSL_do_handshake(SSL *s); +int SSL_renegotiate(SSL *s); +int SSL_renegotiate_pending(SSL *s); +int SSL_shutdown(SSL *s); + +const SSL_METHOD *SSL_get_ssl_method(SSL *s); +int SSL_set_ssl_method(SSL *s, const SSL_METHOD *method); +const char *SSL_alert_type_string_long(int value); +const char *SSL_alert_type_string(int value); +const char *SSL_alert_desc_string_long(int value); +const char *SSL_alert_desc_string(int value); + +void SSL_set_client_CA_list(SSL *s, STACK_OF(X509_NAME) *name_list); +void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, STACK_OF(X509_NAME) *name_list); +STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *s); +STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(const SSL_CTX *s); +int SSL_add_client_CA(SSL *ssl,X509 *x); +int SSL_CTX_add_client_CA(SSL_CTX *ctx,X509 *x); + +void SSL_set_connect_state(SSL *s); +void SSL_set_accept_state(SSL *s); + +long SSL_get_default_timeout(const SSL *s); + +int SSL_library_init(void ); + +char *SSL_CIPHER_description(const SSL_CIPHER *,char *buf,int size); +STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *sk); + +SSL *SSL_dup(SSL *ssl); + +X509 *SSL_get_certificate(const SSL *ssl); +/* EVP_PKEY */ struct evp_pkey_st *SSL_get_privatekey(SSL *ssl); + +void SSL_CTX_set_quiet_shutdown(SSL_CTX *ctx,int mode); +int SSL_CTX_get_quiet_shutdown(const SSL_CTX *ctx); +void SSL_set_quiet_shutdown(SSL *ssl,int mode); +int SSL_get_quiet_shutdown(const SSL *ssl); +void SSL_set_shutdown(SSL *ssl,int mode); +int SSL_get_shutdown(const SSL *ssl); +int SSL_version(const SSL *ssl); +int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx); +int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, + const char *CApath); +#define SSL_get0_session SSL_get_session /* just peek at pointer */ +SSL_SESSION *SSL_get_session(const SSL *ssl); +SSL_SESSION *SSL_get1_session(SSL *ssl); /* obtain a reference count */ +SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl); +SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX* ctx); +void SSL_set_info_callback(SSL *ssl, + void (*cb)(const SSL *ssl,int type,int val)); +void (*SSL_get_info_callback(const SSL *ssl))(const SSL *ssl,int type,int val); +int SSL_state(const SSL *ssl); + +void SSL_set_verify_result(SSL *ssl,long v); +long SSL_get_verify_result(const SSL *ssl); + +int SSL_set_ex_data(SSL *ssl,int idx,void *data); +void *SSL_get_ex_data(const SSL *ssl,int idx); +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); + +int SSL_SESSION_set_ex_data(SSL_SESSION *ss,int idx,void *data); +void *SSL_SESSION_get_ex_data(const SSL_SESSION *ss,int idx); +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); + +int SSL_CTX_set_ex_data(SSL_CTX *ssl,int idx,void *data); +void *SSL_CTX_get_ex_data(const SSL_CTX *ssl,int 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); + +int SSL_get_ex_data_X509_STORE_CTX_idx(void ); + +#define SSL_CTX_sess_set_cache_size(ctx,t) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_SESS_CACHE_SIZE,t,NULL) +#define SSL_CTX_sess_get_cache_size(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_GET_SESS_CACHE_SIZE,0,NULL) +#define SSL_CTX_set_session_cache_mode(ctx,m) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_SESS_CACHE_MODE,m,NULL) +#define SSL_CTX_get_session_cache_mode(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_GET_SESS_CACHE_MODE,0,NULL) + +#define SSL_CTX_get_default_read_ahead(ctx) SSL_CTX_get_read_ahead(ctx) +#define SSL_CTX_set_default_read_ahead(ctx,m) SSL_CTX_set_read_ahead(ctx,m) +#define SSL_CTX_get_read_ahead(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_GET_READ_AHEAD,0,NULL) +#define SSL_CTX_set_read_ahead(ctx,m) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_READ_AHEAD,m,NULL) +#define SSL_CTX_get_max_cert_list(ctx) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_GET_MAX_CERT_LIST,0,NULL) +#define SSL_CTX_set_max_cert_list(ctx,m) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_MAX_CERT_LIST,m,NULL) +#define SSL_get_max_cert_list(ssl) \ + SSL_ctrl(ssl,SSL_CTRL_GET_MAX_CERT_LIST,0,NULL) +#define SSL_set_max_cert_list(ssl,m) \ + SSL_ctrl(ssl,SSL_CTRL_SET_MAX_CERT_LIST,m,NULL) + +#define SSL_CTX_set_max_send_fragment(ctx,m) \ + SSL_CTX_ctrl(ctx,SSL_CTRL_SET_MAX_SEND_FRAGMENT,m,NULL) +#define SSL_set_max_send_fragment(ssl,m) \ + SSL_ctrl(ssl,SSL_CTRL_SET_MAX_SEND_FRAGMENT,m,NULL) + + /* NB: the keylength is only applicable when is_export is true */ +#ifndef OPENSSL_NO_RSA +void SSL_CTX_set_tmp_rsa_callback(SSL_CTX *ctx, + RSA *(*cb)(SSL *ssl,int is_export, + int keylength)); + +void SSL_set_tmp_rsa_callback(SSL *ssl, + RSA *(*cb)(SSL *ssl,int is_export, + int keylength)); +#endif +#ifndef OPENSSL_NO_DH +void SSL_CTX_set_tmp_dh_callback(SSL_CTX *ctx, + DH *(*dh)(SSL *ssl,int is_export, + int keylength)); +void SSL_set_tmp_dh_callback(SSL *ssl, + DH *(*dh)(SSL *ssl,int is_export, + int keylength)); +#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)); +void SSL_set_tmp_ecdh_callback(SSL *ssl, + EC_KEY *(*ecdh)(SSL *ssl,int is_export, + int keylength)); +#endif + +#ifndef OPENSSL_NO_COMP +const COMP_METHOD *SSL_get_current_compression(SSL *s); +const COMP_METHOD *SSL_get_current_expansion(SSL *s); +const char *SSL_COMP_get_name(const COMP_METHOD *comp); +STACK_OF(SSL_COMP) *SSL_COMP_get_compression_methods(void); +int SSL_COMP_add_compression_method(int id,COMP_METHOD *cm); +#else +const void *SSL_get_current_compression(SSL *s); +const void *SSL_get_current_expansion(SSL *s); +const char *SSL_COMP_get_name(const void *comp); +void *SSL_COMP_get_compression_methods(void); +int SSL_COMP_add_compression_method(int id,void *cm); +#endif + +/* TLS extensions functions */ +int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len); + +int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb, + void *arg); + +/* Pre-shared secret session resumption functions */ +int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg); + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_SSL_strings(void); + +/* Error codes for the SSL functions. */ + +/* Function codes. */ +#define SSL_F_CLIENT_CERTIFICATE 100 +#define SSL_F_CLIENT_FINISHED 167 +#define SSL_F_CLIENT_HELLO 101 +#define SSL_F_CLIENT_MASTER_KEY 102 +#define SSL_F_D2I_SSL_SESSION 103 +#define SSL_F_DO_DTLS1_WRITE 245 +#define SSL_F_DO_SSL3_WRITE 104 +#define SSL_F_DTLS1_ACCEPT 246 +#define SSL_F_DTLS1_ADD_CERT_TO_BUF 295 +#define SSL_F_DTLS1_BUFFER_RECORD 247 +#define SSL_F_DTLS1_CLIENT_HELLO 248 +#define SSL_F_DTLS1_CONNECT 249 +#define SSL_F_DTLS1_ENC 250 +#define SSL_F_DTLS1_GET_HELLO_VERIFY 251 +#define SSL_F_DTLS1_GET_MESSAGE 252 +#define SSL_F_DTLS1_GET_MESSAGE_FRAGMENT 253 +#define SSL_F_DTLS1_GET_RECORD 254 +#define SSL_F_DTLS1_HANDLE_TIMEOUT 297 +#define SSL_F_DTLS1_OUTPUT_CERT_CHAIN 255 +#define SSL_F_DTLS1_PREPROCESS_FRAGMENT 288 +#define SSL_F_DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE 256 +#define SSL_F_DTLS1_PROCESS_RECORD 257 +#define SSL_F_DTLS1_READ_BYTES 258 +#define SSL_F_DTLS1_READ_FAILED 259 +#define SSL_F_DTLS1_SEND_CERTIFICATE_REQUEST 260 +#define SSL_F_DTLS1_SEND_CLIENT_CERTIFICATE 261 +#define SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE 262 +#define SSL_F_DTLS1_SEND_CLIENT_VERIFY 263 +#define SSL_F_DTLS1_SEND_HELLO_VERIFY_REQUEST 264 +#define SSL_F_DTLS1_SEND_SERVER_CERTIFICATE 265 +#define SSL_F_DTLS1_SEND_SERVER_HELLO 266 +#define SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE 267 +#define SSL_F_DTLS1_WRITE_APP_DATA_BYTES 268 +#define SSL_F_GET_CLIENT_FINISHED 105 +#define SSL_F_GET_CLIENT_HELLO 106 +#define SSL_F_GET_CLIENT_MASTER_KEY 107 +#define SSL_F_GET_SERVER_FINISHED 108 +#define SSL_F_GET_SERVER_HELLO 109 +#define SSL_F_GET_SERVER_VERIFY 110 +#define SSL_F_I2D_SSL_SESSION 111 +#define SSL_F_READ_N 112 +#define SSL_F_REQUEST_CERTIFICATE 113 +#define SSL_F_SERVER_FINISH 239 +#define SSL_F_SERVER_HELLO 114 +#define SSL_F_SERVER_VERIFY 240 +#define SSL_F_SSL23_ACCEPT 115 +#define SSL_F_SSL23_CLIENT_HELLO 116 +#define SSL_F_SSL23_CONNECT 117 +#define SSL_F_SSL23_GET_CLIENT_HELLO 118 +#define SSL_F_SSL23_GET_SERVER_HELLO 119 +#define SSL_F_SSL23_PEEK 237 +#define SSL_F_SSL23_READ 120 +#define SSL_F_SSL23_WRITE 121 +#define SSL_F_SSL2_ACCEPT 122 +#define SSL_F_SSL2_CONNECT 123 +#define SSL_F_SSL2_ENC_INIT 124 +#define SSL_F_SSL2_GENERATE_KEY_MATERIAL 241 +#define SSL_F_SSL2_PEEK 234 +#define SSL_F_SSL2_READ 125 +#define SSL_F_SSL2_READ_INTERNAL 236 +#define SSL_F_SSL2_SET_CERTIFICATE 126 +#define SSL_F_SSL2_WRITE 127 +#define SSL_F_SSL3_ACCEPT 128 +#define SSL_F_SSL3_ADD_CERT_TO_BUF 296 +#define SSL_F_SSL3_CALLBACK_CTRL 233 +#define SSL_F_SSL3_CHANGE_CIPHER_STATE 129 +#define SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM 130 +#define SSL_F_SSL3_CLIENT_HELLO 131 +#define SSL_F_SSL3_CONNECT 132 +#define SSL_F_SSL3_CTRL 213 +#define SSL_F_SSL3_CTX_CTRL 133 +#define SSL_F_SSL3_DIGEST_CACHED_RECORDS 293 +#define SSL_F_SSL3_DO_CHANGE_CIPHER_SPEC 292 +#define SSL_F_SSL3_ENC 134 +#define SSL_F_SSL3_GENERATE_KEY_BLOCK 238 +#define SSL_F_SSL3_GET_CERTIFICATE_REQUEST 135 +#define SSL_F_SSL3_GET_CERT_STATUS 289 +#define SSL_F_SSL3_GET_CERT_VERIFY 136 +#define SSL_F_SSL3_GET_CLIENT_CERTIFICATE 137 +#define SSL_F_SSL3_GET_CLIENT_HELLO 138 +#define SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE 139 +#define SSL_F_SSL3_GET_FINISHED 140 +#define SSL_F_SSL3_GET_KEY_EXCHANGE 141 +#define SSL_F_SSL3_GET_MESSAGE 142 +#define SSL_F_SSL3_GET_NEW_SESSION_TICKET 283 +#define SSL_F_SSL3_GET_NEXT_PROTO 304 +#define SSL_F_SSL3_GET_RECORD 143 +#define SSL_F_SSL3_GET_SERVER_CERTIFICATE 144 +#define SSL_F_SSL3_GET_SERVER_DONE 145 +#define SSL_F_SSL3_GET_SERVER_HELLO 146 +#define SSL_F_SSL3_HANDSHAKE_MAC 285 +#define SSL_F_SSL3_NEW_SESSION_TICKET 287 +#define SSL_F_SSL3_OUTPUT_CERT_CHAIN 147 +#define SSL_F_SSL3_PEEK 235 +#define SSL_F_SSL3_READ_BYTES 148 +#define SSL_F_SSL3_READ_N 149 +#define SSL_F_SSL3_SEND_CERTIFICATE_REQUEST 150 +#define SSL_F_SSL3_SEND_CLIENT_CERTIFICATE 151 +#define SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE 152 +#define SSL_F_SSL3_SEND_CLIENT_VERIFY 153 +#define SSL_F_SSL3_SEND_SERVER_CERTIFICATE 154 +#define SSL_F_SSL3_SEND_SERVER_HELLO 242 +#define SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE 155 +#define SSL_F_SSL3_SETUP_KEY_BLOCK 157 +#define SSL_F_SSL3_SETUP_READ_BUFFER 156 +#define SSL_F_SSL3_SETUP_WRITE_BUFFER 291 +#define SSL_F_SSL3_WRITE_BYTES 158 +#define SSL_F_SSL3_WRITE_PENDING 159 +#define SSL_F_SSL_ADD_CLIENTHELLO_RENEGOTIATE_EXT 298 +#define SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT 277 +#define SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK 215 +#define SSL_F_SSL_ADD_FILE_CERT_SUBJECTS_TO_STACK 216 +#define SSL_F_SSL_ADD_SERVERHELLO_RENEGOTIATE_EXT 299 +#define SSL_F_SSL_ADD_SERVERHELLO_TLSEXT 278 +#define SSL_F_SSL_BAD_METHOD 160 +#define SSL_F_SSL_BYTES_TO_CIPHER_LIST 161 +#define SSL_F_SSL_CERT_DUP 221 +#define SSL_F_SSL_CERT_INST 222 +#define SSL_F_SSL_CERT_INSTANTIATE 214 +#define SSL_F_SSL_CERT_NEW 162 +#define SSL_F_SSL_CHECK_PRIVATE_KEY 163 +#define SSL_F_SSL_CHECK_SERVERHELLO_TLSEXT 280 +#define SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG 279 +#define SSL_F_SSL_CIPHER_PROCESS_RULESTR 230 +#define SSL_F_SSL_CIPHER_STRENGTH_SORT 231 +#define SSL_F_SSL_CLEAR 164 +#define SSL_F_SSL_COMP_ADD_COMPRESSION_METHOD 165 +#define SSL_F_SSL_CREATE_CIPHER_LIST 166 +#define SSL_F_SSL_CTRL 232 +#define SSL_F_SSL_CTX_CHECK_PRIVATE_KEY 168 +#define SSL_F_SSL_CTX_NEW 169 +#define SSL_F_SSL_CTX_SET_CIPHER_LIST 269 +#define SSL_F_SSL_CTX_SET_CLIENT_CERT_ENGINE 290 +#define SSL_F_SSL_CTX_SET_PURPOSE 226 +#define SSL_F_SSL_CTX_SET_SESSION_ID_CONTEXT 219 +#define SSL_F_SSL_CTX_SET_SSL_VERSION 170 +#define SSL_F_SSL_CTX_SET_TRUST 229 +#define SSL_F_SSL_CTX_USE_CERTIFICATE 171 +#define SSL_F_SSL_CTX_USE_CERTIFICATE_ASN1 172 +#define SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE 220 +#define SSL_F_SSL_CTX_USE_CERTIFICATE_FILE 173 +#define SSL_F_SSL_CTX_USE_PRIVATEKEY 174 +#define SSL_F_SSL_CTX_USE_PRIVATEKEY_ASN1 175 +#define SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE 176 +#define SSL_F_SSL_CTX_USE_PSK_IDENTITY_HINT 272 +#define SSL_F_SSL_CTX_USE_RSAPRIVATEKEY 177 +#define SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_ASN1 178 +#define SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_FILE 179 +#define SSL_F_SSL_DO_HANDSHAKE 180 +#define SSL_F_SSL_GET_NEW_SESSION 181 +#define SSL_F_SSL_GET_PREV_SESSION 217 +#define SSL_F_SSL_GET_SERVER_SEND_CERT 182 +#define SSL_F_SSL_GET_SIGN_PKEY 183 +#define SSL_F_SSL_INIT_WBIO_BUFFER 184 +#define SSL_F_SSL_LOAD_CLIENT_CA_FILE 185 +#define SSL_F_SSL_NEW 186 +#define SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT 300 +#define SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT 302 +#define SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT 301 +#define SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT 303 +#define SSL_F_SSL_PEEK 270 +#define SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT 281 +#define SSL_F_SSL_PREPARE_SERVERHELLO_TLSEXT 282 +#define SSL_F_SSL_READ 223 +#define SSL_F_SSL_RSA_PRIVATE_DECRYPT 187 +#define SSL_F_SSL_RSA_PUBLIC_ENCRYPT 188 +#define SSL_F_SSL_SESSION_NEW 189 +#define SSL_F_SSL_SESSION_PRINT_FP 190 +#define SSL_F_SSL_SESS_CERT_NEW 225 +#define SSL_F_SSL_SET_CERT 191 +#define SSL_F_SSL_SET_CIPHER_LIST 271 +#define SSL_F_SSL_SET_FD 192 +#define SSL_F_SSL_SET_PKEY 193 +#define SSL_F_SSL_SET_PURPOSE 227 +#define SSL_F_SSL_SET_RFD 194 +#define SSL_F_SSL_SET_SESSION 195 +#define SSL_F_SSL_SET_SESSION_ID_CONTEXT 218 +#define SSL_F_SSL_SET_SESSION_TICKET_EXT 294 +#define SSL_F_SSL_SET_TRUST 228 +#define SSL_F_SSL_SET_WFD 196 +#define SSL_F_SSL_SHUTDOWN 224 +#define SSL_F_SSL_UNDEFINED_CONST_FUNCTION 243 +#define SSL_F_SSL_UNDEFINED_FUNCTION 197 +#define SSL_F_SSL_UNDEFINED_VOID_FUNCTION 244 +#define SSL_F_SSL_USE_CERTIFICATE 198 +#define SSL_F_SSL_USE_CERTIFICATE_ASN1 199 +#define SSL_F_SSL_USE_CERTIFICATE_CHAIN 2000 +#define SSL_F_SSL_USE_CERTIFICATE_FILE 200 +#define SSL_F_SSL_USE_PRIVATEKEY 201 +#define SSL_F_SSL_USE_PRIVATEKEY_ASN1 202 +#define SSL_F_SSL_USE_PRIVATEKEY_FILE 203 +#define SSL_F_SSL_USE_PSK_IDENTITY_HINT 273 +#define SSL_F_SSL_USE_RSAPRIVATEKEY 204 +#define SSL_F_SSL_USE_RSAPRIVATEKEY_ASN1 205 +#define SSL_F_SSL_USE_RSAPRIVATEKEY_FILE 206 +#define SSL_F_SSL_VERIFY_CERT_CHAIN 207 +#define SSL_F_SSL_WRITE 208 +#define SSL_F_TLS1_CERT_VERIFY_MAC 286 +#define SSL_F_TLS1_CHANGE_CIPHER_STATE 209 +#define SSL_F_TLS1_CHECK_SERVERHELLO_TLSEXT 274 +#define SSL_F_TLS1_ENC 210 +#define SSL_F_TLS1_PREPARE_CLIENTHELLO_TLSEXT 275 +#define SSL_F_TLS1_PREPARE_SERVERHELLO_TLSEXT 276 +#define SSL_F_TLS1_PRF 284 +#define SSL_F_TLS1_SETUP_KEY_BLOCK 211 +#define SSL_F_WRITE_PENDING 212 + +/* Reason codes. */ +#define SSL_R_APP_DATA_IN_HANDSHAKE 100 +#define SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT 272 +#define SSL_R_BAD_ALERT_RECORD 101 +#define SSL_R_BAD_AUTHENTICATION_TYPE 102 +#define SSL_R_BAD_CHANGE_CIPHER_SPEC 103 +#define SSL_R_BAD_CHECKSUM 104 +#define SSL_R_BAD_DATA_RETURNED_BY_CALLBACK 106 +#define SSL_R_BAD_DECOMPRESSION 107 +#define SSL_R_BAD_DH_G_LENGTH 108 +#define SSL_R_BAD_DH_PUB_KEY_LENGTH 109 +#define SSL_R_BAD_DH_P_LENGTH 110 +#define SSL_R_BAD_DIGEST_LENGTH 111 +#define SSL_R_BAD_DSA_SIGNATURE 112 +#define SSL_R_BAD_ECC_CERT 304 +#define SSL_R_BAD_ECDSA_SIGNATURE 305 +#define SSL_R_BAD_ECPOINT 306 +#define SSL_R_BAD_HANDSHAKE_LENGTH 332 +#define SSL_R_BAD_HELLO_REQUEST 105 +#define SSL_R_BAD_LENGTH 271 +#define SSL_R_BAD_MAC_DECODE 113 +#define SSL_R_BAD_MAC_LENGTH 333 +#define SSL_R_BAD_MESSAGE_TYPE 114 +#define SSL_R_BAD_PACKET_LENGTH 115 +#define SSL_R_BAD_PROTOCOL_VERSION_NUMBER 116 +#define SSL_R_BAD_PSK_IDENTITY_HINT_LENGTH 316 +#define SSL_R_BAD_RESPONSE_ARGUMENT 117 +#define SSL_R_BAD_RSA_DECRYPT 118 +#define SSL_R_BAD_RSA_ENCRYPT 119 +#define SSL_R_BAD_RSA_E_LENGTH 120 +#define SSL_R_BAD_RSA_MODULUS_LENGTH 121 +#define SSL_R_BAD_RSA_SIGNATURE 122 +#define SSL_R_BAD_SIGNATURE 123 +#define SSL_R_BAD_SSL_FILETYPE 124 +#define SSL_R_BAD_SSL_SESSION_ID_LENGTH 125 +#define SSL_R_BAD_STATE 126 +#define SSL_R_BAD_WRITE_RETRY 127 +#define SSL_R_BIO_NOT_SET 128 +#define SSL_R_BLOCK_CIPHER_PAD_IS_WRONG 129 +#define SSL_R_BN_LIB 130 +#define SSL_R_CA_DN_LENGTH_MISMATCH 131 +#define SSL_R_CA_DN_TOO_LONG 132 +#define SSL_R_CCS_RECEIVED_EARLY 133 +#define SSL_R_CERTIFICATE_VERIFY_FAILED 134 +#define SSL_R_CERT_LENGTH_MISMATCH 135 +#define SSL_R_CHALLENGE_IS_DIFFERENT 136 +#define SSL_R_CIPHER_CODE_WRONG_LENGTH 137 +#define SSL_R_CIPHER_OR_HASH_UNAVAILABLE 138 +#define SSL_R_CIPHER_TABLE_SRC_ERROR 139 +#define SSL_R_CLIENTHELLO_TLSEXT 226 +#define SSL_R_COMPRESSED_LENGTH_TOO_LONG 140 +#define SSL_R_COMPRESSION_DISABLED 343 +#define SSL_R_COMPRESSION_FAILURE 141 +#define SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE 307 +#define SSL_R_COMPRESSION_LIBRARY_ERROR 142 +#define SSL_R_CONNECTION_ID_IS_DIFFERENT 143 +#define SSL_R_CONNECTION_TYPE_NOT_SET 144 +#define SSL_R_COOKIE_MISMATCH 308 +#define SSL_R_DATA_BETWEEN_CCS_AND_FINISHED 145 +#define SSL_R_DATA_LENGTH_TOO_LONG 146 +#define SSL_R_DECRYPTION_FAILED 147 +#define SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC 281 +#define SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG 148 +#define SSL_R_DIGEST_CHECK_FAILED 149 +#define SSL_R_DTLS_MESSAGE_TOO_BIG 334 +#define SSL_R_DUPLICATE_COMPRESSION_ID 309 +#define SSL_R_ECC_CERT_NOT_FOR_KEY_AGREEMENT 317 +#define SSL_R_ECC_CERT_NOT_FOR_SIGNING 318 +#define SSL_R_ECC_CERT_SHOULD_HAVE_RSA_SIGNATURE 322 +#define SSL_R_ECC_CERT_SHOULD_HAVE_SHA1_SIGNATURE 323 +#define SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER 310 +#define SSL_R_ENCRYPTED_LENGTH_TOO_LONG 150 +#define SSL_R_ERROR_GENERATING_TMP_RSA_KEY 282 +#define SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST 151 +#define SSL_R_EXCESSIVE_MESSAGE_SIZE 152 +#define SSL_R_EXTRA_DATA_IN_MESSAGE 153 +#define SSL_R_GOT_A_FIN_BEFORE_A_CCS 154 +#define SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS 346 +#define SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION 347 +#define SSL_R_HTTPS_PROXY_REQUEST 155 +#define SSL_R_HTTP_REQUEST 156 +#define SSL_R_ILLEGAL_PADDING 283 +#define SSL_R_INCONSISTENT_COMPRESSION 340 +#define SSL_R_INVALID_CHALLENGE_LENGTH 158 +#define SSL_R_INVALID_COMMAND 280 +#define SSL_R_INVALID_COMPRESSION_ALGORITHM 341 +#define SSL_R_INVALID_PURPOSE 278 +#define SSL_R_INVALID_STATUS_RESPONSE 328 +#define SSL_R_INVALID_TICKET_KEYS_LENGTH 325 +#define SSL_R_INVALID_TRUST 279 +#define SSL_R_KEY_ARG_TOO_LONG 284 +#define SSL_R_KRB5 285 +#define SSL_R_KRB5_C_CC_PRINC 286 +#define SSL_R_KRB5_C_GET_CRED 287 +#define SSL_R_KRB5_C_INIT 288 +#define SSL_R_KRB5_C_MK_REQ 289 +#define SSL_R_KRB5_S_BAD_TICKET 290 +#define SSL_R_KRB5_S_INIT 291 +#define SSL_R_KRB5_S_RD_REQ 292 +#define SSL_R_KRB5_S_TKT_EXPIRED 293 +#define SSL_R_KRB5_S_TKT_NYV 294 +#define SSL_R_KRB5_S_TKT_SKEW 295 +#define SSL_R_LENGTH_MISMATCH 159 +#define SSL_R_LENGTH_TOO_SHORT 160 +#define SSL_R_LIBRARY_BUG 274 +#define SSL_R_LIBRARY_HAS_NO_CIPHERS 161 +#define SSL_R_MESSAGE_TOO_LONG 296 +#define SSL_R_MISSING_DH_DSA_CERT 162 +#define SSL_R_MISSING_DH_KEY 163 +#define SSL_R_MISSING_DH_RSA_CERT 164 +#define SSL_R_MISSING_DSA_SIGNING_CERT 165 +#define SSL_R_MISSING_EXPORT_TMP_DH_KEY 166 +#define SSL_R_MISSING_EXPORT_TMP_RSA_KEY 167 +#define SSL_R_MISSING_RSA_CERTIFICATE 168 +#define SSL_R_MISSING_RSA_ENCRYPTING_CERT 169 +#define SSL_R_MISSING_RSA_SIGNING_CERT 170 +#define SSL_R_MISSING_TMP_DH_KEY 171 +#define SSL_R_MISSING_TMP_ECDH_KEY 311 +#define SSL_R_MISSING_TMP_RSA_KEY 172 +#define SSL_R_MISSING_TMP_RSA_PKEY 173 +#define SSL_R_MISSING_VERIFY_MESSAGE 174 +#define SSL_R_NON_SSLV2_INITIAL_PACKET 175 +#define SSL_R_NO_CERTIFICATES_RETURNED 176 +#define SSL_R_NO_CERTIFICATE_ASSIGNED 177 +#define SSL_R_NO_CERTIFICATE_RETURNED 178 +#define SSL_R_NO_CERTIFICATE_SET 179 +#define SSL_R_NO_CERTIFICATE_SPECIFIED 180 +#define SSL_R_NO_CIPHERS_AVAILABLE 181 +#define SSL_R_NO_CIPHERS_PASSED 182 +#define SSL_R_NO_CIPHERS_SPECIFIED 183 +#define SSL_R_NO_CIPHER_LIST 184 +#define SSL_R_NO_CIPHER_MATCH 185 +#define SSL_R_NO_CLIENT_CERT_METHOD 331 +#define SSL_R_NO_CLIENT_CERT_RECEIVED 186 +#define SSL_R_NO_COMPRESSION_SPECIFIED 187 +#define SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER 330 +#define SSL_R_NO_METHOD_SPECIFIED 188 +#define SSL_R_NO_PRIVATEKEY 189 +#define SSL_R_NO_PRIVATE_KEY_ASSIGNED 190 +#define SSL_R_NO_PROTOCOLS_AVAILABLE 191 +#define SSL_R_NO_PUBLICKEY 192 +#define SSL_R_NO_RENEGOTIATION 339 +#define SSL_R_NO_REQUIRED_DIGEST 324 +#define SSL_R_NO_SHARED_CIPHER 193 +#define SSL_R_NO_VERIFY_CALLBACK 194 +#define SSL_R_NULL_SSL_CTX 195 +#define SSL_R_NULL_SSL_METHOD_PASSED 196 +#define SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED 197 +#define SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED 344 +#define SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE 297 +#define SSL_R_OPAQUE_PRF_INPUT_TOO_LONG 327 +#define SSL_R_PACKET_LENGTH_TOO_LONG 198 +#define SSL_R_PARSE_TLSEXT 227 +#define SSL_R_PATH_TOO_LONG 270 +#define SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE 199 +#define SSL_R_PEER_ERROR 200 +#define SSL_R_PEER_ERROR_CERTIFICATE 201 +#define SSL_R_PEER_ERROR_NO_CERTIFICATE 202 +#define SSL_R_PEER_ERROR_NO_CIPHER 203 +#define SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE 204 +#define SSL_R_PRE_MAC_LENGTH_TOO_LONG 205 +#define SSL_R_PROBLEMS_MAPPING_CIPHER_FUNCTIONS 206 +#define SSL_R_PROTOCOL_IS_SHUTDOWN 207 +#define SSL_R_PSK_IDENTITY_NOT_FOUND 223 +#define SSL_R_PSK_NO_CLIENT_CB 224 +#define SSL_R_PSK_NO_SERVER_CB 225 +#define SSL_R_PUBLIC_KEY_ENCRYPT_ERROR 208 +#define SSL_R_PUBLIC_KEY_IS_NOT_RSA 209 +#define SSL_R_PUBLIC_KEY_NOT_RSA 210 +#define SSL_R_READ_BIO_NOT_SET 211 +#define SSL_R_READ_TIMEOUT_EXPIRED 312 +#define SSL_R_READ_WRONG_PACKET_TYPE 212 +#define SSL_R_RECORD_LENGTH_MISMATCH 213 +#define SSL_R_RECORD_TOO_LARGE 214 +#define SSL_R_RECORD_TOO_SMALL 298 +#define SSL_R_RENEGOTIATE_EXT_TOO_LONG 335 +#define SSL_R_RENEGOTIATION_ENCODING_ERR 336 +#define SSL_R_RENEGOTIATION_MISMATCH 337 +#define SSL_R_REQUIRED_CIPHER_MISSING 215 +#define SSL_R_REQUIRED_COMPRESSSION_ALGORITHM_MISSING 342 +#define SSL_R_REUSE_CERT_LENGTH_NOT_ZERO 216 +#define SSL_R_REUSE_CERT_TYPE_NOT_ZERO 217 +#define SSL_R_REUSE_CIPHER_LIST_NOT_ZERO 218 +#define SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING 345 +#define SSL_R_SERVERHELLO_TLSEXT 275 +#define SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED 277 +#define SSL_R_SESSION_MAY_NOT_BE_CREATED 2000 +#define SSL_R_SHORT_READ 219 +#define SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE 220 +#define SSL_R_SSL23_DOING_SESSION_ID_REUSE 221 +#define SSL_R_SSL2_CONNECTION_ID_TOO_LONG 299 +#define SSL_R_SSL3_EXT_INVALID_ECPOINTFORMAT 321 +#define SSL_R_SSL3_EXT_INVALID_SERVERNAME 319 +#define SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE 320 +#define SSL_R_SSL3_SESSION_ID_TOO_LONG 300 +#define SSL_R_SSL3_SESSION_ID_TOO_SHORT 222 +#define SSL_R_SSLV3_ALERT_BAD_CERTIFICATE 1042 +#define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020 +#define SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED 1045 +#define SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED 1044 +#define SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN 1046 +#define SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE 1030 +#define SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE 1040 +#define SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER 1047 +#define SSL_R_SSLV3_ALERT_NO_CERTIFICATE 1041 +#define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010 +#define SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE 1043 +#define SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION 228 +#define SSL_R_SSL_HANDSHAKE_FAILURE 229 +#define SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS 230 +#define SSL_R_SSL_SESSION_ID_CALLBACK_FAILED 301 +#define SSL_R_SSL_SESSION_ID_CONFLICT 302 +#define SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG 273 +#define SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH 303 +#define SSL_R_SSL_SESSION_ID_IS_DIFFERENT 231 +#define SSL_R_TLSV1_ALERT_ACCESS_DENIED 1049 +#define SSL_R_TLSV1_ALERT_DECODE_ERROR 1050 +#define SSL_R_TLSV1_ALERT_DECRYPTION_FAILED 1021 +#define SSL_R_TLSV1_ALERT_DECRYPT_ERROR 1051 +#define SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION 1060 +#define SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY 1071 +#define SSL_R_TLSV1_ALERT_INTERNAL_ERROR 1080 +#define SSL_R_TLSV1_ALERT_NO_RENEGOTIATION 1100 +#define SSL_R_TLSV1_ALERT_PROTOCOL_VERSION 1070 +#define SSL_R_TLSV1_ALERT_RECORD_OVERFLOW 1022 +#define SSL_R_TLSV1_ALERT_UNKNOWN_CA 1048 +#define SSL_R_TLSV1_ALERT_USER_CANCELLED 1090 +#define SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE 1114 +#define SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE 1113 +#define SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE 1111 +#define SSL_R_TLSV1_UNRECOGNIZED_NAME 1112 +#define SSL_R_TLSV1_UNSUPPORTED_EXTENSION 1110 +#define SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER 232 +#define SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST 157 +#define SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST 233 +#define SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG 234 +#define SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER 235 +#define SSL_R_UNABLE_TO_DECODE_DH_CERTS 236 +#define SSL_R_UNABLE_TO_DECODE_ECDH_CERTS 313 +#define SSL_R_UNABLE_TO_EXTRACT_PUBLIC_KEY 237 +#define SSL_R_UNABLE_TO_FIND_DH_PARAMETERS 238 +#define SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS 314 +#define SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS 239 +#define SSL_R_UNABLE_TO_FIND_SSL_METHOD 240 +#define SSL_R_UNABLE_TO_LOAD_SSL2_MD5_ROUTINES 241 +#define SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES 242 +#define SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES 243 +#define SSL_R_UNEXPECTED_MESSAGE 244 +#define SSL_R_UNEXPECTED_RECORD 245 +#define SSL_R_UNINITIALIZED 276 +#define SSL_R_UNKNOWN_ALERT_TYPE 246 +#define SSL_R_UNKNOWN_CERTIFICATE_TYPE 247 +#define SSL_R_UNKNOWN_CIPHER_RETURNED 248 +#define SSL_R_UNKNOWN_CIPHER_TYPE 249 +#define SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE 250 +#define SSL_R_UNKNOWN_PKEY_TYPE 251 +#define SSL_R_UNKNOWN_PROTOCOL 252 +#define SSL_R_UNKNOWN_REMOTE_ERROR_TYPE 253 +#define SSL_R_UNKNOWN_SSL_VERSION 254 +#define SSL_R_UNKNOWN_STATE 255 +#define SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED 338 +#define SSL_R_UNSUPPORTED_CIPHER 256 +#define SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM 257 +#define SSL_R_UNSUPPORTED_DIGEST_TYPE 326 +#define SSL_R_UNSUPPORTED_ELLIPTIC_CURVE 315 +#define SSL_R_UNSUPPORTED_PROTOCOL 258 +#define SSL_R_UNSUPPORTED_SSL_VERSION 259 +#define SSL_R_UNSUPPORTED_STATUS_TYPE 329 +#define SSL_R_WRITE_BIO_NOT_SET 260 +#define SSL_R_WRONG_CIPHER_RETURNED 261 +#define SSL_R_WRONG_MESSAGE_TYPE 262 +#define SSL_R_WRONG_NUMBER_OF_KEY_BITS 263 +#define SSL_R_WRONG_SIGNATURE_LENGTH 264 +#define SSL_R_WRONG_SIGNATURE_SIZE 265 +#define SSL_R_WRONG_SSL_VERSION 266 +#define SSL_R_WRONG_VERSION_NUMBER 267 +#define SSL_R_X509_LIB 268 +#define SSL_R_X509_VERIFICATION_SETUP_PROBLEMS 269 + +#ifdef __cplusplus +} +#endif +#endif diff --git a/app/openssl/ssl/ssl2.h b/app/openssl/ssl/ssl2.h new file mode 100644 index 00000000..99a52ea0 --- /dev/null +++ b/app/openssl/ssl/ssl2.h @@ -0,0 +1,268 @@ +/* ssl/ssl2.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.] + */ + +#ifndef HEADER_SSL2_H +#define HEADER_SSL2_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Protocol Version Codes */ +#define SSL2_VERSION 0x0002 +#define SSL2_VERSION_MAJOR 0x00 +#define SSL2_VERSION_MINOR 0x02 +/* #define SSL2_CLIENT_VERSION 0x0002 */ +/* #define SSL2_SERVER_VERSION 0x0002 */ + +/* Protocol Message Codes */ +#define SSL2_MT_ERROR 0 +#define SSL2_MT_CLIENT_HELLO 1 +#define SSL2_MT_CLIENT_MASTER_KEY 2 +#define SSL2_MT_CLIENT_FINISHED 3 +#define SSL2_MT_SERVER_HELLO 4 +#define SSL2_MT_SERVER_VERIFY 5 +#define SSL2_MT_SERVER_FINISHED 6 +#define SSL2_MT_REQUEST_CERTIFICATE 7 +#define SSL2_MT_CLIENT_CERTIFICATE 8 + +/* Error Message Codes */ +#define SSL2_PE_UNDEFINED_ERROR 0x0000 +#define SSL2_PE_NO_CIPHER 0x0001 +#define SSL2_PE_NO_CERTIFICATE 0x0002 +#define SSL2_PE_BAD_CERTIFICATE 0x0004 +#define SSL2_PE_UNSUPPORTED_CERTIFICATE_TYPE 0x0006 + +/* Cipher Kind Values */ +#define SSL2_CK_NULL_WITH_MD5 0x02000000 /* v3 */ +#define SSL2_CK_RC4_128_WITH_MD5 0x02010080 +#define SSL2_CK_RC4_128_EXPORT40_WITH_MD5 0x02020080 +#define SSL2_CK_RC2_128_CBC_WITH_MD5 0x02030080 +#define SSL2_CK_RC2_128_CBC_EXPORT40_WITH_MD5 0x02040080 +#define SSL2_CK_IDEA_128_CBC_WITH_MD5 0x02050080 +#define SSL2_CK_DES_64_CBC_WITH_MD5 0x02060040 +#define SSL2_CK_DES_64_CBC_WITH_SHA 0x02060140 /* v3 */ +#define SSL2_CK_DES_192_EDE3_CBC_WITH_MD5 0x020700c0 +#define SSL2_CK_DES_192_EDE3_CBC_WITH_SHA 0x020701c0 /* v3 */ +#define SSL2_CK_RC4_64_WITH_MD5 0x02080080 /* MS hack */ + +#define SSL2_CK_DES_64_CFB64_WITH_MD5_1 0x02ff0800 /* SSLeay */ +#define SSL2_CK_NULL 0x02ff0810 /* SSLeay */ + +#define SSL2_TXT_DES_64_CFB64_WITH_MD5_1 "DES-CFB-M1" +#define SSL2_TXT_NULL_WITH_MD5 "NULL-MD5" +#define SSL2_TXT_RC4_128_WITH_MD5 "RC4-MD5" +#define SSL2_TXT_RC4_128_EXPORT40_WITH_MD5 "EXP-RC4-MD5" +#define SSL2_TXT_RC2_128_CBC_WITH_MD5 "RC2-CBC-MD5" +#define SSL2_TXT_RC2_128_CBC_EXPORT40_WITH_MD5 "EXP-RC2-CBC-MD5" +#define SSL2_TXT_IDEA_128_CBC_WITH_MD5 "IDEA-CBC-MD5" +#define SSL2_TXT_DES_64_CBC_WITH_MD5 "DES-CBC-MD5" +#define SSL2_TXT_DES_64_CBC_WITH_SHA "DES-CBC-SHA" +#define SSL2_TXT_DES_192_EDE3_CBC_WITH_MD5 "DES-CBC3-MD5" +#define SSL2_TXT_DES_192_EDE3_CBC_WITH_SHA "DES-CBC3-SHA" +#define SSL2_TXT_RC4_64_WITH_MD5 "RC4-64-MD5" + +#define SSL2_TXT_NULL "NULL" + +/* Flags for the SSL_CIPHER.algorithm2 field */ +#define SSL2_CF_5_BYTE_ENC 0x01 +#define SSL2_CF_8_BYTE_ENC 0x02 + +/* Certificate Type Codes */ +#define SSL2_CT_X509_CERTIFICATE 0x01 + +/* Authentication Type Code */ +#define SSL2_AT_MD5_WITH_RSA_ENCRYPTION 0x01 + +#define SSL2_MAX_SSL_SESSION_ID_LENGTH 32 + +/* Upper/Lower Bounds */ +#define SSL2_MAX_MASTER_KEY_LENGTH_IN_BITS 256 +#ifdef OPENSSL_SYS_MPE +#define SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER 29998u +#else +#define SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER 32767u /* 2^15-1 */ +#endif +#define SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER 16383 /* 2^14-1 */ + +#define SSL2_CHALLENGE_LENGTH 16 +/*#define SSL2_CHALLENGE_LENGTH 32 */ +#define SSL2_MIN_CHALLENGE_LENGTH 16 +#define SSL2_MAX_CHALLENGE_LENGTH 32 +#define SSL2_CONNECTION_ID_LENGTH 16 +#define SSL2_MAX_CONNECTION_ID_LENGTH 16 +#define SSL2_SSL_SESSION_ID_LENGTH 16 +#define SSL2_MAX_CERT_CHALLENGE_LENGTH 32 +#define SSL2_MIN_CERT_CHALLENGE_LENGTH 16 +#define SSL2_MAX_KEY_MATERIAL_LENGTH 24 + +#ifndef HEADER_SSL_LOCL_H +#define CERT char +#endif + +typedef struct ssl2_state_st + { + int three_byte_header; + int clear_text; /* clear text */ + int escape; /* not used in SSLv2 */ + int ssl2_rollback; /* used if SSLv23 rolled back to SSLv2 */ + + /* non-blocking io info, used to make sure the same + * args were passwd */ + unsigned int wnum; /* number of bytes sent so far */ + int wpend_tot; + const unsigned char *wpend_buf; + + int wpend_off; /* offset to data to write */ + int wpend_len; /* number of bytes passwd to write */ + int wpend_ret; /* number of bytes to return to caller */ + + /* buffer raw data */ + int rbuf_left; + int rbuf_offs; + unsigned char *rbuf; + unsigned char *wbuf; + + unsigned char *write_ptr;/* used to point to the start due to + * 2/3 byte header. */ + + unsigned int padding; + unsigned int rlength; /* passed to ssl2_enc */ + int ract_data_length; /* Set when things are encrypted. */ + unsigned int wlength; /* passed to ssl2_enc */ + int wact_data_length; /* Set when things are decrypted. */ + unsigned char *ract_data; + unsigned char *wact_data; + unsigned char *mac_data; + + unsigned char *read_key; + unsigned char *write_key; + + /* Stuff specifically to do with this SSL session */ + unsigned int challenge_length; + unsigned char challenge[SSL2_MAX_CHALLENGE_LENGTH]; + unsigned int conn_id_length; + unsigned char conn_id[SSL2_MAX_CONNECTION_ID_LENGTH]; + unsigned int key_material_length; + unsigned char key_material[SSL2_MAX_KEY_MATERIAL_LENGTH*2]; + + unsigned long read_sequence; + unsigned long write_sequence; + + struct { + unsigned int conn_id_length; + unsigned int cert_type; + unsigned int cert_length; + unsigned int csl; + unsigned int clear; + unsigned int enc; + unsigned char ccl[SSL2_MAX_CERT_CHALLENGE_LENGTH]; + unsigned int cipher_spec_length; + unsigned int session_id_length; + unsigned int clen; + unsigned int rlen; + } tmp; + } SSL2_STATE; + +/* SSLv2 */ +/* client */ +#define SSL2_ST_SEND_CLIENT_HELLO_A (0x10|SSL_ST_CONNECT) +#define SSL2_ST_SEND_CLIENT_HELLO_B (0x11|SSL_ST_CONNECT) +#define SSL2_ST_GET_SERVER_HELLO_A (0x20|SSL_ST_CONNECT) +#define SSL2_ST_GET_SERVER_HELLO_B (0x21|SSL_ST_CONNECT) +#define SSL2_ST_SEND_CLIENT_MASTER_KEY_A (0x30|SSL_ST_CONNECT) +#define SSL2_ST_SEND_CLIENT_MASTER_KEY_B (0x31|SSL_ST_CONNECT) +#define SSL2_ST_SEND_CLIENT_FINISHED_A (0x40|SSL_ST_CONNECT) +#define SSL2_ST_SEND_CLIENT_FINISHED_B (0x41|SSL_ST_CONNECT) +#define SSL2_ST_SEND_CLIENT_CERTIFICATE_A (0x50|SSL_ST_CONNECT) +#define SSL2_ST_SEND_CLIENT_CERTIFICATE_B (0x51|SSL_ST_CONNECT) +#define SSL2_ST_SEND_CLIENT_CERTIFICATE_C (0x52|SSL_ST_CONNECT) +#define SSL2_ST_SEND_CLIENT_CERTIFICATE_D (0x53|SSL_ST_CONNECT) +#define SSL2_ST_GET_SERVER_VERIFY_A (0x60|SSL_ST_CONNECT) +#define SSL2_ST_GET_SERVER_VERIFY_B (0x61|SSL_ST_CONNECT) +#define SSL2_ST_GET_SERVER_FINISHED_A (0x70|SSL_ST_CONNECT) +#define SSL2_ST_GET_SERVER_FINISHED_B (0x71|SSL_ST_CONNECT) +#define SSL2_ST_CLIENT_START_ENCRYPTION (0x80|SSL_ST_CONNECT) +#define SSL2_ST_X509_GET_CLIENT_CERTIFICATE (0x90|SSL_ST_CONNECT) +/* server */ +#define SSL2_ST_GET_CLIENT_HELLO_A (0x10|SSL_ST_ACCEPT) +#define SSL2_ST_GET_CLIENT_HELLO_B (0x11|SSL_ST_ACCEPT) +#define SSL2_ST_GET_CLIENT_HELLO_C (0x12|SSL_ST_ACCEPT) +#define SSL2_ST_SEND_SERVER_HELLO_A (0x20|SSL_ST_ACCEPT) +#define SSL2_ST_SEND_SERVER_HELLO_B (0x21|SSL_ST_ACCEPT) +#define SSL2_ST_GET_CLIENT_MASTER_KEY_A (0x30|SSL_ST_ACCEPT) +#define SSL2_ST_GET_CLIENT_MASTER_KEY_B (0x31|SSL_ST_ACCEPT) +#define SSL2_ST_SEND_SERVER_VERIFY_A (0x40|SSL_ST_ACCEPT) +#define SSL2_ST_SEND_SERVER_VERIFY_B (0x41|SSL_ST_ACCEPT) +#define SSL2_ST_SEND_SERVER_VERIFY_C (0x42|SSL_ST_ACCEPT) +#define SSL2_ST_GET_CLIENT_FINISHED_A (0x50|SSL_ST_ACCEPT) +#define SSL2_ST_GET_CLIENT_FINISHED_B (0x51|SSL_ST_ACCEPT) +#define SSL2_ST_SEND_SERVER_FINISHED_A (0x60|SSL_ST_ACCEPT) +#define SSL2_ST_SEND_SERVER_FINISHED_B (0x61|SSL_ST_ACCEPT) +#define SSL2_ST_SEND_REQUEST_CERTIFICATE_A (0x70|SSL_ST_ACCEPT) +#define SSL2_ST_SEND_REQUEST_CERTIFICATE_B (0x71|SSL_ST_ACCEPT) +#define SSL2_ST_SEND_REQUEST_CERTIFICATE_C (0x72|SSL_ST_ACCEPT) +#define SSL2_ST_SEND_REQUEST_CERTIFICATE_D (0x73|SSL_ST_ACCEPT) +#define SSL2_ST_SERVER_START_ENCRYPTION (0x80|SSL_ST_ACCEPT) +#define SSL2_ST_X509_GET_SERVER_CERTIFICATE (0x90|SSL_ST_ACCEPT) + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/app/openssl/ssl/ssl23.h b/app/openssl/ssl/ssl23.h new file mode 100644 index 00000000..d3228983 --- /dev/null +++ b/app/openssl/ssl/ssl23.h @@ -0,0 +1,83 @@ +/* ssl/ssl23.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.] + */ + +#ifndef HEADER_SSL23_H +#define HEADER_SSL23_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*client */ +/* write to server */ +#define SSL23_ST_CW_CLNT_HELLO_A (0x210|SSL_ST_CONNECT) +#define SSL23_ST_CW_CLNT_HELLO_B (0x211|SSL_ST_CONNECT) +/* read from server */ +#define SSL23_ST_CR_SRVR_HELLO_A (0x220|SSL_ST_CONNECT) +#define SSL23_ST_CR_SRVR_HELLO_B (0x221|SSL_ST_CONNECT) + +/* server */ +/* read from client */ +#define SSL23_ST_SR_CLNT_HELLO_A (0x210|SSL_ST_ACCEPT) +#define SSL23_ST_SR_CLNT_HELLO_B (0x211|SSL_ST_ACCEPT) + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/app/openssl/ssl/ssl3.h b/app/openssl/ssl/ssl3.h new file mode 100644 index 00000000..f9268c57 --- /dev/null +++ b/app/openssl/ssl/ssl3.h @@ -0,0 +1,664 @@ +/* ssl/ssl3.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-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. + */ + +#ifndef HEADER_SSL3_H +#define HEADER_SSL3_H + +#ifndef OPENSSL_NO_COMP +#include <openssl/comp.h> +#endif +#include <openssl/buffer.h> +#include <openssl/evp.h> +#include <openssl/ssl.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* Signalling cipher suite value: from draft-ietf-tls-renegotiation-03.txt */ +#define SSL3_CK_SCSV 0x030000FF + +#define SSL3_CK_RSA_NULL_MD5 0x03000001 +#define SSL3_CK_RSA_NULL_SHA 0x03000002 +#define SSL3_CK_RSA_RC4_40_MD5 0x03000003 +#define SSL3_CK_RSA_RC4_128_MD5 0x03000004 +#define SSL3_CK_RSA_RC4_128_SHA 0x03000005 +#define SSL3_CK_RSA_RC2_40_MD5 0x03000006 +#define SSL3_CK_RSA_IDEA_128_SHA 0x03000007 +#define SSL3_CK_RSA_DES_40_CBC_SHA 0x03000008 +#define SSL3_CK_RSA_DES_64_CBC_SHA 0x03000009 +#define SSL3_CK_RSA_DES_192_CBC3_SHA 0x0300000A + +#define SSL3_CK_DH_DSS_DES_40_CBC_SHA 0x0300000B +#define SSL3_CK_DH_DSS_DES_64_CBC_SHA 0x0300000C +#define SSL3_CK_DH_DSS_DES_192_CBC3_SHA 0x0300000D +#define SSL3_CK_DH_RSA_DES_40_CBC_SHA 0x0300000E +#define SSL3_CK_DH_RSA_DES_64_CBC_SHA 0x0300000F +#define SSL3_CK_DH_RSA_DES_192_CBC3_SHA 0x03000010 + +#define SSL3_CK_EDH_DSS_DES_40_CBC_SHA 0x03000011 +#define SSL3_CK_EDH_DSS_DES_64_CBC_SHA 0x03000012 +#define SSL3_CK_EDH_DSS_DES_192_CBC3_SHA 0x03000013 +#define SSL3_CK_EDH_RSA_DES_40_CBC_SHA 0x03000014 +#define SSL3_CK_EDH_RSA_DES_64_CBC_SHA 0x03000015 +#define SSL3_CK_EDH_RSA_DES_192_CBC3_SHA 0x03000016 + +#define SSL3_CK_ADH_RC4_40_MD5 0x03000017 +#define SSL3_CK_ADH_RC4_128_MD5 0x03000018 +#define SSL3_CK_ADH_DES_40_CBC_SHA 0x03000019 +#define SSL3_CK_ADH_DES_64_CBC_SHA 0x0300001A +#define SSL3_CK_ADH_DES_192_CBC_SHA 0x0300001B + +#if 0 + #define SSL3_CK_FZA_DMS_NULL_SHA 0x0300001C + #define SSL3_CK_FZA_DMS_FZA_SHA 0x0300001D + #if 0 /* Because it clashes with KRB5, is never used any more, and is safe + to remove according to David Hopwood <david.hopwood@zetnet.co.uk> + of the ietf-tls list */ + #define SSL3_CK_FZA_DMS_RC4_SHA 0x0300001E + #endif +#endif + +/* VRS Additional Kerberos5 entries + */ +#define SSL3_CK_KRB5_DES_64_CBC_SHA 0x0300001E +#define SSL3_CK_KRB5_DES_192_CBC3_SHA 0x0300001F +#define SSL3_CK_KRB5_RC4_128_SHA 0x03000020 +#define SSL3_CK_KRB5_IDEA_128_CBC_SHA 0x03000021 +#define SSL3_CK_KRB5_DES_64_CBC_MD5 0x03000022 +#define SSL3_CK_KRB5_DES_192_CBC3_MD5 0x03000023 +#define SSL3_CK_KRB5_RC4_128_MD5 0x03000024 +#define SSL3_CK_KRB5_IDEA_128_CBC_MD5 0x03000025 + +#define SSL3_CK_KRB5_DES_40_CBC_SHA 0x03000026 +#define SSL3_CK_KRB5_RC2_40_CBC_SHA 0x03000027 +#define SSL3_CK_KRB5_RC4_40_SHA 0x03000028 +#define SSL3_CK_KRB5_DES_40_CBC_MD5 0x03000029 +#define SSL3_CK_KRB5_RC2_40_CBC_MD5 0x0300002A +#define SSL3_CK_KRB5_RC4_40_MD5 0x0300002B + +#define SSL3_TXT_RSA_NULL_MD5 "NULL-MD5" +#define SSL3_TXT_RSA_NULL_SHA "NULL-SHA" +#define SSL3_TXT_RSA_RC4_40_MD5 "EXP-RC4-MD5" +#define SSL3_TXT_RSA_RC4_128_MD5 "RC4-MD5" +#define SSL3_TXT_RSA_RC4_128_SHA "RC4-SHA" +#define SSL3_TXT_RSA_RC2_40_MD5 "EXP-RC2-CBC-MD5" +#define SSL3_TXT_RSA_IDEA_128_SHA "IDEA-CBC-SHA" +#define SSL3_TXT_RSA_DES_40_CBC_SHA "EXP-DES-CBC-SHA" +#define SSL3_TXT_RSA_DES_64_CBC_SHA "DES-CBC-SHA" +#define SSL3_TXT_RSA_DES_192_CBC3_SHA "DES-CBC3-SHA" + +#define SSL3_TXT_DH_DSS_DES_40_CBC_SHA "EXP-DH-DSS-DES-CBC-SHA" +#define SSL3_TXT_DH_DSS_DES_64_CBC_SHA "DH-DSS-DES-CBC-SHA" +#define SSL3_TXT_DH_DSS_DES_192_CBC3_SHA "DH-DSS-DES-CBC3-SHA" +#define SSL3_TXT_DH_RSA_DES_40_CBC_SHA "EXP-DH-RSA-DES-CBC-SHA" +#define SSL3_TXT_DH_RSA_DES_64_CBC_SHA "DH-RSA-DES-CBC-SHA" +#define SSL3_TXT_DH_RSA_DES_192_CBC3_SHA "DH-RSA-DES-CBC3-SHA" + +#define SSL3_TXT_EDH_DSS_DES_40_CBC_SHA "EXP-EDH-DSS-DES-CBC-SHA" +#define SSL3_TXT_EDH_DSS_DES_64_CBC_SHA "EDH-DSS-DES-CBC-SHA" +#define SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA "EDH-DSS-DES-CBC3-SHA" +#define SSL3_TXT_EDH_RSA_DES_40_CBC_SHA "EXP-EDH-RSA-DES-CBC-SHA" +#define SSL3_TXT_EDH_RSA_DES_64_CBC_SHA "EDH-RSA-DES-CBC-SHA" +#define SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA "EDH-RSA-DES-CBC3-SHA" + +#define SSL3_TXT_ADH_RC4_40_MD5 "EXP-ADH-RC4-MD5" +#define SSL3_TXT_ADH_RC4_128_MD5 "ADH-RC4-MD5" +#define SSL3_TXT_ADH_DES_40_CBC_SHA "EXP-ADH-DES-CBC-SHA" +#define SSL3_TXT_ADH_DES_64_CBC_SHA "ADH-DES-CBC-SHA" +#define SSL3_TXT_ADH_DES_192_CBC_SHA "ADH-DES-CBC3-SHA" + +#if 0 + #define SSL3_TXT_FZA_DMS_NULL_SHA "FZA-NULL-SHA" + #define SSL3_TXT_FZA_DMS_FZA_SHA "FZA-FZA-CBC-SHA" + #define SSL3_TXT_FZA_DMS_RC4_SHA "FZA-RC4-SHA" +#endif + +#define SSL3_TXT_KRB5_DES_64_CBC_SHA "KRB5-DES-CBC-SHA" +#define SSL3_TXT_KRB5_DES_192_CBC3_SHA "KRB5-DES-CBC3-SHA" +#define SSL3_TXT_KRB5_RC4_128_SHA "KRB5-RC4-SHA" +#define SSL3_TXT_KRB5_IDEA_128_CBC_SHA "KRB5-IDEA-CBC-SHA" +#define SSL3_TXT_KRB5_DES_64_CBC_MD5 "KRB5-DES-CBC-MD5" +#define SSL3_TXT_KRB5_DES_192_CBC3_MD5 "KRB5-DES-CBC3-MD5" +#define SSL3_TXT_KRB5_RC4_128_MD5 "KRB5-RC4-MD5" +#define SSL3_TXT_KRB5_IDEA_128_CBC_MD5 "KRB5-IDEA-CBC-MD5" + +#define SSL3_TXT_KRB5_DES_40_CBC_SHA "EXP-KRB5-DES-CBC-SHA" +#define SSL3_TXT_KRB5_RC2_40_CBC_SHA "EXP-KRB5-RC2-CBC-SHA" +#define SSL3_TXT_KRB5_RC4_40_SHA "EXP-KRB5-RC4-SHA" +#define SSL3_TXT_KRB5_DES_40_CBC_MD5 "EXP-KRB5-DES-CBC-MD5" +#define SSL3_TXT_KRB5_RC2_40_CBC_MD5 "EXP-KRB5-RC2-CBC-MD5" +#define SSL3_TXT_KRB5_RC4_40_MD5 "EXP-KRB5-RC4-MD5" + +#define SSL3_SSL_SESSION_ID_LENGTH 32 +#define SSL3_MAX_SSL_SESSION_ID_LENGTH 32 + +#define SSL3_MASTER_SECRET_SIZE 48 +#define SSL3_RANDOM_SIZE 32 +#define SSL3_SESSION_ID_SIZE 32 +#define SSL3_RT_HEADER_LENGTH 5 + +#ifndef SSL3_ALIGN_PAYLOAD + /* Some will argue that this increases memory footprint, but it's + * not actually true. Point is that malloc has to return at least + * 64-bit aligned pointers, meaning that allocating 5 bytes wastes + * 3 bytes in either case. Suggested pre-gaping simply moves these + * wasted bytes from the end of allocated region to its front, + * but makes data payload aligned, which improves performance:-) */ +# define SSL3_ALIGN_PAYLOAD 8 +#else +# if (SSL3_ALIGN_PAYLOAD&(SSL3_ALIGN_PAYLOAD-1))!=0 +# error "insane SSL3_ALIGN_PAYLOAD" +# undef SSL3_ALIGN_PAYLOAD +# endif +#endif + +/* This is the maximum MAC (digest) size used by the SSL library. + * Currently maximum of 20 is used by SHA1, but we reserve for + * future extension for 512-bit hashes. + */ + +#define SSL3_RT_MAX_MD_SIZE 64 + +/* Maximum block size used in all ciphersuites. Currently 16 for AES. + */ + +#define SSL_RT_MAX_CIPHER_BLOCK_SIZE 16 + +#define SSL3_RT_MAX_EXTRA (16384) + +/* Default buffer length used for writen records. Thus a generated record + * will contain plaintext no larger than this value. */ +#define SSL3_RT_DEFAULT_PLAIN_LENGTH 2048 +/* Maximum plaintext length: defined by SSL/TLS standards */ +#define SSL3_RT_MAX_PLAIN_LENGTH 16384 +/* Maximum compression overhead: defined by SSL/TLS standards */ +#define SSL3_RT_MAX_COMPRESSED_OVERHEAD 1024 + +/* The standards give a maximum encryption overhead of 1024 bytes. + * In practice the value is lower than this. The overhead is the maximum + * number of padding bytes (256) plus the mac size. + */ +#define SSL3_RT_MAX_ENCRYPTED_OVERHEAD (256 + SSL3_RT_MAX_MD_SIZE) + +/* OpenSSL currently only uses a padding length of at most one block so + * the send overhead is smaller. + */ + +#define SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD \ + (SSL_RT_MAX_CIPHER_BLOCK_SIZE + SSL3_RT_MAX_MD_SIZE) + +/* If compression isn't used don't include the compression overhead */ + +#ifdef OPENSSL_NO_COMP +#define SSL3_RT_MAX_COMPRESSED_LENGTH SSL3_RT_MAX_PLAIN_LENGTH +#else +#define SSL3_RT_MAX_COMPRESSED_LENGTH \ + (SSL3_RT_MAX_PLAIN_LENGTH+SSL3_RT_MAX_COMPRESSED_OVERHEAD) +#endif +#define SSL3_RT_MAX_ENCRYPTED_LENGTH \ + (SSL3_RT_MAX_ENCRYPTED_OVERHEAD+SSL3_RT_MAX_COMPRESSED_LENGTH) +#define SSL3_RT_MAX_PACKET_SIZE \ + (SSL3_RT_MAX_ENCRYPTED_LENGTH+SSL3_RT_HEADER_LENGTH) + +/* Extra space for empty fragment, headers, MAC, and padding. */ +#define SSL3_RT_DEFAULT_WRITE_OVERHEAD 256 +#define SSL3_RT_DEFAULT_PACKET_SIZE 4096 - SSL3_RT_DEFAULT_WRITE_OVERHEAD +#if SSL3_RT_DEFAULT_PLAIN_LENGTH + SSL3_RT_DEFAULT_WRITE_OVERHEAD > SSL3_RT_DEFAULT_PACKET_SIZE +#error "Insufficient space allocated for write buffers." +#endif + +#define SSL3_MD_CLIENT_FINISHED_CONST "\x43\x4C\x4E\x54" +#define SSL3_MD_SERVER_FINISHED_CONST "\x53\x52\x56\x52" + +#define SSL3_VERSION 0x0300 +#define SSL3_VERSION_MAJOR 0x03 +#define SSL3_VERSION_MINOR 0x00 + +#define SSL3_RT_CHANGE_CIPHER_SPEC 20 +#define SSL3_RT_ALERT 21 +#define SSL3_RT_HANDSHAKE 22 +#define SSL3_RT_APPLICATION_DATA 23 + +#define SSL3_AL_WARNING 1 +#define SSL3_AL_FATAL 2 + +#define SSL3_AD_CLOSE_NOTIFY 0 +#define SSL3_AD_UNEXPECTED_MESSAGE 10 /* fatal */ +#define SSL3_AD_BAD_RECORD_MAC 20 /* fatal */ +#define SSL3_AD_DECOMPRESSION_FAILURE 30 /* fatal */ +#define SSL3_AD_HANDSHAKE_FAILURE 40 /* fatal */ +#define SSL3_AD_NO_CERTIFICATE 41 +#define SSL3_AD_BAD_CERTIFICATE 42 +#define SSL3_AD_UNSUPPORTED_CERTIFICATE 43 +#define SSL3_AD_CERTIFICATE_REVOKED 44 +#define SSL3_AD_CERTIFICATE_EXPIRED 45 +#define SSL3_AD_CERTIFICATE_UNKNOWN 46 +#define SSL3_AD_ILLEGAL_PARAMETER 47 /* fatal */ + +typedef struct ssl3_record_st + { +/*r */ int type; /* type of record */ +/*rw*/ unsigned int length; /* How many bytes available */ +/*r */ unsigned int off; /* read/write offset into 'buf' */ +/*rw*/ unsigned char *data; /* pointer to the record data */ +/*rw*/ unsigned char *input; /* where the decode bytes are */ +/*r */ unsigned char *comp; /* only used with decompression - malloc()ed */ +/*r */ unsigned long epoch; /* epoch number, needed by DTLS1 */ +/*r */ unsigned char seq_num[8]; /* sequence number, needed by DTLS1 */ + } SSL3_RECORD; + +typedef struct ssl3_buffer_st + { + unsigned char *buf; /* at least SSL3_RT_MAX_PACKET_SIZE bytes, + * see ssl3_setup_buffers() */ + size_t len; /* buffer size */ + int offset; /* where to 'copy from' */ + int left; /* how many bytes left */ + } SSL3_BUFFER; + +#define SSL3_CT_RSA_SIGN 1 +#define SSL3_CT_DSS_SIGN 2 +#define SSL3_CT_RSA_FIXED_DH 3 +#define SSL3_CT_DSS_FIXED_DH 4 +#define SSL3_CT_RSA_EPHEMERAL_DH 5 +#define SSL3_CT_DSS_EPHEMERAL_DH 6 +#define SSL3_CT_FORTEZZA_DMS 20 +/* SSL3_CT_NUMBER is used to size arrays and it must be large + * enough to contain all of the cert types defined either for + * SSLv3 and TLSv1. + */ +#define SSL3_CT_NUMBER 9 + + +#define SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS 0x0001 +#define SSL3_FLAGS_DELAY_CLIENT_FINISHED 0x0002 +#define SSL3_FLAGS_POP_BUFFER 0x0004 +#define TLS1_FLAGS_TLS_PADDING_BUG 0x0008 +#define TLS1_FLAGS_SKIP_CERT_VERIFY 0x0010 + +typedef struct ssl3_state_st + { + long flags; + int delay_buf_pop_ret; + + unsigned char read_sequence[8]; + int read_mac_secret_size; + unsigned char read_mac_secret[EVP_MAX_MD_SIZE]; + unsigned char write_sequence[8]; + int write_mac_secret_size; + unsigned char write_mac_secret[EVP_MAX_MD_SIZE]; + + unsigned char server_random[SSL3_RANDOM_SIZE]; + unsigned char client_random[SSL3_RANDOM_SIZE]; + + /* flags for countermeasure against known-IV weakness */ + int need_empty_fragments; + int empty_fragment_done; + + /* The value of 'extra' when the buffers were initialized */ + int init_extra; + + SSL3_BUFFER rbuf; /* read IO goes into here */ + SSL3_BUFFER wbuf; /* write IO goes into here */ + + SSL3_RECORD rrec; /* each decoded record goes in here */ + SSL3_RECORD wrec; /* goes out from here */ + + /* storage for Alert/Handshake protocol data received but not + * yet processed by ssl3_read_bytes: */ + unsigned char alert_fragment[2]; + unsigned int alert_fragment_len; + unsigned char handshake_fragment[4]; + unsigned int handshake_fragment_len; + + /* partial write - check the numbers match */ + unsigned int wnum; /* number of bytes sent so far */ + int wpend_tot; /* number bytes written */ + int wpend_type; + int wpend_ret; /* number of bytes submitted */ + const unsigned char *wpend_buf; + + /* used during startup, digest all incoming/outgoing packets */ + BIO *handshake_buffer; + /* When set of handshake digests is determined, buffer is hashed + * and freed and MD_CTX-es for all required digests are stored in + * this array */ + EVP_MD_CTX **handshake_dgst; + /* this is set whenerver we see a change_cipher_spec message + * come in when we are not looking for one */ + int change_cipher_spec; + + int warn_alert; + int fatal_alert; + /* we allow one fatal and one warning alert to be outstanding, + * send close alert via the warning alert */ + int alert_dispatch; + unsigned char send_alert[2]; + + /* This flag is set when we should renegotiate ASAP, basically when + * there is no more data in the read or write buffers */ + int renegotiate; + int total_renegotiations; + int num_renegotiations; + + int in_read_app_data; + + /* Opaque PRF input as used for the current handshake. + * These fields are used only if TLSEXT_TYPE_opaque_prf_input is defined + * (otherwise, they are merely present to improve binary compatibility) */ + void *client_opaque_prf_input; + size_t client_opaque_prf_input_len; + void *server_opaque_prf_input; + size_t server_opaque_prf_input_len; + +#ifndef OPENSSL_NO_NEXTPROTONEG + /* Set if we saw the Next Protocol Negotiation extension from + our peer. */ + int next_proto_neg_seen; +#endif + + struct { + /* actually only needs to be 16+20 */ + unsigned char cert_verify_md[EVP_MAX_MD_SIZE*2]; + + /* actually only need to be 16+20 for SSLv3 and 12 for TLS */ + unsigned char finish_md[EVP_MAX_MD_SIZE*2]; + int finish_md_len; + unsigned char peer_finish_md[EVP_MAX_MD_SIZE*2]; + int peer_finish_md_len; + + unsigned long message_size; + int message_type; + + /* used to hold the new cipher we are going to use */ + const SSL_CIPHER *new_cipher; +#ifndef OPENSSL_NO_DH + DH *dh; +#endif + +#ifndef OPENSSL_NO_ECDH + EC_KEY *ecdh; /* holds short lived ECDH key */ +#endif + + /* used when SSL_ST_FLUSH_DATA is entered */ + int next_state; + + int reuse_message; + + /* used for certificate requests */ + int cert_req; + int ctype_num; + char ctype[SSL3_CT_NUMBER]; + STACK_OF(X509_NAME) *ca_names; + + int use_rsa_tmp; + + int key_block_length; + unsigned char *key_block; + + const EVP_CIPHER *new_sym_enc; + const EVP_MD *new_hash; + int new_mac_pkey_type; + int new_mac_secret_size; +#ifndef OPENSSL_NO_COMP + const SSL_COMP *new_compression; +#else + char *new_compression; +#endif + int cert_request; + } tmp; + + /* Connection binding to prevent renegotiation attacks */ + unsigned char previous_client_finished[EVP_MAX_MD_SIZE]; + unsigned char previous_client_finished_len; + unsigned char previous_server_finished[EVP_MAX_MD_SIZE]; + unsigned char previous_server_finished_len; + int send_connection_binding; /* TODOEKR */ + } SSL3_STATE; + + +/* SSLv3 */ +/*client */ +/* extra state */ +#define SSL3_ST_CW_FLUSH (0x100|SSL_ST_CONNECT) +#define SSL3_ST_CUTTHROUGH_COMPLETE (0x101|SSL_ST_CONNECT) +/* write to server */ +#define SSL3_ST_CW_CLNT_HELLO_A (0x110|SSL_ST_CONNECT) +#define SSL3_ST_CW_CLNT_HELLO_B (0x111|SSL_ST_CONNECT) +/* read from server */ +#define SSL3_ST_CR_SRVR_HELLO_A (0x120|SSL_ST_CONNECT) +#define SSL3_ST_CR_SRVR_HELLO_B (0x121|SSL_ST_CONNECT) +#define DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A (0x126|SSL_ST_CONNECT) +#define DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B (0x127|SSL_ST_CONNECT) +#define SSL3_ST_CR_CERT_A (0x130|SSL_ST_CONNECT) +#define SSL3_ST_CR_CERT_B (0x131|SSL_ST_CONNECT) +#define SSL3_ST_CR_KEY_EXCH_A (0x140|SSL_ST_CONNECT) +#define SSL3_ST_CR_KEY_EXCH_B (0x141|SSL_ST_CONNECT) +#define SSL3_ST_CR_CERT_REQ_A (0x150|SSL_ST_CONNECT) +#define SSL3_ST_CR_CERT_REQ_B (0x151|SSL_ST_CONNECT) +#define SSL3_ST_CR_SRVR_DONE_A (0x160|SSL_ST_CONNECT) +#define SSL3_ST_CR_SRVR_DONE_B (0x161|SSL_ST_CONNECT) +/* write to server */ +#define SSL3_ST_CW_CERT_A (0x170|SSL_ST_CONNECT) +#define SSL3_ST_CW_CERT_B (0x171|SSL_ST_CONNECT) +#define SSL3_ST_CW_CERT_C (0x172|SSL_ST_CONNECT) +#define SSL3_ST_CW_CERT_D (0x173|SSL_ST_CONNECT) +#define SSL3_ST_CW_KEY_EXCH_A (0x180|SSL_ST_CONNECT) +#define SSL3_ST_CW_KEY_EXCH_B (0x181|SSL_ST_CONNECT) +#define SSL3_ST_CW_CERT_VRFY_A (0x190|SSL_ST_CONNECT) +#define SSL3_ST_CW_CERT_VRFY_B (0x191|SSL_ST_CONNECT) +#define SSL3_ST_CW_CHANGE_A (0x1A0|SSL_ST_CONNECT) +#define SSL3_ST_CW_CHANGE_B (0x1A1|SSL_ST_CONNECT) +#ifndef OPENSSL_NO_NEXTPROTONEG +#define SSL3_ST_CW_NEXT_PROTO_A (0x200|SSL_ST_CONNECT) +#define SSL3_ST_CW_NEXT_PROTO_B (0x201|SSL_ST_CONNECT) +#endif +#define SSL3_ST_CW_FINISHED_A (0x1B0|SSL_ST_CONNECT) +#define SSL3_ST_CW_FINISHED_B (0x1B1|SSL_ST_CONNECT) +/* read from server */ +#define SSL3_ST_CR_CHANGE_A (0x1C0|SSL_ST_CONNECT) +#define SSL3_ST_CR_CHANGE_B (0x1C1|SSL_ST_CONNECT) +#define SSL3_ST_CR_FINISHED_A (0x1D0|SSL_ST_CONNECT) +#define SSL3_ST_CR_FINISHED_B (0x1D1|SSL_ST_CONNECT) +#define SSL3_ST_CR_SESSION_TICKET_A (0x1E0|SSL_ST_CONNECT) +#define SSL3_ST_CR_SESSION_TICKET_B (0x1E1|SSL_ST_CONNECT) +#define SSL3_ST_CR_CERT_STATUS_A (0x1F0|SSL_ST_CONNECT) +#define SSL3_ST_CR_CERT_STATUS_B (0x1F1|SSL_ST_CONNECT) + +/* server */ +/* extra state */ +#define SSL3_ST_SW_FLUSH (0x100|SSL_ST_ACCEPT) +/* read from client */ +/* Do not change the number values, they do matter */ +#define SSL3_ST_SR_CLNT_HELLO_A (0x110|SSL_ST_ACCEPT) +#define SSL3_ST_SR_CLNT_HELLO_B (0x111|SSL_ST_ACCEPT) +#define SSL3_ST_SR_CLNT_HELLO_C (0x112|SSL_ST_ACCEPT) +/* write to client */ +#define DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A (0x113|SSL_ST_ACCEPT) +#define DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B (0x114|SSL_ST_ACCEPT) +#define SSL3_ST_SW_HELLO_REQ_A (0x120|SSL_ST_ACCEPT) +#define SSL3_ST_SW_HELLO_REQ_B (0x121|SSL_ST_ACCEPT) +#define SSL3_ST_SW_HELLO_REQ_C (0x122|SSL_ST_ACCEPT) +#define SSL3_ST_SW_SRVR_HELLO_A (0x130|SSL_ST_ACCEPT) +#define SSL3_ST_SW_SRVR_HELLO_B (0x131|SSL_ST_ACCEPT) +#define SSL3_ST_SW_CERT_A (0x140|SSL_ST_ACCEPT) +#define SSL3_ST_SW_CERT_B (0x141|SSL_ST_ACCEPT) +#define SSL3_ST_SW_KEY_EXCH_A (0x150|SSL_ST_ACCEPT) +#define SSL3_ST_SW_KEY_EXCH_B (0x151|SSL_ST_ACCEPT) +#define SSL3_ST_SW_CERT_REQ_A (0x160|SSL_ST_ACCEPT) +#define SSL3_ST_SW_CERT_REQ_B (0x161|SSL_ST_ACCEPT) +#define SSL3_ST_SW_SRVR_DONE_A (0x170|SSL_ST_ACCEPT) +#define SSL3_ST_SW_SRVR_DONE_B (0x171|SSL_ST_ACCEPT) +/* read from client */ +#define SSL3_ST_SR_CERT_A (0x180|SSL_ST_ACCEPT) +#define SSL3_ST_SR_CERT_B (0x181|SSL_ST_ACCEPT) +#define SSL3_ST_SR_KEY_EXCH_A (0x190|SSL_ST_ACCEPT) +#define SSL3_ST_SR_KEY_EXCH_B (0x191|SSL_ST_ACCEPT) +#define SSL3_ST_SR_CERT_VRFY_A (0x1A0|SSL_ST_ACCEPT) +#define SSL3_ST_SR_CERT_VRFY_B (0x1A1|SSL_ST_ACCEPT) +#define SSL3_ST_SR_CHANGE_A (0x1B0|SSL_ST_ACCEPT) +#define SSL3_ST_SR_CHANGE_B (0x1B1|SSL_ST_ACCEPT) +#ifndef OPENSSL_NO_NEXTPROTONEG +#define SSL3_ST_SR_NEXT_PROTO_A (0x210|SSL_ST_ACCEPT) +#define SSL3_ST_SR_NEXT_PROTO_B (0x211|SSL_ST_ACCEPT) +#endif +#define SSL3_ST_SR_FINISHED_A (0x1C0|SSL_ST_ACCEPT) +#define SSL3_ST_SR_FINISHED_B (0x1C1|SSL_ST_ACCEPT) +/* write to client */ +#define SSL3_ST_SW_CHANGE_A (0x1D0|SSL_ST_ACCEPT) +#define SSL3_ST_SW_CHANGE_B (0x1D1|SSL_ST_ACCEPT) +#define SSL3_ST_SW_FINISHED_A (0x1E0|SSL_ST_ACCEPT) +#define SSL3_ST_SW_FINISHED_B (0x1E1|SSL_ST_ACCEPT) +#define SSL3_ST_SW_SESSION_TICKET_A (0x1F0|SSL_ST_ACCEPT) +#define SSL3_ST_SW_SESSION_TICKET_B (0x1F1|SSL_ST_ACCEPT) +#define SSL3_ST_SW_CERT_STATUS_A (0x200|SSL_ST_ACCEPT) +#define SSL3_ST_SW_CERT_STATUS_B (0x201|SSL_ST_ACCEPT) + +#define SSL3_MT_HELLO_REQUEST 0 +#define SSL3_MT_CLIENT_HELLO 1 +#define SSL3_MT_SERVER_HELLO 2 +#define SSL3_MT_NEWSESSION_TICKET 4 +#define SSL3_MT_CERTIFICATE 11 +#define SSL3_MT_SERVER_KEY_EXCHANGE 12 +#define SSL3_MT_CERTIFICATE_REQUEST 13 +#define SSL3_MT_SERVER_DONE 14 +#define SSL3_MT_CERTIFICATE_VERIFY 15 +#define SSL3_MT_CLIENT_KEY_EXCHANGE 16 +#define SSL3_MT_FINISHED 20 +#define SSL3_MT_CERTIFICATE_STATUS 22 +#ifndef OPENSSL_NO_NEXTPROTONEG +#define SSL3_MT_NEXT_PROTO 67 +#endif +#define DTLS1_MT_HELLO_VERIFY_REQUEST 3 + + +#define SSL3_MT_CCS 1 + +/* These are used when changing over to a new cipher */ +#define SSL3_CC_READ 0x01 +#define SSL3_CC_WRITE 0x02 +#define SSL3_CC_CLIENT 0x10 +#define SSL3_CC_SERVER 0x20 +#define SSL3_CHANGE_CIPHER_CLIENT_WRITE (SSL3_CC_CLIENT|SSL3_CC_WRITE) +#define SSL3_CHANGE_CIPHER_SERVER_READ (SSL3_CC_SERVER|SSL3_CC_READ) +#define SSL3_CHANGE_CIPHER_CLIENT_READ (SSL3_CC_CLIENT|SSL3_CC_READ) +#define SSL3_CHANGE_CIPHER_SERVER_WRITE (SSL3_CC_SERVER|SSL3_CC_WRITE) + +#ifdef __cplusplus +} +#endif +#endif diff --git a/app/openssl/ssl/ssl_algs.c b/app/openssl/ssl/ssl_algs.c new file mode 100644 index 00000000..0967b2df --- /dev/null +++ b/app/openssl/ssl/ssl_algs.c @@ -0,0 +1,140 @@ +/* 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()); +#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()); +#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/app/openssl/ssl/ssl_asn1.c b/app/openssl/ssl/ssl_asn1.c new file mode 100644 index 00000000..d7f4c608 --- /dev/null +++ b/app/openssl/ssl/ssl_asn1.c @@ -0,0 +1,592 @@ +/* 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 */ + } 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 + 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 */ + + 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 */ + + 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 + 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; + 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; + goto err; + } + id=0x03000000L| + ((unsigned long)os.data[0]<<8L)| + (unsigned long)os.data[1]; + } + else + { + c.error=SSL_R_UNKNOWN_SSL_VERSION; + 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; + 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; +#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 + + M_ASN1_D2I_Finish(a,SSL_SESSION_free,SSL_F_D2I_SSL_SESSION); + } diff --git a/app/openssl/ssl/ssl_cert.c b/app/openssl/ssl/ssl_cert.c new file mode 100644 index 00000000..27256eea --- /dev/null +++ b/app/openssl/ssl/ssl_cert.c @@ -0,0 +1,834 @@ +/*! \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; + } + +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; + + 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; + + 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/app/openssl/ssl/ssl_ciph.c b/app/openssl/ssl/ssl_ciph.c new file mode 100644 index 00000000..e523a8f2 --- /dev/null +++ b/app/openssl/ssl/ssl_ciph.c @@ -0,0 +1,1792 @@ +/* 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_NUM_IDX 12 + + +static const EVP_CIPHER *ssl_cipher_methods[SSL_ENC_NUM_IDX]={ + 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 +/*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 + }; +/* 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 + }; + +static int ssl_mac_secret_size[SSL_MD_NUM_IDX]={ + 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 + }; + +#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_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}, + + + /* 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,0,0,0,0,0,0}, + {0,SSL_TXT_AES256,0, 0,0,SSL_AES256,0,0,0,0,0,0}, + {0,SSL_TXT_AES,0, 0,0,SSL_AES128|SSL_AES256,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}, + + /* 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}, + + /* 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_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; + } + + } +#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); + } + } + } + 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; + 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_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; + + } + 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) && (!mac_pkey_type||*mac_pkey_type != NID_undef)) + 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; + } + if (ssl_handshake_digest_flag[idx]==0) return 0; + *mask = ssl_handshake_digest_flag[idx]; + *md = ssl_digest_methods[idx]; + 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 + /* 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_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_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 && + !(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 == '-')) +#else + while ( isalnum(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) + { + if (curr->active) + { + 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 + 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; + 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_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; + 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); + } + +/* return string version of key exchange algorithm */ +const char* SSL_CIPHER_authentication_method(const SSL_CIPHER* cipher) + { + switch (cipher->algorithm_mkey) + { + case SSL_kRSA: + return SSL_TXT_RSA; + case SSL_kDHr: + return SSL_TXT_DH "_" SSL_TXT_RSA; + case SSL_kDHd: + return SSL_TXT_DH "_" SSL_TXT_DSS; + case SSL_kEDH: + switch (cipher->algorithm_auth) + { + case SSL_aDSS: + return "DHE_" SSL_TXT_DSS; + case SSL_aRSA: + return "DHE_" SSL_TXT_RSA; + case SSL_aNULL: + return SSL_TXT_DH "_anon"; + default: + return "UNKNOWN"; + } + case SSL_kKRB5: + return SSL_TXT_KRB5; + case SSL_kECDHr: + return SSL_TXT_ECDH "_" SSL_TXT_RSA; + case SSL_kECDHe: + return SSL_TXT_ECDH "_" SSL_TXT_ECDSA; + case SSL_kEECDH: + switch (cipher->algorithm_auth) + { + case SSL_aECDSA: + return "ECDHE_" SSL_TXT_ECDSA; + case SSL_aRSA: + return "ECDHE_" SSL_TXT_RSA; + case SSL_aNULL: + return SSL_TXT_ECDH "_anon"; + default: + return "UNKNOWN"; + } + default: + return "UNKNOWN"; + } + } + +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/app/openssl/ssl/ssl_err.c b/app/openssl/ssl/ssl_err.c new file mode 100644 index 00000000..8bff5905 --- /dev/null +++ b/app/openssl/ssl/ssl_err.c @@ -0,0 +1,575 @@ +/* ssl/ssl_err.c */ +/* ==================================================================== + * Copyright (c) 1999-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). + * + */ + +/* 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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_SESSION_MAY_NOT_BE_CREATED),"session may not be created"}, +{ERR_REASON(SSL_R_SHORT_READ) ,"short read"}, +{ERR_REASON(SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE),"signature for non signing certificate"}, +{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_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_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_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_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/app/openssl/ssl/ssl_err2.c b/app/openssl/ssl/ssl_err2.c new file mode 100644 index 00000000..ea95a5f9 --- /dev/null +++ b/app/openssl/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/app/openssl/ssl/ssl_lib.c b/app/openssl/ssl/ssl_lib.c new file mode 100644 index 00000000..b169ba93 --- /dev/null +++ b/app/openssl/ssl/ssl_lib.c @@ -0,0 +1,3242 @@ +/*! \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_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->new_session) return(1); +#else + if (s->new_session) + { + 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->session_creation_enabled=1; + 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 + + 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->new_session == 0) + { + s->new_session=1; + } + 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->new_session != 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: + 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; + } + +/** specify the ciphers to be used by the SSL */ +int SSL_set_cipher_lists(SSL *s,STACK_OF(SSL_CIPHER) *sk) + { + STACK_OF(SSL_CIPHER) *tmp_cipher_list; + + if (sk == NULL) + return 0; + + /* Based on end of ssl_create_cipher_list */ + tmp_cipher_list = sk_SSL_CIPHER_dup(sk); + if (tmp_cipher_list == NULL) + { + return 0; + } + if (s->cipher_list != NULL) + sk_SSL_CIPHER_free(s->cipher_list); + s->cipher_list = sk; + if (s->cipher_list_by_id != NULL) + sk_SSL_CIPHER_free(s->cipher_list_by_id); + s->cipher_list_by_id = tmp_cipher_list; + (void)sk_SSL_CIPHER_set_cmp_func(s->cipher_list_by_id,ssl_cipher_ptr_id_cmp); + + sk_SSL_CIPHER_sort(s->cipher_list_by_id); + 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; + 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); +#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->new_session) + { + 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->new_session) + { + 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 + +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); + } + + 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; + 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_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_PSK + if (a->psk_identity_hint) + OPENSSL_free(a->psk_identity_hint); +#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, const SSL_CIPHER *cs) + { + unsigned long alg_k, alg_a; + EVP_PKEY *pkey = NULL; + int keysize = 0; + int signature_nid = 0, md_nid = 0, pk_nid = 0; + + 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) + { + /* 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) + { + /* 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 */ +X509 *ssl_get_server_send_cert(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_CERT,ERR_R_INTERNAL_ERROR); + return(NULL); + } + if (c->pkeys[i].x509 == NULL) return(NULL); + + return(c->pkeys[i].x509); + } + +EVP_PKEY *ssl_get_sign_pkey(SSL *s,const SSL_CIPHER *cipher) + { + unsigned long alg_a; + CERT *c; + + alg_a = cipher->algorithm_auth; + c=s->cert; + + if ((alg_a & SSL_aDSS) && + (c->pkeys[SSL_PKEY_DSA_SIGN].privatekey != NULL)) + return(c->pkeys[SSL_PKEY_DSA_SIGN].privatekey); + else if (alg_a & SSL_aRSA) + { + if (c->pkeys[SSL_PKEY_RSA_SIGN].privatekey != NULL) + return(c->pkeys[SSL_PKEY_RSA_SIGN].privatekey); + else if (c->pkeys[SSL_PKEY_RSA_ENC].privatekey != NULL) + return(c->pkeys[SSL_PKEY_RSA_ENC].privatekey); + else + return(NULL); + } + else if ((alg_a & SSL_aECDSA) && + (c->pkeys[SSL_PKEY_ECC].privatekey != NULL)) + return(c->pkeys[SSL_PKEY_ECC].privatekey); + else /* if (alg_a & SSL_aNULL) */ + { + SSLerr(SSL_F_SSL_GET_SIGN_PKEY,ERR_R_INTERNAL_ERROR); + return(NULL); + } + } + +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); + } + +static const char *ssl_get_version(int version) + { + if (version == TLS1_VERSION) + return("TLSv1"); + else if (version == SSL3_VERSION) + return("SSLv3"); + else if (version == SSL2_VERSION) + return("SSLv2"); + else + return("unknown"); + } + +const char *SSL_get_version(const SSL *s) + { + return ssl_get_version(s->version); + } + +const char *SSL_SESSION_get_version(const SSL_SESSION *s) + { + return ssl_get_version(s->ssl_version); + } + +const char* SSL_authentication_method(const SSL* ssl) + { + if (ssl->cert != NULL && ssl->cert->rsa_tmp != NULL) + return SSL_TXT_RSA "_" SSL_TXT_EXPORT; + switch (ssl->version) + { + case SSL2_VERSION: + return SSL_TXT_RSA; + case SSL3_VERSION: + case TLS1_VERSION: + case DTLS1_VERSION: + return SSL_CIPHER_authentication_method(ssl->s3->tmp.new_cipher); + default: + 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->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_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); + } + +int SSL_cutthrough_complete(const SSL *s) + { + return (!s->server && /* cutthrough only applies to clients */ + !s->hit && /* full-handshake */ + s->version >= SSL3_VERSION && + s->s3->in_read_app_data == 0 && /* cutthrough only applies to write() */ + (SSL_get_mode((SSL*)s) & SSL_MODE_HANDSHAKE_CUTTHROUGH) && /* cutthrough enabled */ + SSL_get_cipher_bits(s, NULL) >= 128 && /* strong cipher choosen */ + s->s3->previous_server_finished_len == 0 && /* not a renegotiation handshake */ + (s->state == SSL3_ST_CR_SESSION_TICKET_A || /* ready to write app-data*/ + s->state == SSL3_ST_CR_FINISHED_A)); + } + +/* 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; +} + +#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/app/openssl/ssl/ssl_locl.h b/app/openssl/ssl/ssl_locl.h new file mode 100644 index 00000000..25f8e16c --- /dev/null +++ b/app/openssl/ssl/ssl_locl.h @@ -0,0 +1,1085 @@ +/* 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 + +#define 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 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 */ + +/* 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_AES (SSL_AES128|SSL_AES256) +#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 + +/* Bits for algorithm_ssl (protocol version) */ +#define SSL_SSLV2 0x00000001L +#define SSL_SSLV3 0x00000002L +#define SSL_TLSV1 SSL_SSLV3 /* for now */ + + +/* 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_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 4 + +#define TLS1_PRF_DGST_SHIFT 8 +#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_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; + STACK_OF(X509) *cert_chain; + EVP_PKEY *privatekey; + } 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); + } 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 IMPLEMENT_tls1_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_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_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, \ + ssl3_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); +X509 *ssl_get_server_send_cert(SSL *); +EVP_PKEY *ssl_get_sign_pkey(SSL *,const SSL_CIPHER *); +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 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_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); + +/* 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); + +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_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, const SSL_CIPHER *cs); +#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(SSL *s); +int ssl_check_serverhello_tlsext(SSL *s); + +#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); +#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); +#endif diff --git a/app/openssl/ssl/ssl_rsa.c b/app/openssl/ssl/ssl_rsa.c new file mode 100644 index 00000000..c43f3e2a --- /dev/null +++ b/app/openssl/ssl/ssl_rsa.c @@ -0,0 +1,815 @@ +/* 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); + } + + +int SSL_use_certificate_chain(SSL *ssl, STACK_OF(X509) *cert_chain) + { + if (ssl == NULL) + { + SSLerr(SSL_F_SSL_USE_CERTIFICATE_CHAIN,ERR_R_PASSED_NULL_PARAMETER); + return(0); + } + if (ssl->cert == NULL) + { + SSLerr(SSL_F_SSL_USE_CERTIFICATE_CHAIN,SSL_R_NO_CERTIFICATE_ASSIGNED); + return(0); + } + if (ssl->cert->key == NULL) + { + SSLerr(SSL_F_SSL_USE_CERTIFICATE_CHAIN,SSL_R_NO_CERTIFICATE_ASSIGNED); + return(0); + } + ssl->cert->key->cert_chain = cert_chain; + return(1); + } + +STACK_OF(X509) *SSL_get_certificate_chain(SSL *ssl, X509 *x) + { + int i; + if (x == NULL) + return NULL; + if (ssl == NULL) + return NULL; + if (ssl->cert == NULL) + return NULL; + for (i = 0; i < SSL_PKEY_NUM; i++) + if (ssl->cert->pkeys[i].x509 == x) + return ssl->cert->pkeys[i].cert_chain; + return NULL; + } + +#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/app/openssl/ssl/ssl_sess.c b/app/openssl/ssl/ssl_sess.c new file mode 100644 index 00000000..93954e48 --- /dev/null +++ b/app/openssl/ssl/ssl_sess.c @@ -0,0 +1,1102 @@ +/* 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 + 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; + } + +/* 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; +} + +void SSL_set_session_creation_enabled (SSL *s, int creation_enabled) + { + s->session_creation_enabled = creation_enabled; + } + +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; + + /* caller should check this if they can do better error handling */ + if (!s->session_creation_enabled) return(0); + 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 == 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); + } + +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; +#ifndef OPENSSL_NO_TLSEXT + int r; +#endif + + if (len > SSL_MAX_SSL_SESSION_ID_LENGTH) + goto err; +#ifndef OPENSSL_NO_TLSEXT + r = tls1_process_ticket(s, session_id, len, limit, &ret); + if (r == -1) + { + fatal = 1; + goto err; + } + else if (r == 0 || (!ret && !len)) + goto err; + else if (!ret && !(s->session_ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)) +#else + if (len == 0) + goto err; + if (!(s->session_ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)) +#endif + { + 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) + { + int copy=1; + + s->session_ctx->stats.sess_miss++; + ret=NULL; + if (s->session_ctx->get_session_cb != NULL + && (ret=s->session_ctx->get_session_cb(s,session_id,len,©)) + != NULL) + { + 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've found the session named by the client, but we don't + * want to use it in this context. */ + +#if 0 /* The client cannot always know when a session is not appropriate, + * so we shouldn't generate an error message. */ + + SSLerr(SSL_F_SSL_GET_PREV_SESSION,SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT); +#endif + 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 0 /* This is way too late. */ + + /* If a thread got the session, then 'swaped', and another got + * it and then due to a time-out decided to 'OPENSSL_free' it we could + * be in trouble. So I'll increment it now, then double decrement + * later - am I speaking rubbish?. */ + CRYPTO_add(&ret->references,1,CRYPTO_LOCK_SSL_SESSION); +#endif + + if (ret->timeout < (long)(time(NULL) - ret->time)) /* timeout */ + { + s->session_ctx->stats.sess_timeout++; + /* remove it from the cache */ + SSL_CTX_remove_session(s->session_ctx,ret); + goto err; + } + + s->session_ctx->stats.sess_hit++; + + /* ret->time=time(NULL); */ /* rezero timeout? */ + /* again, just leave the session + * if it is the same session, we have just incremented and + * then decremented the reference count :-) */ + 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); + 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 + 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); + if (s->ctx->session_timeout == 0) + session->timeout=SSL_get_default_timeout(s); + else + session->timeout=s->ctx->session_timeout; + } + +#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); + } + +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/app/openssl/ssl/ssl_stat.c b/app/openssl/ssl/ssl_stat.c new file mode 100644 index 00000000..144b81e5 --- /dev/null +++ b/app/openssl/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/app/openssl/ssl/ssl_txt.c b/app/openssl/ssl/ssl_txt.c new file mode 100644 index 00000000..3122440e --- /dev/null +++ b/app/openssl/ssl/ssl_txt.c @@ -0,0 +1,240 @@ +/* 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_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_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/app/openssl/ssl/ssltest.c b/app/openssl/ssl/ssltest.c new file mode 100644 index 00000000..f6a2c79d --- /dev/null +++ b/app/openssl/ssl/ssltest.c @@ -0,0 +1,2503 @@ +/* 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 +#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 + +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"); + 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_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"); + fprintf(stderr," -c_small_records - enable client side use of small SSL record buffers\n"); + fprintf(stderr," -s_small_records - enable server side use of small SSL record buffers\n"); + fprintf(stderr," -cutthrough - enable 1-RTT full-handshake for strong ciphers\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 ssl_mode = 0; + int c_small_records=0; + int s_small_records=0; + int cutthrough = 0; + +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 + 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; +#endif + STACK_OF(SSL_COMP) *ssl_comp_methods = NULL; + int test_cipherlist = 0; + + 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,"-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 + } + 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 if (strcmp(*argv, "-c_small_records") == 0) + { + c_small_records = 1; + } + else if (strcmp(*argv, "-s_small_records") == 0) + { + s_small_records = 1; + } + else if (strcmp(*argv, "-cutthrough") == 0) + { + cutthrough = 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); + } + + 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 + meth=SSLv3_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); + } + + ssl_mode = 0; + if (c_small_records) + { + ssl_mode = SSL_CTX_get_mode(c_ctx); + ssl_mode |= SSL_MODE_SMALL_BUFFERS; + SSL_CTX_set_mode(c_ctx, ssl_mode); + } + ssl_mode = 0; + if (s_small_records) + { + ssl_mode = SSL_CTX_get_mode(s_ctx); + ssl_mode |= SSL_MODE_SMALL_BUFFERS; + SSL_CTX_set_mode(s_ctx, ssl_mode); + } + ssl_mode = 0; + if (cutthrough) + { + ssl_mode = SSL_CTX_get_mode(c_ctx); + ssl_mode = SSL_MODE_HANDSHAKE_CUTTHROUGH; + SSL_CTX_set_mode(c_ctx, ssl_mode); + } + +#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 + nid = NID_sect163r2; + + 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 + } + + 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 +# ifdef OPENSSL_FIPS + if(s->version == TLS1_VERSION) + FIPS_allow_md5(1); +# endif + ok = X509_verify_cert(ctx); +# ifdef OPENSSL_FIPS + if(s->version == TLS1_VERSION) + FIPS_allow_md5(0); +# endif +#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/app/openssl/ssl/t1_clnt.c b/app/openssl/ssl/t1_clnt.c new file mode 100644 index 00000000..c87af177 --- /dev/null +++ b/app/openssl/ssl/t1_clnt.c @@ -0,0 +1,79 @@ +/* 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_VERSION) + return(TLSv1_client_method()); + else + return(NULL); + } + +IMPLEMENT_tls1_meth_func(TLSv1_client_method, + ssl_undefined_function, + ssl3_connect, + tls1_get_client_method) + diff --git a/app/openssl/ssl/t1_enc.c b/app/openssl/ssl/t1_enc.c new file mode 100644 index 00000000..793ea43e --- /dev/null +++ b/app/openssl/ssl/t1_enc.c @@ -0,0 +1,1045 @@ +/* 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> +#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; + unsigned int j; + HMAC_CTX ctx; + HMAC_CTX ctx_tmp; + unsigned char A1[EVP_MAX_MD_SIZE]; + unsigned int A1_len; + int ret = 0; + + chunk=EVP_MD_size(md); + OPENSSL_assert(chunk >= 0); + + HMAC_CTX_init(&ctx); + HMAC_CTX_init(&ctx_tmp); + if (!HMAC_Init_ex(&ctx,sec,sec_len,md, NULL)) + goto err; + if (!HMAC_Init_ex(&ctx_tmp,sec,sec_len,md, NULL)) + goto err; + if (seed1 != NULL && !HMAC_Update(&ctx,seed1,seed1_len)) + goto err; + if (seed2 != NULL && !HMAC_Update(&ctx,seed2,seed2_len)) + goto err; + if (seed3 != NULL && !HMAC_Update(&ctx,seed3,seed3_len)) + goto err; + if (seed4 != NULL && !HMAC_Update(&ctx,seed4,seed4_len)) + goto err; + if (seed5 != NULL && !HMAC_Update(&ctx,seed5,seed5_len)) + goto err; + if (!HMAC_Final(&ctx,A1,&A1_len)) + goto err; + + for (;;) + { + if (!HMAC_Init_ex(&ctx,NULL,0,NULL,NULL)) /* re-init */ + goto err; + if (!HMAC_Init_ex(&ctx_tmp,NULL,0,NULL,NULL)) /* re-init */ + goto err; + if (!HMAC_Update(&ctx,A1,A1_len)) + goto err; + if (!HMAC_Update(&ctx_tmp,A1,A1_len)) + goto err; + if (seed1 != NULL && !HMAC_Update(&ctx,seed1,seed1_len)) + goto err; + if (seed2 != NULL && !HMAC_Update(&ctx,seed2,seed2_len)) + goto err; + if (seed3 != NULL && !HMAC_Update(&ctx,seed3,seed3_len)) + goto err; + if (seed4 != NULL && !HMAC_Update(&ctx,seed4,seed4_len)) + goto err; + if (seed5 != NULL && !HMAC_Update(&ctx,seed5,seed5_len)) + goto err; + + if (olen > chunk) + { + if (!HMAC_Final(&ctx,out,&j)) + goto err; + out+=j; + olen-=j; + if (!HMAC_Final(&ctx_tmp,A1,&A1_len)) /* calc the next A1 value */ + goto err; + } + else /* last one */ + { + if (!HMAC_Final(&ctx,A1,&A1_len)) + goto err; + memcpy(out,A1,olen); + break; + } + } + ret = 1; +err: + HMAC_CTX_cleanup(&ctx); + HMAC_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; + 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(s->s3->tmp.new_cipher->algorithm2, + 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", 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) + 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; + 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); */ + 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); + 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(s->s3->tmp.new_cipher->algorithm2, + 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(s->s3->tmp.new_cipher->algorithm2, + 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 */ + + EVP_CipherInit_ex(dd,c,NULL,key,iv,(which & SSL3_CC_WRITE)); +#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)) + { + /* 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); + } + +int tls1_enc(SSL *s, int send) + { + SSL3_RECORD *rec; + EVP_CIPHER_CTX *ds; + unsigned long l; + int bs,i,ii,j,k,n=0; + const EVP_CIPHER *enc; + + if (send) + { + if (EVP_MD_CTX_md(s->write_hash)) + { + 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 + enc=EVP_CIPHER_CTX_cipher(s->enc_write_ctx); + } + else + { + if (EVP_MD_CTX_md(s->read_hash)) + { + 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; + } + 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) + { + SSLerr(SSL_F_TLS1_ENC,SSL_R_BLOCK_CIPHER_PAD_IS_WRONG); + ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECRYPTION_FAILED); + 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) + { + ii=i=rec->data[l-1]; /* padding_length */ + i++; + /* 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) && !(ii & 1)) + s->s3->flags|=TLS1_FLAGS_TLS_PADDING_BUG; + if (s->s3->flags & TLS1_FLAGS_TLS_PADDING_BUG) + i--; + } + /* TLS 1.0 does not bound the number of padding bytes by the block size. + * All of them must have value 'padding_length'. */ + if (i > (int)rec->length) + { + /* Incorrect padding. SSLerr() and ssl3_alert are done + * by caller: we don't want to reveal whether this is + * a decryption error or a MAC verification failure + * (see http://www.openssl.org/~bodo/tls-cbc.txt) */ + return -1; + } + for (j=(int)(l-i); j<(int)l; j++) + { + if (rec->data[j] != ii) + { + /* Incorrect padding */ + return -1; + } + } + rec->length-=i; + } + } + return(1); + } +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 & s->s3->tmp.new_cipher->algorithm2) + { + int hashsize = EVP_MD_size(md); + if (hashsize < 0 || hashsize > (int)(sizeof buf - (size_t)(q-buf))) + { + /* internal error: 'buf' is too small for this cipersuite! */ + err = 1; + } + else + { + EVP_MD_CTX_copy_ex(&ctx,s->s3->handshake_dgst[idx]); + EVP_DigestFinal_ex(&ctx,q,&i); + if (i != (unsigned int)hashsize) /* can't really happen */ + err = 1; + q+=i; + } + } + } + + if (!tls1_PRF(s->s3->tmp.new_cipher->algorithm2, + 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; + int i; + EVP_MD_CTX hmac, *mac_ctx; + unsigned char buf[5]; + 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; + + buf[0]=rec->type; + buf[1]=(unsigned char)(ssl->version>>8); + buf[2]=(unsigned char)(ssl->version); + buf[3]=rec->length>>8; + buf[4]=rec->length&0xff; + + /* I should fix this up TLS TLS TLS TLS TLS XXXXXXXX */ + if (stream_mac) + { + mac_ctx = hash; + } + else + { + EVP_MD_CTX_copy(&hmac,hash); + 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); + + EVP_DigestSignUpdate(mac_ctx,dtlsseq,8); + } + else + EVP_DigestSignUpdate(mac_ctx,seq,8); + + EVP_DigestSignUpdate(mac_ctx,buf,5); + EVP_DigestSignUpdate(mac_ctx,rec->input,rec->length); + t=EVP_DigestSignFinal(mac_ctx,md,&md_size); + OPENSSL_assert(t > 0); + + if (!stream_mac) EVP_MD_CTX_cleanup(&hmac); +#ifdef TLS_DEBUG +printf("sec="); +{unsigned int z; for (z=0; z<md_size; z++) printf("%02X ",mac_sec[z]); printf("\n"); } +printf("seq="); +{int z; for (z=0; z<8; z++) printf("%02X ",seq[z]); printf("\n"); } +printf("buf="); +{int z; for (z=0; z<5; z++) printf("%02X ",buf[z]); printf("\n"); } +printf("rec="); +{unsigned int z; for (z=0; z<rec->length; z++) printf("%02X ",buf[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(s->s3->tmp.new_cipher->algorithm2, + 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 KSSL_DEBUG + printf ("tls1_generate_master_secret() complete\n"); +#endif /* KSSL_DEBUG */ + return(SSL3_MASTER_SECRET_SIZE); + } + +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/app/openssl/ssl/t1_lib.c b/app/openssl/ssl/t1_lib.c new file mode 100644 index 00000000..bbab4675 --- /dev/null +++ b/app/openssl/ssl/t1_lib.c @@ -0,0 +1,1859 @@ +/* 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 "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, + }; + +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=TLS1_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) */ + }; + +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 +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->new_session) + { + 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_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: + +#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_NEXTPROTONEG + if (s->ctx->next_proto_select_cb && !s->s3->tmp.finish_md_len) + { + /* The client advertises an emtpy extension to indicate its + * support for Next Protocol Negotiation */ + if (limit - ret - 4 < 0) + return NULL; + s2n(TLSEXT_TYPE_next_proto_neg,ret); + s2n(0,ret); + } +#endif + + if ((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 + 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_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; + } + +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; + + s->servername_done = 0; + s->tlsext_status_type = -1; + + 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_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) + { + *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_status_request && + s->version != DTLS1_VERSION && s->ctx->tlsext_status_cb) + { + + 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) + { + 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_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 */ + data+=size; + } + + *p = data; + + ri_check: + + /* Need RI if renegotiating */ + + if (!renegotiate_seen && s->new_session && + !(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 int 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; + + 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) + { + *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) + { + 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; + } +#endif + else if (type == TLSEXT_TYPE_renegotiate) + { + if(!ssl_parse_serverhello_renegotiate_ext(s, data, size, al)) + return 0; + renegotiate_seen = 1; + } + 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(nid_list)/sizeof(nid_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 = 1, j = s->tlsext_ellipticcurvelist; (unsigned int)i <= + sizeof(nid_list)/sizeof(nid_list[0]); i++) + s2n(i,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(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); + + /* If status request then ask callback what to do. + * Note: this must be called after servername callbacks in case + * the certificate has changed. + */ + if ((s->tlsext_status_type != -1) && s->ctx && s->ctx->tlsext_status_cb) + { + int r; + 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; + +#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(). */ + + 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; + } + } + +#endif + 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; + + case SSL_TLSEXT_ERR_NOACK: + s->servername_done=0; + 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 client + * hello and other operations depend on the result we need to handle any TLS + * session ticket extension at the same time. + */ + +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; + + /* If tickets disabled behave as if no ticket present + * to permit stateful resumption. + */ + if (SSL_get_options(s) & SSL_OP_NO_TICKET) + return 1; + + if ((s->version <= SSL3_VERSION) || !limit) + return 1; + 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 1; + n2s(p, i); + while ((p + 4) <= limit) + { + unsigned short type, size; + n2s(p, type); + n2s(p, size); + if (p + size > limit) + return 1; + if (type == TLSEXT_TYPE_session_ticket) + { + /* If tickets disabled indicate cache miss which will + * trigger a full handshake + */ + if (SSL_get_options(s) & SSL_OP_NO_TICKET) + return 1; + /* If zero length note client will accept a ticket + * and indicate cache miss to trigger full handshake + */ + if (size == 0) + { + s->tlsext_ticket_expected = 1; + return 0; /* Cache miss */ + } + if (s->tls_session_secret_cb) + { + /* Indicate cache miss here and instead of + * generating the session from ticket now, + * trigger abbreviated handshake based on + * external mechanism to calculate the master + * secret later. */ + return 0; + } + return tls_decrypt_ticket(s, p, size, session_id, len, + ret); + } + p += size; + } + return 1; + } + +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) + goto tickerr; + /* 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) + goto tickerr; + if (rv == 2) + renew_ticket = 1; + } + else + { + /* Check key name matches */ + if (memcmp(etick, tctx->tlsext_tick_key_name, 16)) + goto tickerr; + 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 (memcmp(tick_hmac, etick + eticklen, mlen)) + goto tickerr; + /* 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) + goto tickerr; + 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; + s->tlsext_ticket_expected = renew_ticket; + return 1; + } + /* If session decrypt failure indicate a cache miss and set state to + * send a new ticket + */ + tickerr: + s->tlsext_ticket_expected = 1; + return 0; + } + +#endif diff --git a/app/openssl/ssl/t1_meth.c b/app/openssl/ssl/t1_meth.c new file mode 100644 index 00000000..6ce7c0bb --- /dev/null +++ b/app/openssl/ssl/t1_meth.c @@ -0,0 +1,76 @@ +/* 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); +static const SSL_METHOD *tls1_get_method(int ver) + { + if (ver == TLS1_VERSION) + return(TLSv1_method()); + else + return(NULL); + } + +IMPLEMENT_tls1_meth_func(TLSv1_method, + ssl3_accept, + ssl3_connect, + tls1_get_method) + diff --git a/app/openssl/ssl/t1_reneg.c b/app/openssl/ssl/t1_reneg.c new file mode 100644 index 00000000..9c2cc3c7 --- /dev/null +++ b/app/openssl/ssl/t1_reneg.c @@ -0,0 +1,292 @@ +/* ssl/t1_reneg.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2009 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +#include <stdio.h> +#include <openssl/objects.h> +#include "ssl_locl.h" + +/* Add the client's renegotiation binding */ +int ssl_add_clienthello_renegotiate_ext(SSL *s, unsigned char *p, int *len, + int maxlen) + { + if(p) + { + if((s->s3->previous_client_finished_len+1) > maxlen) + { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATE_EXT_TOO_LONG); + return 0; + } + + /* Length byte */ + *p = s->s3->previous_client_finished_len; + p++; + + memcpy(p, s->s3->previous_client_finished, + s->s3->previous_client_finished_len); +#ifdef OPENSSL_RI_DEBUG + fprintf(stderr, "%s RI extension sent by client\n", + s->s3->previous_client_finished_len ? "Non-empty" : "Empty"); +#endif + } + + *len=s->s3->previous_client_finished_len + 1; + + + return 1; + } + +/* Parse the client's renegotiation binding and abort if it's not + right */ +int ssl_parse_clienthello_renegotiate_ext(SSL *s, unsigned char *d, int len, + int *al) + { + int ilen; + + /* Parse the length byte */ + if(len < 1) + { + SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_ENCODING_ERR); + *al=SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + ilen = *d; + d++; + + /* Consistency check */ + if((ilen+1) != len) + { + SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_ENCODING_ERR); + *al=SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + + /* Check that the extension matches */ + if(ilen != s->s3->previous_client_finished_len) + { + SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_MISMATCH); + *al=SSL_AD_HANDSHAKE_FAILURE; + return 0; + } + + if(memcmp(d, s->s3->previous_client_finished, + s->s3->previous_client_finished_len)) + { + SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_MISMATCH); + *al=SSL_AD_HANDSHAKE_FAILURE; + return 0; + } +#ifdef OPENSSL_RI_DEBUG + fprintf(stderr, "%s RI extension received by server\n", + ilen ? "Non-empty" : "Empty"); +#endif + + s->s3->send_connection_binding=1; + + return 1; + } + +/* Add the server's renegotiation binding */ +int ssl_add_serverhello_renegotiate_ext(SSL *s, unsigned char *p, int *len, + int maxlen) + { + if(p) + { + if((s->s3->previous_client_finished_len + + s->s3->previous_server_finished_len + 1) > maxlen) + { + SSLerr(SSL_F_SSL_ADD_SERVERHELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATE_EXT_TOO_LONG); + return 0; + } + + /* Length byte */ + *p = s->s3->previous_client_finished_len + s->s3->previous_server_finished_len; + p++; + + memcpy(p, s->s3->previous_client_finished, + s->s3->previous_client_finished_len); + p += s->s3->previous_client_finished_len; + + memcpy(p, s->s3->previous_server_finished, + s->s3->previous_server_finished_len); +#ifdef OPENSSL_RI_DEBUG + fprintf(stderr, "%s RI extension sent by server\n", + s->s3->previous_client_finished_len ? "Non-empty" : "Empty"); +#endif + } + + *len=s->s3->previous_client_finished_len + + s->s3->previous_server_finished_len + 1; + + return 1; + } + +/* Parse the server's renegotiation binding and abort if it's not + right */ +int ssl_parse_serverhello_renegotiate_ext(SSL *s, unsigned char *d, int len, + int *al) + { + int expected_len=s->s3->previous_client_finished_len + + s->s3->previous_server_finished_len; + int ilen; + + /* Check for logic errors */ + OPENSSL_assert(!expected_len || s->s3->previous_client_finished_len); + OPENSSL_assert(!expected_len || s->s3->previous_server_finished_len); + + /* Parse the length byte */ + if(len < 1) + { + SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_ENCODING_ERR); + *al=SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + ilen = *d; + d++; + + /* Consistency check */ + if(ilen+1 != len) + { + SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_ENCODING_ERR); + *al=SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + + /* Check that the extension matches */ + if(ilen != expected_len) + { + SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_MISMATCH); + *al=SSL_AD_HANDSHAKE_FAILURE; + return 0; + } + + if(memcmp(d, s->s3->previous_client_finished, + s->s3->previous_client_finished_len)) + { + SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_MISMATCH); + *al=SSL_AD_HANDSHAKE_FAILURE; + return 0; + } + d += s->s3->previous_client_finished_len; + + if(memcmp(d, s->s3->previous_server_finished, + s->s3->previous_server_finished_len)) + { + SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT,SSL_R_RENEGOTIATION_MISMATCH); + *al=SSL_AD_ILLEGAL_PARAMETER; + return 0; + } +#ifdef OPENSSL_RI_DEBUG + fprintf(stderr, "%s RI extension received by client\n", + ilen ? "Non-empty" : "Empty"); +#endif + s->s3->send_connection_binding=1; + + return 1; + } diff --git a/app/openssl/ssl/t1_srvr.c b/app/openssl/ssl/t1_srvr.c new file mode 100644 index 00000000..42525e9e --- /dev/null +++ b/app/openssl/ssl/t1_srvr.c @@ -0,0 +1,80 @@ +/* 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_VERSION) + return(TLSv1_server_method()); + else + return(NULL); + } + +IMPLEMENT_tls1_meth_func(TLSv1_server_method, + ssl3_accept, + ssl_undefined_function, + tls1_get_server_method) + diff --git a/app/openssl/ssl/tls1.h b/app/openssl/ssl/tls1.h new file mode 100644 index 00000000..76f368ac --- /dev/null +++ b/app/openssl/ssl/tls1.h @@ -0,0 +1,537 @@ +/* ssl/tls1.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-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 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. + */ + +#ifndef HEADER_TLS1_H +#define HEADER_TLS1_H + +#include <openssl/buffer.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES 0 + +#define TLS1_VERSION 0x0301 +#define TLS1_VERSION_MAJOR 0x03 +#define TLS1_VERSION_MINOR 0x01 + +#define TLS1_AD_DECRYPTION_FAILED 21 +#define TLS1_AD_RECORD_OVERFLOW 22 +#define TLS1_AD_UNKNOWN_CA 48 /* fatal */ +#define TLS1_AD_ACCESS_DENIED 49 /* fatal */ +#define TLS1_AD_DECODE_ERROR 50 /* fatal */ +#define TLS1_AD_DECRYPT_ERROR 51 +#define TLS1_AD_EXPORT_RESTRICTION 60 /* fatal */ +#define TLS1_AD_PROTOCOL_VERSION 70 /* fatal */ +#define TLS1_AD_INSUFFICIENT_SECURITY 71 /* fatal */ +#define TLS1_AD_INTERNAL_ERROR 80 /* fatal */ +#define TLS1_AD_USER_CANCELLED 90 +#define TLS1_AD_NO_RENEGOTIATION 100 +/* codes 110-114 are from RFC3546 */ +#define TLS1_AD_UNSUPPORTED_EXTENSION 110 +#define TLS1_AD_CERTIFICATE_UNOBTAINABLE 111 +#define TLS1_AD_UNRECOGNIZED_NAME 112 +#define TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE 113 +#define TLS1_AD_BAD_CERTIFICATE_HASH_VALUE 114 +#define TLS1_AD_UNKNOWN_PSK_IDENTITY 115 /* fatal */ + +/* ExtensionType values from RFC3546 / RFC4366 */ +#define TLSEXT_TYPE_server_name 0 +#define TLSEXT_TYPE_max_fragment_length 1 +#define TLSEXT_TYPE_client_certificate_url 2 +#define TLSEXT_TYPE_trusted_ca_keys 3 +#define TLSEXT_TYPE_truncated_hmac 4 +#define TLSEXT_TYPE_status_request 5 +/* ExtensionType values from RFC4492 */ +#define TLSEXT_TYPE_elliptic_curves 10 +#define TLSEXT_TYPE_ec_point_formats 11 +#define TLSEXT_TYPE_session_ticket 35 +/* ExtensionType value from draft-rescorla-tls-opaque-prf-input-00.txt */ +#if 0 /* will have to be provided externally for now , + * i.e. build with -DTLSEXT_TYPE_opaque_prf_input=38183 + * using whatever extension number you'd like to try */ +# define TLSEXT_TYPE_opaque_prf_input ?? */ +#endif + +/* Temporary extension type */ +#define TLSEXT_TYPE_renegotiate 0xff01 + +#ifndef OPENSSL_NO_NEXTPROTONEG +/* This is not an IANA defined extension number */ +#define TLSEXT_TYPE_next_proto_neg 13172 +#endif + +/* NameType value from RFC 3546 */ +#define TLSEXT_NAMETYPE_host_name 0 +/* status request value from RFC 3546 */ +#define TLSEXT_STATUSTYPE_ocsp 1 + +/* ECPointFormat values from draft-ietf-tls-ecc-12 */ +#define TLSEXT_ECPOINTFORMAT_first 0 +#define TLSEXT_ECPOINTFORMAT_uncompressed 0 +#define TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime 1 +#define TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2 2 +#define TLSEXT_ECPOINTFORMAT_last 2 + +#ifndef OPENSSL_NO_TLSEXT + +#define TLSEXT_MAXLEN_host_name 255 + +const char *SSL_get_servername(const SSL *s, const int type) ; +int SSL_get_servername_type(const SSL *s) ; + +#define SSL_set_tlsext_host_name(s,name) \ +SSL_ctrl(s,SSL_CTRL_SET_TLSEXT_HOSTNAME,TLSEXT_NAMETYPE_host_name,(char *)name) + +#define SSL_set_tlsext_debug_callback(ssl, cb) \ +SSL_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_DEBUG_CB,(void (*)(void))cb) + +#define SSL_set_tlsext_debug_arg(ssl, arg) \ +SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_DEBUG_ARG,0, (void *)arg) + +#define SSL_set_tlsext_status_type(ssl, type) \ +SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE,type, NULL) + +#define SSL_get_tlsext_status_exts(ssl, arg) \ +SSL_ctrl(ssl,SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS,0, (void *)arg) + +#define SSL_set_tlsext_status_exts(ssl, arg) \ +SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS,0, (void *)arg) + +#define SSL_get_tlsext_status_ids(ssl, arg) \ +SSL_ctrl(ssl,SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS,0, (void *)arg) + +#define SSL_set_tlsext_status_ids(ssl, arg) \ +SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS,0, (void *)arg) + +#define SSL_get_tlsext_status_ocsp_resp(ssl, arg) \ +SSL_ctrl(ssl,SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP,0, (void *)arg) + +#define SSL_set_tlsext_status_ocsp_resp(ssl, arg, arglen) \ +SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP,arglen, (void *)arg) + +#define SSL_CTX_set_tlsext_servername_callback(ctx, cb) \ +SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_CB,(void (*)(void))cb) + +#define SSL_TLSEXT_ERR_OK 0 +#define SSL_TLSEXT_ERR_ALERT_WARNING 1 +#define SSL_TLSEXT_ERR_ALERT_FATAL 2 +#define SSL_TLSEXT_ERR_NOACK 3 + +#define SSL_CTX_set_tlsext_servername_arg(ctx, arg) \ +SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG,0, (void *)arg) + +#define SSL_CTX_get_tlsext_ticket_keys(ctx, keys, keylen) \ + SSL_CTX_ctrl((ctx),SSL_CTRL_GET_TLSEXT_TICKET_KEYS,(keylen),(keys)) +#define SSL_CTX_set_tlsext_ticket_keys(ctx, keys, keylen) \ + SSL_CTX_ctrl((ctx),SSL_CTRL_SET_TLSEXT_TICKET_KEYS,(keylen),(keys)) + +#define SSL_CTX_set_tlsext_status_cb(ssl, cb) \ +SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB,(void (*)(void))cb) + +#define SSL_CTX_set_tlsext_status_arg(ssl, arg) \ +SSL_CTX_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG,0, (void *)arg) + +#define SSL_set_tlsext_opaque_prf_input(s, src, len) \ +SSL_ctrl(s,SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT, len, src) +#define SSL_CTX_set_tlsext_opaque_prf_input_callback(ctx, cb) \ +SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB, (void (*)(void))cb) +#define SSL_CTX_set_tlsext_opaque_prf_input_callback_arg(ctx, arg) \ +SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB_ARG, 0, arg) + +#define SSL_CTX_set_tlsext_ticket_key_cb(ssl, cb) \ +SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB,(void (*)(void))cb) + +#endif + +/* PSK ciphersuites from 4279 */ +#define TLS1_CK_PSK_WITH_RC4_128_SHA 0x0300008A +#define TLS1_CK_PSK_WITH_3DES_EDE_CBC_SHA 0x0300008B +#define TLS1_CK_PSK_WITH_AES_128_CBC_SHA 0x0300008C +#define TLS1_CK_PSK_WITH_AES_256_CBC_SHA 0x0300008D + +/* Additional TLS ciphersuites from expired Internet Draft + * draft-ietf-tls-56-bit-ciphersuites-01.txt + * (available if TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES is defined, see + * s3_lib.c). We actually treat them like SSL 3.0 ciphers, which we probably + * shouldn't. Note that the first two are actually not in the IDs. */ +#define TLS1_CK_RSA_EXPORT1024_WITH_RC4_56_MD5 0x03000060 /* not in ID */ +#define TLS1_CK_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5 0x03000061 /* not in ID */ +#define TLS1_CK_RSA_EXPORT1024_WITH_DES_CBC_SHA 0x03000062 +#define TLS1_CK_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA 0x03000063 +#define TLS1_CK_RSA_EXPORT1024_WITH_RC4_56_SHA 0x03000064 +#define TLS1_CK_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA 0x03000065 +#define TLS1_CK_DHE_DSS_WITH_RC4_128_SHA 0x03000066 + +/* AES ciphersuites from RFC3268 */ + +#define TLS1_CK_RSA_WITH_AES_128_SHA 0x0300002F +#define TLS1_CK_DH_DSS_WITH_AES_128_SHA 0x03000030 +#define TLS1_CK_DH_RSA_WITH_AES_128_SHA 0x03000031 +#define TLS1_CK_DHE_DSS_WITH_AES_128_SHA 0x03000032 +#define TLS1_CK_DHE_RSA_WITH_AES_128_SHA 0x03000033 +#define TLS1_CK_ADH_WITH_AES_128_SHA 0x03000034 + +#define TLS1_CK_RSA_WITH_AES_256_SHA 0x03000035 +#define TLS1_CK_DH_DSS_WITH_AES_256_SHA 0x03000036 +#define TLS1_CK_DH_RSA_WITH_AES_256_SHA 0x03000037 +#define TLS1_CK_DHE_DSS_WITH_AES_256_SHA 0x03000038 +#define TLS1_CK_DHE_RSA_WITH_AES_256_SHA 0x03000039 +#define TLS1_CK_ADH_WITH_AES_256_SHA 0x0300003A + +/* Camellia ciphersuites from RFC4132 */ +#define TLS1_CK_RSA_WITH_CAMELLIA_128_CBC_SHA 0x03000041 +#define TLS1_CK_DH_DSS_WITH_CAMELLIA_128_CBC_SHA 0x03000042 +#define TLS1_CK_DH_RSA_WITH_CAMELLIA_128_CBC_SHA 0x03000043 +#define TLS1_CK_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA 0x03000044 +#define TLS1_CK_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA 0x03000045 +#define TLS1_CK_ADH_WITH_CAMELLIA_128_CBC_SHA 0x03000046 + +#define TLS1_CK_RSA_WITH_CAMELLIA_256_CBC_SHA 0x03000084 +#define TLS1_CK_DH_DSS_WITH_CAMELLIA_256_CBC_SHA 0x03000085 +#define TLS1_CK_DH_RSA_WITH_CAMELLIA_256_CBC_SHA 0x03000086 +#define TLS1_CK_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA 0x03000087 +#define TLS1_CK_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA 0x03000088 +#define TLS1_CK_ADH_WITH_CAMELLIA_256_CBC_SHA 0x03000089 + +/* SEED ciphersuites from RFC4162 */ +#define TLS1_CK_RSA_WITH_SEED_SHA 0x03000096 +#define TLS1_CK_DH_DSS_WITH_SEED_SHA 0x03000097 +#define TLS1_CK_DH_RSA_WITH_SEED_SHA 0x03000098 +#define TLS1_CK_DHE_DSS_WITH_SEED_SHA 0x03000099 +#define TLS1_CK_DHE_RSA_WITH_SEED_SHA 0x0300009A +#define TLS1_CK_ADH_WITH_SEED_SHA 0x0300009B + +/* ECC ciphersuites from draft-ietf-tls-ecc-12.txt with changes soon to be in draft 13 */ +#define TLS1_CK_ECDH_ECDSA_WITH_NULL_SHA 0x0300C001 +#define TLS1_CK_ECDH_ECDSA_WITH_RC4_128_SHA 0x0300C002 +#define TLS1_CK_ECDH_ECDSA_WITH_DES_192_CBC3_SHA 0x0300C003 +#define TLS1_CK_ECDH_ECDSA_WITH_AES_128_CBC_SHA 0x0300C004 +#define TLS1_CK_ECDH_ECDSA_WITH_AES_256_CBC_SHA 0x0300C005 + +#define TLS1_CK_ECDHE_ECDSA_WITH_NULL_SHA 0x0300C006 +#define TLS1_CK_ECDHE_ECDSA_WITH_RC4_128_SHA 0x0300C007 +#define TLS1_CK_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA 0x0300C008 +#define TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CBC_SHA 0x0300C009 +#define TLS1_CK_ECDHE_ECDSA_WITH_AES_256_CBC_SHA 0x0300C00A + +#define TLS1_CK_ECDH_RSA_WITH_NULL_SHA 0x0300C00B +#define TLS1_CK_ECDH_RSA_WITH_RC4_128_SHA 0x0300C00C +#define TLS1_CK_ECDH_RSA_WITH_DES_192_CBC3_SHA 0x0300C00D +#define TLS1_CK_ECDH_RSA_WITH_AES_128_CBC_SHA 0x0300C00E +#define TLS1_CK_ECDH_RSA_WITH_AES_256_CBC_SHA 0x0300C00F + +#define TLS1_CK_ECDHE_RSA_WITH_NULL_SHA 0x0300C010 +#define TLS1_CK_ECDHE_RSA_WITH_RC4_128_SHA 0x0300C011 +#define TLS1_CK_ECDHE_RSA_WITH_DES_192_CBC3_SHA 0x0300C012 +#define TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA 0x0300C013 +#define TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA 0x0300C014 + +#define TLS1_CK_ECDH_anon_WITH_NULL_SHA 0x0300C015 +#define TLS1_CK_ECDH_anon_WITH_RC4_128_SHA 0x0300C016 +#define TLS1_CK_ECDH_anon_WITH_DES_192_CBC3_SHA 0x0300C017 +#define TLS1_CK_ECDH_anon_WITH_AES_128_CBC_SHA 0x0300C018 +#define TLS1_CK_ECDH_anon_WITH_AES_256_CBC_SHA 0x0300C019 + +/* XXX + * Inconsistency alert: + * The OpenSSL names of ciphers with ephemeral DH here include the string + * "DHE", while elsewhere it has always been "EDH". + * (The alias for the list of all such ciphers also is "EDH".) + * The specifications speak of "EDH"; maybe we should allow both forms + * for everything. */ +#define TLS1_TXT_RSA_EXPORT1024_WITH_RC4_56_MD5 "EXP1024-RC4-MD5" +#define TLS1_TXT_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5 "EXP1024-RC2-CBC-MD5" +#define TLS1_TXT_RSA_EXPORT1024_WITH_DES_CBC_SHA "EXP1024-DES-CBC-SHA" +#define TLS1_TXT_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA "EXP1024-DHE-DSS-DES-CBC-SHA" +#define TLS1_TXT_RSA_EXPORT1024_WITH_RC4_56_SHA "EXP1024-RC4-SHA" +#define TLS1_TXT_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA "EXP1024-DHE-DSS-RC4-SHA" +#define TLS1_TXT_DHE_DSS_WITH_RC4_128_SHA "DHE-DSS-RC4-SHA" + +/* AES ciphersuites from RFC3268 */ +#define TLS1_TXT_RSA_WITH_AES_128_SHA "AES128-SHA" +#define TLS1_TXT_DH_DSS_WITH_AES_128_SHA "DH-DSS-AES128-SHA" +#define TLS1_TXT_DH_RSA_WITH_AES_128_SHA "DH-RSA-AES128-SHA" +#define TLS1_TXT_DHE_DSS_WITH_AES_128_SHA "DHE-DSS-AES128-SHA" +#define TLS1_TXT_DHE_RSA_WITH_AES_128_SHA "DHE-RSA-AES128-SHA" +#define TLS1_TXT_ADH_WITH_AES_128_SHA "ADH-AES128-SHA" + +#define TLS1_TXT_RSA_WITH_AES_256_SHA "AES256-SHA" +#define TLS1_TXT_DH_DSS_WITH_AES_256_SHA "DH-DSS-AES256-SHA" +#define TLS1_TXT_DH_RSA_WITH_AES_256_SHA "DH-RSA-AES256-SHA" +#define TLS1_TXT_DHE_DSS_WITH_AES_256_SHA "DHE-DSS-AES256-SHA" +#define TLS1_TXT_DHE_RSA_WITH_AES_256_SHA "DHE-RSA-AES256-SHA" +#define TLS1_TXT_ADH_WITH_AES_256_SHA "ADH-AES256-SHA" + +/* ECC ciphersuites from draft-ietf-tls-ecc-01.txt (Mar 15, 2001) */ +#define TLS1_TXT_ECDH_ECDSA_WITH_NULL_SHA "ECDH-ECDSA-NULL-SHA" +#define TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA "ECDH-ECDSA-RC4-SHA" +#define TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA "ECDH-ECDSA-DES-CBC3-SHA" +#define TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA "ECDH-ECDSA-AES128-SHA" +#define TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA "ECDH-ECDSA-AES256-SHA" + +#define TLS1_TXT_ECDHE_ECDSA_WITH_NULL_SHA "ECDHE-ECDSA-NULL-SHA" +#define TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA "ECDHE-ECDSA-RC4-SHA" +#define TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA "ECDHE-ECDSA-DES-CBC3-SHA" +#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA "ECDHE-ECDSA-AES128-SHA" +#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA "ECDHE-ECDSA-AES256-SHA" + +#define TLS1_TXT_ECDH_RSA_WITH_NULL_SHA "ECDH-RSA-NULL-SHA" +#define TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA "ECDH-RSA-RC4-SHA" +#define TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA "ECDH-RSA-DES-CBC3-SHA" +#define TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA "ECDH-RSA-AES128-SHA" +#define TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA "ECDH-RSA-AES256-SHA" + +#define TLS1_TXT_ECDHE_RSA_WITH_NULL_SHA "ECDHE-RSA-NULL-SHA" +#define TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA "ECDHE-RSA-RC4-SHA" +#define TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA "ECDHE-RSA-DES-CBC3-SHA" +#define TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA "ECDHE-RSA-AES128-SHA" +#define TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA "ECDHE-RSA-AES256-SHA" + +#define TLS1_TXT_ECDH_anon_WITH_NULL_SHA "AECDH-NULL-SHA" +#define TLS1_TXT_ECDH_anon_WITH_RC4_128_SHA "AECDH-RC4-SHA" +#define TLS1_TXT_ECDH_anon_WITH_DES_192_CBC3_SHA "AECDH-DES-CBC3-SHA" +#define TLS1_TXT_ECDH_anon_WITH_AES_128_CBC_SHA "AECDH-AES128-SHA" +#define TLS1_TXT_ECDH_anon_WITH_AES_256_CBC_SHA "AECDH-AES256-SHA" + +/* PSK ciphersuites from RFC 4279 */ +#define TLS1_TXT_PSK_WITH_RC4_128_SHA "PSK-RC4-SHA" +#define TLS1_TXT_PSK_WITH_3DES_EDE_CBC_SHA "PSK-3DES-EDE-CBC-SHA" +#define TLS1_TXT_PSK_WITH_AES_128_CBC_SHA "PSK-AES128-CBC-SHA" +#define TLS1_TXT_PSK_WITH_AES_256_CBC_SHA "PSK-AES256-CBC-SHA" + +/* Camellia ciphersuites from RFC4132 */ +#define TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA "CAMELLIA128-SHA" +#define TLS1_TXT_DH_DSS_WITH_CAMELLIA_128_CBC_SHA "DH-DSS-CAMELLIA128-SHA" +#define TLS1_TXT_DH_RSA_WITH_CAMELLIA_128_CBC_SHA "DH-RSA-CAMELLIA128-SHA" +#define TLS1_TXT_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA "DHE-DSS-CAMELLIA128-SHA" +#define TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA "DHE-RSA-CAMELLIA128-SHA" +#define TLS1_TXT_ADH_WITH_CAMELLIA_128_CBC_SHA "ADH-CAMELLIA128-SHA" + +#define TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA "CAMELLIA256-SHA" +#define TLS1_TXT_DH_DSS_WITH_CAMELLIA_256_CBC_SHA "DH-DSS-CAMELLIA256-SHA" +#define TLS1_TXT_DH_RSA_WITH_CAMELLIA_256_CBC_SHA "DH-RSA-CAMELLIA256-SHA" +#define TLS1_TXT_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA "DHE-DSS-CAMELLIA256-SHA" +#define TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA "DHE-RSA-CAMELLIA256-SHA" +#define TLS1_TXT_ADH_WITH_CAMELLIA_256_CBC_SHA "ADH-CAMELLIA256-SHA" + +/* SEED ciphersuites from RFC4162 */ +#define TLS1_TXT_RSA_WITH_SEED_SHA "SEED-SHA" +#define TLS1_TXT_DH_DSS_WITH_SEED_SHA "DH-DSS-SEED-SHA" +#define TLS1_TXT_DH_RSA_WITH_SEED_SHA "DH-RSA-SEED-SHA" +#define TLS1_TXT_DHE_DSS_WITH_SEED_SHA "DHE-DSS-SEED-SHA" +#define TLS1_TXT_DHE_RSA_WITH_SEED_SHA "DHE-RSA-SEED-SHA" +#define TLS1_TXT_ADH_WITH_SEED_SHA "ADH-SEED-SHA" + + +#define TLS_CT_RSA_SIGN 1 +#define TLS_CT_DSS_SIGN 2 +#define TLS_CT_RSA_FIXED_DH 3 +#define TLS_CT_DSS_FIXED_DH 4 +#define TLS_CT_ECDSA_SIGN 64 +#define TLS_CT_RSA_FIXED_ECDH 65 +#define TLS_CT_ECDSA_FIXED_ECDH 66 +#define TLS_CT_GOST94_SIGN 21 +#define TLS_CT_GOST01_SIGN 22 +/* when correcting this number, correct also SSL3_CT_NUMBER in ssl3.h (see + * comment there) */ +#define TLS_CT_NUMBER 9 + +#define TLS1_FINISH_MAC_LENGTH 12 + +#define TLS_MD_MAX_CONST_SIZE 20 +#define TLS_MD_CLIENT_FINISH_CONST "client finished" +#define TLS_MD_CLIENT_FINISH_CONST_SIZE 15 +#define TLS_MD_SERVER_FINISH_CONST "server finished" +#define TLS_MD_SERVER_FINISH_CONST_SIZE 15 +#define TLS_MD_SERVER_WRITE_KEY_CONST "server write key" +#define TLS_MD_SERVER_WRITE_KEY_CONST_SIZE 16 +#define TLS_MD_KEY_EXPANSION_CONST "key expansion" +#define TLS_MD_KEY_EXPANSION_CONST_SIZE 13 +#define TLS_MD_CLIENT_WRITE_KEY_CONST "client write key" +#define TLS_MD_CLIENT_WRITE_KEY_CONST_SIZE 16 +#define TLS_MD_SERVER_WRITE_KEY_CONST "server write key" +#define TLS_MD_SERVER_WRITE_KEY_CONST_SIZE 16 +#define TLS_MD_IV_BLOCK_CONST "IV block" +#define TLS_MD_IV_BLOCK_CONST_SIZE 8 +#define TLS_MD_MASTER_SECRET_CONST "master secret" +#define TLS_MD_MASTER_SECRET_CONST_SIZE 13 + +#ifdef CHARSET_EBCDIC +#undef TLS_MD_CLIENT_FINISH_CONST +#define TLS_MD_CLIENT_FINISH_CONST "\x63\x6c\x69\x65\x6e\x74\x20\x66\x69\x6e\x69\x73\x68\x65\x64" /*client finished*/ +#undef TLS_MD_SERVER_FINISH_CONST +#define TLS_MD_SERVER_FINISH_CONST "\x73\x65\x72\x76\x65\x72\x20\x66\x69\x6e\x69\x73\x68\x65\x64" /*server finished*/ +#undef TLS_MD_SERVER_WRITE_KEY_CONST +#define TLS_MD_SERVER_WRITE_KEY_CONST "\x73\x65\x72\x76\x65\x72\x20\x77\x72\x69\x74\x65\x20\x6b\x65\x79" /*server write key*/ +#undef TLS_MD_KEY_EXPANSION_CONST +#define TLS_MD_KEY_EXPANSION_CONST "\x6b\x65\x79\x20\x65\x78\x70\x61\x6e\x73\x69\x6f\x6e" /*key expansion*/ +#undef TLS_MD_CLIENT_WRITE_KEY_CONST +#define TLS_MD_CLIENT_WRITE_KEY_CONST "\x63\x6c\x69\x65\x6e\x74\x20\x77\x72\x69\x74\x65\x20\x6b\x65\x79" /*client write key*/ +#undef TLS_MD_SERVER_WRITE_KEY_CONST +#define TLS_MD_SERVER_WRITE_KEY_CONST "\x73\x65\x72\x76\x65\x72\x20\x77\x72\x69\x74\x65\x20\x6b\x65\x79" /*server write key*/ +#undef TLS_MD_IV_BLOCK_CONST +#define TLS_MD_IV_BLOCK_CONST "\x49\x56\x20\x62\x6c\x6f\x63\x6b" /*IV block*/ +#undef TLS_MD_MASTER_SECRET_CONST +#define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/ +#endif + +/* TLS Session Ticket extension struct */ +struct tls_session_ticket_ext_st + { + unsigned short length; + void *data; + }; + +#ifdef __cplusplus +} +#endif +#endif |