+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+ return 0;
+#endif
+}
+
+static int tls_process_cke_gost18(SSL_CONNECTION *s, PACKET *pkt)
+{
+#ifndef OPENSSL_NO_GOST
+ unsigned char rnd_dgst[32];
+ EVP_PKEY_CTX *pkey_ctx = NULL;
+ EVP_PKEY *pk = NULL;
+ unsigned char premaster_secret[32];
+ const unsigned char *start = NULL;
+ size_t outlen = 32, inlen = 0;
+ int ret = 0;
+ int cipher_nid = ossl_gost18_cke_cipher_nid(s);
+ SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(s);
+
+ if (cipher_nid == NID_undef) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ if (ossl_gost_ukm(s, rnd_dgst) <= 0) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ /* Get our certificate private key */
+ pk = s->cert->pkeys[SSL_PKEY_GOST12_512].privatekey != NULL ?
+ s->cert->pkeys[SSL_PKEY_GOST12_512].privatekey :
+ s->cert->pkeys[SSL_PKEY_GOST12_256].privatekey;
+ if (pk == NULL) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_BAD_HANDSHAKE_STATE);
+ goto err;
+ }
+
+ pkey_ctx = EVP_PKEY_CTX_new_from_pkey(sctx->libctx, pk, sctx->propq);
+ if (pkey_ctx == NULL) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB);
+ goto err;
+ }
+ if (EVP_PKEY_decrypt_init(pkey_ctx) <= 0) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ /* Reuse EVP_PKEY_CTRL_SET_IV, make choice in engine code depending on size */
+ if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, EVP_PKEY_OP_DECRYPT,
+ EVP_PKEY_CTRL_SET_IV, 32, rnd_dgst) <= 0) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_LIBRARY_BUG);
+ goto err;
+ }
+
+ if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, EVP_PKEY_OP_DECRYPT,
+ EVP_PKEY_CTRL_CIPHER, cipher_nid, NULL) <= 0) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_R_LIBRARY_BUG);
+ goto err;
+ }
+ inlen = PACKET_remaining(pkt);
+ start = PACKET_data(pkt);
+
+ if (EVP_PKEY_decrypt(pkey_ctx, premaster_secret, &outlen, start, inlen) <= 0) {
+ SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_R_DECRYPTION_FAILED);
+ goto err;
+ }
+ /* Generate master secret */
+ if (!ssl_generate_master_secret(s, premaster_secret,
+ sizeof(premaster_secret), 0)) {
+ /* SSLfatal() already called */
+ goto err;
+ }
+ ret = 1;
+
+ err:
+ EVP_PKEY_CTX_free(pkey_ctx);
+ return ret;
+#else
+ /* Should never happen */
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);