aboutsummaryrefslogtreecommitdiff
path: root/ssl/statem/statem_clnt.c
diff options
context:
space:
mode:
authorMatt Caswell <matt@openssl.org>2016-07-08 10:07:55 +0100
committerMatt Caswell <matt@openssl.org>2016-07-18 23:05:14 +0100
commite00e0b3d84719e80ed5a8fd48c1162537c2fa12c (patch)
tree444994679b9144abf947484931a485ddf5f42470 /ssl/statem/statem_clnt.c
parent67ad5aabe6b6d60ac27f6a4b10e7b1ba65113829 (diff)
downloadopenssl-e00e0b3d84719e80ed5a8fd48c1162537c2fa12c.zip
openssl-e00e0b3d84719e80ed5a8fd48c1162537c2fa12c.tar.gz
openssl-e00e0b3d84719e80ed5a8fd48c1162537c2fa12c.tar.bz2
Split out GOST CKE construction into a separate function
Continuing previous commit to break up the tls_construct_client_key_exchange() function. This splits out the GOST code. Reviewed-by: Richard Levitte <levitte@openssl.org>
Diffstat (limited to 'ssl/statem/statem_clnt.c')
-rw-r--r--ssl/statem/statem_clnt.c273
1 files changed, 144 insertions, 129 deletions
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index 8e48f34..a9fcf10 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -2283,6 +2283,148 @@ static int tls_construct_cke_ecdhe(SSL *s, unsigned char **p, int *len, int *al)
#endif
}
+static int tls_construct_cke_gost(SSL *s, unsigned char **p, int *len, int *al)
+{
+#ifndef OPENSSL_NO_GOST
+ /* GOST key exchange message creation */
+ EVP_PKEY_CTX *pkey_ctx = NULL;
+ X509 *peer_cert;
+ size_t msglen;
+ unsigned int md_len;
+ unsigned char shared_ukm[32], tmp[256];
+ EVP_MD_CTX *ukm_hash = NULL;
+ int dgst_nid = NID_id_GostR3411_94;
+ unsigned char *pms = NULL;
+ size_t pmslen = 0;
+
+ if ((s->s3->tmp.new_cipher->algorithm_auth & SSL_aGOST12) != 0)
+ dgst_nid = NID_id_GostR3411_2012_256;
+
+ /*
+ * Get server sertificate PKEY and create ctx from it
+ */
+ peer_cert = s->session->peer;
+ if (!peer_cert) {
+ *al = SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+ SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER);
+ return 0;
+ }
+
+ pkey_ctx = EVP_PKEY_CTX_new(X509_get0_pubkey(peer_cert), NULL);
+ if (pkey_ctx == NULL) {
+ *al = SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+ ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ /*
+ * If we have send a certificate, and certificate key
+ * parameters match those of server certificate, use
+ * certificate key for key exchange
+ */
+
+ /* Otherwise, generate ephemeral key pair */
+ pmslen = 32;
+ pms = OPENSSL_malloc(pmslen);
+ if (pms == NULL) {
+ *al = SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+ ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ if (EVP_PKEY_encrypt_init(pkey_ctx) <= 0
+ /* Generate session key */
+ || RAND_bytes(pms, pmslen) <= 0) {
+ *al = SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+ ERR_R_INTERNAL_ERROR);
+ goto err;
+ };
+ /*
+ * If we have client certificate, use its secret as peer key
+ */
+ if (s->s3->tmp.cert_req && s->cert->key->privatekey) {
+ if (EVP_PKEY_derive_set_peer
+ (pkey_ctx, s->cert->key->privatekey) <= 0) {
+ /*
+ * If there was an error - just ignore it. Ephemeral key
+ * * would be used
+ */
+ ERR_clear_error();
+ }
+ }
+ /*
+ * Compute shared IV and store it in algorithm-specific context
+ * data
+ */
+ ukm_hash = EVP_MD_CTX_new();
+ if (ukm_hash == NULL
+ || EVP_DigestInit(ukm_hash, EVP_get_digestbynid(dgst_nid)) <= 0
+ || EVP_DigestUpdate(ukm_hash, s->s3->client_random,
+ SSL3_RANDOM_SIZE) <= 0
+ || EVP_DigestUpdate(ukm_hash, s->s3->server_random,
+ SSL3_RANDOM_SIZE) <= 0
+ || EVP_DigestFinal_ex(ukm_hash, shared_ukm, &md_len) <= 0) {
+ *al = SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+ ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ EVP_MD_CTX_free(ukm_hash);
+ ukm_hash = NULL;
+ if (EVP_PKEY_CTX_ctrl(pkey_ctx, -1, EVP_PKEY_OP_ENCRYPT,
+ EVP_PKEY_CTRL_SET_IV, 8, shared_ukm) < 0) {
+ *al = SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+ SSL_R_LIBRARY_BUG);
+ goto err;
+ }
+ /* Make GOST keytransport blob message */
+ /*
+ * Encapsulate it into sequence
+ */
+ *((*p)++) = V_ASN1_SEQUENCE | V_ASN1_CONSTRUCTED;
+ msglen = 255;
+ if (EVP_PKEY_encrypt(pkey_ctx, tmp, &msglen, pms, pmslen) <= 0) {
+ *al = SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
+ SSL_R_LIBRARY_BUG);
+ goto err;
+ }
+ if (msglen >= 0x80) {
+ *((*p)++) = 0x81;
+ *((*p)++) = msglen & 0xff;
+ *len = msglen + 3;
+ } else {
+ *((*p)++) = msglen & 0xff;
+ *len = msglen + 2;
+ }
+ memcpy(*p, tmp, msglen);
+ /* 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) {
+ /* Set flag "skip certificate verify" */
+ s->s3->flags |= TLS1_FLAGS_SKIP_CERT_VERIFY;
+ }
+ EVP_PKEY_CTX_free(pkey_ctx);
+ s->s3->tmp.pms = pms;
+ s->s3->tmp.pmslen = pmslen;
+
+ return 1;
+ err:
+ EVP_PKEY_CTX_free(pkey_ctx);
+ OPENSSL_clear_free(pms, pmslen);
+ EVP_MD_CTX_free(ukm_hash);
+ return 0;
+#else
+ SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+ *al = SSL_AD_INTERNAL_ERROR;
+ return 0;
+#endif
+}
+
int tls_construct_client_key_exchange(SSL *s)
{
unsigned char *p;
@@ -2312,134 +2454,10 @@ int tls_construct_client_key_exchange(SSL *s)
} else if (alg_k & (SSL_kECDHE | SSL_kECDHEPSK)) {
if (!tls_construct_cke_ecdhe(s, &p, &n, &al))
goto err;
- }
-#ifndef OPENSSL_NO_GOST
- else if (alg_k & SSL_kGOST) {
- /* GOST key exchange message creation */
- EVP_PKEY_CTX *pkey_ctx;
- X509 *peer_cert;
- size_t msglen;
- unsigned int md_len;
- unsigned char shared_ukm[32], tmp[256];
- EVP_MD_CTX *ukm_hash;
- int dgst_nid = NID_id_GostR3411_94;
- unsigned char *pms = NULL;
- size_t pmslen = 0;
-
- if ((s->s3->tmp.new_cipher->algorithm_auth & SSL_aGOST12) != 0)
- dgst_nid = NID_id_GostR3411_2012_256;
-
-
- /*
- * Get server sertificate PKEY and create ctx from it
- */
- peer_cert = s->session->peer;
- if (!peer_cert) {
- SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
- SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER);
- goto err;
- }
-
- pkey_ctx = EVP_PKEY_CTX_new(X509_get0_pubkey(peer_cert), NULL);
- if (pkey_ctx == NULL) {
- SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
- ERR_R_MALLOC_FAILURE);
+ } else if (alg_k & SSL_kGOST) {
+ if (!tls_construct_cke_gost(s, &p, &n, &al))
goto err;
- }
- /*
- * If we have send a certificate, and certificate key
- * parameters match those of server certificate, use
- * certificate key for key exchange
- */
-
- /* Otherwise, generate ephemeral key pair */
- pmslen = 32;
- pms = OPENSSL_malloc(pmslen);
- if (pms == NULL)
- goto memerr;
-
- if (pkey_ctx == NULL
- || EVP_PKEY_encrypt_init(pkey_ctx) <= 0
- /* Generate session key */
- || RAND_bytes(pms, pmslen) <= 0) {
- EVP_PKEY_CTX_free(pkey_ctx);
- OPENSSL_clear_free(pms, pmslen);
- SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
- ERR_R_INTERNAL_ERROR);
- goto err;
- };
- /*
- * If we have client certificate, use its secret as peer key
- */
- if (s->s3->tmp.cert_req && s->cert->key->privatekey) {
- if (EVP_PKEY_derive_set_peer
- (pkey_ctx, s->cert->key->privatekey) <= 0) {
- /*
- * If there was an error - just ignore it. Ephemeral key
- * * would be used
- */
- ERR_clear_error();
- }
- }
- /*
- * Compute shared IV and store it in algorithm-specific context
- * data
- */
- ukm_hash = EVP_MD_CTX_new();
- if (EVP_DigestInit(ukm_hash,
- EVP_get_digestbynid(dgst_nid)) <= 0
- || EVP_DigestUpdate(ukm_hash, s->s3->client_random,
- SSL3_RANDOM_SIZE) <= 0
- || EVP_DigestUpdate(ukm_hash, s->s3->server_random,
- SSL3_RANDOM_SIZE) <= 0
- || EVP_DigestFinal_ex(ukm_hash, shared_ukm, &md_len) <= 0) {
- EVP_MD_CTX_free(ukm_hash);
- OPENSSL_clear_free(pms, pmslen);
- SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
- ERR_R_INTERNAL_ERROR);
- goto err;
- }
- EVP_MD_CTX_free(ukm_hash);
- if (EVP_PKEY_CTX_ctrl
- (pkey_ctx, -1, EVP_PKEY_OP_ENCRYPT, EVP_PKEY_CTRL_SET_IV, 8,
- shared_ukm) < 0) {
- OPENSSL_clear_free(pms, pmslen);
- SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
- SSL_R_LIBRARY_BUG);
- goto err;
- }
- /* Make GOST keytransport blob message */
- /*
- * Encapsulate it into sequence
- */
- *(p++) = V_ASN1_SEQUENCE | V_ASN1_CONSTRUCTED;
- msglen = 255;
- if (EVP_PKEY_encrypt(pkey_ctx, tmp, &msglen, pms, pmslen) <= 0) {
- OPENSSL_clear_free(pms, pmslen);
- SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE,
- SSL_R_LIBRARY_BUG);
- goto err;
- }
- if (msglen >= 0x80) {
- *(p++) = 0x81;
- *(p++) = msglen & 0xff;
- n = msglen + 3;
- } else {
- *(p++) = msglen & 0xff;
- n = msglen + 2;
- }
- memcpy(p, tmp, msglen);
- /* 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) {
- /* Set flag "skip certificate verify" */
- s->s3->flags |= TLS1_FLAGS_SKIP_CERT_VERIFY;
- }
- EVP_PKEY_CTX_free(pkey_ctx);
- s->s3->tmp.pms = pms;
- s->s3->tmp.pmslen = pmslen;
}
-#endif
#ifndef OPENSSL_NO_SRP
else if (alg_k & SSL_kSRP) {
if (s->srp_ctx.A != NULL) {
@@ -2477,9 +2495,6 @@ int tls_construct_client_key_exchange(SSL *s)
}
return 1;
- memerr:
- SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
- al = SSL_AD_INTERNAL_ERROR;
err:
if (al != -1)
ssl3_send_alert(s, SSL3_AL_FATAL, al);