@@ -14,34 +14,145 @@ extern "C" {
1414}
1515
1616
17- static bool cert_subject_matches (PCCERT_CONTEXT pCert, const wchar_t *expected )
17+ static std::vector<BYTE> nameinfo_from_blob (CERT_NAME_BLOB *name )
1818{
19- if (!pCert || !expected || !*expected) {
20- return true ;
19+ DWORD cb = 0 ;
20+ if (!CryptDecodeObjectEx (
21+ X509_ASN_ENCODING,
22+ X509_NAME,
23+ name->pbData ,
24+ name->cbData ,
25+ 0 ,
26+ nullptr ,
27+ nullptr ,
28+ &cb
29+ ) || cb == 0 ) {
30+ return {};
31+ }
32+
33+ std::vector<BYTE> buf (cb);
34+ if (!CryptDecodeObjectEx (
35+ X509_ASN_ENCODING,
36+ X509_NAME,
37+ name->pbData ,
38+ name->cbData ,
39+ 0 ,
40+ nullptr ,
41+ buf.data (),
42+ &cb
43+ )) {
44+ return {};
2145 }
46+ buf.resize (cb);
47+ return buf;
48+ }
2249
50+
51+ static std::vector<BYTE> nameinfo_from_name (const wchar_t *name)
52+ {
2353 DWORD encoded_size = 0 ;
2454
25- if (!CertStrToNameW (X509_ASN_ENCODING, expected , CERT_X500_NAME_STR,
55+ if (!CertStrToNameW (X509_ASN_ENCODING, name , CERT_X500_NAME_STR,
2656 nullptr , nullptr , &encoded_size, nullptr )) {
27- return false ;
57+ return {} ;
2858 }
2959
3060 std::vector<BYTE> encoded (encoded_size);
3161
32- if (!CertStrToNameW (X509_ASN_ENCODING, expected , CERT_X500_NAME_STR,
62+ if (!CertStrToNameW (X509_ASN_ENCODING, name , CERT_X500_NAME_STR,
3363 nullptr , encoded.data (), &encoded_size, nullptr )) {
34- return false ;
64+ return {} ;
3565 }
3666
3767 CERT_NAME_BLOB expected_name = {};
3868 expected_name.cbData = encoded_size;
3969 expected_name.pbData = encoded.data ();
4070
41- return CertCompareCertificateName (X509_ASN_ENCODING, &pCert->pCertInfo ->Subject , &expected_name);
71+ return nameinfo_from_blob (&expected_name);
72+ }
73+
74+
75+ static std::wstring read_rdn_attr (CERT_RDN_ATTR &attr) {
76+ DWORD cb = CertRDNValueToStrW (attr.dwValueType , &attr.Value , nullptr , 0 );
77+ if (cb > 1024 ) {
78+ return {};
79+ }
80+ std::wstring v (cb, L' \0 ' );
81+ v.resize (CertRDNValueToStrW (attr.dwValueType , &attr.Value , v.data (), cb));
82+ return v;
4283}
4384
4485
86+ static bool cert_subject_matches (PCCERT_CONTEXT pCert, const wchar_t *expected)
87+ {
88+ if (!pCert || !expected || !*expected) {
89+ return true ;
90+ }
91+
92+ auto expected_info_buf = nameinfo_from_name (expected);
93+ auto actual_info_buf = nameinfo_from_blob (&pCert->pCertInfo ->Subject );
94+
95+ if (expected_info_buf.empty () || actual_info_buf.empty ()) {
96+ return false ;
97+ }
98+
99+ const CERT_NAME_INFO *expected_info =
100+ reinterpret_cast <const CERT_NAME_INFO *>(expected_info_buf.data ());
101+ const CERT_NAME_INFO *actual_info =
102+ reinterpret_cast <const CERT_NAME_INFO *>(actual_info_buf.data ());
103+
104+ // Turn constraints into a vector of (oid, value) pairs.
105+ // Each pair must be present in the actual name.
106+ std::vector<std::pair<std::string, std::wstring>> expected_pairs;
107+ expected_pairs.reserve (8 );
108+
109+ for (DWORD i = 0 ; i < expected_info->cRDN ; ++i) {
110+ CERT_RDN &rdn = expected_info->rgRDN [i];
111+ for (DWORD j = 0 ; j < rdn.cRDNAttr ; ++j) {
112+ CERT_RDN_ATTR &attr = rdn.rgRDNAttr [j];
113+ if (!attr.pszObjId ) {
114+ return false ;
115+ }
116+
117+ auto v = read_rdn_attr (attr);
118+ if (!v.empty ()) {
119+ expected_pairs.emplace_back (std::string (attr.pszObjId ), std::move (v));
120+ }
121+ }
122+ }
123+
124+ // For each expected (OID, value), find an identical (OID, value) in the actual name.
125+ for (const auto &need : expected_pairs) {
126+ const std::string &oid = need.first ;
127+ const std::wstring &expect = need.second ;
128+
129+ bool found = false ;
130+
131+ for (DWORD i = 0 ; i < actual_info->cRDN && !found; ++i) {
132+ CERT_RDN &rdn = actual_info->rgRDN [i];
133+ for (DWORD j = 0 ; j < rdn.cRDNAttr ; ++j) {
134+ CERT_RDN_ATTR &attr = rdn.rgRDNAttr [j];
135+ if (!attr.pszObjId || oid != attr.pszObjId ) {
136+ continue ;
137+ }
138+
139+ auto v = read_rdn_attr (attr);
140+
141+ if (CompareStringOrdinal (v.c_str (), -1 , expect.c_str (), -1 , TRUE ) == CSTR_EQUAL) {
142+ found = true ;
143+ break ;
144+ }
145+ }
146+ }
147+
148+ if (!found) {
149+ return false ;
150+ }
151+ }
152+
153+ return true ;
154+ }
155+
45156static bool resolve_eku_to_oid_utf8 (const wchar_t *eku_in, std::string &oid_out) {
46157 oid_out.clear ();
47158 if (!eku_in || !*eku_in) {
0 commit comments