2 * Copyright 2007 Juan Lang
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #define NONAMELESSUNION
26 #include "wine/debug.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(wintrust
);
30 HRESULT WINAPI
SoftpubInitialize(CRYPT_PROVIDER_DATA
*data
)
32 HRESULT ret
= S_FALSE
;
34 TRACE("(%p)\n", data
);
36 if (data
->padwTrustStepErrors
&&
37 !data
->padwTrustStepErrors
[TRUSTERROR_STEP_FINAL_WVTINIT
])
39 TRACE("returning %08x\n", ret
);
43 /* Assumes data->pWintrustData->u.pFile exists. Makes sure a file handle is
46 static BOOL
SOFTPUB_OpenFile(CRYPT_PROVIDER_DATA
*data
)
50 /* PSDK implies that all values should be initialized to NULL, so callers
51 * typically have hFile as NULL rather than INVALID_HANDLE_VALUE. Check
54 if (!data
->pWintrustData
->u
.pFile
->hFile
||
55 data
->pWintrustData
->u
.pFile
->hFile
== INVALID_HANDLE_VALUE
)
57 data
->pWintrustData
->u
.pFile
->hFile
=
58 CreateFileW(data
->pWintrustData
->u
.pFile
->pcwszFilePath
, GENERIC_READ
,
59 FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
60 if (data
->pWintrustData
->u
.pFile
->hFile
!= INVALID_HANDLE_VALUE
)
61 data
->fOpenedFile
= TRUE
;
65 TRACE("returning %d\n", ret
);
69 /* Assumes data->pWintrustData->u.pFile exists. Sets data->pPDSip->gSubject to
70 * the file's subject GUID.
72 static BOOL
SOFTPUB_GetFileSubject(CRYPT_PROVIDER_DATA
*data
)
76 if (!data
->pWintrustData
->u
.pFile
->pgKnownSubject
)
78 ret
= CryptSIPRetrieveSubjectGuid(
79 data
->pWintrustData
->u
.pFile
->pcwszFilePath
,
80 data
->pWintrustData
->u
.pFile
->hFile
,
81 &data
->u
.pPDSip
->gSubject
);
85 memcpy(&data
->u
.pPDSip
->gSubject
,
86 data
->pWintrustData
->u
.pFile
->pgKnownSubject
, sizeof(GUID
));
89 TRACE("returning %d\n", ret
);
93 /* Assumes data->u.pPDSip exists, and its gSubject member set.
94 * Allocates data->u.pPDSip->pSip and loads it, if possible.
96 static BOOL
SOFTPUB_GetSIP(CRYPT_PROVIDER_DATA
*data
)
100 data
->u
.pPDSip
->pSip
= data
->psPfns
->pfnAlloc(sizeof(SIP_DISPATCH_INFO
));
101 if (data
->u
.pPDSip
->pSip
)
102 ret
= CryptSIPLoad(&data
->u
.pPDSip
->gSubject
, 0, data
->u
.pPDSip
->pSip
);
105 SetLastError(ERROR_OUTOFMEMORY
);
108 TRACE("returning %d\n", ret
);
112 /* Assumes data->u.pPDSip has been loaded, and data->u.pPDSip->pSip allocated.
113 * Calls data->u.pPDSip->pSip->pfGet to construct data->hMsg.
115 static BOOL
SOFTPUB_GetMessageFromFile(CRYPT_PROVIDER_DATA
*data
)
121 data
->u
.pPDSip
->psSipSubjectInfo
=
122 data
->psPfns
->pfnAlloc(sizeof(SIP_SUBJECTINFO
));
123 if (!data
->u
.pPDSip
->psSipSubjectInfo
)
125 SetLastError(ERROR_OUTOFMEMORY
);
129 data
->u
.pPDSip
->psSipSubjectInfo
->cbSize
= sizeof(SIP_SUBJECTINFO
);
130 data
->u
.pPDSip
->psSipSubjectInfo
->pgSubjectType
= &data
->u
.pPDSip
->gSubject
;
131 data
->u
.pPDSip
->psSipSubjectInfo
->hFile
= data
->pWintrustData
->u
.pFile
->hFile
;
132 data
->u
.pPDSip
->psSipSubjectInfo
->pwsFileName
=
133 data
->pWintrustData
->u
.pFile
->pcwszFilePath
;
134 data
->u
.pPDSip
->psSipSubjectInfo
->hProv
= data
->hProv
;
135 ret
= data
->u
.pPDSip
->pSip
->pfGet(data
->u
.pPDSip
->psSipSubjectInfo
,
136 &data
->dwEncoding
, 0, &size
, 0);
139 SetLastError(TRUST_E_NOSIGNATURE
);
143 buf
= data
->psPfns
->pfnAlloc(size
);
146 SetLastError(ERROR_OUTOFMEMORY
);
150 ret
= data
->u
.pPDSip
->pSip
->pfGet(data
->u
.pPDSip
->psSipSubjectInfo
,
151 &data
->dwEncoding
, 0, &size
, buf
);
154 data
->hMsg
= CryptMsgOpenToDecode(data
->dwEncoding
, 0, 0, data
->hProv
,
157 ret
= CryptMsgUpdate(data
->hMsg
, buf
, size
, TRUE
);
160 data
->psPfns
->pfnFree(buf
);
161 TRACE("returning %d\n", ret
);
165 static BOOL
SOFTPUB_CreateStoreFromMessage(CRYPT_PROVIDER_DATA
*data
)
170 store
= CertOpenStore(CERT_STORE_PROV_MSG
, data
->dwEncoding
,
171 data
->hProv
, CERT_STORE_NO_CRYPT_RELEASE_FLAG
, data
->hMsg
);
174 ret
= data
->psPfns
->pfnAddStore2Chain(data
, store
);
175 CertCloseStore(store
, 0);
177 TRACE("returning %d\n", ret
);
181 static DWORD
SOFTPUB_DecodeInnerContent(CRYPT_PROVIDER_DATA
*data
)
187 ret
= CryptMsgGetParam(data
->hMsg
, CMSG_INNER_CONTENT_TYPE_PARAM
, 0, NULL
,
191 buf
= data
->psPfns
->pfnAlloc(size
);
194 SetLastError(ERROR_OUTOFMEMORY
);
198 ret
= CryptMsgGetParam(data
->hMsg
, CMSG_INNER_CONTENT_TYPE_PARAM
, 0, buf
,
202 if (!strcmp((LPCSTR
)buf
, SPC_INDIRECT_DATA_OBJID
))
204 data
->psPfns
->pfnFree(buf
);
206 ret
= CryptMsgGetParam(data
->hMsg
, CMSG_CONTENT_PARAM
, 0, NULL
, &size
);
209 buf
= data
->psPfns
->pfnAlloc(size
);
212 SetLastError(ERROR_OUTOFMEMORY
);
216 ret
= CryptMsgGetParam(data
->hMsg
, CMSG_CONTENT_PARAM
, 0, buf
, &size
);
219 ret
= CryptDecodeObject(data
->dwEncoding
,
220 SPC_INDIRECT_DATA_CONTENT_STRUCT
, buf
, size
, 0, NULL
, &size
);
223 data
->u
.pPDSip
->psIndirectData
= data
->psPfns
->pfnAlloc(size
);
224 if (!data
->u
.pPDSip
->psIndirectData
)
226 SetLastError(ERROR_OUTOFMEMORY
);
230 ret
= CryptDecodeObject(data
->dwEncoding
,
231 SPC_INDIRECT_DATA_CONTENT_STRUCT
, buf
, size
, 0,
232 data
->u
.pPDSip
->psIndirectData
, &size
);
236 FIXME("unimplemented for OID %s\n", (LPCSTR
)buf
);
237 SetLastError(TRUST_E_SUBJECT_FORM_UNKNOWN
);
242 TRACE("returning %d\n", ret
);
246 HRESULT WINAPI
SoftpubLoadMessage(CRYPT_PROVIDER_DATA
*data
)
250 TRACE("(%p)\n", data
);
252 if (!data
->padwTrustStepErrors
)
255 switch (data
->pWintrustData
->dwUnionChoice
)
257 case WTD_CHOICE_CERT
:
258 /* Do nothing!? See the tests */
261 case WTD_CHOICE_FILE
:
262 if (!data
->pWintrustData
->u
.pFile
)
264 SetLastError(ERROR_INVALID_PARAMETER
);
268 ret
= SOFTPUB_OpenFile(data
);
271 ret
= SOFTPUB_GetFileSubject(data
);
274 ret
= SOFTPUB_GetSIP(data
);
277 ret
= SOFTPUB_GetMessageFromFile(data
);
280 ret
= SOFTPUB_CreateStoreFromMessage(data
);
283 ret
= SOFTPUB_DecodeInnerContent(data
);
286 FIXME("unimplemented for %d\n", data
->pWintrustData
->dwUnionChoice
);
287 SetLastError(ERROR_INVALID_PARAMETER
);
293 data
->padwTrustStepErrors
[TRUSTERROR_STEP_FINAL_OBJPROV
] =
295 return ret
? S_OK
: S_FALSE
;
298 static CMSG_SIGNER_INFO
*WINTRUST_GetSigner(CRYPT_PROVIDER_DATA
*data
,
302 CMSG_SIGNER_INFO
*signerInfo
= NULL
;
305 ret
= CryptMsgGetParam(data
->hMsg
, CMSG_SIGNER_INFO_PARAM
, signerIdx
,
309 signerInfo
= data
->psPfns
->pfnAlloc(size
);
312 ret
= CryptMsgGetParam(data
->hMsg
, CMSG_SIGNER_INFO_PARAM
,
313 signerIdx
, signerInfo
, &size
);
316 data
->psPfns
->pfnFree(signerInfo
);
321 SetLastError(ERROR_OUTOFMEMORY
);
326 static BOOL
WINTRUST_SaveSigner(CRYPT_PROVIDER_DATA
*data
, DWORD signerIdx
)
329 CMSG_SIGNER_INFO
*signerInfo
= WINTRUST_GetSigner(data
, signerIdx
);
333 CRYPT_PROVIDER_SGNR sgnr
= { sizeof(sgnr
), { 0 } };
335 sgnr
.psSigner
= signerInfo
;
336 ret
= data
->psPfns
->pfnAddSgnr2Chain(data
, FALSE
, signerIdx
, &sgnr
);
343 static CERT_INFO
*WINTRUST_GetSignerCertInfo(CRYPT_PROVIDER_DATA
*data
,
347 CERT_INFO
*certInfo
= NULL
;
350 ret
= CryptMsgGetParam(data
->hMsg
, CMSG_SIGNER_CERT_INFO_PARAM
, signerIdx
,
354 certInfo
= data
->psPfns
->pfnAlloc(size
);
357 ret
= CryptMsgGetParam(data
->hMsg
, CMSG_SIGNER_CERT_INFO_PARAM
,
358 signerIdx
, certInfo
, &size
);
361 data
->psPfns
->pfnFree(certInfo
);
366 SetLastError(ERROR_OUTOFMEMORY
);
371 static BOOL
WINTRUST_VerifySigner(CRYPT_PROVIDER_DATA
*data
, DWORD signerIdx
)
374 CERT_INFO
*certInfo
= WINTRUST_GetSignerCertInfo(data
, signerIdx
);
378 CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA para
= { sizeof(para
), 0, signerIdx
,
379 CMSG_VERIFY_SIGNER_CERT
, NULL
};
381 para
.pvSigner
= (LPVOID
)CertGetSubjectCertificateFromStore(
382 data
->pahStores
[0], data
->dwEncoding
, certInfo
);
385 ret
= CryptMsgControl(data
->hMsg
, 0, CMSG_CTRL_VERIFY_SIGNATURE_EX
,
388 SetLastError(TRUST_E_CERT_SIGNATURE
);
392 SetLastError(TRUST_E_NO_SIGNER_CERT
);
395 data
->psPfns
->pfnFree(certInfo
);
402 HRESULT WINAPI
SoftpubLoadSignature(CRYPT_PROVIDER_DATA
*data
)
405 DWORD signerCount
, size
;
407 TRACE("(%p)\n", data
);
409 if (!data
->padwTrustStepErrors
)
412 size
= sizeof(signerCount
);
413 ret
= CryptMsgGetParam(data
->hMsg
, CMSG_SIGNER_COUNT_PARAM
, 0,
414 &signerCount
, &size
);
419 for (i
= 0; ret
&& i
< signerCount
; i
++)
421 if ((ret
= WINTRUST_SaveSigner(data
, i
)))
422 ret
= WINTRUST_VerifySigner(data
, i
);
426 SetLastError(TRUST_E_NOSIGNATURE
);
428 data
->padwTrustStepErrors
[TRUSTERROR_STEP_FINAL_OBJPROV
] =
430 return ret
? S_OK
: S_FALSE
;
433 BOOL WINAPI
SoftpubCheckCert(CRYPT_PROVIDER_DATA
*data
, DWORD idxSigner
,
434 BOOL fCounterSignerChain
, DWORD idxCounterSigner
)
438 TRACE("(%p, %d, %d, %d)\n", data
, idxSigner
, fCounterSignerChain
,
441 if (fCounterSignerChain
)
443 FIXME("unimplemented for counter signers\n");
448 PCERT_SIMPLE_CHAIN simpleChain
=
449 data
->pasSigners
[idxSigner
].pChainContext
->rgpChain
[0];
453 for (i
= 0; i
< simpleChain
->cElement
; i
++)
456 data
->pasSigners
[idxSigner
].pasCertChain
[i
].dwConfidence
= 0;
457 /* The last element in the chain doesn't have an issuer, so it
458 * can't have a valid time (with respect to its issuer)
460 if (i
!= simpleChain
->cElement
- 1 &&
461 !(simpleChain
->rgpElement
[i
]->TrustStatus
.dwErrorStatus
&
462 CERT_TRUST_IS_NOT_TIME_VALID
))
463 data
->pasSigners
[idxSigner
].pasCertChain
[i
].dwConfidence
464 |= CERT_CONFIDENCE_TIME
;
465 if (!(simpleChain
->rgpElement
[i
]->TrustStatus
.dwErrorStatus
&
466 CERT_TRUST_IS_NOT_TIME_NESTED
))
467 data
->pasSigners
[idxSigner
].pasCertChain
[i
].dwConfidence
468 |= CERT_CONFIDENCE_TIMENEST
;
469 if (!(simpleChain
->rgpElement
[i
]->TrustStatus
.dwErrorStatus
&
470 CERT_TRUST_IS_NOT_SIGNATURE_VALID
))
471 data
->pasSigners
[idxSigner
].pasCertChain
[i
].dwConfidence
472 |= CERT_CONFIDENCE_SIG
;
473 /* Set additional flags */
474 if (!(simpleChain
->rgpElement
[i
]->TrustStatus
.dwErrorStatus
&
475 CERT_TRUST_IS_UNTRUSTED_ROOT
))
476 data
->pasSigners
[idxSigner
].pasCertChain
[i
].fTrustedRoot
= TRUE
;
477 if (simpleChain
->rgpElement
[i
]->TrustStatus
.dwInfoStatus
&
478 CERT_TRUST_IS_SELF_SIGNED
)
479 data
->pasSigners
[idxSigner
].pasCertChain
[i
].fSelfSigned
= TRUE
;
480 if (simpleChain
->rgpElement
[i
]->TrustStatus
.dwErrorStatus
&
481 CERT_TRUST_IS_CYCLIC
)
482 data
->pasSigners
[idxSigner
].pasCertChain
[i
].fIsCyclic
= TRUE
;
488 static BOOL
WINTRUST_CopyChain(CRYPT_PROVIDER_DATA
*data
, DWORD signerIdx
)
491 PCERT_SIMPLE_CHAIN simpleChain
=
492 data
->pasSigners
[signerIdx
].pChainContext
->rgpChain
[0];
495 data
->pasSigners
[signerIdx
].pasCertChain
[0].pChainElement
=
496 simpleChain
->rgpElement
[0];
498 for (i
= 1; ret
&& i
< simpleChain
->cElement
; i
++)
500 ret
= data
->psPfns
->pfnAddCert2Chain(data
, signerIdx
, FALSE
, 0,
501 simpleChain
->rgpElement
[i
]->pCertContext
);
503 data
->pasSigners
[signerIdx
].pasCertChain
[i
].pChainElement
=
504 simpleChain
->rgpElement
[i
];
509 HRESULT WINAPI
WintrustCertificateTrust(CRYPT_PROVIDER_DATA
*data
)
513 if (!data
->csSigners
)
516 SetLastError(TRUST_E_NOSIGNATURE
);
523 for (i
= 0; i
< data
->csSigners
; i
++)
525 CERT_CHAIN_PARA chainPara
= { sizeof(chainPara
), { 0 } };
528 if (data
->pRequestUsage
)
529 memcpy(&chainPara
.RequestedUsage
, data
->pRequestUsage
,
530 sizeof(CERT_USAGE_MATCH
));
531 if (data
->dwProvFlags
& CPD_REVOCATION_CHECK_END_CERT
)
532 flags
= CERT_CHAIN_REVOCATION_CHECK_END_CERT
;
533 else if (data
->dwProvFlags
& CPD_REVOCATION_CHECK_CHAIN
)
534 flags
= CERT_CHAIN_REVOCATION_CHECK_CHAIN
;
535 else if (data
->dwProvFlags
& CPD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT
)
536 flags
= CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT
;
539 /* Expect the end certificate for each signer to be the only
542 if (data
->pasSigners
[i
].csCertChain
)
544 /* Create a certificate chain for each signer */
545 ret
= CertGetCertificateChain(NULL
,
546 data
->pasSigners
[i
].pasCertChain
[0].pCert
,
547 NULL
, /* FIXME: use data->pasSigners[i].sftVerifyAsOf? */
548 data
->chStores
? data
->pahStores
[0] : NULL
,
549 &chainPara
, flags
, NULL
, &data
->pasSigners
[i
].pChainContext
);
552 if (data
->pasSigners
[i
].pChainContext
->cChain
!= 1)
554 FIXME("unimplemented for more than 1 simple chain\n");
559 if ((ret
= WINTRUST_CopyChain(data
, i
)))
560 ret
= data
->psPfns
->pfnCertCheckPolicy(data
, i
,
568 data
->padwTrustStepErrors
[TRUSTERROR_STEP_FINAL_CERTPROV
] =
570 return ret
? S_OK
: S_FALSE
;