| Index: openssl/ssl/d1_clnt.c
|
| ===================================================================
|
| --- openssl/ssl/d1_clnt.c (revision 105093)
|
| +++ openssl/ssl/d1_clnt.c (working copy)
|
| @@ -4,7 +4,7 @@
|
| * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
|
| */
|
| /* ====================================================================
|
| - * Copyright (c) 1999-2005 The OpenSSL Project. All rights reserved.
|
| + * 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
|
| @@ -115,20 +115,23 @@
|
|
|
| #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 SSL_METHOD *dtls1_get_client_method(int ver);
|
| +static const SSL_METHOD *dtls1_get_client_method(int ver);
|
| static int dtls1_get_hello_verify(SSL *s);
|
|
|
| -static SSL_METHOD *dtls1_get_client_method(int ver)
|
| +static const SSL_METHOD *dtls1_get_client_method(int ver)
|
| {
|
| if (ver == DTLS1_VERSION || ver == DTLS1_BAD_VER)
|
| return(DTLSv1_client_method());
|
| @@ -144,7 +147,7 @@
|
| int dtls1_connect(SSL *s)
|
| {
|
| BUF_MEM *buf=NULL;
|
| - unsigned long Time=(unsigned long)time(NULL),l;
|
| + 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;;
|
| @@ -296,8 +299,9 @@
|
| break;
|
| }
|
| #endif
|
| - /* Check if it is anon DH */
|
| - if (!(s->s3->tmp.new_cipher->algorithms & SSL_aNULL))
|
| + /* 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;
|
| @@ -374,7 +378,6 @@
|
| dtls1_start_timer(s);
|
| ret=dtls1_send_client_key_exchange(s);
|
| if (ret <= 0) goto end;
|
| - l=s->s3->tmp.new_cipher->algorithms;
|
| /* EAY EAY EAY need to check for DH fix cert
|
| * sent back */
|
| /* For TLS, cert_req is set to 2, so a cert chain
|
| @@ -404,7 +407,8 @@
|
|
|
| case SSL3_ST_CW_CHANGE_A:
|
| case SSL3_ST_CW_CHANGE_B:
|
| - dtls1_start_timer(s);
|
| + 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;
|
| @@ -439,7 +443,8 @@
|
|
|
| case SSL3_ST_CW_FINISHED_A:
|
| case SSL3_ST_CW_FINISHED_B:
|
| - dtls1_start_timer(s);
|
| + 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,
|
| @@ -471,7 +476,6 @@
|
| s->s3->tmp.next_state=SSL3_ST_CR_FINISHED_A;
|
| }
|
| s->init_num=0;
|
| -
|
| break;
|
|
|
| #ifndef OPENSSL_NO_TLSEXT
|
| @@ -611,12 +615,19 @@
|
| #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++) ;
|
| @@ -624,7 +635,7 @@
|
| {
|
| Time=(unsigned long)time(NULL); /* Time */
|
| l2n(Time,p);
|
| - RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4);
|
| + RAND_pseudo_bytes(p,sizeof(s->s3->client_random)-4);
|
| }
|
|
|
| /* Do the message type and length last */
|
| @@ -771,7 +782,7 @@
|
| {
|
| unsigned char *p,*d;
|
| int n;
|
| - unsigned long l;
|
| + unsigned long alg_k;
|
| #ifndef OPENSSL_NO_RSA
|
| unsigned char *q;
|
| EVP_PKEY *pkey=NULL;
|
| @@ -779,18 +790,26 @@
|
| #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;
|
|
|
| - l=s->s3->tmp.new_cipher->algorithms;
|
| -
|
| /* Fool emacs indentation */
|
| if (0) {}
|
| #ifndef OPENSSL_NO_RSA
|
| - else if (l & SSL_kRSA)
|
| + else if (alg_k & SSL_kRSA)
|
| {
|
| RSA *rsa;
|
| unsigned char tmp_buf[SSL_MAX_MASTER_KEY_LENGTH];
|
| @@ -849,7 +868,7 @@
|
| }
|
| #endif
|
| #ifndef OPENSSL_NO_KRB5
|
| - else if (l & SSL_kKRB5)
|
| + else if (alg_k & SSL_kKRB5)
|
| {
|
| krb5_error_code krb5rc;
|
| KSSL_CTX *kssl_ctx = s->kssl_ctx;
|
| @@ -857,7 +876,7 @@
|
| krb5_data *enc_ticket;
|
| krb5_data authenticator, *authp = NULL;
|
| EVP_CIPHER_CTX ciph_ctx;
|
| - EVP_CIPHER *enc = NULL;
|
| + 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
|
| @@ -868,7 +887,7 @@
|
|
|
| #ifdef KSSL_DEBUG
|
| printf("ssl3_send_client_key_exchange(%lx & %lx)\n",
|
| - l, SSL_kKRB5);
|
| + alg_k, SSL_kKRB5);
|
| #endif /* KSSL_DEBUG */
|
|
|
| authp = NULL;
|
| @@ -958,7 +977,7 @@
|
| sizeof tmp_buf);
|
| EVP_EncryptFinal_ex(&ciph_ctx,&(epms[outl]),&padl);
|
| outl += padl;
|
| - if (outl > sizeof epms)
|
| + if (outl > (int)sizeof epms)
|
| {
|
| SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
|
| goto err;
|
| @@ -981,7 +1000,7 @@
|
| }
|
| #endif
|
| #ifndef OPENSSL_NO_DH
|
| - else if (l & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
|
| + else if (alg_k & (SSL_kEDH|SSL_kDHr|SSL_kDHd))
|
| {
|
| DH *dh_srvr,*dh_clnt;
|
|
|
| @@ -1036,6 +1055,274 @@
|
| /* 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);
|
| @@ -1064,6 +1351,13 @@
|
| /* 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);
|
| }
|
|
|
| @@ -1076,7 +1370,7 @@
|
| unsigned u=0;
|
| #endif
|
| unsigned long n;
|
| -#ifndef OPENSSL_NO_DSA
|
| +#if !defined(OPENSSL_NO_DSA) || !defined(OPENSSL_NO_ECDSA)
|
| int j;
|
| #endif
|
|
|
| @@ -1086,14 +1380,16 @@
|
| p= &(d[DTLS1_HM_HEADER_LENGTH]);
|
| pkey=s->cert->key->privatekey;
|
|
|
| - s->method->ssl3_enc->cert_verify_mac(s,&(s->s3->finish_dgst2),
|
| + 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,
|
| - &(s->s3->finish_dgst1),&(data[0]));
|
| + NID_md5,
|
| + &(data[0]));
|
| if (RSA_sign(NID_md5_sha1, data,
|
| MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH,
|
| &(p[2]), &u, pkey->pkey.rsa) <= 0 )
|
| @@ -1122,7 +1418,24 @@
|
| }
|
| 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;
|
| }
|
|
|