Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
7fa618aa
Commit
7fa618aa
authored
Oct 20, 2009
by
Juan Lang
Committed by
Alexandre Julliard
Oct 21, 2009
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
crypt32: Check key usage during chain validation.
parent
f2057592
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
114 additions
and
17 deletions
+114
-17
chain.c
dlls/crypt32/chain.c
+111
-14
chain.c
dlls/crypt32/tests/chain.c
+3
-3
No files found.
dlls/crypt32/chain.c
View file @
7fa618aa
...
...
@@ -815,6 +815,106 @@ static void dump_element(PCCERT_CONTEXT cert)
dump_extension
(
&
cert
->
pCertInfo
->
rgExtension
[
i
]);
}
static
void
trace_usage
(
const
CRYPT_BIT_BLOB
*
usage
)
{
#define trace_usage_bit(bits, bit) \
if ((bits) & (bit)) TRACE_(chain)("%s\n", #bit)
if
(
usage
->
cbData
)
{
trace_usage_bit
(
usage
->
pbData
[
0
],
CERT_DIGITAL_SIGNATURE_KEY_USAGE
);
trace_usage_bit
(
usage
->
pbData
[
0
],
CERT_NON_REPUDIATION_KEY_USAGE
);
trace_usage_bit
(
usage
->
pbData
[
0
],
CERT_KEY_ENCIPHERMENT_KEY_USAGE
);
trace_usage_bit
(
usage
->
pbData
[
0
],
CERT_DATA_ENCIPHERMENT_KEY_USAGE
);
trace_usage_bit
(
usage
->
pbData
[
0
],
CERT_KEY_AGREEMENT_KEY_USAGE
);
trace_usage_bit
(
usage
->
pbData
[
0
],
CERT_KEY_CERT_SIGN_KEY_USAGE
);
trace_usage_bit
(
usage
->
pbData
[
0
],
CERT_CRL_SIGN_KEY_USAGE
);
trace_usage_bit
(
usage
->
pbData
[
0
],
CERT_ENCIPHER_ONLY_KEY_USAGE
);
}
#undef trace_usage_bit
if
(
usage
->
cbData
>
1
&&
usage
->
pbData
[
1
]
&
CERT_DECIPHER_ONLY_KEY_USAGE
)
TRACE_
(
chain
)(
"CERT_DECIPHER_ONLY_KEY_USAGE
\n
"
);
}
static
BOOL
CRYPT_KeyUsageValid
(
PCCERT_CONTEXT
cert
,
BOOL
isRoot
,
BOOL
isCA
,
DWORD
index
)
{
PCERT_EXTENSION
ext
;
BOOL
ret
;
BYTE
usageBits
=
0
;
ext
=
CertFindExtension
(
szOID_KEY_USAGE
,
cert
->
pCertInfo
->
cExtension
,
cert
->
pCertInfo
->
rgExtension
);
if
(
ext
)
{
CRYPT_BIT_BLOB
usage
;
DWORD
size
=
sizeof
(
usage
);
ret
=
CryptDecodeObjectEx
(
cert
->
dwCertEncodingType
,
X509_BITS
,
ext
->
Value
.
pbData
,
ext
->
Value
.
cbData
,
CRYPT_DECODE_NOCOPY_FLAG
,
NULL
,
&
usage
,
&
size
);
if
(
!
ret
)
return
FALSE
;
else
if
(
usage
.
cbData
>
2
)
{
/* The key usage extension only defines 9 bits => no more than 2
* bytes are needed to encode all known usages.
*/
return
FALSE
;
}
else
{
/* The only bit relevant to chain validation is the keyCertSign
* bit, which is always in the least significant byte of the
* key usage bits.
*/
usageBits
=
usage
.
pbData
[
usage
.
cbData
-
1
];
if
(
TRACE_ON
(
chain
))
trace_usage
(
&
usage
);
}
}
if
(
isCA
)
{
if
(
!
ext
)
{
/* MS appears to violate RFC 3280, section 4.2.1.3 (Key Usage)
* here. Quoting the RFC:
* "This [key usage] extension MUST appear in certificates that
* contain public keys that are used to validate digital signatures
* on other public key certificates or CRLs."
* Most of the test chains' certs do not contain key usage
* extensions, yet are allowed to be CA certs. This appears to
* be common usage too: the root CA in a chain often does not have
* the key usage extension. We are a little more restrictive:
* root certs, which commonly do not have any extensions, are
* allowed to sign certificates without the key usage extension.
*/
WARN_
(
chain
)(
"no key usage extension on a CA cert
\n
"
);
ret
=
isRoot
;
}
else
{
if
(
!
(
usageBits
&
CERT_KEY_CERT_SIGN_KEY_USAGE
))
{
WARN_
(
chain
)(
"keyCertSign not asserted on a CA cert
\n
"
);
ret
=
FALSE
;
}
else
ret
=
TRUE
;
}
}
else
{
if
(
ext
&&
(
usageBits
&
CERT_KEY_CERT_SIGN_KEY_USAGE
))
{
WARN_
(
chain
)(
"keyCertSign asserted on a non-CA cert
\n
"
);
ret
=
FALSE
;
}
else
ret
=
TRUE
;
}
return
ret
;
}
static
BOOL
CRYPT_CriticalExtensionsSupported
(
PCCERT_CONTEXT
cert
)
{
BOOL
ret
=
TRUE
;
...
...
@@ -833,13 +933,7 @@ static BOOL CRYPT_CriticalExtensionsSupported(PCCERT_CONTEXT cert)
else
if
(
!
strcmp
(
oid
,
szOID_NAME_CONSTRAINTS
))
ret
=
TRUE
;
else
if
(
!
strcmp
(
oid
,
szOID_KEY_USAGE
))
{
static
int
warned
;
if
(
!
warned
++
)
FIXME
(
"key usage extension unsupported, ignoring
\n
"
);
ret
=
TRUE
;
}
else
if
(
!
strcmp
(
oid
,
szOID_SUBJECT_ALT_NAME
))
ret
=
TRUE
;
else
...
...
@@ -865,21 +959,21 @@ static void CRYPT_CheckSimpleChain(PCertificateChainEngine engine,
chain
->
cElement
,
debugstr_w
(
filetime_to_str
(
time
)));
for
(
i
=
chain
->
cElement
-
1
;
i
>=
0
;
i
--
)
{
BOOL
isRoot
;
if
(
TRACE_ON
(
chain
))
dump_element
(
chain
->
rgpElement
[
i
]
->
pCertContext
);
if
(
CertVerifyTimeValidity
(
time
,
chain
->
rgpElement
[
i
]
->
pCertContext
->
pCertInfo
)
!=
0
)
chain
->
rgpElement
[
i
]
->
TrustStatus
.
dwErrorStatus
|=
CERT_TRUST_IS_NOT_TIME_VALID
;
if
(
i
==
chain
->
cElement
-
1
)
isRoot
=
CRYPT_IsCertificateSelfSigned
(
chain
->
rgpElement
[
i
]
->
pCertContext
);
else
isRoot
=
FALSE
;
if
(
i
!=
0
)
{
BOOL
isRoot
;
if
(
i
==
chain
->
cElement
-
1
)
isRoot
=
CRYPT_IsCertificateSelfSigned
(
chain
->
rgpElement
[
i
]
->
pCertContext
);
else
isRoot
=
FALSE
;
/* Check the signature of the cert this issued */
if
(
!
CryptVerifyCertificateSignatureEx
(
0
,
X509_ASN_ENCODING
,
CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT
,
...
...
@@ -914,6 +1008,10 @@ static void CRYPT_CheckSimpleChain(PCertificateChainEngine engine,
chain
->
rgpElement
[
i
]
->
TrustStatus
.
dwErrorStatus
|=
CERT_TRUST_INVALID_BASIC_CONSTRAINTS
;
}
if
(
!
CRYPT_KeyUsageValid
(
chain
->
rgpElement
[
i
]
->
pCertContext
,
isRoot
,
constraints
.
fCA
,
i
))
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
...
...
@@ -924,7 +1022,6 @@ static void CRYPT_CheckSimpleChain(PCertificateChainEngine engine,
CERT_TRUST_IS_PARTIAL_CHAIN
|
CERT_TRUST_INVALID_BASIC_CONSTRAINTS
;
}
/* FIXME: check valid usages */
/* Check whether every critical extension is supported */
if
(
!
CRYPT_CriticalExtensionsSupported
(
chain
->
rgpElement
[
i
]
->
pCertContext
))
...
...
dlls/crypt32/tests/chain.c
View file @
7fa618aa
...
...
@@ -1782,7 +1782,7 @@ static ChainCheck chainCheck[] = {
{
{
CERT_TRUST_IS_NOT_TIME_NESTED
,
CERT_TRUST_HAS_PREFERRED_ISSUER
},
{
CERT_TRUST_IS_UNTRUSTED_ROOT
|
CERT_TRUST_IS_NOT_VALID_FOR_USAGE
,
0
},
1
,
simpleStatus15
},
TODO_ERROR
},
0
},
/* Windows XP incorrectly does not complain that the end cert's key usage is
* invalid, so ignore that error.
*/
...
...
@@ -1791,7 +1791,7 @@ static ChainCheck chainCheck[] = {
CERT_TRUST_HAS_PREFERRED_ISSUER
},
{
CERT_TRUST_IS_UNTRUSTED_ROOT
|
CERT_TRUST_IS_NOT_VALID_FOR_USAGE
,
0
},
1
,
simpleStatus16
},
TODO_ERROR
},
0
},
{
{
sizeof
(
chain17
)
/
sizeof
(
chain17
[
0
]),
chain17
},
{
{
CERT_TRUST_IS_NOT_TIME_NESTED
,
CERT_TRUST_HAS_PREFERRED_ISSUER
},
{
CERT_TRUST_IS_UNTRUSTED_ROOT
,
0
},
1
,
simpleStatus17
},
...
...
@@ -1800,7 +1800,7 @@ static ChainCheck chainCheck[] = {
{
{
CERT_TRUST_IS_NOT_TIME_NESTED
,
CERT_TRUST_HAS_PREFERRED_ISSUER
},
{
CERT_TRUST_IS_UNTRUSTED_ROOT
|
CERT_TRUST_IS_NOT_VALID_FOR_USAGE
,
0
},
1
,
simpleStatus18
},
TODO_ERROR
},
0
},
{
{
sizeof
(
selfSignedChain
)
/
sizeof
(
selfSignedChain
[
0
]),
selfSignedChain
},
{
{
0
,
CERT_TRUST_HAS_PREFERRED_ISSUER
},
{
CERT_TRUST_IS_NOT_TIME_VALID
|
CERT_TRUST_IS_UNTRUSTED_ROOT
,
0
},
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment