Add functions to parse and generate PKCS#7 files with CRLs.

Change-Id: I7b6acc9004beb7b7090de1837814ccdff2e9930e
Reviewed-on: https://boringssl-review.googlesource.com/3680
Reviewed-by: David Benjamin <davidben@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/err/err_data.h b/crypto/err/err_data.h
index 8e78309..1a68170 100644
--- a/crypto/err/err_data.h
+++ b/crypto/err/err_data.h
@@ -210,58 +210,60 @@
     0x2c332806,
     0x2c33a817,
     0x2c342830,
-    0x2c34a849,
-    0x2c352860,
-    0x2c35a87d,
-    0x2c36289a,
-    0x2c36a8b7,
-    0x2c3728d0,
-    0x2c37a8e9,
-    0x2c3828ff,
-    0x2c38a90d,
-    0x2c39291f,
-    0x2c39a93c,
-    0x2c3a2959,
-    0x2c3aa967,
-    0x2c3b2985,
-    0x2c3ba9a3,
-    0x2c3c29be,
-    0x2c3ca9d2,
-    0x2c3d29e4,
-    0x2c3da9f4,
-    0x2c3e2a02,
-    0x2c3eaa12,
-    0x2c3f2a22,
-    0x2c3faa3d,
-    0x2c402a4e,
-    0x2c40aa69,
-    0x2c412a7d,
-    0x2c41aa90,
-    0x2c422aaf,
-    0x2c42aac3,
-    0x2c432ad6,
-    0x2c43aae5,
-    0x2c442af4,
-    0x2c44ab0b,
-    0x2c452b26,
-    0x2c45ab3e,
-    0x2c462b52,
-    0x2c46ab65,
-    0x2c472b76,
-    0x2c47ab87,
-    0x2c482b98,
-    0x2c48aba9,
-    0x2c492bb8,
-    0x2c49abc5,
-    0x2c4a2bd2,
-    0x2c4aabdf,
-    0x2c4b2be8,
-    0x2c4babfc,
-    0x2c4c2c0b,
-    0x2c4cac19,
-    0x2c4d2c28,
-    0x2c4dac39,
-    0x2c4e2c4a,
+    0x2c34a858,
+    0x2c35286f,
+    0x2c35a88c,
+    0x2c3628a9,
+    0x2c36a8c6,
+    0x2c3728df,
+    0x2c37a8f8,
+    0x2c38290e,
+    0x2c38a91c,
+    0x2c39292e,
+    0x2c39a94b,
+    0x2c3a2968,
+    0x2c3aa976,
+    0x2c3b2994,
+    0x2c3ba9b2,
+    0x2c3c29cd,
+    0x2c3ca9e1,
+    0x2c3d29f3,
+    0x2c3daa03,
+    0x2c3e2a11,
+    0x2c3eaa21,
+    0x2c3f2a31,
+    0x2c3faa4c,
+    0x2c402a5d,
+    0x2c40aa78,
+    0x2c412a8c,
+    0x2c41aa9f,
+    0x2c422abe,
+    0x2c42aad2,
+    0x2c432ae5,
+    0x2c43aaf4,
+    0x2c442b03,
+    0x2c44ab1a,
+    0x2c452b35,
+    0x2c45ab4d,
+    0x2c462b61,
+    0x2c46ab74,
+    0x2c472b85,
+    0x2c47ab96,
+    0x2c482ba7,
+    0x2c48abb8,
+    0x2c492bc7,
+    0x2c49abd4,
+    0x2c4a2be1,
+    0x2c4aabee,
+    0x2c4b2bf7,
+    0x2c4bac0b,
+    0x2c4c2c1a,
+    0x2c4cac28,
+    0x2c4d2c4a,
+    0x2c4dac5b,
+    0x2c4e2c6c,
+    0x2c4eac37,
+    0x2c4f2849,
     0x30320000,
     0x30328018,
     0x3033002c,
@@ -592,63 +594,63 @@
     0x4c3996e4,
     0x4c3a16fc,
     0x4c3a970f,
