+
+#ifndef OPENSSL_NO_ECDH
+ if (alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe))
+ {
+ int ret = 1;
+ int field_size = 0;
+ const EC_KEY *tkey;
+ const EC_GROUP *group;
+ const BIGNUM *priv_key;
+
+ /* initialize structures for server's ECDH key pair */
+ if ((srvr_ecdh = EC_KEY_new()) == NULL)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ /* Let's get server private key and group information */
+ if (alg_k & (SSL_kECDHr|SSL_kECDHe))
+ {
+ /* use the certificate */
+ tkey = s->cert->pkeys[SSL_PKEY_ECC].privatekey->pkey.ec;
+ }
+ else
+ {
+ /* use the ephermeral values we saved when
+ * generating the ServerKeyExchange msg.
+ */
+ tkey = s->s3->tmp.ecdh;
+ }
+
+ group = EC_KEY_get0_group(tkey);
+ priv_key = EC_KEY_get0_private_key(tkey);
+
+ if (!EC_KEY_set_group(srvr_ecdh, group) ||
+ !EC_KEY_set_private_key(srvr_ecdh, priv_key))
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ ERR_R_EC_LIB);
+ goto err;
+ }
+
+ /* Let's get client's public key */
+ if ((clnt_ecpoint = EC_POINT_new(group)) == NULL)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (n == 0L)
+ {
+ /* Client Publickey was in Client Certificate */
+
+ if (alg_k & SSL_kEECDH)
+ {
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_MISSING_TMP_ECDH_KEY);
+ goto f_err;
+ }
+ if (((clnt_pub_pkey=X509_get_pubkey(s->session->peer))
+ == NULL) ||
+ (clnt_pub_pkey->type != EVP_PKEY_EC))
+ {
+ /* XXX: For now, we do not support client
+ * authentication using ECDH certificates
+ * so this branch (n == 0L) of the code is
+ * never executed. When that support is
+ * added, we ought to ensure the key
+ * received in the certificate is
+ * authorized for key agreement.
+ * ECDH_compute_key implicitly checks that
+ * the two ECDH shares are for the same
+ * group.
+ */
+ al=SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ SSL_R_UNABLE_TO_DECODE_ECDH_CERTS);
+ goto f_err;
+ }
+
+ if (EC_POINT_copy(clnt_ecpoint,
+ EC_KEY_get0_public_key(clnt_pub_pkey->pkey.ec)) == 0)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ ERR_R_EC_LIB);
+ goto err;
+ }
+ ret = 2; /* Skip certificate verify processing */
+ }
+ else
+ {
+ /* Get client's public key from encoded point
+ * in the ClientKeyExchange message.
+ */
+ if ((bn_ctx = BN_CTX_new()) == NULL)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ /* Get encoded point length */
+ i = *p;
+ p += 1;
+ if (EC_POINT_oct2point(group,
+ clnt_ecpoint, p, i, bn_ctx) == 0)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ ERR_R_EC_LIB);
+ goto err;
+ }
+ /* p is pointing to somewhere in the buffer
+ * currently, so set it to the start
+ */
+ p=(unsigned char *)s->init_buf->data;
+ }
+
+ /* Compute the shared pre-master secret */
+ field_size = EC_GROUP_get_degree(group);
+ if (field_size <= 0)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ ERR_R_ECDH_LIB);
+ goto err;
+ }
+ i = ECDH_compute_key(p, (field_size+7)/8, clnt_ecpoint, srvr_ecdh, NULL);
+ if (i <= 0)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ ERR_R_ECDH_LIB);
+ goto err;
+ }
+
+ EVP_PKEY_free(clnt_pub_pkey);
+ EC_POINT_free(clnt_ecpoint);
+ if (srvr_ecdh != NULL)
+ EC_KEY_free(srvr_ecdh);
+ BN_CTX_free(bn_ctx);
+
+ /* Compute the master secret */
+ s->session->master_key_length = s->method->ssl3_enc-> \
+ generate_master_secret(s, s->session->master_key, p, i);
+
+ OPENSSL_cleanse(p, i);
+ return (ret);
+ }
+ else
+#endif
+#ifndef OPENSSL_NO_PSK
+ if (alg_k & SSL_kPSK)
+ {
+ 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;
+ char tmp_id[PSK_MAX_IDENTITY_LEN+1];
+
+ al=SSL_AD_HANDSHAKE_FAILURE;
+
+ n2s(p,i);
+ if (n != i+2)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ SSL_R_LENGTH_MISMATCH);
+ goto psk_err;
+ }
+ if (i > PSK_MAX_IDENTITY_LEN)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ SSL_R_DATA_LENGTH_TOO_LONG);
+ goto psk_err;
+ }
+ if (s->psk_server_callback == NULL)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ SSL_R_PSK_NO_SERVER_CB);
+ goto psk_err;
+ }
+
+ /* Create guaranteed NULL-terminated identity
+ * string for the callback */
+ memcpy(tmp_id, p, i);
+ memset(tmp_id+i, 0, PSK_MAX_IDENTITY_LEN+1-i);
+ psk_len = s->psk_server_callback(s, tmp_id,
+ psk_or_pre_ms, sizeof(psk_or_pre_ms));
+ OPENSSL_cleanse(tmp_id, PSK_MAX_IDENTITY_LEN+1);
+
+ if (psk_len > PSK_MAX_PSK_LEN)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ ERR_R_INTERNAL_ERROR);
+ goto psk_err;
+ }
+ else if (psk_len == 0)
+ {
+ /* PSK related to the given identity not found */
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ SSL_R_PSK_IDENTITY_NOT_FOUND);
+ al=SSL_AD_UNKNOWN_PSK_IDENTITY;
+ 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 != NULL)
+ OPENSSL_free(s->session->psk_identity);
+ s->session->psk_identity = BUF_strdup((char *)p);
+ if (s->session->psk_identity == NULL)
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,
+ ERR_R_MALLOC_FAILURE);
+ goto psk_err;
+ }
+
+ 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_SSL3_GET_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);
+ psk_err = 0;
+ psk_err:
+ OPENSSL_cleanse(psk_or_pre_ms, sizeof(psk_or_pre_ms));
+ if (psk_err != 0)
+ goto f_err;
+ }
+ else
+#endif
+ if (alg_k & SSL_kGOST)
+ {
+ EVP_PKEY_CTX *pkey_ctx;
+ unsigned char premaster_secret[32];
+ size_t outlen;
+
+ /* Get our certificate privatec key*/
+ pkey_ctx = EVP_PKEY_CTX_new(s->cert->key->privatekey,NULL);
+ EVP_PKEY_decrypt_init(pkey_ctx);
+ /* Decrypt session key */
+ if ((*p!=( V_ASN1_SEQUENCE| V_ASN1_CONSTRUCTED)) || p[1]!=0x81 )
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED);
+ goto err;
+ }
+ if (EVP_PKEY_decrypt(pkey_ctx,premaster_secret,&outlen,p+3,p[2]) <0)
+
+ {
+ SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_DECRYPTION_FAILED);
+ goto err;
+ }
+ /* Generate master secret */
+ EVP_PKEY_CTX_free(pkey_ctx);
+ s->session->master_key_length=
+ s->method->ssl3_enc->generate_master_secret(s,
+ s->session->master_key,premaster_secret,32);
+
+ }
+ else