sl@0: /* ssl/s3_enc.c */ sl@0: /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) sl@0: * All rights reserved. sl@0: * sl@0: * This package is an SSL implementation written sl@0: * by Eric Young (eay@cryptsoft.com). sl@0: * The implementation was written so as to conform with Netscapes SSL. sl@0: * sl@0: * This library is free for commercial and non-commercial use as long as sl@0: * the following conditions are aheared to. The following conditions sl@0: * apply to all code found in this distribution, be it the RC4, RSA, sl@0: * lhash, DES, etc., code; not just the SSL code. The SSL documentation sl@0: * included with this distribution is covered by the same copyright terms sl@0: * except that the holder is Tim Hudson (tjh@cryptsoft.com). sl@0: * sl@0: * Copyright remains Eric Young's, and as such any Copyright notices in sl@0: * the code are not to be removed. sl@0: * If this package is used in a product, Eric Young should be given attribution sl@0: * as the author of the parts of the library used. sl@0: * This can be in the form of a textual message at program startup or sl@0: * in documentation (online or textual) provided with the package. sl@0: * sl@0: * Redistribution and use in source and binary forms, with or without sl@0: * modification, are permitted provided that the following conditions sl@0: * are met: sl@0: * 1. Redistributions of source code must retain the copyright sl@0: * notice, this list of conditions and the following disclaimer. sl@0: * 2. Redistributions in binary form must reproduce the above copyright sl@0: * notice, this list of conditions and the following disclaimer in the sl@0: * documentation and/or other materials provided with the distribution. sl@0: * 3. All advertising materials mentioning features or use of this software sl@0: * must display the following acknowledgement: sl@0: * "This product includes cryptographic software written by sl@0: * Eric Young (eay@cryptsoft.com)" sl@0: * The word 'cryptographic' can be left out if the rouines from the library sl@0: * being used are not cryptographic related :-). sl@0: * 4. If you include any Windows specific code (or a derivative thereof) from sl@0: * the apps directory (application code) you must include an acknowledgement: sl@0: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" sl@0: * sl@0: * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND sl@0: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE sl@0: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE sl@0: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE sl@0: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL sl@0: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS sl@0: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) sl@0: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT sl@0: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY sl@0: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF sl@0: * SUCH DAMAGE. sl@0: * sl@0: * The licence and distribution terms for any publically available version or sl@0: * derivative of this code cannot be changed. i.e. this code cannot simply be sl@0: * copied and put under another distribution licence sl@0: * [including the GNU Public Licence.] sl@0: */ sl@0: /* ==================================================================== sl@0: * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved. sl@0: * sl@0: * Redistribution and use in source and binary forms, with or without sl@0: * modification, are permitted provided that the following conditions sl@0: * are met: sl@0: * sl@0: * 1. Redistributions of source code must retain the above copyright sl@0: * notice, this list of conditions and the following disclaimer. sl@0: * sl@0: * 2. Redistributions in binary form must reproduce the above copyright sl@0: * notice, this list of conditions and the following disclaimer in sl@0: * the documentation and/or other materials provided with the sl@0: * distribution. sl@0: * sl@0: * 3. All advertising materials mentioning features or use of this sl@0: * software must display the following acknowledgment: sl@0: * "This product includes software developed by the OpenSSL Project sl@0: * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" sl@0: * sl@0: * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to sl@0: * endorse or promote products derived from this software without sl@0: * prior written permission. For written permission, please contact sl@0: * openssl-core@openssl.org. sl@0: * sl@0: * 5. Products derived from this software may not be called "OpenSSL" sl@0: * nor may "OpenSSL" appear in their names without prior written sl@0: * permission of the OpenSSL Project. sl@0: * sl@0: * 6. Redistributions of any form whatsoever must retain the following sl@0: * acknowledgment: sl@0: * "This product includes software developed by the OpenSSL Project sl@0: * for use in the OpenSSL Toolkit (http://www.openssl.org/)" sl@0: * sl@0: * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY sl@0: * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE sl@0: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR sl@0: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR sl@0: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, sl@0: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT sl@0: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; sl@0: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) sl@0: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, sl@0: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) sl@0: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED sl@0: * OF THE POSSIBILITY OF SUCH DAMAGE. sl@0: * ==================================================================== sl@0: * sl@0: * This product includes cryptographic software written by Eric Young sl@0: * (eay@cryptsoft.com). This product includes software written by Tim sl@0: * Hudson (tjh@cryptsoft.com). sl@0: * sl@0: */ sl@0: /* sl@0: © Portions copyright (c) 2006 Nokia Corporation. All rights reserved. sl@0: */ sl@0: sl@0: #include sl@0: #include "ssl_locl.h" sl@0: #include sl@0: #include sl@0: sl@0: #ifndef EMULATOR sl@0: static unsigned char ssl3_pad_1[48]={ sl@0: #else sl@0: static const unsigned char ssl3_pad_1[48]={ sl@0: #endif sl@0: 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, sl@0: 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, sl@0: 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, sl@0: 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, sl@0: 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, sl@0: 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36 }; sl@0: sl@0: #ifndef EMULATOR sl@0: static unsigned char ssl3_pad_2[48]={ sl@0: #else sl@0: static const unsigned char ssl3_pad_2[48]={ sl@0: #endif sl@0: 0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c, sl@0: 0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c, sl@0: 0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c, sl@0: 0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c, sl@0: 0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c, sl@0: 0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c,0x5c }; sl@0: sl@0: static int ssl3_handshake_mac(SSL *s, EVP_MD_CTX *in_ctx, sl@0: const char *sender, int len, unsigned char *p); sl@0: sl@0: static int ssl3_generate_key_block(SSL *s, unsigned char *km, int num) sl@0: { sl@0: EVP_MD_CTX m5; sl@0: EVP_MD_CTX s1; sl@0: unsigned char buf[16],smd[SHA_DIGEST_LENGTH]; sl@0: unsigned char c='A'; sl@0: unsigned int i,j,k; sl@0: sl@0: #ifdef CHARSET_EBCDIC sl@0: c = os_toascii[c]; /*'A' in ASCII */ sl@0: #endif sl@0: k=0; sl@0: EVP_MD_CTX_init(&m5); sl@0: EVP_MD_CTX_init(&s1); sl@0: for (i=0; (int)i sizeof buf) sl@0: { sl@0: /* bug: 'buf' is too small for this ciphersuite */ sl@0: SSLerr(SSL_F_SSL3_GENERATE_KEY_BLOCK, ERR_R_INTERNAL_ERROR); sl@0: return 0; sl@0: } sl@0: sl@0: for (j=0; jsession->master_key, sl@0: s->session->master_key_length); sl@0: EVP_DigestUpdate(&s1,s->s3->server_random,SSL3_RANDOM_SIZE); sl@0: EVP_DigestUpdate(&s1,s->s3->client_random,SSL3_RANDOM_SIZE); sl@0: EVP_DigestFinal_ex(&s1,smd,NULL); sl@0: sl@0: EVP_DigestInit_ex(&m5,EVP_md5(), NULL); sl@0: EVP_DigestUpdate(&m5,s->session->master_key, sl@0: s->session->master_key_length); sl@0: EVP_DigestUpdate(&m5,smd,SHA_DIGEST_LENGTH); sl@0: if ((int)(i+MD5_DIGEST_LENGTH) > num) sl@0: { sl@0: EVP_DigestFinal_ex(&m5,smd,NULL); sl@0: memcpy(km,smd,(num-i)); sl@0: } sl@0: else sl@0: EVP_DigestFinal_ex(&m5,km,NULL); sl@0: sl@0: km+=MD5_DIGEST_LENGTH; sl@0: } sl@0: OPENSSL_cleanse(smd,SHA_DIGEST_LENGTH); sl@0: EVP_MD_CTX_cleanup(&m5); sl@0: EVP_MD_CTX_cleanup(&s1); sl@0: return 1; sl@0: } sl@0: sl@0: int ssl3_change_cipher_state(SSL *s, int which) sl@0: { sl@0: unsigned char *p,*key_block,*mac_secret; sl@0: unsigned char exp_key[EVP_MAX_KEY_LENGTH]; sl@0: unsigned char exp_iv[EVP_MAX_IV_LENGTH]; sl@0: unsigned char *ms,*key,*iv,*er1,*er2; sl@0: EVP_CIPHER_CTX *dd; sl@0: const EVP_CIPHER *c; sl@0: #ifndef OPENSSL_NO_COMP sl@0: COMP_METHOD *comp; sl@0: #endif sl@0: const EVP_MD *m; sl@0: EVP_MD_CTX md; sl@0: int is_exp,n,i,j,k,cl; sl@0: int reuse_dd = 0; sl@0: sl@0: is_exp=SSL_C_IS_EXPORT(s->s3->tmp.new_cipher); sl@0: c=s->s3->tmp.new_sym_enc; sl@0: m=s->s3->tmp.new_hash; sl@0: #ifndef OPENSSL_NO_COMP sl@0: if (s->s3->tmp.new_compression == NULL) sl@0: comp=NULL; sl@0: else sl@0: comp=s->s3->tmp.new_compression->method; sl@0: #endif sl@0: key_block=s->s3->tmp.key_block; sl@0: sl@0: if (which & SSL3_CC_READ) sl@0: { sl@0: if (s->enc_read_ctx != NULL) sl@0: reuse_dd = 1; sl@0: else if ((s->enc_read_ctx=OPENSSL_malloc(sizeof(EVP_CIPHER_CTX))) == NULL) sl@0: goto err; sl@0: else sl@0: /* make sure it's intialized in case we exit later with an error */ sl@0: EVP_CIPHER_CTX_init(s->enc_read_ctx); sl@0: dd= s->enc_read_ctx; sl@0: s->read_hash=m; sl@0: #ifndef OPENSSL_NO_COMP sl@0: /* COMPRESS */ sl@0: if (s->expand != NULL) sl@0: { sl@0: COMP_CTX_free(s->expand); sl@0: s->expand=NULL; sl@0: } sl@0: if (comp != NULL) sl@0: { sl@0: s->expand=COMP_CTX_new(comp); sl@0: if (s->expand == NULL) sl@0: { sl@0: SSLerr(SSL_F_SSL3_CHANGE_CIPHER_STATE,SSL_R_COMPRESSION_LIBRARY_ERROR); sl@0: goto err2; sl@0: } sl@0: if (s->s3->rrec.comp == NULL) sl@0: s->s3->rrec.comp=(unsigned char *) sl@0: OPENSSL_malloc(SSL3_RT_MAX_PLAIN_LENGTH); sl@0: if (s->s3->rrec.comp == NULL) sl@0: goto err; sl@0: } sl@0: #endif sl@0: memset(&(s->s3->read_sequence[0]),0,8); sl@0: mac_secret= &(s->s3->read_mac_secret[0]); sl@0: } sl@0: else sl@0: { sl@0: if (s->enc_write_ctx != NULL) sl@0: reuse_dd = 1; sl@0: else if ((s->enc_write_ctx=OPENSSL_malloc(sizeof(EVP_CIPHER_CTX))) == NULL) sl@0: goto err; sl@0: else sl@0: /* make sure it's intialized in case we exit later with an error */ sl@0: EVP_CIPHER_CTX_init(s->enc_write_ctx); sl@0: dd= s->enc_write_ctx; sl@0: sl@0: sl@0: s->write_hash=m; sl@0: #ifndef OPENSSL_NO_COMP sl@0: /* COMPRESS */ sl@0: if (s->compress != NULL) sl@0: { sl@0: COMP_CTX_free(s->compress); sl@0: s->compress=NULL; sl@0: } sl@0: if (comp != NULL) sl@0: { sl@0: s->compress=COMP_CTX_new(comp); sl@0: if (s->compress == NULL) sl@0: { sl@0: SSLerr(SSL_F_SSL3_CHANGE_CIPHER_STATE,SSL_R_COMPRESSION_LIBRARY_ERROR); sl@0: goto err2; sl@0: } sl@0: } sl@0: #endif sl@0: memset(&(s->s3->write_sequence[0]),0,8); sl@0: mac_secret= &(s->s3->write_mac_secret[0]); sl@0: } sl@0: sl@0: if (reuse_dd) sl@0: EVP_CIPHER_CTX_cleanup(dd); sl@0: sl@0: p=s->s3->tmp.key_block; sl@0: i=EVP_MD_size(m); sl@0: cl=EVP_CIPHER_key_length(c); sl@0: j=is_exp ? (cl < SSL_C_EXPORT_KEYLENGTH(s->s3->tmp.new_cipher) ? sl@0: cl : SSL_C_EXPORT_KEYLENGTH(s->s3->tmp.new_cipher)) : cl; sl@0: /* Was j=(is_exp)?5:EVP_CIPHER_key_length(c); */ sl@0: k=EVP_CIPHER_iv_length(c); sl@0: if ( (which == SSL3_CHANGE_CIPHER_CLIENT_WRITE) || sl@0: (which == SSL3_CHANGE_CIPHER_SERVER_READ)) sl@0: { sl@0: ms= &(p[ 0]); n=i+i; sl@0: key= &(p[ n]); n+=j+j; sl@0: iv= &(p[ n]); n+=k+k; sl@0: er1= &(s->s3->client_random[0]); sl@0: er2= &(s->s3->server_random[0]); sl@0: } sl@0: else sl@0: { sl@0: n=i; sl@0: ms= &(p[ n]); n+=i+j; sl@0: key= &(p[ n]); n+=j+k; sl@0: iv= &(p[ n]); n+=k; sl@0: er1= &(s->s3->server_random[0]); sl@0: er2= &(s->s3->client_random[0]); sl@0: } sl@0: sl@0: if (n > s->s3->tmp.key_block_length) sl@0: { sl@0: SSLerr(SSL_F_SSL3_CHANGE_CIPHER_STATE,ERR_R_INTERNAL_ERROR); sl@0: goto err2; sl@0: } sl@0: sl@0: EVP_MD_CTX_init(&md); sl@0: memcpy(mac_secret,ms,i); sl@0: if (is_exp) sl@0: { sl@0: /* In here I set both the read and write key/iv to the sl@0: * same value since only the correct one will be used :-). sl@0: */ sl@0: EVP_DigestInit_ex(&md,EVP_md5(), NULL); sl@0: EVP_DigestUpdate(&md,key,j); sl@0: EVP_DigestUpdate(&md,er1,SSL3_RANDOM_SIZE); sl@0: EVP_DigestUpdate(&md,er2,SSL3_RANDOM_SIZE); sl@0: EVP_DigestFinal_ex(&md,&(exp_key[0]),NULL); sl@0: key= &(exp_key[0]); sl@0: sl@0: if (k > 0) sl@0: { sl@0: EVP_DigestInit_ex(&md,EVP_md5(), NULL); sl@0: EVP_DigestUpdate(&md,er1,SSL3_RANDOM_SIZE); sl@0: EVP_DigestUpdate(&md,er2,SSL3_RANDOM_SIZE); sl@0: EVP_DigestFinal_ex(&md,&(exp_iv[0]),NULL); sl@0: iv= &(exp_iv[0]); sl@0: } sl@0: } sl@0: sl@0: s->session->key_arg_length=0; sl@0: sl@0: EVP_CipherInit_ex(dd,c,NULL,key,iv,(which & SSL3_CC_WRITE)); sl@0: sl@0: OPENSSL_cleanse(&(exp_key[0]),sizeof(exp_key)); sl@0: OPENSSL_cleanse(&(exp_iv[0]),sizeof(exp_iv)); sl@0: EVP_MD_CTX_cleanup(&md); sl@0: return(1); sl@0: err: sl@0: SSLerr(SSL_F_SSL3_CHANGE_CIPHER_STATE,ERR_R_MALLOC_FAILURE); sl@0: err2: sl@0: return(0); sl@0: } sl@0: sl@0: int ssl3_setup_key_block(SSL *s) sl@0: { sl@0: unsigned char *p; sl@0: const EVP_CIPHER *c; sl@0: const EVP_MD *hash; sl@0: int num; sl@0: int ret = 0; sl@0: SSL_COMP *comp; sl@0: sl@0: if (s->s3->tmp.key_block_length != 0) sl@0: return(1); sl@0: sl@0: if (!ssl_cipher_get_evp(s->session,&c,&hash,&comp)) sl@0: { sl@0: SSLerr(SSL_F_SSL3_SETUP_KEY_BLOCK,SSL_R_CIPHER_OR_HASH_UNAVAILABLE); sl@0: return(0); sl@0: } sl@0: sl@0: s->s3->tmp.new_sym_enc=c; sl@0: s->s3->tmp.new_hash=hash; sl@0: #ifdef OPENSSL_NO_COMP sl@0: s->s3->tmp.new_compression=NULL; sl@0: #else sl@0: s->s3->tmp.new_compression=comp; sl@0: #endif sl@0: sl@0: num=EVP_CIPHER_key_length(c)+EVP_MD_size(hash)+EVP_CIPHER_iv_length(c); sl@0: num*=2; sl@0: sl@0: ssl3_cleanup_key_block(s); sl@0: sl@0: if ((p=OPENSSL_malloc(num)) == NULL) sl@0: goto err; sl@0: sl@0: s->s3->tmp.key_block_length=num; sl@0: s->s3->tmp.key_block=p; sl@0: sl@0: ret = ssl3_generate_key_block(s,p,num); sl@0: sl@0: if (!(s->options & SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS)) sl@0: { sl@0: /* enable vulnerability countermeasure for CBC ciphers with sl@0: * known-IV problem (http://www.openssl.org/~bodo/tls-cbc.txt) sl@0: */ sl@0: s->s3->need_empty_fragments = 1; sl@0: sl@0: if (s->session->cipher != NULL) sl@0: { sl@0: if ((s->session->cipher->algorithms & SSL_ENC_MASK) == SSL_eNULL) sl@0: s->s3->need_empty_fragments = 0; sl@0: sl@0: #ifndef OPENSSL_NO_RC4 sl@0: if ((s->session->cipher->algorithms & SSL_ENC_MASK) == SSL_RC4) sl@0: s->s3->need_empty_fragments = 0; sl@0: #endif sl@0: } sl@0: } sl@0: sl@0: return ret; sl@0: sl@0: err: sl@0: SSLerr(SSL_F_SSL3_SETUP_KEY_BLOCK,ERR_R_MALLOC_FAILURE); sl@0: return(0); sl@0: } sl@0: sl@0: void ssl3_cleanup_key_block(SSL *s) sl@0: { sl@0: if (s->s3->tmp.key_block != NULL) sl@0: { sl@0: OPENSSL_cleanse(s->s3->tmp.key_block, sl@0: s->s3->tmp.key_block_length); sl@0: OPENSSL_free(s->s3->tmp.key_block); sl@0: s->s3->tmp.key_block=NULL; sl@0: } sl@0: s->s3->tmp.key_block_length=0; sl@0: } sl@0: sl@0: int ssl3_enc(SSL *s, int send) sl@0: { sl@0: SSL3_RECORD *rec; sl@0: EVP_CIPHER_CTX *ds; sl@0: unsigned long l; sl@0: int bs,i; sl@0: const EVP_CIPHER *enc; sl@0: sl@0: if (send) sl@0: { sl@0: ds=s->enc_write_ctx; sl@0: rec= &(s->s3->wrec); sl@0: if (s->enc_write_ctx == NULL) sl@0: enc=NULL; sl@0: else sl@0: enc=EVP_CIPHER_CTX_cipher(s->enc_write_ctx); sl@0: } sl@0: else sl@0: { sl@0: ds=s->enc_read_ctx; sl@0: rec= &(s->s3->rrec); sl@0: if (s->enc_read_ctx == NULL) sl@0: enc=NULL; sl@0: else sl@0: enc=EVP_CIPHER_CTX_cipher(s->enc_read_ctx); sl@0: } sl@0: sl@0: if ((s->session == NULL) || (ds == NULL) || sl@0: (enc == NULL)) sl@0: { sl@0: memmove(rec->data,rec->input,rec->length); sl@0: rec->input=rec->data; sl@0: } sl@0: else sl@0: { sl@0: l=rec->length; sl@0: bs=EVP_CIPHER_block_size(ds->cipher); sl@0: sl@0: /* COMPRESS */ sl@0: sl@0: if ((bs != 1) && send) sl@0: { sl@0: i=bs-((int)l%bs); sl@0: sl@0: /* we need to add 'i-1' padding bytes */ sl@0: l+=i; sl@0: rec->length+=i; sl@0: rec->input[l-1]=(i-1); sl@0: } sl@0: sl@0: if (!send) sl@0: { sl@0: if (l == 0 || l%bs != 0) sl@0: { sl@0: SSLerr(SSL_F_SSL3_ENC,SSL_R_BLOCK_CIPHER_PAD_IS_WRONG); sl@0: ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECRYPTION_FAILED); sl@0: return 0; sl@0: } sl@0: /* otherwise, rec->length >= bs */ sl@0: } sl@0: sl@0: EVP_Cipher(ds,rec->data,rec->input,l); sl@0: sl@0: if ((bs != 1) && !send) sl@0: { sl@0: i=rec->data[l-1]+1; sl@0: /* SSL 3.0 bounds the number of padding bytes by the block size; sl@0: * padding bytes (except the last one) are arbitrary */ sl@0: if (i > bs) sl@0: { sl@0: /* Incorrect padding. SSLerr() and ssl3_alert are done sl@0: * by caller: we don't want to reveal whether this is sl@0: * a decryption error or a MAC verification failure sl@0: * (see http://www.openssl.org/~bodo/tls-cbc.txt) */ sl@0: return -1; sl@0: } sl@0: /* now i <= bs <= rec->length */ sl@0: rec->length-=i; sl@0: } sl@0: } sl@0: return(1); sl@0: } sl@0: sl@0: void ssl3_init_finished_mac(SSL *s) sl@0: { sl@0: EVP_DigestInit_ex(&(s->s3->finish_dgst1),s->ctx->md5, NULL); sl@0: EVP_DigestInit_ex(&(s->s3->finish_dgst2),s->ctx->sha1, NULL); sl@0: } sl@0: sl@0: void ssl3_finish_mac(SSL *s, const unsigned char *buf, int len) sl@0: { sl@0: EVP_DigestUpdate(&(s->s3->finish_dgst1),buf,len); sl@0: EVP_DigestUpdate(&(s->s3->finish_dgst2),buf,len); sl@0: } sl@0: sl@0: int ssl3_cert_verify_mac(SSL *s, EVP_MD_CTX *ctx, unsigned char *p) sl@0: { sl@0: return(ssl3_handshake_mac(s,ctx,NULL,0,p)); sl@0: } sl@0: sl@0: int ssl3_final_finish_mac(SSL *s, EVP_MD_CTX *ctx1, EVP_MD_CTX *ctx2, sl@0: const char *sender, int len, unsigned char *p) sl@0: { sl@0: int ret; sl@0: sl@0: ret=ssl3_handshake_mac(s,ctx1,sender,len,p); sl@0: p+=ret; sl@0: ret+=ssl3_handshake_mac(s,ctx2,sender,len,p); sl@0: return(ret); sl@0: } sl@0: sl@0: static int ssl3_handshake_mac(SSL *s, EVP_MD_CTX *in_ctx, sl@0: const char *sender, int len, unsigned char *p) sl@0: { sl@0: unsigned int ret; sl@0: int npad,n; sl@0: unsigned int i; sl@0: unsigned char md_buf[EVP_MAX_MD_SIZE]; sl@0: EVP_MD_CTX ctx; sl@0: sl@0: EVP_MD_CTX_init(&ctx); sl@0: EVP_MD_CTX_copy_ex(&ctx,in_ctx); sl@0: sl@0: n=EVP_MD_CTX_size(&ctx); sl@0: npad=(48/n)*n; sl@0: sl@0: if (sender != NULL) sl@0: EVP_DigestUpdate(&ctx,sender,len); sl@0: EVP_DigestUpdate(&ctx,s->session->master_key, sl@0: s->session->master_key_length); sl@0: EVP_DigestUpdate(&ctx,ssl3_pad_1,npad); sl@0: EVP_DigestFinal_ex(&ctx,md_buf,&i); sl@0: sl@0: EVP_DigestInit_ex(&ctx,EVP_MD_CTX_md(&ctx), NULL); sl@0: EVP_DigestUpdate(&ctx,s->session->master_key, sl@0: s->session->master_key_length); sl@0: EVP_DigestUpdate(&ctx,ssl3_pad_2,npad); sl@0: EVP_DigestUpdate(&ctx,md_buf,i); sl@0: EVP_DigestFinal_ex(&ctx,p,&ret); sl@0: sl@0: EVP_MD_CTX_cleanup(&ctx); sl@0: sl@0: return((int)ret); sl@0: } sl@0: sl@0: int ssl3_mac(SSL *ssl, unsigned char *md, int send) sl@0: { sl@0: SSL3_RECORD *rec; sl@0: unsigned char *mac_sec,*seq; sl@0: EVP_MD_CTX md_ctx; sl@0: const EVP_MD *hash; sl@0: unsigned char *p,rec_char; sl@0: unsigned int md_size; sl@0: int npad; sl@0: sl@0: if (send) sl@0: { sl@0: rec= &(ssl->s3->wrec); sl@0: mac_sec= &(ssl->s3->write_mac_secret[0]); sl@0: seq= &(ssl->s3->write_sequence[0]); sl@0: hash=ssl->write_hash; sl@0: } sl@0: else sl@0: { sl@0: rec= &(ssl->s3->rrec); sl@0: mac_sec= &(ssl->s3->read_mac_secret[0]); sl@0: seq= &(ssl->s3->read_sequence[0]); sl@0: hash=ssl->read_hash; sl@0: } sl@0: sl@0: md_size=EVP_MD_size(hash); sl@0: npad=(48/md_size)*md_size; sl@0: sl@0: /* Chop the digest off the end :-) */ sl@0: EVP_MD_CTX_init(&md_ctx); sl@0: sl@0: EVP_DigestInit_ex( &md_ctx,hash, NULL); sl@0: EVP_DigestUpdate(&md_ctx,mac_sec,md_size); sl@0: EVP_DigestUpdate(&md_ctx,ssl3_pad_1,npad); sl@0: EVP_DigestUpdate(&md_ctx,seq,8); sl@0: rec_char=rec->type; sl@0: EVP_DigestUpdate(&md_ctx,&rec_char,1); sl@0: p=md; sl@0: s2n(rec->length,p); sl@0: EVP_DigestUpdate(&md_ctx,md,2); sl@0: EVP_DigestUpdate(&md_ctx,rec->input,rec->length); sl@0: EVP_DigestFinal_ex( &md_ctx,md,NULL); sl@0: sl@0: EVP_DigestInit_ex( &md_ctx,hash, NULL); sl@0: EVP_DigestUpdate(&md_ctx,mac_sec,md_size); sl@0: EVP_DigestUpdate(&md_ctx,ssl3_pad_2,npad); sl@0: EVP_DigestUpdate(&md_ctx,md,md_size); sl@0: EVP_DigestFinal_ex( &md_ctx,md,&md_size); sl@0: sl@0: EVP_MD_CTX_cleanup(&md_ctx); sl@0: sl@0: ssl3_record_sequence_update(seq); sl@0: return(md_size); sl@0: } sl@0: sl@0: void ssl3_record_sequence_update(unsigned char *seq) sl@0: { sl@0: int i; sl@0: sl@0: for (i=7; i>=0; i--) sl@0: { sl@0: ++seq[i]; sl@0: if (seq[i] != 0) break; sl@0: } sl@0: } sl@0: sl@0: int ssl3_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p, sl@0: int len) sl@0: { sl@0: #ifndef EMULATOR sl@0: static const unsigned char *salt[3]={ sl@0: #else sl@0: static const unsigned char *const salt[3]={ sl@0: #endif sl@0: sl@0: #ifndef CHARSET_EBCDIC sl@0: (const unsigned char *)"A", sl@0: (const unsigned char *)"BB", sl@0: (const unsigned char *)"CCC", sl@0: #else sl@0: (const unsigned char *)"\x41", sl@0: (const unsigned char *)"\x42\x42", sl@0: (const unsigned char *)"\x43\x43\x43", sl@0: #endif sl@0: }; sl@0: unsigned char buf[EVP_MAX_MD_SIZE]; sl@0: EVP_MD_CTX ctx; sl@0: int i,ret=0; sl@0: unsigned int n; sl@0: sl@0: EVP_MD_CTX_init(&ctx); sl@0: for (i=0; i<3; i++) sl@0: { sl@0: EVP_DigestInit_ex(&ctx,s->ctx->sha1, NULL); sl@0: EVP_DigestUpdate(&ctx,salt[i],strlen((const char *)salt[i])); sl@0: EVP_DigestUpdate(&ctx,p,len); sl@0: EVP_DigestUpdate(&ctx,&(s->s3->client_random[0]), sl@0: SSL3_RANDOM_SIZE); sl@0: EVP_DigestUpdate(&ctx,&(s->s3->server_random[0]), sl@0: SSL3_RANDOM_SIZE); sl@0: EVP_DigestFinal_ex(&ctx,buf,&n); sl@0: sl@0: EVP_DigestInit_ex(&ctx,s->ctx->md5, NULL); sl@0: EVP_DigestUpdate(&ctx,p,len); sl@0: EVP_DigestUpdate(&ctx,buf,n); sl@0: EVP_DigestFinal_ex(&ctx,out,&n); sl@0: out+=n; sl@0: ret+=n; sl@0: } sl@0: EVP_MD_CTX_cleanup(&ctx); sl@0: return(ret); sl@0: } sl@0: sl@0: int ssl3_alert_code(int code) sl@0: { sl@0: switch (code) sl@0: { sl@0: case SSL_AD_CLOSE_NOTIFY: return(SSL3_AD_CLOSE_NOTIFY); sl@0: case SSL_AD_UNEXPECTED_MESSAGE: return(SSL3_AD_UNEXPECTED_MESSAGE); sl@0: case SSL_AD_BAD_RECORD_MAC: return(SSL3_AD_BAD_RECORD_MAC); sl@0: case SSL_AD_DECRYPTION_FAILED: return(SSL3_AD_BAD_RECORD_MAC); sl@0: case SSL_AD_RECORD_OVERFLOW: return(SSL3_AD_BAD_RECORD_MAC); sl@0: case SSL_AD_DECOMPRESSION_FAILURE:return(SSL3_AD_DECOMPRESSION_FAILURE); sl@0: case SSL_AD_HANDSHAKE_FAILURE: return(SSL3_AD_HANDSHAKE_FAILURE); sl@0: case SSL_AD_NO_CERTIFICATE: return(SSL3_AD_NO_CERTIFICATE); sl@0: case SSL_AD_BAD_CERTIFICATE: return(SSL3_AD_BAD_CERTIFICATE); sl@0: case SSL_AD_UNSUPPORTED_CERTIFICATE:return(SSL3_AD_UNSUPPORTED_CERTIFICATE); sl@0: case SSL_AD_CERTIFICATE_REVOKED:return(SSL3_AD_CERTIFICATE_REVOKED); sl@0: case SSL_AD_CERTIFICATE_EXPIRED:return(SSL3_AD_CERTIFICATE_EXPIRED); sl@0: case SSL_AD_CERTIFICATE_UNKNOWN:return(SSL3_AD_CERTIFICATE_UNKNOWN); sl@0: case SSL_AD_ILLEGAL_PARAMETER: return(SSL3_AD_ILLEGAL_PARAMETER); sl@0: case SSL_AD_UNKNOWN_CA: return(SSL3_AD_BAD_CERTIFICATE); sl@0: case SSL_AD_ACCESS_DENIED: return(SSL3_AD_HANDSHAKE_FAILURE); sl@0: case SSL_AD_DECODE_ERROR: return(SSL3_AD_HANDSHAKE_FAILURE); sl@0: case SSL_AD_DECRYPT_ERROR: return(SSL3_AD_HANDSHAKE_FAILURE); sl@0: case SSL_AD_EXPORT_RESTRICTION: return(SSL3_AD_HANDSHAKE_FAILURE); sl@0: case SSL_AD_PROTOCOL_VERSION: return(SSL3_AD_HANDSHAKE_FAILURE); sl@0: case SSL_AD_INSUFFICIENT_SECURITY:return(SSL3_AD_HANDSHAKE_FAILURE); sl@0: case SSL_AD_INTERNAL_ERROR: return(SSL3_AD_HANDSHAKE_FAILURE); sl@0: case SSL_AD_USER_CANCELLED: return(SSL3_AD_HANDSHAKE_FAILURE); sl@0: case SSL_AD_NO_RENEGOTIATION: return(-1); /* Don't send it :-) */ sl@0: default: return(-1); sl@0: } sl@0: } sl@0: