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
24 #include "wine/debug.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(crypt
);
28 HCERTSTORE WINAPI
CryptGetMessageCertificates(DWORD dwMsgAndCertEncodingType
,
29 HCRYPTPROV_LEGACY hCryptProv
, DWORD dwFlags
, const BYTE
* pbSignedBlob
,
32 CRYPT_DATA_BLOB blob
= { cbSignedBlob
, (LPBYTE
)pbSignedBlob
};
34 TRACE("(%08x, %ld, %d08x %p, %d)\n", dwMsgAndCertEncodingType
, hCryptProv
,
35 dwFlags
, pbSignedBlob
, cbSignedBlob
);
37 return CertOpenStore(CERT_STORE_PROV_PKCS7
, dwMsgAndCertEncodingType
,
38 hCryptProv
, dwFlags
, &blob
);
41 LONG WINAPI
CryptGetMessageSignerCount(DWORD dwMsgEncodingType
,
42 const BYTE
*pbSignedBlob
, DWORD cbSignedBlob
)
47 TRACE("(%08x, %p, %d)\n", dwMsgEncodingType
, pbSignedBlob
, cbSignedBlob
);
49 msg
= CryptMsgOpenToDecode(dwMsgEncodingType
, 0, 0, 0, NULL
, NULL
);
52 if (CryptMsgUpdate(msg
, pbSignedBlob
, cbSignedBlob
, TRUE
))
54 DWORD size
= sizeof(count
);
56 CryptMsgGetParam(msg
, CMSG_SIGNER_COUNT_PARAM
, 0, &count
, &size
);
63 static CERT_INFO
*CRYPT_GetSignerCertInfoFromMsg(HCRYPTMSG msg
,
66 CERT_INFO
*certInfo
= NULL
;
69 if (CryptMsgGetParam(msg
, CMSG_SIGNER_CERT_INFO_PARAM
, dwSignerIndex
, NULL
,
72 certInfo
= CryptMemAlloc(size
);
75 if (!CryptMsgGetParam(msg
, CMSG_SIGNER_CERT_INFO_PARAM
,
76 dwSignerIndex
, certInfo
, &size
))
78 CryptMemFree(certInfo
);
84 SetLastError(CRYPT_E_UNEXPECTED_MSG_TYPE
);
88 static PCCERT_CONTEXT WINAPI
CRYPT_DefaultGetSignerCertificate(void *pvGetArg
,
89 DWORD dwCertEncodingType
, PCERT_INFO pSignerId
, HCERTSTORE hMsgCertStore
)
91 return CertFindCertificateInStore(hMsgCertStore
, dwCertEncodingType
, 0,
92 CERT_FIND_SUBJECT_CERT
, pSignerId
, NULL
);
95 static inline PCCERT_CONTEXT
CRYPT_GetSignerCertificate(HCRYPTMSG msg
,
96 PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara
, PCERT_INFO certInfo
, HCERTSTORE store
)
98 PFN_CRYPT_GET_SIGNER_CERTIFICATE getCert
;
100 if (pVerifyPara
->pfnGetSignerCertificate
)
101 getCert
= pVerifyPara
->pfnGetSignerCertificate
;
103 getCert
= CRYPT_DefaultGetSignerCertificate
;
104 return getCert(pVerifyPara
->pvGetArg
,
105 pVerifyPara
->dwMsgAndCertEncodingType
, certInfo
, store
);
108 BOOL WINAPI
CryptVerifyDetachedMessageSignature(
109 PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara
, DWORD dwSignerIndex
,
110 const BYTE
*pbDetachedSignBlob
, DWORD cbDetachedSignBlob
, DWORD cToBeSigned
,
111 const BYTE
*rgpbToBeSigned
[], DWORD rgcbToBeSigned
[],
112 PCCERT_CONTEXT
*ppSignerCert
)
117 TRACE("(%p, %d, %p, %d, %d, %p, %p, %p)\n", pVerifyPara
, dwSignerIndex
,
118 pbDetachedSignBlob
, cbDetachedSignBlob
, cToBeSigned
, rgpbToBeSigned
,
119 rgcbToBeSigned
, ppSignerCert
);
122 *ppSignerCert
= NULL
;
124 pVerifyPara
->cbSize
!= sizeof(CRYPT_VERIFY_MESSAGE_PARA
) ||
125 GET_CMSG_ENCODING_TYPE(pVerifyPara
->dwMsgAndCertEncodingType
) !=
128 SetLastError(E_INVALIDARG
);
132 msg
= CryptMsgOpenToDecode(pVerifyPara
->dwMsgAndCertEncodingType
,
133 CMSG_DETACHED_FLAG
, 0, pVerifyPara
->hCryptProv
, NULL
, NULL
);
136 ret
= CryptMsgUpdate(msg
, pbDetachedSignBlob
, cbDetachedSignBlob
, TRUE
);
141 for (i
= 0; ret
&& i
< cToBeSigned
; i
++)
142 ret
= CryptMsgUpdate(msg
, rgpbToBeSigned
[i
], rgcbToBeSigned
[i
],
143 i
== cToBeSigned
- 1 ? TRUE
: FALSE
);
147 CERT_INFO
*certInfo
= CRYPT_GetSignerCertInfoFromMsg(msg
,
153 HCERTSTORE store
= CertOpenStore(CERT_STORE_PROV_MSG
,
154 pVerifyPara
->dwMsgAndCertEncodingType
,
155 pVerifyPara
->hCryptProv
, 0, msg
);
159 PCCERT_CONTEXT cert
= CRYPT_GetSignerCertificate(
160 msg
, pVerifyPara
, certInfo
, store
);
164 ret
= CryptMsgControl(msg
, 0,
165 CMSG_CTRL_VERIFY_SIGNATURE
, cert
->pCertInfo
);
166 if (ret
&& ppSignerCert
)
167 *ppSignerCert
= cert
;
169 CertFreeCertificateContext(cert
);
172 SetLastError(CRYPT_E_NOT_FOUND
);
173 CertCloseStore(store
, 0);
175 CryptMemFree(certInfo
);
180 TRACE("returning %d\n", ret
);
184 BOOL WINAPI
CryptVerifyMessageSignature(PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara
,
185 DWORD dwSignerIndex
, const BYTE
* pbSignedBlob
, DWORD cbSignedBlob
,
186 BYTE
* pbDecoded
, DWORD
* pcbDecoded
, PCCERT_CONTEXT
* ppSignerCert
)
191 TRACE("(%p, %d, %p, %d, %p, %p, %p)\n",
192 pVerifyPara
, dwSignerIndex
, pbSignedBlob
, cbSignedBlob
,
193 pbDecoded
, pcbDecoded
, ppSignerCert
);
196 *ppSignerCert
= NULL
;
198 pVerifyPara
->cbSize
!= sizeof(CRYPT_VERIFY_MESSAGE_PARA
) ||
199 GET_CMSG_ENCODING_TYPE(pVerifyPara
->dwMsgAndCertEncodingType
) !=
204 SetLastError(E_INVALIDARG
);
208 msg
= CryptMsgOpenToDecode(pVerifyPara
->dwMsgAndCertEncodingType
, 0, 0,
209 pVerifyPara
->hCryptProv
, NULL
, NULL
);
212 ret
= CryptMsgUpdate(msg
, pbSignedBlob
, cbSignedBlob
, TRUE
);
215 CERT_INFO
*certInfo
= CRYPT_GetSignerCertInfoFromMsg(msg
,
221 HCERTSTORE store
= CertOpenStore(CERT_STORE_PROV_MSG
,
222 pVerifyPara
->dwMsgAndCertEncodingType
,
223 pVerifyPara
->hCryptProv
, 0, msg
);
227 PCCERT_CONTEXT cert
= CRYPT_GetSignerCertificate(
228 msg
, pVerifyPara
, certInfo
, store
);
232 ret
= CryptMsgControl(msg
, 0,
233 CMSG_CTRL_VERIFY_SIGNATURE
, cert
->pCertInfo
);
234 if (ret
&& ppSignerCert
)
235 *ppSignerCert
= cert
;
237 CertFreeCertificateContext(cert
);
239 CertCloseStore(store
, 0);
242 CryptMemFree(certInfo
);
246 /* The caller is expected to pass a valid pointer to pcbDecoded
247 * when the message verifies successfully.
250 ret
= CryptMsgGetParam(msg
, CMSG_CONTENT_PARAM
, 0, pbDecoded
,
254 SetLastError(CRYPT_E_NOT_FOUND
);
260 if(!ret
&& pcbDecoded
)
262 TRACE("returning %d\n", ret
);
266 BOOL WINAPI
CryptHashMessage(PCRYPT_HASH_MESSAGE_PARA pHashPara
,
267 BOOL fDetachedHash
, DWORD cToBeHashed
, const BYTE
*rgpbToBeHashed
[],
268 DWORD rgcbToBeHashed
[], BYTE
*pbHashedBlob
, DWORD
*pcbHashedBlob
,
269 BYTE
*pbComputedHash
, DWORD
*pcbComputedHash
)
274 CMSG_HASHED_ENCODE_INFO info
;
276 TRACE("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n", pHashPara
, fDetachedHash
,
277 cToBeHashed
, rgpbToBeHashed
, rgcbToBeHashed
, pbHashedBlob
, pcbHashedBlob
,
278 pbComputedHash
, pcbComputedHash
);
280 if (pHashPara
->cbSize
!= sizeof(CRYPT_HASH_MESSAGE_PARA
))
282 SetLastError(E_INVALIDARG
);
285 /* Native seems to ignore any encoding type other than the expected
286 * PKCS_7_ASN_ENCODING
288 if (GET_CMSG_ENCODING_TYPE(pHashPara
->dwMsgEncodingType
) !=
291 /* Native also seems to do nothing if the output parameter isn't given */
295 flags
= fDetachedHash
? CMSG_DETACHED_FLAG
: 0;
296 memset(&info
, 0, sizeof(info
));
297 info
.cbSize
= sizeof(info
);
298 info
.hCryptProv
= pHashPara
->hCryptProv
;
299 memcpy(&info
.HashAlgorithm
, &pHashPara
->HashAlgorithm
,
300 sizeof(info
.HashAlgorithm
));
301 info
.pvHashAuxInfo
= pHashPara
->pvHashAuxInfo
;
302 msg
= CryptMsgOpenToEncode(pHashPara
->dwMsgEncodingType
, flags
, CMSG_HASHED
,
306 for (i
= 0, ret
= TRUE
; ret
&& i
< cToBeHashed
; i
++)
307 ret
= CryptMsgUpdate(msg
, rgpbToBeHashed
[i
], rgcbToBeHashed
[i
],
308 i
== cToBeHashed
- 1 ? TRUE
: FALSE
);
311 ret
= CryptMsgGetParam(msg
, CMSG_CONTENT_PARAM
, 0, pbHashedBlob
,
313 if (ret
&& pcbComputedHash
)
314 ret
= CryptMsgGetParam(msg
, CMSG_COMPUTED_HASH_PARAM
, 0,
315 pbComputedHash
, pcbComputedHash
);
322 BOOL WINAPI
CryptVerifyDetachedMessageHash(PCRYPT_HASH_MESSAGE_PARA pHashPara
,
323 BYTE
*pbDetachedHashBlob
, DWORD cbDetachedHashBlob
, DWORD cToBeHashed
,
324 const BYTE
*rgpbToBeHashed
[], DWORD rgcbToBeHashed
[], BYTE
*pbComputedHash
,
325 DWORD
*pcbComputedHash
)
330 TRACE("(%p, %p, %d, %d, %p, %p, %p, %p)\n", pHashPara
, pbDetachedHashBlob
,
331 cbDetachedHashBlob
, cToBeHashed
, rgpbToBeHashed
, rgcbToBeHashed
,
332 pbComputedHash
, pcbComputedHash
);
334 if (pHashPara
->cbSize
!= sizeof(CRYPT_HASH_MESSAGE_PARA
))
336 SetLastError(E_INVALIDARG
);
339 if (GET_CMSG_ENCODING_TYPE(pHashPara
->dwMsgEncodingType
) !=
342 SetLastError(E_INVALIDARG
);
345 msg
= CryptMsgOpenToDecode(pHashPara
->dwMsgEncodingType
, CMSG_DETACHED_FLAG
,
346 0, pHashPara
->hCryptProv
, NULL
, NULL
);
351 ret
= CryptMsgUpdate(msg
, pbDetachedHashBlob
, cbDetachedHashBlob
, TRUE
);
356 for (i
= 0; ret
&& i
< cToBeHashed
; i
++)
358 ret
= CryptMsgUpdate(msg
, rgpbToBeHashed
[i
],
359 rgcbToBeHashed
[i
], i
== cToBeHashed
- 1 ? TRUE
: FALSE
);
363 ret
= CryptMsgUpdate(msg
, NULL
, 0, TRUE
);
367 ret
= CryptMsgControl(msg
, 0, CMSG_CTRL_VERIFY_HASH
, NULL
);
368 if (ret
&& pcbComputedHash
)
369 ret
= CryptMsgGetParam(msg
, CMSG_COMPUTED_HASH_PARAM
, 0,
370 pbComputedHash
, pcbComputedHash
);
377 BOOL WINAPI
CryptVerifyMessageHash(PCRYPT_HASH_MESSAGE_PARA pHashPara
,
378 BYTE
*pbHashedBlob
, DWORD cbHashedBlob
, BYTE
*pbToBeHashed
,
379 DWORD
*pcbToBeHashed
, BYTE
*pbComputedHash
, DWORD
*pcbComputedHash
)
384 TRACE("(%p, %p, %d, %p, %p, %p, %p)\n", pHashPara
, pbHashedBlob
,
385 cbHashedBlob
, pbToBeHashed
, pcbToBeHashed
, pbComputedHash
,
388 if (pHashPara
->cbSize
!= sizeof(CRYPT_HASH_MESSAGE_PARA
))
390 SetLastError(E_INVALIDARG
);
393 if (GET_CMSG_ENCODING_TYPE(pHashPara
->dwMsgEncodingType
) !=
396 SetLastError(E_INVALIDARG
);
399 msg
= CryptMsgOpenToDecode(pHashPara
->dwMsgEncodingType
, 0, 0,
400 pHashPara
->hCryptProv
, NULL
, NULL
);
403 ret
= CryptMsgUpdate(msg
, pbHashedBlob
, cbHashedBlob
, TRUE
);
406 ret
= CryptMsgControl(msg
, 0, CMSG_CTRL_VERIFY_HASH
, NULL
);
407 if (ret
&& pcbToBeHashed
)
408 ret
= CryptMsgGetParam(msg
, CMSG_CONTENT_PARAM
, 0,
409 pbToBeHashed
, pcbToBeHashed
);
410 if (ret
&& pcbComputedHash
)
411 ret
= CryptMsgGetParam(msg
, CMSG_COMPUTED_HASH_PARAM
, 0,
412 pbComputedHash
, pcbComputedHash
);
419 BOOL WINAPI
CryptSignMessage(PCRYPT_SIGN_MESSAGE_PARA pSignPara
,
420 BOOL fDetachedSignature
, DWORD cToBeSigned
, const BYTE
*rgpbToBeSigned
[],
421 DWORD rgcbToBeSigned
[], BYTE
*pbSignedBlob
, DWORD
*pcbSignedBlob
)
423 HCRYPTPROV hCryptProv
;
424 BOOL ret
, freeProv
= FALSE
;
426 PCERT_BLOB certBlob
= NULL
;
427 PCRL_BLOB crlBlob
= NULL
;
428 CMSG_SIGNED_ENCODE_INFO signInfo
;
429 CMSG_SIGNER_ENCODE_INFO signer
;
432 TRACE("(%p, %d, %d, %p, %p, %p, %p)\n", pSignPara
, fDetachedSignature
,
433 cToBeSigned
, rgpbToBeSigned
, rgcbToBeSigned
, pbSignedBlob
, pcbSignedBlob
);
435 if (pSignPara
->cbSize
!= sizeof(CRYPT_SIGN_MESSAGE_PARA
) ||
436 GET_CMSG_ENCODING_TYPE(pSignPara
->dwMsgEncodingType
) !=
440 SetLastError(E_INVALIDARG
);
443 if (!pSignPara
->pSigningCert
)
446 ret
= CryptAcquireCertificatePrivateKey(pSignPara
->pSigningCert
,
447 CRYPT_ACQUIRE_CACHE_FLAG
, NULL
, &hCryptProv
, &keySpec
, &freeProv
);
451 memset(&signer
, 0, sizeof(signer
));
452 signer
.cbSize
= sizeof(signer
);
453 signer
.pCertInfo
= pSignPara
->pSigningCert
->pCertInfo
;
454 signer
.hCryptProv
= hCryptProv
;
455 signer
.dwKeySpec
= keySpec
;
456 signer
.HashAlgorithm
= pSignPara
->HashAlgorithm
;
457 signer
.pvHashAuxInfo
= pSignPara
->pvHashAuxInfo
;
458 signer
.cAuthAttr
= pSignPara
->cAuthAttr
;
459 signer
.rgAuthAttr
= pSignPara
->rgAuthAttr
;
460 signer
.cUnauthAttr
= pSignPara
->cUnauthAttr
;
461 signer
.rgUnauthAttr
= pSignPara
->rgUnauthAttr
;
463 memset(&signInfo
, 0, sizeof(signInfo
));
464 signInfo
.cbSize
= sizeof(signInfo
);
465 signInfo
.cSigners
= 1;
466 signInfo
.rgSigners
= &signer
;
468 if (pSignPara
->cMsgCert
)
470 certBlob
= CryptMemAlloc(sizeof(CERT_BLOB
) * pSignPara
->cMsgCert
);
473 for (i
= 0; i
< pSignPara
->cMsgCert
; ++i
)
475 certBlob
[i
].cbData
= pSignPara
->rgpMsgCert
[i
]->cbCertEncoded
;
476 certBlob
[i
].pbData
= pSignPara
->rgpMsgCert
[i
]->pbCertEncoded
;
478 signInfo
.cCertEncoded
= pSignPara
->cMsgCert
;
479 signInfo
.rgCertEncoded
= certBlob
;
484 if (pSignPara
->cMsgCrl
)
486 crlBlob
= CryptMemAlloc(sizeof(CRL_BLOB
) * pSignPara
->cMsgCrl
);
489 for (i
= 0; i
< pSignPara
->cMsgCrl
; ++i
)
491 crlBlob
[i
].cbData
= pSignPara
->rgpMsgCrl
[i
]->cbCrlEncoded
;
492 crlBlob
[i
].pbData
= pSignPara
->rgpMsgCrl
[i
]->pbCrlEncoded
;
494 signInfo
.cCrlEncoded
= pSignPara
->cMsgCrl
;
495 signInfo
.rgCrlEncoded
= crlBlob
;
500 if (pSignPara
->dwFlags
|| pSignPara
->dwInnerContentType
)
501 FIXME("unimplemented feature\n");
504 msg
= CryptMsgOpenToEncode(pSignPara
->dwMsgEncodingType
,
505 fDetachedSignature
? CMSG_DETACHED_FLAG
: 0, CMSG_SIGNED
, &signInfo
,
511 for (i
= 0; ret
&& i
< cToBeSigned
; ++i
)
513 ret
= CryptMsgUpdate(msg
, rgpbToBeSigned
[i
], rgcbToBeSigned
[i
],
514 i
== cToBeSigned
- 1 ? TRUE
: FALSE
);
518 ret
= CryptMsgUpdate(msg
, NULL
, 0, TRUE
);
520 ret
= CryptMsgGetParam(msg
, CMSG_CONTENT_PARAM
, 0, pbSignedBlob
,
527 CryptMemFree(crlBlob
);
528 CryptMemFree(certBlob
);
530 CryptReleaseContext(hCryptProv
, 0);
534 BOOL WINAPI
CryptEncryptMessage(PCRYPT_ENCRYPT_MESSAGE_PARA pEncryptPara
,
535 DWORD cRecipientCert
, PCCERT_CONTEXT rgpRecipientCert
[],
536 const BYTE
*pbToBeEncrypted
, DWORD cbToBeEncrypted
, BYTE
*pbEncryptedBlob
,
537 DWORD
*pcbEncryptedBlob
)
541 PCERT_INFO
*certInfo
= NULL
;
542 CMSG_ENVELOPED_ENCODE_INFO envelopedInfo
;
545 TRACE("(%p, %d, %p, %p, %d, %p, %p)\n", pEncryptPara
, cRecipientCert
,
546 rgpRecipientCert
, pbToBeEncrypted
, cbToBeEncrypted
, pbEncryptedBlob
,
549 if (pEncryptPara
->cbSize
!= sizeof(CRYPT_ENCRYPT_MESSAGE_PARA
) ||
550 GET_CMSG_ENCODING_TYPE(pEncryptPara
->dwMsgEncodingType
) !=
553 *pcbEncryptedBlob
= 0;
554 SetLastError(E_INVALIDARG
);
558 memset(&envelopedInfo
, 0, sizeof(envelopedInfo
));
559 envelopedInfo
.cbSize
= sizeof(envelopedInfo
);
560 envelopedInfo
.hCryptProv
= pEncryptPara
->hCryptProv
;
561 envelopedInfo
.ContentEncryptionAlgorithm
=
562 pEncryptPara
->ContentEncryptionAlgorithm
;
563 envelopedInfo
.pvEncryptionAuxInfo
= pEncryptPara
->pvEncryptionAuxInfo
;
567 certInfo
= CryptMemAlloc(sizeof(PCERT_INFO
) * cRecipientCert
);
570 for (i
= 0; i
< cRecipientCert
; ++i
)
571 certInfo
[i
] = rgpRecipientCert
[i
]->pCertInfo
;
572 envelopedInfo
.cRecipients
= cRecipientCert
;
573 envelopedInfo
.rgpRecipientCert
= certInfo
;
580 msg
= CryptMsgOpenToEncode(pEncryptPara
->dwMsgEncodingType
, 0,
581 CMSG_ENVELOPED
, &envelopedInfo
, NULL
, NULL
);
584 ret
= CryptMsgUpdate(msg
, pbToBeEncrypted
, cbToBeEncrypted
, TRUE
);
586 ret
= CryptMsgGetParam(msg
, CMSG_CONTENT_PARAM
, 0, pbEncryptedBlob
,
593 CryptMemFree(certInfo
);
594 if (!ret
) *pcbEncryptedBlob
= 0;