Fix undefined function pointer casts in {d2i,i2d}_Foo_{bio,fp}

Lacking C++, this instead adds a mess of macros. With this done, all the
function-pointer-munging "_of" macros in asn1.h can also be removed.

Update-Note: A number of *really* old and unused ASN.1 macros were
removed.

Bug: chromium:785442
Change-Id: Iab260d114c7d8cdf0429759e714d91ce3f3c04b2
Reviewed-on: https://boringssl-review.googlesource.com/32106
Reviewed-by: Adam Langley <agl@google.com>
Reviewed-by: Adam Langley <alangley@gmail.com>
diff --git a/crypto/asn1/a_d2i_fp.c b/crypto/asn1/a_d2i_fp.c
index ee71ee9..fd423e2 100644
--- a/crypto/asn1/a_d2i_fp.c
+++ b/crypto/asn1/a_d2i_fp.c
@@ -58,66 +58,24 @@
 
 #include <limits.h>
 
-#include <openssl/buf.h>
+#include <openssl/bio.h>
 #include <openssl/err.h>
 #include <openssl/mem.h>
 
-static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb);
-
-#ifndef NO_OLD_ASN1
-# ifndef OPENSSL_NO_FP_API
-
-void *ASN1_d2i_fp(void *(*xnew) (void), d2i_of_void *d2i, FILE *in, void **x)
-{
-    BIO *b = BIO_new_fp(in, BIO_NOCLOSE);
-    if (b == NULL) {
-        OPENSSL_PUT_ERROR(ASN1, ERR_R_BUF_LIB);
-        return NULL;
-    }
-    void *ret = ASN1_d2i_bio(xnew, d2i, b, x);
-    BIO_free(b);
-    return (ret);
-}
-# endif
-
-void *ASN1_d2i_bio(void *(*xnew) (void), d2i_of_void *d2i, BIO *in, void **x)
-{
-    BUF_MEM *b = NULL;
-    const unsigned char *p;
-    void *ret = NULL;
-    int len;
-
-    len = asn1_d2i_read_bio(in, &b);
-    if (len < 0)
-        goto err;
-
-    p = (unsigned char *)b->data;
-    ret = d2i(x, &p, len);
- err:
-    if (b != NULL)
-        BUF_MEM_free(b);
-    return (ret);
-}
-
-#endif
 
 void *ASN1_item_d2i_bio(const ASN1_ITEM *it, BIO *in, void *x)
 {
-    BUF_MEM *b = NULL;
-    const unsigned char *p;
-    void *ret = NULL;
-    int len;
-
-    len = asn1_d2i_read_bio(in, &b);
-    if (len < 0)
-        goto err;
-
-    p = (const unsigned char *)b->data;
-    ret = ASN1_item_d2i(x, &p, len, it);
- err:
-    if (b != NULL)
-        BUF_MEM_free(b);
-    return (ret);
+    uint8_t *data;
+    size_t len;
+    // Historically, this function did not impose a limit in OpenSSL and is used
+    // to read CRLs, so we leave this without an external bound.
+    if (!BIO_read_asn1(in, &data, &len, INT_MAX)) {
+        return NULL;
+    }
+    const uint8_t *ptr = data;
+    void *ret = ASN1_item_d2i(x, &ptr, len, it);
+    OPENSSL_free(data);
+    return ret;
 }
 
 #ifndef OPENSSL_NO_FP_API
@@ -133,158 +91,3 @@
     return ret;
 }
 #endif
