Add SSL_get_ivs.

This function allows one to extract the current IVs from an SSL
connection. This is needed for the CBC cipher suites with implicit IVs
because, for those, the IV can't be extracted from the handshake key
material.

Change-Id: I247a1d0813b7a434b3cfc88db86d2fe8754344b6
Reviewed-on: https://boringssl-review.googlesource.com/6433
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/cipher/aead.c b/crypto/cipher/aead.c
index 7e747f8..b1db83d 100644
--- a/crypto/cipher/aead.c
+++ b/crypto/cipher/aead.c
@@ -156,3 +156,12 @@
 
   return ctx->aead->get_rc4_state(ctx, out_key);
 }
+
+int EVP_AEAD_CTX_get_iv(const EVP_AEAD_CTX *ctx, const uint8_t **out_iv,
+                        size_t *out_len) {
+  if (ctx->aead->get_iv == NULL) {
+    return 0;
+  }
+
+  return ctx->aead->get_iv(ctx, out_iv, out_len);
+}
diff --git a/crypto/cipher/e_aes.c b/crypto/cipher/e_aes.c
index 442d1ed..b46fed4 100644
--- a/crypto/cipher/e_aes.c
+++ b/crypto/cipher/e_aes.c
@@ -1203,6 +1203,7 @@
     aead_aes_gcm_seal,
     aead_aes_gcm_open,
     NULL,                     /* get_rc4_state */
+    NULL,                     /* get_iv */
 };
 
 static const EVP_AEAD aead_aes_256_gcm = {
@@ -1216,6 +1217,7 @@
     aead_aes_gcm_seal,
     aead_aes_gcm_open,
     NULL,                     /* get_rc4_state */
+    NULL,                     /* get_iv */
 };
 
 const EVP_AEAD *EVP_aead_aes_128_gcm(void) { return &aead_aes_128_gcm; }
@@ -1462,7 +1464,8 @@
     aead_aes_key_wrap_cleanup,
     aead_aes_key_wrap_seal,
     aead_aes_key_wrap_open,
-    NULL,  /* get_rc4_state */
+    NULL, /* get_rc4_state */
+    NULL, /* get_iv */
 };
 
 static const EVP_AEAD aead_aes_256_key_wrap = {
@@ -1475,7 +1478,8 @@
     aead_aes_key_wrap_cleanup,
     aead_aes_key_wrap_seal,
     aead_aes_key_wrap_open,
-    NULL,  /* get_rc4_state */
+    NULL, /* get_rc4_state */
+    NULL, /* get_iv */
 };
 
 const EVP_AEAD *EVP_aead_aes_128_key_wrap(void) { return &aead_aes_128_key_wrap; }
@@ -1726,6 +1730,7 @@
     aead_aes_ctr_hmac_sha256_seal,
     aead_aes_ctr_hmac_sha256_open,
     NULL /* get_rc4_state */,
+    NULL /* get_iv */,
 };
 
 static const EVP_AEAD aead_aes_256_ctr_hmac_sha256 = {
@@ -1740,6 +1745,7 @@
     aead_aes_ctr_hmac_sha256_seal,
     aead_aes_ctr_hmac_sha256_open,
     NULL /* get_rc4_state */,
+    NULL /* get_iv */,
 };
 
 const EVP_AEAD *EVP_aead_aes_128_ctr_hmac_sha256(void) {
diff --git a/crypto/cipher/e_chacha20poly1305.c b/crypto/cipher/e_chacha20poly1305.c
index 3bf7834..c3ba457 100644
--- a/crypto/cipher/e_chacha20poly1305.c
+++ b/crypto/cipher/e_chacha20poly1305.c
@@ -240,6 +240,7 @@
     aead_chacha20_poly1305_seal,
     aead_chacha20_poly1305_open,
     NULL,               /* get_rc4_state */
+    NULL,               /* get_iv */
 };
 
 const EVP_AEAD *EVP_aead_chacha20_poly1305_rfc7539(void) {
@@ -296,6 +297,7 @@
     aead_chacha20_poly1305_old_seal,
     aead_chacha20_poly1305_old_open,
     NULL,               /* get_rc4_state */
+    NULL,               /* get_iv */
 };
 
 const EVP_AEAD *EVP_aead_chacha20_poly1305_old(void) {
diff --git a/crypto/cipher/e_rc4.c b/crypto/cipher/e_rc4.c
index e05b9fd..86d9395 100644
--- a/crypto/cipher/e_rc4.c
+++ b/crypto/cipher/e_rc4.c
@@ -392,6 +392,7 @@
     aead_rc4_md5_tls_seal,
     aead_rc4_md5_tls_open,
     aead_rc4_md5_tls_get_rc4_state,
+    NULL, /* get_iv */
 };
 
 const EVP_AEAD *EVP_aead_rc4_md5_tls(void) { return &aead_rc4_md5_tls; }
diff --git a/crypto/cipher/e_ssl3.c b/crypto/cipher/e_ssl3.c
index 389c52f..7dddf24 100644
--- a/crypto/cipher/e_ssl3.c
+++ b/crypto/cipher/e_ssl3.c
@@ -307,6 +307,19 @@
   return 1;
 }
 
