blob: 328795f59540aee6bab85387bc71d14409e69cbb [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/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