-
-typedef struct asn1_const_ctx_st
-    {
-    const unsigned char *p;/* work char pointer */
-    int eos;    /* end of sequence read for indefinite encoding */
-    int error;  /* error code to use when returning an error */
-    int inf;    /* constructed if 0x20, indefinite is 0x21 */
-    int tag;    /* tag from last 'get object' */
-    int xclass; /* class from last 'get object' */
-    long slen;  /* length of last 'get object' */
-    const unsigned char *max; /* largest value of p allowed */
-    const unsigned char *q;/* temporary variable */
-    const unsigned char **pp;/* variable */
-    int line;   /* used in error processing */
-    } ASN1_const_CTX;
-
-#define HEADER_SIZE   8
-#define ASN1_CHUNK_INITIAL_SIZE (16 * 1024)
-static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb)
-{
-    BUF_MEM *b;
-    unsigned char *p;
-    int i;
-    ASN1_const_CTX c;
-    size_t want = HEADER_SIZE;
-    int eos = 0;
-    size_t off = 0;
-    size_t len = 0;
-
-    b = BUF_MEM_new();
-    if (b == NULL) {
-        OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
-        return -1;
-    }
-
-    ERR_clear_error();
-    for (;;) {
-        if (want >= (len - off)) {
-            want -= (len - off);
-
-            if (len + want < len || !BUF_MEM_grow_clean(b, len + want)) {
-                OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
-                goto err;
-            }
-            i = BIO_read(in, &(b->data[len]), want);
-            if ((i < 0) && ((len - off) == 0)) {
-                OPENSSL_PUT_ERROR(ASN1, ASN1_R_NOT_ENOUGH_DATA);
-                goto err;
-            }
-            if (i > 0) {
-                if (len + i < len) {
-                    OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG);
-                    goto err;
-                }
-                len += i;
-            }
-        }
-        /* else data already loaded */
-
-        p = (unsigned char *)&(b->data[off]);
-        c.p = p;
-        c.inf = ASN1_get_object(&(c.p), &(c.slen), &(c.tag), &(c.xclass),
-                                len - off);
-        if (c.inf & 0x80) {
-            uint32_t error = ERR_peek_error();
-            if (ERR_GET_LIB(error) != ERR_LIB_ASN1 ||
-                ERR_GET_REASON(error) != ASN1_R_TOO_LONG) {
-                goto err;
-            }
-            ERR_clear_error();
-        }
-        i = c.p - p;            /* header length */
-        off += i;               /* end of data */
-
-        if (c.inf & 1) {
-            /* no data body so go round again */
-            eos++;
-            if (eos < 0) {
-                OPENSSL_PUT_ERROR(ASN1, ASN1_R_HEADER_TOO_LONG);
-                goto err;
-            }
-            want = HEADER_SIZE;
-        } else if (eos && (c.slen == 0) && (c.tag == V_ASN1_EOC)) {
-            /* eos value, so go back and read another header */
-            eos--;
-            if (eos <= 0)
-                break;
-            else
-                want = HEADER_SIZE;
-        } else {
-            /* suck in c.slen bytes of data */
-            want = c.slen;
-            if (want > (len - off)) {
-                size_t chunk_max = ASN1_CHUNK_INITIAL_SIZE;
-                want -= (len - off);
-                if (want > INT_MAX /* BIO_read takes an int length */  ||
-                    len + want < len) {
-                    OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG);
-                    goto err;
-                }
-                while (want > 0) {
-                    /*
-                     * Read content in chunks of increasing size
-                     * so we can return an error for EOF without
-                     * having to allocate the entire content length
-                     * in one go.
-                     */
-                    size_t chunk = want > chunk_max ? chunk_max : want;
-
-                    if (!BUF_MEM_grow_clean(b, len + chunk)) {
-                        OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
-                        goto err;
-                    }
-                    want -= chunk;
-                    while (chunk > 0) {
-                        i = BIO_read(in, &(b->data[len]), chunk);
-                        if (i <= 0) {
-                            OPENSSL_PUT_ERROR(ASN1, ASN1_R_NOT_ENOUGH_DATA);
-                            goto err;
-                        }
-                        /*
-                         * This can't overflow because |len+want| didn't
-                         * overflow.
-                         */
-                        len += i;
-                        chunk -= i;
-                    }
-                    if (chunk_max < INT_MAX/2)
-                        chunk_max *= 2;
-                }
-            }
-            if (off + c.slen < off) {
-                OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG);
-                goto err;
-            }
-            off += c.slen;
-            if (eos <= 0) {
-                break;
-            } else
-                want = HEADER_SIZE;
-        }
-    }
-
-    if (off > INT_MAX) {
-        OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG);
-        goto err;
-    }
-
-    *pb = b;
-    return off;
- err:
-    if (b != NULL)
-        BUF_MEM_free(b);
-    return -1;
-}
diff --git a/crypto/asn1/a_dup.c b/crypto/asn1/a_dup.c
index 57394f5..9ede851 100644
--- a/crypto/asn1/a_dup.c
+++ b/crypto/asn1/a_dup.c
@@ -59,30 +59,6 @@
 #include <openssl/err.h>
 #include <openssl/mem.h>
 
-void *ASN1_dup(i2d_of_void *i2d, d2i_of_void *d2i, void *x)
-{
-    unsigned char *b, *p;
-    const unsigned char *p2;
-    int i;
-    char *ret;
-
-    if (x == NULL)
-        return (NULL);
-
-    i = i2d(x, NULL);
-    b = OPENSSL_malloc(i + 10);
-    if (b == NULL) {
-        OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
-        return (NULL);
-    }
-    p = b;
-    i = i2d(x, &p);
-    p2 = b;
-    ret = d2i(NULL, &p2, i);
-    OPENSSL_free(b);
-    return (ret);
-}
-
 /*
  * ASN1_ITEM version of dup: this follows the model above except we don't
  * need to allocate the buffer. At some point this could be rewritten to
diff --git a/crypto/asn1/a_i2d_fp.c b/crypto/asn1/a_i2d_fp.c
index 5cc97d2..db0d812 100644
--- a/crypto/asn1/a_i2d_fp.c
+++ b/crypto/asn1/a_i2d_fp.c
@@ -56,54 +56,10 @@
 
 #include <openssl/asn1.h>
 
+#include <openssl/bio.h>
 #include <openssl/err.h>
 #include <openssl/mem.h>
 
-int ASN1_i2d_fp(i2d_of_void *i2d, FILE *out, void *x)
-{
-    BIO *b = BIO_new_fp(out, BIO_NOCLOSE);
-    if (b == NULL) {
-        OPENSSL_PUT_ERROR(ASN1, ERR_R_BUF_LIB);
-        return 0;
-    }
-    int ret = ASN1_i2d_bio(i2d, b, x);
-    BIO_free(b);
-    return ret;
-}
-
-int ASN1_i2d_bio(i2d_of_void *i2d, BIO *out, void *x)
-{
-    char *b;
-    unsigned char *p;
-    int i, j = 0, n, ret = 1;
-
-    n = i2d(x, NULL);
-    if (n <= 0)
-        return 0;
-
-    b = (char *)OPENSSL_malloc(n);
-    if (b == NULL) {
-        OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
-        return (0);
-    }
-
-    p = (unsigned char *)b;
-    i2d(x, &p);
-
-    for (;;) {
-        i = BIO_write(out, &(b[j]), n);
-        if (i == n)
-            break;
-        if (i <= 0) {
-            ret = 0;
-            break;
-        }
-        j += i;
-        n -= i;
-    }
-    OPENSSL_free(b);
-    return (ret);
-}
 
 int ASN1_item_i2d_fp(const ASN1_ITEM *it, FILE *out, void *x)
 {
@@ -120,25 +76,13 @@
 int ASN1_item_i2d_bio(const ASN1_ITEM *it, BIO *out, void *x)
 {
     unsigned char *b = NULL;
-    int i, j = 0, n, ret = 1;
-
-    n = ASN1_item_i2d(x, &b, it);
+    int n = ASN1_item_i2d(x, &b, it);
     if (b == NULL) {
         OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
-        return (0);
+        return 0;
     }
 
-    for (;;) {
-        i = BIO_write(out, &(b[j]), n);
-        if (i == n)
-            break;
-        if (i <= 0) {
-            ret = 0;
-            break;
-        }
-        j += i;
-        n -= i;
-    }
+    int ret = BIO_write_all(out, b, n);
     OPENSSL_free(b);
-    return (ret);
+    return ret;
 }
diff --git a/crypto/bio/bio.c b/crypto/bio/bio.c
index 3e788b8..881c14e 100644
--- a/crypto/bio/bio.c
+++ b/crypto/bio/bio.c
@@ -177,6 +177,19 @@
   return ret;
 }
 
+int BIO_write_all(BIO *bio, const void *data, size_t len) {
+  const uint8_t *data_u8 = data;
+  while (len > 0) {
+    int ret = BIO_write(bio, data_u8, len > INT_MAX ? INT_MAX : (int)len);
+    if (ret <= 0) {
+      return 0;
+    }
+    data_u8 += ret;
+    len -= ret;
+  }
+  return 1;
+}
+
 int BIO_puts(BIO *bio, const char *in) {
   return BIO_write(bio, in, strlen(in));
 }
diff --git a/crypto/pkcs7/pkcs7_x509.c b/crypto/pkcs7/pkcs7_x509.c
index a2a6b46..d6ca44e 100644
--- a/crypto/pkcs7/pkcs7_x509.c
+++ b/crypto/pkcs7/pkcs7_x509.c
@@ -333,17 +333,7 @@
 }
 
 int i2d_PKCS7_bio(BIO *bio, const PKCS7 *p7) {
-  size_t written = 0;
-  while (written < p7->ber_len) {
-    size_t todo = p7->ber_len - written;
-    int len = todo > INT_MAX ? INT_MAX : (int)todo;
-    int ret = BIO_write(bio, p7->ber_bytes + written, len);
-    if (ret <= 0) {
-      return 0;
-    }
-    written += (size_t)ret;
-  }
-  return 1;
+  return BIO_write_all(bio, p7->ber_bytes, p7->ber_len);
 }
 
 void PKCS7_free(PKCS7 *p7) {
diff --git a/crypto/pkcs8/pkcs8_x509.c b/crypto/pkcs8/pkcs8_x509.c
index dc74d96..2c7841e 100644
--- a/crypto/pkcs8/pkcs8_x509.c
+++ b/crypto/pkcs8/pkcs8_x509.c
@@ -861,17 +861,7 @@
 }
 
 int i2d_PKCS12_bio(BIO *bio, const PKCS12 *p12) {
-  size_t written = 0;
-  while (written < p12->ber_len) {
-    size_t todo = p12->ber_len - written;
-    int len = todo > INT_MAX ? INT_MAX : (int)todo;
-    int ret = BIO_write(bio, p12->ber_bytes + written, len);
-    if (ret <= 0) {
-      return 0;
-    }
-    written += (size_t)ret;
-  }
-  return 1;
+  return BIO_write_all(bio, p12->ber_bytes, p12->ber_len);
 }
 
 int i2d_PKCS12_fp(FILE *fp, const PKCS12 *p12) {
diff --git a/crypto/x509/x_all.c b/crypto/x509/x_all.c
index 064c89c..a37d7bd 100644
--- a/crypto/x509/x_all.c
+++ b/crypto/x509/x_all.c
@@ -54,14 +54,18 @@
  * copied and put under another distribution licence
  * [including the GNU Public Licence.] */
 
+#include <openssl/x509.h>
+
+#include <limits.h>
+
 #include <openssl/asn1.h>
 #include <openssl/buf.h>
 #include <openssl/digest.h>
 #include <openssl/dsa.h>
 #include <openssl/evp.h>
+#include <openssl/mem.h>
 #include <openssl/rsa.h>
 #include <openssl/stack.h>
-#include <openssl/x509.h>
 
 int X509_verify(X509 *a, EVP_PKEY *r)
 {
@@ -201,154 +205,102 @@
 }
 
 #ifndef OPENSSL_NO_FP_API
-RSA *d2i_RSAPrivateKey_fp(FILE *fp, RSA **rsa)
-{
-    return ASN1_d2i_fp_of(RSA, RSA_new, d2i_RSAPrivateKey, fp, rsa);
-}
 
-int i2d_RSAPrivateKey_fp(FILE *fp, RSA *rsa)
-{
-    return ASN1_i2d_fp_of_const(RSA, i2d_RSAPrivateKey, fp, rsa);
-}
+#define IMPLEMENT_D2I_FP(type, name, bio_func) \
+  type *name(FILE *fp, type **obj) {           \
+    BIO *bio = BIO_new_fp(fp, BIO_NOCLOSE);    \
+    if (bio == NULL) {                         \
+      return NULL;                             \
+    }                                          \
+    type *ret = bio_func(bio, obj);            \
+    BIO_free(bio);                             \
+    return ret;                                \
+  }
 
-RSA *d2i_RSAPublicKey_fp(FILE *fp, RSA **rsa)
-{
-    return ASN1_d2i_fp_of(RSA, RSA_new, d2i_RSAPublicKey, fp, rsa);
-}
+#define IMPLEMENT_I2D_FP(type, name, bio_func) \
+  int name(FILE *fp, type *obj) {              \
+    BIO *bio = BIO_new_fp(fp, BIO_NOCLOSE);    \
+    if (bio == NULL) {                         \
+      return 0;                                \
+    }                                          \
+    int ret = bio_func(bio, obj);              \
+    BIO_free(bio);                             \
+    return ret;                                \
+  }
 
