Convert pkcs12_test to C++.

Change-Id: If5caf6bb17a5efc9d0cb2c6c52194685d90614d9
Reviewed-on: https://boringssl-review.googlesource.com/4700
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/pkcs8/CMakeLists.txt b/crypto/pkcs8/CMakeLists.txt
index 5c06fb8..c0f2746 100644
--- a/crypto/pkcs8/CMakeLists.txt
+++ b/crypto/pkcs8/CMakeLists.txt
@@ -14,7 +14,7 @@
 add_executable(
   pkcs12_test
 
-  pkcs12_test.c
+  pkcs12_test.cc
 )
 
 target_link_libraries(pkcs12_test crypto)
diff --git a/crypto/pkcs8/pkcs12_test.c b/crypto/pkcs8/pkcs12_test.cc
similarity index 97%
rename from crypto/pkcs8/pkcs12_test.c
rename to crypto/pkcs8/pkcs12_test.cc
index 11a3090..8b265cd 100644
--- a/crypto/pkcs8/pkcs12_test.c
+++ b/crypto/pkcs8/pkcs12_test.cc
@@ -23,6 +23,8 @@
 #include <openssl/stack.h>
 #include <openssl/x509.h>
 
+#include "../test/scoped_types.h"
+
 
 /* kPKCS12DER contains sample PKCS#12 data generated by OpenSSL with:
  * openssl pkcs12 -export -inkey key.pem -in cacert.pem */
@@ -679,81 +681,76 @@
     0xfe, 0x3a, 0x66, 0x47, 0x40, 0x49, 0x02, 0x02, 0x07, 0xd0,
 };
 
