Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-cw
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-cw
Commits
5e674f35
Commit
5e674f35
authored
Sep 06, 2007
by
Juan Lang
Committed by
Alexandre Julliard
Sep 10, 2007
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
crypt32: Consider alternate issuers when building chains.
parent
1fc8c607
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
328 additions
and
16 deletions
+328
-16
chain.c
dlls/crypt32/chain.c
+326
-14
chain.c
dlls/crypt32/tests/chain.c
+2
-2
No files found.
dlls/crypt32/chain.c
View file @
5e674f35
...
...
@@ -602,6 +602,312 @@ static BOOL CRYPT_BuildCandidateChainFromCert(HCERTCHAINENGINE hChainEngine,
return
ret
;
}
/* Makes and returns a copy of chain, up to and including element iElement. */
static
PCERT_SIMPLE_CHAIN
CRYPT_CopySimpleChainToElement
(
PCERT_SIMPLE_CHAIN
chain
,
DWORD
iElement
)
{
PCERT_SIMPLE_CHAIN
copy
=
CryptMemAlloc
(
sizeof
(
CERT_SIMPLE_CHAIN
));
if
(
copy
)
{
memset
(
copy
,
0
,
sizeof
(
CERT_SIMPLE_CHAIN
));
copy
->
cbSize
=
sizeof
(
CERT_SIMPLE_CHAIN
);
copy
->
rgpElement
=
CryptMemAlloc
((
iElement
+
1
)
*
sizeof
(
PCERT_CHAIN_ELEMENT
));
if
(
copy
->
rgpElement
)
{
DWORD
i
;
BOOL
ret
=
TRUE
;
memset
(
copy
->
rgpElement
,
0
,
(
iElement
+
1
)
*
sizeof
(
PCERT_CHAIN_ELEMENT
));
for
(
i
=
0
;
ret
&&
i
<=
iElement
;
i
++
)
{
PCERT_CHAIN_ELEMENT
element
=
CryptMemAlloc
(
sizeof
(
CERT_CHAIN_ELEMENT
));
if
(
element
)
{
memcpy
(
element
,
chain
->
rgpElement
[
i
],
sizeof
(
CERT_CHAIN_ELEMENT
));
element
->
pCertContext
=
CertDuplicateCertificateContext
(
chain
->
rgpElement
[
i
]
->
pCertContext
);
/* Reset the trust status of the copied element, it'll get
* rechecked after the new chain is done.
*/
memset
(
&
element
->
TrustStatus
,
0
,
sizeof
(
CERT_TRUST_STATUS
));
copy
->
rgpElement
[
copy
->
cElement
++
]
=
element
;
}
else
ret
=
FALSE
;
}
if
(
!
ret
)
{
for
(
i
=
0
;
i
<=
iElement
;
i
++
)
CryptMemFree
(
copy
->
rgpElement
[
i
]);
CryptMemFree
(
copy
->
rgpElement
);
CryptMemFree
(
copy
);
copy
=
NULL
;
}
}
else
{
CryptMemFree
(
copy
);
copy
=
NULL
;
}
}
return
copy
;
}
static
void
CRYPT_FreeLowerQualityChains
(
PCertificateChain
chain
)
{
DWORD
i
;
for
(
i
=
0
;
i
<
chain
->
context
.
cLowerQualityChainContext
;
i
++
)
CertFreeCertificateChain
(
chain
->
context
.
rgpLowerQualityChainContext
[
i
]);
CryptMemFree
(
chain
->
context
.
rgpLowerQualityChainContext
);
}
static
void
CRYPT_FreeChainContext
(
PCertificateChain
chain
)
{
DWORD
i
;
CRYPT_FreeLowerQualityChains
(
chain
);
for
(
i
=
0
;
i
<
chain
->
context
.
cChain
;
i
++
)
CRYPT_FreeSimpleChain
(
chain
->
context
.
rgpChain
[
i
]);
CryptMemFree
(
chain
->
context
.
rgpChain
);
CertCloseStore
(
chain
->
world
,
0
);
CryptMemFree
(
chain
);
}
/* Makes and returns a copy of chain, up to and including element iElement of
* simple chain iChain.
*/
static
PCertificateChain
CRYPT_CopyChainToElement
(
PCertificateChain
chain
,
DWORD
iChain
,
DWORD
iElement
)
{
PCertificateChain
copy
=
CryptMemAlloc
(
sizeof
(
CertificateChain
));
if
(
copy
)
{
copy
->
ref
=
1
;
copy
->
world
=
CertDuplicateStore
(
chain
->
world
);
copy
->
context
.
cbSize
=
sizeof
(
CERT_CHAIN_CONTEXT
);
/* Leave the trust status of the copied chain unset, it'll get
* rechecked after the new chain is done.
*/
memset
(
&
copy
->
context
.
TrustStatus
,
0
,
sizeof
(
CERT_TRUST_STATUS
));
copy
->
context
.
cLowerQualityChainContext
=
0
;
copy
->
context
.
rgpLowerQualityChainContext
=
NULL
;
copy
->
context
.
fHasRevocationFreshnessTime
=
FALSE
;
copy
->
context
.
dwRevocationFreshnessTime
=
0
;
copy
->
context
.
rgpChain
=
CryptMemAlloc
(
(
iChain
+
1
)
*
sizeof
(
PCERT_SIMPLE_CHAIN
));
if
(
copy
->
context
.
rgpChain
)
{
BOOL
ret
=
TRUE
;
DWORD
i
;
memset
(
copy
->
context
.
rgpChain
,
0
,
(
iChain
+
1
)
*
sizeof
(
PCERT_SIMPLE_CHAIN
));
if
(
iChain
)
{
for
(
i
=
0
;
ret
&&
iChain
&&
i
<
iChain
-
1
;
i
++
)
{
copy
->
context
.
rgpChain
[
i
]
=
CRYPT_CopySimpleChainToElement
(
chain
->
context
.
rgpChain
[
i
],
chain
->
context
.
rgpChain
[
i
]
->
cElement
-
1
);
if
(
!
copy
->
context
.
rgpChain
[
i
])
ret
=
FALSE
;
}
}
else
i
=
0
;
if
(
ret
)
{
copy
->
context
.
rgpChain
[
i
]
=
CRYPT_CopySimpleChainToElement
(
chain
->
context
.
rgpChain
[
i
],
iElement
);
if
(
!
copy
->
context
.
rgpChain
[
i
])
ret
=
FALSE
;
}
if
(
!
ret
)
{
CRYPT_FreeChainContext
(
copy
);
copy
=
NULL
;
}
else
copy
->
context
.
cChain
=
iChain
+
1
;
}
else
{
CryptMemFree
(
copy
);
copy
=
NULL
;
}
}
return
copy
;
}
static
PCertificateChain
CRYPT_BuildAlternateContextFromChain
(
HCERTCHAINENGINE
hChainEngine
,
LPFILETIME
pTime
,
HCERTSTORE
hAdditionalStore
,
PCertificateChain
chain
)
{
PCertificateChainEngine
engine
=
(
PCertificateChainEngine
)
hChainEngine
;
PCertificateChain
alternate
;
TRACE
(
"(%p, %p, %p, %p)
\n
"
,
hChainEngine
,
pTime
,
hAdditionalStore
,
chain
);
/* Always start with the last "lower quality" chain to ensure a consistent
* order of alternate creation:
*/
if
(
chain
->
context
.
cLowerQualityChainContext
)
chain
=
(
PCertificateChain
)
chain
->
context
.
rgpLowerQualityChainContext
[
chain
->
context
.
cLowerQualityChainContext
-
1
];
/* A chain with only one element can't have any alternates */
if
(
chain
->
context
.
cChain
<=
1
&&
chain
->
context
.
rgpChain
[
0
]
->
cElement
<=
1
)
alternate
=
NULL
;
else
{
DWORD
i
,
j
,
flags
;
PCCERT_CONTEXT
alternateIssuer
=
NULL
;
alternate
=
NULL
;
for
(
i
=
0
;
!
alternateIssuer
&&
i
<
chain
->
context
.
cChain
;
i
++
)
for
(
j
=
0
;
!
alternateIssuer
&&
j
<
chain
->
context
.
rgpChain
[
i
]
->
cElement
-
1
;
j
++
)
{
PCCERT_CONTEXT
subject
=
chain
->
context
.
rgpChain
[
i
]
->
rgpElement
[
j
]
->
pCertContext
;
PCCERT_CONTEXT
prevIssuer
=
CertDuplicateCertificateContext
(
chain
->
context
.
rgpChain
[
i
]
->
rgpElement
[
j
+
1
]
->
pCertContext
);
flags
=
CERT_STORE_REVOCATION_FLAG
|
CERT_STORE_SIGNATURE_FLAG
;
alternateIssuer
=
CertGetIssuerCertificateFromStore
(
prevIssuer
->
hCertStore
,
subject
,
prevIssuer
,
&
flags
);
}
if
(
alternateIssuer
)
{
i
--
;
j
--
;
alternate
=
CRYPT_CopyChainToElement
(
chain
,
i
,
j
);
if
(
alternate
)
{
BOOL
ret
=
CRYPT_AddCertToSimpleChain
(
engine
,
alternate
->
context
.
rgpChain
[
i
],
alternateIssuer
);
if
(
ret
)
{
ret
=
CRYPT_BuildSimpleChain
(
engine
,
alternate
->
world
,
alternate
->
context
.
rgpChain
[
i
]);
if
(
ret
)
CRYPT_CheckSimpleChain
(
engine
,
alternate
->
context
.
rgpChain
[
i
],
pTime
);
CRYPT_CombineTrustStatus
(
&
alternate
->
context
.
TrustStatus
,
&
alternate
->
context
.
rgpChain
[
i
]
->
TrustStatus
);
}
if
(
!
ret
)
{
CRYPT_FreeChainContext
(
alternate
);
alternate
=
NULL
;
}
}
}
}
TRACE
(
"%p
\n
"
,
alternate
);
return
alternate
;
}
#define CHAIN_QUALITY_SIGNATURE_VALID 8
#define CHAIN_QUALITY_TIME_VALID 4
#define CHAIN_QUALITY_COMPLETE_CHAIN 2
#define CHAIN_QUALITY_TRUSTED_ROOT 1
#define CHAIN_QUALITY_HIGHEST \
CHAIN_QUALITY_SIGNATURE_VALID | CHAIN_QUALITY_TIME_VALID | \
CHAIN_QUALITY_COMPLETE_CHAIN | CHAIN_QUALITY_TRUSTED_ROOT
#define IS_TRUST_ERROR_SET(TrustStatus, bits) \
(TrustStatus)->dwErrorStatus & (bits)
static
DWORD
CRYPT_ChainQuality
(
PCertificateChain
chain
)
{
DWORD
quality
=
CHAIN_QUALITY_HIGHEST
;
if
(
IS_TRUST_ERROR_SET
(
&
chain
->
context
.
TrustStatus
,
CERT_TRUST_IS_UNTRUSTED_ROOT
))
quality
&=
~
CHAIN_QUALITY_TRUSTED_ROOT
;
if
(
IS_TRUST_ERROR_SET
(
&
chain
->
context
.
TrustStatus
,
CERT_TRUST_IS_PARTIAL_CHAIN
))
if
(
chain
->
context
.
TrustStatus
.
dwErrorStatus
&
CERT_TRUST_IS_PARTIAL_CHAIN
)
quality
&=
~
CHAIN_QUALITY_COMPLETE_CHAIN
;
if
(
IS_TRUST_ERROR_SET
(
&
chain
->
context
.
TrustStatus
,
CERT_TRUST_IS_NOT_TIME_VALID
|
CERT_TRUST_IS_NOT_TIME_NESTED
))
quality
&=
~
CHAIN_QUALITY_TIME_VALID
;
if
(
IS_TRUST_ERROR_SET
(
&
chain
->
context
.
TrustStatus
,
CERT_TRUST_IS_NOT_SIGNATURE_VALID
))
quality
&=
~
CHAIN_QUALITY_SIGNATURE_VALID
;
return
quality
;
}
/* Chooses the highest quality chain among chain and its "lower quality"
* alternate chains. Returns the highest quality chain, with all other
* chains as lower quality chains of it.
*/
static
PCertificateChain
CRYPT_ChooseHighestQualityChain
(
PCertificateChain
chain
)
{
DWORD
i
;
/* There are always only two chains being considered: chain, and an
* alternate at chain->rgpLowerQualityChainContext[i]. If the alternate
* has a higher quality than chain, the alternate gets assigned the lower
* quality contexts, with chain taking the alternate's place among the
* lower quality contexts.
*/
for
(
i
=
0
;
i
<
chain
->
context
.
cLowerQualityChainContext
;
i
++
)
{
PCertificateChain
alternate
=
(
PCertificateChain
)
chain
->
context
.
rgpLowerQualityChainContext
[
i
];
if
(
CRYPT_ChainQuality
(
alternate
)
>
CRYPT_ChainQuality
(
chain
))
{
alternate
->
context
.
cLowerQualityChainContext
=
chain
->
context
.
cLowerQualityChainContext
;
alternate
->
context
.
rgpLowerQualityChainContext
=
chain
->
context
.
rgpLowerQualityChainContext
;
alternate
->
context
.
rgpLowerQualityChainContext
[
i
]
=
(
PCCERT_CHAIN_CONTEXT
)
chain
;
chain
=
alternate
;
}
}
return
chain
;
}
static
BOOL
CRYPT_AddAlternateChainToChain
(
PCertificateChain
chain
,
PCertificateChain
alternate
)
{
BOOL
ret
;
if
(
chain
->
context
.
cLowerQualityChainContext
)
chain
->
context
.
rgpLowerQualityChainContext
=
CryptMemRealloc
(
chain
->
context
.
rgpLowerQualityChainContext
,
(
chain
->
context
.
cLowerQualityChainContext
+
1
)
*
sizeof
(
PCCERT_CHAIN_CONTEXT
));
else
chain
->
context
.
rgpLowerQualityChainContext
=
CryptMemAlloc
(
sizeof
(
PCCERT_CHAIN_CONTEXT
));
if
(
chain
->
context
.
rgpLowerQualityChainContext
)
{
chain
->
context
.
rgpLowerQualityChainContext
[
chain
->
context
.
cLowerQualityChainContext
++
]
=
(
PCCERT_CHAIN_CONTEXT
)
alternate
;
ret
=
TRUE
;
}
else
ret
=
FALSE
;
return
ret
;
}
typedef
struct
_CERT_CHAIN_PARA_NO_EXTRA_FIELDS
{
DWORD
cbSize
;
CERT_USAGE_MATCH
RequestedUsage
;
...
...
@@ -647,6 +953,26 @@ BOOL WINAPI CertGetCertificateChain(HCERTCHAINENGINE hChainEngine,
hAdditionalStore
,
&
chain
);
if
(
ret
)
{
PCertificateChain
alternate
=
NULL
;
do
{
alternate
=
CRYPT_BuildAlternateContextFromChain
(
hChainEngine
,
pTime
,
hAdditionalStore
,
chain
);
/* Alternate contexts are added as "lower quality" contexts of
* chain, to avoid loops in alternate chain creation.
* The highest-quality chain is chosen at the end.
*/
if
(
alternate
)
ret
=
CRYPT_AddAlternateChainToChain
(
chain
,
alternate
);
}
while
(
ret
&&
alternate
);
chain
=
CRYPT_ChooseHighestQualityChain
(
chain
);
if
(
!
(
dwFlags
&
CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS
))
{
CRYPT_FreeLowerQualityChains
(
chain
);
chain
->
context
.
cLowerQualityChainContext
=
0
;
chain
->
context
.
rgpLowerQualityChainContext
=
NULL
;
}
if
(
ppChainContext
)
*
ppChainContext
=
(
PCCERT_CHAIN_CONTEXT
)
chain
;
else
...
...
@@ -656,20 +982,6 @@ BOOL WINAPI CertGetCertificateChain(HCERTCHAINENGINE hChainEngine,
return
ret
;
}
static
void
CRYPT_FreeChainContext
(
PCertificateChain
chain
)
{
DWORD
i
;
for
(
i
=
0
;
i
<
chain
->
context
.
cLowerQualityChainContext
;
i
++
)
CertFreeCertificateChain
(
chain
->
context
.
rgpLowerQualityChainContext
[
i
]);
CryptMemFree
(
chain
->
context
.
rgpLowerQualityChainContext
);
for
(
i
=
0
;
i
<
chain
->
context
.
cChain
;
i
++
)
CRYPT_FreeSimpleChain
(
chain
->
context
.
rgpChain
[
i
]);
CryptMemFree
(
chain
->
context
.
rgpChain
);
CertCloseStore
(
chain
->
world
,
0
);
CryptMemFree
(
chain
);
}
PCCERT_CHAIN_CONTEXT
WINAPI
CertDuplicateCertificateChain
(
PCCERT_CHAIN_CONTEXT
pChainContext
)
{
...
...
dlls/crypt32/tests/chain.c
View file @
5e674f35
...
...
@@ -1589,11 +1589,11 @@ static ChainCheck chainCheck[] = {
{
{
sizeof
(
chain10
)
/
sizeof
(
chain10
[
0
]),
chain10
},
{
{
0
,
CERT_TRUST_HAS_PREFERRED_ISSUER
},
{
CERT_TRUST_IS_UNTRUSTED_ROOT
,
0
},
1
,
simpleStatus10
},
TODO_
ERROR
|
TODO_
INFO
},
TODO_INFO
},
{
{
sizeof
(
chain11
)
/
sizeof
(
chain11
[
0
]),
chain11
},
{
{
0
,
CERT_TRUST_HAS_PREFERRED_ISSUER
},
{
CERT_TRUST_IS_UNTRUSTED_ROOT
,
0
},
1
,
simpleStatus10
},
TODO_
ERROR
|
TODO_
INFO
},
TODO_INFO
},
{
{
sizeof
(
chain12
)
/
sizeof
(
chain12
[
0
]),
chain12
},
{
{
0
,
CERT_TRUST_HAS_PREFERRED_ISSUER
},
{
CERT_TRUST_IS_UNTRUSTED_ROOT
,
0
},
1
,
simpleStatus12
},
...
...
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