Add server-side support for asynchronous signing.
The RSA key exchange needs decryption and is still unsupported. Change-Id: I8c13b74e25a5424356afbe6e97b5f700a56de41f Reviewed-on: https://boringssl-review.googlesource.com/5467 Reviewed-by: Adam Langley <agl@google.com>
This commit is contained in:
parent
0950563a9b
commit
601448aa13
@ -634,6 +634,8 @@ 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_D (0x153 | 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)
|
||||
|
@ -246,6 +246,8 @@ int dtls1_accept(SSL *s) {
|
||||
|
||||
case SSL3_ST_SW_KEY_EXCH_A:
|
||||
case SSL3_ST_SW_KEY_EXCH_B:
|
||||
case SSL3_ST_SW_KEY_EXCH_C:
|
||||
case SSL3_ST_SW_KEY_EXCH_D:
|
||||
alg_a = s->s3->tmp.new_cipher->algorithm_auth;
|
||||
|
||||
/* Send a ServerKeyExchange message if:
|
||||
|
@ -346,6 +346,10 @@ int SSL_AEAD_CTX_seal(SSL_AEAD_CTX *ctx, uint8_t *out, size_t *out_len,
|
||||
|
||||
/* Private key operations. */
|
||||
|
||||
/* ssl_has_private_key returns one if |ssl| has a private key
|
||||
* configured and zero otherwise. */
|
||||
int ssl_has_private_key(SSL *ssl);
|
||||
|
||||
/* ssl_private_key_* call the corresponding function on the
|
||||
* |SSL_PRIVATE_KEY_METHOD| for |ssl|, if configured. Otherwise, they implement
|
||||
* the operation with |EVP_PKEY|. */
|
||||
|
@ -1959,7 +1959,7 @@ int ssl3_send_cert_verify(SSL *s) {
|
||||
uint8_t *p = ssl_handshake_start(s);
|
||||
size_t signature_length = 0;
|
||||
unsigned long n = 0;
|
||||
assert(s->cert->privatekey != NULL || s->cert->key_method != NULL);
|
||||
assert(ssl_has_private_key(s));
|
||||
|
||||
if (s->state == SSL3_ST_CW_CERT_VRFY_A) {
|
||||
uint8_t *buf = (uint8_t *)s->init_buf->data;
|
||||
@ -2036,8 +2036,7 @@ int ssl3_send_cert_verify(SSL *s) {
|
||||
/* ssl3_has_client_certificate returns true if a client certificate is
|
||||
* configured. */
|
||||
static int ssl3_has_client_certificate(SSL *ssl) {
|
||||
return ssl->cert && ssl->cert->x509 && (ssl->cert->privatekey ||
|
||||
ssl->cert->key_method);
|
||||
return ssl->cert && ssl->cert->x509 && ssl_has_private_key(ssl);
|
||||
}
|
||||
|
||||
int ssl3_send_client_certificate(SSL *s) {
|
||||
|
@ -312,6 +312,8 @@ int ssl3_accept(SSL *s) {
|
||||
|
||||
case SSL3_ST_SW_KEY_EXCH_A:
|
||||
case SSL3_ST_SW_KEY_EXCH_B:
|
||||
case SSL3_ST_SW_KEY_EXCH_C:
|
||||
case SSL3_ST_SW_KEY_EXCH_D:
|
||||
alg_a = s->s3->tmp.new_cipher->algorithm_auth;
|
||||
|
||||
/* Send a ServerKeyExchange message if:
|
||||
@ -1247,7 +1249,8 @@ int ssl3_send_server_key_exchange(SSL *s) {
|
||||
BN_CTX *bn_ctx = NULL;
|
||||
const char *psk_identity_hint = NULL;
|
||||
size_t psk_identity_hint_len = 0;
|
||||
EVP_PKEY *pkey;
|
||||
size_t sig_len;
|
||||
size_t max_sig_len;
|
||||
uint8_t *p, *d;
|
||||
int al, i;
|
||||
uint32_t alg_k;
|
||||
@ -1255,10 +1258,20 @@ int ssl3_send_server_key_exchange(SSL *s) {
|
||||
int n;
|
||||
CERT *cert;
|
||||
BIGNUM *r[4];
|
||||
int nr[4], kn;
|
||||
int nr[4];
|
||||
BUF_MEM *buf;
|
||||
EVP_MD_CTX md_ctx;
|
||||
|
||||
if (ssl_cipher_has_server_public_key(s->s3->tmp.new_cipher)) {
|
||||
if (!ssl_has_private_key(s)) {
|
||||
al = SSL_AD_INTERNAL_ERROR;
|
||||
goto f_err;
|
||||
}
|
||||
max_sig_len = ssl_private_key_max_signature_len(s);
|
||||
} else {
|
||||
max_sig_len = 0;
|
||||
}
|
||||
|
||||
EVP_MD_CTX_init(&md_ctx);
|
||||
if (s->state == SSL3_ST_SW_KEY_EXCH_A) {
|
||||
alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
|
||||
@ -1400,19 +1413,7 @@ int ssl3_send_server_key_exchange(SSL *s) {
|
||||
n += 2 + nr[i];
|
||||
}
|
||||
|
||||
if (ssl_cipher_has_server_public_key(s->s3->tmp.new_cipher)) {
|
||||
pkey = s->cert->privatekey;
|
||||
if (pkey == NULL) {
|
||||
al = SSL_AD_DECODE_ERROR;
|
||||
goto f_err;
|
||||
}
|
||||
kn = EVP_PKEY_size(pkey);
|
||||
} else {
|
||||
pkey = NULL;
|
||||
kn = 0;
|
||||
}
|
||||
|
||||
if (!BUF_MEM_grow_clean(buf, n + SSL_HM_HEADER_LENGTH(s) + kn)) {
|
||||
if (!BUF_MEM_grow_clean(buf, n + SSL_HM_HEADER_LENGTH(s) + max_sig_len)) {
|
||||
OPENSSL_PUT_ERROR(SSL, ERR_LIB_BUF);
|
||||
goto err;
|
||||
}
|
||||
@ -1453,11 +1454,14 @@ int ssl3_send_server_key_exchange(SSL *s) {
|
||||
}
|
||||
|
||||
/* not anonymous */
|
||||
if (pkey != NULL) {
|
||||
/* n is the length of the params, they start at &(d[4]) and p points to
|
||||
if (ssl_cipher_has_server_public_key(s->s3->tmp.new_cipher)) {
|
||||
/* n is the length of the params, they start at d and p points to
|
||||
* the space at the end. */
|
||||
const EVP_MD *md;
|
||||
size_t sig_len = EVP_PKEY_size(pkey);
|
||||
uint8_t digest[EVP_MAX_MD_SIZE];
|
||||
unsigned int digest_length;
|
||||
|
||||
const int pkey_type = ssl_private_key_type(s);
|
||||
|
||||
/* Determine signature algorithm. */
|
||||
if (SSL_USE_SIGALGS(s)) {
|
||||
@ -1469,36 +1473,66 @@ int ssl3_send_server_key_exchange(SSL *s) {
|
||||
goto f_err;
|
||||
}
|
||||
p += 2;
|
||||
} else if (pkey->type == EVP_PKEY_RSA) {
|
||||
} else if (pkey_type == EVP_PKEY_RSA) {
|
||||
md = EVP_md5_sha1();
|
||||
} else {
|
||||
md = EVP_sha1();
|
||||
}
|
||||
|
||||
if (!EVP_DigestSignInit(&md_ctx, NULL, md, NULL, pkey) ||
|
||||
!EVP_DigestSignUpdate(&md_ctx, s->s3->client_random,
|
||||
SSL3_RANDOM_SIZE) ||
|
||||
!EVP_DigestSignUpdate(&md_ctx, s->s3->server_random,
|
||||
SSL3_RANDOM_SIZE) ||
|
||||
!EVP_DigestSignUpdate(&md_ctx, d, n) ||
|
||||
!EVP_DigestSignFinal(&md_ctx, &p[2], &sig_len)) {
|
||||
if (!EVP_DigestInit_ex(&md_ctx, md, NULL) ||
|
||||
!EVP_DigestUpdate(&md_ctx, s->s3->client_random, SSL3_RANDOM_SIZE) ||
|
||||
!EVP_DigestUpdate(&md_ctx, s->s3->server_random, SSL3_RANDOM_SIZE) ||
|
||||
!EVP_DigestUpdate(&md_ctx, d, n) ||
|
||||
!EVP_DigestFinal_ex(&md_ctx, digest, &digest_length)) {
|
||||
OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP);
|
||||
goto err;
|
||||
}
|
||||
|
||||
s2n(sig_len, p);
|
||||
n += sig_len + 2;
|
||||
if (SSL_USE_SIGALGS(s)) {
|
||||
n += 2;
|
||||
const enum ssl_private_key_result_t sign_result = ssl_private_key_sign(
|
||||
s, &p[2], &sig_len, max_sig_len, EVP_MD_CTX_md(&md_ctx),
|
||||
digest, digest_length);
|
||||
if (sign_result == ssl_private_key_retry) {
|
||||
s->rwstate = SSL_PRIVATE_KEY_OPERATION;
|
||||
/* Stash away |p|. */
|
||||
s->init_num = p - ssl_handshake_start(s) + SSL_HM_HEADER_LENGTH(s);
|
||||
s->state = SSL3_ST_SW_KEY_EXCH_B;
|
||||
goto err;
|
||||
} else if (sign_result != ssl_private_key_success) {
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ssl_set_handshake_header(s, SSL3_MT_SERVER_KEY_EXCHANGE, n)) {
|
||||
s->state = SSL3_ST_SW_KEY_EXCH_C;
|
||||
} else if (s->state == SSL3_ST_SW_KEY_EXCH_B) {
|
||||
/* Complete async sign. */
|
||||
/* Restore |p|. */
|
||||
p = ssl_handshake_start(s) + s->init_num - SSL_HM_HEADER_LENGTH(s);
|
||||
const enum ssl_private_key_result_t sign_result =
|
||||
ssl_private_key_sign_complete(s, &p[2], &sig_len, max_sig_len);
|
||||
if (sign_result == ssl_private_key_retry) {
|
||||
s->rwstate = SSL_PRIVATE_KEY_OPERATION;
|
||||
goto err;
|
||||
} else if (sign_result != ssl_private_key_success) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
s->rwstate = SSL_NOTHING;
|
||||
s->state = SSL3_ST_SW_KEY_EXCH_C;
|
||||
}
|
||||
|
||||
s->state = SSL3_ST_SW_KEY_EXCH_B;
|
||||
if (s->state == SSL3_ST_SW_KEY_EXCH_C) {
|
||||
if (ssl_cipher_has_server_public_key(s->s3->tmp.new_cipher)) {
|
||||
s2n(sig_len, p);
|
||||
p += sig_len;
|
||||
}
|
||||
if (!ssl_set_handshake_header(s, SSL3_MT_SERVER_KEY_EXCHANGE,
|
||||
p - ssl_handshake_start(s))) {
|
||||
goto err;
|
||||
}
|
||||
s->state = SSL3_ST_SW_KEY_EXCH_D;
|
||||
}
|
||||
|
||||
/* state SSL3_ST_SW_KEY_EXCH_D */
|
||||
EVP_MD_CTX_cleanup(&md_ctx);
|
||||
return ssl_do_write(s);
|
||||
|
||||
|
@ -1834,13 +1834,14 @@ void ssl_get_compatible_server_ciphers(SSL *s, uint32_t *out_mask_k,
|
||||
|
||||
dh_tmp = (c->dh_tmp != NULL || c->dh_tmp_cb != NULL);
|
||||
|
||||
if (s->cert->x509 != NULL && s->cert->privatekey != NULL) {
|
||||
if (s->cert->privatekey->type == EVP_PKEY_RSA) {
|
||||
if (s->cert->x509 != NULL && ssl_has_private_key(s)) {
|
||||
if (ssl_private_key_type(s) == EVP_PKEY_RSA) {
|
||||
have_rsa_cert = 1;
|
||||
} else if (s->cert->privatekey->type == EVP_PKEY_EC) {
|
||||
} else if (ssl_private_key_type(s) == EVP_PKEY_EC) {
|
||||
have_ecc_cert = 1;
|
||||
}
|
||||
}
|
||||
|
||||
mask_k = 0;
|
||||
mask_a = 0;
|
||||
|
||||
|
@ -632,6 +632,10 @@ void SSL_set_private_key_method(SSL *ssl,
|
||||
ssl->cert->key_method = key_method;
|
||||
}
|
||||
|
||||
int ssl_has_private_key(SSL *ssl) {
|
||||
return ssl->cert->privatekey != NULL || ssl->cert->key_method != NULL;
|
||||
}
|
||||
|
||||
int ssl_private_key_type(SSL *ssl) {
|
||||
if (ssl->cert->key_method != NULL) {
|
||||
return ssl->cert->key_method->type(ssl);
|
||||
|
@ -205,6 +205,7 @@ static ssl_private_key_result_t AsyncPrivateKeySignComplete(
|
||||
}
|
||||
memcpy(out, bssl::vector_data(&test_state->signature),
|
||||
test_state->signature.size());
|
||||
*out_len = test_state->signature.size();
|
||||
|
||||
test_state->signature.clear();
|
||||
test_state->signature_retries = 0;
|
||||
|
@ -2234,6 +2234,24 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol)
|
||||
"-use-async-private-key",
|
||||
},
|
||||
})
|
||||
tests = append(tests, testCase{
|
||||
testType: serverTest,
|
||||
name: "Basic-Server-RSAAsyncKey",
|
||||
flags: []string{
|
||||
"-cert-file", path.Join(*resourceDir, rsaCertificateFile),
|
||||
"-key-file", path.Join(*resourceDir, rsaKeyFile),
|
||||
"-use-async-private-key",
|
||||
},
|
||||
})
|
||||
tests = append(tests, testCase{
|
||||
testType: serverTest,
|
||||
name: "Basic-Server-ECDSAAsyncKey",
|
||||
flags: []string{
|
||||
"-cert-file", path.Join(*resourceDir, ecdsaCertificateFile),
|
||||
"-key-file", path.Join(*resourceDir, ecdsaKeyFile),
|
||||
"-use-async-private-key",
|
||||
},
|
||||
})
|
||||
}
|
||||
tests = append(tests, testCase{
|
||||
testType: serverTest,
|
||||
|
Loading…
Reference in New Issue
Block a user