Extract friendly names attached to certificates.

OpenSSL staples each certificate's friendly name to the X509 with
X509_alias_set1. Mimic this. pyOpenSSL expects to find it there.

Update-Note: We actually parse some attributes now. PKCS#12 files with
malformed ones may not parse.

Change-Id: I3b78958eedf195509cd222ea4f0c884be3753770
Reviewed-on: https://boringssl-review.googlesource.com/28551
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/crypto/pkcs8/pkcs12_test.cc b/crypto/pkcs8/pkcs12_test.cc
index d1d09fa..5fb7903 100644
--- a/crypto/pkcs8/pkcs12_test.cc
+++ b/crypto/pkcs8/pkcs12_test.cc
@@ -1165,7 +1165,8 @@
 static const char kUnicodePassword[] = u8"Hello, 世界";
 
 static void TestImpl(const char *name, bssl::Span<const uint8_t> der,
-                     const char *password) {
+                     const char *password,
+                     const char *friendly_name) {
   SCOPED_TRACE(name);
   bssl::UniquePtr<STACK_OF(X509)> certs(sk_X509_new_null());
   ASSERT_TRUE(certs);
@@ -1177,6 +1178,17 @@
 
   ASSERT_EQ(1u, sk_X509_num(certs.get()));
   ASSERT_TRUE(key);
+
+  int actual_name_len;
+  const uint8_t *actual_name =
+      X509_alias_get0(sk_X509_value(certs.get(), 0), &actual_name_len);
+  if (friendly_name == nullptr) {
+    EXPECT_EQ(nullptr, actual_name);
+  } else {
+    EXPECT_EQ(friendly_name,
+              std::string(reinterpret_cast<const char *>(actual_name),
+                          static_cast<size_t>(actual_name_len)));
+  }
 }
 
 static void TestCompat(bssl::Span<const uint8_t> der) {
@@ -1204,33 +1216,35 @@
 }
 
 TEST(PKCS12Test, TestOpenSSL) {
-  TestImpl("OpenSSL", kOpenSSL, kPassword);
+  TestImpl("OpenSSL", kOpenSSL, kPassword, nullptr);
 }
 
 TEST(PKCS12Test, TestNSS) {
-  TestImpl("NSS", kNSS, kPassword);
+  TestImpl("NSS", kNSS, kPassword, "Internet Widgits Pty Ltd");
 }
 
 TEST(PKCS12Test, TestWindows) {
-  TestImpl("Windows", kWindows, kPassword);
+  // kWindows has a friendlyName, but only on the key, where we ignore it, and
+  // not the certificate.
+  TestImpl("Windows", kWindows, kPassword, nullptr);
 }
 
 TEST(PKCS12Test, TestPBES2) {
-  TestImpl("PBES2", kPBES2, kPassword);
+  TestImpl("PBES2", kPBES2, kPassword, nullptr);
 }
 
 TEST(PKCS12Test, TestEmptyPassword) {
-  TestImpl("EmptyPassword (empty password)", kEmptyPassword, "");
-  TestImpl("EmptyPassword (null password)", kEmptyPassword, nullptr);
+  TestImpl("EmptyPassword (empty password)", kEmptyPassword, "", nullptr);
+  TestImpl("EmptyPassword (null password)", kEmptyPassword, nullptr, nullptr);
 }
 
 TEST(PKCS12Test, TestNullPassword) {
-  TestImpl("NullPassword (empty password)", kNullPassword, "");
-  TestImpl("NullPassword (null password)", kNullPassword, nullptr);
+  TestImpl("NullPassword (empty password)", kNullPassword, "", nullptr);
+  TestImpl("NullPassword (null password)", kNullPassword, nullptr, nullptr);
 }
 
 TEST(PKCS12Test, TestUnicode) {
-  TestImpl("Unicode", kUnicode, kUnicodePassword);
+  TestImpl("Unicode", kUnicode, kUnicodePassword, nullptr);
 }
 
 TEST(PKCS12Test, TestWindowsCompat) {
@@ -1419,6 +1433,17 @@
     EXPECT_EQ(0, X509_cmp(sk_X509_value(chain.get(), i),
                           sk_X509_value(certs2.get(), i + offset)));
   }
+  if (sk_X509_num(certs2.get()) > 0) {
+    int actual_name_len;
+    const uint8_t *actual_name =
+        X509_alias_get0(sk_X509_value(certs2.get(), 0), &actual_name_len);
+    if (name == NULL) {
+      EXPECT_EQ(nullptr, actual_name);
+    } else {
+      EXPECT_EQ(name, std::string(reinterpret_cast<const char *>(actual_name),
+                                  static_cast<size_t>(actual_name_len)));
+    }
+  }
 
   // Check that writing to a |BIO| does the same thing.
   bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
diff --git a/crypto/pkcs8/pkcs8_x509.c b/crypto/pkcs8/pkcs8_x509.c
index 24aaa27..3cdbddb 100644
--- a/crypto/pkcs8/pkcs8_x509.c
+++ b/crypto/pkcs8/pkcs8_x509.c
@@ -293,18 +293,93 @@
 static const uint8_t kCertBag[] = {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
                                    0x01, 0x0c, 0x0a, 0x01, 0x03};
 
+// 1.2.840.113549.1.9.20
+static const uint8_t kFriendlyName[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
+                                        0x0d, 0x01, 0x09, 0x14};
+
+// 1.2.840.113549.1.9.21
+static const uint8_t kLocalKeyID[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
+                                      0x0d, 0x01, 0x09, 0x15};
+
 // 1.2.840.113549.1.9.22.1
 static const uint8_t kX509Certificate[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
                                            0x0d, 0x01, 0x09, 0x16, 0x01};
 
+// parse_bag_attributes parses the bagAttributes field of a SafeBag structure.
+// It sets |*out_friendly_name| to a newly-allocated copy of the friendly name,
+// encoded as a UTF-8 string, or NULL if there is none. It returns one on
+// success and zero on error.
+static int parse_bag_attributes(CBS *attrs, uint8_t **out_friendly_name,
+                                size_t *out_friendly_name_len) {
+  *out_friendly_name = NULL;
+  *out_friendly_name_len = 0;
+
+  // See https://tools.ietf.org/html/rfc7292#section-4.2.
+  while (CBS_len(attrs) != 0) {
+    CBS attr, oid, values;
+    if (!CBS_get_asn1(attrs, &attr, CBS_ASN1_SEQUENCE) ||
+        !CBS_get_asn1(&attr, &oid, CBS_ASN1_OBJECT) ||
+        !CBS_get_asn1(&attr, &values, CBS_ASN1_SET) ||
+        CBS_len(&attr) != 0) {
+      OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+      goto err;
+    }
+    if (CBS_mem_equal(&oid, kFriendlyName, sizeof(kFriendlyName))) {
+      // See https://tools.ietf.org/html/rfc2985, section 5.5.1.
+      CBS value;
+      if (*out_friendly_name != NULL ||
+          !CBS_get_asn1(&values, &value, CBS_ASN1_BMPSTRING) ||
+          CBS_len(&values) != 0 ||
+          CBS_len(&value) == 0) {
+        OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+        goto err;
+      }
+      // Convert the friendly name to UTF-8.
+      CBB cbb;
+      if (!CBB_init(&cbb, CBS_len(&value))) {
+        OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
+        goto err;
+      }
+      while (CBS_len(&value) != 0) {
+        uint32_t c;
+        if (!cbs_get_ucs2_be(&value, &c) ||
+            !cbb_add_utf8(&cbb, c)) {
+          OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_INVALID_CHARACTERS);
+          CBB_cleanup(&cbb);
+          goto err;
+        }
+      }
+      if (!CBB_finish(&cbb, out_friendly_name, out_friendly_name_len)) {
+        OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
+        CBB_cleanup(&cbb);
+        goto err;
+      }
+    }
+  }
+
+  return 1;
+
+err:
+  OPENSSL_free(*out_friendly_name);
+  *out_friendly_name = NULL;
+  *out_friendly_name_len = 0;
+  return 0;
+}
+
 // PKCS12_handle_safe_bag parses a single SafeBag element in a PKCS#12
 // structure.
 static int PKCS12_handle_safe_bag(CBS *safe_bag, struct pkcs12_context *ctx) {
-  CBS bag_id, wrapped_value;
+  CBS bag_id, wrapped_value, bag_attrs;
   if (!CBS_get_asn1(safe_bag, &bag_id, CBS_ASN1_OBJECT) ||
       !CBS_get_asn1(safe_bag, &wrapped_value,
-                        CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)
-      /* Ignore the bagAttributes field. */) {
+                    CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) {
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+    return 0;
+  }
+  if (CBS_len(safe_bag) == 0) {
+    CBS_init(&bag_attrs, NULL, 0);
+  } else if (!CBS_get_asn1(safe_bag, &bag_attrs, CBS_ASN1_SET) ||
+             CBS_len(safe_bag) != 0) {
     OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
     return 0;
   }
@@ -369,7 +444,17 @@
       return 0;
     }
 
-    if (0 == sk_X509_push(ctx->out_certs, x509)) {
+    uint8_t *friendly_name;
+    size_t friendly_name_len;
+    if (!parse_bag_attributes(&bag_attrs, &friendly_name, &friendly_name_len)) {
+      X509_free(x509);
+      return 0;
+    }
+    int ok = friendly_name_len == 0 ||
+             X509_alias_set1(x509, friendly_name, friendly_name_len);
+    OPENSSL_free(friendly_name);
+    if (!ok ||
+        0 == sk_X509_push(ctx->out_certs, x509)) {
       X509_free(x509);
       return 0;
     }
@@ -861,14 +946,6 @@
   return 1;
 }
 
-// 1.2.840.113549.1.9.20
-static const uint8_t kFriendlyName[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
-                                        0x0d, 0x01, 0x09, 0x14};
-
-// 1.2.840.113549.1.9.21
-static const uint8_t kLocalKeyID[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
-                                      0x0d, 0x01, 0x09, 0x15};
-
 // add_bag_attributes adds the bagAttributes field of a SafeBag structure,
 // containing the specified friendlyName and localKeyId attributes.
 static int add_bag_attributes(CBB *bag, const char *name, const uint8_t *key_id,