static int pkcs7_to_cert(struct hs20_osu_client *ctx, const u8 *pkcs7, size_t len, char *pem_file, char *der_file) { #ifdef OPENSSL_IS_BORINGSSL CBS pkcs7_cbs; #else /* OPENSSL_IS_BORINGSSL */ PKCS7 *p7 = NULL; const unsigned char *p = pkcs7; #endif /* OPENSSL_IS_BORINGSSL */ STACK_OF(X509) *certs; int i, num, ret = -1; BIO *out = NULL; #ifdef OPENSSL_IS_BORINGSSL certs = sk_X509_new_null(); if (!certs) goto fail; CBS_init(&pkcs7_cbs, pkcs7, len); if (!PKCS7_get_certificates(certs, &pkcs7_cbs)) { wpa_printf(MSG_INFO, "Could not parse PKCS#7 object: %s", ERR_error_string(ERR_get_error(), NULL)); write_result(ctx, "Could not parse PKCS#7 object from EST"); goto fail; } #else /* OPENSSL_IS_BORINGSSL */ p7 = d2i_PKCS7(NULL, &p, len); if (p7 == NULL) { wpa_printf(MSG_INFO, "Could not parse PKCS#7 object: %s", ERR_error_string(ERR_get_error(), NULL)); write_result(ctx, "Could not parse PKCS#7 object from EST"); goto fail; } switch (OBJ_obj2nid(p7->type)) { case NID_pkcs7_signed: certs = p7->d.sign->cert; break; case NID_pkcs7_signedAndEnveloped: certs = p7->d.signed_and_enveloped->cert; break; default: certs = NULL; break; } #endif /* OPENSSL_IS_BORINGSSL */ if (!certs || ((num = sk_X509_num(certs)) == 0)) { wpa_printf(MSG_INFO, "No certificates found in PKCS#7 object"); write_result(ctx, "No certificates found in PKCS#7 object"); goto fail; } if (der_file) { FILE *f = fopen(der_file, "wb"); if (f == NULL) goto fail; i2d_X509_fp(f, sk_X509_value(certs, 0)); fclose(f); } if (pem_file) { out = BIO_new(BIO_s_file()); if (out == NULL || BIO_write_filename(out, pem_file) <= 0) goto fail; for (i = 0; i < num; i++) { X509 *cert = sk_X509_value(certs, i); X509_print(out, cert); PEM_write_bio_X509(out, cert); BIO_puts(out, "\n"); } } ret = 0; fail: #ifdef OPENSSL_IS_BORINGSSL if (certs) sk_X509_pop_free(certs, X509_free); #else /* OPENSSL_IS_BORINGSSL */ PKCS7_free(p7); #endif /* OPENSSL_IS_BORINGSSL */ if (out) BIO_free_all(out); return ret; }
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(); STACK_OF(X509) *certs2 = sk_X509_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_certificates(certs, &pkcs7)) { fprintf(stderr, "PKCS7_get_certificates failed.\n"); return 0; } CBB_init(&cbb, der_len); if (!PKCS7_bundle_certificates(&cbb, certs) || !CBB_finish(&cbb, &result_data, &result_len)) { fprintf(stderr, "PKCS7_bundle_certificates failed.\n"); return 0; } CBS_init(&pkcs7, result_data, result_len); if (!PKCS7_get_certificates(certs2, &pkcs7)) { fprintf(stderr, "PKCS7_get_certificates reparse failed.\n"); return 0; } if (sk_X509_num(certs) != sk_X509_num(certs2)) { fprintf(stderr, "Number of certs in results differ.\n"); return 0; } for (i = 0; i < sk_X509_num(certs); i++) { X509 *a = sk_X509_value(certs, i); X509 *b = sk_X509_value(certs2, i); if (X509_cmp(a, b) != 0) { fprintf(stderr, "Certificate %u differs.\n", (unsigned) i); return 0; } } CBB_init(&cbb, der_len); if (!PKCS7_bundle_certificates(&cbb, certs2) || !CBB_finish(&cbb, &result2_data, &result2_len)) { fprintf(stderr, "PKCS7_bundle_certificates 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_pop_free(certs, X509_free); sk_X509_pop_free(certs2, X509_free); return 1; }