diff --git a/ydb/core/protos/config.proto b/ydb/core/protos/config.proto index 6ae48cfafea1..0e2bba79e6fb 100644 --- a/ydb/core/protos/config.proto +++ b/ydb/core/protos/config.proto @@ -1777,8 +1777,15 @@ message TClientCertificateAuthorization { repeated string Suffixes = 3; } + // Matches subject alternative names (DNS) and Common Name (CN) in certificate + message TSubjectDns { + repeated string Values = 1; + repeated string Suffixes = 2; + } + message TClientCertificateDefinition { repeated TSubjectTerm SubjectTerms = 1; + optional TSubjectDns SubjectDns = 5; optional bool CanCheckNodeHostByCN = 2 [default = false]; repeated string MemberGroups = 3; optional bool RequireSameIssuer = 4 [default = true]; diff --git a/ydb/core/security/certificate_check/cert_auth_processor.cpp b/ydb/core/security/certificate_check/cert_auth_processor.cpp index f2effa29e9a7..f2275b35a441 100644 --- a/ydb/core/security/certificate_check/cert_auth_processor.cpp +++ b/ydb/core/security/certificate_check/cert_auth_processor.cpp @@ -1,6 +1,7 @@ #include "cert_auth_processor.h" #include +#include #include #include #include @@ -100,6 +101,56 @@ TVector> X509CertificateReader::ReadIssuerTerms(cons return ReadTerms(name); } +static void FreeList(GENERAL_NAMES* list) { + sk_GENERAL_NAME_pop_free(list, GENERAL_NAME_free); +} + +TVector X509CertificateReader::ReadSubjectDns(const X509Ptr& x509, const std::vector>& subjectTerms) { + TVector result; + // 1. Subject's common name (CN) must be a subject DNS name, so add it to DNS names of subject first + for (const auto& [k, v] : subjectTerms) { + if (k == "CN") { + result.emplace_back(v); + } + } + + using TGeneralNamesPtr = std::unique_ptr>; + TGeneralNamesPtr subjectAltNames((GENERAL_NAMES*)X509_get_ext_d2i(x509.get(), NID_subject_alt_name, NULL, NULL)); + if (!subjectAltNames) { + return result; + } + const int subjectAltNamesCount = sk_GENERAL_NAME_num(subjectAltNames.get()); + if (subjectAltNamesCount <= 0) { + return result; + } + + result.reserve(static_cast(subjectAltNamesCount) + result.size()); + // 2. Additionally find subject alternative names with type=DNS + for (int i = 0; i < subjectAltNamesCount; ++i) { + const GENERAL_NAME* name = sk_GENERAL_NAME_value(subjectAltNames.get(), i); + if (!name) { + continue; + } + if (name->type == GEN_DNS) { + const ASN1_STRING* value = name->d.dNSName; + if (!value) { + continue; + } + + const char* data = reinterpret_cast(ASN1_STRING_get0_data(value)); + if (!data) { + continue; + } + int size = ASN1_STRING_length(value); + if (size <= 0) { + continue; + } + result.emplace_back(data, static_cast(size)); + } + } + return result; +} + TString X509CertificateReader::GetFingerprint(const X509Ptr& x509) { static constexpr size_t FINGERPRINT_LENGTH = SHA_DIGEST_LENGTH; unsigned char fingerprint[FINGERPRINT_LENGTH]; @@ -109,14 +160,16 @@ TString X509CertificateReader::GetFingerprint(const X509Ptr& x509) { return HexEncode(fingerprint, FINGERPRINT_LENGTH); } -TCertificateAuthorizationParams::TCertificateAuthorizationParams(const TDN& dn, bool requireSameIssuer, const std::vector& groups) +TCertificateAuthorizationParams::TCertificateAuthorizationParams(const TDN& dn, const std::optional& subjectDns, bool requireSameIssuer, const std::vector& groups) : SubjectDn(dn) + , SubjectDns(subjectDns) , RequireSameIssuer(requireSameIssuer) , Groups(groups) {} -TCertificateAuthorizationParams::TCertificateAuthorizationParams(TDN&& dn, bool requireSameIssuer, std::vector&& groups) +TCertificateAuthorizationParams::TCertificateAuthorizationParams(TDN&& dn, std::optional&& subjectDns, bool requireSameIssuer, std::vector&& groups) : SubjectDn(std::move(dn)) + , SubjectDns(std::move(subjectDns)) , RequireSameIssuer(requireSameIssuer) , Groups(std::move(groups)) {} @@ -127,59 +180,44 @@ TCertificateAuthorizationParams::TDN& TCertificateAuthorizationParams::TDN::AddR } TCertificateAuthorizationParams::operator bool() const { - return SubjectDn; + return SubjectDn || SubjectDns; } -bool TCertificateAuthorizationParams::CheckSubject(const std::unordered_map>& subjectDescription) const { - bool isDescriptionMatched = false; - for (const auto& rdn: SubjectDn.RDNs) { - isDescriptionMatched = false; +bool TCertificateAuthorizationParams::CheckSubject(const std::unordered_map>& subjectDescription, const std::vector& subjectDns) const { + for (const TRDN& rdn: SubjectDn.RDNs) { auto fieldIt = subjectDescription.find(rdn.Attribute); if (fieldIt == subjectDescription.cend()) { - break; + return false; } const auto& attributeValues = fieldIt->second; - bool attributeMatched = false; - for (const auto& attributeValue : attributeValues) { - attributeMatched = false; - for (const auto& value: rdn.Values) { - if (value == attributeValue) { - attributeMatched = true; - break; - } - } - if (!attributeMatched) { - for (const auto& suffix: rdn.Suffixes) { - if (attributeValue.EndsWith(suffix)) { - attributeMatched = true; - break; - } - } - } - if (!attributeMatched) { + if (!rdn.Match(attributeValues)) { + return false; + } + } + + if (SubjectDns) { + bool dnsMatched = false; + for (const TString& dns : subjectDns) { + if (SubjectDns->Match(dns)) { + dnsMatched = true; break; } } - if (!attributeMatched) { - isDescriptionMatched = false; - break; + if (!dnsMatched) { + return false; } - isDescriptionMatched = true; } - if (isDescriptionMatched) { - return true; - } - return false; + return true; } TCertificateAuthorizationParams::TDN::operator bool() const { return !RDNs.empty(); } -TCertificateAuthorizationParams::TRDN::TRDN(const TString& Attribute) - :Attribute(Attribute) +TCertificateAuthorizationParams::TRDN::TRDN(const TString& attribute) + : Attribute(attribute) {} TCertificateAuthorizationParams::TRDN& TCertificateAuthorizationParams::TRDN::AddValue(const TString& val) @@ -194,4 +232,30 @@ TCertificateAuthorizationParams::TRDN& TCertificateAuthorizationParams::TRDN::Ad return *this; } +bool TCertificateAuthorizationParams::TRDN::Match(const TString& value) const +{ + for (const auto& v : Values) { + if (value == v) { + return true; + } + } + for (const auto& s : Suffixes) { + if (value.EndsWith(s)) { + return true; + } + } + + return false; +} + +bool TCertificateAuthorizationParams::TRDN::Match(const std::vector& values) const +{ + for (const auto& value : values) { + if (!Match(value)) { + return false; + } + } + return true; +} + } //namespace NKikimr { diff --git a/ydb/core/security/certificate_check/cert_auth_processor.h b/ydb/core/security/certificate_check/cert_auth_processor.h index 42ec4bf3981c..bcbc1bb7c8a1 100644 --- a/ydb/core/security/certificate_check/cert_auth_processor.h +++ b/ydb/core/security/certificate_check/cert_auth_processor.h @@ -15,9 +15,11 @@ struct TCertificateAuthorizationParams { TVector Values; TVector Suffixes; - TRDN(const TString& Attribute); + TRDN(const TString& attribute); TRDN& AddValue(const TString& val); TRDN& AddSuffix(const TString& suffix); + bool Match(const std::vector& values) const; + bool Match(const TString& value) const; }; struct TDN { @@ -27,11 +29,11 @@ struct TCertificateAuthorizationParams { operator bool () const; }; - TCertificateAuthorizationParams(const TDN& dn = TDN(), bool requireSameIssuer = true, const std::vector& groups = {}); - TCertificateAuthorizationParams(TDN&& dn, bool requireSameIssuer = true, std::vector&& groups = {}); + TCertificateAuthorizationParams(const TDN& dn = TDN(), const std::optional& subjectDns = std::nullopt, bool requireSameIssuer = true, const std::vector& groups = {}); + TCertificateAuthorizationParams(TDN&& dn, std::optional&& subjectDns, bool requireSameIssuer = true, std::vector&& groups = {}); operator bool () const; - bool CheckSubject(const std::unordered_map>& subjectDescription) const; + bool CheckSubject(const std::unordered_map>& subjectDescription, const std::vector& subjectDns) const; void SetSubjectDn(const TDN& subjectDn) { SubjectDn = subjectDn; } @@ -42,6 +44,7 @@ struct TCertificateAuthorizationParams { bool CanCheckNodeByAttributeCN = false; TDN SubjectDn; + std::optional SubjectDns; bool RequireSameIssuer = true; std::vector Groups; }; @@ -61,6 +64,7 @@ struct X509CertificateReader { static X509Ptr ReadCertAsPEM(const TStringBuf& cert); static TVector> ReadSubjectTerms(const X509Ptr& x509); + static TVector ReadSubjectDns(const X509Ptr& x509, const std::vector>& subjectTerms); static TVector> ReadAllSubjectTerms(const X509Ptr& x509); static TVector> ReadIssuerTerms(const X509Ptr& x509); static TString GetFingerprint(const X509Ptr& x509); diff --git a/ydb/core/security/certificate_check/cert_auth_utils.cpp b/ydb/core/security/certificate_check/cert_auth_utils.cpp index a310c197d2f0..82c380d9df50 100644 --- a/ydb/core/security/certificate_check/cert_auth_utils.cpp +++ b/ydb/core/security/certificate_check/cert_auth_utils.cpp @@ -17,7 +17,7 @@ namespace NKikimr { -std::vector GetCertificateAuthorizationParams(const NKikimrConfig::TClientCertificateAuthorization &clientCertificateAuth) { +std::vector GetCertificateAuthorizationParams(const NKikimrConfig::TClientCertificateAuthorization& clientCertificateAuth) { std::vector certAuthParams; certAuthParams.reserve(clientCertificateAuth.ClientCertificateDefinitionsSize()); @@ -33,9 +33,19 @@ std::vector GetCertificateAuthorizationParams(c } dn.AddRDN(std::move(rdn)); } - if (dn) { + std::optional subjectDns; + if (const auto& subjectDnsCfg = clientCertificateDefinition.GetSubjectDns(); subjectDnsCfg.ValuesSize() || subjectDnsCfg.SuffixesSize()) { + TCertificateAuthorizationParams::TRDN& dns = subjectDns.emplace(TString()); + for (const auto& value: subjectDnsCfg.GetValues()) { + dns.AddValue(value); + } + for (const auto& suffix: subjectDnsCfg.GetSuffixes()) { + dns.AddSuffix(suffix); + } + } + if (dn || subjectDns) { std::vector groups(clientCertificateDefinition.GetMemberGroups().cbegin(), clientCertificateDefinition.GetMemberGroups().cend()); - certAuthParams.emplace_back(std::move(dn), clientCertificateDefinition.GetRequireSameIssuer(), std::move(groups)); + certAuthParams.emplace_back(std::move(dn), std::move(subjectDns), clientCertificateDefinition.GetRequireSameIssuer(), std::move(groups)); } } @@ -130,8 +140,8 @@ int FillNameFromProps(X509_NAME* name, const TProps& props) { return 1; } - if (!props.Coutry.empty()) { - X509_NAME_add_entry_by_txt(name, SN_countryName, MBSTRING_ASC, (const unsigned char*)props.Coutry.c_str(), -1, -1, 0); + if (!props.Country.empty()) { + X509_NAME_add_entry_by_txt(name, SN_countryName, MBSTRING_ASC, (const unsigned char*)props.Country.c_str(), -1, -1, 0); } if (!props.State.empty()) { @@ -377,7 +387,7 @@ X509REQPtr GenerateRequest(PKeyPtr& pkey, const TProps& props) { return std::move(request); } -X509Ptr SingRequest(X509REQPtr& request, X509Ptr& rootCert, PKeyPtr& rootKey, const TProps& props) { +X509Ptr SignRequest(X509REQPtr& request, X509Ptr& rootCert, PKeyPtr& rootKey, const TProps& props) { auto* pktmp = X509_REQ_get0_pubkey(request.get()); // X509_REQ_get0_pubkey returns the key, that shouldn't freed CHECK(pktmp, "Error unpacking public key from request."); @@ -455,7 +465,7 @@ TCertAndKey GenerateSignedCert(const TCertAndKey& rootCA, const TProps& props) { auto rootCert = ReadCertAsPEM(rootCA.Certificate); auto rootKey = ReadPrivateKeyAsPEM(rootCA.PrivateKey); - auto cert = SingRequest(request, rootCert, rootKey, props); // NID_authority_key_identifier must see ca + auto cert = SignRequest(request, rootCert, rootKey, props); // NID_authority_key_identifier must see ca TCertAndKey result; result.Certificate = WriteAsPEM(cert); @@ -475,7 +485,7 @@ TProps TProps::AsCA() { TProps props; props.SecondsValid = 3*365 * 24 * 60 *60; // 3 years - props.Coutry = "RU"; + props.Country = "RU"; props.State = "MSK"; props.Location = "MSK"; props.Organization = "YA"; diff --git a/ydb/core/security/certificate_check/cert_auth_utils.h b/ydb/core/security/certificate_check/cert_auth_utils.h index 9bffa64093db..f76a94665029 100644 --- a/ydb/core/security/certificate_check/cert_auth_utils.h +++ b/ydb/core/security/certificate_check/cert_auth_utils.h @@ -22,7 +22,7 @@ struct TCertAndKey { struct TProps { long SecondsValid = 0; - std::string Coutry; // C + std::string Country; // C std::string State; // ST std::string Location; // L std::string Organization; // O diff --git a/ydb/core/security/certificate_check/cert_check.cpp b/ydb/core/security/certificate_check/cert_check.cpp index 18808760c350..85b6c928c27e 100644 --- a/ydb/core/security/certificate_check/cert_check.cpp +++ b/ydb/core/security/certificate_check/cert_check.cpp @@ -71,6 +71,7 @@ TCertificateChecker::TReadClientSubjectResult TCertificateChecker::ReadSubjectFr result.Error = { .Message = "Cannot extract subject from client certificate", .Retryable = false }; return result; } + result.SubjectDns = X509CertificateReader::ReadSubjectDns(pemCertificates.ClientCertX509, result.SubjectDn); return result; } @@ -84,14 +85,14 @@ TString TCertificateChecker::CreateUserSidFromSubjectDn(const std::vector>& subjectDn, const TCertificateAuthorizationParams& authParams) const { +TEvTicketParser::TError TCertificateChecker::CheckClientSubject(const TReadClientSubjectResult& subjectInfo, const TCertificateAuthorizationParams& authParams) const { std::unordered_map> subjectDescription; - for (const auto& [attribute, value] : subjectDn) { + for (const auto& [attribute, value] : subjectInfo.SubjectDn) { auto& attributeValues = subjectDescription[attribute]; attributeValues.push_back(value); } - if (!authParams.CheckSubject(subjectDescription)) { + if (!authParams.CheckSubject(subjectDescription, subjectInfo.SubjectDns)) { return { .Message = "Client certificate failed verification", .Retryable = false }; } return {}; @@ -128,7 +129,7 @@ TCertificateChecker::TCertificateCheckResult TCertificateChecker::CheckClientCer continue; } - auto checkClientSubjectError = CheckClientSubject(readClientSubjectResult.SubjectDn, authParams); + auto checkClientSubjectError = CheckClientSubject(readClientSubjectResult, authParams); if (!checkClientSubjectError.empty()) { continue; } diff --git a/ydb/core/security/certificate_check/cert_check.h b/ydb/core/security/certificate_check/cert_check.h index 7525cc0fb600..84cb978e32fc 100644 --- a/ydb/core/security/certificate_check/cert_check.h +++ b/ydb/core/security/certificate_check/cert_check.h @@ -27,6 +27,7 @@ class TCertificateChecker { struct TReadClientSubjectResult { std::vector> SubjectDn; + std::vector SubjectDns; // Subject alternative names, DNS TEvTicketParser::TError Error; }; @@ -47,7 +48,7 @@ class TCertificateChecker { TEvTicketParser::TError CheckIssuers(const TPemCertificates& pemCertificates) const; TReadClientSubjectResult ReadSubjectFromClientCertificate(const TPemCertificates& pemCertificates) const; TString CreateUserSidFromSubjectDn(const std::vector>& subjectDn) const; - TEvTicketParser::TError CheckClientSubject(const std::vector>& subjectDn, const TCertificateAuthorizationParams& authParams) const; + TEvTicketParser::TError CheckClientSubject(const TReadClientSubjectResult& subjectInfo, const TCertificateAuthorizationParams& authParams) const; TCertificateCheckResult DefaultCheckClientCertificate(const TPemCertificates& pemCertificates) const; TCertificateCheckResult CheckClientCertificate(const TPemCertificates& pemCertificates) const; TString GetDefaultGroup() const; diff --git a/ydb/core/security/certificate_check/cert_check_ut.cpp b/ydb/core/security/certificate_check/cert_check_ut.cpp new file mode 100644 index 000000000000..d9d1d48c0912 --- /dev/null +++ b/ydb/core/security/certificate_check/cert_check_ut.cpp @@ -0,0 +1,282 @@ +#include "cert_check.h" +#include "cert_auth_utils.h" + +#include + +#include +#include + +namespace NKikimr { + +TTempFile SaveToTempFile(const std::string& content, const char* prefix = "cert") { + TTempFile file = MakeTempName(nullptr, prefix); + TUnbufferedFileOutput(file.Name()).Write(content); + return file; +} + +Y_UNIT_TEST_SUITE(TCertificateCheckerTest) { + Y_UNIT_TEST(CheckSubjectDns) { + using TTestSubjectTerm = std::pair>; + struct TTestSubjectDnsData { + TString CommonName = "localhost"; + std::vector AltNames; + std::vector DnsValues; + std::vector DnsSuffixes; + std::optional SubjectTerm; // one is enough, because we test DNS now + bool CheckResult = false; + }; + + std::vector tests = { + { + .AltNames = { + "IP:1.2.3.4", + "DNS:other.name.net", + "DNS:node-1.cluster.net", + "DNS:*.cluster.net", + "DNS:balancer.cluster.net", + }, + .DnsSuffixes = { + ".cluster.net", + }, + .CheckResult = true, + }, + { + .AltNames = { + "IP:1.2.3.4", // not DNS + }, + .DnsValues = { + "1.2.3.4", + }, + .CheckResult = false, + }, + { + .CommonName = "the.only.name.net", // CN is also FQDN + .DnsValues = { + "the.only.name.net", + }, + .CheckResult = true, + }, + { + .CommonName = "the.only.name.net", // CN is also FQDN + .DnsSuffixes = { + ".name.net", + ".some.other.domain.net", + }, + .CheckResult = true, + }, + { + .CommonName = "", // no DNS in cert + .DnsSuffixes = { + ".cluster.net", + }, + .CheckResult = false, + }, + { + .CommonName = "", // no DNS in cert + .DnsValues = { + "node-1.cluster.net", + }, + .CheckResult = false, + }, + { + // Complex matching + .AltNames = { + "IP:1.2.3.4", + "DNS:other.name.net", + "DNS:node-1.cluster.net", + "DNS:*.cluster.net", + "DNS:balancer.cluster.net", + "DNS:my-host.us", + }, + .DnsValues = { + "hello.su", + "balancer.cluster.net", + }, + .DnsSuffixes = { + ".123.us", + ".cluster-0.net", + ".cluster-1.net", + }, + .CheckResult = true, + }, + { + // Complex matching + .AltNames = { + "IP:1.2.3.4", + "DNS:other.name.net", + "DNS:node-1.cluster.net", + "DNS:*.cluster.net", + "DNS:balancer.cluster.net", + "DNS:my-host.us", + }, + .DnsValues = { + "hello.su", + "no-name", + }, + .DnsSuffixes = { + ".123.us", + ".cluster-0.net", + ".cluster-1.net", + "my-host.us", + }, + .CheckResult = true, + }, + { + // Additional conditions + // No DNS + // Subject OK + .AltNames = { + "DNS:other.name.net", + "DNS:node-1.cluster.net", + "DNS:*.cluster.net", + "DNS:balancer.cluster.net", + }, + .SubjectTerm = TTestSubjectTerm{ + "L", + {"TLV", "MSK"}, + }, + .CheckResult = true, + }, + { + // Additional conditions + // No DNS + // Subject not OK + .AltNames = { + "DNS:other.name.net", + "DNS:node-1.cluster.net", + "DNS:*.cluster.net", + "DNS:balancer.cluster.net", + }, + .SubjectTerm = TTestSubjectTerm{ + "O", + {"Google", "Meta"}, + }, + .CheckResult = false, + }, + { + // Additional conditions + // DNS OK + // Subject OK + .AltNames = { + "DNS:other.name.net", + "DNS:node-1.cluster.net", + "DNS:*.cluster.net", + "DNS:balancer.cluster.net", + }, + .DnsValues = { + "node-1.cluster.net", + }, + .SubjectTerm = TTestSubjectTerm{ + "L", + {"TLV", "MSK"}, + }, + .CheckResult = true, + }, + { + // Additional conditions + // DNS not OK + // Subject OK + .AltNames = { + "DNS:other.name.net", + "DNS:node-1.cluster.net", + "DNS:*.cluster.net", + "DNS:balancer.cluster.net", + }, + .DnsSuffixes = { + ".my-cluster.net", + }, + .SubjectTerm = TTestSubjectTerm{ + "L", + {"TLV", "MSK"}, + }, + .CheckResult = false, + }, + { + // Additional conditions + // DNS not OK + // Subject not OK + .AltNames = { + "DNS:other.name.net", + "DNS:node-1.cluster.net", + "DNS:*.cluster.net", + "DNS:balancer.cluster.net", + }, + .DnsSuffixes = { + ".my-cluster.net", + }, + .SubjectTerm = TTestSubjectTerm{ + "O", + {"Google", "Meta"}, + }, + .CheckResult = false, + }, + { + // Additional conditions + // DNS OK + // Subject not OK + .AltNames = { + "DNS:other.name.net", + "DNS:node-1.cluster.net", + "DNS:*.cluster.net", + "DNS:balancer.cluster.net", + "DNS:balancer.my-cluster.net", + }, + .DnsSuffixes = { + ".my-cluster.net", + }, + .SubjectTerm = TTestSubjectTerm{ + "O", + {"Google", "Meta"}, + }, + .CheckResult = false, + }, + }; + + TCertAndKey ca = GenerateCA(TProps::AsCA()); + + for (size_t testNumber = 0; testNumber < tests.size(); ++testNumber) { + const TTestSubjectDnsData& test = tests[testNumber]; + TProps props = TProps::AsClientServer(); + props.CommonName = test.CommonName; + props.AltNames = test.AltNames; + TCertAndKey clientServer = GenerateSignedCert(ca, props); + VerifyCert(clientServer.Certificate, ca.Certificate); + + TCertificateAuthValues opts; + opts.Domain = "cert"; + TTempFile serverCert = SaveToTempFile(clientServer.Certificate); + opts.ServerCertificateFilePath = serverCert.Name(); + auto* defs = opts.ClientCertificateAuthorization.AddClientCertificateDefinitions(); + defs->AddMemberGroups("ClusterNodeGroup@cert"); + + if (!test.DnsValues.empty() || !test.DnsSuffixes.empty()) { + auto* dnsCondition = defs->MutableSubjectDns(); + for (const TString& v : test.DnsValues) { + dnsCondition->AddValues(v); + } + for (const TString& s : test.DnsSuffixes) { + dnsCondition->AddSuffixes(s); + } + } + if (test.SubjectTerm) { + auto* t = defs->AddSubjectTerms(); + t->SetShortName(test.SubjectTerm->first); + for (const TString& v : test.SubjectTerm->second) { + t->AddValues(v); + } + } + TCertificateChecker checker(opts); + + TCertificateChecker::TCertificateCheckResult result = checker.Check(TString(clientServer.Certificate)); + if (test.CheckResult) { + UNIT_ASSERT_C(result.Error.empty(), "Test number: " << testNumber << ". Error: " << result.Error); + UNIT_ASSERT_VALUES_EQUAL_C(result.Groups.size(), 1, "Test number: " << testNumber); + UNIT_ASSERT_VALUES_EQUAL_C(result.Groups[0], "ClusterNodeGroup@cert", "Test number: " << testNumber); + } else { + UNIT_ASSERT_C(!result.Error.empty(), "Test number: " << testNumber); + } + } + } +} + +} // namespace NKikimr diff --git a/ydb/core/security/certificate_check/cert_utils_ut.cpp b/ydb/core/security/certificate_check/cert_utils_ut.cpp index 583182da7360..9dfce0ebb59a 100644 --- a/ydb/core/security/certificate_check/cert_utils_ut.cpp +++ b/ydb/core/security/certificate_check/cert_utils_ut.cpp @@ -29,7 +29,7 @@ Y_UNIT_TEST_SUITE(TCertificateAuthUtilsTest) { .AddRDN(TCertificateAuthorizationParams::TRDN("O").AddValue("YA")) .AddRDN(TCertificateAuthorizationParams::TRDN("OU").AddValue("UtTest").AddValue("OtherUnit")) .AddRDN(TCertificateAuthorizationParams::TRDN("CN").AddValue("localhost").AddSuffix(".yandex.ru")); - TCertificateAuthorizationParams authParams(std::move(dn)); + TCertificateAuthorizationParams authParams(std::move(dn), std::nullopt); { std::unordered_map> subjectTerms; @@ -40,7 +40,7 @@ Y_UNIT_TEST_SUITE(TCertificateAuthUtilsTest) { subjectTerms["OU"].push_back("UtTest"); subjectTerms["CN"].push_back("localhost"); - UNIT_ASSERT(authParams.CheckSubject(subjectTerms)); + UNIT_ASSERT(authParams.CheckSubject(subjectTerms, {})); } { @@ -53,7 +53,7 @@ Y_UNIT_TEST_SUITE(TCertificateAuthUtilsTest) { subjectTerms["OU"].push_back("OtherUnit"); subjectTerms["CN"].push_back("localhost"); - UNIT_ASSERT(authParams.CheckSubject(subjectTerms)); + UNIT_ASSERT(authParams.CheckSubject(subjectTerms, {})); } { @@ -66,7 +66,7 @@ Y_UNIT_TEST_SUITE(TCertificateAuthUtilsTest) { subjectTerms["OU"].push_back("WrongUnit"); subjectTerms["CN"].push_back("localhost"); - UNIT_ASSERT(!authParams.CheckSubject(subjectTerms)); + UNIT_ASSERT(!authParams.CheckSubject(subjectTerms, {})); } { @@ -78,7 +78,7 @@ Y_UNIT_TEST_SUITE(TCertificateAuthUtilsTest) { subjectTerms["OU"].push_back("UtTest"); subjectTerms["CN"].push_back("test.yandex.ru"); - UNIT_ASSERT(authParams.CheckSubject(subjectTerms)); + UNIT_ASSERT(authParams.CheckSubject(subjectTerms, {})); } { @@ -91,7 +91,7 @@ Y_UNIT_TEST_SUITE(TCertificateAuthUtilsTest) { subjectTerms["CN"].push_back("test.yandex.ru"); subjectTerms["ELSE"].push_back("WhatEver"); - UNIT_ASSERT(authParams.CheckSubject(subjectTerms)); + UNIT_ASSERT(authParams.CheckSubject(subjectTerms, {})); } { @@ -103,7 +103,7 @@ Y_UNIT_TEST_SUITE(TCertificateAuthUtilsTest) { subjectTerms["OU"].push_back("UtTest"); subjectTerms["CN"].push_back("test.yandex.ru"); - UNIT_ASSERT(!authParams.CheckSubject(subjectTerms)); + UNIT_ASSERT(!authParams.CheckSubject(subjectTerms, {})); } { @@ -115,7 +115,7 @@ Y_UNIT_TEST_SUITE(TCertificateAuthUtilsTest) { subjectTerms["OU"].push_back("UtTest"); subjectTerms["CN"].push_back("test.not-yandex.ru"); - UNIT_ASSERT(!authParams.CheckSubject(subjectTerms)); + UNIT_ASSERT(!authParams.CheckSubject(subjectTerms, {})); } { @@ -127,7 +127,19 @@ Y_UNIT_TEST_SUITE(TCertificateAuthUtilsTest) { subjectTerms["OU"].push_back("UtTest"); subjectTerms["CN"].push_back("test.yandex.ru"); - UNIT_ASSERT(!authParams.CheckSubject(subjectTerms)); + UNIT_ASSERT(!authParams.CheckSubject(subjectTerms, {})); + } + + { + std::unordered_map> subjectTerms; + //subjectTerms["C"] = "RU"; + subjectTerms["ST"].push_back("MSK"); + subjectTerms["L"].push_back("MSK"); + subjectTerms["O"].push_back("YA"); + subjectTerms["OU"].push_back("UtTest"); + subjectTerms["CN"].push_back("test.yandex.ru"); + + UNIT_ASSERT(!authParams.CheckSubject(subjectTerms, {"test.yandex.ru"})); } } } diff --git a/ydb/core/security/certificate_check/ut/ya.make b/ydb/core/security/certificate_check/ut/ya.make index 228fa7162126..5e0c281d3093 100644 --- a/ydb/core/security/certificate_check/ut/ya.make +++ b/ydb/core/security/certificate_check/ut/ya.make @@ -13,6 +13,7 @@ PEERDIR( YQL_LAST_ABI_VERSION() SRCS( + cert_check_ut.cpp cert_utils_ut.cpp )