Author: cwittich
Date: Sat Dec 5 21:37:08 2009
New Revision: 44422
URL:
http://svn.reactos.org/svn/reactos?rev=44422&view=rev
Log:
sync crypt32 to wine 1.1.34
Modified:
trunk/reactos/dll/win32/crypt32/cert.c
trunk/reactos/dll/win32/crypt32/chain.c
trunk/reactos/dll/win32/crypt32/crl.c
trunk/reactos/dll/win32/crypt32/crypt32.spec
trunk/reactos/dll/win32/crypt32/decode.c
trunk/reactos/dll/win32/crypt32/encode.c
trunk/reactos/dll/win32/crypt32/oid.c
trunk/reactos/dll/win32/crypt32/rootstore.c
Modified: trunk/reactos/dll/win32/crypt32/cert.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/crypt32/cert.c?r…
==============================================================================
--- trunk/reactos/dll/win32/crypt32/cert.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/crypt32/cert.c [iso-8859-1] Sat Dec 5 21:37:08 2009
@@ -1829,6 +1829,92 @@
if (pName->rgRDN[i].rgRDNAttr[j].pszObjId && !strcmp(pszObjId,
pName->rgRDN[i].rgRDNAttr[j].pszObjId))
ret = &pName->rgRDN[i].rgRDNAttr[j];
+ return ret;
+}
+
+static BOOL find_matching_rdn_attr(DWORD dwFlags, const CERT_NAME_INFO *name,
+ const CERT_RDN_ATTR *attr)
+{
+ DWORD i, j;
+ BOOL match = FALSE;
+
+ for (i = 0; !match && i < name->cRDN; i++)
+ {
+ for (j = 0; j < name->rgRDN[i].cRDNAttr; j++)
+ {
+ if (!strcmp(name->rgRDN[i].rgRDNAttr[j].pszObjId,
+ attr->pszObjId) &&
+ name->rgRDN[i].rgRDNAttr[j].dwValueType ==
+ attr->dwValueType)
+ {
+ if (dwFlags & CERT_UNICODE_IS_RDN_ATTRS_FLAG)
+ {
+ LPCWSTR nameStr =
+ (LPCWSTR)name->rgRDN[i].rgRDNAttr[j].Value.pbData;
+ LPCWSTR attrStr = (LPCWSTR)attr->Value.pbData;
+
+ if (attr->Value.cbData !=
+ name->rgRDN[i].rgRDNAttr[j].Value.cbData)
+ match = FALSE;
+ else if (dwFlags & CERT_CASE_INSENSITIVE_IS_RDN_ATTRS_FLAG)
+ match = !strncmpiW(nameStr, attrStr,
+ attr->Value.cbData / sizeof(WCHAR));
+ else
+ match = !strncmpW(nameStr, attrStr,
+ attr->Value.cbData / sizeof(WCHAR));
+ TRACE("%s : %s => %d\n",
+ debugstr_wn(nameStr, attr->Value.cbData / sizeof(WCHAR)),
+ debugstr_wn(attrStr, attr->Value.cbData / sizeof(WCHAR)),
+ match);
+ }
+ else
+ {
+ LPCSTR nameStr =
+ (LPCSTR)name->rgRDN[i].rgRDNAttr[j].Value.pbData;
+ LPCSTR attrStr = (LPCSTR)attr->Value.pbData;
+
+ if (attr->Value.cbData !=
+ name->rgRDN[i].rgRDNAttr[j].Value.cbData)
+ match = FALSE;
+ else if (dwFlags & CERT_CASE_INSENSITIVE_IS_RDN_ATTRS_FLAG)
+ match = !strncasecmp(nameStr, attrStr,
+ attr->Value.cbData);
+ else
+ match = !strncmp(nameStr, attrStr, attr->Value.cbData);
+ TRACE("%s : %s => %d\n",
+ debugstr_an(nameStr, attr->Value.cbData),
+ debugstr_an(attrStr, attr->Value.cbData), match);
+ }
+ }
+ }
+ }
+ return match;
+}
+
+BOOL WINAPI CertIsRDNAttrsInCertificateName(DWORD dwCertEncodingType,
+ DWORD dwFlags, PCERT_NAME_BLOB pCertName, PCERT_RDN pRDN)
+{
+ CERT_NAME_INFO *name;
+ LPCSTR type;
+ DWORD size;
+ BOOL ret;
+
+ TRACE("(%08x, %08x, %p, %p)\n", dwCertEncodingType, dwFlags, pCertName,
+ pRDN);
+
+ type = dwFlags & CERT_UNICODE_IS_RDN_ATTRS_FLAG ? X509_UNICODE_NAME :
+ X509_NAME;
+ if ((ret = CryptDecodeObjectEx(dwCertEncodingType, type, pCertName->pbData,
+ pCertName->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &name, &size)))
+ {
+ DWORD i;
+
+ for (i = 0; ret && i < pRDN->cRDNAttr; i++)
+ ret = find_matching_rdn_attr(dwFlags, name, &pRDN->rgRDNAttr[i]);
+ if (!ret)
+ SetLastError(CRYPT_E_NO_MATCH);
+ LocalFree(name);
+ }
return ret;
}
Modified: trunk/reactos/dll/win32/crypt32/chain.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/crypt32/chain.c?…
==============================================================================
--- trunk/reactos/dll/win32/crypt32/chain.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/crypt32/chain.c [iso-8859-1] Sat Dec 5 21:37:08 2009
@@ -506,6 +506,41 @@
return validBasicConstraints;
}
+static BOOL domain_name_matches(LPCWSTR constraint, LPCWSTR name)
+{
+ BOOL match;
+
+ /* RFC 5280, section 4.2.1.10:
+ * "For URIs, the constraint applies to the host part of the name...
+ * When the constraint begins with a period, it MAY be expanded with one
+ * or more labels. That is, the constraint ".example.com" is satisfied
by
+ * both
host.example.com and
my.host.example.com. However, the constraint
+ * ".example.com" is not satisfied by "example.com". When the
constraint
+ * does not begin with a period, it specifies a host."
+ * and for email addresses,
+ * "To indicate all Internet mail addresses on a particular host, the
+ * constraint is specified as the host name. For example, the constraint
+ * "example.com" is satisfied by any mail address at the host
+ * "example.com". To specify any address within a domain, the constraint
+ * is specified with a leading period (as with URIs)."
+ */
+ if (constraint[0] == '.')
+ {
+ /* Must be strictly greater than, a name can't begin with '.' */
+ if (lstrlenW(name) > lstrlenW(constraint))
+ match = !lstrcmpiW(name + lstrlenW(name) - lstrlenW(constraint),
+ constraint);
+ else
+ {
+ /* name is too short, no match */
+ match = FALSE;
+ }
+ }
+ else
+ match = !lstrcmpiW(name, constraint);
+ return match;
+}
+
static BOOL url_matches(LPCWSTR constraint, LPCWSTR name,
DWORD *trustErrorStatus)
{
@@ -517,14 +552,58 @@
*trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS;
else if (!name)
; /* no match */
- else if (constraint[0] == '.')
- {
- if (lstrlenW(name) > lstrlenW(constraint))
- match = !lstrcmpiW(name + lstrlenW(name) - lstrlenW(constraint),
- constraint);
- }
else
- match = !lstrcmpiW(constraint, name);
+ {
+ LPCWSTR colon, authority_end, at, hostname = NULL;
+ /* The maximum length for a hostname is 254 in the DNS, see RFC 1034 */
+ WCHAR hostname_buf[255];
+
+ /* RFC 5280: only the hostname portion of the URL is compared. From
+ * section 4.2.1.10:
+ * "For URIs, the constraint applies to the host part of the name.
+ * The constraint MUST be specified as a fully qualified domain name
+ * and MAY specify a host or a domain."
+ * The format for URIs is in RFC 2396.
+ *
+ * First, remove any scheme that's present. */
+ colon = strchrW(name, ':');
+ if (colon && *(colon + 1) == '/' && *(colon + 2) ==
'/')
+ name = colon + 3;
+ /* Next, find the end of the authority component. (The authority is
+ * generally just the hostname, but it may contain a username or a port.
+ * Those are removed next.)
+ */
+ authority_end = strchrW(name, '/');
+ if (!authority_end)
+ authority_end = strchrW(name, '?');
+ if (!authority_end)
+ authority_end = name + strlenW(name);
+ /* Remove any port number from the authority */
+ for (colon = authority_end; colon >= name && *colon != ':';
colon--)
+ ;
+ if (*colon == ':')
+ authority_end = colon;
+ /* Remove any username from the authority */
+ if ((at = strchrW(name, '@')))
+ name = at;
+ /* Ignore any path or query portion of the URL. */
+ if (*authority_end)
+ {
+ if (authority_end - name < sizeof(hostname_buf) /
+ sizeof(hostname_buf[0]))
+ {
+ memcpy(hostname_buf, name,
+ (authority_end - name) * sizeof(WCHAR));
+ hostname_buf[authority_end - name] = 0;
+ hostname = hostname_buf;
+ }
+ /* else: Hostname is too long, not a match */
+ }
+ else
+ hostname = name;
+ if (hostname)
+ match = domain_name_matches(constraint, hostname);
+ }
return match;
}
@@ -545,7 +624,7 @@
else
{
if ((at = strchrW(name, '@')))
- match = url_matches(constraint, at + 1, trustErrorStatus);
+ match = domain_name_matches(constraint, at + 1);
else
match = !lstrcmpiW(constraint, name);
}
@@ -563,9 +642,35 @@
*trustErrorStatus |= CERT_TRUST_INVALID_NAME_CONSTRAINTS;
else if (!name)
; /* no match */
- else if (lstrlenW(name) >= lstrlenW(constraint))
+ /* RFC 5280, section 4.2.1.10:
+ * "DNS name restrictions are expressed as
host.example.com. Any DNS name
+ * that can be constructed by simply adding zero or more labels to the
+ * left-hand side of the name satisfies the name constraint. For example,
+ *
www.host.example.com would satisfy the constraint but
host1.example.com
+ * would not."
+ */
+ else if (lstrlenW(name) == lstrlenW(constraint))
+ match = !lstrcmpiW(name, constraint);
+ else if (lstrlenW(name) > lstrlenW(constraint))
+ {
match = !lstrcmpiW(name + lstrlenW(name) - lstrlenW(constraint),
constraint);
+ if (match)
+ {
+ BOOL dot = FALSE;
+ LPCWSTR ptr;
+
+ /* This only matches if name is a subdomain of constraint, i.e.
+ * there's a '.' between the beginning of the name and the
+ * matching portion of the name.
+ */
+ for (ptr = name + lstrlenW(name) - lstrlenW(constraint);
+ !dot && ptr >= name; ptr--)
+ if (*ptr == '.')
+ dot = TRUE;
+ match = dot;
+ }
+ }
/* else: name is too short, no match */
return match;
@@ -615,46 +720,95 @@
return match;
}
-static void CRYPT_FindMatchingNameEntry(const CERT_ALT_NAME_ENTRY *constraint,
- const CERT_ALT_NAME_INFO *subjectName, DWORD *trustErrorStatus,
- DWORD errorIfFound, DWORD errorIfNotFound)
+static BOOL directory_name_matches(const CERT_NAME_BLOB *constraint,
+ const CERT_NAME_BLOB *name)
+{
+ CERT_NAME_INFO *constraintName;
+ DWORD size;
+ BOOL match = FALSE;
+
+ if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_NAME, constraint->pbData,
+ constraint->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &constraintName,
&size))
+ {
+ DWORD i;
+
+ match = TRUE;
+ for (i = 0; match && i < constraintName->cRDN; i++)
+ match = CertIsRDNAttrsInCertificateName(X509_ASN_ENCODING,
+ CERT_CASE_INSENSITIVE_IS_RDN_ATTRS_FLAG,
+ (CERT_NAME_BLOB *)name, &constraintName->rgRDN[i]);
+ LocalFree(constraintName);
+ }
+ return match;
+}
+
+static BOOL alt_name_matches(const CERT_ALT_NAME_ENTRY *name,
+ const CERT_ALT_NAME_ENTRY *constraint, DWORD *trustErrorStatus, BOOL *present)
+{
+ BOOL match = FALSE;
+
+ if (name->dwAltNameChoice == constraint->dwAltNameChoice)
+ {
+ if (present)
+ *present = TRUE;
+ switch (constraint->dwAltNameChoice)
+ {
+ case CERT_ALT_NAME_RFC822_NAME:
+ match = rfc822_name_matches(constraint->u.pwszURL,
+ name->u.pwszURL, trustErrorStatus);
+ break;
+ case CERT_ALT_NAME_DNS_NAME:
+ match = dns_name_matches(constraint->u.pwszURL,
+ name->u.pwszURL, trustErrorStatus);
+ break;
+ case CERT_ALT_NAME_URL:
+ match = url_matches(constraint->u.pwszURL,
+ name->u.pwszURL, trustErrorStatus);
+ break;
+ case CERT_ALT_NAME_IP_ADDRESS:
+ match = ip_address_matches(&constraint->u.IPAddress,
+ &name->u.IPAddress, trustErrorStatus);
+ break;
+ case CERT_ALT_NAME_DIRECTORY_NAME:
+ match = directory_name_matches(&constraint->u.DirectoryName,
+ &name->u.DirectoryName);
+ break;
+ default:
+ ERR("name choice %d unsupported in this context\n",
+ constraint->dwAltNameChoice);
+ *trustErrorStatus |=
+ CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT;
+ }
+ }
+ else if (present)
+ *present = FALSE;
+ return match;
+}
+
+static BOOL alt_name_matches_excluded_name(const CERT_ALT_NAME_ENTRY *name,
+ const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus)
{
DWORD i;
BOOL match = FALSE;
- for (i = 0; i < subjectName->cAltEntry; i++)
- {
- if (subjectName->rgAltEntry[i].dwAltNameChoice ==
- constraint->dwAltNameChoice)
- {
- switch (constraint->dwAltNameChoice)
- {
- case CERT_ALT_NAME_RFC822_NAME:
- match = rfc822_name_matches(constraint->u.pwszURL,
- subjectName->rgAltEntry[i].u.pwszURL, trustErrorStatus);
- break;
- case CERT_ALT_NAME_DNS_NAME:
- match = dns_name_matches(constraint->u.pwszURL,
- subjectName->rgAltEntry[i].u.pwszURL, trustErrorStatus);
- break;
- case CERT_ALT_NAME_URL:
- match = url_matches(constraint->u.pwszURL,
- subjectName->rgAltEntry[i].u.pwszURL, trustErrorStatus);
- break;
- case CERT_ALT_NAME_IP_ADDRESS:
- match = ip_address_matches(&constraint->u.IPAddress,
- &subjectName->rgAltEntry[i].u.IPAddress, trustErrorStatus);
- break;
- case CERT_ALT_NAME_DIRECTORY_NAME:
- default:
- ERR("name choice %d unsupported in this context\n",
- constraint->dwAltNameChoice);
- *trustErrorStatus |=
- CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT;
- }
- }
- }
- *trustErrorStatus |= match ? errorIfFound : errorIfNotFound;
+ for (i = 0; !match && i < nameConstraints->cExcludedSubtree; i++)
+ match = alt_name_matches(name,
+ &nameConstraints->rgExcludedSubtree[i].Base, trustErrorStatus, NULL);
+ return match;
+}
+
+static BOOL alt_name_matches_permitted_name(const CERT_ALT_NAME_ENTRY *name,
+ const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus,
+ BOOL *present)
+{
+ DWORD i;
+ BOOL match = FALSE;
+
+ for (i = 0; !match && i < nameConstraints->cPermittedSubtree; i++)
+ match = alt_name_matches(name,
+ &nameConstraints->rgPermittedSubtree[i].Base, trustErrorStatus,
+ present);
+ return match;
}
static inline PCERT_EXTENSION get_subject_alt_name_ext(const CERT_INFO *cert)
@@ -669,55 +823,251 @@
return ext;
}
+static void compare_alt_name_with_constraints(const CERT_EXTENSION *altNameExt,
+ const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus)
+{
+ CERT_ALT_NAME_INFO *subjectAltName;
+ DWORD size;
+
+ if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ALTERNATE_NAME,
+ altNameExt->Value.pbData, altNameExt->Value.cbData,
+ CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
+ &subjectAltName, &size))
+ {
+ DWORD i;
+
+ for (i = 0; i < subjectAltName->cAltEntry; i++)
+ {
+ BOOL nameFormPresent;
+
+ /* A name constraint only applies if the name form is present.
+ * From RFC 5280, section 4.2.1.10:
+ * "Restrictions apply only when the specified name form is
+ * present. If no name of the type is in the certificate,
+ * the certificate is acceptable."
+ */
+ if (alt_name_matches_excluded_name(
+ &subjectAltName->rgAltEntry[i], nameConstraints,
+ trustErrorStatus))
+ {
+ TRACE_(chain)("subject alternate name form %d excluded\n",
+ subjectAltName->rgAltEntry[i].dwAltNameChoice);
+ *trustErrorStatus |=
+ CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT;
+ }
+ nameFormPresent = FALSE;
+ if (!alt_name_matches_permitted_name(
+ &subjectAltName->rgAltEntry[i], nameConstraints,
+ trustErrorStatus, &nameFormPresent) && nameFormPresent)
+ {
+ TRACE_(chain)("subject alternate name form %d not
permitted\n",
+ subjectAltName->rgAltEntry[i].dwAltNameChoice);
+ *trustErrorStatus |=
+ CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT;
+ }
+ }
+ LocalFree(subjectAltName);
+ }
+ else
+ *trustErrorStatus |=
+ CERT_TRUST_INVALID_EXTENSION | CERT_TRUST_INVALID_NAME_CONSTRAINTS;
+}
+
+static BOOL rfc822_attr_matches_excluded_name(const CERT_RDN_ATTR *attr,
+ const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus)
+{
+ DWORD i;
+ BOOL match = FALSE;
+
+ for (i = 0; !match && i < nameConstraints->cExcludedSubtree; i++)
+ {
+ const CERT_ALT_NAME_ENTRY *constraint =
+ &nameConstraints->rgExcludedSubtree[i].Base;
+
+ if (constraint->dwAltNameChoice == CERT_ALT_NAME_RFC822_NAME)
+ match = rfc822_name_matches(constraint->u.pwszRfc822Name,
+ (LPCWSTR)attr->Value.pbData, trustErrorStatus);
+ }
+ return match;
+}
+
+static BOOL rfc822_attr_matches_permitted_name(const CERT_RDN_ATTR *attr,
+ const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus,
+ BOOL *present)
+{
+ DWORD i;
+ BOOL match = FALSE;
+
+ for (i = 0; !match && i < nameConstraints->cPermittedSubtree; i++)
+ {
+ const CERT_ALT_NAME_ENTRY *constraint =
+ &nameConstraints->rgPermittedSubtree[i].Base;
+
+ if (constraint->dwAltNameChoice == CERT_ALT_NAME_RFC822_NAME)
+ {
+ *present = TRUE;
+ match = rfc822_name_matches(constraint->u.pwszRfc822Name,
+ (LPCWSTR)attr->Value.pbData, trustErrorStatus);
+ }
+ }
+ return match;
+}
+
+static void compare_subject_with_email_constraints(
+ const CERT_NAME_BLOB *subjectName,
+ const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus)
+{
+ CERT_NAME_INFO *name;
+ DWORD size;
+
+ if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_UNICODE_NAME,
+ subjectName->pbData, subjectName->cbData,
+ CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL, &name, &size))
+ {
+ DWORD i, j;
+
+ for (i = 0; i < name->cRDN; i++)
+ for (j = 0; j < name->rgRDN[i].cRDNAttr; j++)
+ if (!strcmp(name->rgRDN[i].rgRDNAttr[j].pszObjId,
+ szOID_RSA_emailAddr))
+ {
+ BOOL nameFormPresent;
+
+ /* A name constraint only applies if the name form is
+ * present. From RFC 5280, section 4.2.1.10:
+ * "Restrictions apply only when the specified name form is
+ * present. If no name of the type is in the certificate,
+ * the certificate is acceptable."
+ */
+ if (rfc822_attr_matches_excluded_name(
+ &name->rgRDN[i].rgRDNAttr[j], nameConstraints,
+ trustErrorStatus))
+ {
+ TRACE_(chain)(
+ "email address in subject name is excluded\n");
+ *trustErrorStatus |=
+ CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT;
+ }
+ nameFormPresent = FALSE;
+ if (!rfc822_attr_matches_permitted_name(
+ &name->rgRDN[i].rgRDNAttr[j], nameConstraints,
+ trustErrorStatus, &nameFormPresent) && nameFormPresent)
+ {
+ TRACE_(chain)(
+ "email address in subject name is not permitted\n");
+ *trustErrorStatus |=
+ CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT;
+ }
+ }
+ LocalFree(name);
+ }
+ else
+ *trustErrorStatus |=
+ CERT_TRUST_INVALID_EXTENSION | CERT_TRUST_INVALID_NAME_CONSTRAINTS;
+}
+
+static BOOL CRYPT_IsEmptyName(const CERT_NAME_BLOB *name)
+{
+ BOOL empty;
+
+ if (!name->cbData)
+ empty = TRUE;
+ else if (name->cbData == 2 && name->pbData[1] == 0)
+ {
+ /* An empty sequence is also empty */
+ empty = TRUE;
+ }
+ else
+ empty = FALSE;
+ return empty;
+}
+
+static void compare_subject_with_constraints(const CERT_NAME_BLOB *subjectName,
+ const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, DWORD *trustErrorStatus)
+{
+ BOOL hasEmailConstraint = FALSE;
+ DWORD i;
+
+ /* In general, a subject distinguished name only matches a directory name
+ * constraint. However, an exception exists for email addresses.
+ * From RFC 5280, section 4.2.1.6:
+ * "Legacy implementations exist where an electronic mail address is
+ * embedded in the subject distinguished name as an emailAddress
+ * attribute [RFC2985]."
+ * If an email address constraint exists, check that constraint separately.
+ */
+ for (i = 0; !hasEmailConstraint && i <
nameConstraints->cExcludedSubtree;
+ i++)
+ if (nameConstraints->rgExcludedSubtree[i].Base.dwAltNameChoice ==
+ CERT_ALT_NAME_RFC822_NAME)
+ hasEmailConstraint = TRUE;
+ for (i = 0; !hasEmailConstraint && i <
nameConstraints->cPermittedSubtree;
+ i++)
+ if (nameConstraints->rgPermittedSubtree[i].Base.dwAltNameChoice ==
+ CERT_ALT_NAME_RFC822_NAME)
+ hasEmailConstraint = TRUE;
+ if (hasEmailConstraint)
+ compare_subject_with_email_constraints(subjectName, nameConstraints,
+ trustErrorStatus);
+ for (i = 0; i < nameConstraints->cExcludedSubtree; i++)
+ {
+ CERT_ALT_NAME_ENTRY *constraint =
+ &nameConstraints->rgExcludedSubtree[i].Base;
+
+ if (constraint->dwAltNameChoice == CERT_ALT_NAME_DIRECTORY_NAME &&
+ directory_name_matches(&constraint->u.DirectoryName, subjectName))
+ {
+ TRACE_(chain)("subject name is excluded\n");
+ *trustErrorStatus |=
+ CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT;
+ }
+ }
+ /* RFC 5280, section 4.2.1.10:
+ * "Restrictions apply only when the specified name form is present.
+ * If no name of the type is in the certificate, the certificate is
+ * acceptable."
+ * An empty name can't have the name form present, so don't check it.
+ */
+ if (nameConstraints->cPermittedSubtree &&
!CRYPT_IsEmptyName(subjectName))
+ {
+ BOOL match = FALSE, hasDirectoryConstraint = FALSE;
+
+ for (i = 0; !match && i < nameConstraints->cPermittedSubtree; i++)
+ {
+ CERT_ALT_NAME_ENTRY *constraint =
+ &nameConstraints->rgPermittedSubtree[i].Base;
+
+ if (constraint->dwAltNameChoice == CERT_ALT_NAME_DIRECTORY_NAME)
+ {
+ hasDirectoryConstraint = TRUE;
+ match = directory_name_matches(&constraint->u.DirectoryName,
+ subjectName);
+ }
+ }
+ if (hasDirectoryConstraint && !match)
+ {
+ TRACE_(chain)("subject name is not permitted\n");
+ *trustErrorStatus |= CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT;
+ }
+ }
+}
+
static void CRYPT_CheckNameConstraints(
const CERT_NAME_CONSTRAINTS_INFO *nameConstraints, const CERT_INFO *cert,
DWORD *trustErrorStatus)
{
- /* If there aren't any existing constraints, don't bother checking */
- if (nameConstraints->cPermittedSubtree || nameConstraints->cExcludedSubtree)
- {
- CERT_EXTENSION *ext = get_subject_alt_name_ext(cert);
-
- if (ext)
- {
- CERT_ALT_NAME_INFO *subjectName;
- DWORD size;
-
- if (CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ALTERNATE_NAME,
- ext->Value.pbData, ext->Value.cbData,
- CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
- &subjectName, &size))
- {
- DWORD i;
-
- for (i = 0; i < nameConstraints->cExcludedSubtree; i++)
- CRYPT_FindMatchingNameEntry(
- &nameConstraints->rgExcludedSubtree[i].Base, subjectName,
- trustErrorStatus,
- CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT, 0);
- for (i = 0; i < nameConstraints->cPermittedSubtree; i++)
- CRYPT_FindMatchingNameEntry(
- &nameConstraints->rgPermittedSubtree[i].Base, subjectName,
- trustErrorStatus, 0,
- CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT);
- LocalFree(subjectName);
- }
- else
- *trustErrorStatus |=
- CERT_TRUST_INVALID_EXTENSION |
- CERT_TRUST_INVALID_NAME_CONSTRAINTS;
- }
- else
- {
- if (nameConstraints->cPermittedSubtree)
- *trustErrorStatus |=
- CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT |
- CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT;
- if (nameConstraints->cExcludedSubtree)
- *trustErrorStatus |=
- CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT;
- }
- }
+ CERT_EXTENSION *ext = get_subject_alt_name_ext(cert);
+
+ if (ext)
+ compare_alt_name_with_constraints(ext, nameConstraints,
+ trustErrorStatus);
+ /* Name constraints apply to the subject alternative name as well as the
+ * subject name. From RFC 5280, section 4.2.1.10:
+ * "Restrictions apply to the subject distinguished name and apply to
+ * subject alternative names."
+ */
+ compare_subject_with_constraints(&cert->Subject, nameConstraints,
+ trustErrorStatus);
}
/* Gets cert's name constraints, if any. Free with LocalFree. */
@@ -745,6 +1095,17 @@
DWORD i;
BOOL ret = TRUE;
+ /* Make sure at least one permitted or excluded subtree is present. From
+ * RFC 5280, section 4.2.1.10:
+ * "Conforming CAs MUST NOT issue certificates where name constraints is an
+ * empty sequence. That is, either the permittedSubtrees field or the
+ * excludedSubtrees MUST be present."
+ */
+ if (!info->cPermittedSubtree && !info->cExcludedSubtree)
+ {
+ WARN_(chain)("constraints contain no permitted nor excluded
subtree\n");
+ ret = FALSE;
+ }
/* Check that none of the constraints specifies a minimum or a maximum.
* See RFC 5280, section 4.2.1.10:
* "Within this profile, the minimum and maximum fields are not used with
@@ -815,8 +1176,16 @@
CRYPT_CheckNameConstraints(nameConstraints,
chain->rgpElement[j]->pCertContext->pCertInfo,
&errorStatus);
- chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
- errorStatus;
+ if (errorStatus)
+ {
+ chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
+ errorStatus;
+ CRYPT_CombineTrustStatus(&chain->TrustStatus,
+ &chain->rgpElement[i]->TrustStatus);
+ }
+ else
+ chain->rgpElement[i]->TrustStatus.dwInfoStatus |=
+ CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS;
}
}
}
@@ -1235,58 +1604,6 @@
return ret;
}
-static BOOL CRYPT_ExtendedKeyUsageValidForCA(PCCERT_CONTEXT cert)
-{
- PCERT_EXTENSION ext;
- BOOL ret;
-
- /* RFC 5280, section 4.2.1.12: "In general, this extension will only
- * appear in end entity certificates." And, "If a certificate contains
- * both a key usage extension and an extended key usage extension, then
- * both extensions MUST be processed independently and the certificate MUST
- * only be used for a purpose consistent with both extensions." This seems
- * to imply that it should be checked if present, and ignored if not.
- * Unfortunately some CAs, e.g. the Thawte SGC CA, don't include the code
- * signing extended key usage, whereas they do include the keyCertSign
- * key usage. Thus, when checking for a CA, we only require the
- * code signing extended key usage if the extended key usage is critical.
- */
- ext = CertFindExtension(szOID_ENHANCED_KEY_USAGE,
- cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
- if (ext && ext->fCritical)
- {
- CERT_ENHKEY_USAGE *usage;
- DWORD size;
-
- ret = CryptDecodeObjectEx(cert->dwCertEncodingType,
- X509_ENHANCED_KEY_USAGE, ext->Value.pbData, ext->Value.cbData,
- CRYPT_DECODE_ALLOC_FLAG, NULL, &usage, &size);
- if (ret)
- {
- DWORD i;
-
- /* Explicitly require the code signing extended key usage for a CA
- * with an extended key usage extension. That is, don't assume
- * a cert is allowed to be a CA if it specifies the
- * anyExtendedKeyUsage usage oid. See again RFC 5280, section
- * 4.2.1.12: "Applications that require the presence of a
- * particular purpose MAY reject certificates that include the
- * anyExtendedKeyUsage OID but not the particular OID expected for
- * the application."
- */
- ret = FALSE;
- for (i = 0; !ret && i < usage->cUsageIdentifier; i++)
- if (!strcmp(usage->rgpszUsageIdentifier[i],
- szOID_PKIX_KP_CODE_SIGNING))
- ret = TRUE;
- LocalFree(usage);
- }
- }
- else
- ret = TRUE;
- return ret;
-}
-
static BOOL CRYPT_CriticalExtensionsSupported(PCCERT_CONTEXT cert)
{
BOOL ret = TRUE;
@@ -1435,11 +1752,6 @@
isRoot, constraints.fCA, i))
chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
- if (i != 0)
- if (!CRYPT_ExtendedKeyUsageValidForCA(
- chain->rgpElement[i]->pCertContext))
- chain->rgpElement[i]->TrustStatus.dwErrorStatus |=
- CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
if (CRYPT_IsSimpleChainCyclic(chain))
{
/* If the chain is cyclic, then the path length constraints
@@ -1501,7 +1813,10 @@
subject->dwCertEncodingType, 0, CERT_FIND_CERT_ID, &id,
prevIssuer);
if (issuer)
+ {
+ TRACE_(chain)("issuer found by issuer/serial number\n");
*infoStatus = CERT_TRUST_HAS_EXACT_MATCH_ISSUER;
+ }
}
else if (info->KeyId.cbData)
{
@@ -1511,7 +1826,10 @@
subject->dwCertEncodingType, 0, CERT_FIND_CERT_ID, &id,
prevIssuer);
if (issuer)
+ {
+ TRACE_(chain)("issuer found by key id\n");
*infoStatus = CERT_TRUST_HAS_KEY_MATCH_ISSUER;
+ }
}
LocalFree(info);
}
@@ -1554,7 +1872,10 @@
subject->dwCertEncodingType, 0, CERT_FIND_CERT_ID, &id,
prevIssuer);
if (issuer)
+ {
+ TRACE_(chain)("issuer found by directory name\n");
*infoStatus = CERT_TRUST_HAS_EXACT_MATCH_ISSUER;
+ }
}
else
FIXME("no supported name type in authority key id2\n");
@@ -1567,7 +1888,10 @@
subject->dwCertEncodingType, 0, CERT_FIND_CERT_ID, &id,
prevIssuer);
if (issuer)
+ {
+ TRACE_(chain)("issuer found by key id\n");
*infoStatus = CERT_TRUST_HAS_KEY_MATCH_ISSUER;
+ }
}
LocalFree(info);
}
@@ -1577,6 +1901,7 @@
issuer = CertFindCertificateInStore(store,
subject->dwCertEncodingType, 0, CERT_FIND_SUBJECT_NAME,
&subject->pCertInfo->Issuer, prevIssuer);
+ TRACE_(chain)("issuer found by name\n");
*infoStatus = CERT_TRUST_HAS_NAME_MATCH_ISSUER;
}
return issuer;
@@ -2054,7 +2379,7 @@
if (cContext)
{
PCCERT_CONTEXT *contexts =
- CryptMemAlloc(cContext * sizeof(PCCERT_CONTEXT *));
+ CryptMemAlloc(cContext * sizeof(PCCERT_CONTEXT));
if (contexts)
{
@@ -2101,7 +2426,11 @@
case CRYPT_E_NO_REVOCATION_CHECK:
case CRYPT_E_NO_REVOCATION_DLL:
case CRYPT_E_NOT_IN_REVOCATION_DATABASE:
- error = CERT_TRUST_REVOCATION_STATUS_UNKNOWN;
+ /* If the revocation status is unknown, it's assumed to be
+ * offline too.
+ */
+ error = CERT_TRUST_REVOCATION_STATUS_UNKNOWN |
+ CERT_TRUST_IS_OFFLINE_REVOCATION;
break;
case CRYPT_E_REVOCATION_OFFLINE:
error = CERT_TRUST_IS_OFFLINE_REVOCATION;
@@ -2125,14 +2454,122 @@
}
}
+static void CRYPT_CheckUsages(PCERT_CHAIN_CONTEXT chain,
+ const CERT_CHAIN_PARA *pChainPara)
+{
+ if (pChainPara->cbSize >= sizeof(CERT_CHAIN_PARA_NO_EXTRA_FIELDS) &&
+ pChainPara->RequestedUsage.Usage.cUsageIdentifier)
+ {
+ PCCERT_CONTEXT endCert;
+ PCERT_EXTENSION ext;
+ BOOL validForUsage;
+
+ /* A chain, if created, always includes the end certificate */
+ endCert = chain->rgpChain[0]->rgpElement[0]->pCertContext;
+ /* The extended key usage extension specifies how a certificate's
+ * public key may be used. From RFC 5280, section 4.2.1.12:
+ * "This extension indicates one or more purposes for which the
+ * certified public key may be used, in addition to or in place of the
+ * basic purposes indicated in the key usage extension."
+ * If the extension is present, it only satisfies the requested usage
+ * if that usage is included in the extension:
+ * "If the extension is present, then the certificate MUST only be used
+ * for one of the purposes indicated."
+ * There is also the special anyExtendedKeyUsage OID, but it doesn't
+ * have to be respected:
+ * "Applications that require the presence of a particular purpose
+ * MAY reject certificates that include the anyExtendedKeyUsage OID
+ * but not the particular OID expected for the application."
+ * For now, I'm being more conservative and ignoring the presence of
+ * the anyExtendedKeyUsage OID.
+ */
+ if ((ext = CertFindExtension(szOID_ENHANCED_KEY_USAGE,
+ endCert->pCertInfo->cExtension, endCert->pCertInfo->rgExtension)))
+ {
+ const CERT_ENHKEY_USAGE *requestedUsage =
+ &pChainPara->RequestedUsage.Usage;
+ CERT_ENHKEY_USAGE *usage;
+ DWORD size;
+
+ if (CryptDecodeObjectEx(X509_ASN_ENCODING,
+ X509_ENHANCED_KEY_USAGE, ext->Value.pbData, ext->Value.cbData,
+ CRYPT_DECODE_ALLOC_FLAG, NULL, &usage, &size))
+ {
+ if (pChainPara->RequestedUsage.dwType == USAGE_MATCH_TYPE_AND)
+ {
+ DWORD i, j;
+
+ /* For AND matches, all usages must be present */
+ validForUsage = TRUE;
+ for (i = 0; validForUsage &&
+ i < requestedUsage->cUsageIdentifier; i++)
+ {
+ BOOL match = FALSE;
+
+ for (j = 0; !match && j < usage->cUsageIdentifier;
j++)
+ match = !strcmp(usage->rgpszUsageIdentifier[j],
+ requestedUsage->rgpszUsageIdentifier[i]);
+ if (!match)
+ validForUsage = FALSE;
+ }
+ }
+ else
+ {
+ DWORD i, j;
+
+ /* For OR matches, any matching usage suffices */
+ validForUsage = FALSE;
+ for (i = 0; !validForUsage &&
+ i < requestedUsage->cUsageIdentifier; i++)
+ {
+ for (j = 0; !validForUsage &&
+ j < usage->cUsageIdentifier; j++)
+ validForUsage =
+ !strcmp(usage->rgpszUsageIdentifier[j],
+ requestedUsage->rgpszUsageIdentifier[i]);
+ }
+ }
+ LocalFree(usage);
+ }
+ else
+ validForUsage = FALSE;
+ }
+ else
+ {
+ /* If the extension isn't present, any interpretation is valid:
+ * "Certificate using applications MAY require that the extended
+ * key usage extension be present and that a particular purpose
+ * be indicated in order for the certificate to be acceptable to
+ * that application."
+ * For now I'm being more conservative and disallowing it.
+ */
+ WARN_(chain)("requested usage from a certificate with no
usages\n");
+ validForUsage = FALSE;
+ }
+ if (!validForUsage)
+ {
+ chain->TrustStatus.dwErrorStatus |=
+ CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
+ chain->rgpChain[0]->rgpElement[0]->TrustStatus.dwErrorStatus |=
+ CERT_TRUST_IS_NOT_VALID_FOR_USAGE;
+ }
+ }
+ if (pChainPara->cbSize >= sizeof(CERT_CHAIN_PARA) &&
+ pChainPara->RequestedIssuancePolicy.Usage.cUsageIdentifier)
+ FIXME("unimplemented for RequestedIssuancePolicy\n");
+}
+
static void dump_usage_match(LPCSTR name, const CERT_USAGE_MATCH *usageMatch)
{
- DWORD i;
-
- TRACE_(chain)("%s: %s\n", name,
- usageMatch->dwType == USAGE_MATCH_TYPE_AND ? "AND" : "OR");
- for (i = 0; i < usageMatch->Usage.cUsageIdentifier; i++)
- TRACE_(chain)("%s\n", usageMatch->Usage.rgpszUsageIdentifier[i]);
+ if (usageMatch->Usage.cUsageIdentifier)
+ {
+ DWORD i;
+
+ TRACE_(chain)("%s: %s\n", name,
+ usageMatch->dwType == USAGE_MATCH_TYPE_AND ? "AND" :
"OR");
+ for (i = 0; i < usageMatch->Usage.cUsageIdentifier; i++)
+ TRACE_(chain)("%s\n",
usageMatch->Usage.rgpszUsageIdentifier[i]);
+ }
}
static void dump_chain_para(const CERT_CHAIN_PARA *pChainPara)
@@ -2201,7 +2638,9 @@
if (!(dwFlags & CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS))
CRYPT_FreeLowerQualityChains(chain);
pChain = (PCERT_CHAIN_CONTEXT)chain;
- CRYPT_VerifyChainRevocation(pChain, pTime, pChainPara, dwFlags);
+ if (!pChain->TrustStatus.dwErrorStatus)
+ CRYPT_VerifyChainRevocation(pChain, pTime, pChainPara, dwFlags);
+ CRYPT_CheckUsages(pChain, pChainPara);
if (ppChainContext)
*ppChainContext = pChain;
else
@@ -2378,8 +2817,8 @@
* in section 4.2.1.6:
* "Multiple name forms, and multiple instances of each name form,
* MAY be included."
- * It doesn't specify the behavior in such cases, but common usage is
- * to accept a certificate if any name matches.
+ * It doesn't specify the behavior in such cases, but both RFC 2818
+ * and RFC 2595 explicitly accept a certificate if any name matches.
*/
for (i = 0; !matches && i < subjectName->cAltEntry; i++)
{
Modified: trunk/reactos/dll/win32/crypt32/crl.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/crypt32/crl.c?re…
==============================================================================
--- trunk/reactos/dll/win32/crypt32/crl.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/crypt32/crl.c [iso-8859-1] Sat Dec 5 21:37:08 2009
@@ -19,10 +19,12 @@
#include <assert.h>
#include <stdarg.h>
+#define NONAMELESSUNION
#include "windef.h"
#include "winbase.h"
#include "wincrypt.h"
#include "wine/debug.h"
+#include "wine/unicode.h"
#include "crypt32_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(crypt);
@@ -113,7 +115,82 @@
PCCERT_CONTEXT issuer = pvPara;
ret = CertCompareCertificateName(issuer->dwCertEncodingType,
- &issuer->pCertInfo->Issuer,
&pCrlContext->pCrlInfo->Issuer);
+ &issuer->pCertInfo->Subject,
&pCrlContext->pCrlInfo->Issuer);
+ if (ret && (dwFlags & CRL_FIND_ISSUED_BY_SIGNATURE_FLAG))
+ ret = CryptVerifyCertificateSignatureEx(0,
+ issuer->dwCertEncodingType,
+ CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL, (void *)pCrlContext,
+ CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, (void *)issuer, 0, NULL);
+ if (ret && (dwFlags & CRL_FIND_ISSUED_BY_AKI_FLAG))
+ {
+ PCERT_EXTENSION ext = CertFindExtension(
+ szOID_AUTHORITY_KEY_IDENTIFIER2, pCrlContext->pCrlInfo->cExtension,
+ pCrlContext->pCrlInfo->rgExtension);
+
+ if (ext)
+ {
+ CERT_AUTHORITY_KEY_ID2_INFO *info;
+ DWORD size;
+
+ if ((ret = CryptDecodeObjectEx(X509_ASN_ENCODING,
+ X509_AUTHORITY_KEY_ID2, ext->Value.pbData, ext->Value.cbData,
+ CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
+ {
+ if (info->AuthorityCertIssuer.cAltEntry &&
+ info->AuthorityCertSerialNumber.cbData)
+ {
+ PCERT_ALT_NAME_ENTRY directoryName = NULL;
+ DWORD i;
+
+ for (i = 0; !directoryName &&
+ i < info->AuthorityCertIssuer.cAltEntry; i++)
+ if (info->AuthorityCertIssuer.rgAltEntry[i].
+ dwAltNameChoice == CERT_ALT_NAME_DIRECTORY_NAME)
+ directoryName =
+ &info->AuthorityCertIssuer.rgAltEntry[i];
+ if (directoryName)
+ {
+ ret = CertCompareCertificateName(
+ issuer->dwCertEncodingType,
+ &issuer->pCertInfo->Subject,
+ &directoryName->u.DirectoryName);
+ if (ret)
+ ret = CertCompareIntegerBlob(
+ &issuer->pCertInfo->SerialNumber,
+ &info->AuthorityCertSerialNumber);
+ }
+ else
+ {
+ FIXME("no supported name type in authority key
id2\n");
+ ret = FALSE;
+ }
+ }
+ else if (info->KeyId.cbData)
+ {
+ if ((ext = CertFindExtension(
+ szOID_SUBJECT_KEY_IDENTIFIER,
+ issuer->pCertInfo->cExtension,
+ issuer->pCertInfo->rgExtension)))
+ {
+ if (info->KeyId.cbData == ext->Value.cbData)
+ ret = !memcmp(info->KeyId.pbData,
+ ext->Value.pbData, info->KeyId.cbData);
+ else
+ ret = FALSE;
+ }
+ else
+ ret = FALSE;
+ }
+ else
+ {
+ FIXME("unsupported value for AKI extension\n");
+ ret = FALSE;
+ }
+ LocalFree(info);
+ }
+ }
+ /* else: a CRL without an AKI matches any cert */
+ }
}
else
ret = TRUE;
@@ -134,6 +211,17 @@
}
else
ret = TRUE;
+ return ret;
+}
+
+static BOOL compare_crl_issued_for(PCCRL_CONTEXT pCrlContext, DWORD dwType,
+ DWORD dwFlags, const void *pvPara)
+{
+ const CRL_FIND_ISSUED_FOR_PARA *para = pvPara;
+ BOOL ret;
+
+ ret = CertCompareCertificateName(para->pIssuerCert->dwCertEncodingType,
+ ¶->pIssuerCert->pCertInfo->Issuer,
&pCrlContext->pCrlInfo->Issuer);
return ret;
}
@@ -157,6 +245,9 @@
break;
case CRL_FIND_EXISTING:
compare = compare_crl_existing;
+ break;
+ case CRL_FIND_ISSUED_FOR:
+ compare = compare_crl_issued_for;
break;
default:
FIXME("find type %08x unimplemented\n", dwFindType);
@@ -467,11 +558,151 @@
return ret;
}
+static BOOL compare_dist_point_name(const CRL_DIST_POINT_NAME *name1,
+ const CRL_DIST_POINT_NAME *name2)
+{
+ BOOL match;
+
+ if (name1->dwDistPointNameChoice == name2->dwDistPointNameChoice)
+ {
+ match = TRUE;
+ if (name1->dwDistPointNameChoice == CRL_DIST_POINT_FULL_NAME)
+ {
+ if (name1->u.FullName.cAltEntry == name2->u.FullName.cAltEntry)
+ {
+ DWORD i;
+
+ for (i = 0; match && i < name1->u.FullName.cAltEntry; i++)
+ {
+ const CERT_ALT_NAME_ENTRY *entry1 =
+ &name1->u.FullName.rgAltEntry[i];
+ const CERT_ALT_NAME_ENTRY *entry2 =
+ &name2->u.FullName.rgAltEntry[i];
+
+ if (entry1->dwAltNameChoice == entry2->dwAltNameChoice)
+ {
+ switch (entry1->dwAltNameChoice)
+ {
+ case CERT_ALT_NAME_URL:
+ match = !strcmpiW(entry1->u.pwszURL,
+ entry2->u.pwszURL);
+ break;
+ case CERT_ALT_NAME_DIRECTORY_NAME:
+ match = (entry1->u.DirectoryName.cbData ==
+ entry2->u.DirectoryName.cbData) &&
+ !memcmp(entry1->u.DirectoryName.pbData,
+ entry2->u.DirectoryName.pbData,
+ entry1->u.DirectoryName.cbData);
+ break;
+ default:
+ FIXME("unimplemented for type %d\n",
+ entry1->dwAltNameChoice);
+ match = FALSE;
+ }
+ }
+ else
+ match = FALSE;
+ }
+ }
+ else
+ match = FALSE;
+ }
+ }
+ else
+ match = FALSE;
+ return match;
+}
+
+static BOOL match_dist_point_with_issuing_dist_point(
+ const CRL_DIST_POINT *distPoint, const CRL_ISSUING_DIST_POINT *idp)
+{
+ BOOL match;
+
+ /* While RFC 5280, section 4.2.1.13 recommends against segmenting
+ * CRL distribution points by reasons, it doesn't preclude doing so.
+ * "This profile RECOMMENDS against segmenting CRLs by reason code."
+ * If the issuing distribution point for this CRL is only valid for
+ * some reasons, only match if the reasons covered also match the
+ * reasons in the CRL distribution point.
+ */
+ if (idp->OnlySomeReasonFlags.cbData)
+ {
+ if (idp->OnlySomeReasonFlags.cbData == distPoint->ReasonFlags.cbData)
+ {
+ DWORD i;
+
+ match = TRUE;
+ for (i = 0; match && i < distPoint->ReasonFlags.cbData; i++)
+ if (idp->OnlySomeReasonFlags.pbData[i] !=
+ distPoint->ReasonFlags.pbData[i])
+ match = FALSE;
+ }
+ else
+ match = FALSE;
+ }
+ else
+ match = TRUE;
+ if (match)
+ match = compare_dist_point_name(&idp->DistPointName,
+ &distPoint->DistPointName);
+ return match;
+}
+
BOOL WINAPI CertIsValidCRLForCertificate(PCCERT_CONTEXT pCert,
PCCRL_CONTEXT pCrl, DWORD dwFlags, void *pvReserved)
{
+ PCERT_EXTENSION ext;
+ BOOL ret;
+
TRACE("(%p, %p, %08x, %p)\n", pCert, pCrl, dwFlags, pvReserved);
- return TRUE;
+
+ if (!pCert)
+ return TRUE;
+
+ if ((ext = CertFindExtension(szOID_ISSUING_DIST_POINT,
+ pCrl->pCrlInfo->cExtension, pCrl->pCrlInfo->rgExtension)))
+ {
+ CRL_ISSUING_DIST_POINT *idp;
+ DWORD size;
+
+ if ((ret = CryptDecodeObjectEx(pCrl->dwCertEncodingType,
+ X509_ISSUING_DIST_POINT, ext->Value.pbData, ext->Value.cbData,
+ CRYPT_DECODE_ALLOC_FLAG, NULL, &idp, &size)))
+ {
+ if ((ext = CertFindExtension(szOID_CRL_DIST_POINTS,
+ pCert->pCertInfo->cExtension, pCert->pCertInfo->rgExtension)))
+ {
+ CRL_DIST_POINTS_INFO *distPoints;
+
+ if ((ret = CryptDecodeObjectEx(pCert->dwCertEncodingType,
+ X509_CRL_DIST_POINTS, ext->Value.pbData, ext->Value.cbData,
+ CRYPT_DECODE_ALLOC_FLAG, NULL, &distPoints, &size)))
+ {
+ DWORD i;
+
+ ret = FALSE;
+ for (i = 0; !ret && i < distPoints->cDistPoint; i++)
+ ret = match_dist_point_with_issuing_dist_point(
+ &distPoints->rgDistPoint[i], idp);
+ if (!ret)
+ SetLastError(CRYPT_E_NO_MATCH);
+ LocalFree(distPoints);
+ }
+ }
+ else
+ {
+ /* no CRL dist points extension in cert, can't match the CRL
+ * (which has an issuing dist point extension)
+ */
+ ret = FALSE;
+ SetLastError(CRYPT_E_NO_MATCH);
+ }
+ LocalFree(idp);
+ }
+ }
+ else
+ ret = TRUE;
+ return ret;
}
static PCRL_ENTRY CRYPT_FindCertificateInCRL(PCERT_INFO cert, const CRL_INFO *crl)
Modified: trunk/reactos/dll/win32/crypt32/crypt32.spec
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/crypt32/crypt32.…
==============================================================================
--- trunk/reactos/dll/win32/crypt32/crypt32.spec [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/crypt32/crypt32.spec [iso-8859-1] Sat Dec 5 21:37:08 2009
@@ -66,7 +66,7 @@
@ stdcall CertGetStoreProperty(ptr long ptr ptr)
@ stdcall CertGetSubjectCertificateFromStore(ptr long ptr)
@ stdcall CertGetValidUsages(long ptr ptr ptr ptr)
-@ stub CertIsRDNAttrsInCertificateName
+@ stdcall CertIsRDNAttrsInCertificateName(long long ptr ptr)
@ stdcall CertIsValidCRLForCertificate(ptr ptr long ptr)
@ stdcall CertNameToStrA(long ptr long ptr long)
@ stdcall CertNameToStrW(long ptr long ptr long)
Modified: trunk/reactos/dll/win32/crypt32/decode.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/crypt32/decode.c…
==============================================================================
--- trunk/reactos/dll/win32/crypt32/decode.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/crypt32/decode.c [iso-8859-1] Sat Dec 5 21:37:08 2009
@@ -3106,43 +3106,6 @@
return ret;
}
-/* Like CRYPT_AsnDecodeIntegerInternal, but swaps the bytes */
-static BOOL CRYPT_AsnDecodeIntegerSwapBytes(const BYTE *pbEncoded,
- DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, DWORD *pcbStructInfo,
- DWORD *pcbDecoded)
-{
- BOOL ret;
-
- TRACE("(%p, %d, 0x%08x, %p, %d, %p)\n", pbEncoded, cbEncoded, dwFlags,
- pvStructInfo, *pcbStructInfo, pcbDecoded);
-
- /* Can't use the CRYPT_DECODE_NOCOPY_FLAG, because we modify the bytes in-
- * place.
- */
- ret = CRYPT_AsnDecodeIntegerInternal(pbEncoded, cbEncoded,
- dwFlags & ~CRYPT_DECODE_NOCOPY_FLAG, pvStructInfo, pcbStructInfo,
- pcbDecoded);
- if (ret && pvStructInfo)
- {
- CRYPT_DATA_BLOB *blob = pvStructInfo;
-
- if (blob->cbData)
- {
- DWORD i;
- BYTE temp;
-
- for (i = 0; i < blob->cbData / 2; i++)
- {
- temp = blob->pbData[i];
- blob->pbData[i] = blob->pbData[blob->cbData - i - 1];
- blob->pbData[blob->cbData - i - 1] = temp;
- }
- }
- }
- TRACE("returning %d (%08x)\n", ret, GetLastError());
- return ret;
-}
-
static BOOL WINAPI CRYPT_AsnDecodeAuthorityKeyId(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
@@ -3153,7 +3116,7 @@
{
struct AsnDecodeSequenceItem items[] = {
{ ASN_CONTEXT | 0, offsetof(CERT_AUTHORITY_KEY_ID_INFO, KeyId),
- CRYPT_AsnDecodeIntegerSwapBytes, sizeof(CRYPT_DATA_BLOB),
+ CRYPT_AsnDecodeOctetsInternal, sizeof(CRYPT_DATA_BLOB),
TRUE, TRUE, offsetof(CERT_AUTHORITY_KEY_ID_INFO, KeyId.pbData), 0 },
{ ASN_CONTEXT | ASN_CONSTRUCTOR| 1,
offsetof(CERT_AUTHORITY_KEY_ID_INFO, CertIssuer),
@@ -3188,7 +3151,7 @@
{
struct AsnDecodeSequenceItem items[] = {
{ ASN_CONTEXT | 0, offsetof(CERT_AUTHORITY_KEY_ID2_INFO, KeyId),
- CRYPT_AsnDecodeIntegerSwapBytes, sizeof(CRYPT_DATA_BLOB),
+ CRYPT_AsnDecodeOctetsInternal, sizeof(CRYPT_DATA_BLOB),
TRUE, TRUE, offsetof(CERT_AUTHORITY_KEY_ID2_INFO, KeyId.pbData), 0 },
{ ASN_CONTEXT | ASN_CONSTRUCTOR| 1,
offsetof(CERT_AUTHORITY_KEY_ID2_INFO, AuthorityCertIssuer),
Modified: trunk/reactos/dll/win32/crypt32/encode.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/crypt32/encode.c…
==============================================================================
--- trunk/reactos/dll/win32/crypt32/encode.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/crypt32/encode.c [iso-8859-1] Sat Dec 5 21:37:08 2009
@@ -2438,45 +2438,6 @@
return ret;
}
-static BOOL WINAPI CRYPT_AsnEncodeIntegerSwapBytes(DWORD dwCertEncodingType,
- LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
- PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
-{
- BOOL ret;
-
- __TRY
- {
- const CRYPT_DATA_BLOB *blob = pvStructInfo;
- CRYPT_DATA_BLOB newBlob = { blob->cbData, NULL };
-
- ret = TRUE;
- if (newBlob.cbData)
- {
- newBlob.pbData = CryptMemAlloc(newBlob.cbData);
- if (newBlob.pbData)
- {
- DWORD i;
-
- for (i = 0; i < newBlob.cbData; i++)
- newBlob.pbData[newBlob.cbData - i - 1] = blob->pbData[i];
- }
- else
- ret = FALSE;
- }
- if (ret)
- ret = CRYPT_AsnEncodeInteger(dwCertEncodingType, lpszStructType,
- &newBlob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
- CryptMemFree(newBlob.pbData);
- }
- __EXCEPT_PAGE_FAULT
- {
- SetLastError(STATUS_ACCESS_VIOLATION);
- ret = FALSE;
- }
- __ENDTRY
- return ret;
-}
-
static BOOL WINAPI CRYPT_AsnEncodeAuthorityKeyId(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
@@ -2495,7 +2456,7 @@
{
swapped[cSwapped].tag = ASN_CONTEXT | 0;
swapped[cSwapped].pvStructInfo = &info->KeyId;
- swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeIntegerSwapBytes;
+ swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeOctets;
items[cItem].pvStructInfo = &swapped[cSwapped];
items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
cSwapped++;
@@ -2626,7 +2587,7 @@
{
swapped[cSwapped].tag = ASN_CONTEXT | 0;
swapped[cSwapped].pvStructInfo = &info->KeyId;
- swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeIntegerSwapBytes;
+ swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeOctets;
items[cItem].pvStructInfo = &swapped[cSwapped];
items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
cSwapped++;
Modified: trunk/reactos/dll/win32/crypt32/oid.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/crypt32/oid.c?re…
==============================================================================
--- trunk/reactos/dll/win32/crypt32/oid.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/crypt32/oid.c [iso-8859-1] Sat Dec 5 21:37:08 2009
@@ -881,9 +881,11 @@
}
else
{
+ LPCWSTR nextStr = spotToRemove + lstrlenW(toRemove) + 1;
+
/* Copy remainder of string "left" */
- memmove(spotToRemove, spotToRemove + lstrlenW(toRemove) + 1,
- (len - (spotToRemove - multi)) * sizeof(WCHAR));
+ memmove(spotToRemove, nextStr,
+ (len - (nextStr - multi)) * sizeof(WCHAR));
}
ret = TRUE;
}
Modified: trunk/reactos/dll/win32/crypt32/rootstore.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/crypt32/rootstor…
==============================================================================
--- trunk/reactos/dll/win32/crypt32/rootstore.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/crypt32/rootstore.c [iso-8859-1] Sat Dec 5 21:37:08 2009
@@ -40,6 +40,9 @@
#include "winternl.h"
#include "wine/debug.h"
#include "crypt32_private.h"
+#ifdef __APPLE__
+#include <Security/Security.h>
+#endif
WINE_DEFAULT_DEBUG_CHANNEL(crypt);
@@ -713,6 +716,35 @@
DWORD i;
BOOL ret = FALSE;
+#ifdef __APPLE__
+ OSStatus status;
+ CFArrayRef rootCerts;
+
+ status = SecTrustCopyAnchorCertificates(&rootCerts);
+ if (status == noErr)
+ {
+ int i;
+ for (i = 0; i < CFArrayGetCount(rootCerts); i++)
+ {
+ SecCertificateRef cert =
(SecCertificateRef)CFArrayGetValueAtIndex(rootCerts, i);
+ CFDataRef certData;
+ if ((status = SecKeychainItemExport(cert, kSecFormatX509Cert, 0, NULL,
&certData)) == noErr)
+ {
+ if (CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
+ CFDataGetBytePtr(certData), CFDataGetLength(certData),
+ CERT_STORE_ADD_NEW, NULL))
+ ret = TRUE;
+ else
+ WARN("adding root cert %d failed: %08x\n", i,
GetLastError());
+ CFRelease(certData);
+ }
+ else
+ WARN("could not export certificate %d to X509 format:
0x%08x\n", i, (unsigned int)status);
+ }
+ CFRelease(rootCerts);
+ }
+#endif
+
for (i = 0; !ret &&
i < sizeof(CRYPT_knownLocations) / sizeof(CRYPT_knownLocations[0]);
i++)