Use X509 certificate alias as friendlyName in PKCS12

Bug: 481
Change-Id: I5c1dd6e39874cd1e88cb6fd0b3a6c6c6fac0db85
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/51665
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
This commit is contained in:
Alex Gaynor
2022-03-05 13:40:48 -05:00
committed by Boringssl LUCI CQ
parent c9a7dd6879
commit 225e8d39b5
4 changed files with 75 additions and 6 deletions
+1
View File
@@ -1,3 +1,4 @@
PKCS8,133,AMBIGUOUS_FRIENDLY_NAME
PKCS8,129,BAD_ITERATION_COUNT
PKCS8,100,BAD_PKCS12_DATA
PKCS8,101,BAD_PKCS12_VERSION
+42
View File
@@ -599,3 +599,45 @@ TEST(PKCS12Test, Order) {
ASSERT_TRUE(PKCS12CreateVector(&p12, key1.get(), {cert2.get(), cert3.get()}));
ExpectPKCS12Parse(p12, key1.get(), nullptr, {cert2.get(), cert3.get()});
}
TEST(PKCS12Test, CreateWithAlias) {
bssl::UniquePtr<EVP_PKEY> key = MakeTestKey();
ASSERT_TRUE(key);
bssl::UniquePtr<X509> cert1 = MakeTestCert(key.get());
ASSERT_TRUE(cert1);
bssl::UniquePtr<X509> cert2 = MakeTestCert(key.get());
ASSERT_TRUE(cert2);
std::string alias = "I'm an alias";
int res = X509_alias_set1(
cert1.get(), reinterpret_cast<const unsigned char *>(alias.data()),
alias.size());
ASSERT_EQ(res, 1);
std::vector<X509 *> certs = {cert1.get(), cert2.get()};
std::vector<uint8_t> der;
ASSERT_TRUE(PKCS12CreateVector(&der, key.get(), certs));
bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(der.data(), der.size()));
ASSERT_TRUE(bio);
bssl::UniquePtr<PKCS12> p12(d2i_PKCS12_bio(bio.get(), nullptr));
ASSERT_TRUE(p12);
EVP_PKEY *parsed_key = nullptr;
X509 *parsed_cert = nullptr;
STACK_OF(X509) *ca_certs = nullptr;
ASSERT_TRUE(
PKCS12_parse(p12.get(), kPassword, &parsed_key, &parsed_cert, &ca_certs));
bssl::UniquePtr<EVP_PKEY> delete_key(parsed_key);
bssl::UniquePtr<X509> delete_cert(parsed_cert);
bssl::UniquePtr<STACK_OF(X509)> delete_ca_certs(ca_certs);
ASSERT_EQ(sk_X509_num(ca_certs), 1UL);
int alias_len = 0;
const unsigned char *parsed_alias =
X509_alias_get0(sk_X509_value(ca_certs, 0), &alias_len);
ASSERT_TRUE(parsed_alias);
ASSERT_EQ(alias, std::string(reinterpret_cast<const char *>(parsed_alias),
static_cast<size_t>(alias_len)));
}
+24 -6
View File
@@ -993,8 +993,8 @@ int PKCS12_verify_mac(const PKCS12 *p12, const char *password,
// 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,
size_t key_id_len) {
static int add_bag_attributes(CBB *bag, const char *name, size_t name_len,
const uint8_t *key_id, size_t key_id_len) {
if (name == NULL && key_id_len == 0) {
return 1; // Omit the OPTIONAL SET.
}
@@ -1003,7 +1003,7 @@ static int add_bag_attributes(CBB *bag, const char *name, const uint8_t *key_id,
if (!CBB_add_asn1(bag, &attrs, CBS_ASN1_SET)) {
return 0;
}
if (name != NULL) {
if (name_len != 0) {
// See https://tools.ietf.org/html/rfc2985, section 5.5.1.
if (!CBB_add_asn1(&attrs, &attr, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&attr, &oid, CBS_ASN1_OBJECT) ||
@@ -1014,7 +1014,7 @@ static int add_bag_attributes(CBB *bag, const char *name, const uint8_t *key_id,
}
// Convert the friendly name to a BMPString.
CBS name_cbs;
CBS_init(&name_cbs, (const uint8_t *)name, strlen(name));
CBS_init(&name_cbs, (const uint8_t *)name, name_len);
while (CBS_len(&name_cbs) != 0) {
uint32_t c;
if (!cbs_get_utf8(&name_cbs, &c) ||
@@ -1059,10 +1059,24 @@ static int add_cert_bag(CBB *cbb, X509 *cert, const char *name,
}
uint8_t *buf;
int len = i2d_X509(cert, NULL);
int int_name_len = 0;
const char *cert_name = (const char *)X509_alias_get0(cert, &int_name_len);
size_t name_len = int_name_len;
if (name) {
if (name_len != 0) {
OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_AMBIGUOUS_FRIENDLY_NAME);
return 0;
}
name_len = strlen(name);
} else {
name = cert_name;
}
if (len < 0 ||
!CBB_add_space(&cert_value, &buf, (size_t)len) ||
i2d_X509(cert, &buf) < 0 ||
!add_bag_attributes(&bag, name, key_id, key_id_len) ||
!add_bag_attributes(&bag, name, name_len, key_id, key_id_len) ||
!CBB_flush(cbb)) {
return 0;
}
@@ -1323,7 +1337,11 @@ PKCS12 *PKCS12_create(const char *password, const char *name,
goto err;
}
}
if (!add_bag_attributes(&bag, name, key_id, key_id_len) ||
size_t name_len = 0;
if (name) {
name_len = strlen(name);
}
if (!add_bag_attributes(&bag, name, name_len, key_id, key_id_len) ||
!CBB_flush(&content_infos)) {
goto err;
}
+8
View File
@@ -122,6 +122,8 @@ OPENSSL_EXPORT EVP_PKEY *PKCS8_parse_encrypted_private_key(CBS *cbs,
// and decrypts it using |password|, sets |*out_key| to the included private
// key and appends the included certificates to |out_certs|. It returns one on
// success and zero on error. The caller takes ownership of the outputs.
// Any friendlyName attributes (RFC 2985) in the PKCS#12 structure will be
// returned on the |X509| objects as aliases. See also |X509_alias_get0|.
OPENSSL_EXPORT int PKCS12_get_key_and_certs(EVP_PKEY **out_key,
STACK_OF(X509) *out_certs,
CBS *in, const char *password);
@@ -219,6 +221,11 @@ OPENSSL_EXPORT int PKCS12_verify_mac(const PKCS12 *p12, const char *password,
// implemented for compatibility with external packages. Note the output still
// requires a password for the MAC. Unencrypted keys in PKCS#12 are also not
// widely supported and may not open in other implementations.
//
// If |cert| or |chain| have associated aliases (see |X509_alias_set1|), they
// will be included in the output as friendlyName attributes (RFC 2985). It is
// an error to specify both an alias on |cert| and a non-NULL |name|
// parameter.
OPENSSL_EXPORT PKCS12 *PKCS12_create(const char *password, const char *name,
const EVP_PKEY *pkey, X509 *cert,
const STACK_OF(X509) *chain, int key_nid,
@@ -278,5 +285,6 @@ BSSL_NAMESPACE_END
#define PKCS8_R_UNSUPPORTED_PRF 130
#define PKCS8_R_INVALID_CHARACTERS 131
#define PKCS8_R_UNSUPPORTED_OPTIONS 132
#define PKCS8_R_AMBIGUOUS_FRIENDLY_NAME 133
#endif // OPENSSL_HEADER_PKCS8_H