-RSA *d2i_RSA_PUBKEY_fp(FILE *fp, RSA **rsa)
-{
-    return ASN1_d2i_fp((void *(*)(void))
-                       RSA_new, (D2I_OF(void)) d2i_RSA_PUBKEY, fp,
-                       (void **)rsa);
-}
+IMPLEMENT_D2I_FP(RSA, d2i_RSAPrivateKey_fp, d2i_RSAPrivateKey_bio)
+IMPLEMENT_I2D_FP(RSA, i2d_RSAPrivateKey_fp, i2d_RSAPrivateKey_bio)
 
-int i2d_RSAPublicKey_fp(FILE *fp, RSA *rsa)
-{
-    return ASN1_i2d_fp_of_const(RSA, i2d_RSAPublicKey, fp, rsa);
-}
+IMPLEMENT_D2I_FP(RSA, d2i_RSAPublicKey_fp, d2i_RSAPublicKey_bio)
+IMPLEMENT_I2D_FP(RSA, i2d_RSAPublicKey_fp, i2d_RSAPublicKey_bio)
 
-int i2d_RSA_PUBKEY_fp(FILE *fp, RSA *rsa)
-{
-    return ASN1_i2d_fp((I2D_OF_const(void))i2d_RSA_PUBKEY, fp, rsa);
-}
+IMPLEMENT_D2I_FP(RSA, d2i_RSA_PUBKEY_fp, d2i_RSA_PUBKEY_bio)
+IMPLEMENT_I2D_FP(RSA, i2d_RSA_PUBKEY_fp, i2d_RSA_PUBKEY_bio)
 #endif
 
-RSA *d2i_RSAPrivateKey_bio(BIO *bp, RSA **rsa)
-{
-    return ASN1_d2i_bio_of(RSA, RSA_new, d2i_RSAPrivateKey, bp, rsa);
-}
+#define IMPLEMENT_D2I_BIO(type, name, d2i_func)         \
+  type *name(BIO *bio, type **obj) {                    \
+    uint8_t *data;                                      \
+    size_t len;                                         \
+    if (!BIO_read_asn1(bio, &data, &len, 100 * 1024)) { \
+      return NULL;                                      \
+    }                                                   \
+    const uint8_t *ptr = data;                          \
+    type *ret = d2i_func(obj, &ptr, (long)len);         \
+    OPENSSL_free(data);                                 \
+    return ret;                                         \
+  }
 
-int i2d_RSAPrivateKey_bio(BIO *bp, RSA *rsa)
-{
-    return ASN1_i2d_bio_of_const(RSA, i2d_RSAPrivateKey, bp, rsa);
-}
+#define IMPLEMENT_I2D_BIO(type, name, i2d_func) \
+  int name(BIO *bio, type *obj) {               \
+    uint8_t *data = NULL;                       \
+    int len = i2d_func(obj, &data);             \
+    if (len < 0) {                              \
+      return 0;                                 \
+    }                                           \
+    int ret = BIO_write_all(bio, data, len);    \
+    OPENSSL_free(data);                         \
+    return ret;                                 \
+  }
 
-RSA *d2i_RSAPublicKey_bio(BIO *bp, RSA **rsa)
-{
-    return ASN1_d2i_bio_of(RSA, RSA_new, d2i_RSAPublicKey, bp, rsa);
-}
+IMPLEMENT_D2I_BIO(RSA, d2i_RSAPrivateKey_bio, d2i_RSAPrivateKey)
+IMPLEMENT_I2D_BIO(RSA, i2d_RSAPrivateKey_bio, i2d_RSAPrivateKey)
 
-RSA *d2i_RSA_PUBKEY_bio(BIO *bp, RSA **rsa)
-{
-    return ASN1_d2i_bio_of(RSA, RSA_new, d2i_RSA_PUBKEY, bp, rsa);
-}
+IMPLEMENT_D2I_BIO(RSA, d2i_RSAPublicKey_bio, d2i_RSAPublicKey)
+IMPLEMENT_I2D_BIO(RSA, i2d_RSAPublicKey_bio, i2d_RSAPublicKey)
 
-int i2d_RSAPublicKey_bio(BIO *bp, RSA *rsa)
-{
-    return ASN1_i2d_bio_of_const(RSA, i2d_RSAPublicKey, bp, rsa);
-}
-
-int i2d_RSA_PUBKEY_bio(BIO *bp, RSA *rsa)
-{
-    return ASN1_i2d_bio_of_const(RSA, i2d_RSA_PUBKEY, bp, rsa);
-}
+IMPLEMENT_D2I_BIO(RSA, d2i_RSA_PUBKEY_bio, d2i_RSA_PUBKEY)
+IMPLEMENT_I2D_BIO(RSA, i2d_RSA_PUBKEY_bio, i2d_RSA_PUBKEY)
 
 #ifndef OPENSSL_NO_DSA
 # ifndef OPENSSL_NO_FP_API
-DSA *d2i_DSAPrivateKey_fp(FILE *fp, DSA **dsa)
-{
-    return ASN1_d2i_fp_of(DSA, DSA_new, d2i_DSAPrivateKey, fp, dsa);
-}
+IMPLEMENT_D2I_FP(DSA, d2i_DSAPrivateKey_fp, d2i_DSAPrivateKey_bio)
+IMPLEMENT_I2D_FP(DSA, i2d_DSAPrivateKey_fp, i2d_DSAPrivateKey_bio)
 
-int i2d_DSAPrivateKey_fp(FILE *fp, DSA *dsa)
-{
-    return ASN1_i2d_fp_of_const(DSA, i2d_DSAPrivateKey, fp, dsa);
-}
-
-DSA *d2i_DSA_PUBKEY_fp(FILE *fp, DSA **dsa)
-{
-    return ASN1_d2i_fp_of(DSA, DSA_new, d2i_DSA_PUBKEY, fp, dsa);
-}
-
-int i2d_DSA_PUBKEY_fp(FILE *fp, DSA *dsa)
-{
-    return ASN1_i2d_fp_of_const(DSA, i2d_DSA_PUBKEY, fp, dsa);
-}
+IMPLEMENT_D2I_FP(DSA, d2i_DSA_PUBKEY_fp, d2i_DSA_PUBKEY_bio)
+IMPLEMENT_I2D_FP(DSA, i2d_DSA_PUBKEY_fp, i2d_DSA_PUBKEY_bio)
 # endif
 