-static int test(const char *name, const uint8_t *der, size_t der_len) {
+static bool Test(const char *name, const uint8_t *der, size_t der_len) {
+  ScopedX509Stack certs(sk_X509_new_null());
+  if (!certs) {
+    return false;
+  }
+
   CBS pkcs12;
-  EVP_PKEY *key;
-  STACK_OF(X509) *certs;
-
-  certs = sk_X509_new_null();
-
+  EVP_PKEY *key = nullptr;
   CBS_init(&pkcs12, der, der_len);
-  if (!PKCS12_get_key_and_certs(&key, certs, &pkcs12, "foo")) {
+  if (!PKCS12_get_key_and_certs(&key, certs.get(), &pkcs12, "foo")) {
     fprintf(stderr, "PKCS12 failed on %s data.\n", name);
     ERR_print_errors_fp(stderr);
-    return 0;
+    return false;
   }
+  ScopedEVP_PKEY delete_key(key);
 
-  if (sk_X509_num(certs) != 1 || key == NULL) {
+  if (sk_X509_num(certs.get()) != 1 || key == nullptr) {
     fprintf(stderr, "Bad result from %s data.\n", name);
-    return 0;
+    return false;
   }
 
-  sk_X509_pop_free(certs, X509_free);
-  EVP_PKEY_free(key);
-
-  return 1;
+  return true;
 }
 
-static int test_compat(const uint8_t *der, size_t der_len) {
-  PKCS12 *p12;
-  X509 *cert = NULL;
-  STACK_OF(X509) *ca_certs = NULL;
-  EVP_PKEY *key;
-  BIO *bio;
-
-  bio = BIO_new_mem_buf((void*) der, der_len);
-
-  p12 = d2i_PKCS12_bio(bio, NULL);
-  if (p12 == NULL) {
-    fprintf(stderr, "PKCS12_parse failed.\n");
-    ERR_print_errors_fp(stderr);
-    return 0;
-  }
-  BIO_free(bio);
-
-  if (!PKCS12_parse(p12, "foo", &key, &cert, &ca_certs)) {
-    fprintf(stderr, "PKCS12_parse failed.\n");
-    ERR_print_errors_fp(stderr);
-    return 0;
+static bool TestCompat(const uint8_t *der, size_t der_len) {
+  ScopedBIO bio(BIO_new_mem_buf((void*) der, der_len));
+  if (!bio) {
+    return false;
   }
 
-  if (key == NULL || cert == NULL) {
+  ScopedPKCS12 p12(d2i_PKCS12_bio(bio.get(), nullptr));
+  if (!p12) {
+    fprintf(stderr, "PKCS12_parse failed.\n");
+    ERR_print_errors_fp(stderr);
+    return false;
+  }
+
+  EVP_PKEY *key = nullptr;
+  X509 *cert = nullptr;
+  STACK_OF(X509) *ca_certs = nullptr;
+  if (!PKCS12_parse(p12.get(), "foo", &key, &cert, &ca_certs)) {
+    fprintf(stderr, "PKCS12_parse failed.\n");
+    ERR_print_errors_fp(stderr);
+    return false;
+  }
+  ScopedEVP_PKEY delete_key(key);
+  ScopedX509 delete_cert(cert);
+  ScopedX509Stack delete_ca_certs(ca_certs);
+
+  if (key == nullptr || cert == nullptr) {
     fprintf(stderr, "Bad result from PKCS12_parse.\n");
-    return 0;
+    return false;
   }
 
-  EVP_PKEY_free(key);
-  X509_free(cert);
-
   if (sk_X509_num(ca_certs) != 0) {
     fprintf(stderr, "Bad result from PKCS12_parse.\n");
-    return 0;
+    return false;
   }
-  sk_X509_free(ca_certs);
 
-  PKCS12_free(p12);
-
-  return 1;
+  return true;
 }
 
 int main(int argc, char **argv) {
   CRYPTO_library_init();
   ERR_load_crypto_strings();
 
-  if (!test("OpenSSL", kOpenSSL, sizeof(kOpenSSL)) ||
-      !test("NSS", kNSS, sizeof(kNSS)) ||
-      !test("Windows", kWindows, sizeof(kWindows)) ||
-      !test_compat(kWindows, sizeof(kWindows))) {
+  if (!Test("OpenSSL", kOpenSSL, sizeof(kOpenSSL)) ||
+      !Test("NSS", kNSS, sizeof(kNSS)) ||
+      !Test("Windows", kWindows, sizeof(kWindows)) ||
+      !TestCompat(kWindows, sizeof(kWindows))) {
     return 1;
   }
 
diff --git a/crypto/test/scoped_types.h b/crypto/test/scoped_types.h
index 697dfbf..9f5a8db 100644
--- a/crypto/test/scoped_types.h
+++ b/crypto/test/scoped_types.h
@@ -27,7 +27,9 @@
 #include <openssl/evp.h>
 #include <openssl/hmac.h>
 #include <openssl/mem.h>
+#include <openssl/pkcs8.h>
 #include <openssl/rsa.h>
+#include <openssl/stack.h>
 #include <openssl/x509.h>
 
 #include "stl_compat.h"
@@ -40,6 +42,14 @@
   }
 };
 
+template<typename StackType, typename T, void (*func)(T*)>
+struct OpenSSLStackDeleter {
+  void operator()(StackType *obj) {
+    sk_pop_free(reinterpret_cast<_STACK*>(obj),
+                reinterpret_cast<void (*)(void *)>(func));
+  }
+};
+
 template<typename T>
 struct OpenSSLFree {
   void operator()(T *buf) {
@@ -50,6 +60,10 @@
 template<typename T, void (*func)(T*)>
 using ScopedOpenSSLType = bssl::unique_ptr<T, OpenSSLDeleter<T, func>>;
 
+template<typename StackType, typename T, void (*func)(T*)>
+using ScopedOpenSSLStack =
+    bssl::unique_ptr<StackType, OpenSSLStackDeleter<StackType, T, func>>;
+
 template<typename T, typename CleanupRet, void (*init_func)(T*),
          CleanupRet (*cleanup_func)(T*)>
 class ScopedOpenSSLContext {
@@ -86,9 +100,13 @@
 using ScopedEVP_PKEY = ScopedOpenSSLType<EVP_PKEY, EVP_PKEY_free>;
 using ScopedPKCS8_PRIV_KEY_INFO = ScopedOpenSSLType<PKCS8_PRIV_KEY_INFO,
                                                     PKCS8_PRIV_KEY_INFO_free>;
+using ScopedPKCS12 = ScopedOpenSSLType<PKCS12, PKCS12_free>;
 using ScopedRSA = ScopedOpenSSLType<RSA, RSA_free>;
+using ScopedX509 = ScopedOpenSSLType<X509, X509_free>;
 using ScopedX509_ALGOR = ScopedOpenSSLType<X509_ALGOR, X509_ALGOR_free>;
 
+using ScopedX509Stack = ScopedOpenSSLStack<STACK_OF(X509), X509, X509_free>;
+
 using ScopedEVP_MD_CTX = ScopedOpenSSLContext<EVP_MD_CTX, int, EVP_MD_CTX_init,
                                               EVP_MD_CTX_cleanup>;
 using ScopedHMAC_CTX = ScopedOpenSSLContext<HMAC_CTX, void, HMAC_CTX_init,