| // 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 |