-DSA *d2i_DSAPrivateKey_bio(BIO *bp, DSA **dsa)
-{
-    return ASN1_d2i_bio_of(DSA, DSA_new, d2i_DSAPrivateKey, bp, dsa);
-}
+IMPLEMENT_D2I_BIO(DSA, d2i_DSAPrivateKey_bio, d2i_DSAPrivateKey)
+IMPLEMENT_I2D_BIO(DSA, i2d_DSAPrivateKey_bio, i2d_DSAPrivateKey)
 
-int i2d_DSAPrivateKey_bio(BIO *bp, DSA *dsa)
-{
-    return ASN1_i2d_bio_of_const(DSA, i2d_DSAPrivateKey, bp, dsa);
-}
-
-DSA *d2i_DSA_PUBKEY_bio(BIO *bp, DSA **dsa)
-{
-    return ASN1_d2i_bio_of(DSA, DSA_new, d2i_DSA_PUBKEY, bp, dsa);
-}
-
-int i2d_DSA_PUBKEY_bio(BIO *bp, DSA *dsa)
-{
-    return ASN1_i2d_bio_of_const(DSA, i2d_DSA_PUBKEY, bp, dsa);
-}
-
+IMPLEMENT_D2I_BIO(DSA, d2i_DSA_PUBKEY_bio, d2i_DSA_PUBKEY)
+IMPLEMENT_I2D_BIO(DSA, i2d_DSA_PUBKEY_bio, i2d_DSA_PUBKEY)
 #endif
 
 #ifndef OPENSSL_NO_FP_API
-EC_KEY *d2i_EC_PUBKEY_fp(FILE *fp, EC_KEY **eckey)
-{
-    return ASN1_d2i_fp_of(EC_KEY, EC_KEY_new, d2i_EC_PUBKEY, fp, eckey);
-}
+IMPLEMENT_D2I_FP(EC_KEY, d2i_ECPrivateKey_fp, d2i_ECPrivateKey_bio)
+IMPLEMENT_I2D_FP(EC_KEY, i2d_ECPrivateKey_fp, i2d_ECPrivateKey_bio)
 
-int i2d_EC_PUBKEY_fp(FILE *fp, EC_KEY *eckey)
-{
-    return ASN1_i2d_fp_of_const(EC_KEY, i2d_EC_PUBKEY, fp, eckey);
-}
-
-EC_KEY *d2i_ECPrivateKey_fp(FILE *fp, EC_KEY **eckey)
-{
-    return ASN1_d2i_fp_of(EC_KEY, EC_KEY_new, d2i_ECPrivateKey, fp, eckey);
-}
-
-int i2d_ECPrivateKey_fp(FILE *fp, EC_KEY *eckey)
-{
-    return ASN1_i2d_fp_of_const(EC_KEY, i2d_ECPrivateKey, fp, eckey);
-}
+IMPLEMENT_D2I_FP(EC_KEY, d2i_EC_PUBKEY_fp, d2i_EC_PUBKEY_bio)
+IMPLEMENT_I2D_FP(EC_KEY, i2d_EC_PUBKEY_fp, i2d_EC_PUBKEY_bio)
 #endif
-EC_KEY *d2i_EC_PUBKEY_bio(BIO *bp, EC_KEY **eckey)
-{
-    return ASN1_d2i_bio_of(EC_KEY, EC_KEY_new, d2i_EC_PUBKEY, bp, eckey);
-}
 
-int i2d_EC_PUBKEY_bio(BIO *bp, EC_KEY *ecdsa)
-{
-    return ASN1_i2d_bio_of_const(EC_KEY, i2d_EC_PUBKEY, bp, ecdsa);
-}
+IMPLEMENT_D2I_BIO(EC_KEY, d2i_ECPrivateKey_bio, d2i_ECPrivateKey)
+IMPLEMENT_I2D_BIO(EC_KEY, i2d_ECPrivateKey_bio, i2d_ECPrivateKey)
 
-EC_KEY *d2i_ECPrivateKey_bio(BIO *bp, EC_KEY **eckey)
-{
-    return ASN1_d2i_bio_of(EC_KEY, EC_KEY_new, d2i_ECPrivateKey, bp, eckey);
-}
-
-int i2d_ECPrivateKey_bio(BIO *bp, EC_KEY *eckey)
-{
-    return ASN1_i2d_bio_of_const(EC_KEY, i2d_ECPrivateKey, bp, eckey);
-}
+IMPLEMENT_D2I_BIO(EC_KEY, d2i_EC_PUBKEY_bio, d2i_EC_PUBKEY)
+IMPLEMENT_I2D_BIO(EC_KEY, i2d_EC_PUBKEY_bio, i2d_EC_PUBKEY)
 
 int X509_pubkey_digest(const X509 *data, const EVP_MD *type,
                        unsigned char *md, unsigned int *len)
@@ -389,40 +341,18 @@
 }
 
 #ifndef OPENSSL_NO_FP_API
-X509_SIG *d2i_PKCS8_fp(FILE *fp, X509_SIG **p8)
-{
-    return ASN1_d2i_fp_of(X509_SIG, X509_SIG_new, d2i_X509_SIG, fp, p8);
-}
-
-int i2d_PKCS8_fp(FILE *fp, X509_SIG *p8)
-{
-    return ASN1_i2d_fp_of(X509_SIG, i2d_X509_SIG, fp, p8);
-}
+IMPLEMENT_D2I_FP(X509_SIG, d2i_PKCS8_fp, d2i_PKCS8_bio)
+IMPLEMENT_I2D_FP(X509_SIG, i2d_PKCS8_fp, i2d_PKCS8_bio)
 #endif
 