+static int aead_ssl3_get_iv(const EVP_AEAD_CTX *ctx, const uint8_t **out_iv,
+                            size_t *out_iv_len) {
+  AEAD_SSL3_CTX *ssl3_ctx = (AEAD_SSL3_CTX *)ctx->aead_state;
+  const size_t iv_len = EVP_CIPHER_CTX_iv_length(&ssl3_ctx->cipher_ctx);
+  if (iv_len <= 1) {
+    return 0;
+  }
+
+  *out_iv = ssl3_ctx->cipher_ctx.iv;
+  *out_iv_len = iv_len;
+  return 1;
+}
+
 static int aead_rc4_md5_ssl3_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
                                   size_t key_len, size_t tag_len,
                                   enum evp_aead_direction_t dir) {
@@ -358,6 +371,7 @@
     aead_ssl3_seal,
     aead_ssl3_open,
     aead_ssl3_get_rc4_state,
+    NULL, /* get_iv */
 };
 
 static const EVP_AEAD aead_rc4_sha1_ssl3 = {
@@ -371,6 +385,7 @@
     aead_ssl3_seal,
     aead_ssl3_open,
     aead_ssl3_get_rc4_state,
+    NULL, /* get_iv */
 };
 
 static const EVP_AEAD aead_aes_128_cbc_sha1_ssl3 = {
@@ -384,6 +399,7 @@
     aead_ssl3_seal,
     aead_ssl3_open,
     NULL,                        /* get_rc4_state */
+    aead_ssl3_get_iv,
 };
 
 static const EVP_AEAD aead_aes_256_cbc_sha1_ssl3 = {
@@ -397,6 +413,7 @@
     aead_ssl3_seal,
     aead_ssl3_open,
     NULL,                        /* get_rc4_state */
+    aead_ssl3_get_iv,
 };
 
 static const EVP_AEAD aead_des_ede3_cbc_sha1_ssl3 = {
@@ -410,6 +427,7 @@
     aead_ssl3_seal,
     aead_ssl3_open,
     NULL,                        /* get_rc4_state */
+    aead_ssl3_get_iv,
 };
 
 static const EVP_AEAD aead_null_sha1_ssl3 = {
@@ -423,6 +441,7 @@
     aead_ssl3_seal,
     aead_ssl3_open,
     NULL,                       /* get_rc4_state */
+    NULL,                       /* get_iv */
 };
 
 const EVP_AEAD *EVP_aead_rc4_md5_ssl3(void) { return &aead_rc4_md5_ssl3; }
diff --git a/crypto/cipher/e_tls.c b/crypto/cipher/e_tls.c
index c3ddbde..d781da1 100644
--- a/crypto/cipher/e_tls.c
+++ b/crypto/cipher/e_tls.c
@@ -444,6 +444,19 @@
   return 1;
 }
 
+static int aead_tls_get_iv(const EVP_AEAD_CTX *ctx, const uint8_t **out_iv,
+                           size_t *out_iv_len) {
+  const AEAD_TLS_CTX *tls_ctx = (AEAD_TLS_CTX*) ctx->aead_state;
+  const size_t iv_len = EVP_CIPHER_CTX_iv_length(&tls_ctx->cipher_ctx);
+  if (iv_len <= 1) {
+    return 0;
+  }
+
+  *out_iv = tls_ctx->cipher_ctx.iv;
+  *out_iv_len = iv_len;
+  return 1;
+}
+
 static int aead_null_sha1_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
                                    size_t key_len, size_t tag_len,
                                    enum evp_aead_direction_t dir) {
@@ -462,6 +475,7 @@
     aead_tls_seal,
     aead_tls_open,
     aead_rc4_sha1_tls_get_rc4_state, /* get_rc4_state */
+    NULL,                            /* get_iv */
 };
 
 static const EVP_AEAD aead_aes_128_cbc_sha1_tls = {
@@ -475,6 +489,7 @@
     aead_tls_seal,
     aead_tls_open,
     NULL,                   /* get_rc4_state */
+    NULL,                   /* get_iv */
 };
 
 static const EVP_AEAD aead_aes_128_cbc_sha1_tls_implicit_iv = {
@@ -488,6 +503,7 @@
     aead_tls_seal,
     aead_tls_open,
     NULL,                        /* get_rc4_state */
+    aead_tls_get_iv,             /* get_iv */
 };
 
 static const EVP_AEAD aead_aes_128_cbc_sha256_tls = {
@@ -501,6 +517,7 @@
     aead_tls_seal,
     aead_tls_open,
     NULL,                      /* get_rc4_state */
+    NULL,                      /* get_iv */
 };
 
 static const EVP_AEAD aead_aes_256_cbc_sha1_tls = {
@@ -514,6 +531,7 @@
     aead_tls_seal,
     aead_tls_open,
     NULL,                   /* get_rc4_state */
+    NULL,                   /* get_iv */
 };
 
 static const EVP_AEAD aead_aes_256_cbc_sha1_tls_implicit_iv = {
@@ -527,6 +545,7 @@
     aead_tls_seal,
     aead_tls_open,
     NULL,                        /* get_rc4_state */
+    aead_tls_get_iv,             /* get_iv */
 };
 
 static const EVP_AEAD aead_aes_256_cbc_sha256_tls = {
@@ -540,6 +559,7 @@
     aead_tls_seal,
     aead_tls_open,
     NULL,                      /* get_rc4_state */
+    NULL,                      /* get_iv */
 };
 
 static const EVP_AEAD aead_aes_256_cbc_sha384_tls = {
@@ -553,6 +573,7 @@
     aead_tls_seal,
     aead_tls_open,
     NULL,                      /* get_rc4_state */
+    NULL,                      /* get_iv */
 };
 
 static const EVP_AEAD aead_des_ede3_cbc_sha1_tls = {
@@ -566,6 +587,7 @@
     aead_tls_seal,
     aead_tls_open,
     NULL,                   /* get_rc4_state */
+    NULL,                   /* get_iv */
 };
 
 static const EVP_AEAD aead_des_ede3_cbc_sha1_tls_implicit_iv = {
@@ -579,6 +601,7 @@
     aead_tls_seal,
     aead_tls_open,
     NULL,                       /* get_rc4_state */
+    aead_tls_get_iv,            /* get_iv */
 };
 
 static const EVP_AEAD aead_null_sha1_tls = {
@@ -592,6 +615,7 @@
     aead_tls_seal,
     aead_tls_open,
     NULL,                       /* get_rc4_state */
+    NULL,                       /* get_iv */
 };
 
 const EVP_AEAD *EVP_aead_rc4_sha1_tls(void) { return &aead_rc4_sha1_tls; }
