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
9a58b308
Commit
9a58b308
authored
Aug 14, 2007
by
Juan Lang
Committed by
Alexandre Julliard
Aug 15, 2007
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
crypt32: Initial implementation of CertGetCertificateChain and CertFreeCertificateChain.
parent
51651c7c
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
294 additions
and
15 deletions
+294
-15
chain.c
dlls/crypt32/chain.c
+294
-6
chain.c
dlls/crypt32/tests/chain.c
+0
-9
No files found.
dlls/crypt32/chain.c
View file @
9a58b308
...
...
@@ -25,6 +25,8 @@
WINE_DEFAULT_DEBUG_CHANNEL
(
crypt
);
static
HCERTCHAINENGINE
CRYPT_defaultChainEngine
;
/* This represents a subset of a certificate chain engine: it doesn't include
* the "hOther" store described by MSDN, because I'm not sure how that's used.
* It also doesn't include the "hTrust" store, because I don't yet implement
...
...
@@ -171,22 +173,308 @@ void WINAPI CertFreeCertificateChainEngine(HCERTCHAINENGINE hChainEngine)
}
}
static
HCERTCHAINENGINE
CRYPT_GetDefaultChainEngine
(
void
)
{
if
(
!
CRYPT_defaultChainEngine
)
{
CERT_CHAIN_ENGINE_CONFIG
config
=
{
0
};
HCERTCHAINENGINE
engine
;
config
.
cbSize
=
sizeof
(
config
);
CertCreateCertificateChainEngine
(
&
config
,
&
engine
);
InterlockedCompareExchangePointer
(
&
CRYPT_defaultChainEngine
,
engine
,
NULL
);
if
(
CRYPT_defaultChainEngine
!=
engine
)
CertFreeCertificateChainEngine
(
engine
);
}
return
CRYPT_defaultChainEngine
;
}
void
default_chain_engine_free
(
void
)
{
CertFreeCertificateChainEngine
(
CRYPT_defaultChainEngine
);
}
typedef
struct
_CertificateChain
{
CERT_CHAIN_CONTEXT
context
;
LONG
ref
;
}
CertificateChain
,
*
PCertificateChain
;
static
inline
BOOL
WINAPI
CRYPT_IsCertificateSelfSigned
(
PCCERT_CONTEXT
cert
)
{
return
CertCompareCertificateName
(
cert
->
dwCertEncodingType
,
&
cert
->
pCertInfo
->
Subject
,
&
cert
->
pCertInfo
->
Issuer
);
}
/* Gets cert's issuer from store, and returns the validity flags associated
* with it. Returns NULL if no issuer whose public key matches cert's
* signature could be found.
*/
static
PCCERT_CONTEXT
CRYPT_GetIssuerFromStore
(
HCERTSTORE
store
,
PCCERT_CONTEXT
cert
,
PDWORD
pdwFlags
)
{
PCCERT_CONTEXT
issuer
=
NULL
;
/* There might be more than issuer with the same name, so keep looking until
* one produces the correct signature for this cert.
*/
do
{
*
pdwFlags
=
CERT_STORE_REVOCATION_FLAG
|
CERT_STORE_SIGNATURE_FLAG
|
CERT_STORE_TIME_VALIDITY_FLAG
;
issuer
=
CertGetIssuerCertificateFromStore
(
store
,
cert
,
issuer
,
pdwFlags
);
}
while
(
issuer
&&
(
*
pdwFlags
&
CERT_STORE_SIGNATURE_FLAG
));
return
issuer
;
}
static
BOOL
CRYPT_AddCertToSimpleChain
(
PCERT_SIMPLE_CHAIN
chain
,
PCCERT_CONTEXT
cert
,
DWORD
dwFlags
)
{
BOOL
ret
=
FALSE
;
PCERT_CHAIN_ELEMENT
element
=
CryptMemAlloc
(
sizeof
(
CERT_CHAIN_ELEMENT
));
if
(
element
)
{
if
(
!
chain
->
cElement
)
chain
->
rgpElement
=
CryptMemAlloc
(
sizeof
(
PCERT_CHAIN_ELEMENT
));
else
chain
->
rgpElement
=
CryptMemRealloc
(
chain
->
rgpElement
,
(
chain
->
cElement
+
1
)
*
sizeof
(
PCERT_CHAIN_ELEMENT
));
if
(
chain
->
rgpElement
)
{
memset
(
element
,
0
,
sizeof
(
CERT_CHAIN_ELEMENT
));
element
->
cbSize
=
sizeof
(
CERT_CHAIN_ELEMENT
);
element
->
pCertContext
=
cert
;
if
(
dwFlags
&
CERT_STORE_REVOCATION_FLAG
&&
!
(
dwFlags
&
CERT_STORE_NO_CRL_FLAG
))
element
->
TrustStatus
.
dwErrorStatus
|=
CERT_TRUST_IS_REVOKED
;
if
(
dwFlags
&
CERT_STORE_SIGNATURE_FLAG
)
element
->
TrustStatus
.
dwErrorStatus
|=
CERT_TRUST_IS_NOT_SIGNATURE_VALID
;
if
(
dwFlags
&
CERT_STORE_TIME_VALIDITY_FLAG
)
element
->
TrustStatus
.
dwErrorStatus
|=
CERT_TRUST_IS_NOT_TIME_VALID
;
/* It appears, from every example certificate chain I've found,
* that this flag is always set:
*/
element
->
TrustStatus
.
dwInfoStatus
=
CERT_TRUST_HAS_PREFERRED_ISSUER
;
if
(
chain
->
cElement
)
{
PCERT_CHAIN_ELEMENT
prevElement
=
chain
->
rgpElement
[
chain
->
cElement
-
1
];
/* This cert is the issuer of the previous one in the chain, so
* retroactively check the previous one's time validity nesting.
*/
if
(
!
CertVerifyValidityNesting
(
prevElement
->
pCertContext
->
pCertInfo
,
cert
->
pCertInfo
))
prevElement
->
TrustStatus
.
dwErrorStatus
|=
CERT_TRUST_IS_NOT_TIME_NESTED
;
}
/* FIXME: check valid usages, name constraints, and for cycles */
/* FIXME: initialize the rest of element */
chain
->
TrustStatus
.
dwErrorStatus
|=
element
->
TrustStatus
.
dwErrorStatus
;
chain
->
TrustStatus
.
dwInfoStatus
|=
element
->
TrustStatus
.
dwInfoStatus
;
chain
->
rgpElement
[
chain
->
cElement
++
]
=
element
;
ret
=
TRUE
;
}
else
CryptMemFree
(
element
);
}
return
ret
;
}
static
void
CRYPT_FreeSimpleChain
(
PCERT_SIMPLE_CHAIN
chain
)
{
DWORD
i
;
for
(
i
=
0
;
i
<
chain
->
cElement
;
i
++
)
CryptMemFree
(
chain
->
rgpElement
[
i
]);
CryptMemFree
(
chain
->
rgpElement
);
CryptMemFree
(
chain
);
}
static
BOOL
CRYPT_BuildSimpleChain
(
HCERTCHAINENGINE
hChainEngine
,
PCCERT_CONTEXT
cert
,
LPFILETIME
pTime
,
HCERTSTORE
hAdditionalStore
,
PCERT_SIMPLE_CHAIN
*
ppChain
)
{
BOOL
ret
=
FALSE
;
PCertificateChainEngine
engine
=
(
PCertificateChainEngine
)
hChainEngine
;
PCERT_SIMPLE_CHAIN
chain
;
HCERTSTORE
world
;
TRACE
(
"(%p, %p, %p, %p)
\n
"
,
hChainEngine
,
cert
,
pTime
,
hAdditionalStore
);
world
=
CertOpenStore
(
CERT_STORE_PROV_COLLECTION
,
0
,
0
,
CERT_STORE_CREATE_NEW_FLAG
,
NULL
);
CertAddStoreToCollection
(
world
,
engine
->
hWorld
,
0
,
0
);
if
(
cert
->
hCertStore
)
CertAddStoreToCollection
(
world
,
cert
->
hCertStore
,
0
,
0
);
if
(
hAdditionalStore
)
CertAddStoreToCollection
(
world
,
hAdditionalStore
,
0
,
0
);
chain
=
CryptMemAlloc
(
sizeof
(
CERT_SIMPLE_CHAIN
));
if
(
chain
)
{
memset
(
chain
,
0
,
sizeof
(
CERT_SIMPLE_CHAIN
));
chain
->
cbSize
=
sizeof
(
CERT_SIMPLE_CHAIN
);
ret
=
CRYPT_AddCertToSimpleChain
(
chain
,
cert
,
0
);
while
(
ret
&&
!
CRYPT_IsCertificateSelfSigned
(
cert
))
{
DWORD
flags
;
PCCERT_CONTEXT
issuer
=
CRYPT_GetIssuerFromStore
(
world
,
cert
,
&
flags
);
if
(
issuer
)
{
ret
=
CRYPT_AddCertToSimpleChain
(
chain
,
issuer
,
flags
);
cert
=
issuer
;
}
else
{
TRACE
(
"Couldn't find issuer, aborting chain creation
\n
"
);
ret
=
FALSE
;
}
}
if
(
ret
)
{
PCCERT_CONTEXT
root
=
chain
->
rgpElement
[
chain
->
cElement
-
1
]
->
pCertContext
;
if
(
!
(
ret
=
CRYPT_IsCertificateSelfSigned
(
root
)))
TRACE
(
"Last certificate is not self-signed
\n
"
);
else
{
chain
->
rgpElement
[
chain
->
cElement
-
1
]
->
TrustStatus
.
dwInfoStatus
|=
CERT_TRUST_IS_SELF_SIGNED
;
if
(
!
(
ret
=
CryptVerifyCertificateSignatureEx
(
0
,
root
->
dwCertEncodingType
,
CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT
,
(
void
*
)
root
,
CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT
,
(
void
*
)
root
,
0
,
NULL
)))
TRACE
(
"Last certificate's signature is invalid
\n
"
);
}
if
(
ret
)
{
BYTE
hash
[
20
];
DWORD
size
=
sizeof
(
hash
);
CRYPT_HASH_BLOB
blob
=
{
sizeof
(
hash
),
hash
};
PCCERT_CONTEXT
trustedRoot
;
CertGetCertificateContextProperty
(
root
,
CERT_HASH_PROP_ID
,
hash
,
&
size
);
trustedRoot
=
CertFindCertificateInStore
(
engine
->
hRoot
,
root
->
dwCertEncodingType
,
0
,
CERT_FIND_SHA1_HASH
,
&
blob
,
NULL
);
if
(
!
trustedRoot
)
chain
->
TrustStatus
.
dwErrorStatus
|=
CERT_TRUST_IS_UNTRUSTED_ROOT
;
else
CertFreeCertificateContext
(
trustedRoot
);
}
}
if
(
!
ret
)
{
CRYPT_FreeSimpleChain
(
chain
);
chain
=
NULL
;
}
*
ppChain
=
chain
;
}
CertCloseStore
(
world
,
0
);
return
ret
;
}
typedef
struct
_CERT_CHAIN_PARA_NO_EXTRA_FIELDS
{
DWORD
cbSize
;
CERT_USAGE_MATCH
RequestedUsage
;
}
CERT_CHAIN_PARA_NO_EXTRA_FIELDS
,
*
PCERT_CHAIN_PARA_NO_EXTRA_FIELDS
;
typedef
struct
_CERT_CHAIN_PARA_EXTRA_FIELDS
{
DWORD
cbSize
;
CERT_USAGE_MATCH
RequestedUsage
;
CERT_USAGE_MATCH
RequestedIssuancePolicy
;
DWORD
dwUrlRetrievalTimeout
;
BOOL
fCheckRevocationFreshnessTime
;
DWORD
dwRevocationFreshnessTime
;
}
CERT_CHAIN_PARA_EXTRA_FIELDS
,
*
PCERT_CHAIN_PARA_EXTRA_FIELDS
;
BOOL
WINAPI
CertGetCertificateChain
(
HCERTCHAINENGINE
hChainEngine
,
PCCERT_CONTEXT
pCertContext
,
LPFILETIME
pTime
,
HCERTSTORE
hAdditionalStore
,
PCERT_CHAIN_PARA
pChainPara
,
DWORD
dwFlags
,
LPVOID
pvReserved
,
PCCERT_CHAIN_CONTEXT
*
ppChainContext
)
{
FIXME
(
"(%p, %p, %p, %p, %p, 0x%08X, %p, %p): stub
\n
"
,
hChainEngine
,
pCertContext
,
pTime
,
hAdditionalStore
,
pChainPara
,
dwFlags
,
pvReserved
,
ppChainContext
);
PCERT_SIMPLE_CHAIN
simpleChain
=
NULL
;
BOOL
ret
;
TRACE
(
"(%p, %p, %p, %p, %p, %08x, %p, %p)
\n
"
,
hChainEngine
,
pCertContext
,
pTime
,
hAdditionalStore
,
pChainPara
,
dwFlags
,
pvReserved
,
ppChainContext
);
if
(
!
pChainPara
)
{
SetLastError
(
E_INVALIDARG
);
return
FALSE
;
}
if
(
ppChainContext
)
*
ppChainContext
=
NULL
;
SetLastError
(
ERROR_CALL_NOT_IMPLEMENTED
);
return
FALSE
;
if
(
!
hChainEngine
)
hChainEngine
=
CRYPT_GetDefaultChainEngine
();
/* FIXME: what about HCCE_LOCAL_MACHINE? */
/* FIXME: pChainPara is for now ignored */
/* FIXME: only simple chains are supported for now, as CTLs aren't
* supported yet.
*/
if
((
ret
=
CRYPT_BuildSimpleChain
(
hChainEngine
,
pCertContext
,
pTime
,
hAdditionalStore
,
&
simpleChain
)))
{
PCertificateChain
chain
=
CryptMemAlloc
(
sizeof
(
CertificateChain
));
if
(
chain
)
{
chain
->
ref
=
1
;
chain
->
context
.
cbSize
=
sizeof
(
CERT_CHAIN_CONTEXT
);
memcpy
(
&
chain
->
context
.
TrustStatus
,
&
simpleChain
->
TrustStatus
,
sizeof
(
CERT_TRUST_STATUS
));
chain
->
context
.
cChain
=
1
;
chain
->
context
.
rgpChain
=
CryptMemAlloc
(
sizeof
(
PCERT_SIMPLE_CHAIN
));
chain
->
context
.
rgpChain
[
0
]
=
simpleChain
;
chain
->
context
.
cLowerQualityChainContext
=
0
;
chain
->
context
.
rgpLowerQualityChainContext
=
NULL
;
chain
->
context
.
fHasRevocationFreshnessTime
=
FALSE
;
chain
->
context
.
dwRevocationFreshnessTime
=
0
;
}
else
ret
=
FALSE
;
if
(
ppChainContext
)
*
ppChainContext
=
(
PCCERT_CHAIN_CONTEXT
)
chain
;
else
CertFreeCertificateChain
((
PCCERT_CHAIN_CONTEXT
)
chain
);
}
TRACE
(
"returning %d
\n
"
,
ret
);
return
ret
;
}
static
void
CRYPT_FreeChainContext
(
PCertificateChain
chain
)
{
DWORD
i
;
/* Note the chain's rgpLowerQualityChainContext isn't freed, but
* it's never set, either.
*/
for
(
i
=
0
;
i
<
chain
->
context
.
cChain
;
i
++
)
CRYPT_FreeSimpleChain
(
chain
->
context
.
rgpChain
[
i
]);
CryptMemFree
(
chain
->
context
.
rgpChain
);
CryptMemFree
(
chain
);
}
void
WINAPI
CertFreeCertificateChain
(
PCCERT_CHAIN_CONTEXT
pChainContext
)
{
FIXME
(
"(%p): stub
\n
"
,
pChainContext
);
PCertificateChain
chain
=
(
PCertificateChain
)
pChainContext
;
TRACE
(
"(%p)
\n
"
,
pChainContext
);
if
(
chain
)
{
if
(
InterlockedDecrement
(
&
chain
->
ref
)
==
0
)
CRYPT_FreeChainContext
(
chain
);
}
}
dlls/crypt32/tests/chain.c
View file @
9a58b308
...
...
@@ -492,12 +492,10 @@ static void testGetCertChain(void)
/* Basic parameter checks */
ret
=
CertGetCertificateChain
(
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
0
,
NULL
,
NULL
);
todo_wine
ok
(
!
ret
&&
GetLastError
()
==
E_INVALIDARG
,
"Expected E_INVALIDARG, got %08x
\n
"
,
GetLastError
());
ret
=
CertGetCertificateChain
(
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
0
,
NULL
,
&
chain
);
todo_wine
ok
(
!
ret
&&
GetLastError
()
==
E_INVALIDARG
,
"Expected E_INVALIDARG, got %08x
\n
"
,
GetLastError
());
/* Crash
...
...
@@ -509,7 +507,6 @@ static void testGetCertChain(void)
sizeof
(
bigCert
));
todo_wine
ret
=
CertGetCertificateChain
(
NULL
,
cert
,
NULL
,
NULL
,
NULL
,
0
,
NULL
,
NULL
);
todo_wine
ok
(
!
ret
&&
GetLastError
()
==
E_INVALIDARG
,
"Expected E_INVALIDARG, got %08x
\n
"
,
GetLastError
());
/* Crash
...
...
@@ -530,14 +527,11 @@ static void testGetCertChain(void)
cert
=
CertCreateCertificateContext
(
X509_ASN_ENCODING
,
selfSignedCert
,
sizeof
(
selfSignedCert
));
ret
=
CertGetCertificateChain
(
NULL
,
cert
,
NULL
,
NULL
,
NULL
,
0
,
NULL
,
NULL
);
todo_wine
ok
(
!
ret
&&
GetLastError
()
==
E_INVALIDARG
,
"Expected E_INVALIDARG, got %08x
\n
"
,
GetLastError
());
ret
=
CertGetCertificateChain
(
NULL
,
cert
,
NULL
,
NULL
,
&
para
,
0
,
NULL
,
&
chain
);
todo_wine
ok
(
ret
,
"CertGetCertificateChain failed: %08x
\n
"
,
GetLastError
());
todo_wine
ok
(
chain
!=
NULL
,
"Expected a chain
\n
"
);
if
(
chain
)
{
...
...
@@ -564,7 +558,6 @@ static void testGetCertChain(void)
ok
(
ret
,
"CertCreateCertificateChainEngine failed: %08x
\n
"
,
GetLastError
());
ret
=
CertGetCertificateChain
(
engine
,
cert
,
NULL
,
NULL
,
&
para
,
0
,
NULL
,
&
chain
);
todo_wine
ok
(
chain
!=
NULL
,
"Expected a chain
\n
"
);
if
(
chain
)
{
...
...
@@ -625,14 +618,12 @@ static void testGetCertChain(void)
else
ret
=
CertGetCertificateChain
(
NULL
,
cert
,
NULL
,
config
.
hRestrictedRoot
,
&
para
,
0
,
NULL
,
&
chain
);
todo_wine
ok
(
ret
,
"CertGetCertificateChain failed: %08x
\n
"
,
GetLastError
());
if
(
ret
)
{
/* Since there's no guarantee the Verisign cert is in the Root
* store, either error is acceptable.
*/
todo_wine
ok
(
chain
->
TrustStatus
.
dwErrorStatus
==
CERT_TRUST_NO_ERROR
||
chain
->
TrustStatus
.
dwErrorStatus
==
CERT_TRUST_IS_UNTRUSTED_ROOT
,
"Expected no error or CERT_TRUST_IS_UNTRUSTED_ROOT, got %08x
\n
"
,
...
...
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