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;
   }