-    0x50322c5b,
-    0x5032ac70,
-    0x50332c81,
-    0x5033ac94,
-    0x50342ca5,
-    0x5034acb8,
-    0x50352cc7,
-    0x5035acdc,
-    0x50362cec,
-    0x5036acfb,
-    0x50372d0c,
-    0x5037ad1c,
-    0x50382d2d,
-    0x5038ad40,
-    0x50392d52,
-    0x5039ad68,
-    0x503a2d7a,
-    0x503aad8b,
-    0x503b2d9c,
-    0x503badad,
-    0x503c2db8,
-    0x503cadc4,
-    0x503d2dcf,
-    0x503dadda,
-    0x503e2de7,
-    0x503eadfc,
-    0x503f2e0a,
-    0x503fae1e,
-    0x50402e31,
-    0x5040ae42,
-    0x50412e5c,
-    0x5041ae6b,
-    0x50422e74,
-    0x5042ae83,
-    0x50432e95,
-    0x5043aea1,
-    0x50442ea9,
-    0x5044aebc,
-    0x50452ecd,
-    0x5045aee3,
-    0x50462eef,
-    0x5046af03,
-    0x50472f11,
-    0x5047af25,
-    0x50482f3f,
-    0x5048af53,
-    0x50492f69,
-    0x5049af80,
-    0x504a2f92,
-    0x504aafa6,
-    0x504b2fbb,
-    0x504bafd2,
-    0x504c2fe6,
-    0x504cafef,
-    0x504d2ff7,
-    0x504db006,
-    0x504e3016,
+    0x50322c7d,
+    0x5032ac92,
+    0x50332ca3,
+    0x5033acb6,
+    0x50342cc7,
+    0x5034acda,
+    0x50352ce9,
+    0x5035acfe,
+    0x50362d0e,
+    0x5036ad1d,
+    0x50372d2e,
+    0x5037ad3e,
+    0x50382d4f,
+    0x5038ad62,
+    0x50392d74,
+    0x5039ad8a,
+    0x503a2d9c,
+    0x503aadad,
+    0x503b2dbe,
+    0x503badcf,
+    0x503c2dda,
+    0x503cade6,
+    0x503d2df1,
+    0x503dadfc,
+    0x503e2e09,
+    0x503eae1e,
+    0x503f2e2c,
+    0x503fae40,
+    0x50402e53,
+    0x5040ae64,
+    0x50412e7e,
+    0x5041ae8d,
+    0x50422e96,
+    0x5042aea5,
+    0x50432eb7,
+    0x5043aec3,
+    0x50442ecb,
+    0x5044aede,
+    0x50452eef,
+    0x5045af05,
+    0x50462f11,
+    0x5046af25,
+    0x50472f33,
+    0x5047af47,
+    0x50482f61,
+    0x5048af75,
+    0x50492f8b,
+    0x5049afa2,
+    0x504a2fb4,
+    0x504aafc8,
+    0x504b2fdd,
+    0x504baff4,
+    0x504c3008,
+    0x504cb011,
+    0x504d3019,
+    0x504db028,
+    0x504e3038,
     0x68320f9d,
     0x68328fae,
     0x68330fbe,
@@ -1219,6 +1221,7 @@
     "ASN1_item_verify\0"
     "NETSCAPE_SPKI_b64_decode\0"
     "NETSCAPE_SPKI_b64_encode\0"
+    "PKCS7_get_CRLs\0"
     "PKCS7_get_certificates\0"
     "X509_ATTRIBUTE_create_by_NID\0"
     "X509_ATTRIBUTE_create_by_OBJ\0"
@@ -1268,6 +1271,7 @@
     "i2d_DSA_PUBKEY\0"
     "i2d_EC_PUBKEY\0"
     "i2d_RSA_PUBKEY\0"
+    "pkcs7_parse_header\0"
     "x509_name_encode\0"
     "x509_name_ex_d2i\0"
     "x509_name_ex_new\0"
@@ -1480,19 +1484,20 @@
     0x2c3c2af3,
     0x2c3cab09,
     0x2c3d2b22,
-    0x2c3dab3f,
-    0x2c3e2b4d,
-    0x2c3eab65,
-    0x2c3f2b7d,
-    0x2c3fab8a,
-    0x2c402bad,
-    0x2c40abcc,
+    0x2c3dab50,
+    0x2c3e2b5e,
+    0x2c3eab76,
+    0x2c3f2b8e,
+    0x2c3fab9b,
+    0x2c402bbe,
+    0x2c40abdd,
     0x2c411151,
-    0x2c41abdd,
-    0x2c422bf0,
+    0x2c41abee,
+    0x2c422c01,
     0x2c4290c3,
-    0x2c432c01,
+    0x2c432c12,
     0x2c4386a2,
+    0x2c442b3f,
     0x30320000,
     0x30328015,
     0x3033001f,
@@ -1856,69 +1861,69 @@
     0x4c3d104b,
     0x4c3d93d7,
     0x4c3e13e4,
-    0x50322c13,
-    0x5032ac22,
-    0x50332c2d,
-    0x5033ac3d,
-    0x50342c56,
-    0x5034ac70,
-    0x50352c7e,
-    0x5035ac94,
-    0x50362ca6,
-    0x5036acbc,
-    0x50372cd5,
-    0x5037ace8,
-    0x50382d00,
-    0x5038ad11,
-    0x50392d26,
-    0x5039ad3a,
-    0x503a2d5a,
-    0x503aad70,
-    0x503b2d88,
-    0x503bad9a,
-    0x503c2db6,
-    0x503cadcd,
-    0x503d2de6,
-    0x503dadfc,
-    0x503e2e09,
-    0x503eae1f,
-    0x503f2e31,
+    0x50322c24,
+    0x5032ac33,
+    0x50332c3e,
+    0x5033ac4e,
+    0x50342c67,
+    0x5034ac81,
+    0x50352c8f,
+    0x5035aca5,
+    0x50362cb7,
+    0x5036accd,
+    0x50372ce6,
+    0x5037acf9,
+    0x50382d11,
+    0x5038ad22,
+    0x50392d37,
+    0x5039ad4b,
+    0x503a2d6b,
+    0x503aad81,
+    0x503b2d99,
+    0x503badab,
+    0x503c2dc7,
+    0x503cadde,
+    0x503d2df7,
+    0x503dae0d,
+    0x503e2e1a,
+    0x503eae30,
+    0x503f2e42,
     0x503f8348,
