blob: d9700248ca63e9e1435cc57df924b25431f82943 [file]
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "crypto/default/x509_certificate.h"
#include <string>
#include <utility>
#include <vector>
#include "absl/log/absl_check.h"
#include "absl/log/check.h"
#include "absl/status/status.h"
#include "absl/status/status_matchers.h"
#include "absl/strings/escaping.h"
#include "absl/strings/string_view.h"
#include "absl/time/time.h"
#include "crypto/algorithms.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "openssl/asn1.h"
#include "openssl/base.h"
#include "openssl/mem.h"
#include "openssl/obj.h"
#include "openssl/x509.h"
#include "proto/common.pb.h"
#include "tink/signature/ecdsa_parameters.h"
#include "tink/signature/ed25519_parameters.h"
#include "tink/signature/rsa_ssa_pss_parameters.h"
namespace credentio {
namespace {
using ::absl_testing::IsOk;
using ::absl_testing::IsOkAndHolds;
using ::absl_testing::StatusIs;
using ::crypto::tink::EcdsaParameters;
using ::crypto::tink::Ed25519Parameters;
using ::crypto::tink::RsaSsaPssParameters;
using ::testing::ElementsAre;
using ::testing::HasSubstr;
using ::testing::IsEmpty;
using ::testing::NotNull;
constexpr absl::string_view kDerRsaBase64 =
"MIIGDDCCA/SgAwIBAgIQf/"
"J0H9HG3kO1lHqOZXCenjANBgkqhkiG9w0BAQsFADB1MQswCQYDVQQGEwJVUzEjMCEGA1UEChMa"
"QWRvYmUgU3lzdGVtcyBJbmNvcnBvcmF0ZWQxHTAbBgNVBAsTFEFkb2JlIFRydXN0IFNlcnZpY2"
"VzMSIwIAYDVQQDExlBZG9iZSBQcm9kdWN0IFNlcnZpY2VzIEczMB4XDTI0MDExMTAwMDAwMFoX"
"DTI1MDExMDIzNTk1OVowfzERMA8GA1UEAwwIY2FpLXByb2QxEzARBgNVBAoMCkFkb2JlIEluYy"
"4xETAPBgNVBAcMCFNhbiBKb3NlMRMwEQYDVQQIDApDYWxpZm9ybmlhMQswCQYDVQQGEwJVUzEg"
"MB4GCSqGSIb3DQEJARYRY2FpLW9wc0BhZG9iZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDw"
"AwggEKAoIBAQDv0wCnfYY9lkHDsykrTG7FYlnYHBcyualuD5u9ULjzv+"
"FsTWOLg8Nhrz9RTxI9EeBbu3Wm7f4vqPsQYfxkEp0wIa6DVmEOZhbAeRfbhybWQ/"
"D4Wvvck4mEZR+QZmTpIn7HX61gbtMFHlJUxkYBctIoAt9TBAFbz9d5Ig2WG0bsH39b6/"
"8USXnIIk4FB6dtBRT1xeEwSDtwOd1YBpXXNBJmRWHXNJZZ85of2tBTesg/"
"kMvTrOJJxYDZ97U416wcvbVomlees+NXUY3/"
"ZB4xH+"
"NsZils7m1bL2v2hSnHiLoqZeUKklbHUmT4ZpjrZCdtuIsWm5j2PPXKr7HKUuCbZSXBAgMBAAWj"
"ggGMMIIBiDAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/"
"wQEAwIHgDAeBgNVHSUEFzAVBgkqhkiG9y8BAQwGCCsGAQUFBwMEMIGOBgNVHSAEgYYwgYMwgYA"
"GCSqGSIb3LwECAzBzMHEGCCsGAQUFBwICMGUMY1lvdSBhcmUgbm90IHBlcm1pdHRlZCB0byB1c"
"2UgdGhpcyBMaWNlbnNlIENlcnRpZmljYXRlIGV4Y2VwdCBhcyBwZXJtaXR0ZWQgYnkgdGhlIGx"
"pY2Vuc2UgYWdyZWVtZW50LjBdBgNVHR8EVjBUMFKgUKBOhkxodHRwOi8vcGtpLWNybC5zeW1hd"
"XRoLmNvbS9jYV83YTVjM2EwYzczMTE3NDA2YWRkMTkzMTJiYzFiYzIzZi9MYXRlc3RDUkwuY3J"
"sMDcGCCsGAQUFBwEBBCswKTAnBggrBgEFBQcwAYYbaHR0cDovL3BraS1vY3NwLnN5bWF1dGguY"
"29tMB8GA1UdIwQYMBaAFFcpejJNzP7kNU7AHyRzznNTq99qMA0GCSqGSIb3DQEBCwUAA4ICAQA"
"hY9X822Lvow9+KlSdkAI/95WsS/"
"n1Y5se5YJkePUHLxsablSaNOA9BiVfJOPxcT+JjbumGCseDSmIOxYPO7mzwHpMqRoyZS+"
"C2T5SC6TJtt920ELoq+"
"0aDLjRw7gOQRSg8OK0PFPWKBtCp0qiAChUqoMRWqcX4IVBDO1sZxmEUj1cpOwJDB/"
"2HDsuEkKjqMA0EgAE3JC1LBYik95IQmE9WBYvIp6mBDEkyovqyBhnEar2kJJCfaBLylp/"
"JAUsHJnAQEP8PHK1FlkvpvdleoX59lmwT1+wHGlxYWK/"
"ykW+AFA60LOVJt8byjtuAE8lebuYADyPe3eEMR4THQbHwH/"
"1rz2nNN5tZWsPdIR7S5mX0RtUL74XgSixEkV1jDO4/"
"WIk7V3kjdXEZr0WtWr8VgEY5G+"
"8NpPBqd2LMLBp7jejMIj3tA8RS1L6MnO3PWRqkdwGwsCHsvGcTzauWarWji990WxBTPscSk6Q8"
"WTIqiHI9OfUUiriWQkpfeMEDo1r+zHJRmj26+"
"zgID7QB41xNeV3K6BFQX6ayl1swuIh26KB0Mu74sndRzG+8tMTffvjBoO9QPW/"
"OtdWyYmsLGT0Kcj9EaaIg1JmgNtRBwo9f89eYJSYwenQ+GddpqdnBIjk63Q+K3gCdlpTs++"
"tJCZ7DX9yndmYlx94HgUZFPcNimun6Q==";
constexpr absl::string_view kDerEcdsaBase64 =
"MIIChzCCAi6gAwIBAgIUcCTmJHYF8dZfG0d1UdT6/"
"LXtkeYwCgYIKoZIzj0EAwIwgYwxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBww"
"JU29tZXdoZXJlMScwJQYDVQQKDB5DMlBBIFRlc3QgSW50ZXJtZWRpYXRlIFJvb3QgQ0ExGTAXB"
"gNVBAsMEEZPUiBURVNUSU5HX09OTFkxGDAWBgNVBAMMD0ludGVybWVkaWF0ZSBDQTAeFw0yMjA"
"2MTAxODQ2NDBaFw0zMDA4MjYxODQ2NDBaMIGAMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExE"
"jAQBgNVBAcMCVNvbWV3aGVyZTEfMB0GA1UECgwWQzJQQSBUZXN0IFNpZ25pbmcgQ2VydDEZMBc"
"GA1UECwwQRk9SIFRFU1RJTkdfT05MWTEUMBIGA1UEAwwLQzJQQSBTaWduZXIwWTATBgcqhkjOP"
"QIBBggqhkjOPQMBBwNCAAQPaL6RkAkYkKU4+IryBSYxJM3h77sFiMrbvbI8fG7w2Bbl9otNG/"
"cch3DAw5rGAPV7NWkyl3QGuV/wt0MrAPDoo3gwdjAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/"
"wQMMAoGCCsGAQUFBwMEMA4GA1UdDwEB/"
"wQEAwIGwDAdBgNVHQ4EFgQUFznP0y83joiNOCedQkxTtAMyNcowHwYDVR0jBBgwFoAUDnyNcma"
"/osnlAJTvtW6A4rYOL2swCgYIKoZIzj0EAwIDRwAwRAIgOY/2szXjslg/"
"MyJFZ2y7OH8giPYTsvS7UPRP9GI9NgICIDQPMKrELQUJEtipZ0TqvI/"
"4mieoyRCeIiQtyuS0LACz";
// Base64 encoded string of DER bytes of an X.509 certificate signed with
// Ed25519 algorithm, which is generated by following commands:
//
// openssl genpkey -algorithm Ed25519 -outform PEM -out private.pem
// openssl pkey -in private.pem -pubout -outform PEM -out public.pem
// openssl req -x509 -key private.pem -out cert.pem -days 99999
// openssl x509 -in cert.pem -outform DER -out cert.der
// cat cert.der | base64
//
// This certificate is self-signed on 2024-09-18 and it will expire on
// 2298-07-03. So, if this code is still around in 2298 and you wonder why your
// test that relies on this certificate being valid fails, please update your
// test certificate.
constexpr absl::string_view kDerEdBase64 =
"MIIBoTCCAVOgAwIBAgIUZnrWsn3k+"
"VyZMdOt2jHxA4Z6QNIwBQYDK2VwMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXR"
"lMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwIBcNMjQwOTE4MTkxMTMyWhgPM"
"jI5ODA3MDMxOTExMzJaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwY"
"DVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwKjAFBgMrZXADIQAYkLGZHs4BuUq11RLkR"
"V3lX6U1CMxpkKMI3dFBkQjDFKNTMFEwHQYDVR0OBBYEFPl9A331I54qf4vhLTs5KZqsJznSMB8"
"GA1UdIwQYMBaAFPl9A331I54qf4vhLTs5KZqsJznSMA8GA1UdEwEB/"
"wQFMAMBAf8wBQYDK2VwA0EAxWKyUVcH4hoW/"
"mS66Ot4UGqaEKUANiyT6khvcUZLUpM2m7Cmh7ZwmjBz7b6X9nqHwd+8WnSMUZHKL5bLmZmsDw="
"=";
// Base64 encoded string of the signature obtained by running the following
// commands:
//
// openssl pkeyutl -sign -inkey private.pem -rawin -in data.txt -out sig.bin
// cat sig.bin | base64
//
// where data.txt contains the text "test data" (without a new line).
constexpr absl::string_view kEdSignatureBase64 =
"wB5+rUKWp47TZ8VPpUlA32IO033ggYB63qXLPyb8bDEGJyD8TBM/"
"psRxl5Z8EsglhzdmvB29VL62xp4+3On/Bg==";
std::string Base64Unescape(absl::string_view base64) {
std::string bytes;
ABSL_CHECK(absl::Base64Unescape(base64, &bytes));
return bytes;
}
TEST(X509CertificateTest, GetPemKeyParamsForRsaKey) {
auto x509 = X509Certificate::Create(Base64Unescape(kDerRsaBase64));
ABSL_ASSERT_OK(x509.status());
const crypto::tink::BigInteger exponent(std::string("\001\000\005", 3));
absl::StatusOr<std::vector<X509Certificate::TinkKeyParameters>> params_ps256 =
(*x509)->GetPemKeyParams(SigningAlgorithm::kPs256);
ABSL_ASSERT_OK(params_ps256.status());
absl::StatusOr<RsaSsaPssParameters> want_ps256_params =
RsaSsaPssParameters::Builder()
.SetModulusSizeInBits(2048)
.SetPublicExponent(exponent)
.SetMgf1HashType(RsaSsaPssParameters::HashType::kSha256)
.SetSigHashType(RsaSsaPssParameters::HashType::kSha256)
.SetSaltLengthInBytes(32)
.SetVariant(RsaSsaPssParameters::Variant::kNoPrefix)
.Build();
ABSL_ASSERT_OK(want_ps256_params.status());
EXPECT_THAT(*params_ps256, ElementsAre(*want_ps256_params));
absl::StatusOr<std::vector<X509Certificate::TinkKeyParameters>> params_ps384 =
(*x509)->GetPemKeyParams(SigningAlgorithm::kPs384);
ABSL_ASSERT_OK(params_ps384.status());
absl::StatusOr<RsaSsaPssParameters> want_ps384_params =
RsaSsaPssParameters::Builder()
.SetModulusSizeInBits(2048)
.SetPublicExponent(exponent)
.SetMgf1HashType(RsaSsaPssParameters::HashType::kSha384)
.SetSigHashType(RsaSsaPssParameters::HashType::kSha384)
.SetVariant(RsaSsaPssParameters::Variant::kNoPrefix)
.SetSaltLengthInBytes(48)
.Build();
ABSL_ASSERT_OK(want_ps384_params.status());
EXPECT_THAT(*params_ps384, ElementsAre(*want_ps384_params));
absl::StatusOr<std::vector<X509Certificate::TinkKeyParameters>> params_ps512 =
(*x509)->GetPemKeyParams(SigningAlgorithm::kPs512);
ABSL_ASSERT_OK(params_ps512.status());
absl::StatusOr<RsaSsaPssParameters> want_ps512_params =
RsaSsaPssParameters::Builder()
.SetModulusSizeInBits(2048)
.SetPublicExponent(exponent)
.SetMgf1HashType(RsaSsaPssParameters::HashType::kSha512)
.SetSigHashType(RsaSsaPssParameters::HashType::kSha512)
.SetVariant(RsaSsaPssParameters::Variant::kNoPrefix)
.SetSaltLengthInBytes(64)
.Build();
ABSL_ASSERT_OK(want_ps512_params.status());
EXPECT_THAT(*params_ps512, ElementsAre(*want_ps512_params));
EXPECT_THAT((*x509)->GetPemKeyParams(SigningAlgorithm::kEs256),
StatusIs(absl::StatusCode::kInvalidArgument,
HasSubstr("Wrong key type")));
EXPECT_THAT((*x509)->GetPemKeyParams(SigningAlgorithm::kEdDsa),
StatusIs(absl::StatusCode::kInvalidArgument,
HasSubstr("Wrong key type")));
}
TEST(X509CertificateTest, GetPemKeyParamsForEcdsaKey) {
auto x509 = X509Certificate::Create(Base64Unescape(kDerEcdsaBase64));
ABSL_ASSERT_OK(x509.status());
absl::StatusOr<std::vector<X509Certificate::TinkKeyParameters>> params_es256 =
(*x509)->GetPemKeyParams(SigningAlgorithm::kEs256);
ABSL_ASSERT_OK(params_es256.status());
absl::StatusOr<EcdsaParameters> want_p256_der_ecdsa_params =
EcdsaParameters::Builder()
.SetCurveType(EcdsaParameters::CurveType::kNistP256)
.SetHashType(EcdsaParameters::HashType::kSha256)
.SetSignatureEncoding(EcdsaParameters::SignatureEncoding::kDer)
.SetVariant(EcdsaParameters::Variant::kNoPrefix)
.Build();
ABSL_ASSERT_OK(want_p256_der_ecdsa_params.status());
absl::StatusOr<EcdsaParameters> want_p256_ieee_ecdsa_params =
EcdsaParameters::Builder()
.SetCurveType(EcdsaParameters::CurveType::kNistP256)
.SetHashType(EcdsaParameters::HashType::kSha256)
.SetSignatureEncoding(EcdsaParameters::SignatureEncoding::kIeeeP1363)
.SetVariant(EcdsaParameters::Variant::kNoPrefix)
.Build();
ABSL_ASSERT_OK(want_p256_ieee_ecdsa_params.status());
EXPECT_THAT(*params_es256, ElementsAre(*want_p256_ieee_ecdsa_params,
*want_p256_der_ecdsa_params));
absl::StatusOr<std::vector<X509Certificate::TinkKeyParameters>> params_es384 =
(*x509)->GetPemKeyParams(SigningAlgorithm::kEs384);
ABSL_ASSERT_OK(params_es384.status());
absl::StatusOr<EcdsaParameters> want_p384_der_ecdsa_params =
EcdsaParameters::Builder()
.SetCurveType(EcdsaParameters::CurveType::kNistP384)
.SetHashType(EcdsaParameters::HashType::kSha384)
.SetSignatureEncoding(EcdsaParameters::SignatureEncoding::kDer)
.SetVariant(EcdsaParameters::Variant::kNoPrefix)
.Build();
ABSL_ASSERT_OK(want_p384_der_ecdsa_params.status());
absl::StatusOr<EcdsaParameters> want_p384_ieee_ecdsa_params =
EcdsaParameters::Builder()
.SetCurveType(EcdsaParameters::CurveType::kNistP384)
.SetHashType(EcdsaParameters::HashType::kSha384)
.SetSignatureEncoding(EcdsaParameters::SignatureEncoding::kIeeeP1363)
.SetVariant(EcdsaParameters::Variant::kNoPrefix)
.Build();
ABSL_ASSERT_OK(want_p384_ieee_ecdsa_params.status());
EXPECT_THAT(*params_es384, ElementsAre(*want_p384_ieee_ecdsa_params,
*want_p384_der_ecdsa_params));
absl::StatusOr<std::vector<X509Certificate::TinkKeyParameters>> params_es521 =
(*x509)->GetPemKeyParams(SigningAlgorithm::kEs512);
ABSL_ASSERT_OK(params_es521.status());
absl::StatusOr<EcdsaParameters> want_p521_der_ecdsa_params =
EcdsaParameters::Builder()
.SetCurveType(EcdsaParameters::CurveType::kNistP521)
.SetHashType(EcdsaParameters::HashType::kSha512)
.SetSignatureEncoding(EcdsaParameters::SignatureEncoding::kDer)
.SetVariant(EcdsaParameters::Variant::kNoPrefix)
.Build();
ABSL_ASSERT_OK(want_p521_der_ecdsa_params.status());
absl::StatusOr<EcdsaParameters> want_p521_ieee_ecdsa_params =
EcdsaParameters::Builder()
.SetCurveType(EcdsaParameters::CurveType::kNistP521)
.SetHashType(EcdsaParameters::HashType::kSha512)
.SetSignatureEncoding(EcdsaParameters::SignatureEncoding::kIeeeP1363)
.SetVariant(EcdsaParameters::Variant::kNoPrefix)
.Build();
ABSL_ASSERT_OK(want_p521_ieee_ecdsa_params.status());
EXPECT_THAT(*params_es521, ElementsAre(*want_p521_ieee_ecdsa_params,
*want_p521_der_ecdsa_params));
EXPECT_THAT((*x509)->GetPemKeyParams(SigningAlgorithm::kPs256),
StatusIs(absl::StatusCode::kInvalidArgument,
HasSubstr("Wrong key type")));
EXPECT_THAT((*x509)->GetPemKeyParams(SigningAlgorithm::kEdDsa),
StatusIs(absl::StatusCode::kInvalidArgument,
HasSubstr("Wrong key type")));
}
TEST(X509CertificateTest, GetPemKeyParamsForEdKey) {
auto x509 = X509Certificate::Create(Base64Unescape(kDerEdBase64));
ABSL_ASSERT_OK(x509.status());
absl::StatusOr<std::vector<X509Certificate::TinkKeyParameters>> params_eddsa =
(*x509)->GetPemKeyParams(SigningAlgorithm::kEdDsa);
ABSL_ASSERT_OK(params_eddsa.status());
absl::StatusOr<Ed25519Parameters> want_params =
Ed25519Parameters::Create(Ed25519Parameters::Variant::kNoPrefix);
ABSL_ASSERT_OK(want_params.status());
EXPECT_THAT(*params_eddsa, ElementsAre(*want_params));
EXPECT_THAT((*x509)->GetPemKeyParams(SigningAlgorithm::kPs256),
StatusIs(absl::StatusCode::kInvalidArgument,
HasSubstr("Wrong key type")));
EXPECT_THAT((*x509)->GetPemKeyParams(SigningAlgorithm::kEs256),
StatusIs(absl::StatusCode::kInvalidArgument,
HasSubstr("Wrong key type")));
}
TEST(X509CertificateTest, VerifyEdSignedData) {
auto x509 = X509Certificate::Create(Base64Unescape(kDerEdBase64));
ABSL_ASSERT_OK(x509.status());
EXPECT_THAT(
(*x509)->VerifySignature(Base64Unescape(kEdSignatureBase64),
"this is a test", SigningAlgorithm::kEdDsa),
IsOk());
}
TEST(X509CertificateTest, VerifySignatureWithRsaKey) {
auto x509 = X509Certificate::Create(Base64Unescape(kDerRsaBase64));
ABSL_ASSERT_OK(x509.status());
// The actual signature and data don't matter for covering the lines in
// MaybeConvertPssToRsa, as the key conversion happens before signature
// verification. We expect a failure because the signature is invalid.
EXPECT_THAT((*x509)->VerifySignature("fake_signature", "fake_data",
SigningAlgorithm::kPs256),
StatusIs(absl::StatusCode::kInvalidArgument,
HasSubstr("Tink verification failed")));
}
TEST(X509CertificateTest, GetStartTime) {
auto x509 = X509Certificate::Create(Base64Unescape(kDerRsaBase64));
ABSL_ASSERT_OK(x509.status());
auto start_time = (*x509)->StartTime();
ABSL_ASSERT_OK(start_time.status());
EXPECT_EQ(absl::ToUnixSeconds(*start_time), 1704931200);
}
TEST(X509CertificateTest, GetEndTime) {
auto x509 = X509Certificate::Create(Base64Unescape(kDerRsaBase64));
ABSL_ASSERT_OK(x509.status());
auto end_time = (*x509)->EndTime();
ABSL_ASSERT_OK(end_time.status());
EXPECT_EQ(absl::ToUnixSeconds(*end_time), 1736553599);
}
TEST(X509CertificateTest, GetSubjectIssuerNullName) {
bssl::UniquePtr<X509> x509(X509_new());
X509Certificate cert(std::move(x509));
EXPECT_THAT(cert.GetSubject(), IsEmpty());
EXPECT_THAT(cert.GetIssuer(), IsEmpty());
}
TEST(X509CertificateTest, GetSerialNumberHexRsa) {
auto x509 = X509Certificate::Create(Base64Unescape(kDerRsaBase64));
ABSL_ASSERT_OK(x509.status());
auto serial_hex = (*x509)->GetSerialNumberHex();
ABSL_ASSERT_OK(serial_hex.status());
EXPECT_EQ(*serial_hex, "7ff2741fd1c6de43b5947a8e65709e9e");
}
TEST(X509CertificateTest, GetSerialNumberHexEcdsa) {
auto x509 = X509Certificate::Create(Base64Unescape(kDerEcdsaBase64));
ABSL_ASSERT_OK(x509.status());
auto serial_hex = (*x509)->GetSerialNumberHex();
ABSL_ASSERT_OK(serial_hex.status());
EXPECT_EQ(*serial_hex, "7024e6247605f1d65f1b477551d4fafcb5ed91e6");
}
TEST(X509CertificateTest, GetSerialNumberHexEdDsa) {
auto x509 = X509Certificate::Create(Base64Unescape(kDerEdBase64));
ABSL_ASSERT_OK(x509.status());
auto serial_hex = (*x509)->GetSerialNumberHex();
ABSL_ASSERT_OK(serial_hex.status());
EXPECT_EQ(*serial_hex, "667ad6b27de4f95c9931d3adda31f103867a40d2");
}
TEST(X509CertificateTest, GetAssuranceLevelNotFound) {
auto x509 = X509Certificate::Create(Base64Unescape(kDerRsaBase64));
ABSL_ASSERT_OK(x509.status());
EXPECT_THAT((*x509)->GetAssuranceLevel(),
StatusIs(absl::StatusCode::kNotFound));
}
TEST(X509CertificateTest, GetAssuranceLevelCorrectlyDecodesExtension) {
constexpr absl::string_view kAssuranceLevelValueOid =
"1.3.6.1.4.1.62558.3.20";
constexpr absl::string_view kAssuranceLevelExtensionOid =
"1.3.6.1.4.1.62558.3";
bssl::UniquePtr<X509> x509(X509_new());
ASSERT_NE(x509, nullptr);
bssl::UniquePtr<ASN1_OBJECT> ext_oid(
OBJ_txt2obj(kAssuranceLevelExtensionOid.data(), /*dont_search_names=*/1));
ASSERT_NE(ext_oid, nullptr);
bssl::UniquePtr<ASN1_OBJECT> val_oid(
OBJ_txt2obj(kAssuranceLevelValueOid.data(), /*dont_search_names=*/1));
ASSERT_NE(val_oid, nullptr);
unsigned char* der_data = nullptr;
int der_len = i2d_ASN1_OBJECT(val_oid.get(), &der_data);
ASSERT_GT(der_len, 0);
bssl::UniquePtr<ASN1_OCTET_STRING> octet_str(ASN1_OCTET_STRING_new());
ASSERT_TRUE(ASN1_OCTET_STRING_set(octet_str.get(), der_data, der_len));
OPENSSL_free(der_data);
bssl::UniquePtr<X509_EXTENSION> ext(X509_EXTENSION_create_by_OBJ(
nullptr, ext_oid.get(), /*crit=*/0, octet_str.get()));
ASSERT_NE(ext, nullptr);
ASSERT_TRUE(X509_add_ext(x509.get(), ext.get(), -1));
X509Certificate cert(std::move(x509));
EXPECT_THAT(cert.GetAssuranceLevel(), IsOkAndHolds(kAssuranceLevelValueOid));
}
TEST(X509CertificateTest, GetConformingProductIdNotFound) {
auto x509 = X509Certificate::Create(Base64Unescape(kDerRsaBase64));
ABSL_ASSERT_OK(x509.status());
EXPECT_THAT((*x509)->GetConformingProductId(),
StatusIs(absl::StatusCode::kNotFound));
}
TEST(X509CertificateTest, GetConformingProductIdCorrectlyDecodesExtension) {
// Create a cert with the conforming product id extension.
bssl::UniquePtr<X509> x509(X509_new());
bssl::UniquePtr<ASN1_OBJECT> ext_oid(
OBJ_txt2obj("1.3.6.1.4.1.62558.4", /*dont_search_names=*/1));
ASSERT_THAT(ext_oid, NotNull());
bssl::UniquePtr<ASN1_UTF8STRING> val_str(ASN1_UTF8STRING_new());
constexpr absl::string_view kUuid = "c25c0e15-84dc-4cd7-95de-1d9ea4c7f0db";
ASSERT_TRUE(ASN1_STRING_set(val_str.get(), kUuid.data(), kUuid.size()));
unsigned char* der_data = nullptr;
int der_len = i2d_ASN1_UTF8STRING(val_str.get(), &der_data);
ASSERT_GT(der_len, 0);
bssl::UniquePtr<ASN1_OCTET_STRING> octet_str(ASN1_OCTET_STRING_new());
ASSERT_TRUE(ASN1_OCTET_STRING_set(octet_str.get(), der_data, der_len));
OPENSSL_free(der_data);
bssl::UniquePtr<X509_EXTENSION> ext(X509_EXTENSION_create_by_OBJ(
nullptr, ext_oid.get(), /*crit=*/0, octet_str.get()));
ASSERT_THAT(ext, NotNull());
ASSERT_TRUE(X509_add_ext(x509.get(), ext.get(), -1));
// Parse cert and extract the conforming product id.
X509Certificate cert(std::move(x509));
EXPECT_THAT(cert.GetConformingProductId(), IsOkAndHolds(kUuid));
}
TEST(X509CertificateTest, CertificateWithoutValidPublicKey) {
bssl::UniquePtr<X509> x509(X509_new());
ASSERT_NE(x509, nullptr);
X509Certificate cert(std::move(x509));
EXPECT_THAT(
cert.VerifySignature("sig", "data", SigningAlgorithm::kPs256),
StatusIs(absl::StatusCode::kInvalidArgument,
HasSubstr("Certificate does not have a valid public key")));
EXPECT_THAT(
cert.GetPemKeyParams(SigningAlgorithm::kPs256),
StatusIs(absl::StatusCode::kInvalidArgument,
HasSubstr("Certificate does not have a valid public key")));
}
} // namespace
} // namespace credentio