| // 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/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/signature_pem_keyset_reader.h" |
| |
| namespace credentio { |
| namespace { |
| |
| using ::absl_testing::IsOk; |
| using ::absl_testing::IsOkAndHolds; |
| using ::absl_testing::StatusIs; |
| using ::testing::HasSubstr; |
| using ::testing::IsEmpty; |
| using ::testing::NotNull; |
| using ::testing::SizeIs; |
| |
| 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; |
| CHECK(absl::Base64Unescape(base64, &bytes)); |
| return bytes; |
| } |
| |
| TEST(X509CertificateTest, GetPemKeyParamsForRsaKey) { |
| auto x509 = X509Certificate::Create(Base64Unescape(kDerRsaBase64)); |
| ASSERT_THAT(x509.status(), IsOk()); |
| std::vector<crypto::tink::PemKeyParams> params; |
| |
| auto params_ps256 = (*x509)->GetPemKeyParams(SigningAlgorithm::kPs256); |
| ASSERT_THAT(params_ps256.status(), IsOk()); |
| params = *params_ps256; |
| ASSERT_THAT(params, SizeIs(1)); |
| EXPECT_EQ(params[0].key_type, crypto::tink::PemKeyType::PEM_RSA); |
| EXPECT_EQ(params[0].algorithm, crypto::tink::PemAlgorithm::RSASSA_PSS); |
| EXPECT_EQ(params[0].key_size_in_bits, 2048); |
| EXPECT_EQ(params[0].hash_type, google::crypto::tink::HashType::SHA256); |
| |
| auto params_ps384 = (*x509)->GetPemKeyParams(SigningAlgorithm::kPs384); |
| ASSERT_THAT(params_ps384.status(), IsOk()); |
| params = *params_ps384; |
| ASSERT_THAT(params, SizeIs(1)); |
| EXPECT_EQ(params[0].key_type, crypto::tink::PemKeyType::PEM_RSA); |
| EXPECT_EQ(params[0].algorithm, crypto::tink::PemAlgorithm::RSASSA_PSS); |
| EXPECT_EQ(params[0].key_size_in_bits, 2048); |
| EXPECT_EQ(params[0].hash_type, google::crypto::tink::HashType::SHA384); |
| |
| auto params_ps512 = (*x509)->GetPemKeyParams(SigningAlgorithm::kPs512); |
| ASSERT_THAT(params_ps512.status(), IsOk()); |
| params = *params_ps512; |
| ASSERT_THAT(params, SizeIs(1)); |
| EXPECT_EQ(params[0].key_type, crypto::tink::PemKeyType::PEM_RSA); |
| EXPECT_EQ(params[0].algorithm, crypto::tink::PemAlgorithm::RSASSA_PSS); |
| EXPECT_EQ(params[0].key_size_in_bits, 2048); |
| EXPECT_EQ(params[0].hash_type, google::crypto::tink::HashType::SHA512); |
| |
| 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)); |
| ASSERT_THAT(x509.status(), IsOk()); |
| std::vector<crypto::tink::PemKeyParams> params; |
| |
| auto params_es256 = (*x509)->GetPemKeyParams(SigningAlgorithm::kEs256); |
| ASSERT_THAT(params_es256.status(), IsOk()); |
| params = *params_es256; |
| ASSERT_THAT(params, SizeIs(2)); |
| EXPECT_EQ(params[0].key_type, crypto::tink::PemKeyType::PEM_EC); |
| EXPECT_EQ(params[0].algorithm, crypto::tink::PemAlgorithm::ECDSA_IEEE); |
| EXPECT_EQ(params[0].key_size_in_bits, 256); |
| EXPECT_EQ(params[0].hash_type, google::crypto::tink::HashType::SHA256); |
| EXPECT_EQ(params[1].key_type, crypto::tink::PemKeyType::PEM_EC); |
| EXPECT_EQ(params[1].algorithm, crypto::tink::PemAlgorithm::ECDSA_DER); |
| EXPECT_EQ(params[1].key_size_in_bits, 256); |
| EXPECT_EQ(params[1].hash_type, google::crypto::tink::HashType::SHA256); |
| |
| auto params_es384 = (*x509)->GetPemKeyParams(SigningAlgorithm::kEs384); |
| ASSERT_THAT(params_es384.status(), IsOk()); |
| params = *params_es384; |
| ASSERT_THAT(params, SizeIs(2)); |
| EXPECT_EQ(params[0].key_type, crypto::tink::PemKeyType::PEM_EC); |
| EXPECT_EQ(params[0].algorithm, crypto::tink::PemAlgorithm::ECDSA_IEEE); |
| EXPECT_EQ(params[0].key_size_in_bits, 256); |
| EXPECT_EQ(params[0].hash_type, google::crypto::tink::HashType::SHA384); |
| EXPECT_EQ(params[1].key_type, crypto::tink::PemKeyType::PEM_EC); |
| EXPECT_EQ(params[1].algorithm, crypto::tink::PemAlgorithm::ECDSA_DER); |
| EXPECT_EQ(params[1].key_size_in_bits, 256); |
| EXPECT_EQ(params[1].hash_type, google::crypto::tink::HashType::SHA384); |
| |
| auto params_es512 = (*x509)->GetPemKeyParams(SigningAlgorithm::kEs512); |
| ASSERT_THAT(params_es512.status(), IsOk()); |
| params = *params_es512; |
| ASSERT_THAT(params, SizeIs(2)); |
| EXPECT_EQ(params[0].key_type, crypto::tink::PemKeyType::PEM_EC); |
| EXPECT_EQ(params[0].algorithm, crypto::tink::PemAlgorithm::ECDSA_IEEE); |
| EXPECT_EQ(params[0].key_size_in_bits, 256); |
| EXPECT_EQ(params[0].hash_type, google::crypto::tink::HashType::SHA512); |
| EXPECT_EQ(params[1].key_type, crypto::tink::PemKeyType::PEM_EC); |
| EXPECT_EQ(params[1].algorithm, crypto::tink::PemAlgorithm::ECDSA_DER); |
| EXPECT_EQ(params[1].key_size_in_bits, 256); |
| EXPECT_EQ(params[1].hash_type, google::crypto::tink::HashType::SHA512); |
| |
| 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)); |
| ASSERT_THAT(x509.status(), IsOk()); |
| std::vector<crypto::tink::PemKeyParams> params; |
| |
| auto params_eddsa = (*x509)->GetPemKeyParams(SigningAlgorithm::kEdDsa); |
| ASSERT_THAT(params_eddsa.status(), IsOk()); |
| params = *params_eddsa; |
| ASSERT_THAT(params, SizeIs(1)); |
| EXPECT_EQ(params[0].key_type, crypto::tink::PemKeyType::PEM_EC); |
| EXPECT_EQ(params[0].algorithm, crypto::tink::PemAlgorithm::ED25519); |
| // BoringSSL will return 253 bits here instead of 256 bits because the lower |
| // three bits of the private key scalar are cleared. |
| EXPECT_EQ(params[0].key_size_in_bits, 253); |
| EXPECT_EQ(params[0].hash_type, google::crypto::tink::HashType::SHA512); |
| |
| 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)); |
| ASSERT_THAT(x509.status(), IsOk()); |
| EXPECT_THAT( |
| (*x509)->VerifySignature(Base64Unescape(kEdSignatureBase64), |
| "this is a test", SigningAlgorithm::kEdDsa), |
| IsOk()); |
| } |
| |
| TEST(X509CertificateTest, VerifySignatureWithRsaKey) { |
| auto x509 = X509Certificate::Create(Base64Unescape(kDerRsaBase64)); |
| ASSERT_THAT(x509.status(), IsOk()); |
| // 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)); |
| ASSERT_THAT(x509.status(), IsOk()); |
| auto start_time = (*x509)->StartTime(); |
| ASSERT_THAT(start_time.status(), IsOk()); |
| EXPECT_EQ(absl::ToUnixSeconds(*start_time), 1704931200); |
| } |
| |
| TEST(X509CertificateTest, GetEndTime) { |
| auto x509 = X509Certificate::Create(Base64Unescape(kDerRsaBase64)); |
| ASSERT_THAT(x509.status(), IsOk()); |
| auto end_time = (*x509)->EndTime(); |
| ASSERT_THAT(end_time.status(), IsOk()); |
| 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)); |
| ASSERT_THAT(x509.status(), IsOk()); |
| auto serial_hex = (*x509)->GetSerialNumberHex(); |
| ASSERT_THAT(serial_hex.status(), IsOk()); |
| EXPECT_EQ(*serial_hex, "7ff2741fd1c6de43b5947a8e65709e9e"); |
| } |
| |
| TEST(X509CertificateTest, GetSerialNumberHexEcdsa) { |
| auto x509 = X509Certificate::Create(Base64Unescape(kDerEcdsaBase64)); |
| ASSERT_THAT(x509.status(), IsOk()); |
| auto serial_hex = (*x509)->GetSerialNumberHex(); |
| ASSERT_THAT(serial_hex.status(), IsOk()); |
| EXPECT_EQ(*serial_hex, "7024e6247605f1d65f1b477551d4fafcb5ed91e6"); |
| } |
| |
| TEST(X509CertificateTest, GetSerialNumberHexEdDsa) { |
| auto x509 = X509Certificate::Create(Base64Unescape(kDerEdBase64)); |
| ASSERT_THAT(x509.status(), IsOk()); |
| auto serial_hex = (*x509)->GetSerialNumberHex(); |
| ASSERT_THAT(serial_hex.status(), IsOk()); |
| EXPECT_EQ(*serial_hex, "667ad6b27de4f95c9931d3adda31f103867a40d2"); |
| } |
| |
| TEST(X509CertificateTest, GetAssuranceLevelNotFound) { |
| auto x509 = X509Certificate::Create(Base64Unescape(kDerRsaBase64)); |
| ASSERT_THAT(x509.status(), IsOk()); |
| 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)); |
| ASSERT_THAT(x509.status(), IsOk()); |
| 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 |