Add APIs to extract the SSL key block.
This is a companion to SSL_get_rc4_state and SSL_get_ivs which doesn't
require poking at internal state. Partly since it aligns with the
current code and partly the off chance we ever need to get
wpa_supplicant's EAP-FAST code working, the API allows one to generate
more key material than is actually in the key block.
Change-Id: I58bc3f2b017482dbb8567dcd0cd754947a95397f
Reviewed-on: https://boringssl-review.googlesource.com/6839
Reviewed-by: Adam Langley <alangley@gmail.com>
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index be48995..af1f7b8 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -2592,6 +2592,14 @@
const uint8_t **out_write_iv,
size_t *out_iv_len);
+/* SSL_get_key_block_len returns the length of |ssl|'s key block. */
+OPENSSL_EXPORT size_t SSL_get_key_block_len(const SSL *ssl);
+
+/* SSL_generate_key_block generates |out_len| bytes of key material for |ssl|'s
+ * current connection state. */
+OPENSSL_EXPORT int SSL_generate_key_block(const SSL *ssl, uint8_t *out,
+ size_t out_len);
+
/* SSL_get_structure_sizes returns the sizes of the SSL, SSL_CTX and
* SSL_SESSION structures so that a test can ensure that outside code agrees on
* these values. */
diff --git a/ssl/internal.h b/ssl/internal.h
index 0057235..84d66aa 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -852,8 +852,14 @@
/* This is for the SSLv3/TLSv1.0 differences in crypto/hash stuff It is a bit
* of a mess of functions, but hell, think of it as an opaque structure. */
struct ssl3_enc_method {
- int (*prf)(SSL *, uint8_t *, size_t, const uint8_t *, size_t, const char *,
- size_t, const uint8_t *, size_t, const uint8_t *, size_t);
+ /* prf computes the PRF function for |ssl|. It writes |out_len| bytes to
+ * |out|, using |secret| as the secret and |label| as the label. |seed1| and
+ * |seed2| are concatenated to form the seed parameter. It returns one on
+ * success and zero on failure. */
+ int (*prf)(const SSL *ssl, uint8_t *out, size_t out_len,
+ const uint8_t *secret, size_t secret_len, const char *label,
+ size_t label_len, const uint8_t *seed1, size_t seed1_len,
+ const uint8_t *seed2, size_t seed2_len);
int (*final_finish_mac)(SSL *ssl, int from_server, uint8_t *out);
int (*cert_verify_mac)(SSL *, int, uint8_t *);
int (*alert_value)(int);
@@ -1032,9 +1038,9 @@
int ssl3_send_certificate_status(SSL *ssl);
int ssl3_get_finished(SSL *ssl, int state_a, int state_b);
int ssl3_send_change_cipher_spec(SSL *ssl, int state_a, int state_b);
-int ssl3_prf(SSL *ssl, uint8_t *out, size_t out_len, const uint8_t *secret,
- size_t secret_len, const char *label, size_t label_len,
- const uint8_t *seed1, size_t seed1_len,
+int ssl3_prf(const SSL *ssl, uint8_t *out, size_t out_len,
+ const uint8_t *secret, size_t secret_len, const char *label,
+ size_t label_len, const uint8_t *seed1, size_t seed1_len,
const uint8_t *seed2, size_t seed2_len);
void ssl3_cleanup_key_block(SSL *ssl);
int ssl3_do_write(SSL *ssl, int type);
@@ -1155,14 +1161,9 @@
int ssl_init_wbio_buffer(SSL *ssl, int push);
void ssl_free_wbio_buffer(SSL *ssl);
-/* tls1_prf computes the TLS PRF function for |ssl| as described in RFC 5246,
- * section 5 and RFC 2246 section 5. It writes |out_len| bytes to |out|, using
- * |secret| as the secret and |label| as the label. |seed1| and |seed2| are
- * concatenated to form the seed parameter. It returns one on success and zero
- * on failure. */
-int tls1_prf(SSL *ssl, uint8_t *out, size_t out_len, const uint8_t *secret,
- size_t secret_len, const char *label, size_t label_len,
- const uint8_t *seed1, size_t seed1_len,
+int tls1_prf(const SSL *ssl, uint8_t *out, size_t out_len,
+ const uint8_t *secret, size_t secret_len, const char *label,
+ size_t label_len, const uint8_t *seed1, size_t seed1_len,
const uint8_t *seed2, size_t seed2_len);
int tls1_change_cipher_state(SSL *ssl, int which);
@@ -1288,7 +1289,7 @@
* the wire version except at API boundaries. */
uint16_t ssl3_version_from_wire(SSL *ssl, uint16_t wire_version);
-uint32_t ssl_get_algorithm_prf(SSL *ssl);
+uint32_t ssl_get_algorithm_prf(const SSL *ssl);
int tls1_parse_peer_sigalgs(SSL *ssl, const CBS *sigalgs);
/* tls1_choose_signing_digest returns a digest for use with |ssl|'s private key
diff --git a/ssl/s3_enc.c b/ssl/s3_enc.c
index 16c7dae..38b0c4e 100644
--- a/ssl/s3_enc.c
+++ b/ssl/s3_enc.c
@@ -165,9 +165,9 @@
static int ssl3_handshake_mac(SSL *ssl, int md_nid, const char *sender,
size_t sender_len, uint8_t *p);
-int ssl3_prf(SSL *ssl, uint8_t *out, size_t out_len, const uint8_t *secret,
- size_t secret_len, const char *label, size_t label_len,
- const uint8_t *seed1, size_t seed1_len,
+int ssl3_prf(const SSL *ssl, uint8_t *out, size_t out_len,
+ const uint8_t *secret, size_t secret_len, const char *label,
+ size_t label_len, const uint8_t *seed1, size_t seed1_len,
const uint8_t *seed2, size_t seed2_len) {
EVP_MD_CTX md5;
EVP_MD_CTX sha1;
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 42e2854..2a5e4d6 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -575,7 +575,7 @@
/* If we are using default SHA1+MD5 algorithms switch to new SHA256 PRF and
* handshake macs if required. */
-uint32_t ssl_get_algorithm_prf(SSL *ssl) {
+uint32_t ssl_get_algorithm_prf(const SSL *ssl) {
uint32_t algorithm_prf = ssl->s3->tmp.new_cipher->algorithm_prf;
if (ssl->enc_method->enc_flags & SSL_ENC_FLAG_SHA256_PRF &&
algorithm_prf == SSL_HANDSHAKE_MAC_DEFAULT) {
diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c
index 06dcf28..8b2ee54 100644
--- a/ssl/t1_enc.c
+++ b/ssl/t1_enc.c
@@ -224,11 +224,10 @@
return ret;
}
-int tls1_prf(SSL *ssl, uint8_t *out, size_t out_len, const uint8_t *secret,
- size_t secret_len, const char *label, size_t label_len,
- const uint8_t *seed1, size_t seed1_len,
+int tls1_prf(const SSL *ssl, uint8_t *out, size_t out_len,
+ const uint8_t *secret, size_t secret_len, const char *label,
+ size_t label_len, const uint8_t *seed1, size_t seed1_len,
const uint8_t *seed2, size_t seed2_len) {
-
if (out_len == 0) {
return 1;
}
@@ -260,14 +259,6 @@
return 1;
}
-static int tls1_generate_key_block(SSL *ssl, uint8_t *out, size_t out_len) {
- return ssl->enc_method->prf(
- ssl, out, out_len, ssl->session->master_key,
- ssl->session->master_key_length, TLS_MD_KEY_EXPANSION_CONST,
- TLS_MD_KEY_EXPANSION_CONST_SIZE, ssl->s3->server_random, SSL3_RANDOM_SIZE,
- ssl->s3->client_random, SSL3_RANDOM_SIZE);
-}
-
int tls1_change_cipher_state(SSL *ssl, int which) {
/* Ensure the key block is set up. */
if (!tls1_setup_key_block(ssl)) {
@@ -330,6 +321,20 @@
return 1;
}
+size_t SSL_get_key_block_len(const SSL *ssl) {
+ return 2 * ((size_t)ssl->s3->tmp.new_mac_secret_len +
+ (size_t)ssl->s3->tmp.new_key_len +
+ (size_t)ssl->s3->tmp.new_fixed_iv_len);
+}
+
+int SSL_generate_key_block(const SSL *ssl, uint8_t *out, size_t out_len) {
+ return ssl->enc_method->prf(
+ ssl, out, out_len, ssl->session->master_key,
+ ssl->session->master_key_length, TLS_MD_KEY_EXPANSION_CONST,
+ TLS_MD_KEY_EXPANSION_CONST_SIZE, ssl->s3->server_random, SSL3_RANDOM_SIZE,
+ ssl->s3->client_random, SSL3_RANDOM_SIZE);
+}
+
int tls1_setup_key_block(SSL *ssl) {
if (ssl->s3->tmp.key_block_length != 0) {
return 1;
@@ -364,8 +369,7 @@
ssl->s3->tmp.new_key_len = (uint8_t)key_len;
ssl->s3->tmp.new_fixed_iv_len = (uint8_t)fixed_iv_len;
- size_t key_block_len = mac_secret_len + key_len + fixed_iv_len;
- key_block_len *= 2;
+ size_t key_block_len = SSL_get_key_block_len(ssl);
ssl3_cleanup_key_block(ssl);
@@ -375,7 +379,7 @@
return 0;
}
- if (!tls1_generate_key_block(ssl, keyblock, key_block_len)) {
+ if (!SSL_generate_key_block(ssl, keyblock, key_block_len)) {
OPENSSL_free(keyblock);
return 0;
}