crypt32: Allow messages to be opened when compiled with CMSG_SIGNED_ENCODE_INFO_HAS_C...
[wine/gsoc_dplay.git] / dlls / crypt32 / msg.c
blobad4ba959d22b3694cbacc3fd5a94fa6e5d569b81
1 /*
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
19 #include "config.h"
20 #include "wine/port.h"
22 #include <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wincrypt.h"
26 #include "snmp.h"
28 #include "wine/debug.h"
29 #include "wine/exception.h"
30 #include "crypt32_private.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
34 /* Called when a message's ref count reaches zero. Free any message-specific
35 * data here.
37 typedef void (*CryptMsgCloseFunc)(HCRYPTMSG msg);
39 typedef BOOL (*CryptMsgGetParamFunc)(HCRYPTMSG hCryptMsg, DWORD dwParamType,
40 DWORD dwIndex, void *pvData, DWORD *pcbData);
42 typedef BOOL (*CryptMsgUpdateFunc)(HCRYPTMSG hCryptMsg, const BYTE *pbData,
43 DWORD cbData, BOOL fFinal);
45 typedef BOOL (*CryptMsgControlFunc)(HCRYPTMSG hCryptMsg, DWORD dwFlags,
46 DWORD dwCtrlType, const void *pvCtrlPara);
48 BOOL CRYPT_DefaultMsgControl(HCRYPTMSG hCryptMsg, DWORD dwFlags,
49 DWORD dwCtrlType, const void *pvCtrlPara)
51 TRACE("(%p, %08x, %d, %p)\n", hCryptMsg, dwFlags, dwCtrlType, pvCtrlPara);
52 SetLastError(E_INVALIDARG);
53 return FALSE;
56 typedef enum _CryptMsgState {
57 MsgStateInit,
58 MsgStateUpdated,
59 MsgStateDataFinalized,
60 MsgStateFinalized
61 } CryptMsgState;
63 typedef struct _CryptMsgBase
65 LONG ref;
66 DWORD open_flags;
67 BOOL streamed;
68 CMSG_STREAM_INFO stream_info;
69 CryptMsgState state;
70 CryptMsgCloseFunc close;
71 CryptMsgUpdateFunc update;
72 CryptMsgGetParamFunc get_param;
73 CryptMsgControlFunc control;
74 } CryptMsgBase;
76 static inline void CryptMsgBase_Init(CryptMsgBase *msg, DWORD dwFlags,
77 PCMSG_STREAM_INFO pStreamInfo, CryptMsgCloseFunc close,
78 CryptMsgGetParamFunc get_param, CryptMsgUpdateFunc update,
79 CryptMsgControlFunc control)
81 msg->ref = 1;
82 msg->open_flags = dwFlags;
83 if (pStreamInfo)
85 msg->streamed = TRUE;
86 msg->stream_info = *pStreamInfo;
88 else
90 msg->streamed = FALSE;
91 memset(&msg->stream_info, 0, sizeof(msg->stream_info));
93 msg->close = close;
94 msg->get_param = get_param;
95 msg->update = update;
96 msg->control = control;
97 msg->state = MsgStateInit;
100 typedef struct _CDataEncodeMsg
102 CryptMsgBase base;
103 DWORD bare_content_len;
104 LPBYTE bare_content;
105 } CDataEncodeMsg;
107 static const BYTE empty_data_content[] = { 0x04,0x00 };
109 static void CDataEncodeMsg_Close(HCRYPTMSG hCryptMsg)
111 CDataEncodeMsg *msg = (CDataEncodeMsg *)hCryptMsg;
113 if (msg->bare_content != empty_data_content)
114 LocalFree(msg->bare_content);
117 static BOOL WINAPI CRYPT_EncodeContentLength(DWORD dwCertEncodingType,
118 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
119 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
121 DWORD dataLen = *(DWORD *)pvStructInfo;
122 DWORD lenBytes;
123 BOOL ret = TRUE;
125 /* Trick: report bytes needed based on total message length, even though
126 * the message isn't available yet. The caller will use the length
127 * reported here to encode its length.
129 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
130 if (!pbEncoded)
131 *pcbEncoded = 1 + lenBytes + dataLen;
132 else
134 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
135 pcbEncoded, 1 + lenBytes)))
137 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
138 pbEncoded = *(BYTE **)pbEncoded;
139 *pbEncoded++ = ASN_OCTETSTRING;
140 CRYPT_EncodeLen(dataLen, pbEncoded,
141 &lenBytes);
144 return ret;
147 static BOOL CRYPT_EncodeDataContentInfoHeader(CDataEncodeMsg *msg,
148 CRYPT_DATA_BLOB *header)
150 BOOL ret;
152 if (msg->base.streamed && msg->base.stream_info.cbContent == 0xffffffff)
154 static const BYTE headerValue[] = { 0x30,0x80,0x06,0x09,0x2a,0x86,0x48,
155 0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x80,0x24,0x80 };
157 header->pbData = LocalAlloc(0, sizeof(headerValue));
158 if (header->pbData)
160 header->cbData = sizeof(headerValue);
161 memcpy(header->pbData, headerValue, sizeof(headerValue));
162 ret = TRUE;
164 else
165 ret = FALSE;
167 else
169 struct AsnConstructedItem constructed = { 0,
170 &msg->base.stream_info.cbContent, CRYPT_EncodeContentLength };
171 struct AsnEncodeSequenceItem items[2] = {
172 { szOID_RSA_data, CRYPT_AsnEncodeOid, 0 },
173 { &constructed, CRYPT_AsnEncodeConstructed, 0 },
176 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items,
177 sizeof(items) / sizeof(items[0]), CRYPT_ENCODE_ALLOC_FLAG, NULL,
178 (LPBYTE)&header->pbData, &header->cbData);
179 if (ret)
181 /* Trick: subtract the content length from the reported length,
182 * as the actual content hasn't come yet.
184 header->cbData -= msg->base.stream_info.cbContent;
187 return ret;
190 static BOOL CDataEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
191 DWORD cbData, BOOL fFinal)
193 CDataEncodeMsg *msg = (CDataEncodeMsg *)hCryptMsg;
194 BOOL ret = FALSE;
196 if (msg->base.state == MsgStateFinalized)
197 SetLastError(CRYPT_E_MSG_ERROR);
198 else if (msg->base.streamed)
200 __TRY
202 if (msg->base.state != MsgStateUpdated)
204 CRYPT_DATA_BLOB header;
206 ret = CRYPT_EncodeDataContentInfoHeader(msg, &header);
207 if (ret)
209 ret = msg->base.stream_info.pfnStreamOutput(
210 msg->base.stream_info.pvArg, header.pbData, header.cbData,
211 FALSE);
212 LocalFree(header.pbData);
215 /* Curiously, every indefinite-length streamed update appears to
216 * get its own tag and length, regardless of fFinal.
218 if (msg->base.stream_info.cbContent == 0xffffffff)
220 BYTE *header;
221 DWORD headerLen;
223 ret = CRYPT_EncodeContentLength(X509_ASN_ENCODING, NULL,
224 &cbData, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&header,
225 &headerLen);
226 if (ret)
228 ret = msg->base.stream_info.pfnStreamOutput(
229 msg->base.stream_info.pvArg, header, headerLen,
230 FALSE);
231 LocalFree(header);
234 if (!fFinal)
236 ret = msg->base.stream_info.pfnStreamOutput(
237 msg->base.stream_info.pvArg, (BYTE *)pbData, cbData,
238 FALSE);
239 msg->base.state = MsgStateUpdated;
241 else
243 msg->base.state = MsgStateFinalized;
244 if (msg->base.stream_info.cbContent == 0xffffffff)
246 BYTE indefinite_trailer[6] = { 0 };
248 ret = msg->base.stream_info.pfnStreamOutput(
249 msg->base.stream_info.pvArg, (BYTE *)pbData, cbData,
250 FALSE);
251 if (ret)
252 ret = msg->base.stream_info.pfnStreamOutput(
253 msg->base.stream_info.pvArg, indefinite_trailer,
254 sizeof(indefinite_trailer), TRUE);
256 else
257 ret = msg->base.stream_info.pfnStreamOutput(
258 msg->base.stream_info.pvArg, (BYTE *)pbData, cbData, TRUE);
261 __EXCEPT_PAGE_FAULT
263 SetLastError(STATUS_ACCESS_VIOLATION);
264 ret = FALSE;
266 __ENDTRY;
268 else
270 if (!fFinal)
272 if (msg->base.open_flags & CMSG_DETACHED_FLAG)
273 SetLastError(E_INVALIDARG);
274 else
275 SetLastError(CRYPT_E_MSG_ERROR);
277 else
279 msg->base.state = MsgStateFinalized;
280 if (!cbData)
281 SetLastError(E_INVALIDARG);
282 else
284 CRYPT_DATA_BLOB blob = { cbData, (LPBYTE)pbData };
286 /* non-streamed data messages don't allow non-final updates,
287 * don't bother checking whether data already exist, they can't.
289 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING,
290 &blob, CRYPT_ENCODE_ALLOC_FLAG, NULL, &msg->bare_content,
291 &msg->bare_content_len);
295 return ret;
298 static BOOL CRYPT_CopyParam(void *pvData, DWORD *pcbData, const void *src,
299 DWORD len)
301 BOOL ret = TRUE;
303 if (!pvData)
304 *pcbData = len;
305 else if (*pcbData < len)
307 *pcbData = len;
308 SetLastError(ERROR_MORE_DATA);
309 ret = FALSE;
311 else
313 *pcbData = len;
314 memcpy(pvData, src, len);
316 return ret;
319 static BOOL CDataEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
320 DWORD dwIndex, void *pvData, DWORD *pcbData)
322 CDataEncodeMsg *msg = (CDataEncodeMsg *)hCryptMsg;
323 BOOL ret = FALSE;
325 switch (dwParamType)
327 case CMSG_CONTENT_PARAM:
328 if (msg->base.streamed)
329 SetLastError(E_INVALIDARG);
330 else
332 CRYPT_CONTENT_INFO info;
333 char rsa_data[] = "1.2.840.113549.1.7.1";
335 info.pszObjId = rsa_data;
336 info.Content.cbData = msg->bare_content_len;
337 info.Content.pbData = msg->bare_content;
338 ret = CryptEncodeObject(X509_ASN_ENCODING, PKCS_CONTENT_INFO, &info,
339 pvData, pcbData);
341 break;
342 case CMSG_BARE_CONTENT_PARAM:
343 if (msg->base.streamed)
344 SetLastError(E_INVALIDARG);
345 else
346 ret = CRYPT_CopyParam(pvData, pcbData, msg->bare_content,
347 msg->bare_content_len);
348 break;
349 default:
350 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
352 return ret;
355 static HCRYPTMSG CDataEncodeMsg_Open(DWORD dwFlags, const void *pvMsgEncodeInfo,
356 LPSTR pszInnerContentObjID, PCMSG_STREAM_INFO pStreamInfo)
358 CDataEncodeMsg *msg;
360 if (pvMsgEncodeInfo)
362 SetLastError(E_INVALIDARG);
363 return NULL;
365 msg = CryptMemAlloc(sizeof(CDataEncodeMsg));
366 if (msg)
368 CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo,
369 CDataEncodeMsg_Close, CDataEncodeMsg_GetParam, CDataEncodeMsg_Update,
370 CRYPT_DefaultMsgControl);
371 msg->bare_content_len = sizeof(empty_data_content);
372 msg->bare_content = (LPBYTE)empty_data_content;
374 return (HCRYPTMSG)msg;
377 typedef struct _CHashEncodeMsg
379 CryptMsgBase base;
380 HCRYPTPROV prov;
381 HCRYPTHASH hash;
382 CRYPT_DATA_BLOB data;
383 } CHashEncodeMsg;
385 static void CHashEncodeMsg_Close(HCRYPTMSG hCryptMsg)
387 CHashEncodeMsg *msg = (CHashEncodeMsg *)hCryptMsg;
389 CryptMemFree(msg->data.pbData);
390 CryptDestroyHash(msg->hash);
391 if (msg->base.open_flags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG)
392 CryptReleaseContext(msg->prov, 0);
395 static BOOL CRYPT_EncodePKCSDigestedData(CHashEncodeMsg *msg, void *pvData,
396 DWORD *pcbData)
398 BOOL ret;
399 ALG_ID algID;
400 DWORD size = sizeof(algID);
402 ret = CryptGetHashParam(msg->hash, HP_ALGID, (BYTE *)&algID, &size, 0);
403 if (ret)
405 CRYPT_DIGESTED_DATA digestedData = { 0 };
406 char oid_rsa_data[] = szOID_RSA_data;
408 digestedData.version = CMSG_HASHED_DATA_PKCS_1_5_VERSION;
409 digestedData.DigestAlgorithm.pszObjId = (LPSTR)CertAlgIdToOID(algID);
410 /* FIXME: what about digestedData.DigestAlgorithm.Parameters? */
411 /* Quirk: OID is only encoded messages if an update has happened */
412 if (msg->base.state != MsgStateInit)
413 digestedData.ContentInfo.pszObjId = oid_rsa_data;
414 if (!(msg->base.open_flags & CMSG_DETACHED_FLAG) && msg->data.cbData)
416 ret = CRYPT_AsnEncodeOctets(0, NULL, &msg->data,
417 CRYPT_ENCODE_ALLOC_FLAG, NULL,
418 (LPBYTE)&digestedData.ContentInfo.Content.pbData,
419 &digestedData.ContentInfo.Content.cbData);
421 if (msg->base.state == MsgStateFinalized)
423 size = sizeof(DWORD);
424 ret = CryptGetHashParam(msg->hash, HP_HASHSIZE,
425 (LPBYTE)&digestedData.hash.cbData, &size, 0);
426 if (ret)
428 digestedData.hash.pbData = CryptMemAlloc(
429 digestedData.hash.cbData);
430 ret = CryptGetHashParam(msg->hash, HP_HASHVAL,
431 digestedData.hash.pbData, &digestedData.hash.cbData, 0);
434 if (ret)
435 ret = CRYPT_AsnEncodePKCSDigestedData(&digestedData, pvData,
436 pcbData);
437 CryptMemFree(digestedData.hash.pbData);
438 LocalFree(digestedData.ContentInfo.Content.pbData);
440 return ret;
443 static BOOL CHashEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
444 DWORD dwIndex, void *pvData, DWORD *pcbData)
446 CHashEncodeMsg *msg = (CHashEncodeMsg *)hCryptMsg;
447 BOOL ret = FALSE;
449 TRACE("(%p, %d, %d, %p, %p)\n", hCryptMsg, dwParamType, dwIndex,
450 pvData, pcbData);
452 switch (dwParamType)
454 case CMSG_BARE_CONTENT_PARAM:
455 if (msg->base.streamed)
456 SetLastError(E_INVALIDARG);
457 else
458 ret = CRYPT_EncodePKCSDigestedData(msg, pvData, pcbData);
459 break;
460 case CMSG_CONTENT_PARAM:
462 CRYPT_CONTENT_INFO info;
464 ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0, NULL,
465 &info.Content.cbData);
466 if (ret)
468 info.Content.pbData = CryptMemAlloc(info.Content.cbData);
469 if (info.Content.pbData)
471 ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0,
472 info.Content.pbData, &info.Content.cbData);
473 if (ret)
475 char oid_rsa_hashed[] = szOID_RSA_hashedData;
477 info.pszObjId = oid_rsa_hashed;
478 ret = CryptEncodeObjectEx(X509_ASN_ENCODING,
479 PKCS_CONTENT_INFO, &info, 0, NULL, pvData, pcbData);
481 CryptMemFree(info.Content.pbData);
483 else
484 ret = FALSE;
486 break;
488 case CMSG_COMPUTED_HASH_PARAM:
489 ret = CryptGetHashParam(msg->hash, HP_HASHVAL, (BYTE *)pvData, pcbData,
491 break;
492 case CMSG_VERSION_PARAM:
493 if (msg->base.state != MsgStateFinalized)
494 SetLastError(CRYPT_E_MSG_ERROR);
495 else
497 DWORD version = CMSG_HASHED_DATA_PKCS_1_5_VERSION;
499 /* Since the data are always encoded as octets, the version is
500 * always 0 (see rfc3852, section 7)
502 ret = CRYPT_CopyParam(pvData, pcbData, &version, sizeof(version));
504 break;
505 default:
506 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
508 return ret;
511 static BOOL CHashEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
512 DWORD cbData, BOOL fFinal)
514 CHashEncodeMsg *msg = (CHashEncodeMsg *)hCryptMsg;
515 BOOL ret = FALSE;
517 TRACE("(%p, %p, %d, %d)\n", hCryptMsg, pbData, cbData, fFinal);
519 if (msg->base.state == MsgStateFinalized)
520 SetLastError(CRYPT_E_MSG_ERROR);
521 else if (msg->base.streamed || (msg->base.open_flags & CMSG_DETACHED_FLAG))
523 /* Doesn't do much, as stream output is never called, and you
524 * can't get the content.
526 ret = CryptHashData(msg->hash, pbData, cbData, 0);
527 msg->base.state = fFinal ? MsgStateFinalized : MsgStateUpdated;
529 else
531 if (!fFinal)
532 SetLastError(CRYPT_E_MSG_ERROR);
533 else
535 ret = CryptHashData(msg->hash, pbData, cbData, 0);
536 if (ret)
538 msg->data.pbData = CryptMemAlloc(cbData);
539 if (msg->data.pbData)
541 memcpy(msg->data.pbData + msg->data.cbData, pbData, cbData);
542 msg->data.cbData += cbData;
544 else
545 ret = FALSE;
547 msg->base.state = MsgStateFinalized;
550 return ret;
553 static HCRYPTMSG CHashEncodeMsg_Open(DWORD dwFlags, const void *pvMsgEncodeInfo,
554 LPSTR pszInnerContentObjID, PCMSG_STREAM_INFO pStreamInfo)
556 CHashEncodeMsg *msg;
557 const CMSG_HASHED_ENCODE_INFO *info =
558 (const CMSG_HASHED_ENCODE_INFO *)pvMsgEncodeInfo;
559 HCRYPTPROV prov;
560 ALG_ID algID;
562 if (info->cbSize != sizeof(CMSG_HASHED_ENCODE_INFO))
564 SetLastError(E_INVALIDARG);
565 return NULL;
567 if (!(algID = CertOIDToAlgId(info->HashAlgorithm.pszObjId)))
569 SetLastError(CRYPT_E_UNKNOWN_ALGO);
570 return NULL;
572 if (info->hCryptProv)
573 prov = info->hCryptProv;
574 else
576 prov = CRYPT_GetDefaultProvider();
577 dwFlags &= ~CMSG_CRYPT_RELEASE_CONTEXT_FLAG;
579 msg = CryptMemAlloc(sizeof(CHashEncodeMsg));
580 if (msg)
582 CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo,
583 CHashEncodeMsg_Close, CHashEncodeMsg_GetParam, CHashEncodeMsg_Update,
584 CRYPT_DefaultMsgControl);
585 msg->prov = prov;
586 msg->data.cbData = 0;
587 msg->data.pbData = NULL;
588 if (!CryptCreateHash(prov, algID, 0, 0, &msg->hash))
590 CryptMsgClose(msg);
591 msg = NULL;
594 return (HCRYPTMSG)msg;
597 typedef struct _CMSG_SIGNER_ENCODE_INFO_WITH_CMS
599 DWORD cbSize;
600 PCERT_INFO pCertInfo;
601 HCRYPTPROV hCryptProv;
602 DWORD dwKeySpec;
603 CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm;
604 void *pvHashAuxInfo;
605 DWORD cAuthAttr;
606 PCRYPT_ATTRIBUTE rgAuthAttr;
607 DWORD cUnauthAttr;
608 PCRYPT_ATTRIBUTE rgUnauthAttr;
609 CERT_ID SignerId;
610 CRYPT_ALGORITHM_IDENTIFIER HashEncryptionAlgorithm;
611 void *pvHashEncryptionAuxInfo;
612 } CMSG_SIGNER_ENCODE_INFO_WITH_CMS, *PCMSG_SIGNER_ENCODE_INFO_WITH_CMS;
614 typedef struct _CMSG_SIGNED_ENCODE_INFO_WITH_CMS
616 DWORD cbSize;
617 DWORD cSigners;
618 PCMSG_SIGNER_ENCODE_INFO_WITH_CMS rgSigners;
619 DWORD cCertEncoded;
620 PCERT_BLOB rgCertEncoded;
621 DWORD cCrlEncoded;
622 PCRL_BLOB rgCrlEncoded;
623 DWORD cAttrCertEncoded;
624 PCERT_BLOB rgAttrCertEncoded;
625 } CMSG_SIGNED_ENCODE_INFO_WITH_CMS, *PCMSG_SIGNED_ENCODE_INFO_WITH_CMS;
627 static BOOL CRYPT_IsValidSigner(CMSG_SIGNER_ENCODE_INFO_WITH_CMS *signer)
629 if (signer->cbSize != sizeof(CMSG_SIGNER_ENCODE_INFO) &&
630 signer->cbSize != sizeof(CMSG_SIGNER_ENCODE_INFO_WITH_CMS))
632 SetLastError(E_INVALIDARG);
633 return FALSE;
635 if (!signer->pCertInfo->SerialNumber.cbData)
637 SetLastError(E_INVALIDARG);
638 return FALSE;
640 if (!signer->pCertInfo->Issuer.cbData)
642 SetLastError(E_INVALIDARG);
643 return FALSE;
645 if (!signer->hCryptProv)
647 SetLastError(E_INVALIDARG);
648 return FALSE;
650 if (!CertOIDToAlgId(signer->HashAlgorithm.pszObjId))
652 SetLastError(CRYPT_E_UNKNOWN_ALGO);
653 return FALSE;
655 if (signer->cbSize == sizeof(CMSG_SIGNER_ENCODE_INFO_WITH_CMS))
657 if (signer->SignerId.dwIdChoice)
659 FIXME("CMSG_SIGNER_ENCODE_INFO with CMS fields unsupported\n");
660 return FALSE;
662 if (signer->HashEncryptionAlgorithm.pszObjId)
664 FIXME("CMSG_SIGNER_ENCODE_INFO with CMS fields unsupported\n");
665 return FALSE;
668 return TRUE;
671 static BOOL CRYPT_ConstructBlob(CRYPT_DATA_BLOB *out, const CRYPT_DATA_BLOB *in)
673 BOOL ret = TRUE;
675 out->cbData = in->cbData;
676 if (out->cbData)
678 out->pbData = CryptMemAlloc(out->cbData);
679 if (out->pbData)
680 memcpy(out->pbData, in->pbData, out->cbData);
681 else
682 ret = FALSE;
684 else
685 out->pbData = NULL;
686 return ret;
689 typedef struct _BlobArray
691 DWORD cBlobs;
692 PCRYPT_DATA_BLOB blobs;
693 } BlobArray;
695 static BOOL CRYPT_ConstructBlobArray(BlobArray *out, const BlobArray *in)
697 BOOL ret = TRUE;
699 out->cBlobs = in->cBlobs;
700 if (out->cBlobs)
702 out->blobs = CryptMemAlloc(out->cBlobs * sizeof(CRYPT_DATA_BLOB));
703 if (out->blobs)
705 DWORD i;
707 memset(out->blobs, 0, out->cBlobs * sizeof(CRYPT_DATA_BLOB));
708 for (i = 0; ret && i < out->cBlobs; i++)
709 ret = CRYPT_ConstructBlob(&out->blobs[i], &in->blobs[i]);
711 else
712 ret = FALSE;
714 return ret;
717 static void CRYPT_FreeBlobArray(BlobArray *array)
719 DWORD i;
721 for (i = 0; i < array->cBlobs; i++)
722 CryptMemFree(array->blobs[i].pbData);
723 CryptMemFree(array->blobs);
726 static BOOL CRYPT_ConstructAttribute(CRYPT_ATTRIBUTE *out,
727 const CRYPT_ATTRIBUTE *in)
729 BOOL ret;
731 out->pszObjId = CryptMemAlloc(strlen(in->pszObjId) + 1);
732 if (out->pszObjId)
734 strcpy(out->pszObjId, in->pszObjId);
735 ret = CRYPT_ConstructBlobArray((BlobArray *)&out->cValue,
736 (const BlobArray *)&in->cValue);
738 else
739 ret = FALSE;
740 return ret;
743 static BOOL CRYPT_ConstructAttributes(CRYPT_ATTRIBUTES *out,
744 const CRYPT_ATTRIBUTES *in)
746 BOOL ret = TRUE;
748 out->cAttr = in->cAttr;
749 if (out->cAttr)
751 out->rgAttr = CryptMemAlloc(out->cAttr * sizeof(CRYPT_ATTRIBUTE));
752 if (out->rgAttr)
754 DWORD i;
756 memset(out->rgAttr, 0, out->cAttr * sizeof(CRYPT_ATTRIBUTE));
757 for (i = 0; ret && i < out->cAttr; i++)
758 ret = CRYPT_ConstructAttribute(&out->rgAttr[i], &in->rgAttr[i]);
760 else
761 ret = FALSE;
763 else
764 out->rgAttr = NULL;
765 return ret;
768 /* Constructs a CMSG_SIGNER_INFO from a CMSG_SIGNER_ENCODE_INFO_WITH_CMS. */
769 static BOOL CSignerInfo_Construct(CMSG_SIGNER_INFO *info,
770 CMSG_SIGNER_ENCODE_INFO_WITH_CMS *in)
772 BOOL ret;
774 /* Note: needs to change if CMS fields are supported */
775 info->dwVersion = CMSG_SIGNER_INFO_V1;
776 ret = CRYPT_ConstructBlob(&info->Issuer, &in->pCertInfo->Issuer);
777 if (ret)
778 ret = CRYPT_ConstructBlob(&info->SerialNumber,
779 &in->pCertInfo->SerialNumber);
780 /* Assumption: algorithm IDs will point to static strings, not
781 * stack-based ones, so copying the pointer values is safe.
783 info->HashAlgorithm.pszObjId = in->HashAlgorithm.pszObjId;
784 if (ret)
785 ret = CRYPT_ConstructBlob(&info->HashAlgorithm.Parameters,
786 &in->HashAlgorithm.Parameters);
787 memset(&info->HashEncryptionAlgorithm, 0,
788 sizeof(info->HashEncryptionAlgorithm));
789 if (ret)
790 ret = CRYPT_ConstructAttributes(&info->AuthAttrs,
791 (CRYPT_ATTRIBUTES *)&in->cAuthAttr);
792 if (ret)
793 ret = CRYPT_ConstructAttributes(&info->UnauthAttrs,
794 (CRYPT_ATTRIBUTES *)&in->cUnauthAttr);
795 return ret;
798 static void CSignerInfo_Free(CMSG_SIGNER_INFO *info)
800 DWORD i, j;
802 CryptMemFree(info->Issuer.pbData);
803 CryptMemFree(info->SerialNumber.pbData);
804 CryptMemFree(info->HashAlgorithm.Parameters.pbData);
805 CryptMemFree(info->EncryptedHash.pbData);
806 for (i = 0; i < info->AuthAttrs.cAttr; i++)
808 for (j = 0; j < info->AuthAttrs.rgAttr[i].cValue; j++)
809 CryptMemFree(info->AuthAttrs.rgAttr[i].rgValue[j].pbData);
810 CryptMemFree(info->AuthAttrs.rgAttr[i].rgValue);
811 CryptMemFree(info->AuthAttrs.rgAttr[i].pszObjId);
813 CryptMemFree(info->AuthAttrs.rgAttr);
814 for (i = 0; i < info->UnauthAttrs.cAttr; i++)
816 for (j = 0; j < info->UnauthAttrs.rgAttr[i].cValue; j++)
817 CryptMemFree(info->UnauthAttrs.rgAttr[i].rgValue[j].pbData);
818 CryptMemFree(info->UnauthAttrs.rgAttr[i].rgValue);
819 CryptMemFree(info->UnauthAttrs.rgAttr[i].pszObjId);
821 CryptMemFree(info->UnauthAttrs.rgAttr);
824 typedef struct _CSignerHandles
826 HCRYPTHASH contentHash;
827 HCRYPTHASH authAttrHash;
828 } CSignerHandles;
830 typedef struct _CSignedMsgData
832 CRYPT_SIGNED_INFO *info;
833 DWORD cSignerHandle;
834 CSignerHandles *signerHandles;
835 } CSignedMsgData;
837 /* Constructs the signer handles for the signerIndex'th signer of msg_data.
838 * Assumes signerIndex is a valid idnex, and that msg_data's info has already
839 * been constructed.
841 static BOOL CSignedMsgData_ConstructSignerHandles(CSignedMsgData *msg_data,
842 DWORD signerIndex, HCRYPTPROV crypt_prov)
844 ALG_ID algID;
845 BOOL ret;
847 algID = CertOIDToAlgId(
848 msg_data->info->rgSignerInfo[signerIndex].HashAlgorithm.pszObjId);
849 ret = CryptCreateHash(crypt_prov, algID, 0, 0,
850 &msg_data->signerHandles->contentHash);
851 if (ret && msg_data->info->rgSignerInfo[signerIndex].AuthAttrs.cAttr > 0)
852 ret = CryptCreateHash(crypt_prov, algID, 0, 0,
853 &msg_data->signerHandles->authAttrHash);
854 return ret;
857 /* Allocates a CSignedMsgData's handles. Assumes its info has already been
858 * constructed.
860 static BOOL CSignedMsgData_AllocateHandles(CSignedMsgData *msg_data)
862 BOOL ret = TRUE;
864 if (msg_data->info->cSignerInfo)
866 msg_data->signerHandles =
867 CryptMemAlloc(msg_data->info->cSignerInfo * sizeof(CSignerHandles));
868 if (msg_data->signerHandles)
870 msg_data->cSignerHandle = msg_data->info->cSignerInfo;
871 memset(msg_data->signerHandles, 0,
872 msg_data->info->cSignerInfo * sizeof(CSignerHandles));
874 else
876 msg_data->cSignerHandle = 0;
877 ret = FALSE;
880 else
882 msg_data->cSignerHandle = 0;
883 msg_data->signerHandles = NULL;
885 return ret;
888 static void CSignedMsgData_CloseHandles(CSignedMsgData *msg_data)
890 DWORD i;
892 for (i = 0; i < msg_data->cSignerHandle; i++)
894 if (msg_data->signerHandles[i].contentHash)
895 CryptDestroyHash(msg_data->signerHandles[i].contentHash);
896 if (msg_data->signerHandles[i].authAttrHash)
897 CryptDestroyHash(msg_data->signerHandles[i].authAttrHash);
899 CryptMemFree(msg_data->signerHandles);
900 msg_data->signerHandles = NULL;
901 msg_data->cSignerHandle = 0;
904 static BOOL CSignedMsgData_UpdateHash(CSignedMsgData *msg_data,
905 const BYTE *pbData, DWORD cbData)
907 DWORD i;
908 BOOL ret = TRUE;
910 for (i = 0; ret && i < msg_data->cSignerHandle; i++)
911 ret = CryptHashData(msg_data->signerHandles[i].contentHash, pbData,
912 cbData, 0);
913 return ret;
916 static BOOL CRYPT_AppendAttribute(CRYPT_ATTRIBUTES *out,
917 const CRYPT_ATTRIBUTE *in)
919 BOOL ret = FALSE;
921 out->rgAttr = CryptMemRealloc(out->rgAttr,
922 (out->cAttr + 1) * sizeof(CRYPT_ATTRIBUTE));
923 if (out->rgAttr)
925 ret = CRYPT_ConstructAttribute(&out->rgAttr[out->cAttr], in);
926 if (ret)
927 out->cAttr++;
929 return ret;
932 static BOOL CSignedMsgData_AppendMessageDigestAttribute(
933 CSignedMsgData *msg_data, DWORD signerIndex)
935 BOOL ret;
936 DWORD size;
937 CRYPT_HASH_BLOB hash = { 0, NULL }, encodedHash = { 0, NULL };
938 char messageDigest[] = szOID_RSA_messageDigest;
939 CRYPT_ATTRIBUTE messageDigestAttr = { messageDigest, 1, &encodedHash };
941 size = sizeof(DWORD);
942 ret = CryptGetHashParam(
943 msg_data->signerHandles[signerIndex].contentHash, HP_HASHSIZE,
944 (LPBYTE)&hash.cbData, &size, 0);
945 if (ret)
947 hash.pbData = CryptMemAlloc(hash.cbData);
948 ret = CryptGetHashParam(
949 msg_data->signerHandles[signerIndex].contentHash, HP_HASHVAL,
950 hash.pbData, &hash.cbData, 0);
951 if (ret)
953 ret = CRYPT_AsnEncodeOctets(0, NULL, &hash, CRYPT_ENCODE_ALLOC_FLAG,
954 NULL, (LPBYTE)&encodedHash.pbData, &encodedHash.cbData);
955 if (ret)
957 ret = CRYPT_AppendAttribute(
958 &msg_data->info->rgSignerInfo[signerIndex].AuthAttrs,
959 &messageDigestAttr);
960 LocalFree(encodedHash.pbData);
963 CryptMemFree(hash.pbData);
965 return ret;
968 typedef enum {
969 Sign,
970 Verify
971 } SignOrVerify;
973 static BOOL CSignedMsgData_UpdateAuthenticatedAttributes(
974 CSignedMsgData *msg_data, SignOrVerify flag)
976 DWORD i;
977 BOOL ret = TRUE;
979 TRACE("(%p)\n", msg_data);
981 for (i = 0; ret && i < msg_data->info->cSignerInfo; i++)
983 if (msg_data->info->rgSignerInfo[i].AuthAttrs.cAttr)
985 if (flag == Sign)
987 BYTE oid_rsa_data_encoded[] = { 0x06,0x09,0x2a,0x86,0x48,0x86,
988 0xf7,0x0d,0x01,0x07,0x01 };
989 CRYPT_DATA_BLOB content = { sizeof(oid_rsa_data_encoded),
990 oid_rsa_data_encoded };
991 char contentType[] = szOID_RSA_contentType;
992 CRYPT_ATTRIBUTE contentTypeAttr = { contentType, 1, &content };
994 /* FIXME: does this depend on inner OID? */
995 ret = CRYPT_AppendAttribute(
996 &msg_data->info->rgSignerInfo[i].AuthAttrs, &contentTypeAttr);
997 if (ret)
998 ret = CSignedMsgData_AppendMessageDigestAttribute(msg_data,
1001 if (ret)
1003 LPBYTE encodedAttrs;
1004 DWORD size;
1006 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, PKCS_ATTRIBUTES,
1007 &msg_data->info->rgSignerInfo[i].AuthAttrs,
1008 CRYPT_ENCODE_ALLOC_FLAG, NULL, (LPBYTE)&encodedAttrs, &size);
1009 if (ret)
1011 ret = CryptHashData(
1012 msg_data->signerHandles[i].authAttrHash, encodedAttrs,
1013 size, 0);
1014 LocalFree(encodedAttrs);
1019 TRACE("returning %d\n", ret);
1020 return ret;
1023 static void CRYPT_ReverseBytes(CRYPT_HASH_BLOB *hash)
1025 DWORD i;
1026 BYTE tmp;
1028 for (i = 0; i < hash->cbData / 2; i++)
1030 tmp = hash->pbData[hash->cbData - i - 1];
1031 hash->pbData[hash->cbData - i - 1] = hash->pbData[i];
1032 hash->pbData[i] = tmp;
1036 static BOOL CSignedMsgData_Sign(CSignedMsgData *msg_data)
1038 DWORD i;
1039 BOOL ret = TRUE;
1041 TRACE("(%p)\n", msg_data);
1043 for (i = 0; ret && i < msg_data->info->cSignerInfo; i++)
1045 HCRYPTHASH hash;
1047 if (msg_data->info->rgSignerInfo[i].AuthAttrs.cAttr)
1048 hash = msg_data->signerHandles[i].authAttrHash;
1049 else
1050 hash = msg_data->signerHandles[i].contentHash;
1051 ret = CryptSignHashW(hash, AT_SIGNATURE, NULL, 0, NULL,
1052 &msg_data->info->rgSignerInfo[i].EncryptedHash.cbData);
1053 if (ret)
1055 msg_data->info->rgSignerInfo[i].EncryptedHash.pbData =
1056 CryptMemAlloc(
1057 msg_data->info->rgSignerInfo[i].EncryptedHash.cbData);
1058 if (msg_data->info->rgSignerInfo[i].EncryptedHash.pbData)
1060 ret = CryptSignHashW(hash, AT_SIGNATURE, NULL, 0,
1061 msg_data->info->rgSignerInfo[i].EncryptedHash.pbData,
1062 &msg_data->info->rgSignerInfo[i].EncryptedHash.cbData);
1063 if (ret)
1064 CRYPT_ReverseBytes(
1065 &msg_data->info->rgSignerInfo[i].EncryptedHash);
1067 else
1068 ret = FALSE;
1071 return ret;
1074 static BOOL CSignedMsgData_Update(CSignedMsgData *msg_data,
1075 const BYTE *pbData, DWORD cbData, BOOL fFinal, SignOrVerify flag)
1077 BOOL ret = CSignedMsgData_UpdateHash(msg_data, pbData, cbData);
1079 if (ret && fFinal)
1081 ret = CSignedMsgData_UpdateAuthenticatedAttributes(msg_data, flag);
1082 if (ret && flag == Sign)
1083 ret = CSignedMsgData_Sign(msg_data);
1085 return ret;
1088 typedef struct _CSignedEncodeMsg
1090 CryptMsgBase base;
1091 CRYPT_DATA_BLOB data;
1092 CSignedMsgData msg_data;
1093 } CSignedEncodeMsg;
1095 static void CSignedEncodeMsg_Close(HCRYPTMSG hCryptMsg)
1097 CSignedEncodeMsg *msg = (CSignedEncodeMsg *)hCryptMsg;
1098 DWORD i;
1100 CryptMemFree(msg->data.pbData);
1101 CRYPT_FreeBlobArray((BlobArray *)&msg->msg_data.info->cCertEncoded);
1102 CRYPT_FreeBlobArray((BlobArray *)&msg->msg_data.info->cCrlEncoded);
1103 for (i = 0; i < msg->msg_data.info->cSignerInfo; i++)
1104 CSignerInfo_Free(&msg->msg_data.info->rgSignerInfo[i]);
1105 CSignedMsgData_CloseHandles(&msg->msg_data);
1106 CryptMemFree(msg->msg_data.info->rgSignerInfo);
1107 CryptMemFree(msg->msg_data.info);
1110 static BOOL CSignedEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
1111 DWORD dwIndex, void *pvData, DWORD *pcbData)
1113 CSignedEncodeMsg *msg = (CSignedEncodeMsg *)hCryptMsg;
1114 BOOL ret = FALSE;
1116 switch (dwParamType)
1118 case CMSG_CONTENT_PARAM:
1120 CRYPT_CONTENT_INFO info;
1122 ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0, NULL,
1123 &info.Content.cbData);
1124 if (ret)
1126 info.Content.pbData = CryptMemAlloc(info.Content.cbData);
1127 if (info.Content.pbData)
1129 ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0,
1130 info.Content.pbData, &info.Content.cbData);
1131 if (ret)
1133 char oid_rsa_signed[] = szOID_RSA_signedData;
1135 info.pszObjId = oid_rsa_signed;
1136 ret = CryptEncodeObjectEx(X509_ASN_ENCODING,
1137 PKCS_CONTENT_INFO, &info, 0, NULL, pvData, pcbData);
1139 CryptMemFree(info.Content.pbData);
1141 else
1142 ret = FALSE;
1144 break;
1146 case CMSG_BARE_CONTENT_PARAM:
1148 CRYPT_SIGNED_INFO info;
1149 char oid_rsa_data[] = szOID_RSA_data;
1151 info = *msg->msg_data.info;
1152 /* Quirk: OID is only encoded messages if an update has happened */
1153 if (msg->base.state != MsgStateInit)
1154 info.content.pszObjId = oid_rsa_data;
1155 else
1156 info.content.pszObjId = NULL;
1157 if (msg->data.cbData)
1159 CRYPT_DATA_BLOB blob = { msg->data.cbData, msg->data.pbData };
1161 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING,
1162 &blob, CRYPT_ENCODE_ALLOC_FLAG, NULL,
1163 &info.content.Content.pbData, &info.content.Content.cbData);
1165 else
1167 info.content.Content.cbData = 0;
1168 info.content.Content.pbData = NULL;
1169 ret = TRUE;
1171 if (ret)
1173 ret = CRYPT_AsnEncodePKCSSignedInfo(&info, pvData, pcbData);
1174 LocalFree(info.content.Content.pbData);
1176 break;
1178 case CMSG_COMPUTED_HASH_PARAM:
1179 if (dwIndex >= msg->msg_data.cSignerHandle)
1180 SetLastError(CRYPT_E_INVALID_INDEX);
1181 else
1182 ret = CryptGetHashParam(
1183 msg->msg_data.signerHandles[dwIndex].contentHash, HP_HASHVAL,
1184 pvData, pcbData, 0);
1185 break;
1186 case CMSG_ENCODED_SIGNER:
1187 if (dwIndex >= msg->msg_data.info->cSignerInfo)
1188 SetLastError(CRYPT_E_INVALID_INDEX);
1189 else
1190 ret = CryptEncodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
1191 PKCS7_SIGNER_INFO, &msg->msg_data.info->rgSignerInfo[dwIndex], 0,
1192 NULL, pvData, pcbData);
1193 break;
1194 case CMSG_VERSION_PARAM:
1195 ret = CRYPT_CopyParam(pvData, pcbData, &msg->msg_data.info->version,
1196 sizeof(msg->msg_data.info->version));
1197 break;
1198 default:
1199 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
1201 return ret;
1204 static BOOL CSignedEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
1205 DWORD cbData, BOOL fFinal)
1207 CSignedEncodeMsg *msg = (CSignedEncodeMsg *)hCryptMsg;
1208 BOOL ret = FALSE;
1210 if (msg->base.state == MsgStateFinalized)
1211 SetLastError(CRYPT_E_MSG_ERROR);
1212 else if (msg->base.streamed || (msg->base.open_flags & CMSG_DETACHED_FLAG))
1214 ret = CSignedMsgData_Update(&msg->msg_data, pbData, cbData, fFinal,
1215 Sign);
1216 if (msg->base.streamed)
1217 FIXME("streamed partial stub\n");
1218 msg->base.state = fFinal ? MsgStateFinalized : MsgStateUpdated;
1220 else
1222 if (!fFinal)
1223 SetLastError(CRYPT_E_MSG_ERROR);
1224 else
1226 if (cbData)
1228 msg->data.pbData = CryptMemAlloc(cbData);
1229 if (msg->data.pbData)
1231 memcpy(msg->data.pbData, pbData, cbData);
1232 msg->data.cbData = cbData;
1233 ret = TRUE;
1236 else
1237 ret = TRUE;
1238 if (ret)
1239 ret = CSignedMsgData_Update(&msg->msg_data, pbData, cbData,
1240 fFinal, Sign);
1241 msg->base.state = MsgStateFinalized;
1244 return ret;
1247 static HCRYPTMSG CSignedEncodeMsg_Open(DWORD dwFlags,
1248 const void *pvMsgEncodeInfo, LPSTR pszInnerContentObjID,
1249 PCMSG_STREAM_INFO pStreamInfo)
1251 const CMSG_SIGNED_ENCODE_INFO_WITH_CMS *info =
1252 (const CMSG_SIGNED_ENCODE_INFO_WITH_CMS *)pvMsgEncodeInfo;
1253 DWORD i;
1254 CSignedEncodeMsg *msg;
1256 if (info->cbSize != sizeof(CMSG_SIGNED_ENCODE_INFO) &&
1257 info->cbSize != sizeof(CMSG_SIGNED_ENCODE_INFO_WITH_CMS))
1259 SetLastError(E_INVALIDARG);
1260 return NULL;
1262 if (info->cbSize == sizeof(CMSG_SIGNED_ENCODE_INFO_WITH_CMS) &&
1263 info->rgAttrCertEncoded)
1265 FIXME("CMSG_SIGNED_ENCODE_INFO with CMS fields unsupported\n");
1266 return NULL;
1268 for (i = 0; i < info->cSigners; i++)
1269 if (!CRYPT_IsValidSigner(&info->rgSigners[i]))
1270 return NULL;
1271 msg = CryptMemAlloc(sizeof(CSignedEncodeMsg));
1272 if (msg)
1274 BOOL ret = TRUE;
1276 CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo,
1277 CSignedEncodeMsg_Close, CSignedEncodeMsg_GetParam,
1278 CSignedEncodeMsg_Update, CRYPT_DefaultMsgControl);
1279 msg->data.cbData = 0;
1280 msg->data.pbData = NULL;
1281 msg->msg_data.info = CryptMemAlloc(sizeof(CRYPT_SIGNED_INFO));
1282 if (msg->msg_data.info)
1284 memset(msg->msg_data.info, 0, sizeof(CRYPT_SIGNED_INFO));
1285 msg->msg_data.info->version = CMSG_SIGNED_DATA_V1;
1287 else
1288 ret = FALSE;
1289 if (ret)
1291 if (info->cSigners)
1293 msg->msg_data.info->rgSignerInfo =
1294 CryptMemAlloc(info->cSigners * sizeof(CMSG_SIGNER_INFO));
1295 if (msg->msg_data.info->rgSignerInfo)
1297 msg->msg_data.info->cSignerInfo = info->cSigners;
1298 memset(msg->msg_data.info->rgSignerInfo, 0,
1299 msg->msg_data.info->cSignerInfo * sizeof(CMSG_SIGNER_INFO));
1300 ret = CSignedMsgData_AllocateHandles(&msg->msg_data);
1301 for (i = 0; ret && i < msg->msg_data.info->cSignerInfo; i++)
1303 ret = CSignerInfo_Construct(
1304 &msg->msg_data.info->rgSignerInfo[i],
1305 &info->rgSigners[i]);
1306 if (ret)
1308 ret = CSignedMsgData_ConstructSignerHandles(
1309 &msg->msg_data, i, info->rgSigners[i].hCryptProv);
1310 if (dwFlags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG)
1311 CryptReleaseContext(info->rgSigners[i].hCryptProv,
1316 else
1317 ret = FALSE;
1319 else
1321 msg->msg_data.info->cSignerInfo = 0;
1322 msg->msg_data.signerHandles = NULL;
1323 msg->msg_data.cSignerHandle = 0;
1326 if (ret)
1327 ret = CRYPT_ConstructBlobArray(
1328 (BlobArray *)&msg->msg_data.info->cCertEncoded,
1329 (const BlobArray *)&info->cCertEncoded);
1330 if (ret)
1331 ret = CRYPT_ConstructBlobArray(
1332 (BlobArray *)&msg->msg_data.info->cCrlEncoded,
1333 (const BlobArray *)&info->cCrlEncoded);
1334 if (!ret)
1336 CSignedEncodeMsg_Close(msg);
1337 msg = NULL;
1340 return msg;
1343 static inline const char *MSG_TYPE_STR(DWORD type)
1345 switch (type)
1347 #define _x(x) case (x): return #x
1348 _x(CMSG_DATA);
1349 _x(CMSG_SIGNED);
1350 _x(CMSG_ENVELOPED);
1351 _x(CMSG_SIGNED_AND_ENVELOPED);
1352 _x(CMSG_HASHED);
1353 _x(CMSG_ENCRYPTED);
1354 #undef _x
1355 default:
1356 return wine_dbg_sprintf("unknown (%d)", type);
1360 HCRYPTMSG WINAPI CryptMsgOpenToEncode(DWORD dwMsgEncodingType, DWORD dwFlags,
1361 DWORD dwMsgType, const void *pvMsgEncodeInfo, LPSTR pszInnerContentObjID,
1362 PCMSG_STREAM_INFO pStreamInfo)
1364 HCRYPTMSG msg = NULL;
1366 TRACE("(%08x, %08x, %08x, %p, %s, %p)\n", dwMsgEncodingType, dwFlags,
1367 dwMsgType, pvMsgEncodeInfo, debugstr_a(pszInnerContentObjID), pStreamInfo);
1369 if (GET_CMSG_ENCODING_TYPE(dwMsgEncodingType) != PKCS_7_ASN_ENCODING)
1371 SetLastError(E_INVALIDARG);
1372 return NULL;
1374 switch (dwMsgType)
1376 case CMSG_DATA:
1377 msg = CDataEncodeMsg_Open(dwFlags, pvMsgEncodeInfo,
1378 pszInnerContentObjID, pStreamInfo);
1379 break;
1380 case CMSG_HASHED:
1381 msg = CHashEncodeMsg_Open(dwFlags, pvMsgEncodeInfo,
1382 pszInnerContentObjID, pStreamInfo);
1383 break;
1384 case CMSG_SIGNED:
1385 msg = CSignedEncodeMsg_Open(dwFlags, pvMsgEncodeInfo,
1386 pszInnerContentObjID, pStreamInfo);
1387 break;
1388 case CMSG_ENVELOPED:
1389 FIXME("unimplemented for type %s\n", MSG_TYPE_STR(dwMsgType));
1390 break;
1391 case CMSG_SIGNED_AND_ENVELOPED:
1392 case CMSG_ENCRYPTED:
1393 /* defined but invalid, fall through */
1394 default:
1395 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
1397 return msg;
1400 typedef struct _CDecodeMsg
1402 CryptMsgBase base;
1403 DWORD type;
1404 HCRYPTPROV crypt_prov;
1405 union {
1406 HCRYPTHASH hash;
1407 CSignedMsgData signed_data;
1408 } u;
1409 CRYPT_DATA_BLOB msg_data;
1410 PCONTEXT_PROPERTY_LIST properties;
1411 } CDecodeMsg;
1413 static void CDecodeMsg_Close(HCRYPTMSG hCryptMsg)
1415 CDecodeMsg *msg = (CDecodeMsg *)hCryptMsg;
1417 if (msg->base.open_flags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG)
1418 CryptReleaseContext(msg->crypt_prov, 0);
1419 switch (msg->type)
1421 case CMSG_HASHED:
1422 if (msg->u.hash)
1423 CryptDestroyHash(msg->u.hash);
1424 break;
1425 case CMSG_SIGNED:
1426 if (msg->u.signed_data.info)
1428 LocalFree(msg->u.signed_data.info);
1429 CSignedMsgData_CloseHandles(&msg->u.signed_data);
1431 break;
1433 CryptMemFree(msg->msg_data.pbData);
1434 ContextPropertyList_Free(msg->properties);
1437 static BOOL CDecodeMsg_CopyData(CDecodeMsg *msg, const BYTE *pbData,
1438 DWORD cbData)
1440 BOOL ret = TRUE;
1442 if (cbData)
1444 if (msg->msg_data.cbData)
1445 msg->msg_data.pbData = CryptMemRealloc(msg->msg_data.pbData,
1446 msg->msg_data.cbData + cbData);
1447 else
1448 msg->msg_data.pbData = CryptMemAlloc(cbData);
1449 if (msg->msg_data.pbData)
1451 memcpy(msg->msg_data.pbData + msg->msg_data.cbData, pbData, cbData);
1452 msg->msg_data.cbData += cbData;
1454 else
1455 ret = FALSE;
1457 return ret;
1460 static BOOL CDecodeMsg_DecodeDataContent(CDecodeMsg *msg, CRYPT_DER_BLOB *blob)
1462 BOOL ret;
1463 CRYPT_DATA_BLOB *data;
1464 DWORD size;
1466 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING,
1467 blob->pbData, blob->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, (LPBYTE)&data,
1468 &size);
1469 if (ret)
1471 ret = ContextPropertyList_SetProperty(msg->properties,
1472 CMSG_CONTENT_PARAM, data->pbData, data->cbData);
1473 LocalFree(data);
1475 return ret;
1478 static void CDecodeMsg_SaveAlgorithmID(CDecodeMsg *msg, DWORD param,
1479 const CRYPT_ALGORITHM_IDENTIFIER *id)
1481 static const BYTE nullParams[] = { ASN_NULL, 0 };
1482 CRYPT_ALGORITHM_IDENTIFIER *copy;
1483 DWORD len = sizeof(CRYPT_ALGORITHM_IDENTIFIER);
1485 /* Linearize algorithm id */
1486 len += strlen(id->pszObjId) + 1;
1487 len += id->Parameters.cbData;
1488 copy = CryptMemAlloc(len);
1489 if (copy)
1491 copy->pszObjId =
1492 (LPSTR)((BYTE *)copy + sizeof(CRYPT_ALGORITHM_IDENTIFIER));
1493 strcpy(copy->pszObjId, id->pszObjId);
1494 copy->Parameters.pbData = (BYTE *)copy->pszObjId + strlen(id->pszObjId)
1495 + 1;
1496 /* Trick: omit NULL parameters */
1497 if (id->Parameters.cbData == sizeof(nullParams) &&
1498 !memcmp(id->Parameters.pbData, nullParams, sizeof(nullParams)))
1500 copy->Parameters.cbData = 0;
1501 len -= sizeof(nullParams);
1503 else
1504 copy->Parameters.cbData = id->Parameters.cbData;
1505 if (copy->Parameters.cbData)
1506 memcpy(copy->Parameters.pbData, id->Parameters.pbData,
1507 id->Parameters.cbData);
1508 ContextPropertyList_SetProperty(msg->properties, param, (BYTE *)copy,
1509 len);
1510 CryptMemFree(copy);
1514 static inline void CRYPT_FixUpAlgorithmID(CRYPT_ALGORITHM_IDENTIFIER *id)
1516 id->pszObjId = (LPSTR)((BYTE *)id + sizeof(CRYPT_ALGORITHM_IDENTIFIER));
1517 id->Parameters.pbData = (BYTE *)id->pszObjId + strlen(id->pszObjId) + 1;
1520 static BOOL CDecodeMsg_DecodeHashedContent(CDecodeMsg *msg,
1521 CRYPT_DER_BLOB *blob)
1523 BOOL ret;
1524 CRYPT_DIGESTED_DATA *digestedData;
1525 DWORD size;
1527 ret = CRYPT_AsnDecodePKCSDigestedData(blob->pbData, blob->cbData,
1528 CRYPT_DECODE_ALLOC_FLAG, NULL, (CRYPT_DIGESTED_DATA *)&digestedData,
1529 &size);
1530 if (ret)
1532 ContextPropertyList_SetProperty(msg->properties, CMSG_VERSION_PARAM,
1533 (const BYTE *)&digestedData->version, sizeof(digestedData->version));
1534 CDecodeMsg_SaveAlgorithmID(msg, CMSG_HASH_ALGORITHM_PARAM,
1535 &digestedData->DigestAlgorithm);
1536 ContextPropertyList_SetProperty(msg->properties,
1537 CMSG_INNER_CONTENT_TYPE_PARAM,
1538 (const BYTE *)digestedData->ContentInfo.pszObjId,
1539 digestedData->ContentInfo.pszObjId ?
1540 strlen(digestedData->ContentInfo.pszObjId) + 1 : 0);
1541 if (digestedData->ContentInfo.Content.cbData)
1542 CDecodeMsg_DecodeDataContent(msg,
1543 &digestedData->ContentInfo.Content);
1544 else
1545 ContextPropertyList_SetProperty(msg->properties,
1546 CMSG_CONTENT_PARAM, NULL, 0);
1547 ContextPropertyList_SetProperty(msg->properties, CMSG_HASH_DATA_PARAM,
1548 digestedData->hash.pbData, digestedData->hash.cbData);
1549 LocalFree(digestedData);
1551 return ret;
1554 static BOOL CDecodeMsg_DecodeSignedContent(CDecodeMsg *msg,
1555 CRYPT_DER_BLOB *blob)
1557 BOOL ret;
1558 CRYPT_SIGNED_INFO *signedInfo;
1559 DWORD size;
1561 ret = CRYPT_AsnDecodePKCSSignedInfo(blob->pbData, blob->cbData,
1562 CRYPT_DECODE_ALLOC_FLAG, NULL, (CRYPT_SIGNED_INFO *)&signedInfo,
1563 &size);
1564 if (ret)
1566 DWORD i;
1568 msg->u.signed_data.info = signedInfo;
1569 ret = CSignedMsgData_AllocateHandles(&msg->u.signed_data);
1570 for (i = 0; ret && i < msg->u.signed_data.info->cSignerInfo; i++)
1571 ret = CSignedMsgData_ConstructSignerHandles(&msg->u.signed_data, i,
1572 msg->crypt_prov);
1573 if (ret)
1575 /* Now that we have all the content, update the hash handles with
1576 * it. Have to decode it if the type is szOID_RSA_data.
1578 if (msg->u.signed_data.info->content.Content.cbData)
1580 if (!strcmp(msg->u.signed_data.info->content.pszObjId,
1581 szOID_RSA_data))
1583 CRYPT_DATA_BLOB *blob;
1585 ret = CryptDecodeObjectEx(X509_ASN_ENCODING,
1586 X509_OCTET_STRING,
1587 msg->u.signed_data.info->content.Content.pbData,
1588 msg->u.signed_data.info->content.Content.cbData,
1589 CRYPT_DECODE_ALLOC_FLAG, NULL, (LPBYTE)&blob, &size);
1590 if (ret)
1592 ret = CSignedMsgData_Update(&msg->u.signed_data,
1593 blob->pbData, blob->cbData, TRUE, Verify);
1594 LocalFree(blob);
1597 else
1598 ret = CSignedMsgData_Update(&msg->u.signed_data,
1599 msg->u.signed_data.info->content.Content.pbData,
1600 msg->u.signed_data.info->content.Content.cbData, TRUE,
1601 Verify);
1605 return ret;
1607 /* Decodes the content in blob as the type given, and updates the value
1608 * (type, parameters, etc.) of msg based on what blob contains.
1609 * It doesn't just use msg's type, to allow a recursive call from an implicitly
1610 * typed message once the outer content info has been decoded.
1612 static BOOL CDecodeMsg_DecodeContent(CDecodeMsg *msg, CRYPT_DER_BLOB *blob,
1613 DWORD type)
1615 BOOL ret;
1617 switch (type)
1619 case CMSG_DATA:
1620 if ((ret = CDecodeMsg_DecodeDataContent(msg, blob)))
1621 msg->type = CMSG_DATA;
1622 break;
1623 case CMSG_HASHED:
1624 if ((ret = CDecodeMsg_DecodeHashedContent(msg, blob)))
1625 msg->type = CMSG_HASHED;
1626 break;
1627 case CMSG_ENVELOPED:
1628 FIXME("unimplemented for type %s\n", MSG_TYPE_STR(type));
1629 ret = TRUE;
1630 break;
1631 case CMSG_SIGNED:
1632 if ((ret = CDecodeMsg_DecodeSignedContent(msg, blob)))
1633 msg->type = CMSG_SIGNED;
1634 break;
1635 default:
1637 CRYPT_CONTENT_INFO *info;
1638 DWORD size;
1640 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, PKCS_CONTENT_INFO,
1641 msg->msg_data.pbData, msg->msg_data.cbData, CRYPT_DECODE_ALLOC_FLAG,
1642 NULL, (LPBYTE)&info, &size);
1643 if (ret)
1645 if (!strcmp(info->pszObjId, szOID_RSA_data))
1646 ret = CDecodeMsg_DecodeContent(msg, &info->Content, CMSG_DATA);
1647 else if (!strcmp(info->pszObjId, szOID_RSA_digestedData))
1648 ret = CDecodeMsg_DecodeContent(msg, &info->Content,
1649 CMSG_HASHED);
1650 else if (!strcmp(info->pszObjId, szOID_RSA_envelopedData))
1651 ret = CDecodeMsg_DecodeContent(msg, &info->Content,
1652 CMSG_ENVELOPED);
1653 else if (!strcmp(info->pszObjId, szOID_RSA_signedData))
1654 ret = CDecodeMsg_DecodeContent(msg, &info->Content,
1655 CMSG_SIGNED);
1656 else
1658 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
1659 ret = FALSE;
1661 LocalFree(info);
1665 return ret;
1668 static BOOL CDecodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
1669 DWORD cbData, BOOL fFinal)
1671 CDecodeMsg *msg = (CDecodeMsg *)hCryptMsg;
1672 BOOL ret = FALSE;
1674 TRACE("(%p, %p, %d, %d)\n", hCryptMsg, pbData, cbData, fFinal);
1676 if (msg->base.state == MsgStateFinalized)
1677 SetLastError(CRYPT_E_MSG_ERROR);
1678 else if (msg->base.streamed)
1680 FIXME("(%p, %p, %d, %d): streamed update stub\n", hCryptMsg, pbData,
1681 cbData, fFinal);
1682 if (fFinal)
1684 if (msg->base.open_flags & CMSG_DETACHED_FLAG &&
1685 msg->base.state != MsgStateDataFinalized)
1687 ret = CDecodeMsg_CopyData(msg, pbData, cbData);
1688 msg->base.state = MsgStateDataFinalized;
1689 if (ret)
1690 ret = CDecodeMsg_DecodeContent(msg, &msg->msg_data,
1691 msg->type);
1693 else
1695 FIXME("(%p, %p, %d, %d): detached update stub\n", hCryptMsg,
1696 pbData, cbData, fFinal);
1697 ret = TRUE;
1698 msg->base.state = MsgStateFinalized;
1701 else
1703 ret = CDecodeMsg_CopyData(msg, pbData, cbData);
1704 if (msg->base.state == MsgStateInit)
1705 msg->base.state = MsgStateUpdated;
1708 else
1710 if (!fFinal)
1711 SetLastError(CRYPT_E_MSG_ERROR);
1712 else
1714 if (msg->base.state == MsgStateInit)
1716 ret = CDecodeMsg_CopyData(msg, pbData, cbData);
1717 if (ret)
1718 ret = CDecodeMsg_DecodeContent(msg, &msg->msg_data,
1719 msg->type);
1720 if (msg->base.open_flags & CMSG_DETACHED_FLAG)
1721 msg->base.state = MsgStateDataFinalized;
1722 else
1723 msg->base.state = MsgStateFinalized;
1725 else if (msg->base.state == MsgStateDataFinalized)
1727 FIXME("(%p, %p, %d, %d): detached update stub\n", hCryptMsg,
1728 pbData, cbData, fFinal);
1729 ret = TRUE;
1730 msg->base.state = MsgStateFinalized;
1734 return ret;
1737 static BOOL CDecodeHashMsg_GetParam(CDecodeMsg *msg, DWORD dwParamType,
1738 DWORD dwIndex, void *pvData, DWORD *pcbData)
1740 BOOL ret = FALSE;
1742 switch (dwParamType)
1744 case CMSG_TYPE_PARAM:
1745 ret = CRYPT_CopyParam(pvData, pcbData, &msg->type, sizeof(msg->type));
1746 break;
1747 case CMSG_HASH_ALGORITHM_PARAM:
1749 CRYPT_DATA_BLOB blob;
1751 ret = ContextPropertyList_FindProperty(msg->properties, dwParamType,
1752 &blob);
1753 if (ret)
1755 ret = CRYPT_CopyParam(pvData, pcbData, blob.pbData, blob.cbData);
1756 if (ret && pvData)
1757 CRYPT_FixUpAlgorithmID((CRYPT_ALGORITHM_IDENTIFIER *)pvData);
1759 else
1760 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
1761 break;
1763 case CMSG_COMPUTED_HASH_PARAM:
1764 if (!msg->u.hash)
1766 CRYPT_ALGORITHM_IDENTIFIER *hashAlgoID = NULL;
1767 DWORD size = 0;
1768 ALG_ID algID = 0;
1770 CryptMsgGetParam(msg, CMSG_HASH_ALGORITHM_PARAM, 0, NULL, &size);
1771 hashAlgoID = CryptMemAlloc(size);
1772 ret = CryptMsgGetParam(msg, CMSG_HASH_ALGORITHM_PARAM, 0,
1773 hashAlgoID, &size);
1774 if (ret)
1775 algID = CertOIDToAlgId(hashAlgoID->pszObjId);
1776 ret = CryptCreateHash(msg->crypt_prov, algID, 0, 0, &msg->u.hash);
1777 if (ret)
1779 CRYPT_DATA_BLOB content;
1781 ret = ContextPropertyList_FindProperty(msg->properties,
1782 CMSG_CONTENT_PARAM, &content);
1783 if (ret)
1784 ret = CryptHashData(msg->u.hash, content.pbData,
1785 content.cbData, 0);
1787 CryptMemFree(hashAlgoID);
1789 else
1790 ret = TRUE;
1791 if (ret)
1792 ret = CryptGetHashParam(msg->u.hash, HP_HASHVAL, pvData, pcbData,
1794 break;
1795 default:
1797 CRYPT_DATA_BLOB blob;
1799 ret = ContextPropertyList_FindProperty(msg->properties, dwParamType,
1800 &blob);
1801 if (ret)
1802 ret = CRYPT_CopyParam(pvData, pcbData, blob.pbData, blob.cbData);
1803 else
1804 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
1807 return ret;
1810 /* nextData is an in/out parameter - on input it's the memory location in
1811 * which a copy of in's data should be made, and on output it's the memory
1812 * location immediately after out's copy of in's data.
1814 static inline void CRYPT_CopyBlob(CRYPT_DATA_BLOB *out,
1815 const CRYPT_DATA_BLOB *in, LPBYTE *nextData)
1817 out->cbData = in->cbData;
1818 if (in->cbData)
1820 out->pbData = *nextData;
1821 memcpy(out->pbData, in->pbData, in->cbData);
1822 *nextData += in->cbData;
1826 static inline void CRYPT_CopyAlgorithmId(CRYPT_ALGORITHM_IDENTIFIER *out,
1827 const CRYPT_ALGORITHM_IDENTIFIER *in, LPBYTE *nextData)
1829 if (in->pszObjId)
1831 out->pszObjId = (LPSTR)*nextData;
1832 strcpy(out->pszObjId, in->pszObjId);
1833 *nextData += strlen(out->pszObjId) + 1;
1835 CRYPT_CopyBlob(&out->Parameters, &in->Parameters, nextData);
1838 static inline void CRYPT_CopyAttributes(CRYPT_ATTRIBUTES *out,
1839 const CRYPT_ATTRIBUTES *in, LPBYTE *nextData)
1841 out->cAttr = in->cAttr;
1842 if (in->cAttr)
1844 DWORD i;
1846 if ((*nextData - (LPBYTE)0) % sizeof(DWORD_PTR))
1847 *nextData += (*nextData - (LPBYTE)0) % sizeof(DWORD_PTR);
1848 out->rgAttr = (CRYPT_ATTRIBUTE *)*nextData;
1849 *nextData += in->cAttr * sizeof(CRYPT_ATTRIBUTE);
1850 for (i = 0; i < in->cAttr; i++)
1852 if (in->rgAttr[i].pszObjId)
1854 out->rgAttr[i].pszObjId = (LPSTR)*nextData;
1855 strcpy(out->rgAttr[i].pszObjId, in->rgAttr[i].pszObjId);
1856 *nextData += strlen(in->rgAttr[i].pszObjId) + 1;
1858 if (in->rgAttr[i].cValue)
1860 DWORD j;
1862 out->rgAttr[i].cValue = in->rgAttr[i].cValue;
1863 if ((*nextData - (LPBYTE)0) % sizeof(DWORD_PTR))
1864 *nextData += (*nextData - (LPBYTE)0) % sizeof(DWORD_PTR);
1865 out->rgAttr[i].rgValue = (PCRYPT_DATA_BLOB)*nextData;
1866 *nextData += in->rgAttr[i].cValue * sizeof(CRYPT_DATA_BLOB);
1867 for (j = 0; j < in->rgAttr[i].cValue; j++)
1868 CRYPT_CopyBlob(&out->rgAttr[i].rgValue[j],
1869 &in->rgAttr[i].rgValue[j], nextData);
1875 static DWORD CRYPT_SizeOfAttributes(const CRYPT_ATTRIBUTES *attr)
1877 DWORD size = attr->cAttr * sizeof(CRYPT_ATTRIBUTE), i, j;
1879 for (i = 0; i < attr->cAttr; i++)
1881 if (attr->rgAttr[i].pszObjId)
1882 size += strlen(attr->rgAttr[i].pszObjId) + 1;
1883 /* align pointer */
1884 if (size % sizeof(DWORD_PTR))
1885 size += size % sizeof(DWORD_PTR);
1886 size += attr->rgAttr[i].cValue * sizeof(CRYPT_DATA_BLOB);
1887 for (j = 0; j < attr->rgAttr[i].cValue; j++)
1888 size += attr->rgAttr[i].rgValue[j].cbData;
1890 /* align pointer again to be conservative */
1891 if (size % sizeof(DWORD_PTR))
1892 size += size % sizeof(DWORD_PTR);
1893 return size;
1896 static BOOL CRYPT_CopySignerInfo(void *pvData, DWORD *pcbData,
1897 const CMSG_SIGNER_INFO *in)
1899 DWORD size = sizeof(CMSG_SIGNER_INFO);
1900 BOOL ret;
1902 TRACE("(%p, %d, %p)\n", pvData, pvData ? *pcbData : 0, in);
1904 size += in->Issuer.cbData;
1905 size += in->SerialNumber.cbData;
1906 if (in->HashAlgorithm.pszObjId)
1907 size += strlen(in->HashAlgorithm.pszObjId) + 1;
1908 size += in->HashAlgorithm.Parameters.cbData;
1909 if (in->HashEncryptionAlgorithm.pszObjId)
1910 size += strlen(in->HashEncryptionAlgorithm.pszObjId) + 1;
1911 size += in->HashEncryptionAlgorithm.Parameters.cbData;
1912 size += in->EncryptedHash.cbData;
1913 /* align pointer */
1914 if (size % sizeof(DWORD_PTR))
1915 size += size % sizeof(DWORD_PTR);
1916 size += CRYPT_SizeOfAttributes(&in->AuthAttrs);
1917 size += CRYPT_SizeOfAttributes(&in->UnauthAttrs);
1918 if (!pvData)
1920 *pcbData = size;
1921 ret = TRUE;
1923 else if (*pcbData < size)
1925 *pcbData = size;
1926 SetLastError(ERROR_MORE_DATA);
1927 ret = FALSE;
1929 else
1931 LPBYTE nextData = (BYTE *)pvData + sizeof(CMSG_SIGNER_INFO);
1932 CMSG_SIGNER_INFO *out = (CMSG_SIGNER_INFO *)pvData;
1934 out->dwVersion = in->dwVersion;
1935 CRYPT_CopyBlob(&out->Issuer, &in->Issuer, &nextData);
1936 CRYPT_CopyBlob(&out->SerialNumber, &in->SerialNumber, &nextData);
1937 CRYPT_CopyAlgorithmId(&out->HashAlgorithm, &in->HashAlgorithm,
1938 &nextData);
1939 CRYPT_CopyAlgorithmId(&out->HashEncryptionAlgorithm,
1940 &in->HashEncryptionAlgorithm, &nextData);
1941 CRYPT_CopyBlob(&out->EncryptedHash, &in->EncryptedHash, &nextData);
1942 /* align pointer */
1943 if ((nextData - (LPBYTE)0) % sizeof(DWORD_PTR))
1944 nextData += (nextData - (LPBYTE)0) % sizeof(DWORD_PTR);
1945 CRYPT_CopyAttributes(&out->AuthAttrs, &in->AuthAttrs, &nextData);
1946 CRYPT_CopyAttributes(&out->UnauthAttrs, &in->UnauthAttrs, &nextData);
1947 ret = TRUE;
1949 TRACE("returning %d\n", ret);
1950 return ret;
1953 static BOOL CRYPT_CopySignerCertInfo(void *pvData, DWORD *pcbData,
1954 const CMSG_SIGNER_INFO *in)
1956 DWORD size = sizeof(CERT_INFO);
1957 BOOL ret;
1959 TRACE("(%p, %d, %p)\n", pvData, pvData ? *pcbData : 0, in);
1961 size += in->Issuer.cbData;
1962 size += in->SerialNumber.cbData;
1963 if (!pvData)
1965 *pcbData = size;
1966 ret = TRUE;
1968 else if (*pcbData < size)
1970 *pcbData = size;
1971 SetLastError(ERROR_MORE_DATA);
1972 ret = FALSE;
1974 else
1976 LPBYTE nextData = (BYTE *)pvData + sizeof(CERT_INFO);
1977 CERT_INFO *out = (CERT_INFO *)pvData;
1979 memset(out, 0, sizeof(CERT_INFO));
1980 CRYPT_CopyBlob(&out->Issuer, &in->Issuer, &nextData);
1981 CRYPT_CopyBlob(&out->SerialNumber, &in->SerialNumber, &nextData);
1982 ret = TRUE;
1984 TRACE("returning %d\n", ret);
1985 return ret;
1988 static BOOL CDecodeSignedMsg_GetParam(CDecodeMsg *msg, DWORD dwParamType,
1989 DWORD dwIndex, void *pvData, DWORD *pcbData)
1991 BOOL ret = FALSE;
1993 switch (dwParamType)
1995 case CMSG_TYPE_PARAM:
1996 ret = CRYPT_CopyParam(pvData, pcbData, &msg->type, sizeof(msg->type));
1997 break;
1998 case CMSG_CONTENT_PARAM:
1999 if (msg->u.signed_data.info)
2001 if (!strcmp(msg->u.signed_data.info->content.pszObjId,
2002 szOID_RSA_data))
2004 CRYPT_DATA_BLOB *blob;
2005 DWORD size;
2007 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING,
2008 msg->u.signed_data.info->content.Content.pbData,
2009 msg->u.signed_data.info->content.Content.cbData,
2010 CRYPT_DECODE_ALLOC_FLAG, NULL, (LPBYTE)&blob, &size);
2011 if (ret)
2013 ret = CRYPT_CopyParam(pvData, pcbData, blob->pbData,
2014 blob->cbData);
2015 LocalFree(blob);
2018 else
2019 ret = CRYPT_CopyParam(pvData, pcbData,
2020 msg->u.signed_data.info->content.Content.pbData,
2021 msg->u.signed_data.info->content.Content.cbData);
2023 else
2024 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2025 break;
2026 case CMSG_INNER_CONTENT_TYPE_PARAM:
2027 if (msg->u.signed_data.info)
2028 ret = CRYPT_CopyParam(pvData, pcbData,
2029 msg->u.signed_data.info->content.pszObjId,
2030 strlen(msg->u.signed_data.info->content.pszObjId) + 1);
2031 else
2032 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2033 break;
2034 case CMSG_SIGNER_COUNT_PARAM:
2035 if (msg->u.signed_data.info)
2036 ret = CRYPT_CopyParam(pvData, pcbData,
2037 &msg->u.signed_data.info->cSignerInfo, sizeof(DWORD));
2038 else
2039 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2040 break;
2041 case CMSG_SIGNER_INFO_PARAM:
2042 if (msg->u.signed_data.info)
2044 if (dwIndex >= msg->u.signed_data.info->cSignerInfo)
2045 SetLastError(CRYPT_E_INVALID_INDEX);
2046 else
2047 ret = CRYPT_CopySignerInfo(pvData, pcbData,
2048 &msg->u.signed_data.info->rgSignerInfo[dwIndex]);
2050 else
2051 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2052 break;
2053 case CMSG_SIGNER_CERT_INFO_PARAM:
2054 if (msg->u.signed_data.info)
2056 if (dwIndex >= msg->u.signed_data.info->cSignerInfo)
2057 SetLastError(CRYPT_E_INVALID_INDEX);
2058 else
2059 ret = CRYPT_CopySignerCertInfo(pvData, pcbData,
2060 &msg->u.signed_data.info->rgSignerInfo[dwIndex]);
2062 else
2063 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2064 break;
2065 case CMSG_CERT_COUNT_PARAM:
2066 if (msg->u.signed_data.info)
2067 ret = CRYPT_CopyParam(pvData, pcbData,
2068 &msg->u.signed_data.info->cCertEncoded, sizeof(DWORD));
2069 else
2070 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2071 break;
2072 case CMSG_CERT_PARAM:
2073 if (msg->u.signed_data.info)
2075 if (dwIndex >= msg->u.signed_data.info->cCertEncoded)
2076 SetLastError(CRYPT_E_INVALID_INDEX);
2077 else
2078 ret = CRYPT_CopyParam(pvData, pcbData,
2079 msg->u.signed_data.info->rgCertEncoded[dwIndex].pbData,
2080 msg->u.signed_data.info->rgCertEncoded[dwIndex].cbData);
2082 else
2083 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2084 break;
2085 case CMSG_CRL_COUNT_PARAM:
2086 if (msg->u.signed_data.info)
2087 ret = CRYPT_CopyParam(pvData, pcbData,
2088 &msg->u.signed_data.info->cCrlEncoded, sizeof(DWORD));
2089 else
2090 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2091 break;
2092 case CMSG_CRL_PARAM:
2093 if (msg->u.signed_data.info)
2095 if (dwIndex >= msg->u.signed_data.info->cCrlEncoded)
2096 SetLastError(CRYPT_E_INVALID_INDEX);
2097 else
2098 ret = CRYPT_CopyParam(pvData, pcbData,
2099 msg->u.signed_data.info->rgCrlEncoded[dwIndex].pbData,
2100 msg->u.signed_data.info->rgCrlEncoded[dwIndex].cbData);
2102 else
2103 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2104 break;
2105 case CMSG_COMPUTED_HASH_PARAM:
2106 if (msg->u.signed_data.info)
2108 if (dwIndex >= msg->u.signed_data.cSignerHandle)
2109 SetLastError(CRYPT_E_INVALID_INDEX);
2110 else
2111 ret = CryptGetHashParam(
2112 msg->u.signed_data.signerHandles[dwIndex].contentHash,
2113 HP_HASHVAL, pvData, pcbData, 0);
2115 else
2116 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2117 break;
2118 case CMSG_ATTR_CERT_COUNT_PARAM:
2119 if (msg->u.signed_data.info)
2121 DWORD attrCertCount = 0;
2123 ret = CRYPT_CopyParam(pvData, pcbData,
2124 &attrCertCount, sizeof(DWORD));
2126 else
2127 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2128 break;
2129 case CMSG_ATTR_CERT_PARAM:
2130 if (msg->u.signed_data.info)
2131 SetLastError(CRYPT_E_INVALID_INDEX);
2132 else
2133 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2134 break;
2135 default:
2136 FIXME("unimplemented for %d\n", dwParamType);
2137 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2139 return ret;
2142 static BOOL CDecodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
2143 DWORD dwIndex, void *pvData, DWORD *pcbData)
2145 CDecodeMsg *msg = (CDecodeMsg *)hCryptMsg;
2146 BOOL ret = FALSE;
2148 switch (msg->type)
2150 case CMSG_HASHED:
2151 ret = CDecodeHashMsg_GetParam(msg, dwParamType, dwIndex, pvData,
2152 pcbData);
2153 break;
2154 case CMSG_SIGNED:
2155 ret = CDecodeSignedMsg_GetParam(msg, dwParamType, dwIndex, pvData,
2156 pcbData);
2157 break;
2158 default:
2159 switch (dwParamType)
2161 case CMSG_TYPE_PARAM:
2162 ret = CRYPT_CopyParam(pvData, pcbData, &msg->type,
2163 sizeof(msg->type));
2164 break;
2165 default:
2167 CRYPT_DATA_BLOB blob;
2169 ret = ContextPropertyList_FindProperty(msg->properties, dwParamType,
2170 &blob);
2171 if (ret)
2172 ret = CRYPT_CopyParam(pvData, pcbData, blob.pbData,
2173 blob.cbData);
2174 else
2175 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2179 return ret;
2182 static BOOL CDecodeHashMsg_VerifyHash(CDecodeMsg *msg)
2184 BOOL ret;
2185 CRYPT_DATA_BLOB hashBlob;
2187 ret = ContextPropertyList_FindProperty(msg->properties,
2188 CMSG_HASH_DATA_PARAM, &hashBlob);
2189 if (ret)
2191 DWORD computedHashSize = 0;
2193 ret = CDecodeHashMsg_GetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, NULL,
2194 &computedHashSize);
2195 if (hashBlob.cbData == computedHashSize)
2197 LPBYTE computedHash = CryptMemAlloc(computedHashSize);
2199 if (computedHash)
2201 ret = CDecodeHashMsg_GetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0,
2202 computedHash, &computedHashSize);
2203 if (ret)
2204 ret = !memcmp(hashBlob.pbData, computedHash,
2205 hashBlob.cbData);
2206 CryptMemFree(computedHash);
2208 else
2209 ret = FALSE;
2212 return ret;
2215 static BOOL CDecodeSignedMsg_VerifySignatureWithKey(CDecodeMsg *msg,
2216 HCRYPTPROV prov, DWORD signerIndex, PCERT_PUBLIC_KEY_INFO keyInfo)
2218 HCRYPTKEY key;
2219 BOOL ret;
2221 if (!prov)
2222 prov = msg->crypt_prov;
2223 ret = CryptImportPublicKeyInfo(prov, X509_ASN_ENCODING, keyInfo, &key);
2224 if (ret)
2226 HCRYPTHASH hash;
2227 CRYPT_HASH_BLOB reversedHash;
2229 if (msg->u.signed_data.info->rgSignerInfo[signerIndex].AuthAttrs.cAttr)
2230 hash = msg->u.signed_data.signerHandles[signerIndex].authAttrHash;
2231 else
2232 hash = msg->u.signed_data.signerHandles[signerIndex].contentHash;
2233 ret = CRYPT_ConstructBlob(&reversedHash,
2234 &msg->u.signed_data.info->rgSignerInfo[signerIndex].EncryptedHash);
2235 if (ret)
2237 CRYPT_ReverseBytes(&reversedHash);
2238 ret = CryptVerifySignatureW(hash, reversedHash.pbData,
2239 reversedHash.cbData, key, NULL, 0);
2240 CryptMemFree(reversedHash.pbData);
2242 CryptDestroyKey(key);
2244 return ret;
2247 static BOOL CDecodeSignedMsg_VerifySignature(CDecodeMsg *msg, PCERT_INFO info)
2249 BOOL ret = FALSE;
2250 DWORD i;
2252 for (i = 0; !ret && i < msg->u.signed_data.info->cSignerInfo; i++)
2254 ret = CertCompareCertificateName(X509_ASN_ENCODING,
2255 &msg->u.signed_data.info->rgSignerInfo[i].Issuer, &info->Issuer);
2256 if (ret)
2258 ret = CertCompareIntegerBlob(
2259 &msg->u.signed_data.info->rgSignerInfo[i].SerialNumber,
2260 &info->SerialNumber);
2261 if (ret)
2262 break;
2265 if (ret)
2266 ret = CDecodeSignedMsg_VerifySignatureWithKey(msg, 0, i,
2267 &info->SubjectPublicKeyInfo);
2268 else
2269 SetLastError(CRYPT_E_SIGNER_NOT_FOUND);
2271 return ret;
2274 static BOOL CDecodeSignedMsg_VerifySignatureEx(CDecodeMsg *msg,
2275 PCMSG_CTRL_VERIFY_SIGNATURE_EX_PARA para)
2277 BOOL ret = FALSE;
2279 if (para->cbSize != sizeof(CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA))
2280 SetLastError(ERROR_INVALID_PARAMETER);
2281 else if (para->dwSignerIndex >= msg->u.signed_data.info->cSignerInfo)
2282 SetLastError(CRYPT_E_SIGNER_NOT_FOUND);
2283 else
2285 switch (para->dwSignerType)
2287 case CMSG_VERIFY_SIGNER_PUBKEY:
2288 ret = CDecodeSignedMsg_VerifySignatureWithKey(msg,
2289 para->hCryptProv, para->dwSignerIndex,
2290 (PCERT_PUBLIC_KEY_INFO)para->pvSigner);
2291 break;
2292 case CMSG_VERIFY_SIGNER_CERT:
2294 PCCERT_CONTEXT cert = (PCCERT_CONTEXT)para->pvSigner;
2296 ret = CDecodeSignedMsg_VerifySignatureWithKey(msg, para->hCryptProv,
2297 para->dwSignerIndex, &cert->pCertInfo->SubjectPublicKeyInfo);
2298 break;
2300 default:
2301 FIXME("unimplemented for signer type %d\n", para->dwSignerType);
2302 SetLastError(CRYPT_E_SIGNER_NOT_FOUND);
2305 return ret;
2308 static BOOL CDecodeMsg_Control(HCRYPTMSG hCryptMsg, DWORD dwFlags,
2309 DWORD dwCtrlType, const void *pvCtrlPara)
2311 CDecodeMsg *msg = (CDecodeMsg *)hCryptMsg;
2312 BOOL ret = FALSE;
2314 switch (dwCtrlType)
2316 case CMSG_CTRL_VERIFY_SIGNATURE:
2317 switch (msg->type)
2319 case CMSG_SIGNED:
2320 ret = CDecodeSignedMsg_VerifySignature(msg, (PCERT_INFO)pvCtrlPara);
2321 break;
2322 default:
2323 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2325 break;
2326 case CMSG_CTRL_DECRYPT:
2327 switch (msg->type)
2329 default:
2330 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2332 break;
2333 case CMSG_CTRL_VERIFY_HASH:
2334 switch (msg->type)
2336 case CMSG_HASHED:
2337 ret = CDecodeHashMsg_VerifyHash(msg);
2338 break;
2339 default:
2340 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2342 break;
2343 case CMSG_CTRL_VERIFY_SIGNATURE_EX:
2344 switch (msg->type)
2346 case CMSG_SIGNED:
2347 ret = CDecodeSignedMsg_VerifySignatureEx(msg,
2348 (PCMSG_CTRL_VERIFY_SIGNATURE_EX_PARA)pvCtrlPara);
2349 break;
2350 default:
2351 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2353 break;
2354 default:
2355 SetLastError(CRYPT_E_CONTROL_TYPE);
2357 return ret;
2360 HCRYPTMSG WINAPI CryptMsgOpenToDecode(DWORD dwMsgEncodingType, DWORD dwFlags,
2361 DWORD dwMsgType, HCRYPTPROV_LEGACY hCryptProv, PCERT_INFO pRecipientInfo,
2362 PCMSG_STREAM_INFO pStreamInfo)
2364 CDecodeMsg *msg;
2366 TRACE("(%08x, %08x, %08x, %08lx, %p, %p)\n", dwMsgEncodingType,
2367 dwFlags, dwMsgType, hCryptProv, pRecipientInfo, pStreamInfo);
2369 if (GET_CMSG_ENCODING_TYPE(dwMsgEncodingType) != PKCS_7_ASN_ENCODING)
2371 SetLastError(E_INVALIDARG);
2372 return NULL;
2374 msg = CryptMemAlloc(sizeof(CDecodeMsg));
2375 if (msg)
2377 CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo,
2378 CDecodeMsg_Close, CDecodeMsg_GetParam, CDecodeMsg_Update,
2379 CDecodeMsg_Control);
2380 msg->type = dwMsgType;
2381 if (hCryptProv)
2382 msg->crypt_prov = hCryptProv;
2383 else
2385 msg->crypt_prov = CRYPT_GetDefaultProvider();
2386 msg->base.open_flags &= ~CMSG_CRYPT_RELEASE_CONTEXT_FLAG;
2388 memset(&msg->u, 0, sizeof(msg->u));
2389 msg->msg_data.cbData = 0;
2390 msg->msg_data.pbData = NULL;
2391 msg->properties = ContextPropertyList_Create();
2393 return msg;
2396 HCRYPTMSG WINAPI CryptMsgDuplicate(HCRYPTMSG hCryptMsg)
2398 TRACE("(%p)\n", hCryptMsg);
2400 if (hCryptMsg)
2402 CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg;
2404 InterlockedIncrement(&msg->ref);
2406 return hCryptMsg;
2409 BOOL WINAPI CryptMsgClose(HCRYPTMSG hCryptMsg)
2411 TRACE("(%p)\n", hCryptMsg);
2413 if (hCryptMsg)
2415 CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg;
2417 if (InterlockedDecrement(&msg->ref) == 0)
2419 TRACE("freeing %p\n", msg);
2420 if (msg->close)
2421 msg->close(msg);
2422 CryptMemFree(msg);
2425 return TRUE;
2428 BOOL WINAPI CryptMsgUpdate(HCRYPTMSG hCryptMsg, const BYTE *pbData,
2429 DWORD cbData, BOOL fFinal)
2431 CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg;
2433 TRACE("(%p, %p, %d, %d)\n", hCryptMsg, pbData, cbData, fFinal);
2435 return msg->update(hCryptMsg, pbData, cbData, fFinal);
2438 BOOL WINAPI CryptMsgGetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
2439 DWORD dwIndex, void *pvData, DWORD *pcbData)
2441 CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg;
2443 TRACE("(%p, %d, %d, %p, %p)\n", hCryptMsg, dwParamType, dwIndex,
2444 pvData, pcbData);
2445 return msg->get_param(hCryptMsg, dwParamType, dwIndex, pvData, pcbData);
2448 BOOL WINAPI CryptMsgControl(HCRYPTMSG hCryptMsg, DWORD dwFlags,
2449 DWORD dwCtrlType, const void *pvCtrlPara)
2451 CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg;
2453 TRACE("(%p, %08x, %d, %p)\n", hCryptMsg, dwFlags, dwCtrlType,
2454 pvCtrlPara);
2455 return msg->control(hCryptMsg, dwFlags, dwCtrlType, pvCtrlPara);
2458 static CERT_INFO *CRYPT_GetSignerCertInfoFromMsg(HCRYPTMSG msg,
2459 DWORD dwSignerIndex)
2461 CERT_INFO *certInfo = NULL;
2462 DWORD size;
2464 if (CryptMsgGetParam(msg, CMSG_SIGNER_CERT_INFO_PARAM, dwSignerIndex, NULL,
2465 &size))
2467 certInfo = CryptMemAlloc(size);
2468 if (certInfo)
2470 if (!CryptMsgGetParam(msg, CMSG_SIGNER_CERT_INFO_PARAM,
2471 dwSignerIndex, certInfo, &size))
2473 CryptMemFree(certInfo);
2474 certInfo = NULL;
2478 return certInfo;
2481 BOOL WINAPI CryptMsgGetAndVerifySigner(HCRYPTMSG hCryptMsg, DWORD cSignerStore,
2482 HCERTSTORE *rghSignerStore, DWORD dwFlags, PCCERT_CONTEXT *ppSigner,
2483 DWORD *pdwSignerIndex)
2485 HCERTSTORE store;
2486 DWORD i, signerIndex;
2487 PCCERT_CONTEXT signerCert = NULL;
2488 BOOL ret = FALSE;
2490 TRACE("(%p, %d, %p, %08x, %p, %p)\n", hCryptMsg, cSignerStore,
2491 rghSignerStore, dwFlags, ppSigner, pdwSignerIndex);
2493 /* Clear output parameters */
2494 if (ppSigner)
2495 *ppSigner = NULL;
2496 if (pdwSignerIndex && !(dwFlags & CMSG_USE_SIGNER_INDEX_FLAG))
2497 *pdwSignerIndex = 0;
2499 /* Create store to search for signer certificates */
2500 store = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
2501 CERT_STORE_CREATE_NEW_FLAG, NULL);
2502 if (!(dwFlags & CMSG_TRUSTED_SIGNER_FLAG))
2504 HCERTSTORE msgStore = CertOpenStore(CERT_STORE_PROV_MSG, 0, 0, 0,
2505 hCryptMsg);
2507 CertAddStoreToCollection(store, msgStore, 0, 0);
2508 CertCloseStore(msgStore, 0);
2510 for (i = 0; i < cSignerStore; i++)
2511 CertAddStoreToCollection(store, rghSignerStore[i], 0, 0);
2513 /* Find signer cert */
2514 if (dwFlags & CMSG_USE_SIGNER_INDEX_FLAG)
2516 CERT_INFO *signer = CRYPT_GetSignerCertInfoFromMsg(hCryptMsg,
2517 *pdwSignerIndex);
2519 if (signer)
2521 signerIndex = *pdwSignerIndex;
2522 signerCert = CertFindCertificateInStore(store, X509_ASN_ENCODING,
2523 0, CERT_FIND_SUBJECT_CERT, signer, NULL);
2524 CryptMemFree(signer);
2527 else
2529 DWORD count, size = sizeof(count);
2531 if (CryptMsgGetParam(hCryptMsg, CMSG_SIGNER_COUNT_PARAM, 0, &count,
2532 &size))
2534 for (i = 0; !signerCert && i < count; i++)
2536 CERT_INFO *signer = CRYPT_GetSignerCertInfoFromMsg(hCryptMsg,
2539 if (signer)
2541 signerCert = CertFindCertificateInStore(store,
2542 X509_ASN_ENCODING, 0, CERT_FIND_SUBJECT_CERT, signer,
2543 NULL);
2544 if (signerCert)
2545 signerIndex = i;
2546 CryptMemFree(signer);
2550 if (!signerCert)
2551 SetLastError(CRYPT_E_NO_TRUSTED_SIGNER);
2553 if (signerCert)
2555 if (!(dwFlags & CMSG_SIGNER_ONLY_FLAG))
2556 ret = CryptMsgControl(hCryptMsg, 0, CMSG_CTRL_VERIFY_SIGNATURE,
2557 signerCert->pCertInfo);
2558 else
2559 ret = TRUE;
2560 if (ret)
2562 if (ppSigner)
2563 *ppSigner = CertDuplicateCertificateContext(signerCert);
2564 if (pdwSignerIndex)
2565 *pdwSignerIndex = signerIndex;
2567 CertFreeCertificateContext(signerCert);
2570 CertCloseStore(store, 0);
2571 return ret;
2574 BOOL WINAPI CryptMsgVerifyCountersignatureEncodedEx(HCRYPTPROV_LEGACY hCryptProv,
2575 DWORD dwEncodingType, PBYTE pbSignerInfo, DWORD cbSignerInfo,
2576 PBYTE pbSignerInfoCountersignature, DWORD cbSignerInfoCountersignature,
2577 DWORD dwSignerType, void *pvSigner, DWORD dwFlags, void *pvReserved)
2579 FIXME("(%08lx, %08x, %p, %d, %p, %d, %d, %p, %08x, %p): stub\n", hCryptProv,
2580 dwEncodingType, pbSignerInfo, cbSignerInfo, pbSignerInfoCountersignature,
2581 cbSignerInfoCountersignature, dwSignerType, pvSigner, dwFlags, pvReserved);
2582 return FALSE;