aboutsummaryrefslogtreecommitdiff
path: root/openssl/ssl/d1_srvr.c
diff options
context:
space:
mode:
Diffstat (limited to 'openssl/ssl/d1_srvr.c')
-rw-r--r--openssl/ssl/d1_srvr.c540
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