| Index: openssl/ssl/d1_srvr.c
|
| ===================================================================
|
| --- openssl/ssl/d1_srvr.c (revision 105093)
|
| +++ openssl/ssl/d1_srvr.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
|
| @@ -121,14 +121,15 @@
|
| #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 SSL_METHOD *dtls1_get_server_method(int ver);
|
| +static const SSL_METHOD *dtls1_get_server_method(int ver);
|
| static int dtls1_send_hello_verify_request(SSL *s);
|
|
|
| -static SSL_METHOD *dtls1_get_server_method(int ver)
|
| +static const SSL_METHOD *dtls1_get_server_method(int ver)
|
| {
|
| if (ver == DTLS1_VERSION)
|
| return(DTLSv1_server_method());
|
| @@ -144,10 +145,12 @@
|
| int dtls1_accept(SSL *s)
|
| {
|
| BUF_MEM *buf;
|
| - unsigned long l,Time=(unsigned long)time(NULL);
|
| + 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();
|
| @@ -157,11 +160,15 @@
|
| 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);
|
| @@ -271,11 +278,23 @@
|
|
|
| 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 (s->d1->listen && s->state == SSL3_ST_SW_SRVR_HELLO_A)
|
| + 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;
|
| }
|
|
|
| @@ -284,14 +303,13 @@
|
| case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A:
|
| case DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B:
|
|
|
| - dtls1_start_timer(s);
|
| 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;
|
|
|
| - /* HelloVerifyRequests resets Finished MAC */
|
| - if (s->client_version != DTLS1_BAD_VER)
|
| + /* HelloVerifyRequest resets Finished MAC */
|
| + if (s->version != DTLS1_BAD_VER)
|
| ssl3_init_finished_mac(s);
|
| break;
|
|
|
| @@ -321,8 +339,9 @@
|
|
|
| case SSL3_ST_SW_CERT_A:
|
| case SSL3_ST_SW_CERT_B:
|
| - /* Check if it is anon DH */
|
| - if (!(s->s3->tmp.new_cipher->algorithms & SSL_aNULL))
|
| + /* 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);
|
| @@ -350,13 +369,13 @@
|
|
|
| case SSL3_ST_SW_KEY_EXCH_A:
|
| case SSL3_ST_SW_KEY_EXCH_B:
|
| - l=s->s3->tmp.new_cipher->algorithms;
|
| + 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
|
| - && !(l & SSL_KRB5)
|
| + && !(alg_k & SSL_kKRB5)
|
| #endif /* OPENSSL_NO_KRB5 */
|
| )
|
| /* option SSL_OP_EPHEMERAL_RSA sends temporary RSA key
|
| @@ -367,11 +386,17 @@
|
| else
|
| s->s3->tmp.use_rsa_tmp=0;
|
|
|
| - /* only send if a DH key exchange, fortezza or
|
| + /* only send if a DH key exchange or
|
| * RSA but we have a sign only certificate */
|
| if (s->s3->tmp.use_rsa_tmp
|
| - || (l & (SSL_DH|SSL_kFZA))
|
| - || ((l & SSL_kRSA)
|
| + /* 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)
|
| @@ -402,12 +427,15 @@
|
| /* never request cert in anonymous ciphersuites
|
| * (see section "Certificate request" in SSL 3 drafts
|
| * and in RFC 2246): */
|
| - ((s->s3->tmp.new_cipher->algorithms & SSL_aNULL) &&
|
| + ((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->algorithms & SSL_aKRB5))
|
| + /* 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;
|
| @@ -479,15 +507,30 @@
|
| 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,
|
| - &(s->s3->finish_dgst1),
|
| - &(s->s3->tmp.cert_verify_md[0]));
|
| - s->method->ssl3_enc->cert_verify_mac(s,
|
| - &(s->s3->finish_dgst2),
|
| - &(s->s3->tmp.cert_verify_md[MD5_DIGEST_LENGTH]));
|
| + 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:
|
| @@ -686,12 +729,8 @@
|
| buf = (unsigned char *)s->init_buf->data;
|
|
|
| msg = p = &(buf[DTLS1_HM_HEADER_LENGTH]);
|
| - if (s->client_version == DTLS1_BAD_VER)
|
| - *(p++) = DTLS1_BAD_VER>>8,
|
| - *(p++) = DTLS1_BAD_VER&0xff;
|
| - else
|
| - *(p++) = s->version >> 8,
|
| - *(p++) = s->version & 0xFF;
|
| + *(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,
|
| @@ -713,9 +752,6 @@
|
| /* 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);
|
| }
|
|
|
| /* s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B */
|
| @@ -740,12 +776,8 @@
|
| /* Do the message type and length last */
|
| d=p= &(buf[DTLS1_HM_HEADER_LENGTH]);
|
|
|
| - if (s->client_version == DTLS1_BAD_VER)
|
| - *(p++)=DTLS1_BAD_VER>>8,
|
| - *(p++)=DTLS1_BAD_VER&0xff;
|
| - else
|
| - *(p++)=s->version>>8,
|
| - *(p++)=s->version&0xff;
|
| + *(p++)=s->version>>8;
|
| + *(p++)=s->version&0xff;
|
|
|
| /* Random stuff */
|
| memcpy(p,s->s3->server_random,SSL3_RANDOM_SIZE);
|
| @@ -851,6 +883,13 @@
|
| #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;
|
| @@ -865,7 +904,7 @@
|
| EVP_MD_CTX_init(&md_ctx);
|
| if (s->state == SSL3_ST_SW_KEY_EXCH_A)
|
| {
|
| - type=s->s3->tmp.new_cipher->algorithms & SSL_MKEY_MASK;
|
| + type=s->s3->tmp.new_cipher->algorithm_mkey;
|
| cert=s->cert;
|
|
|
| buf=s->init_buf;
|
| @@ -959,7 +998,142 @@
|
| }
|
| 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;
|
| @@ -970,7 +1144,8 @@
|
| n+=2+nr[i];
|
| }
|
|
|
| - if (!(s->s3->tmp.new_cipher->algorithms & SSL_aNULL))
|
| + 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)
|
| @@ -1001,6 +1176,41 @@
|
| 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)
|
| {
|
| @@ -1054,7 +1264,26 @@
|
| }
|
| else
|
| #endif
|
| +#if !defined(OPENSSL_NO_ECDSA)
|
| + if (pkey->type == EVP_PKEY_EC)
|
| {
|
| + /* let's do ECDSA */
|
| + EVP_SignInit_ex(&md_ctx,EVP_ecdsa(), NULL);
|
| + EVP_SignUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
|
| + EVP_SignUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
|
| + EVP_SignUpdate(&md_ctx,&(d[DTLS1_HM_HEADER_LENGTH]),n);
|
| + if (!EVP_SignFinal(&md_ctx,&(p[2]),
|
| + (unsigned int *)&i,pkey))
|
| + {
|
| + SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_ECDSA);
|
| + goto err;
|
| + }
|
| + s2n(i,p);
|
| + n+=i+2;
|
| + }
|
| + else
|
| +#endif
|
| + {
|
| /* Is this error check actually needed? */
|
| al=SSL_AD_HANDSHAKE_FAILURE;
|
| SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNKNOWN_PKEY_TYPE);
|
| @@ -1080,6 +1309,10 @@
|
| 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);
|
| }
|
| @@ -1193,14 +1426,15 @@
|
| 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 */
|
| - (s->s3->tmp.new_cipher->algorithms
|
| - & (SSL_MKEY_MASK|SSL_AUTH_MASK))
|
| - != (SSL_aKRB5|SSL_kKRB5))
|
| + if (x == NULL)
|
| {
|
| - SSLerr(SSL_F_DTLS1_SEND_SERVER_CERTIFICATE,ERR_R_INTERNAL_ERROR);
|
| - return(0);
|
| + /* 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);
|
|
|