Skip to content

Instantly share code, notes, and snippets.

@indutny

indutny/1.patch Secret

Last active April 8, 2020 00:01
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save indutny/1bda1561254f2d133b18 to your computer and use it in GitHub Desktop.
Save indutny/1bda1561254f2d133b18 to your computer and use it in GitHub Desktop.
commit f73a6c537fe89bf85bdf0b2edfe6ed4d676725cf
Author: Fedor Indutny <fedor@indutny.com>
Date: Thu Sep 11 17:03:47 2014 +0100
ssl: SSL_MODE_ASYNC_KEY_EX
Support async RSA exchange by providing new SSL_want_rsa_sign(),
SSL_want_rsa_decrypt() API methods.
After getting such want values - SSL_supply_key_ex_data() should be
invoked to continue handshake with a sign/decrypt data that was received
from the remote server.
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index c907f2b..e067eff 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -489,15 +489,41 @@ int ssl3_accept(SSL *s)
)
{
ret=ssl3_send_server_key_exchange(s);
- if (ret <= 0) goto end;
+ if (ret <= 0)
+ goto end;
+ else if (ret == 2)
+ {
+ s->state=SSL3_ST_SW_KEY_EXCH_SIGN_SUPPLY;
+ break;
+ }
+ else if (ret == 3)
+ {
+ s->state=SSL3_ST_SW_KEY_EXCH_SIGN_WAIT;
+ break;
+ }
}
else
skip=1;
+ /* Intentional fall through */
+ case SSL3_ST_SW_KEY_EXCH_C:
s->state=SSL3_ST_SW_CERT_REQ_A;
s->init_num=0;
break;
+ case SSL3_ST_SW_KEY_EXCH_SIGN_WAIT:
+ s->rwstate=SSL_SIGN;
+ ret = -1;
+ goto end;
+
+ case SSL3_ST_SW_KEY_EXCH_SIGN_SUPPLY:
+ ret=ssl3_cont_server_key_exchange(s);
+ if (ret != 1)
+ goto end;
+ s->rwstate=SSL_NOTHING;
+ s->state=SSL3_ST_SW_KEY_EXCH_C;
+ break;
+
case SSL3_ST_SW_CERT_REQ_A:
case SSL3_ST_SW_CERT_REQ_B:
if (/* don't request cert unless asked for it: */
@@ -600,7 +626,13 @@ int ssl3_accept(SSL *s)
ret=ssl3_get_client_key_exchange(s);
if (ret <= 0)
goto end;
- if (ret == 2)
+ if (ret == 3)
+ {
+ s->state=(s->mode & SSL_MODE_ASYNC_KEY_EX) ?
+ SSL3_ST_SR_KEY_EXCH_RSA_DECRYPT_WAIT :
+ SSL3_ST_SR_KEY_EXCH_RSA_DECRYPT_SUPPLY;
+ }
+ else if (ret == 2)
{
/* For the ECDH ciphersuites when
* the client sends its ECDH pub key in
@@ -620,7 +652,14 @@ int ssl3_accept(SSL *s)
#endif
s->init_num = 0;
}
- else if (TLS1_get_version(s) >= TLS1_2_VERSION)
+ else
+ {
+ s->state=SSL3_ST_SR_KEY_EXCH_C;
+ }
+ break;
+
+ case SSL3_ST_SR_KEY_EXCH_C:
+ if (TLS1_get_version(s) >= TLS1_2_VERSION)
{
s->state=SSL3_ST_SR_CERT_VRFY_A;
s->init_num=0;
@@ -671,6 +710,19 @@ int ssl3_accept(SSL *s)
}
break;
+ case SSL3_ST_SR_KEY_EXCH_RSA_DECRYPT_WAIT:
+ s->rwstate=SSL_RSA_DECRYPT;
+ ret = -1;
+ goto end;
+
+ case SSL3_ST_SR_KEY_EXCH_RSA_DECRYPT_SUPPLY:
+ ret=ssl3_cont_client_key_exchange(s);
+ if (ret != 1)
+ goto end;
+ s->rwstate=SSL_NOTHING;
+ s->state=SSL3_ST_SR_KEY_EXCH_C;
+ break;
+
case SSL3_ST_SR_CERT_VRFY_A:
case SSL3_ST_SR_CERT_VRFY_B:
@@ -1582,7 +1634,9 @@ int ssl3_send_server_key_exchange(SSL *s)
int nr[4],kn;
BUF_MEM *buf;
EVP_MD_CTX md_ctx;
+ int async;
+ async=0;
EVP_MD_CTX_init(&md_ctx);
if (s->state == SSL3_ST_SW_KEY_EXCH_A)
{
@@ -1948,14 +2002,30 @@ int ssl3_send_server_key_exchange(SSL *s)
q+=i;
j+=i;
}
- if (RSA_sign(NID_md5_sha1, md_buf, j,
- &(p[2]), &u, pkey->pkey.rsa) <= 0)
+
+ s->init_num=n;
+ s->init_off=&(p[2]) - d;
+ s->s3->tmp.reuse_message=1;
+ if ((s->mode & SSL_MODE_ASYNC_KEY_EX) == 0)
{
- SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_RSA);
- goto err;
+ if (RSA_sign(NID_md5_sha1, md_buf, j,
+ &(p[2]), &u, pkey->pkey.rsa) <= 0)
+ {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_RSA);
+ goto err;
+ }
+ s->key_ex.len=u;
+ }
+ else
+ {
+ /* Copy md_buf contents to init_buf */
+ s->key_ex.data=&(p[2]);
+ s->key_ex.md=NID_md5_sha1;
+ s->key_ex.type=pkey->type;
+ s->key_ex.len=j;
+ memcpy(s->key_ex.data, md_buf, s->key_ex.len);
+ async=1;
}
- s2n(u,p);
- n+=u+2;
}
else
#endif
@@ -1978,20 +2048,40 @@ int ssl3_send_server_key_exchange(SSL *s)
fprintf(stderr, "Using hash %s\n",
EVP_MD_name(md));
#endif
- EVP_SignInit_ex(&md_ctx, md, NULL);
- EVP_SignUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
- EVP_SignUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
- EVP_SignUpdate(&md_ctx,&(d[4]),n);
- if (!EVP_SignFinal(&md_ctx,&(p[2]),
- (unsigned int *)&i,pkey))
+ s->init_num=n;
+ s->init_off=&(p[2]) - d;
+ s->s3->tmp.reuse_message=1;
+ if ((s->mode & SSL_MODE_ASYNC_KEY_EX) == 0)
{
- SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_EVP);
- goto err;
+ EVP_SignInit_ex(&md_ctx, md, NULL);
+ EVP_SignUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
+ EVP_SignUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
+ EVP_SignUpdate(&md_ctx,&(d[4]),n);
+ if (!EVP_SignFinal(&md_ctx,&(p[2]),
+ (unsigned int *)&i,pkey))
+ {
+ SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,ERR_LIB_EVP);
+ goto err;
+ }
+ s->key_ex.len=i;
+ }
+ else
+ {
+ /* Copy digest inputs to init_buf */
+ s->key_ex.data=&p[2];
+ s->key_ex.len=2 * SSL3_RANDOM_SIZE + n;
+ s->key_ex.md=EVP_MD_nid(md);
+ s->key_ex.type=pkey->type;
+ q=s->key_ex.data;
+ memcpy(q, &(s->s3->client_random[0]), SSL3_RANDOM_SIZE);
+ memcpy(q + SSL3_RANDOM_SIZE,
+ &(s->s3->server_random[0]),
+ SSL3_RANDOM_SIZE);
+ memcpy(q + 2 * SSL3_RANDOM_SIZE,
+ &(d[4]),
+ n);
+ async=1;
}
- s2n(i,p);
- n+=i+2;
- if (TLS1_get_version(s) >= TLS1_2_VERSION)
- n+= 2;
}
else
{
@@ -2000,8 +2090,9 @@ int ssl3_send_server_key_exchange(SSL *s)
SSLerr(SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE,SSL_R_UNKNOWN_PKEY_TYPE);
goto f_err;
}
+ EVP_MD_CTX_cleanup(&md_ctx);
+ return async ? 3 : 2;
}
-
*(d++)=SSL3_MT_SERVER_KEY_EXCHANGE;
l2n3(n,d);
@@ -2025,6 +2116,35 @@ err:
return(-1);
}
+int ssl3_cont_server_key_exchange(SSL *s)
+ {
+ unsigned char *p,*d;
+ int n;
+
+ d=(unsigned char*) s->init_buf->data;
+ /* NOTE: init_off points to the supplied data */
+ p=d + s->init_off - 2;
+ n=s->init_num;
+ s->s3->tmp.reuse_message=0;
+
+ s2n(s->key_ex.len,p);
+ n+=s->key_ex.len+2;
+
+ /* Signature/Hash algorithms */
+ if (TLS1_get_version(s) >= TLS1_2_VERSION)
+ n+= 2;
+ *(d++)=SSL3_MT_SERVER_KEY_EXCHANGE;
+ l2n3(n,d);
+
+ /* we should now have things packed up, so lets send
+ * it off */
+ s->init_num=n+4;
+ s->init_off=0;
+
+ s->state = SSL3_ST_SW_KEY_EXCH_B;
+ return(ssl3_do_write(s,SSL3_RT_HANDSHAKE));
+ }
+
int ssl3_send_certificate_request(SSL *s)
{
unsigned char *p,*d;
@@ -2214,59 +2334,19 @@ int ssl3_get_client_key_exchange(SSL *s)
n=i;
}
- i=RSA_private_decrypt((int)n,p,p,rsa,RSA_PKCS1_PADDING);
-
- al = -1;
-
- if (i != SSL_MAX_MASTER_KEY_LENGTH)
- {
- al=SSL_AD_DECODE_ERROR;
- /* SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_RSA_DECRYPT); */
- }
-
- if ((al == -1) && !((p[0] == (s->client_version>>8)) && (p[1] == (s->client_version & 0xff))))
+ s->init_off=p-(unsigned char*) s->init_buf->data;
+ s->s3->tmp.reuse_message=1;
+ if ((s->mode & SSL_MODE_ASYNC_KEY_EX) == 0)
{
- /* The premaster secret must contain the same version number as the
- * ClientHello to detect version rollback attacks (strangely, the
- * protocol does not offer such protection for DH ciphersuites).
- * However, buggy clients exist that send the negotiated protocol
- * version instead if the server does not support the requested
- * protocol version.
- * If SSL_OP_TLS_ROLLBACK_BUG is set, tolerate such clients. */
- if (!((s->options & SSL_OP_TLS_ROLLBACK_BUG) &&
- (p[0] == (s->version>>8)) && (p[1] == (s->version & 0xff))))
- {
- al=SSL_AD_DECODE_ERROR;
- /* SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_PROTOCOL_VERSION_NUMBER); */
-
- /* The Klima-Pokorny-Rosa extension of Bleichenbacher's attack
- * (http://eprint.iacr.org/2003/052/) exploits the version
- * number check as a "bad version oracle" -- an alert would
- * reveal that the plaintext corresponding to some ciphertext
- * made up by the adversary is properly formatted except
- * that the version number is wrong. To avoid such attacks,
- * we should treat this just like any other decryption error. */
- }
+ i=RSA_private_decrypt((int)n,p,p,rsa,RSA_PKCS1_PADDING);
+ s->key_ex.len=i;
}
-
- if (al != -1)
+ else
{
- /* Some decryption failure -- use random value instead as countermeasure
- * against Bleichenbacher's attack on PKCS #1 v1.5 RSA padding
- * (see RFC 2246, section 7.4.7.1). */
- ERR_clear_error();
- i = SSL_MAX_MASTER_KEY_LENGTH;
- p[0] = s->client_version >> 8;
- p[1] = s->client_version & 0xff;
- if (RAND_pseudo_bytes(p+2, i-2) <= 0) /* should be RAND_bytes, but we cannot work around a failure */
- goto err;
+ s->key_ex.data=p;
+ s->key_ex.len=n;
}
-
- s->session->master_key_length=
- s->method->ssl3_enc->generate_master_secret(s,
- s->session->master_key,
- p,i);
- OPENSSL_cleanse(p,i);
+ return 3;
}
else
#endif
@@ -2910,6 +2990,68 @@ err:
return(-1);
}
+int ssl3_cont_client_key_exchange(SSL *s)
+ {
+ int i,al;
+ unsigned char *p;
+
+ p=(unsigned char *)s->init_buf->data + s->init_off;
+ al=-1;
+ i=s->key_ex.len;
+ s->s3->tmp.reuse_message=0;
+
+ if (i != SSL_MAX_MASTER_KEY_LENGTH)
+ {
+ al=SSL_AD_DECODE_ERROR;
+ /* SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_RSA_DECRYPT); */
+ }
+
+ if ((al == -1) && !((p[0] == (s->client_version>>8)) && (p[1] == (s->client_version & 0xff))))
+ {
+ /* The premaster secret must contain the same version number as the
+ * ClientHello to detect version rollback attacks (strangely, the
+ * protocol does not offer such protection for DH ciphersuites).
+ * However, buggy clients exist that send the negotiated protocol
+ * version instead if the server does not support the requested
+ * protocol version.
+ * If SSL_OP_TLS_ROLLBACK_BUG is set, tolerate such clients. */
+ if (!((s->options & SSL_OP_TLS_ROLLBACK_BUG) &&
+ (p[0] == (s->version>>8)) && (p[1] == (s->version & 0xff))))
+ {
+ al=SSL_AD_DECODE_ERROR;
+ /* SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_PROTOCOL_VERSION_NUMBER); */
+
+ /* The Klima-Pokorny-Rosa extension of Bleichenbacher's attack
+ * (http://eprint.iacr.org/2003/052/) exploits the version
+ * number check as a "bad version oracle" -- an alert would
+ * reveal that the plaintext corresponding to some ciphertext
+ * made up by the adversary is properly formatted except
+ * that the version number is wrong. To avoid such attacks,
+ * we should treat this just like any other decryption error. */
+ }
+ }
+
+ if (al != -1)
+ {
+ /* Some decryption failure -- use random value instead as countermeasure
+ * against Bleichenbacher's attack on PKCS #1 v1.5 RSA padding
+ * (see RFC 2246, section 7.4.7.1). */
+ ERR_clear_error();
+ i = SSL_MAX_MASTER_KEY_LENGTH;
+ p[0] = s->client_version >> 8;
+ p[1] = s->client_version & 0xff;
+ if (RAND_pseudo_bytes(p+2, i-2) <= 0) /* should be RAND_bytes, but we cannot work around a failure */
+ return -1;
+ }
+
+ s->session->master_key_length=
+ s->method->ssl3_enc->generate_master_secret(s,
+ s->session->master_key,
+ p,i);
+ OPENSSL_cleanse(p,i);
+ return 1;
+ }
+
int ssl3_get_cert_verify(SSL *s)
{
EVP_PKEY *pkey=NULL;
diff --git a/ssl/ssl.h b/ssl/ssl.h
index b73da5e..035447a 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -653,6 +653,31 @@ struct ssl_session_st
*/
#define SSL_MODE_SEND_CLIENTHELLO_TIME 0x00000020L
#define SSL_MODE_SEND_SERVERHELLO_TIME 0x00000040L
+/* If set - SSL_ERROR_WANT_RSA_DECRYPT/SSL_ERROR_WANT_SIGN may be returned
+ * by SSL_read()/SSL_write()/SSL_accept(), when the key exchange requires the
+ * use of the RSA private key.
+ *
+ * In such case following functions should be called in order to get input
+ * data and input length:
+ *
+ * SSL_get_key_ex_data()
+ * SSL_get_key_ex_len()
+ *
+ * In case of SSL_ERROR_WANT_SIGN - SSL_get_key_ex_type() will return the
+ * type of the private key that should be used for signature.
+ * SSL_get_key_ex_md() - for getting the nid of digest. Note that it may return
+ * NID_md5_sha1, which could only be supplied to RSA_sign() and is not accepted
+ * by general EVP methods.
+ *
+ * After performing this operation (decrypt / sign), the output data should be
+ * supplied via:
+ *
+ * SSL_supply_key_ex_data()
+ *
+ * Next either of SSL_accept()/SSL_read()/SSL_write() may be called to continue
+ * the handshake.
+ */
+#define SSL_MODE_ASYNC_KEY_EX 0x00000080L
/* Note: SSL[_CTX]_set_{options,mode} use |= op on the previous value,
* they cannot be used to clear bits. */
@@ -1102,12 +1127,16 @@ const char *SSL_get_psk_identity(const SSL *s);
#define SSL_WRITING 2
#define SSL_READING 3
#define SSL_X509_LOOKUP 4
+#define SSL_RSA_DECRYPT 5
+#define SSL_SIGN 6
/* These will only be used when doing non-blocking IO */
#define SSL_want_nothing(s) (SSL_want(s) == SSL_NOTHING)
#define SSL_want_read(s) (SSL_want(s) == SSL_READING)
#define SSL_want_write(s) (SSL_want(s) == SSL_WRITING)
#define SSL_want_x509_lookup(s) (SSL_want(s) == SSL_X509_LOOKUP)
+#define SSL_want_rsa_decrypt(s) (SSL_want(s) == SSL_RSA_DECRYPT)
+#define SSL_want_sign(s) (SSL_want(s) == SSL_SIGN)
#define SSL_MAC_FLAG_READ_MAC_STREAM 1
#define SSL_MAC_FLAG_WRITE_MAC_STREAM 2
@@ -1364,6 +1393,16 @@ struct ssl_st
#ifndef OPENSSL_NO_SRP
SRP_CTX srp_ctx; /* ctx for SRP authentication */
#endif
+ struct {
+ /* Input data for key exchange */
+ unsigned char* data;
+ /* Input length */
+ long len;
+ /* Digest type for signature */
+ int md;
+ /* EVP_PKEY type */
+ int type;
+ } key_ex;
};
#endif
@@ -1451,6 +1490,27 @@ size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count);
#define OpenSSL_add_ssl_algorithms() SSL_library_init()
#define SSLeay_add_ssl_algorithms() SSL_library_init()
+/*
+ * Async key exchange methods
+ * See SSL_MODE_ASYNC_KEY_EX for detailed documentation
+ */
+
+/* Input data for async key exchange */
+const unsigned char* SSL_get_key_ex_data(const SSL *s);
+
+/* Input length for async key exchange */
+long SSL_get_key_ex_len(const SSL *s);
+
+/* Signature digest algorithm NID */
+int SSL_get_key_ex_md(const SSL *s);
+
+/* Signature private key type, EVP_PKEY_RSA/EVP_PKEY_ECC/... */
+int SSL_get_key_ex_type(const SSL *s);
+
+int SSL_supply_key_ex_data(SSL* s, unsigned char* data, long len);
+/* Supply the key exchange data */
+int SSL_supply_key_ex_data(SSL *s, unsigned char *data, long len);
+
/* this is for backward compatibility */
#if 0 /* NEW_SSLEAY */
#define SSL_CTX_set_default_verify(a,b,c) SSL_CTX_set_verify(a,b,c)
@@ -1521,6 +1581,8 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
#define SSL_ERROR_ZERO_RETURN 6
#define SSL_ERROR_WANT_CONNECT 7
#define SSL_ERROR_WANT_ACCEPT 8
+#define SSL_ERROR_WANT_RSA_DECRYPT 9
+#define SSL_ERROR_WANT_SIGN 10
#define SSL_CTRL_NEED_TMP_RSA 1
#define SSL_CTRL_SET_TMP_RSA 2
diff --git a/ssl/ssl3.h b/ssl/ssl3.h
index 37f19e3..b69ffec 100644
--- a/ssl/ssl3.h
+++ b/ssl/ssl3.h
@@ -628,6 +628,9 @@ typedef struct ssl3_state_st
#define SSL3_ST_SW_CERT_B (0x141|SSL_ST_ACCEPT)
#define SSL3_ST_SW_KEY_EXCH_A (0x150|SSL_ST_ACCEPT)
#define SSL3_ST_SW_KEY_EXCH_B (0x151|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_KEY_EXCH_C (0x152|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_KEY_EXCH_SIGN_WAIT (0x153|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_KEY_EXCH_SIGN_SUPPLY (0x154|SSL_ST_ACCEPT)
#define SSL3_ST_SW_CERT_REQ_A (0x160|SSL_ST_ACCEPT)
#define SSL3_ST_SW_CERT_REQ_B (0x161|SSL_ST_ACCEPT)
#define SSL3_ST_SW_SRVR_DONE_A (0x170|SSL_ST_ACCEPT)
@@ -637,6 +640,9 @@ typedef struct ssl3_state_st
#define SSL3_ST_SR_CERT_B (0x181|SSL_ST_ACCEPT)
#define SSL3_ST_SR_KEY_EXCH_A (0x190|SSL_ST_ACCEPT)
#define SSL3_ST_SR_KEY_EXCH_B (0x191|SSL_ST_ACCEPT)
+#define SSL3_ST_SR_KEY_EXCH_C (0x192|SSL_ST_ACCEPT)
+#define SSL3_ST_SR_KEY_EXCH_RSA_DECRYPT_WAIT (0x193|SSL_ST_ACCEPT)
+#define SSL3_ST_SR_KEY_EXCH_RSA_DECRYPT_SUPPLY (0x194|SSL_ST_ACCEPT)
#define SSL3_ST_SR_CERT_VRFY_A (0x1A0|SSL_ST_ACCEPT)
#define SSL3_ST_SR_CERT_VRFY_B (0x1A1|SSL_ST_ACCEPT)
#define SSL3_ST_SR_CHANGE_A (0x1B0|SSL_ST_ACCEPT)
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 82a2c80..3787bed 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -760,6 +760,55 @@ size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count)
}
+const unsigned char* SSL_get_key_ex_data(const SSL *s)
+ {
+ return s->key_ex.data;
+ }
+
+
+long SSL_get_key_ex_len(const SSL *s)
+ {
+ return s->key_ex.len;
+ }
+
+
+int SSL_get_key_ex_md(const SSL *s)
+ {
+ return s->key_ex.md;
+ }
+
+
+int SSL_get_key_ex_type(const SSL *s)
+ {
+ return s->key_ex.type;
+ }
+
+
+int SSL_supply_key_ex_data(SSL* s, unsigned char* data, long len)
+ {
+ if (s->s3 == NULL)
+ return 0;
+
+ switch (s->state) {
+ case SSL3_ST_SR_KEY_EXCH_RSA_DECRYPT_WAIT:
+ s->state=SSL3_ST_SR_KEY_EXCH_RSA_DECRYPT_SUPPLY;
+ break;
+ case SSL3_ST_SW_KEY_EXCH_SIGN_WAIT:
+ s->state=SSL3_ST_SW_KEY_EXCH_SIGN_SUPPLY;
+ break;
+ default:
+ return 0;
+ }
+ BIO_set_flags(SSL_get_rbio(s), 0);
+ /* Copy the data right into the message */
+ memcpy(s->init_buf->data + s->init_off, data, len);
+ s->key_ex.data=NULL;
+ /* The length is needed for RSA_DECRYPT case */
+ s->key_ex.len=len;
+ return 1;
+ }
+
+
int SSL_get_verify_mode(const SSL *s)
{
return(s->verify_mode);
@@ -2538,7 +2587,14 @@ int SSL_get_error(const SSL *s,int i)
{
return(SSL_ERROR_WANT_X509_LOOKUP);
}
-
+ if ((i < 0) && SSL_want_rsa_decrypt(s))
+ {
+ return(SSL_ERROR_WANT_RSA_DECRYPT);
+ }
+ if ((i < 0) && SSL_want_sign(s))
+ {
+ return(SSL_ERROR_WANT_SIGN);
+ }
if (i == 0)
{
if (s->version == SSL2_VERSION)
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 98888d2..9f2e2ab 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -1030,11 +1030,13 @@ int ssl3_get_client_hello(SSL *s);
int ssl3_send_server_hello(SSL *s);
int ssl3_send_hello_request(SSL *s);
int ssl3_send_server_key_exchange(SSL *s);
+int ssl3_cont_server_key_exchange(SSL *s);
int ssl3_send_certificate_request(SSL *s);
int ssl3_send_server_done(SSL *s);
int ssl3_check_client_hello(SSL *s);
int ssl3_get_client_certificate(SSL *s);
int ssl3_get_client_key_exchange(SSL *s);
+int ssl3_cont_client_key_exchange(SSL *s);
int ssl3_get_cert_verify(SSL *s);
#ifndef OPENSSL_NO_NEXTPROTONEG
int ssl3_get_next_proto(SSL *s);
diff --git a/ssl/ssl_rsa.c b/ssl/ssl_rsa.c
index 60e7b66..a56aa55 100644
--- a/ssl/ssl_rsa.c
+++ b/ssl/ssl_rsa.c
@@ -64,8 +64,8 @@
#include <openssl/x509.h>
#include <openssl/pem.h>
-static int ssl_set_cert(CERT *c, X509 *x509);
-static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey);
+static int ssl_set_cert(CERT *c, X509 *x509, int force);
+static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey, int force);
int SSL_use_certificate(SSL *ssl, X509 *x)
{
if (x == NULL)
@@ -78,7 +78,7 @@ int SSL_use_certificate(SSL *ssl, X509 *x)
SSLerr(SSL_F_SSL_USE_CERTIFICATE,ERR_R_MALLOC_FAILURE);
return(0);
}
- return(ssl_set_cert(ssl->cert,x));
+ return(ssl_set_cert(ssl->cert,x,ssl->mode & SSL_MODE_ASYNC_KEY_EX));
}
#ifndef OPENSSL_NO_STDIO
@@ -173,13 +173,13 @@ int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa)
RSA_up_ref(rsa);
EVP_PKEY_assign_RSA(pkey,rsa);
- ret=ssl_set_pkey(ssl->cert,pkey);
+ ret=ssl_set_pkey(ssl->cert,pkey,ssl->mode & SSL_MODE_ASYNC_KEY_EX);
EVP_PKEY_free(pkey);
return(ret);
}
#endif
-static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey)
+static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey, int force)
{
int i;
@@ -206,7 +206,7 @@ static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey)
;
else
#endif
- if (!X509_check_private_key(c->pkeys[i].x509,pkey))
+ if (!force && !X509_check_private_key(c->pkeys[i].x509,pkey))
{
X509_free(c->pkeys[i].x509);
c->pkeys[i].x509 = NULL;
@@ -306,7 +306,7 @@ int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey)
SSLerr(SSL_F_SSL_USE_PRIVATEKEY,ERR_R_MALLOC_FAILURE);
return(0);
}
- ret=ssl_set_pkey(ssl->cert,pkey);
+ ret=ssl_set_pkey(ssl->cert,pkey,ssl->mode & SSL_MODE_ASYNC_KEY_EX);
return(ret);
}
@@ -388,10 +388,10 @@ int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x)
SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE,ERR_R_MALLOC_FAILURE);
return(0);
}
- return(ssl_set_cert(ctx->cert, x));
+ return(ssl_set_cert(ctx->cert, x,ctx->mode & SSL_MODE_ASYNC_KEY_EX));
}
-static int ssl_set_cert(CERT *c, X509 *x)
+static int ssl_set_cert(CERT *c, X509 *x, int force)
{
EVP_PKEY *pkey;
int i;
@@ -425,7 +425,7 @@ static int ssl_set_cert(CERT *c, X509 *x)
;
else
#endif /* OPENSSL_NO_RSA */
- if (!X509_check_private_key(x,c->pkeys[i].privatekey))
+ if (!force && !X509_check_private_key(x,c->pkeys[i].privatekey))
{
/* don't fail for a cert/key mismatch, just free
* current private key (when switching to a different
@@ -542,7 +542,7 @@ int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa)
RSA_up_ref(rsa);
EVP_PKEY_assign_RSA(pkey,rsa);
- ret=ssl_set_pkey(ctx->cert, pkey);
+ ret=ssl_set_pkey(ctx->cert, pkey,ctx->mode & SSL_MODE_ASYNC_KEY_EX);
EVP_PKEY_free(pkey);
return(ret);
}
@@ -626,7 +626,7 @@ int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey)
SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY,ERR_R_MALLOC_FAILURE);
return(0);
}
- return(ssl_set_pkey(ctx->cert,pkey));
+ return(ssl_set_pkey(ctx->cert,pkey,ctx->mode & SSL_MODE_ASYNC_KEY_EX));
}
#ifndef OPENSSL_NO_STDIO
diff --git a/ssl/ssltest.c b/ssl/ssltest.c
index 4f80be8..9924b1d 100644
--- a/ssl/ssltest.c
+++ b/ssl/ssltest.c
@@ -224,6 +224,7 @@ static void free_tmp_rsa(void);
#endif
static int MS_CALLBACK app_verify_callback(X509_STORE_CTX *ctx, void *arg);
#define APP_CALLBACK_STRING "Test Callback Argument"
+static int handle_async_key_ex(SSL *s);
struct app_verify_arg
{
char *string;
@@ -369,6 +370,7 @@ static void sv_usage(void)
" (default is sect163r2).\n");
#endif
fprintf(stderr," -test_cipherlist - verifies the order of the ssl cipher lists\n");
+ fprintf(stderr," -async_key_ex - use SSL_MODE_ASYNC_KEY_EX\n");
}
static void print_details(SSL *c_ssl, const char *prefix)
@@ -549,6 +551,7 @@ int main(int argc, char *argv[])
#ifdef OPENSSL_FIPS
int fips_mode=0;
#endif
+ int async_key_ex=0;
verbose = 0;
debug = 0;
@@ -765,6 +768,10 @@ int main(int argc, char *argv[])
{
test_cipherlist = 1;
}
+ else if (strcmp(*argv,"-async_key_ex") == 0)
+ {
+ async_key_ex=1;
+ }
else
{
fprintf(stderr,"unknown option %s\n",*argv);
@@ -963,6 +970,13 @@ bad:
(void)no_ecdhe;
#endif
+ if (async_key_ex)
+ {
+ long mode;
+ mode = SSL_CTX_get_mode(s_ctx);
+ SSL_CTX_set_mode(s_ctx, mode | SSL_MODE_ASYNC_KEY_EX);
+ }
+
#ifndef OPENSSL_NO_RSA
SSL_CTX_set_tmp_rsa_callback(s_ctx,tmp_rsa_cb);
#endif
@@ -1335,7 +1349,9 @@ int doit_biopair(SSL *s_ssl, SSL *c_ssl, long count,
i = sizeof sbuf;
else
i = (int)sw_num;
- r = BIO_write(s_ssl_bio, sbuf, i);
+ do
+ r = BIO_write(s_ssl_bio, sbuf, i);
+ while (r < 0 && handle_async_key_ex(s_ssl));
if (r < 0)
{
if (!BIO_should_retry(s_ssl_bio))
@@ -1362,7 +1378,9 @@ int doit_biopair(SSL *s_ssl, SSL *c_ssl, long count,
{
/* Read from client. */
- r = BIO_read(s_ssl_bio, sbuf, sizeof(sbuf));
+ do
+ r = BIO_read(s_ssl_bio, sbuf, sizeof(sbuf));
+ while (r < 0 && handle_async_key_ex(s_ssl));
if (r < 0)
{
if (!BIO_should_retry(s_ssl_bio))
@@ -1725,7 +1743,9 @@ int doit(SSL *s_ssl, SSL *c_ssl, long count)
{
if (!s_write)
{
- i=BIO_read(s_bio,sbuf,sizeof(cbuf));
+ do
+ i=BIO_read(s_bio,sbuf,sizeof(cbuf));
+ while (i < 0 && handle_async_key_ex(s_ssl));
if (i < 0)
{
s_r=0;
@@ -1772,7 +1792,9 @@ int doit(SSL *s_ssl, SSL *c_ssl, long count)
{
j = (sw_num > (long)sizeof(sbuf)) ?
(int)sizeof(sbuf) : (int)sw_num;
- i=BIO_write(s_bio,sbuf,j);
+ do
+ i=BIO_write(s_bio,sbuf,j);
+ while (i < 0 && handle_async_key_ex(s_ssl));
if (i < 0)
{
s_r=0;
@@ -2581,3 +2603,98 @@ static int do_test_cipherlist(void)
return 1;
}
+
+static unsigned char buf[1024];
+
+static int handle_async_key_ex(SSL *s)
+ {
+ EVP_PKEY* pkey;
+ if (!(SSL_get_mode(s) & SSL_MODE_ASYNC_KEY_EX))
+ return 0;
+
+ fprintf(stderr, "performing async key ex\n");
+
+ pkey = SSL_get_privatekey(s);
+ if (pkey == NULL)
+ {
+ fprintf(stderr, "async key ex: no private key\n");
+ return 0;
+ }
+
+ if (SSL_want_sign(s) && SSL_get_key_ex_md(s) == NID_md5_sha1)
+ {
+ assert(SSL_get_key_ex_type(s) == EVP_PKEY_RSA);
+ unsigned int len;
+ if (pkey->type != EVP_PKEY_RSA)
+ {
+ fprintf(stderr, "async key ex: non-rsa private key for sign\n");
+ return 0;
+ }
+ if (RSA_sign(NID_md5_sha1,
+ SSL_get_key_ex_data(s),
+ SSL_get_key_ex_len(s),
+ buf,
+ &len,
+ pkey->pkey.rsa) <= 0)
+ {
+ fprintf(stderr, "async key ex: rsa sign failure\n");
+ return 0;
+ }
+ if (!SSL_supply_key_ex_data(s, buf, len))
+ return 0;
+ return SSL_accept(s);
+ }
+ if (SSL_want_sign(s) && SSL_get_key_ex_md(s) != NID_md5_sha1)
+ {
+ assert(SSL_get_key_ex_type(s) == pkey->type);
+ EVP_MD_CTX md_ctx;
+ const EVP_MD *md = NULL;
+ unsigned int len;
+
+ md = EVP_get_digestbynid(SSL_get_key_ex_md(s));
+ if (md == NULL)
+ {
+ fprintf(stderr, "async key ex: md not found\n");
+ return 0;
+ }
+
+ EVP_MD_CTX_init(&md_ctx);
+
+ EVP_SignInit_ex(&md_ctx, md, NULL);
+ EVP_SignUpdate(&md_ctx, SSL_get_key_ex_data(s), SSL_get_key_ex_len(s));
+ len = sizeof(buf);
+ if (!EVP_SignFinal(&md_ctx, buf, &len, pkey))
+ {
+ fprintf(stderr, "async key ex: sign failure\n");
+ return 0;
+ }
+
+ if (!SSL_supply_key_ex_data(s, buf, len))
+ return 0;
+ return SSL_accept(s);
+ }
+ if (SSL_want_rsa_decrypt(s))
+ {
+ int len;
+ if (pkey->type != EVP_PKEY_RSA)
+ {
+ fprintf(stderr, "async key ex: non-rsa private key for decryption\n");
+ return 0;
+ }
+ len = RSA_private_decrypt(SSL_get_key_ex_len(s),
+ SSL_get_key_ex_data(s),
+ buf,
+ pkey->pkey.rsa,
+ RSA_PKCS1_PADDING);
+ if (len == -1)
+ {
+ fprintf(stderr, "async key ex: rsa decrypt failed\n");
+ return 0;
+ }
+
+ if (!SSL_supply_key_ex_data(s, buf, len))
+ return 0;
+ return SSL_accept(s);
+ }
+ return 0;
+ }
diff --git a/test/testssl b/test/testssl
index 9fb89a3..d8810be 100644
--- a/test/testssl
+++ b/test/testssl
@@ -35,6 +35,9 @@ fi
echo test sslv2
$ssltest -ssl2 $extra || exit 1
+echo test sslv3 with async key ex
+$ssltest -ssl3 -async_key_ex $extra || exit 1
+
echo test sslv2 with server authentication
$ssltest -ssl2 -server_auth $CA $extra || exit 1
@@ -165,6 +168,9 @@ $ssltest -tls1 -cipher PSK -psk abc123 $extra || exit 1
echo test tls1 with PSK via BIO pair
$ssltest -bio_pair -tls1 -cipher PSK -psk abc123 $extra || exit 1
+echo test tls1 with async key ex
+$ssltest -tls1 -async_key_ex $extra || exit 1
+
if ../util/shlib_wrap.sh ../apps/openssl no-srp; then
echo skipping SRP tests
else
@passuf
Copy link

passuf commented Mar 10, 2017

Sorry if this is the wrong place to ask, I'm coming from this ycombinator.com discussion from 2014.

Has there been any interest from the OpenSSL team or is there any progress about the idea of offloading the key to a remote server? I would like to do a similar thing where a server running on iOS has to accept SSL/TLS connections without the possession of the key.

Thanks a lot for a short update!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment