// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif
#include "chromeos/components/kcer/helpers/pkcs12_reader.h"
#include <pk11pub.h>
#include <stdint.h>
#include <memory>
#include <string>
#include <vector>
#include "base/base64.h"
#include "base/containers/span.h"
#include "chromeos/components/kcer/helpers/key_helper.h"
#include "crypto/scoped_test_nss_db.h"
#include "net/cert/x509_certificate.h"
#include "net/cert/x509_util_nss.h"
#include "net/test/cert_test_util.h"
#include "net/test/test_data_directory.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/boringssl/src/include/openssl/base.h"
#include "third_party/boringssl/src/include/openssl/bn.h"
#include "third_party/boringssl/src/include/openssl/ec_key.h"
#include "third_party/boringssl/src/include/openssl/evp.h"
#include "third_party/boringssl/src/include/openssl/mem.h"
#include "third_party/boringssl/src/include/openssl/rsa.h"
#include "third_party/boringssl/src/include/openssl/stack.h"
#include "third_party/boringssl/src/include/openssl/x509.h"
namespace kcer::internal {
namespace {
const char kPkcs12FilePassword[] = "12345";
ScopedX509 X509New() {
return ScopedX509(X509_new());
}
// Custom X509_NAME object creation allows to avoid calls to X509_NAME_free()
// after every test where X509_NAME objects are required.
struct X509NameDeleter {
void operator()(X509_NAME* name) { X509_NAME_free(name); }
};
using ScopedX509_NAME = std::unique_ptr<X509_NAME, X509NameDeleter>;
ScopedX509_NAME X509NameNew() {
return ScopedX509_NAME(X509_NAME_new());
}
// Custom BIGNUM object with object's deleter after the test is finished.
struct BIGNUMDeleter {
void operator()(BIGNUM* num) { BN_free(num); }
};
using ScopedBIGNUM = std::unique_ptr<BIGNUM, BIGNUMDeleter>;
ScopedBIGNUM BIGNUMNew() {
return ScopedBIGNUM(BN_new());
}
scoped_refptr<net::X509Certificate> GetTestCert() {
return net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem");
}
bssl::UniquePtr<EVP_PKEY> GeneratePkey(int type) {
bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new_id(type, /*e=*/nullptr));
CHECK(EVP_PKEY_keygen_init(ctx.get()));
switch (type) {
case EVP_PKEY_RSA:
CHECK(EVP_PKEY_CTX_set_rsa_keygen_bits(ctx.get(), 2048));
break;
case EVP_PKEY_EC:
CHECK(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx.get(),
NID_X9_62_prime256v1));
break;
}
EVP_PKEY* key = nullptr;
CHECK(EVP_PKEY_keygen(ctx.get(), &key));
return bssl::UniquePtr<EVP_PKEY>(key);
}
KeyData BuildKeyDataWithEmptyPkey() {
KeyData key_data;
key_data.key = bssl::UniquePtr<EVP_PKEY>(EVP_PKEY_new());
return key_data;
}
bssl::UniquePtr<EVP_PKEY> GenerateRsaKey() {
return GeneratePkey(EVP_PKEY_RSA);
}
bssl::UniquePtr<EVP_PKEY> GenerateEcKey() {
return GeneratePkey(EVP_PKEY_EC);
}
// Tests for testing methods in chaps_util_helper.cc
// ChapsUtilImplTest is testing successful import and values, these tests
// are mainly checking errors handling.
class Pkcs12ReaderTest : public ::testing::Test {
public:
Pkcs12ReaderTest() { pkcs12Reader_ = std::make_unique<Pkcs12Reader>(); }
Pkcs12ReaderTest(const Pkcs12ReaderTest&) = delete;
Pkcs12ReaderTest& operator=(const Pkcs12ReaderTest&) = delete;
~Pkcs12ReaderTest() override = default;
Pkcs12ReaderStatusCode GetSerialNumberDer(X509* cert) {
int serial_number_der_size;
bssl::UniquePtr<uint8_t> serial_number_der;
return pkcs12Reader_->GetSerialNumberDer(cert, serial_number_der,
serial_number_der_size);
}
Pkcs12ReaderStatusCode GetIssuerNameDer(X509* cert) {
base::span<const uint8_t> issuer_name_data;
return pkcs12Reader_->GetIssuerNameDer(cert, issuer_name_data);
}
Pkcs12ReaderStatusCode GetSubjectNameDer(X509* cert) {
base::span<const uint8_t> subject_name_data;
return pkcs12Reader_->GetSubjectNameDer(cert, subject_name_data);
}
Pkcs12ReaderStatusCode GetDerEncodedCert(X509* cert) {
int cert_der_size;
bssl::UniquePtr<uint8_t> cert_der_ptr;
return pkcs12Reader_->GetDerEncodedCert(cert, cert_der_ptr, cert_der_size);
}
Pkcs12ReaderStatusCode GetLabel(X509* cert) {
std::string label;
return pkcs12Reader_->GetLabel(cert, label);
}
void SetFieldToX509Name(X509_NAME* X509_name,
const char field[],
unsigned char value[]) {
X509_NAME_add_entry_by_txt(X509_name,
/*field=*/field,
/*type=*/MBSTRING_ASC,
/*bytes=*/value,
/*len=*/-1,
/*loc=*/-1,
/*set=*/0);
}
void SetOrgDataWithoutCNToX509Name(X509_NAME* X509_name) {
// Country
unsigned char country_name[] = "DE";
SetFieldToX509Name(X509_name, "C", country_name);
// Company/Organization
unsigned char org_name[] = "Test company";
SetFieldToX509Name(X509_name, "O", org_name);
}
void SetOrgDataToX509Name(X509_NAME* X509_name) {
// Country name and Company/Organization name
SetOrgDataWithoutCNToX509Name(X509_name);
// Common name
SetFieldToX509Name(X509_name, "CN", common_name_);
}
// Build ScopedX509 and set its public key to provided value.
ScopedX509 BuildScopedX509AndSetPublicKey(
const bssl::UniquePtr<EVP_PKEY>& key) {
ScopedX509 cert = X509New();
X509_set_pubkey(cert.get(), key.get());
return cert;
}
// Create KeyData, set RSA key, set rsa_key_modulus_bytes and
// rsa_public_exp_bytes, so RSA KeyData looks same like EnrichKeyData()
// was executed on it.
KeyData BuildRsaKeyData() {
KeyData key_data;
key_data.key = GenerateRsaKey();
return key_data;
}
// Create KeyData, set EC key, set ec_key_public_bytes, so
// KeyData looks same like EnrichKeyData() was executed on it.
KeyData BuildEcKeyData() {
KeyData key_data;
key_data.key = GenerateEcKey();
return key_data;
}
unsigned char common_name_[12] = "common name";
protected:
std::unique_ptr<Pkcs12Reader> pkcs12Reader_;
};
TEST_F(Pkcs12ReaderTest, EmptyBigNumReturnsEmptyVector) {
ScopedBIGNUM bignum = BIGNUMNew();
BN_zero(bignum.get());
std::vector<uint8_t> expected_empty_vector({});
EXPECT_EQ(pkcs12Reader_->BignumToBytes(bignum.get()), expected_empty_vector);
}
TEST_F(Pkcs12ReaderTest, MaxBigNumConvertedCorrectly) {
ScopedBIGNUM bignum = BIGNUMNew();
BN_set_u64(bignum.get(), 0xFFFFFFFFFFFFFFFF);
std::vector<uint8_t> expected_data({
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
});
std::vector<uint8_t> bignum_bytes =
pkcs12Reader_->BignumToBytes(bignum.get());
EXPECT_EQ(bignum_bytes, expected_data);
}
TEST_F(Pkcs12ReaderTest, BigNumZeroConvertedToEmptyVector) {
ScopedBIGNUM bignum = BIGNUMNew();
BN_set_u64(bignum.get(), 0x00000000000000);
std::vector<uint8_t> expected_data({});
std::vector<uint8_t> bignum_bytes =
pkcs12Reader_->BignumToBytes(bignum.get());
EXPECT_EQ(bignum_bytes, expected_data);
}
TEST_F(Pkcs12ReaderTest, BigNumWithFrontZerosConvertedCorrectly) {
ScopedBIGNUM bignum = BIGNUMNew();
BN_set_u64(bignum.get(), 0x00000000000100);
std::vector<uint8_t> expected_data({0x01, 0x00});
std::vector<uint8_t> bignum_bytes =
pkcs12Reader_->BignumToBytes(bignum.get());
EXPECT_EQ(bignum_bytes, expected_data);
}
TEST_F(Pkcs12ReaderTest, EmptyBigNumConvertedCorrectly) {
ScopedBIGNUM bignum = BIGNUMNew();
std::vector<uint8_t> expected_data({});
std::vector<uint8_t> bignum_bytes =
pkcs12Reader_->BignumToBytes(bignum.get());
EXPECT_EQ(bignum_bytes, expected_data);
}
TEST_F(Pkcs12ReaderTest, NullptrBigNumConvertedCorrectly) {
std::vector<uint8_t> expected_data({});
std::vector<uint8_t> bignum_bytes = pkcs12Reader_->BignumToBytes(nullptr);
EXPECT_EQ(bignum_bytes, expected_data);
}
TEST_F(Pkcs12ReaderTest, GetSerialNumberDer) {
// Empty certificate, operation will fail.
{
X509* cert = nullptr;
Pkcs12ReaderStatusCode result = GetSerialNumberDer(cert);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kCertificateDataMissed);
}
// Empty serial number, operation will succeed.
{
ScopedX509 cert = X509New();
Pkcs12ReaderStatusCode result = GetSerialNumberDer(cert.get());
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kSuccess);
}
// Certificate with normal serial number, operation will succeed.
// Check only import success, values are checked in ChapsUtilImplTest.
{
ScopedX509 cert = X509New();
ASN1_INTEGER_set(X509_get_serialNumber(cert.get()), 1);
int serial_number_der_size;
bssl::UniquePtr<uint8_t> serial_number_der;
Pkcs12ReaderStatusCode result = pkcs12Reader_->GetSerialNumberDer(
cert.get(), serial_number_der, serial_number_der_size);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kSuccess);
}
}
TEST_F(Pkcs12ReaderTest, GetIssuerNameDer) {
// Empty certificate, operation will fail.
{
Pkcs12ReaderStatusCode result = GetIssuerNameDer(nullptr);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kCertificateDataMissed);
}
// Empty object for the issuer, operation will succeed.
{
ScopedX509 cert = X509New();
Pkcs12ReaderStatusCode result = GetIssuerNameDer(cert.get());
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kSuccess);
}
// Certificate with normal issuer name, operation will succeed.
// Check only import success, values are checked in ChapsUtilImplTest.
{
ScopedX509 cert = X509New();
ScopedX509_NAME issuer = X509NameNew();
// This only sets org name, country and common name.
SetOrgDataToX509Name(issuer.get());
X509_set_issuer_name(cert.get(), issuer.get());
base::span<const uint8_t> issuer_name_data;
Pkcs12ReaderStatusCode result =
pkcs12Reader_->GetIssuerNameDer(cert.get(), issuer_name_data);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kSuccess);
}
}
TEST_F(Pkcs12ReaderTest, FindRawCertsWithSubject) {
crypto::ScopedTestNSSDB nss_test_db_;
// Empty slot, operation will fail.
{
PK11SlotInfo* slot = nullptr;
base::span<const uint8_t> required_subject_name;
CERTCertificateList* found_certs = nullptr;
Pkcs12ReaderStatusCode result = pkcs12Reader_->FindRawCertsWithSubject(
slot, required_subject_name, &found_certs);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kMissedSlotInfo);
EXPECT_EQ(found_certs, nullptr);
}
// Not defined subject name, operation will fail.
{
PK11SlotInfo* slot = nss_test_db_.slot();
base::span<const uint8_t> required_subject_name;
CERTCertificateList* found_certs = nullptr;
Pkcs12ReaderStatusCode result = pkcs12Reader_->FindRawCertsWithSubject(
slot, required_subject_name, &found_certs);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kPkcs12CertSubjectNameMissed);
EXPECT_EQ(found_certs, nullptr);
}
// Fake subject name, operation will succeed, but list will be still not
// defined because call is using empty nss_test_db.
{
PK11SlotInfo* slot = nss_test_db_.slot();
const uint8_t subject_name[] = "subject_name";
base::span<const uint8_t> required_subject_name{subject_name,
std::size(subject_name)};
CERTCertificateList* found_certs = nullptr;
Pkcs12ReaderStatusCode result = pkcs12Reader_->FindRawCertsWithSubject(
slot, required_subject_name, &found_certs);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kSuccess);
EXPECT_EQ(found_certs, nullptr);
}
}
TEST_F(Pkcs12ReaderTest, GetSubjectNameDer) {
// Empty certificate, operation will fail.
{
Pkcs12ReaderStatusCode result = GetSubjectNameDer(nullptr);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kCertificateDataMissed);
}
// Empty object for the subject name, operation will succeed.
{
ScopedX509 cert = X509New();
Pkcs12ReaderStatusCode result = GetSubjectNameDer(cert.get());
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kSuccess);
}
// Certificate with normal subject name, operation will succeed.
// Check only import success, values are checked in ChapsUtilImplTest.
{
ScopedX509 cert = X509New();
ScopedX509_NAME subject = X509NameNew();
// This only sets org name, country and common name.
SetOrgDataToX509Name(subject.get());
X509_set_subject_name(cert.get(), subject.get());
base::span<const uint8_t> subject_name_data;
Pkcs12ReaderStatusCode result =
pkcs12Reader_->GetSubjectNameDer(cert.get(), subject_name_data);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kSuccess);
}
}
TEST_F(Pkcs12ReaderTest, GetDerEncodedCert) {
// No certificate, operation will fail.
{
Pkcs12ReaderStatusCode result = GetDerEncodedCert(nullptr);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kCertificateDataMissed);
}
// Empty certificate, operation will fail.
{
ScopedX509 cert = X509New();
Pkcs12ReaderStatusCode result = GetDerEncodedCert(cert.get());
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kPkcs12CertDerFailed);
}
}
TEST_F(Pkcs12ReaderTest, GetPkcs12KeyAndCerts) {
// No pkcs12 data, operation will fail.
{
bssl::UniquePtr<EVP_PKEY> key;
bssl::UniquePtr<STACK_OF(X509)> certs;
const std::vector<uint8_t>& pkcs12_data = {};
Pkcs12ReaderStatusCode result = pkcs12Reader_->GetPkcs12KeyAndCerts(
pkcs12_data, kPkcs12FilePassword, key, certs);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kMissedPkcs12Data);
}
// Wrong pkcs12 data's, operation will fail.
{
bssl::UniquePtr<EVP_PKEY> key;
bssl::UniquePtr<STACK_OF(X509)> certs;
const std::vector<uint8_t>& wrong_pkcs12_data = {0, 0, 0, 0, 0,
0, 0, 0, 0, 0};
Pkcs12ReaderStatusCode result = pkcs12Reader_->GetPkcs12KeyAndCerts(
wrong_pkcs12_data, kPkcs12FilePassword, key, certs);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kPkcs12InvalidFile);
}
// Not testing for normal case and for password, those cases are tested from
// higher level chaps_util_impl_unittest.cc
}
TEST_F(Pkcs12ReaderTest, GetLabel) {
// Certificate is NULL, operation will fail.
{
Pkcs12ReaderStatusCode result = GetLabel(nullptr);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kCertificateDataMissed);
}
// Certificate with present friendly name (alias), operation will
// succeed. Label is taken from friendly name (alias).
{
ScopedX509 cert = X509New();
ScopedX509_NAME subject = X509NameNew();
// This only sets org name, country and common name.
SetOrgDataToX509Name(subject.get());
X509_set_subject_name(cert.get(), subject.get());
unsigned char alias[20] = "new alias";
std::string expected_label(reinterpret_cast<char*>(alias));
X509_alias_set1(cert.get(), alias, std::size(alias));
std::string label;
Pkcs12ReaderStatusCode result = pkcs12Reader_->GetLabel(cert.get(), label);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kSuccess);
EXPECT_EQ(label.c_str(), expected_label);
}
// Certificate without friendly name (alias) and with empty subject name,
// operation will fail with kPkcs12CNExtractionFailed.
{
ScopedX509 cert = X509New();
std::string label;
Pkcs12ReaderStatusCode result = pkcs12Reader_->GetLabel(cert.get(), label);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kPkcs12CNExtractionFailed);
}
// Certificate without friendly name (alias), but with subject name,
// operation will succeed. Label will be taken from CN.
{
ScopedX509 cert = X509New();
ScopedX509_NAME subject = X509NameNew();
// This only sets org name, country and common name.
SetOrgDataToX509Name(subject.get());
X509_set_subject_name(cert.get(), subject.get());
std::string expected_label(reinterpret_cast<char*>(common_name_));
std::string label;
Pkcs12ReaderStatusCode result = pkcs12Reader_->GetLabel(cert.get(), label);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kSuccess);
EXPECT_EQ(label.c_str(), expected_label);
}
// Certificate without friendly name (alias) and with empty subject name,
// operation will fail with kPkcs12CNExtractionFailed.
{
ScopedX509 cert = X509New();
std::string label;
Pkcs12ReaderStatusCode result = pkcs12Reader_->GetLabel(cert.get(), label);
EXPECT_TRUE(label.empty());
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kPkcs12CNExtractionFailed);
}
}
TEST_F(Pkcs12ReaderTest, isCertsWithNicknamesInSlots) {
// Empty nickname, isCertsWithNicknamesInSlot() returns failure.
// Operation will fail.
{
std::string nickname = "";
bool is_nickname_present = false;
Pkcs12ReaderStatusCode result =
pkcs12Reader_->IsCertWithNicknameInSlots(nickname, is_nickname_present);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kPkcs12MissedNickname);
}
// Not defined nickname, isCertsWithNicknamesInSlot() returns failure.
// Operation will fail.
{
std::string not_defined_nickname;
bool is_nickname_present = false;
Pkcs12ReaderStatusCode result = pkcs12Reader_->IsCertWithNicknameInSlots(
not_defined_nickname, is_nickname_present);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kPkcs12MissedNickname);
}
// Not testing normal case, it is tested with certificate in
// chaps_util_impl_unittest.cc
}
TEST_F(Pkcs12ReaderTest, DoesKeyForCertExist) {
crypto::ScopedTestNSSDB nss_test_db_;
auto cert_type = Pkcs12ReaderCertSearchType::kPlainType;
// Empty certificate, operation will fail.
{
PK11SlotInfo* slot = nullptr;
scoped_refptr<net::X509Certificate> cert = nullptr;
Pkcs12ReaderStatusCode result =
pkcs12Reader_->DoesKeyForCertExist(slot, cert_type, cert);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kCertificateDataMissed);
}
// Empty slot, operation will fail.
{
PK11SlotInfo* slot = nullptr;
scoped_refptr<net::X509Certificate> cert = GetTestCert();
Pkcs12ReaderStatusCode result =
pkcs12Reader_->DoesKeyForCertExist(slot, cert_type, cert);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kMissedSlotInfo);
}
// Slot and cert provided, it is a test slot, so key will be missed.
{
scoped_refptr<net::X509Certificate> cert = GetTestCert();
Pkcs12ReaderStatusCode result = pkcs12Reader_->DoesKeyForCertExist(
nss_test_db_.slot(), cert_type, cert);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kKeyDataMissed);
}
}
TEST_F(Pkcs12ReaderTest, DoesKeyForDerCertExist) {
crypto::ScopedTestNSSDB nss_test_db_;
auto cert_type = Pkcs12ReaderCertSearchType::kDerType;
// Empty certificate, operation will fail.
{
PK11SlotInfo* slot = nullptr;
scoped_refptr<net::X509Certificate> cert = nullptr;
Pkcs12ReaderStatusCode result =
pkcs12Reader_->DoesKeyForCertExist(slot, cert_type, cert);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kCertificateDataMissed);
}
// Empty slot, operation will fail.
{
PK11SlotInfo* slot = nullptr;
scoped_refptr<net::X509Certificate> cert = GetTestCert();
Pkcs12ReaderStatusCode result =
pkcs12Reader_->DoesKeyForCertExist(slot, cert_type, cert);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kMissedSlotInfo);
}
// Slot and cert provided, it is a test slot, so key will be missed.
{
scoped_refptr<net::X509Certificate> cert = GetTestCert();
Pkcs12ReaderStatusCode result = pkcs12Reader_->DoesKeyForCertExist(
nss_test_db_.slot(), cert_type, cert);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kKeyDataMissed);
}
}
TEST_F(Pkcs12ReaderTest, EnrichKeyDataCommonErrors) {
// Empty key_data, operation will fail.
{
KeyData key_data;
Pkcs12ReaderStatusCode result = pkcs12Reader_->EnrichKeyData(key_data);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kKeyDataMissed);
}
// Empty key data - not RSA and not EC keys, operation will fail.
{
KeyData key_data;
key_data.key = bssl::UniquePtr<EVP_PKEY>(EVP_PKEY_new());
Pkcs12ReaderStatusCode result = pkcs12Reader_->EnrichKeyData(key_data);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kPkcs12NotSupportedKeyType);
}
// NONE type of key, operation will fail.
{
KeyData key_data;
EVP_PKEY* key = EVP_PKEY_new();
EVP_PKEY_set_type(key, EVP_PKEY_NONE);
key_data.key = bssl::UniquePtr<EVP_PKEY>(key);
Pkcs12ReaderStatusCode result = pkcs12Reader_->EnrichKeyData(key_data);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kPkcs12NotSupportedKeyType);
}
}
TEST_F(Pkcs12ReaderTest, EnrichRsaKeyData) {
// RSA is NULL. Operation will fail.
{
KeyData key_data;
key_data.key = GenerateRsaKey();
EVP_PKEY_assign_RSA(key_data.key.get(), nullptr);
Pkcs12ReaderStatusCode result = pkcs12Reader_->EnrichKeyData(key_data);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kRsaKeyExtractionFailed);
}
// Normal RSA key, operation will succeed.
{
KeyData key_data;
key_data.key = GenerateRsaKey();
Pkcs12ReaderStatusCode result = pkcs12Reader_->EnrichKeyData(key_data);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kSuccess);
}
}
TEST_F(Pkcs12ReaderTest, EnrichEcKeyData) {
// EC in key_data is NULL. Operation will fail.
{
KeyData key_data;
key_data.key = GenerateEcKey();
EVP_PKEY_assign_EC_KEY(key_data.key.get(), nullptr);
Pkcs12ReaderStatusCode result = pkcs12Reader_->EnrichKeyData(key_data);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kEcKeyExtractionFailed);
}
// EC is present, but empty. Operation will fail.
{
KeyData key_data;
key_data.key = GenerateEcKey();
EVP_PKEY_assign_EC_KEY(key_data.key.get(), EC_KEY_new());
Pkcs12ReaderStatusCode result = pkcs12Reader_->EnrichKeyData(key_data);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kEcKeyBytesEmpty);
}
// Normal EC key, operation will succeed.
{
KeyData key_data;
key_data.key = GenerateEcKey();
Pkcs12ReaderStatusCode result = pkcs12Reader_->EnrichKeyData(key_data);
// Key is randomly generated, so not checking key_data here. It is
// checked from the higher level test chaps_util_impl_unittest.cc
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kSuccess);
}
}
TEST_F(Pkcs12ReaderTest, CheckKeyRelationCommonErrors) {
// Empty key_data, operation will fail.
{
KeyData key_data;
ScopedX509 cert = X509New();
bool is_related = true;
Pkcs12ReaderStatusCode result =
pkcs12Reader_->CheckRelation(key_data, cert.get(), is_related);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kKeyDataMissed);
EXPECT_FALSE(is_related);
}
// Empty cert, operation will fail.
{
KeyData key_data = BuildKeyDataWithEmptyPkey();
X509* cert = nullptr;
bool is_related = true;
Pkcs12ReaderStatusCode result =
pkcs12Reader_->CheckRelation(key_data, cert, is_related);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kCertificateDataMissed);
EXPECT_FALSE(is_related);
}
// No key RSA data and no EC key data, operation will fail.
{
KeyData key_data = BuildKeyDataWithEmptyPkey();
ScopedX509 cert = BuildScopedX509AndSetPublicKey(GenerateRsaKey());
bool is_related = true;
Pkcs12ReaderStatusCode result =
pkcs12Reader_->CheckRelation(key_data, cert.get(), is_related);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kPkcs12NotSupportedKeyType);
EXPECT_FALSE(is_related);
}
// Cert has no public key, operation will fail.
{
KeyData key_data = BuildRsaKeyData();
ScopedX509 cert = X509New();
bool is_related = true;
Pkcs12ReaderStatusCode result =
pkcs12Reader_->CheckRelation(key_data, cert.get(), is_related);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kPKeyExtractionFailed);
EXPECT_FALSE(is_related);
}
}
TEST_F(Pkcs12ReaderTest, CheckRelationRsaKey) {
// RSA key is empty in key_data, operation will return
// kPkcs12NoValidCertificatesFound.
{
KeyData key_data = BuildRsaKeyData();
EVP_PKEY_assign_RSA(key_data.key.get(), RSA_new());
ScopedX509 cert = BuildScopedX509AndSetPublicKey(GenerateRsaKey());
bool is_related = true;
Pkcs12ReaderStatusCode result =
pkcs12Reader_->CheckRelation(key_data, cert.get(), is_related);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kPkcs12NoValidCertificatesFound);
EXPECT_FALSE(is_related);
}
// Regular RSA key, cert has a public key not related to private key.
// Operation will return kPkcs12NoValidCertificatesFound.
{
KeyData key_data = BuildRsaKeyData();
ScopedX509 cert = BuildScopedX509AndSetPublicKey(GenerateRsaKey());
bool is_related = true;
Pkcs12ReaderStatusCode result =
pkcs12Reader_->CheckRelation(key_data, cert.get(), is_related);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kPkcs12NoValidCertificatesFound);
EXPECT_FALSE(is_related);
}
// Regular RSA key, cert has other type (EC) of public key.
// Operation will fail.
{
KeyData key_data = BuildRsaKeyData();
ScopedX509 cert = BuildScopedX509AndSetPublicKey(GenerateEcKey());
bool is_related = false;
Pkcs12ReaderStatusCode result =
pkcs12Reader_->CheckRelation(key_data, cert.get(), is_related);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kPkeyComparisonFailure);
EXPECT_FALSE(is_related);
}
// Regular RSA key, cert has a public key related to private key,
// operation will succeed.
{
KeyData key_data = BuildRsaKeyData();
ScopedX509 cert = BuildScopedX509AndSetPublicKey(key_data.key);
bool is_related = false;
Pkcs12ReaderStatusCode result =
pkcs12Reader_->CheckRelation(key_data, cert.get(), is_related);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kSuccess);
EXPECT_TRUE(is_related);
}
}
TEST_F(Pkcs12ReaderTest, CheckRelationEcKey) {
// EC key is null in key_data, operation will fail.
{
KeyData key_data = BuildEcKeyData();
EVP_PKEY_assign_EC_KEY(key_data.key.get(), nullptr);
ScopedX509 cert = BuildScopedX509AndSetPublicKey(GenerateEcKey());
bool is_related = true;
Pkcs12ReaderStatusCode result =
pkcs12Reader_->CheckRelation(key_data, cert.get(), is_related);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kPkeyComparisonFailure);
EXPECT_FALSE(is_related);
}
// EC key is empty in key_data, operation will fail.
{
KeyData key_data = BuildEcKeyData();
EVP_PKEY_assign_EC_KEY(key_data.key.get(), EC_KEY_new());
ScopedX509 cert = BuildScopedX509AndSetPublicKey(GenerateEcKey());
bool is_related = true;
Pkcs12ReaderStatusCode result =
pkcs12Reader_->CheckRelation(key_data, cert.get(), is_related);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kPkeyComparisonFailure);
EXPECT_FALSE(is_related);
}
// Regular EC key_data, public key in cert is other type of key.
// Operation will fail.
{
KeyData key_data = BuildEcKeyData();
ScopedX509 cert = BuildScopedX509AndSetPublicKey(GenerateRsaKey());
bool is_related = true;
Pkcs12ReaderStatusCode result =
pkcs12Reader_->CheckRelation(key_data, cert.get(), is_related);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kPkeyComparisonFailure);
EXPECT_FALSE(is_related);
}
// Regular EC key_data, public key in cert is not related to
// the private key. Operation will fail.
{
KeyData key_data = BuildEcKeyData();
ScopedX509 cert = BuildScopedX509AndSetPublicKey(GenerateEcKey());
bool is_related = true;
Pkcs12ReaderStatusCode result =
pkcs12Reader_->CheckRelation(key_data, cert.get(), is_related);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kPkcs12NoValidCertificatesFound);
EXPECT_FALSE(is_related);
}
// Regular EC key_data, public key in cert is related to private key.
// Operation will succeed.
{
KeyData key_data = BuildEcKeyData();
ScopedX509 cert = BuildScopedX509AndSetPublicKey(key_data.key);
bool is_related = false;
Pkcs12ReaderStatusCode result =
pkcs12Reader_->CheckRelation(key_data, cert.get(), is_related);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kSuccess);
EXPECT_TRUE(is_related);
}
}
TEST_F(Pkcs12ReaderTest, IsCertInSlot) {
crypto::ScopedTestNSSDB nss_test_db_;
// Empty cert, operation will fail.
{
PK11SlotInfo* slot = nss_test_db_.slot();
scoped_refptr<net::X509Certificate> cert = nullptr;
bool is_cert_present = false;
Pkcs12ReaderStatusCode result =
pkcs12Reader_->IsCertInSlot(slot, cert, is_cert_present);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kCertificateDataMissed);
}
// Empty slot, operation will fail.
{
PK11SlotInfo* slot = nullptr;
scoped_refptr<net::X509Certificate> cert = GetTestCert();
bool is_cert_present = false;
Pkcs12ReaderStatusCode result =
pkcs12Reader_->IsCertInSlot(slot, cert, is_cert_present);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kMissedSlotInfo);
}
// Slot and cert provided, slot is empty, cert will be not found.
{
bool is_cert_present = true;
scoped_refptr<net::X509Certificate> cert = GetTestCert();
Pkcs12ReaderStatusCode result =
pkcs12Reader_->IsCertInSlot(nss_test_db_.slot(), cert, is_cert_present);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kSuccess);
EXPECT_FALSE(is_cert_present);
}
// Slot and cert provided, cert is already stored in slot, cert will be found.
{
bool is_cert_present = false;
scoped_refptr<net::X509Certificate> cert = GetTestCert();
PK11SlotInfo* slot = nss_test_db_.slot();
net::ImportClientCertToSlot(cert.get(), slot);
Pkcs12ReaderStatusCode result =
pkcs12Reader_->IsCertInSlot(slot, cert, is_cert_present);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kSuccess);
EXPECT_TRUE(is_cert_present);
}
}
TEST_F(Pkcs12ReaderTest, GetCertFromDerData) {
// Cert data is empty, valid cert can not be extracted. Operation will fail.
{
const unsigned char* der_cert_data = nullptr;
int der_cert_len = 1;
bssl::UniquePtr<X509> x509;
Pkcs12ReaderStatusCode result =
pkcs12Reader_->GetCertFromDerData(der_cert_data, der_cert_len, x509);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kPkcs12NoValidCertificatesFound);
}
// Cert len is 0, valid cert can not be extracted. Operation will fail.
{
const unsigned char der_cert_data[1024] = {1, 2};
int der_cert_len = 0;
bssl::UniquePtr<X509> x509;
Pkcs12ReaderStatusCode result =
pkcs12Reader_->GetCertFromDerData(der_cert_data, der_cert_len, x509);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kPkcs12NoValidCertificatesFound);
}
// Cert data is not empty, but it is not a valid cert.
// Operation will fail.
{
const unsigned char der_cert_data[1024] = {1, 2};
int der_cert_len = 2;
bssl::UniquePtr<X509> x509;
Pkcs12ReaderStatusCode result =
pkcs12Reader_->GetCertFromDerData(der_cert_data, der_cert_len, x509);
EXPECT_EQ(result, Pkcs12ReaderStatusCode::kCreateCertFailed);
}
}
} // namespace
} // namespace kcer::internal