diff options
Diffstat (limited to 'openssl/ssl/d1_srvr.c')
-rw-r--r-- | openssl/ssl/d1_srvr.c | 540 |
1 files changed, 472 insertions, 68 deletions
diff --git a/openssl/ssl/d1_srvr.c b/openssl/ssl/d1_srvr.c index 0bbf8ae7f..301ceda7a 100644 --- a/openssl/ssl/d1_srvr.c +++ b/openssl/ssl/d1_srvr.c @@ -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,9 +145,9 @@ IMPLEMENT_dtls1_meth_func(DTLSv1_server_method, 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; - long num1; + unsigned long alg_k; int ret= -1; int new_state,state,skip=0; @@ -236,17 +237,13 @@ int dtls1_accept(SSL *s) s->state=SSL3_ST_SW_HELLO_REQ_A; } - if ( (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE)) - s->d1->send_cookie = 1; - else - s->d1->send_cookie = 0; - 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; @@ -267,37 +264,58 @@ int dtls1_accept(SSL *s) s->shutdown=0; ret=ssl3_get_client_hello(s); if (ret <= 0) goto end; - s->new_session = 2; + dtls1_stop_timer(s); - if ( s->d1->send_cookie) + 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; + + /* If we're just listening, stop here */ + if (s->d1->listen && s->state == SSL3_ST_SW_SRVR_HELLO_A) + { + ret = 2; + s->d1->listen = 0; + goto end; + } + break; 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->d1->send_cookie = 0; 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; 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) - s->state=SSL3_ST_SW_CHANGE_A; + { + 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; @@ -305,27 +323,43 @@ int dtls1_accept(SSL *s) 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); 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: - 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 @@ -336,11 +370,17 @@ int dtls1_accept(SSL *s) 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) @@ -349,6 +389,7 @@ int dtls1_accept(SSL *s) ) ) { + dtls1_start_timer(s); ret=dtls1_send_server_key_exchange(s); if (ret <= 0) goto end; } @@ -370,12 +411,15 @@ int dtls1_accept(SSL *s) /* 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; @@ -385,6 +429,7 @@ int dtls1_accept(SSL *s) 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 @@ -399,6 +444,7 @@ int dtls1_accept(SSL *s) 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; @@ -407,16 +453,13 @@ int dtls1_accept(SSL *s) break; case SSL3_ST_SW_FLUSH: - /* number of bytes to be flushed */ - num1=BIO_ctrl(s->wbio,BIO_CTRL_INFO,0,NULL); - if (num1 > 0) + s->rwstate=SSL_WRITING; + if (BIO_flush(s->wbio) <= 0) { - s->rwstate=SSL_WRITING; - num1=BIO_flush(s->wbio); - if (num1 <= 0) { ret= -1; goto end; } - s->rwstate=SSL_NOTHING; + ret= -1; + goto end; } - + s->rwstate=SSL_NOTHING; s->state=s->s3->tmp.next_state; break; @@ -426,6 +469,7 @@ int dtls1_accept(SSL *s) 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 { @@ -433,6 +477,7 @@ int dtls1_accept(SSL *s) * 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; } @@ -442,26 +487,44 @@ int dtls1_accept(SSL *s) 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; - /* 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: 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; @@ -469,16 +532,41 @@ int dtls1_accept(SSL *s) 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: @@ -554,6 +642,7 @@ int dtls1_accept(SSL *s) 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; */ @@ -624,22 +713,16 @@ int dtls1_send_hello_verify_request(SSL *s) 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, - &(s->d1->cookie_len)) == 0) + 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; } - /* else the cookie is assumed to have - * been initialized by the application */ *(p++) = (unsigned char) s->d1->cookie_len; memcpy(p, s->d1->cookie, s->d1->cookie_len); @@ -680,12 +763,8 @@ int dtls1_send_server_hello(SSL *s) /* 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); @@ -713,6 +792,8 @@ int dtls1_send_server_hello(SSL *s) 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; @@ -726,6 +807,14 @@ int dtls1_send_server_hello(SSL *s) *(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; @@ -781,6 +870,13 @@ int dtls1_send_server_key_exchange(SSL *s) #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; @@ -795,7 +891,7 @@ int dtls1_send_server_key_exchange(SSL *s) 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; @@ -889,6 +985,142 @@ int dtls1_send_server_key_exchange(SSL *s) } 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 (!EC_KEY_up_ref(ecdhp)) + { + SSLerr(SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE,ERR_R_ECDH_LIB); + goto err; + } + ecdh = ecdhp; + + 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); @@ -900,7 +1132,8 @@ int dtls1_send_server_key_exchange(SSL *s) 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) @@ -931,6 +1164,41 @@ int dtls1_send_server_key_exchange(SSL *s) 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) { @@ -984,6 +1252,25 @@ int dtls1_send_server_key_exchange(SSL *s) } 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; @@ -1010,6 +1297,10 @@ int dtls1_send_server_key_exchange(SSL *s) 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); } @@ -1123,14 +1414,15 @@ int dtls1_send_server_certificate(SSL *s) 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); @@ -1145,3 +1437,115 @@ int dtls1_send_server_certificate(SSL *s) /* 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 |