PR: 1921
Submitted by: Michael Tuexen <tuexen@fh-muenster.de> Reviewed by: steve@openssl.org Add ECDHE and PSK support to DTLS.
This commit is contained in:
parent
f16411ccfd
commit
e1f09dfd84
3
CHANGES
3
CHANGES
@ -4,6 +4,9 @@
|
||||
|
||||
Changes between 0.9.8k and 1.0 [xx XXX xxxx]
|
||||
|
||||
*) Add ECDHE and PSK support to DTLS.
|
||||
[Michael Tuexen <tuexen@fh-muenster.de>]
|
||||
|
||||
*) Add CHECKED_STACK_OF macro to safestack.h, otherwise safestack can't
|
||||
be used on C++.
|
||||
[Steve Henson]
|
||||
|
307
ssl/d1_clnt.c
307
ssl/d1_clnt.c
@ -284,8 +284,9 @@ int dtls1_connect(SSL *s)
|
||||
|
||||
case SSL3_ST_CR_CERT_A:
|
||||
case SSL3_ST_CR_CERT_B:
|
||||
/* Check if it is anon DH */
|
||||
if (!(s->s3->tmp.new_cipher->algorithm_auth & 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;
|
||||
@ -716,6 +717,14 @@ int dtls1_send_client_key_exchange(SSL *s)
|
||||
#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)
|
||||
{
|
||||
@ -972,6 +981,274 @@ int dtls1_send_client_key_exchange(SSL *s)
|
||||
|
||||
/* 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
|
||||
{
|
||||
@ -1001,6 +1278,13 @@ int dtls1_send_client_key_exchange(SSL *s)
|
||||
/* 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);
|
||||
}
|
||||
|
||||
@ -1013,7 +1297,7 @@ int dtls1_send_client_verify(SSL *s)
|
||||
unsigned u=0;
|
||||
#endif
|
||||
unsigned long n;
|
||||
#ifndef OPENSSL_NO_DSA
|
||||
#if !defined(OPENSSL_NO_DSA) || !defined(OPENSSL_NO_ECDSA)
|
||||
int j;
|
||||
#endif
|
||||
|
||||
@ -1060,6 +1344,23 @@ int dtls1_send_client_verify(SSL *s)
|
||||
n=j+2;
|
||||
}
|
||||
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_SSL3_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);
|
||||
|
@ -203,9 +203,6 @@ const SSL_CIPHER *dtls1_get_cipher(unsigned int u)
|
||||
{
|
||||
if (ciph->algorithm_enc == SSL_RC4)
|
||||
return NULL;
|
||||
/* We currently don't support ECDH either */
|
||||
if (ciph->algorithm_mkey & SSL_kEECDH)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ciph;
|
||||
|
251
ssl/d1_srvr.c
251
ssl/d1_srvr.c
@ -311,8 +311,9 @@ 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->algorithm_auth & 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);
|
||||
@ -346,7 +347,13 @@ int dtls1_accept(SSL *s)
|
||||
/* only send if a DH key exchange or
|
||||
* RSA but we have a sign only certificate */
|
||||
if (s->s3->tmp.use_rsa_tmp
|
||||
/* 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)
|
||||
@ -383,7 +390,10 @@ int dtls1_accept(SSL *s)
|
||||
* (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->algorithm_auth & SSL_aKRB5))
|
||||
(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;
|
||||
@ -458,15 +468,30 @@ int dtls1_accept(SSL *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,
|
||||
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]));
|
||||
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:
|
||||
@ -788,6 +813,13 @@ int dtls1_send_server_key_exchange(SSL *s)
|
||||
#endif
|
||||
#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;
|
||||
@ -897,6 +929,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);
|
||||
@ -908,7 +1076,8 @@ int dtls1_send_server_key_exchange(SSL *s)
|
||||
n+=2+nr[i];
|
||||
}
|
||||
|
||||
if (!(s->s3->tmp.new_cipher->algorithm_auth & 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)
|
||||
@ -939,6 +1108,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)
|
||||
{
|
||||
@ -991,6 +1195,25 @@ int dtls1_send_server_key_exchange(SSL *s)
|
||||
n+=i+2;
|
||||
}
|
||||
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? */
|
||||
@ -1018,6 +1241,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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user