-#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_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;
+
+ if (s->session->sess_cert == NULL) {
+ ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
+ SSLerr(SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE,
+ SSL_R_UNEXPECTED_MESSAGE);
+ goto err;
+ }
+
+ /*
+ * 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 */