diff --git a/crypto/cipher/internal.h b/crypto/cipher/internal.h
index b2a94f4..72ac118 100644
--- a/crypto/cipher/internal.h
+++ b/crypto/cipher/internal.h
@@ -96,6 +96,9 @@
               size_t ad_len);
 
   int (*get_rc4_state)(const EVP_AEAD_CTX *ctx, const RC4_KEY **out_key);
+
+  int (*get_iv)(const EVP_AEAD_CTX *ctx, const uint8_t **out_iv,
+                size_t *out_len);
 };
 
 
diff --git a/include/openssl/aead.h b/include/openssl/aead.h
index aa2b080..ba8e2df 100644
--- a/include/openssl/aead.h
+++ b/include/openssl/aead.h
@@ -330,6 +330,13 @@
 OPENSSL_EXPORT int EVP_AEAD_CTX_get_rc4_state(const EVP_AEAD_CTX *ctx,
                                               const RC4_KEY **out_key);
 
+/* EVP_AEAD_CTX_get_iv sets |*out_len| to the length of the IV for |ctx| and
+ * sets |*out_iv| to point to that many bytes of the current IV. This is only
+ * meaningful for AEADs with implicit IVs (i.e. CBC mode in SSLv3 and TLS 1.0).
+ *
+ * It returns one on success or zero on error. */
+OPENSSL_EXPORT int EVP_AEAD_CTX_get_iv(const EVP_AEAD_CTX *ctx,
+                                       const uint8_t **out_iv, size_t *out_len);
 
 #if defined(__cplusplus)
 }  /* extern C */
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 465d44f..acdb984 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -2613,6 +2613,16 @@
 OPENSSL_EXPORT int SSL_get_rc4_state(const SSL *ssl, const RC4_KEY **read_key,
                                      const RC4_KEY **write_key);
 
+/* SSL_get_ivs sets |*out_iv_len| to the length of the IVs for the ciphers
+ * underlying |ssl| and sets |*out_read_iv| and |*out_write_iv| to point to the
+ * current IVs for the read and write directions. This is only meaningful for
+ * connections with implicit IVs (i.e. CBC mode with SSLv3 or TLS 1.0).
+ *
+ * It returns one on success or zero on error. */
+OPENSSL_EXPORT int SSL_get_ivs(const SSL *ssl, const uint8_t **out_read_iv,
+                               const uint8_t **out_write_iv,
+                               size_t *out_iv_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/ssl_lib.c b/ssl/ssl_lib.c
index d1535d1..68eb4ac 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -2636,6 +2636,23 @@
          EVP_AEAD_CTX_get_rc4_state(&ssl->aead_write_ctx->ctx, write_key);
 }
 
+int SSL_get_ivs(const SSL *ssl, const uint8_t **out_read_iv,
+                const uint8_t **out_write_iv, size_t *out_iv_len) {
+  if (ssl->aead_read_ctx == NULL || ssl->aead_write_ctx == NULL) {
+    return 0;
+  }
+
+  size_t write_iv_len;
+  if (!EVP_AEAD_CTX_get_iv(&ssl->aead_read_ctx->ctx, out_read_iv, out_iv_len) ||
+      !EVP_AEAD_CTX_get_iv(&ssl->aead_write_ctx->ctx, out_write_iv,
+                           &write_iv_len) ||
+      *out_iv_len != write_iv_len) {
+    return 0;
+  }
+
+  return 1;
+}
+
 int SSL_clear(SSL *ssl) {
   if (ssl->method == NULL) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_NO_METHOD_SPECIFIED);