-    0x50402e44,
-    0x5040ae54,
-    0x50412e6e,
-    0x5041ae7d,
-    0x50422e97,
-    0x5042aeb4,
-    0x50432ec4,
-    0x5043aed4,
-    0x50442ee3,
+    0x50402e55,
+    0x5040ae65,
+    0x50412e7f,
+    0x5041ae8e,
+    0x50422ea8,
+    0x5042aec5,
+    0x50432ed5,
+    0x5043aee5,
+    0x50442ef4,
     0x50448414,
-    0x50452ef7,
-    0x5045af15,
-    0x50462f28,
-    0x5046af3e,
-    0x50472f50,
-    0x5047af65,
-    0x50482f8b,
-    0x5048af99,
-    0x50492fac,
-    0x5049afc1,
-    0x504a2fd7,
-    0x504aafe7,
-    0x504b3007,
-    0x504bb01a,
-    0x504c303d,
-    0x504cb06b,
-    0x504d307d,
-    0x504db09a,
-    0x504e30b5,
-    0x504eb0d1,
-    0x504f30e3,
-    0x504fb0fa,
-    0x50503109,
+    0x50452f08,
+    0x5045af26,
+    0x50462f39,
+    0x5046af4f,
+    0x50472f61,
+    0x5047af76,
+    0x50482f9c,
+    0x5048afaa,
+    0x50492fbd,
+    0x5049afd2,
+    0x504a2fe8,
+    0x504aaff8,
+    0x504b3018,
+    0x504bb02b,
+    0x504c304e,
+    0x504cb07c,
+    0x504d308e,
+    0x504db0ab,
+    0x504e30c6,
+    0x504eb0e2,
+    0x504f30f4,
+    0x504fb10b,
+    0x5050311a,
     0x50508687,
-    0x5051311c,
+    0x5051312d,
     0x58320dd6,
     0x68320d98,
     0x68328b7d,
@@ -2473,6 +2478,7 @@
     "NOT_PKCS7_SIGNED_DATA\0"
     "NO_CERTIFICATES_INCLUDED\0"
     "NO_CERT_SET_FOR_US_TO_VERIFY\0"
+    "NO_CRLS_INCLUDED\0"
     "NO_CRL_NUMBER\0"
     "PUBLIC_KEY_DECODE_ERROR\0"
     "PUBLIC_KEY_ENCODE_ERROR\0"
diff --git a/crypto/err/x509.errordata b/crypto/err/x509.errordata
index f6fbf0f..1b50e36 100644
--- a/crypto/err/x509.errordata
+++ b/crypto/err/x509.errordata
@@ -3,6 +3,7 @@
 X509,function,102,ASN1_item_verify
 X509,function,103,NETSCAPE_SPKI_b64_decode
 X509,function,104,NETSCAPE_SPKI_b64_encode
+X509,function,158,PKCS7_get_CRLs
 X509,function,105,PKCS7_get_certificates
 X509,function,106,X509_ATTRIBUTE_create_by_NID
 X509,function,107,X509_ATTRIBUTE_create_by_OBJ
@@ -52,6 +53,7 @@
 X509,function,151,i2d_DSA_PUBKEY
 X509,function,152,i2d_EC_PUBKEY
 X509,function,153,i2d_RSA_PUBKEY
+X509,function,157,pkcs7_parse_header
 X509,function,154,x509_name_encode
 X509,function,155,x509_name_ex_d2i
 X509,function,156,x509_name_ex_new
@@ -78,6 +80,7 @@
 X509,reason,120,NOT_PKCS7_SIGNED_DATA
 X509,reason,121,NO_CERTIFICATES_INCLUDED
 X509,reason,122,NO_CERT_SET_FOR_US_TO_VERIFY
+X509,reason,136,NO_CRLS_INCLUDED
 X509,reason,123,NO_CRL_NUMBER
 X509,reason,124,PUBLIC_KEY_DECODE_ERROR
 X509,reason,125,PUBLIC_KEY_ENCODE_ERROR
diff --git a/crypto/x509/pkcs7.c b/crypto/x509/pkcs7.c
index 75c101b..9a4e490 100644
--- a/crypto/x509/pkcs7.c
+++ b/crypto/x509/pkcs7.c
@@ -14,6 +14,8 @@
 
 #include <openssl/x509.h>
 
+#include <assert.h>
+
 #include <openssl/bytestring.h>
 #include <openssl/err.h>
 #include <openssl/obj.h>
@@ -22,21 +24,26 @@
 #include "../bytestring/internal.h"
 
 