-X509_SIG *d2i_PKCS8_bio(BIO *bp, X509_SIG **p8)
-{
-    return ASN1_d2i_bio_of(X509_SIG, X509_SIG_new, d2i_X509_SIG, bp, p8);
-}
-
-int i2d_PKCS8_bio(BIO *bp, X509_SIG *p8)
-{
-    return ASN1_i2d_bio_of(X509_SIG, i2d_X509_SIG, bp, p8);
-}
+IMPLEMENT_D2I_BIO(X509_SIG, d2i_PKCS8_bio, d2i_X509_SIG)
+IMPLEMENT_I2D_BIO(X509_SIG, i2d_PKCS8_bio, i2d_X509_SIG)
 
 #ifndef OPENSSL_NO_FP_API
-PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_fp(FILE *fp,
-                                                PKCS8_PRIV_KEY_INFO **p8inf)
-{
-    return ASN1_d2i_fp_of(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_new,
-                          d2i_PKCS8_PRIV_KEY_INFO, fp, p8inf);
-}
-
-int i2d_PKCS8_PRIV_KEY_INFO_fp(FILE *fp, PKCS8_PRIV_KEY_INFO *p8inf)
-{
-    return ASN1_i2d_fp_of(PKCS8_PRIV_KEY_INFO, i2d_PKCS8_PRIV_KEY_INFO, fp,
-                          p8inf);
-}
+IMPLEMENT_D2I_FP(PKCS8_PRIV_KEY_INFO, d2i_PKCS8_PRIV_KEY_INFO_fp,
+                 d2i_PKCS8_PRIV_KEY_INFO_bio)
+IMPLEMENT_I2D_FP(PKCS8_PRIV_KEY_INFO, i2d_PKCS8_PRIV_KEY_INFO_fp,
+                 i2d_PKCS8_PRIV_KEY_INFO_bio)
 
 int i2d_PKCS8PrivateKeyInfo_fp(FILE *fp, EVP_PKEY *key)
 {
@@ -436,38 +366,16 @@
     return ret;
 }
 
-int i2d_PrivateKey_fp(FILE *fp, EVP_PKEY *pkey)
-{
-    return ASN1_i2d_fp_of_const(EVP_PKEY, i2d_PrivateKey, fp, pkey);
-}
+IMPLEMENT_D2I_FP(EVP_PKEY, d2i_PrivateKey_fp, d2i_PrivateKey_bio)
+IMPLEMENT_I2D_FP(EVP_PKEY, i2d_PrivateKey_fp, i2d_PrivateKey_bio)
 
-EVP_PKEY *d2i_PrivateKey_fp(FILE *fp, EVP_PKEY **a)
-{
-    return ASN1_d2i_fp_of(EVP_PKEY, EVP_PKEY_new, d2i_AutoPrivateKey, fp, a);
-}
+IMPLEMENT_D2I_FP(EVP_PKEY, d2i_PUBKEY_fp, d2i_PUBKEY_bio)
+IMPLEMENT_I2D_FP(EVP_PKEY, i2d_PUBKEY_fp, i2d_PUBKEY_bio)
 
-int i2d_PUBKEY_fp(FILE *fp, EVP_PKEY *pkey)
-{
-    return ASN1_i2d_fp_of_const(EVP_PKEY, i2d_PUBKEY, fp, pkey);
-}
-
-EVP_PKEY *d2i_PUBKEY_fp(FILE *fp, EVP_PKEY **a)
-{
-    return ASN1_d2i_fp_of(EVP_PKEY, EVP_PKEY_new, d2i_PUBKEY, fp, a);
-}
-
-PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_bio(BIO *bp,
-                                                 PKCS8_PRIV_KEY_INFO **p8inf)
-{
-    return ASN1_d2i_bio_of(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_new,
-                           d2i_PKCS8_PRIV_KEY_INFO, bp, p8inf);
-}
-
-int i2d_PKCS8_PRIV_KEY_INFO_bio(BIO *bp, PKCS8_PRIV_KEY_INFO *p8inf)
-{
-    return ASN1_i2d_bio_of(PKCS8_PRIV_KEY_INFO, i2d_PKCS8_PRIV_KEY_INFO, bp,
-                           p8inf);
-}
+IMPLEMENT_D2I_BIO(PKCS8_PRIV_KEY_INFO, d2i_PKCS8_PRIV_KEY_INFO_bio,
+                  d2i_PKCS8_PRIV_KEY_INFO)
+IMPLEMENT_I2D_BIO(PKCS8_PRIV_KEY_INFO, i2d_PKCS8_PRIV_KEY_INFO_bio,
+                  i2d_PKCS8_PRIV_KEY_INFO)
 
 int i2d_PKCS8PrivateKeyInfo_bio(BIO *bp, EVP_PKEY *key)
 {
@@ -482,32 +390,11 @@
 }
 #endif
 
-int i2d_PrivateKey_bio(BIO *bp, EVP_PKEY *pkey)
-{
-    return ASN1_i2d_bio_of_const(EVP_PKEY, i2d_PrivateKey, bp, pkey);
-}
+IMPLEMENT_D2I_BIO(EVP_PKEY, d2i_PrivateKey_bio, d2i_AutoPrivateKey)
+IMPLEMENT_I2D_BIO(EVP_PKEY, i2d_PrivateKey_bio, i2d_PrivateKey)
 
-EVP_PKEY *d2i_PrivateKey_bio(BIO *bp, EVP_PKEY **a)
-{
-    return ASN1_d2i_bio_of(EVP_PKEY, EVP_PKEY_new, d2i_AutoPrivateKey, bp, a);
-}
+IMPLEMENT_D2I_BIO(EVP_PKEY, d2i_PUBKEY_bio, d2i_PUBKEY)
+IMPLEMENT_I2D_BIO(EVP_PKEY, i2d_PUBKEY_bio, i2d_PUBKEY)
 
