| // 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/eku_verifier.h" |
| |
| #include <string> |
| |
| #include "absl/log/check.h" |
| #include "absl/strings/escaping.h" |
| #include "absl/strings/string_view.h" |
| #include "gtest/gtest.h" |
| |
| namespace credentio { |
| namespace { |
| |
| // This certificate is self-signed and has no EKU. |
| // The certificate is created by following the steps below: |
| // 1. Create a configuration file called `cert.cnf` with the following content: |
| // |
| // [ req ] |
| // distinguished_name = req_distinguished_name |
| // prompt = no |
| // |
| // [ req_distinguished_name ] |
| // C = US |
| // ST = MA |
| // L = Cambridge |
| // O = Unit Test |
| // CN = Unit Test |
| // |
| // [ v3_ext ] |
| // basicConstraints = CA:false |
| // keyUsage = digitalSignature, keyEncipherment |
| // |
| // 2. Generate the self-signed certificate by running the following command: |
| // openssl req -x509 -new -newkey rsa:2048 -keyout mycert.key -out mycert.crt \ |
| // -days 365 -config cert.cnf -extensions v3_ext -nodes |
| // |
| // 3. Generate the DER bytes of the certificate by running the following |
| // command: |
| // openssl req -x509 -new -newkey rsa:2048 -keyout mycert.key -out mycert.der \ |
| // -days 365 -config cert.cnf -extensions v3_ext -nodes -outform DER |
| // |
| // 4. Encode the DER bytes to base64 by running the following command: |
| // cat mycert.der | base64 -w 0 |
| constexpr absl::string_view kSelfSignedCertNoEkuBase64 = |
| R"(MIIC+TCCAeGgAwIBAgIUYSYg4BtYfbjcgKpPxDjiPGSmolMwDQYJKoZIhvcNAQELBQAwEjEQMA4GA1UEAwwHVGVzdCBDQTAeFw0yNTA4MDkxNzA5MzhaFw0yNjA4MDkxNzA5MzhaMBcxFTATBgNVBAMMDG15c2VydmVyLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPNaCaGamYc4i98Jqzkvi3+RW1cDQnLeWfxayJmo2f821iphgT+SnndzGqgzKnBDqoyxzu4oAOPxvm2AB/IVnnpth4UHYCvLkjYH5KLAWGCy3cJ+9IiN5XqLBB1gi4hert4kZfPRsZkLuCLiNPnFx3De9JRqd+S9kPcGkXZS2WIdjkk4MK9fmy2RsCUsvywQCDmmoEUpyhB7cj1ZiML4JH46wXRwQdoHGa1DGde13suhtCnf2QfFvVnP+SEGbhHkGAydwWi30YJojzQTEpI8wZa1oTMbXgfYZ13AObE2g2N84BVfk4CUivMI0Agrdx4Ix1nuPqPqwh7zyx6rc49kt+kCAwEAAaNCMEAwHQYDVR0OBBYEFEkKD+6lAuhRcKIs3BqU1VA12nB8MB8GA1UdIwQYMBaAFBdH5e5xEcv9yEjPOO2+XNgncNkXMA0GCSqGSIb3DQEBCwUAA4IBAQAelWiUlQsMtdZRn5OfwnQC1p5jlbni+HMYofZRWmFqNrFqVURxHZmtfN6bqI0gNARVKJzTy/y8g006603zPBIu4Ax715TSbhEhPsnOucB6b0ydvA6ynYm3n/QLsWeT9ummbbWJjITkhzHmu4t8tHyKMXOnX8LPTi0ZBnZ/Jw6Lb+7kM0X1at7KfhBbAqcCiIsQLS7zURehijoAxcJWdC8OQZZ/3HeqWzuAH52jHrF/g/H6r15JzXCyPVSbBey4GbPh/+1MHe8RQyMmCGyq1gEk1K51XGKjepLoNgxUs4l10lMpGFptEHph+bZfrVKgfi4okq/D5EPdje6N5sCSZL6Q)"; |
| // This certificate is self-signed and it has both the C2PA claim signing EKU |
| // and the `anyExtendedKeyUsage` EKU. |
| // The certificate is created by following the steps above for the |
| // `kSelfSignedCertNoEkuBase64` with the following change: |
| // 1. In the configuration file `cert.cnf`, add the line to the [ v3_ext ] |
| // section: |
| // extendedKeyUsage = 2.5.29.37.0, 1.3.6.1.4.1.62558.2.1 |
| constexpr absl::string_view kSelfSignedCertWithAnyEkuAndC2paEkuBase64 = |
| R"(MIIDkDCCAnigAwIBAgIUFtIA85O7PUfkXi1HpHaUHhci8DEwDQYJKoZIhvcNAQELBQAwVjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk1BMRIwEAYDVQQHDAlDYW1icmlkZ2UxEjAQBgNVBAoMCVVuaXQgVGVzdDESMBAGA1UEAwwJVW5pdCBUZXN0MB4XDTI1MDgwOTE3NDI1MVoXDTI2MDgwOTE3NDI1MVowVjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk1BMRIwEAYDVQQHDAlDYW1icmlkZ2UxEjAQBgNVBAoMCVVuaXQgVGVzdDESMBAGA1UEAwwJVW5pdCBUZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmR3ZSWgPSGo2W6z/JVyV7CHVhYv0BGEkMCfL0vFiHt2ThYQZCQeHV+cd4++acnPuPwvnoZxWPbTemJ7D9bMbWeuQ6XKSrV4nUx+2ZFi/CcwqqdawoiSThTW/Rw48qXacHfGRiM2r1tt7nmJ7gMUcM6kwXeHr1VabiIZqy0kW9+h71UqMW22ntGilfESsZq2QududiWB4ivLnSIFJWHTpGaNSsMdA4AwVV4cfpmf3dyj88u4CrV51k9T2q0ARocgXLVZdv6KoC6MAqvNykRg7qQGlH6nWgYW0DRGu9EHoqaB9JnkSWBkkrBewkTePeRL3eLRmUXrNJV4r8tuL20uq4QIDAQABo1YwVDAJBgNVHRMEAjAAMAsGA1UdDwQEAwIFoDAbBgNVHSUEFDASBgRVHSUABgorBgEEAYPoXgIBMB0GA1UdDgQWBBRVzemKLsqLTYmfYVynHKW2PD3UPTANBgkqhkiG9w0BAQsFAAOCAQEARgFgmk4rUx8xcZQsP7RS16/3tMZvPZ59M8yS+v7y/sHN8lim3jJBtBN0OE/rFQzzH93gkPo0slJzD28GqIV495GyJSi4iOsreGa2j9kqrVGcP8BXTJYYyN5mAHixRq7XgTpjQuJ+d9nFXJo9g3Yy4OrV/SIC1poXb++YX4hdDmwCmoSnutiJQJbGBw1lx2XHaQtrMZFtrsxRUbgOZhMKlaFyBXEJZs4V8oSOH24iiK/qIo2DNUwmOuZngJXfEFB1W8cRPu1gM25wX6uxUjo0Jf/j7ooBNrnC5HFj700RR5jYjau1W6ZilXK41nHo3BsIdmNZLPmwBWCp4zumt9XV4g==)"; |
| // This certificate is self-signed and it only has the C2PA claim signing EKU. |
| // The certificate is created by following the steps above for the |
| // `kSelfSignedCertNoEkuBase64` with the following change: |
| // 1. In the configuration file `cert.cnf`, add the line to the [ v3_ext ] |
| // section: |
| // extendedKeyUsage = 1.3.6.1.4.1.62558.2.1 |
| constexpr absl::string_view kSelfSignedCertWithC2paEkuBase64 = |
| R"(MIIDijCCAnKgAwIBAgIUbvfHtjDh0li8c7UsrlX+7HZANhkwDQYJKoZIhvcNAQELBQAwVjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk1BMRIwEAYDVQQHDAlDYW1icmlkZ2UxEjAQBgNVBAoMCVVuaXQgVGVzdDESMBAGA1UEAwwJVW5pdCBUZXN0MB4XDTI1MDgwOTE3NDUyNloXDTI2MDgwOTE3NDUyNlowVjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk1BMRIwEAYDVQQHDAlDYW1icmlkZ2UxEjAQBgNVBAoMCVVuaXQgVGVzdDESMBAGA1UEAwwJVW5pdCBUZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlohRQoQJeWRV1A6W70Xmaq+SV2ftqGIW+dj9u/JccI/1WI6sXk2hIJPp5LvKDoyiN3gA+cgaTIhiJ2BbnJzFkzAKZhV2KdQyD2OOHefgycRc18Rkg3zJlylubV7/O2kfZsZIwUByqPi/KlMtWwkLTnYDnZ8VvifKSvCVDLA1m6nkhkBCaVlHXEtlCIzYYcbYXX31HsrKpMhYBbRcGaqbWAkSLg3qyovwDyjEKVWRxswUYyfi4IJgB+Fld27YSSBslEHhH2WaTWLIInnNxkR/gzw3fMkNMJTH/l4jUsOR6Kl/9ofzJg371hPp7MKuY37JPyVOFi9l+jw0Gk41eakICwIDAQABo1AwTjAJBgNVHRMEAjAAMAsGA1UdDwQEAwIFoDAVBgNVHSUEDjAMBgorBgEEAYPoXgIBMB0GA1UdDgQWBBTBfCBm97Ba5p/5yjlhNqcesYD2VDANBgkqhkiG9w0BAQsFAAOCAQEAfBwfVUAXh6ZLEtWV4Nc9IqpL6hkF4HJhkPlxPVcUH6nsdBUkr9tGbEBtrg4FyqwbVfsAr6geZK/UZ/fT6iltwU8qQB0+LbT1wvjPgPgVapwMioh8whyNUOHuT3P1DtaJ/ma507Da2osdqk3n9+J+Gc7TUVupetfoDhOowgjhqI8oPrqIUki/arS7T6QfiNlHK0f1/l+nhLaaC4W84l+jCZn54GcZh39aw+I+oG/JhVG+k8bQ+6STG/WiPlXP9+2f8Ufh5U6srUkN0zQ3CEI+jpuvCH+Kco7CTcLjtWeDDOMyr/H7Sgy9gWN1UsdOTjIiJiqM2R9AGJ7Qki1ug8JwuA==)"; |
| // This certificate is self-signed and it has 109 EKU values. |
| // The certificate is created by following the steps above for the |
| // `kSelfSignedCertNoEkuBase64` with the following change: |
| // 1. In the configuration file `cert.cnf`, add the line to the [ v3_ext ] |
| // section: |
| // extendedKeyUsage = 1.3.6.1.4.1.62558.2.1, 1.3.6.1.4.1.62558.2.2, |
| // ..., 1.3.6.1.4.1.62558.2.109 |
| constexpr absl::string_view kSelfSignedCertWithLargeEkuBase64 = |
| R"(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)"; |
| // This certificate is self-signed. It has the C2PA claim signing EKU but does |
| // not assert the `digitalSignature` KU bit. The certificate is created by |
| // following the steps above for the `kSelfSignedCertNoEkuBase64` with the |
| // following changes: |
| // 1. In the configuration file `cert.cnf`, add the line to the [ v3_ext ] |
| // section: |
| // extendedKeyUsage = 1.3.6.1.4.1.62558.2.1 |
| // 2. In the same [v3_ext] section, update the line for the `keyUsage` extension |
| // as follows: |
| // keyUsage = keyEncipherment |
| constexpr absl::string_view kSelfSignedCertWithoutDigitalSignatureKuBase64 = |
| R"(MIIDijCCAnKgAwIBAgIULLgHRj+25oLuEWteEKtmNySP7SYwDQYJKoZIhvcNAQELBQAwVjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk1BMRIwEAYDVQQHDAlDYW1icmlkZ2UxEjAQBgNVBAoMCVVuaXQgVGVzdDESMBAGA1UEAwwJVW5pdCBUZXN0MB4XDTI1MDgxMTE1NTc1OVoXDTI2MDgxMTE1NTc1OVowVjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk1BMRIwEAYDVQQHDAlDYW1icmlkZ2UxEjAQBgNVBAoMCVVuaXQgVGVzdDESMBAGA1UEAwwJVW5pdCBUZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtTI0nTndMHK9cImhhfWaXa4k/6bHwyQk0S71ic+ieibdBFV4mzYbDPZ2u84Z80hFAlyet725PB8j9hJiaT8eG4Tacw19rUN1CimoMb7SJ9a1qshcmNqxNJcfLBmkntzdVwgwxqGtkS66LOCJ2SHqREkrzqBZMB8OCAsf/gbS5vgY/3b5h6Xcdw1B1aIoKtRz8A8y5IK1DZF/0vzs0IqWjXlr5A4znEmdV1p18tcnL920QWim/winTyFXOj/IO+IK8tF1atjbS1RZChmQnN0bGJbc/8hmH5qpy1qDS9qS8sHK2BKTphPpqE5Zjrrb5S+4HUFUQNGxZSve9ghd7vj08wIDAQABo1AwTjAJBgNVHRMEAjAAMAsGA1UdDwQEAwIFIDAVBgNVHSUEDjAMBgorBgEEAYPoXgIBMB0GA1UdDgQWBBQAJkqyo/wRZ7N+SfmmbE/9WOuZszANBgkqhkiG9w0BAQsFAAOCAQEAa15O9d799osT9m8DfS1acQ0PYlhqpgLeeWuKWk/5KkJbNr8nI6SIOmyzXZ/aTvrU+EDkDWVJG8QGN+hRN2J1zhWTJ5zefpkfkXvdUT8Io/TVDkDT/EBzFOC865+yTe9pxcTcS5RjXLC6hCn4Rt37haeBe+dmBESflUpJMql+lkXgIuzRc6U7atb3NcdC2biKSt1FgG07Z4UqjbmwkpwU9nkaoioGZ+qEWEThoKbCdBSeaINP94/QPBnZiJPx0gqqc6v++6gZ5wnYRA3DxT00+5v3WfGzscfq5t5J0hW1dqXWE8svOB/lNmo2Zjz17EO8tqUEeHZgoNeE72ZCTpbo3Q==)"; |
| |
| std::string Base64Decode(absl::string_view base64) { |
| std::string decoded; |
| CHECK(absl::Base64Unescape(base64, &decoded)); |
| return decoded; |
| } |
| |
| TEST(EkuVerifierTest, CheckLeafCertEku_EmptyCert) { |
| EXPECT_FALSE(EkuVerifier::CheckLeafCertEku("")); |
| } |
| |
| TEST(EkuVerifierTest, CheckLeafCertEku_MalformedCert) { |
| EXPECT_FALSE(EkuVerifier::CheckLeafCertEku("malformed cert")); |
| } |
| |
| TEST(EkuVerifierTest, CheckLeafCertEku_NoEku) { |
| EXPECT_FALSE( |
| EkuVerifier::CheckLeafCertEku(Base64Decode(kSelfSignedCertNoEkuBase64))); |
| } |
| |
| TEST(EkuVerifierTest, CheckLeafCertEku_C2paEkuAndAnyEku) { |
| EXPECT_FALSE(EkuVerifier::CheckLeafCertEku( |
| Base64Decode(kSelfSignedCertWithAnyEkuAndC2paEkuBase64))); |
| } |
| |
| TEST(EkuVerifierTest, CheckLeafCertEku_C2paEkuOnly) { |
| EXPECT_TRUE(EkuVerifier::CheckLeafCertEku( |
| Base64Decode(kSelfSignedCertWithC2paEkuBase64))); |
| } |
| |
| TEST(EkuVerifierTest, CheckLeafCertEku_LargeEku) { |
| EXPECT_FALSE(EkuVerifier::CheckLeafCertEku( |
| Base64Decode(kSelfSignedCertWithLargeEkuBase64))); |
| } |
| |
| TEST(EkuVerifierTest, CheckLeafCertEku_WithoutDigitalSignatureKu) { |
| EXPECT_FALSE(EkuVerifier::CheckLeafCertEku( |
| Base64Decode(kSelfSignedCertWithoutDigitalSignatureKuBase64))); |
| } |
| |
| } // namespace |
| } // namespace credentio |