+ pkey_ctx = EVP_PKEY_CTX_new(pk, NULL);
+ if (pkey_ctx == NULL) {
+ *al = SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_TLS_PROCESS_CKE_GOST, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ if (EVP_PKEY_decrypt_init(pkey_ctx) <= 0) {
+ *al = SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_TLS_PROCESS_CKE_GOST, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ /*
+ * If client certificate is present and is of the same type, maybe
+ * use it for key exchange. Don't mind errors from
+ * EVP_PKEY_derive_set_peer, because it is completely valid to use a
+ * client certificate for authorization only.
+ */
+ client_pub_pkey = X509_get0_pubkey(s->session->peer);
+ if (client_pub_pkey) {
+ if (EVP_PKEY_derive_set_peer(pkey_ctx, client_pub_pkey) <= 0)
+ ERR_clear_error();
+ }
+ /* Decrypt session key */
+ sess_key_len = PACKET_remaining(pkt);
+ if (!PACKET_get_bytes(pkt, &data, sess_key_len)) {
+ *al = SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_TLS_PROCESS_CKE_GOST, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ if (ASN1_get_object((const unsigned char **)&data, &Tlen, &Ttag,
+ &Tclass, sess_key_len) != V_ASN1_CONSTRUCTED
+ || Ttag != V_ASN1_SEQUENCE || Tclass != V_ASN1_UNIVERSAL) {
+ *al = SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_TLS_PROCESS_CKE_GOST, SSL_R_DECRYPTION_FAILED);
+ goto err;
+ }
+ start = data;
+ inlen = Tlen;
+ if (EVP_PKEY_decrypt
+ (pkey_ctx, premaster_secret, &outlen, start, inlen) <= 0) {
+ *al = SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_TLS_PROCESS_CKE_GOST, SSL_R_DECRYPTION_FAILED);
+ goto err;
+ }
+ /* Generate master secret */
+ if (!ssl_generate_master_secret(s, premaster_secret,
+ sizeof(premaster_secret), 0)) {
+ *al = SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_TLS_PROCESS_CKE_GOST, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ /* Check if pubkey from client certificate was used */
+ if (EVP_PKEY_CTX_ctrl
+ (pkey_ctx, -1, -1, EVP_PKEY_CTRL_PEER_KEY, 2, NULL) > 0)
+ s->statem.no_cert_verify = 1;