-int PKCS7_get_certificates(STACK_OF(X509) *out_certs, CBS *cbs) {
-  uint8_t *der_bytes = NULL;
+/* pkcs7_parse_header reads the non-certificate/non-CRL prefix of a PKCS#7
+ * SignedData blob from |cbs| and sets |*out| to point to the rest of the
+ * input. If the input is in BER format, then |*der_bytes| will be set to a
+ * pointer that needs to be freed by the caller once they have finished
+ * processing |*out| (which will be pointing into |*der_bytes|).
+ *
+ * It returns one on success or zero on error. On error, |*der_bytes| is
+ * NULL. */
+static int pkcs7_parse_header(uint8_t **der_bytes, CBS *out, CBS *cbs) {
   size_t der_len;
-  CBS in, content_info, content_type, wrapped_signed_data, signed_data,
-      certificates;
-  const size_t initial_certs_len = sk_X509_num(out_certs);
+  CBS in, content_info, content_type, wrapped_signed_data, signed_data;
   uint64_t version;
-  int ret = 0;
 
   /* The input may be in BER format. */
-  if (!CBS_asn1_ber_to_der(cbs, &der_bytes, &der_len)) {
+  *der_bytes = NULL;
+  if (!CBS_asn1_ber_to_der(cbs, der_bytes, &der_len)) {
     return 0;
   }
-  if (der_bytes != NULL) {
-    CBS_init(&in, der_bytes, der_len);
+  if (*der_bytes != NULL) {
+    CBS_init(&in, *der_bytes, der_len);
   } else {
     CBS_init(&in, CBS_data(cbs), CBS_len(cbs));
   }
@@ -48,7 +55,7 @@
   }
 
   if (OBJ_cbs2nid(&content_type) != NID_pkcs7_signed) {
-    OPENSSL_PUT_ERROR(X509, PKCS7_get_certificates,
+    OPENSSL_PUT_ERROR(X509, pkcs7_parse_header,
                       X509_R_NOT_PKCS7_SIGNED_DATA);
     goto err;
   }
@@ -64,11 +71,34 @@
   }
 
   if (version < 1) {
-    OPENSSL_PUT_ERROR(X509, PKCS7_get_certificates,
+    OPENSSL_PUT_ERROR(X509, pkcs7_parse_header,
                       X509_R_BAD_PKCS7_VERSION);
     goto err;
   }
 
+  CBS_init(out, CBS_data(&signed_data), CBS_len(&signed_data));
+  return 1;
+
+err:
+  if (*der_bytes) {
+    OPENSSL_free(*der_bytes);
+    *der_bytes = NULL;
+  }
+
+  return 0;
+}
+
+int PKCS7_get_certificates(STACK_OF(X509) *out_certs, CBS *cbs) {
+  CBS signed_data, certificates;
+  uint8_t *der_bytes = NULL;
+  int ret = 0;
+  const size_t initial_certs_len = sk_X509_num(out_certs);
+
+  if (!pkcs7_parse_header(&der_bytes, &signed_data, cbs)) {
+    return 0;
+  }
+
+  /* See https://tools.ietf.org/html/rfc2315#section-9.1 */
   if (!CBS_get_asn1(&signed_data, &certificates,
                     CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) {
     OPENSSL_PUT_ERROR(X509, PKCS7_get_certificates,
@@ -91,12 +121,12 @@
       goto err;
     }
 
-    if (inp != CBS_data(&cert) + CBS_len(&cert)) {
-      /* This suggests a disconnect between the two ASN.1 parsers. */
+    assert(inp == CBS_data(&cert) + CBS_len(&cert));
+
+    if (sk_X509_push(out_certs, x509) == 0) {
+      X509_free(x509);
       goto err;
     }
-
-    sk_X509_push(out_certs, x509);
   }
 
   ret = 1;
@@ -116,10 +146,83 @@
   return ret;
 }
 
-int PKCS7_bundle_certificates(CBB *out, const STACK_OF(X509) *certs) {
+int PKCS7_get_CRLs(STACK_OF(X509_CRL) *out_crls, CBS *cbs) {
+  CBS signed_data, crls;
+  uint8_t *der_bytes = NULL;
+  int ret = 0;
+  const size_t initial_crls_len = sk_X509_CRL_num(out_crls);
+
+  if (!pkcs7_parse_header(&der_bytes, &signed_data, cbs)) {
+    return 0;
+  }
+
+  /* See https://tools.ietf.org/html/rfc2315#section-9.1 */
+
+  /* Even if only CRLs are included, there may be an empty certificates block.
+   * OpenSSL does this, for example. */
+  if (CBS_peek_asn1_tag(&signed_data,
+                        CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) &&
+      !CBS_get_asn1(&signed_data, NULL /* certificates */,
+                    CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) {
+    goto err;
+  }
+
+  if (!CBS_get_asn1(&signed_data, &crls,
+                    CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1)) {
+    OPENSSL_PUT_ERROR(X509, PKCS7_get_CRLs,
+                      X509_R_NO_CRLS_INCLUDED);
+    goto err;
+  }
+
+  while (CBS_len(&crls) > 0) {
+    CBS crl_data;
+    X509_CRL *crl;
+    const uint8_t *inp;
+
+    if (!CBS_get_asn1_element(&crls, &crl_data, CBS_ASN1_SEQUENCE)) {
+      goto err;
+    }
+
+    inp = CBS_data(&crl_data);
+    crl = d2i_X509_CRL(NULL, &inp, CBS_len(&crl_data));
+    if (!crl) {
+      goto err;
+    }
+
+    assert(inp == CBS_data(&crl_data) + CBS_len(&crl_data));
+
+    if (sk_X509_CRL_push(out_crls, crl) == 0) {
+      X509_CRL_free(crl);
+      goto err;
+    }
+  }
+
+  ret = 1;
+
+err:
+  if (der_bytes) {
+    OPENSSL_free(der_bytes);
+  }
+
+  if (!ret) {
+    while (sk_X509_CRL_num(out_crls) != initial_crls_len) {
+      X509_CRL_free(sk_X509_CRL_pop(out_crls));
+    }
+  }
+
+  return ret;
+}
+
+/* pkcs7_bundle writes a PKCS#7, SignedData structure to |out| and then calls
+ * |cb| with a CBB to which certificate or CRL data can be written, and the
+ * opaque context pointer, |arg|. The callback can return zero to indicate an
+ * error.
+ *
+ * pkcs7_bundle returns one on success or zero on error. */
+static int pkcs7_bundle(CBB *out, int (*cb)(CBB *out, const void *arg),
+                        const void *arg) {
   CBB outer_seq, wrapped_seq, seq, version_bytes, digest_algos_set,
-      content_info, certificates;
-  size_t i;
+      content_info;
 
   /* See https://tools.ietf.org/html/rfc2315#section-7 */
   if (!CBB_add_asn1(out, &outer_seq, CBS_ASN1_SEQUENCE) ||
@@ -133,7 +236,20 @@
       !CBB_add_asn1(&seq, &digest_algos_set, CBS_ASN1_SET) ||
       !CBB_add_asn1(&seq, &content_info, CBS_ASN1_SEQUENCE) ||
       !OBJ_nid2cbb(&content_info, NID_pkcs7_data) ||
-      !CBB_add_asn1(&seq, &certificates,
+      !cb(&seq, arg)) {
+    return 0;
+  }
+
+  return CBB_flush(out);
+}
+
+static int pkcs7_bundle_certificates_cb(CBB *out, const void *arg) {
+  const STACK_OF(X509) *certs = arg;
+  size_t i;
+  CBB certificates;
+
+  /* See https://tools.ietf.org/html/rfc2315#section-9.1 */
+  if (!CBB_add_asn1(out, &certificates,
                     CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) {
     return 0;
   }
@@ -152,3 +268,37 @@
 
   return CBB_flush(out);
 }
+
+int PKCS7_bundle_certificates(CBB *out, const STACK_OF(X509) *certs) {
+  return pkcs7_bundle(out, pkcs7_bundle_certificates_cb, certs);
+}
+
+static int pkcs7_bundle_crls_cb(CBB *out, const void *arg) {
+  const STACK_OF(X509_CRL) *crls = arg;
+  size_t i;
+  CBB crl_data;
+
+  /* See https://tools.ietf.org/html/rfc2315#section-9.1 */
+  if (!CBB_add_asn1(out, &crl_data,
+                    CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1)) {
+    return 0;
+  }
+
+  for (i = 0; i < sk_X509_CRL_num(crls); i++) {
+    X509_CRL *crl = sk_X509_CRL_value(crls, i);
+    uint8_t *buf;
+    int len = i2d_X509_CRL(crl, NULL);
+
+    if (len < 0 ||
+        !CBB_add_space(&crl_data, &buf, len) ||
+        i2d_X509_CRL(crl, &buf) < 0) {
+      return 0;
+    }
+  }
+
+  return CBB_flush(out);
+}
+
+int PKCS7_bundle_CRLs(CBB *out, const STACK_OF(X509_CRL) *crls) {
+  return pkcs7_bundle(out, pkcs7_bundle_crls_cb, crls);
+}
diff --git a/crypto/x509/pkcs7_test.c b/crypto/x509/pkcs7_test.c
index 4283022..ff61a2b 100644
--- a/crypto/x509/pkcs7_test.c
+++ b/crypto/x509/pkcs7_test.c
@@ -331,7 +331,88 @@
     0xcd, 0x5a, 0x2a, 0x82, 0xb2, 0x37, 0x79, 0x31, 0x00,
 };
 
-static int test_reparse(const uint8_t *der_bytes, size_t der_len) {
+/* kOpenSSLCRL is the Equifax CRL, converted to PKCS#7 form by:
+ *   openssl crl2pkcs7 -inform DER -in secureca.crl  */
+static const uint8_t kOpenSSLCRL[] = {
+    0x30, 0x82, 0x03, 0x85, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+    0x01, 0x07, 0x02, 0xa0, 0x82, 0x03, 0x76, 0x30, 0x82, 0x03, 0x72, 0x02,
+    0x01, 0x01, 0x31, 0x00, 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+    0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x00, 0xa1, 0x82, 0x03, 0x58, 0x30,
+    0x82, 0x03, 0x54, 0x30, 0x82, 0x02, 0xbd, 0x30, 0x0d, 0x06, 0x09, 0x2a,
+    0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x4e,
+    0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
+    0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x07,
+    0x45, 0x71, 0x75, 0x69, 0x66, 0x61, 0x78, 0x31, 0x2d, 0x30, 0x2b, 0x06,
+    0x03, 0x55, 0x04, 0x0b, 0x13, 0x24, 0x45, 0x71, 0x75, 0x69, 0x66, 0x61,
+    0x78, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x43, 0x65, 0x72,
+    0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74,
+    0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x17, 0x0d, 0x31, 0x35, 0x30, 0x32,
+    0x32, 0x37, 0x30, 0x31, 0x32, 0x33, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x31,
+    0x35, 0x30, 0x33, 0x30, 0x39, 0x30, 0x31, 0x32, 0x33, 0x30, 0x30, 0x5a,
+    0x30, 0x82, 0x02, 0x3c, 0x30, 0x14, 0x02, 0x03, 0x0f, 0x58, 0xe4, 0x17,
+    0x0d, 0x31, 0x34, 0x30, 0x34, 0x32, 0x37, 0x30, 0x38, 0x31, 0x39, 0x32,
+    0x32, 0x5a, 0x30, 0x14, 0x02, 0x03, 0x14, 0x76, 0x19, 0x17, 0x0d, 0x31,
+    0x34, 0x30, 0x36, 0x31, 0x38, 0x31, 0x35, 0x30, 0x30, 0x30, 0x33, 0x5a,
+    0x30, 0x14, 0x02, 0x03, 0x0f, 0x9a, 0xfb, 0x17, 0x0d, 0x31, 0x34, 0x30,
+    0x34, 0x32, 0x39, 0x31, 0x38, 0x30, 0x39, 0x31, 0x37, 0x5a, 0x30, 0x14,
+    0x02, 0x03, 0x14, 0x8b, 0xc0, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x37, 0x30,
+    0x39, 0x31, 0x39, 0x34, 0x36, 0x33, 0x33, 0x5a, 0x30, 0x14, 0x02, 0x03,
+    0x14, 0xe4, 0x9c, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x34, 0x31, 0x36, 0x32,
+    0x33, 0x33, 0x39, 0x33, 0x35, 0x5a, 0x30, 0x14, 0x02, 0x03, 0x0f, 0x86,
+    0x07, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x35, 0x32, 0x31, 0x31, 0x35, 0x35,
+    0x30, 0x35, 0x33, 0x5a, 0x30, 0x14, 0x02, 0x03, 0x12, 0xe2, 0x29, 0x17,
+    0x0d, 0x31, 0x34, 0x30, 0x36, 0x31, 0x37, 0x31, 0x38, 0x35, 0x35, 0x31,
+    0x35, 0x5a, 0x30, 0x14, 0x02, 0x03, 0x0d, 0x42, 0x66, 0x17, 0x0d, 0x31,
+    0x32, 0x30, 0x36, 0x32, 0x37, 0x31, 0x37, 0x31, 0x30, 0x35, 0x33, 0x5a,
+    0x30, 0x14, 0x02, 0x03, 0x03, 0x1e, 0x33, 0x17, 0x0d, 0x30, 0x32, 0x30,
+    0x35, 0x31, 0x35, 0x31, 0x33, 0x30, 0x36, 0x31, 0x31, 0x5a, 0x30, 0x14,
+    0x02, 0x03, 0x12, 0xe2, 0x23, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x36, 0x30,
+    0x36, 0x32, 0x30, 0x34, 0x30, 0x32, 0x31, 0x5a, 0x30, 0x14, 0x02, 0x03,
+    0x13, 0x9c, 0xab, 0x17, 0x0d, 0x31, 0x30, 0x30, 0x37, 0x32, 0x39, 0x31,
+    0x36, 0x34, 0x34, 0x33, 0x39, 0x5a, 0x30, 0x14, 0x02, 0x03, 0x12, 0xc6,
+    0x0a, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x36, 0x30, 0x36, 0x32, 0x32, 0x32,
+    0x31, 0x33, 0x39, 0x5a, 0x30, 0x14, 0x02, 0x03, 0x03, 0x25, 0x85, 0x17,
+    0x0d, 0x30, 0x32, 0x30, 0x35, 0x31, 0x34, 0x31, 0x38, 0x31, 0x31, 0x35,
+    0x37, 0x5a, 0x30, 0x14, 0x02, 0x03, 0x14, 0x86, 0xe6, 0x17, 0x0d, 0x31,
+    0x34, 0x30, 0x37, 0x32, 0x35, 0x30, 0x32, 0x30, 0x30, 0x33, 0x38, 0x5a,
+    0x30, 0x14, 0x02, 0x03, 0x13, 0x9c, 0xa1, 0x17, 0x0d, 0x31, 0x30, 0x30,
+    0x37, 0x32, 0x39, 0x31, 0x36, 0x34, 0x37, 0x33, 0x32, 0x5a, 0x30, 0x14,
+    0x02, 0x03, 0x15, 0x4d, 0x5c, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x34, 0x33,
+    0x30, 0x30, 0x30, 0x30, 0x34, 0x34, 0x32, 0x5a, 0x30, 0x14, 0x02, 0x03,
+    0x0f, 0xfa, 0x2d, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x36, 0x31, 0x37, 0x31,
+    0x38, 0x35, 0x30, 0x31, 0x31, 0x5a, 0x30, 0x14, 0x02, 0x03, 0x13, 0x75,
+    0x55, 0x17, 0x0d, 0x31, 0x35, 0x30, 0x31, 0x31, 0x38, 0x30, 0x32, 0x32,
+    0x31, 0x33, 0x33, 0x5a, 0x30, 0x14, 0x02, 0x03, 0x0f, 0x56, 0x96, 0x17,
+    0x0d, 0x31, 0x34, 0x30, 0x36, 0x32, 0x34, 0x31, 0x32, 0x33, 0x31, 0x30,
+    0x32, 0x5a, 0x30, 0x14, 0x02, 0x03, 0x0b, 0x80, 0x8a, 0x17, 0x0d, 0x31,
+    0x32, 0x30, 0x36, 0x32, 0x37, 0x31, 0x37, 0x31, 0x30, 0x32, 0x35, 0x5a,
+    0x30, 0x14, 0x02, 0x03, 0x0f, 0x94, 0x16, 0x17, 0x0d, 0x31, 0x30, 0x30,
+    0x33, 0x30, 0x31, 0x31, 0x33, 0x34, 0x35, 0x33, 0x31, 0x5a, 0x30, 0x14,
+    0x02, 0x03, 0x14, 0x16, 0xb3, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x36, 0x31,
+    0x38, 0x31, 0x34, 0x33, 0x32, 0x35, 0x36, 0x5a, 0x30, 0x14, 0x02, 0x03,
+    0x0a, 0xe1, 0x85, 0x17, 0x0d, 0x31, 0x32, 0x30, 0x36, 0x32, 0x37, 0x31,
+    0x37, 0x31, 0x30, 0x31, 0x37, 0x5a, 0x30, 0x14, 0x02, 0x03, 0x14, 0xcc,
+    0x3e, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x37, 0x31, 0x31, 0x31, 0x32, 0x35,
+    0x35, 0x33, 0x31, 0x5a, 0x30, 0x14, 0x02, 0x03, 0x10, 0x5b, 0xcb, 0x17,
+    0x0d, 0x31, 0x30, 0x30, 0x37, 0x33, 0x30, 0x32, 0x31, 0x33, 0x31, 0x32,
+    0x30, 0x5a, 0x30, 0x14, 0x02, 0x03, 0x15, 0x6a, 0x1f, 0x17, 0x0d, 0x31,
+    0x34, 0x30, 0x32, 0x32, 0x36, 0x31, 0x32, 0x33, 0x35, 0x31, 0x39, 0x5a,
+    0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+    0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x1d, 0x5c, 0x27, 0x07, 0x11,
+    0x03, 0xf2, 0x00, 0xbd, 0xf4, 0x46, 0x3e, 0x71, 0xfd, 0x10, 0x84, 0x83,
+    0xd9, 0xd2, 0xd2, 0x19, 0xa0, 0x20, 0xf7, 0x1a, 0x43, 0x3d, 0xac, 0xda,
+    0x33, 0xfc, 0xb7, 0x42, 0x60, 0x1a, 0xa4, 0xa8, 0xb2, 0x07, 0x5c, 0x51,
+    0x16, 0xc0, 0x42, 0x80, 0x0a, 0x0f, 0xf0, 0x47, 0x5b, 0x4b, 0x78, 0x90,
+    0xaf, 0xc7, 0xac, 0x48, 0xf8, 0xca, 0x3c, 0x13, 0x5e, 0xf6, 0xd1, 0x88,
+    0xae, 0x55, 0xa3, 0x0c, 0x8a, 0x62, 0x47, 0x29, 0xf8, 0x72, 0xb8, 0x24,
+    0x17, 0xaf, 0xb2, 0x06, 0x1e, 0xa7, 0x72, 0x76, 0xab, 0x96, 0x1d, 0xe0,
+    0x7c, 0xd4, 0x0c, 0x42, 0x82, 0x3d, 0x4a, 0x8e, 0x15, 0x77, 0x2f, 0x3c,
+    0x2a, 0x8c, 0x3a, 0x04, 0x10, 0x55, 0xdc, 0xbb, 0xba, 0xb1, 0x91, 0xee,
+    0x7b, 0xe7, 0x23, 0xc5, 0x71, 0x13, 0xae, 0x6b, 0x21, 0x35, 0xd3, 0x64,
+    0xf0, 0x00, 0x54, 0x31, 0x00,
+};
+
+static int test_cert_reparse(const uint8_t *der_bytes, size_t der_len) {
   CBS pkcs7;
   CBB cbb;
   STACK_OF(X509) *certs = sk_X509_new_null();
@@ -395,11 +476,76 @@
   return 1;
 }
 
+static int test_crl_reparse(const uint8_t *der_bytes, size_t der_len) {
+  CBS pkcs7;
+  CBB cbb;
+  STACK_OF(X509_CRL) *crls = sk_X509_CRL_new_null();
+  STACK_OF(X509_CRL) *crls2 = sk_X509_CRL_new_null();
+  uint8_t *result_data, *result2_data;
+  size_t result_len, result2_len, i;
+
+  CBS_init(&pkcs7, der_bytes, der_len);
+  if (!PKCS7_get_CRLs(crls, &pkcs7)) {
+    fprintf(stderr, "PKCS7_get_CRLs failed.\n");
+    return 0;
+  }
+
+  CBB_init(&cbb, der_len);
+  if (!PKCS7_bundle_CRLs(&cbb, crls) ||
+      !CBB_finish(&cbb, &result_data, &result_len)) {
+    fprintf(stderr, "PKCS7_bundle_CRLs failed.\n");
+    return 0;
+  }
+
+  CBS_init(&pkcs7, result_data, result_len);
+  if (!PKCS7_get_CRLs(crls2, &pkcs7)) {
+    fprintf(stderr, "PKCS7_get_CRLs reparse failed.\n");
+    return 0;
+  }
+
+  if (sk_X509_CRL_num(crls) != sk_X509_CRL_num(crls)) {
+    fprintf(stderr, "Number of CRLs in results differ.\n");
+    return 0;
+  }
+
+  for (i = 0; i < sk_X509_CRL_num(crls); i++) {
+    X509_CRL *a = sk_X509_CRL_value(crls, i);
+    X509_CRL *b = sk_X509_CRL_value(crls2, i);
+
+    if (X509_CRL_cmp(a, b) != 0) {
+      fprintf(stderr, "CRL %u differs.\n", (unsigned) i);
+      return 0;
+    }
+  }
+
+  CBB_init(&cbb, der_len);
+  if (!PKCS7_bundle_CRLs(&cbb, crls2) ||
+      !CBB_finish(&cbb, &result2_data, &result2_len)) {
+    fprintf(stderr,
+            "PKCS7_bundle_CRLs failed the second time.\n");
+    return 0;
+  }
+
+  if (result_len != result2_len ||
+      memcmp(result_data, result2_data, result_len) != 0) {
+    fprintf(stderr, "Serialisation is not stable.\n");
+    return 0;
+  }
+
+  OPENSSL_free(result_data);
+  OPENSSL_free(result2_data);
+  sk_X509_CRL_pop_free(crls, X509_CRL_free);
+  sk_X509_CRL_pop_free(crls2, X509_CRL_free);
+
+  return 1;
+}
+
 int main(void) {
   CRYPTO_library_init();
 
-  if (!test_reparse(kPKCS7NSS, sizeof(kPKCS7NSS)) ||
-      !test_reparse(kPKCS7Windows, sizeof(kPKCS7Windows))) {
+  if (!test_cert_reparse(kPKCS7NSS, sizeof(kPKCS7NSS)) ||
+      !test_cert_reparse(kPKCS7Windows, sizeof(kPKCS7Windows)) ||
+      !test_crl_reparse(kOpenSSLCRL, sizeof(kOpenSSLCRL))) {
     return 1;
   }
 
diff --git a/include/openssl/x509.h b/include/openssl/x509.h
index acdab6e..4025cf9 100644
--- a/include/openssl/x509.h
+++ b/include/openssl/x509.h
@@ -1163,10 +1163,19 @@
 OPENSSL_EXPORT int PKCS7_get_certificates(STACK_OF(X509) *out_certs, CBS *cbs);
 
 /* PKCS7_bundle_certificates appends a PKCS#7, SignedData structure containing
- * |certs| to |cbb|. It returns one on success and zero on error. */
+ * |certs| to |out|. It returns one on success and zero on error. */
 OPENSSL_EXPORT int PKCS7_bundle_certificates(
     CBB *out, const STACK_OF(X509) *certs);
 
+/* PKCS7_get_CRLs parses a PKCS#7, SignedData structure from |cbs| and appends
+ * the included CRLs to |out_crls|. It returns one on success and zero on
+ * error. */
+OPENSSL_EXPORT int PKCS7_get_CRLs(STACK_OF(X509_CRL) *out_crls, CBS *cbs);
+
+/* PKCS7_bundle_CRLs appends a PKCS#7, SignedData structure containing
+ * |crls| to |out|. It returns one on success and zero on error. */
+OPENSSL_EXPORT int PKCS7_bundle_CRLs(CBB *out, const STACK_OF(X509_CRL) *crls);
+
 
 /* EVP_PK values indicate the algorithm of the public key in a certificate. */
 
@@ -1256,6 +1265,8 @@
 #define X509_F_x509_name_encode 154
 #define X509_F_x509_name_ex_d2i 155
 #define X509_F_x509_name_ex_new 156
+#define X509_F_pkcs7_parse_header 157
+#define X509_F_PKCS7_get_CRLs 158
 #define X509_R_AKID_MISMATCH 100
 #define X509_R_BAD_PKCS7_VERSION 101
 #define X509_R_BAD_X509_FILETYPE 102
@@ -1292,5 +1303,6 @@
 #define X509_R_UNSUPPORTED_ALGORITHM 133
 #define X509_R_WRONG_LOOKUP_TYPE 134
 #define X509_R_WRONG_TYPE 135
+#define X509_R_NO_CRLS_INCLUDED 136
 
 #endif