-int i2d_PUBKEY_bio(BIO *bp, EVP_PKEY *pkey)
-{
-    return ASN1_i2d_bio_of_const(EVP_PKEY, i2d_PUBKEY, bp, pkey);
-}
-
-EVP_PKEY *d2i_PUBKEY_bio(BIO *bp, EVP_PKEY **a)
-{
-    return ASN1_d2i_bio_of(EVP_PKEY, EVP_PKEY_new, d2i_PUBKEY, bp, a);
-}
-
-DH *d2i_DHparams_bio(BIO *bp, DH **dh)
-{
-    return ASN1_d2i_bio_of(DH, DH_new, d2i_DHparams, bp, dh);
-}
-
-int i2d_DHparams_bio(BIO *bp, const DH *dh)
-{
-    return ASN1_i2d_bio_of_const(DH, i2d_DHparams, bp, dh);
-}
+IMPLEMENT_D2I_BIO(DH, d2i_DHparams_bio, d2i_DHparams)
+IMPLEMENT_I2D_BIO(const DH, i2d_DHparams_bio, i2d_DHparams)
diff --git a/crypto/x509v3/v3_genn.c b/crypto/x509v3/v3_genn.c
index 8c92687..552a524 100644
--- a/crypto/x509v3/v3_genn.c
+++ b/crypto/x509v3/v3_genn.c
@@ -100,12 +100,7 @@
 
 IMPLEMENT_ASN1_FUNCTIONS(GENERAL_NAMES)
 
-GENERAL_NAME *GENERAL_NAME_dup(GENERAL_NAME *a)
-{
-    return (GENERAL_NAME *)ASN1_dup((i2d_of_void *)i2d_GENERAL_NAME,
-                                    (d2i_of_void *)d2i_GENERAL_NAME,
-                                    (char *)a);
-}
+IMPLEMENT_ASN1_DUP_FUNCTION(GENERAL_NAME)
 
 /* Returns 0 if they are equal, != 0 otherwise. */
 int GENERAL_NAME_cmp(GENERAL_NAME *a, GENERAL_NAME *b)
diff --git a/include/openssl/asn1.h b/include/openssl/asn1.h
index 46e5f53..7be3d63 100644
--- a/include/openssl/asn1.h
+++ b/include/openssl/asn1.h
@@ -302,15 +302,6 @@
 #define I2D_OF(type) int (*)(type *,unsigned char **)
 #define I2D_OF_const(type) int (*)(const type *,unsigned char **)
 
-#define CHECKED_D2I_OF(type, d2i) \
-    ((d2i_of_void*) (1 ? d2i : ((D2I_OF(type))0)))
-#define CHECKED_I2D_OF(type, i2d) \
-    ((i2d_of_void*) (1 ? i2d : ((I2D_OF(type))0)))
-#define CHECKED_NEW_OF(type, xnew) \
-    ((void *(*)(void)) (1 ? xnew : ((type *(*)(void))0)))
-#define CHECKED_PPTR_OF(type, p) \
-    ((void**) (1 ? p : (type**)0))
-
 typedef void *d2i_of_void(void **, const unsigned char **, long);
 typedef int i2d_of_void(const void *, unsigned char **);
 
@@ -762,76 +753,17 @@
 OPENSSL_EXPORT int ASN1_put_eoc(unsigned char **pp);
 OPENSSL_EXPORT int ASN1_object_size(int constructed, int length, int tag);
 
-/* Used to implement other functions */
-OPENSSL_EXPORT void *ASN1_dup(i2d_of_void *i2d, d2i_of_void *d2i, void *x);
-
-#define ASN1_dup_of(type,i2d,d2i,x) \
-    ((type*)ASN1_dup(CHECKED_I2D_OF(type, i2d), \
-		     CHECKED_D2I_OF(type, d2i), \
-		     CHECKED_PTR_OF(type, x)))
-
-#define ASN1_dup_of_const(type,i2d,d2i,x) \
-    ((type*)ASN1_dup(CHECKED_I2D_OF(const type, i2d), \
-		     CHECKED_D2I_OF(type, d2i), \
-		     CHECKED_PTR_OF(const type, x)))
-
 OPENSSL_EXPORT void *ASN1_item_dup(const ASN1_ITEM *it, void *x);
 
-/* ASN1 alloc/free macros for when a type is only used internally */
-
-#define M_ASN1_new_of(type) (type *)ASN1_item_new(ASN1_ITEM_rptr(type))
-#define M_ASN1_free_of(x, type) \
-		ASN1_item_free(CHECKED_PTR_OF(type, x), ASN1_ITEM_rptr(type))
-
 #ifndef OPENSSL_NO_FP_API
-OPENSSL_EXPORT void *ASN1_d2i_fp(void *(*xnew)(void), d2i_of_void *d2i, FILE *in, void **x);
-
-#define ASN1_d2i_fp_of(type,xnew,d2i,in,x) \
-    ((type*)ASN1_d2i_fp(CHECKED_NEW_OF(type, xnew), \
-			CHECKED_D2I_OF(type, d2i), \
-			in, \
-			CHECKED_PPTR_OF(type, x)))
-
 OPENSSL_EXPORT void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x);
