Add i2d_PKCS12*.

This is not very useful without PKCS12_create, which a follow-up change
will implement.

Change-Id: I355ccd22a165830911ae189871ab90a6101f42ae
Reviewed-on: https://boringssl-review.googlesource.com/28327
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/pkcs8/pkcs8_x509.c b/crypto/pkcs8/pkcs8_x509.c
index b3e2d93..30b76c5 100644
--- a/crypto/pkcs8/pkcs8_x509.c
+++ b/crypto/pkcs8/pkcs8_x509.c
@@ -714,6 +714,55 @@
   return ret;
 }
 
+int i2d_PKCS12(const PKCS12 *p12, uint8_t **out) {
+  if (p12->ber_len > INT_MAX) {
+    OPENSSL_PUT_ERROR(PKCS8, ERR_R_OVERFLOW);
+    return -1;
+  }
+
+  if (out == NULL) {
+    return (int)p12->ber_len;
+  }
+
+  if (*out == NULL) {
+    *out = OPENSSL_malloc(p12->ber_len);
+    if (*out == NULL) {
+      OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
+      return -1;
+    }
+    OPENSSL_memcpy(*out, p12->ber_bytes, p12->ber_len);
+  } else {
+    OPENSSL_memcpy(*out, p12->ber_bytes, p12->ber_len);
+    *out += p12->ber_len;
+  }
+  return (int)p12->ber_len;
+}
+
+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;
+}
+
+int i2d_PKCS12_fp(FILE *fp, const PKCS12 *p12) {
+  BIO *bio = BIO_new_fp(fp, 0 /* don't take ownership */);
+  if (bio == NULL) {
+    return 0;
+  }
+
+  int ret = i2d_PKCS12_bio(bio, p12);
+  BIO_free(bio);
+  return ret;
+}
+
 int PKCS12_parse(const PKCS12 *p12, const char *password, EVP_PKEY **out_pkey,
                  X509 **out_cert, STACK_OF(X509) **out_ca_certs) {
   CBS ber_bytes;
diff --git a/include/openssl/pkcs8.h b/include/openssl/pkcs8.h
index f84906f..05c635e 100644
--- a/include/openssl/pkcs8.h
+++ b/include/openssl/pkcs8.h
@@ -152,6 +152,20 @@
 // d2i_PKCS12_fp acts like |d2i_PKCS12| but reads from a |FILE|.
 OPENSSL_EXPORT PKCS12* d2i_PKCS12_fp(FILE *fp, PKCS12 **out_p12);
 
+// i2d_PKCS12 is a dummy function which copies the contents of |p12|. If |out|
+// is not NULL then the result is written to |*out| and |*out| is advanced just
+// past the output. It returns the number of bytes in the result, whether
+// written or not, or a negative value on error.
+OPENSSL_EXPORT int i2d_PKCS12(const PKCS12 *p12, uint8_t **out);
+
+// i2d_PKCS12_bio writes the contents of |p12| to |bio|. It returns one on
+// success and zero on error.
+OPENSSL_EXPORT int i2d_PKCS12_bio(BIO *bio, const PKCS12 *p12);
+
+// i2d_PKCS12_fp writes the contents of |p12| to |fp|. It returns one on
+// success and zero on error.
+OPENSSL_EXPORT int i2d_PKCS12_fp(FILE *fp, const PKCS12 *p12);
+
 // PKCS12_parse calls |PKCS12_get_key_and_certs| on the ASN.1 data stored in
 // |p12|. The |out_pkey| and |out_cert| arguments must not be NULL and, on
 // successful exit, the private key and first certificate will be stored in