-OPENSSL_EXPORT int ASN1_i2d_fp(i2d_of_void *i2d,FILE *out,void *x);
-
-#define ASN1_i2d_fp_of(type,i2d,out,x) \
-    (ASN1_i2d_fp(CHECKED_I2D_OF(type, i2d), \
-		 out, \
-		 CHECKED_PTR_OF(type, x)))
-
-#define ASN1_i2d_fp_of_const(type,i2d,out,x) \
-    (ASN1_i2d_fp(CHECKED_I2D_OF(const type, i2d), \
-		 out, \
-		 CHECKED_PTR_OF(const type, x)))
-
 OPENSSL_EXPORT int ASN1_item_i2d_fp(const ASN1_ITEM *it, FILE *out, void *x);
 OPENSSL_EXPORT int ASN1_STRING_print_ex_fp(FILE *fp, ASN1_STRING *str, unsigned long flags);
 #endif
 
 OPENSSL_EXPORT int ASN1_STRING_to_UTF8(unsigned char **out, ASN1_STRING *in);
 
-OPENSSL_EXPORT void *ASN1_d2i_bio(void *(*xnew)(void), d2i_of_void *d2i, BIO *in, void **x);
-
-#define ASN1_d2i_bio_of(type,xnew,d2i,in,x) \
-    ((type*)ASN1_d2i_bio( CHECKED_NEW_OF(type, xnew), \
-			  CHECKED_D2I_OF(type, d2i), \
-			  in, \
-			  CHECKED_PPTR_OF(type, x)))
-
 OPENSSL_EXPORT void *ASN1_item_d2i_bio(const ASN1_ITEM *it, BIO *in, void *x);
-OPENSSL_EXPORT int ASN1_i2d_bio(i2d_of_void *i2d,BIO *out, void *x);
-
-#define ASN1_i2d_bio_of(type,i2d,out,x) \
-    (ASN1_i2d_bio(CHECKED_I2D_OF(type, i2d), \
-		  out, \
-		  CHECKED_PTR_OF(type, x)))
-
-#define ASN1_i2d_bio_of_const(type,i2d,out,x) \
-    (ASN1_i2d_bio(CHECKED_I2D_OF(const type, i2d), \
-		  out, \
-		  CHECKED_PTR_OF(const type, x)))
-
 OPENSSL_EXPORT int ASN1_item_i2d_bio(const ASN1_ITEM *it, BIO *out, void *x);
 OPENSSL_EXPORT int ASN1_UTCTIME_print(BIO *fp, const ASN1_UTCTIME *a);
 OPENSSL_EXPORT int ASN1_GENERALIZEDTIME_print(BIO *fp, const ASN1_GENERALIZEDTIME *a);
diff --git a/include/openssl/bio.h b/include/openssl/bio.h
index 70c2fbf..8e2db65 100644
--- a/include/openssl/bio.h
+++ b/include/openssl/bio.h
@@ -117,10 +117,14 @@
 // return a line for this call, remove the warning above.
 OPENSSL_EXPORT int BIO_gets(BIO *bio, char *buf, int size);
 
-// BIO_write writes |len| bytes from |data| to BIO. It returns the number of
+// BIO_write writes |len| bytes from |data| to |bio|. It returns the number of
 // bytes written or a negative number on error.
 OPENSSL_EXPORT int BIO_write(BIO *bio, const void *data, int len);
 
+// BIO_write_all writes |len| bytes from |data| to |bio|, looping as necessary.
+// It returns one if all bytes were successfully written and zero on error.
+OPENSSL_EXPORT int BIO_write_all(BIO *bio, const void *data, size_t len);
+
 // BIO_puts writes a NUL terminated string from |buf| to |bio|. It returns the
 // number of bytes written or a negative number on error.
 OPENSSL_EXPORT int BIO_puts(BIO *bio, const char *buf);
diff --git a/include/openssl/type_check.h b/include/openssl/type_check.h
index da78d70..e5d7047 100644
--- a/include/openssl/type_check.h
+++ b/include/openssl/type_check.h
@@ -72,10 +72,6 @@
 // CHECKED_CAST casts |p| from type |from| to type |to|.
 #define CHECKED_CAST(to, from, p) ((to) (1 ? (p) : (from)0))
 
-// CHECKED_PTR_OF casts a given pointer to void* and statically checks that it
-// was a pointer to |type|.
-#define CHECKED_PTR_OF(type, p) CHECKED_CAST(void*, type*, (p))
-
 #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
 #define OPENSSL_COMPILE_ASSERT(cond, msg) _Static_assert(cond, #msg)
 #else
diff --git a/ssl/ssl_x509.cc b/ssl/ssl_x509.cc
index 9fa800f..ec203b2 100644
--- a/ssl/ssl_x509.cc
+++ b/ssl/ssl_x509.cc
@@ -999,17 +999,25 @@
   return 1;
 }
 
-static SSL_SESSION *ssl_session_new_with_crypto_x509(void) {
-  return ssl_session_new(&ssl_crypto_x509_method).release();
-}
-
 SSL_SESSION *d2i_SSL_SESSION_bio(BIO *bio, SSL_SESSION **out) {
-  return ASN1_d2i_bio_of(SSL_SESSION, ssl_session_new_with_crypto_x509,
-                         d2i_SSL_SESSION, bio, out);
+  uint8_t *data;
+  size_t len;
+  if (!BIO_read_asn1(bio, &data, &len, 1024 * 1024)) {
+    return 0;
+  }
+  bssl::UniquePtr<uint8_t> free_data(data);
+  const uint8_t *ptr = data;
+  return d2i_SSL_SESSION(out, &ptr, static_cast<long>(len));
 }
 
 int i2d_SSL_SESSION_bio(BIO *bio, const SSL_SESSION *session) {
-  return ASN1_i2d_bio_of(SSL_SESSION, i2d_SSL_SESSION, bio, session);
+  uint8_t *data;
+  size_t len;
+  if (!SSL_SESSION_to_bytes(session, &data, &len)) {
+    return 0;
+  }
+  bssl::UniquePtr<uint8_t> free_data(data);
+  return BIO_write_all(bio, data, len);
 }
 
 IMPLEMENT_PEM_rw(SSL_SESSION, SSL_SESSION, PEM_STRING_SSL_SESSION, SSL_SESSION)