cmd: DIR command outputs free space for the path.
[wine.git] / dlls / crypt32 / msg.c
bloba5ee20f04a6329a6afe681a7fddef6ee43ca0737
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 <stdarg.h>
21 #include "windef.h"
22 #include "winbase.h"
23 #include "wincrypt.h"
24 #include "snmp.h"
26 #include "wine/debug.h"
27 #include "wine/exception.h"
28 #include "crypt32_private.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
32 /* Called when a message's ref count reaches zero. Free any message-specific
33 * data here.
35 typedef void (*CryptMsgCloseFunc)(HCRYPTMSG msg);
37 typedef BOOL (*CryptMsgGetParamFunc)(HCRYPTMSG hCryptMsg, DWORD dwParamType,
38 DWORD dwIndex, void *pvData, DWORD *pcbData);
40 typedef BOOL (*CryptMsgUpdateFunc)(HCRYPTMSG hCryptMsg, const BYTE *pbData,
41 DWORD cbData, BOOL fFinal);
43 typedef BOOL (*CryptMsgControlFunc)(HCRYPTMSG hCryptMsg, DWORD dwFlags,
44 DWORD dwCtrlType, const void *pvCtrlPara);
46 static BOOL extract_hash(HCRYPTHASH hash, BYTE **data, DWORD *size)
48 DWORD sz;
50 *data = NULL;
51 sz = sizeof(*size);
52 if (!CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *)size, &sz, 0)) return FALSE;
53 if (!(*data = CryptMemAlloc(*size)))
55 ERR("No memory.\n");
56 return FALSE;
58 if (CryptGetHashParam(hash, HP_HASHVAL, *data, size, 0)) return TRUE;
59 CryptMemFree(*data);
60 *data = NULL;
61 return FALSE;
64 static BOOL CRYPT_DefaultMsgControl(HCRYPTMSG hCryptMsg, DWORD dwFlags,
65 DWORD dwCtrlType, const void *pvCtrlPara)
67 TRACE("(%p, %08lx, %ld, %p)\n", hCryptMsg, dwFlags, dwCtrlType, pvCtrlPara);
68 SetLastError(E_INVALIDARG);
69 return FALSE;
72 typedef enum _CryptMsgState {
73 MsgStateInit,
74 MsgStateUpdated,
75 MsgStateDataFinalized,
76 MsgStateFinalized
77 } CryptMsgState;
79 typedef struct _CryptMsgBase
81 LONG ref;
82 DWORD open_flags;
83 BOOL streamed;
84 CMSG_STREAM_INFO stream_info;
85 CryptMsgState state;
86 CryptMsgCloseFunc close;
87 CryptMsgUpdateFunc update;
88 CryptMsgGetParamFunc get_param;
89 CryptMsgControlFunc control;
90 } CryptMsgBase;
92 static inline void CryptMsgBase_Init(CryptMsgBase *msg, DWORD dwFlags,
93 PCMSG_STREAM_INFO pStreamInfo, CryptMsgCloseFunc close,
94 CryptMsgGetParamFunc get_param, CryptMsgUpdateFunc update,
95 CryptMsgControlFunc control)
97 msg->ref = 1;
98 msg->open_flags = dwFlags;
99 if (pStreamInfo)
101 msg->streamed = TRUE;
102 msg->stream_info = *pStreamInfo;
104 else
106 msg->streamed = FALSE;
107 memset(&msg->stream_info, 0, sizeof(msg->stream_info));
109 msg->close = close;
110 msg->get_param = get_param;
111 msg->update = update;
112 msg->control = control;
113 msg->state = MsgStateInit;
116 typedef struct _CDataEncodeMsg
118 CryptMsgBase base;
119 DWORD bare_content_len;
120 LPBYTE bare_content;
121 } CDataEncodeMsg;
123 static const BYTE empty_data_content[] = { 0x04,0x00 };
125 static void CDataEncodeMsg_Close(HCRYPTMSG hCryptMsg)
127 CDataEncodeMsg *msg = hCryptMsg;
129 if (msg->bare_content != empty_data_content)
130 LocalFree(msg->bare_content);
133 static BOOL WINAPI CRYPT_EncodeContentLength(DWORD dwCertEncodingType,
134 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
135 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
137 DWORD dataLen = *(DWORD *)pvStructInfo;
138 DWORD lenBytes;
139 BOOL ret = TRUE;
141 /* Trick: report bytes needed based on total message length, even though
142 * the message isn't available yet. The caller will use the length
143 * reported here to encode its length.
145 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
146 if (!pbEncoded)
147 *pcbEncoded = 1 + lenBytes + dataLen;
148 else
150 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
151 pcbEncoded, 1 + lenBytes)))
153 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
154 pbEncoded = *(BYTE **)pbEncoded;
155 *pbEncoded++ = ASN_OCTETSTRING;
156 CRYPT_EncodeLen(dataLen, pbEncoded,
157 &lenBytes);
160 return ret;
163 static BOOL CRYPT_EncodeDataContentInfoHeader(const CDataEncodeMsg *msg,
164 CRYPT_DATA_BLOB *header)
166 BOOL ret;
168 if (msg->base.streamed && msg->base.stream_info.cbContent == 0xffffffff)
170 static const BYTE headerValue[] = { 0x30,0x80,0x06,0x09,0x2a,0x86,0x48,
171 0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x80,0x24,0x80 };
173 header->pbData = LocalAlloc(0, sizeof(headerValue));
174 if (header->pbData)
176 header->cbData = sizeof(headerValue);
177 memcpy(header->pbData, headerValue, sizeof(headerValue));
178 ret = TRUE;
180 else
181 ret = FALSE;
183 else
185 struct AsnConstructedItem constructed = { 0,
186 &msg->base.stream_info.cbContent, CRYPT_EncodeContentLength };
187 struct AsnEncodeSequenceItem items[2] = {
188 { szOID_RSA_data, CRYPT_AsnEncodeOid, 0 },
189 { &constructed, CRYPT_AsnEncodeConstructed, 0 },
192 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items,
193 ARRAY_SIZE(items), CRYPT_ENCODE_ALLOC_FLAG, NULL,
194 (LPBYTE)&header->pbData, &header->cbData);
195 if (ret)
197 /* Trick: subtract the content length from the reported length,
198 * as the actual content hasn't come yet.
200 header->cbData -= msg->base.stream_info.cbContent;
203 return ret;
206 static BOOL CDataEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
207 DWORD cbData, BOOL fFinal)
209 CDataEncodeMsg *msg = hCryptMsg;
210 BOOL ret = FALSE;
212 if (msg->base.state == MsgStateFinalized)
213 SetLastError(CRYPT_E_MSG_ERROR);
214 else if (msg->base.streamed)
216 __TRY
218 if (msg->base.state != MsgStateUpdated)
220 CRYPT_DATA_BLOB header;
222 ret = CRYPT_EncodeDataContentInfoHeader(msg, &header);
223 if (ret)
225 ret = msg->base.stream_info.pfnStreamOutput(
226 msg->base.stream_info.pvArg, header.pbData, header.cbData,
227 FALSE);
228 LocalFree(header.pbData);
231 /* Curiously, every indefinite-length streamed update appears to
232 * get its own tag and length, regardless of fFinal.
234 if (msg->base.stream_info.cbContent == 0xffffffff)
236 BYTE *header;
237 DWORD headerLen;
239 ret = CRYPT_EncodeContentLength(X509_ASN_ENCODING, NULL,
240 &cbData, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&header,
241 &headerLen);
242 if (ret)
244 ret = msg->base.stream_info.pfnStreamOutput(
245 msg->base.stream_info.pvArg, header, headerLen,
246 FALSE);
247 LocalFree(header);
250 if (!fFinal)
252 ret = msg->base.stream_info.pfnStreamOutput(
253 msg->base.stream_info.pvArg, (BYTE *)pbData, cbData,
254 FALSE);
255 msg->base.state = MsgStateUpdated;
257 else
259 msg->base.state = MsgStateFinalized;
260 if (msg->base.stream_info.cbContent == 0xffffffff)
262 BYTE indefinite_trailer[6] = { 0 };
264 ret = msg->base.stream_info.pfnStreamOutput(
265 msg->base.stream_info.pvArg, (BYTE *)pbData, cbData,
266 FALSE);
267 if (ret)
268 ret = msg->base.stream_info.pfnStreamOutput(
269 msg->base.stream_info.pvArg, indefinite_trailer,
270 sizeof(indefinite_trailer), TRUE);
272 else
273 ret = msg->base.stream_info.pfnStreamOutput(
274 msg->base.stream_info.pvArg, (BYTE *)pbData, cbData, TRUE);
277 __EXCEPT_PAGE_FAULT
279 SetLastError(STATUS_ACCESS_VIOLATION);
280 ret = FALSE;
282 __ENDTRY;
284 else
286 if (!fFinal)
288 if (msg->base.open_flags & CMSG_DETACHED_FLAG)
289 SetLastError(E_INVALIDARG);
290 else
291 SetLastError(CRYPT_E_MSG_ERROR);
293 else
295 CRYPT_DATA_BLOB blob = { cbData, (LPBYTE)pbData };
297 msg->base.state = MsgStateFinalized;
298 /* non-streamed data messages don't allow non-final updates,
299 * don't bother checking whether data already exist, they can't.
301 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING,
302 &blob, CRYPT_ENCODE_ALLOC_FLAG, NULL, &msg->bare_content,
303 &msg->bare_content_len);
306 return ret;
309 static BOOL CRYPT_CopyParam(void *pvData, DWORD *pcbData, const void *src,
310 DWORD len)
312 BOOL ret = TRUE;
314 if (!pvData)
315 *pcbData = len;
316 else if (*pcbData < len)
318 *pcbData = len;
319 SetLastError(ERROR_MORE_DATA);
320 ret = FALSE;
322 else
324 *pcbData = len;
325 memcpy(pvData, src, len);
327 return ret;
330 static BOOL CDataEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
331 DWORD dwIndex, void *pvData, DWORD *pcbData)
333 CDataEncodeMsg *msg = hCryptMsg;
334 BOOL ret = FALSE;
336 switch (dwParamType)
338 case CMSG_CONTENT_PARAM:
339 if (msg->base.streamed)
340 SetLastError(E_INVALIDARG);
341 else
343 CRYPT_CONTENT_INFO info;
344 char rsa_data[] = "1.2.840.113549.1.7.1";
346 info.pszObjId = rsa_data;
347 info.Content.cbData = msg->bare_content_len;
348 info.Content.pbData = msg->bare_content;
349 ret = CryptEncodeObject(X509_ASN_ENCODING, PKCS_CONTENT_INFO, &info,
350 pvData, pcbData);
352 break;
353 case CMSG_BARE_CONTENT_PARAM:
354 if (msg->base.streamed)
355 SetLastError(E_INVALIDARG);
356 else
357 ret = CRYPT_CopyParam(pvData, pcbData, msg->bare_content,
358 msg->bare_content_len);
359 break;
360 default:
361 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
363 return ret;
366 static HCRYPTMSG CDataEncodeMsg_Open(DWORD dwFlags, const void *pvMsgEncodeInfo,
367 LPSTR pszInnerContentObjID, PCMSG_STREAM_INFO pStreamInfo)
369 CDataEncodeMsg *msg;
371 if (pvMsgEncodeInfo)
373 SetLastError(E_INVALIDARG);
374 return NULL;
376 msg = CryptMemAlloc(sizeof(CDataEncodeMsg));
377 if (msg)
379 CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo,
380 CDataEncodeMsg_Close, CDataEncodeMsg_GetParam, CDataEncodeMsg_Update,
381 CRYPT_DefaultMsgControl);
382 msg->bare_content_len = sizeof(empty_data_content);
383 msg->bare_content = (LPBYTE)empty_data_content;
385 return msg;
388 typedef struct _CHashEncodeMsg
390 CryptMsgBase base;
391 HCRYPTPROV prov;
392 HCRYPTHASH hash;
393 CRYPT_DATA_BLOB data;
394 } CHashEncodeMsg;
396 static void CHashEncodeMsg_Close(HCRYPTMSG hCryptMsg)
398 CHashEncodeMsg *msg = hCryptMsg;
400 CryptMemFree(msg->data.pbData);
401 CryptDestroyHash(msg->hash);
402 if (msg->base.open_flags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG)
403 CryptReleaseContext(msg->prov, 0);
406 static BOOL CRYPT_EncodePKCSDigestedData(CHashEncodeMsg *msg, void *pvData,
407 DWORD *pcbData)
409 BOOL ret;
410 ALG_ID algID;
411 DWORD size = sizeof(algID);
413 ret = CryptGetHashParam(msg->hash, HP_ALGID, (BYTE *)&algID, &size, 0);
414 if (ret)
416 CRYPT_DIGESTED_DATA digestedData = { 0 };
417 char oid_rsa_data[] = szOID_RSA_data;
419 digestedData.version = CMSG_HASHED_DATA_PKCS_1_5_VERSION;
420 digestedData.DigestAlgorithm.pszObjId = (LPSTR)CertAlgIdToOID(algID);
421 /* FIXME: what about digestedData.DigestAlgorithm.Parameters? */
422 /* Quirk: OID is only encoded messages if an update has happened */
423 if (msg->base.state != MsgStateInit)
424 digestedData.ContentInfo.pszObjId = oid_rsa_data;
425 if (!(msg->base.open_flags & CMSG_DETACHED_FLAG) && msg->data.cbData)
427 ret = CRYPT_AsnEncodeOctets(0, NULL, &msg->data,
428 CRYPT_ENCODE_ALLOC_FLAG, NULL,
429 (LPBYTE)&digestedData.ContentInfo.Content.pbData,
430 &digestedData.ContentInfo.Content.cbData);
432 if (msg->base.state == MsgStateFinalized)
433 ret = extract_hash(msg->hash, &digestedData.hash.pbData, &digestedData.hash.cbData);
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 = hCryptMsg;
447 BOOL ret = FALSE;
449 TRACE("(%p, %ld, %ld, %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, pvData, pcbData, 0);
490 break;
491 case CMSG_VERSION_PARAM:
492 if (msg->base.state != MsgStateFinalized)
493 SetLastError(CRYPT_E_MSG_ERROR);
494 else
496 DWORD version = CMSG_HASHED_DATA_PKCS_1_5_VERSION;
498 /* Since the data are always encoded as octets, the version is
499 * always 0 (see rfc3852, section 7)
501 ret = CRYPT_CopyParam(pvData, pcbData, &version, sizeof(version));
503 break;
504 default:
505 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
507 return ret;
510 static BOOL CHashEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
511 DWORD cbData, BOOL fFinal)
513 CHashEncodeMsg *msg = hCryptMsg;
514 BOOL ret = FALSE;
516 TRACE("(%p, %p, %ld, %d)\n", hCryptMsg, pbData, cbData, fFinal);
518 if (msg->base.state == MsgStateFinalized)
519 SetLastError(CRYPT_E_MSG_ERROR);
520 else if (msg->base.streamed || (msg->base.open_flags & CMSG_DETACHED_FLAG))
522 /* Doesn't do much, as stream output is never called, and you
523 * can't get the content.
525 ret = CryptHashData(msg->hash, pbData, cbData, 0);
526 msg->base.state = fFinal ? MsgStateFinalized : MsgStateUpdated;
528 else
530 if (!fFinal)
531 SetLastError(CRYPT_E_MSG_ERROR);
532 else
534 ret = CryptHashData(msg->hash, pbData, cbData, 0);
535 if (ret)
537 msg->data.pbData = CryptMemAlloc(cbData);
538 if (msg->data.pbData)
540 memcpy(msg->data.pbData + msg->data.cbData, pbData, cbData);
541 msg->data.cbData += cbData;
543 else
544 ret = FALSE;
546 msg->base.state = MsgStateFinalized;
549 return ret;
552 static HCRYPTMSG CHashEncodeMsg_Open(DWORD dwFlags, const void *pvMsgEncodeInfo,
553 LPSTR pszInnerContentObjID, PCMSG_STREAM_INFO pStreamInfo)
555 CHashEncodeMsg *msg;
556 const CMSG_HASHED_ENCODE_INFO *info = pvMsgEncodeInfo;
557 HCRYPTPROV prov;
558 ALG_ID algID;
560 if (info->cbSize != sizeof(CMSG_HASHED_ENCODE_INFO))
562 SetLastError(E_INVALIDARG);
563 return NULL;
565 if (!(algID = CertOIDToAlgId(info->HashAlgorithm.pszObjId)))
567 SetLastError(CRYPT_E_UNKNOWN_ALGO);
568 return NULL;
570 if (info->hCryptProv)
571 prov = info->hCryptProv;
572 else
574 prov = I_CryptGetDefaultCryptProv(algID);
575 if (!prov)
577 SetLastError(E_INVALIDARG);
578 return NULL;
580 dwFlags &= ~CMSG_CRYPT_RELEASE_CONTEXT_FLAG;
582 msg = CryptMemAlloc(sizeof(CHashEncodeMsg));
583 if (msg)
585 CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo,
586 CHashEncodeMsg_Close, CHashEncodeMsg_GetParam, CHashEncodeMsg_Update,
587 CRYPT_DefaultMsgControl);
588 msg->prov = prov;
589 msg->data.cbData = 0;
590 msg->data.pbData = NULL;
591 if (!CryptCreateHash(prov, algID, 0, 0, &msg->hash))
593 CryptMsgClose(msg);
594 msg = NULL;
597 return msg;
600 typedef struct _CMSG_SIGNER_ENCODE_INFO_WITH_CMS
602 DWORD cbSize;
603 PCERT_INFO pCertInfo;
604 HCRYPTPROV hCryptProv;
605 DWORD dwKeySpec;
606 CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm;
607 void *pvHashAuxInfo;
608 DWORD cAuthAttr;
609 PCRYPT_ATTRIBUTE rgAuthAttr;
610 DWORD cUnauthAttr;
611 PCRYPT_ATTRIBUTE rgUnauthAttr;
612 CERT_ID SignerId;
613 CRYPT_ALGORITHM_IDENTIFIER HashEncryptionAlgorithm;
614 void *pvHashEncryptionAuxInfo;
615 } CMSG_SIGNER_ENCODE_INFO_WITH_CMS;
617 typedef struct _CMSG_SIGNED_ENCODE_INFO_WITH_CMS
619 DWORD cbSize;
620 DWORD cSigners;
621 CMSG_SIGNER_ENCODE_INFO_WITH_CMS *rgSigners;
622 DWORD cCertEncoded;
623 PCERT_BLOB rgCertEncoded;
624 DWORD cCrlEncoded;
625 PCRL_BLOB rgCrlEncoded;
626 DWORD cAttrCertEncoded;
627 PCERT_BLOB rgAttrCertEncoded;
628 } CMSG_SIGNED_ENCODE_INFO_WITH_CMS;
630 static BOOL CRYPT_IsValidSigner(const CMSG_SIGNER_ENCODE_INFO_WITH_CMS *signer)
632 if (signer->cbSize != sizeof(CMSG_SIGNER_ENCODE_INFO) &&
633 signer->cbSize != sizeof(CMSG_SIGNER_ENCODE_INFO_WITH_CMS))
635 SetLastError(E_INVALIDARG);
636 return FALSE;
638 if (signer->cbSize == sizeof(CMSG_SIGNER_ENCODE_INFO))
640 if (!signer->pCertInfo->SerialNumber.cbData)
642 SetLastError(E_INVALIDARG);
643 return FALSE;
645 if (!signer->pCertInfo->Issuer.cbData)
647 SetLastError(E_INVALIDARG);
648 return FALSE;
651 else if (signer->cbSize == sizeof(CMSG_SIGNER_ENCODE_INFO_WITH_CMS))
653 switch (signer->SignerId.dwIdChoice)
655 case 0:
656 if (!signer->pCertInfo->SerialNumber.cbData)
658 SetLastError(E_INVALIDARG);
659 return FALSE;
661 if (!signer->pCertInfo->Issuer.cbData)
663 SetLastError(E_INVALIDARG);
664 return FALSE;
666 break;
667 case CERT_ID_ISSUER_SERIAL_NUMBER:
668 if (!signer->SignerId.IssuerSerialNumber.SerialNumber.cbData)
670 SetLastError(E_INVALIDARG);
671 return FALSE;
673 if (!signer->SignerId.IssuerSerialNumber.Issuer.cbData)
675 SetLastError(E_INVALIDARG);
676 return FALSE;
678 break;
679 case CERT_ID_KEY_IDENTIFIER:
680 if (!signer->SignerId.KeyId.cbData)
682 SetLastError(E_INVALIDARG);
683 return FALSE;
685 break;
686 default:
687 SetLastError(E_INVALIDARG);
689 if (signer->HashEncryptionAlgorithm.pszObjId)
691 FIXME("CMSG_SIGNER_ENCODE_INFO with CMS fields unsupported\n");
692 return FALSE;
695 if (!signer->hCryptProv)
697 SetLastError(E_INVALIDARG);
698 return FALSE;
700 if (!CertOIDToAlgId(signer->HashAlgorithm.pszObjId))
702 SetLastError(CRYPT_E_UNKNOWN_ALGO);
703 return FALSE;
705 return TRUE;
708 static BOOL CRYPT_ConstructBlob(CRYPT_DATA_BLOB *out, const CRYPT_DATA_BLOB *in)
710 BOOL ret = TRUE;
712 out->cbData = in->cbData;
713 if (out->cbData)
715 out->pbData = CryptMemAlloc(out->cbData);
716 if (out->pbData)
717 memcpy(out->pbData, in->pbData, out->cbData);
718 else
719 ret = FALSE;
721 else
722 out->pbData = NULL;
723 return ret;
726 static BOOL CRYPT_ConstructBlobArray(DWORD *outCBlobs,
727 PCRYPT_DATA_BLOB *outPBlobs, DWORD cBlobs, const CRYPT_DATA_BLOB *pBlobs)
729 BOOL ret = TRUE;
731 *outCBlobs = cBlobs;
732 if (cBlobs)
734 *outPBlobs = CryptMemAlloc(cBlobs * sizeof(CRYPT_DATA_BLOB));
735 if (*outPBlobs)
737 DWORD i;
739 memset(*outPBlobs, 0, cBlobs * sizeof(CRYPT_DATA_BLOB));
740 for (i = 0; ret && i < cBlobs; i++)
741 ret = CRYPT_ConstructBlob(&(*outPBlobs)[i], &pBlobs[i]);
743 else
744 ret = FALSE;
746 return ret;
749 static void CRYPT_FreeBlobArray(DWORD cBlobs, PCRYPT_DATA_BLOB blobs)
751 DWORD i;
753 for (i = 0; i < cBlobs; i++)
754 CryptMemFree(blobs[i].pbData);
755 CryptMemFree(blobs);
758 static BOOL CRYPT_ConstructAttribute(CRYPT_ATTRIBUTE *out,
759 const CRYPT_ATTRIBUTE *in)
761 BOOL ret;
763 out->pszObjId = CryptMemAlloc(strlen(in->pszObjId) + 1);
764 if (out->pszObjId)
766 strcpy(out->pszObjId, in->pszObjId);
767 ret = CRYPT_ConstructBlobArray(&out->cValue, &out->rgValue,
768 in->cValue, in->rgValue);
770 else
771 ret = FALSE;
772 return ret;
775 static BOOL CRYPT_ConstructAttributes(CRYPT_ATTRIBUTES *out,
776 const CRYPT_ATTRIBUTES *in)
778 BOOL ret = TRUE;
780 out->cAttr = in->cAttr;
781 if (out->cAttr)
783 out->rgAttr = CryptMemAlloc(out->cAttr * sizeof(CRYPT_ATTRIBUTE));
784 if (out->rgAttr)
786 DWORD i;
788 memset(out->rgAttr, 0, out->cAttr * sizeof(CRYPT_ATTRIBUTE));
789 for (i = 0; ret && i < out->cAttr; i++)
790 ret = CRYPT_ConstructAttribute(&out->rgAttr[i], &in->rgAttr[i]);
792 else
793 ret = FALSE;
795 else
796 out->rgAttr = NULL;
797 return ret;
800 /* Constructs a CMSG_CMS_SIGNER_INFO from a CMSG_SIGNER_ENCODE_INFO_WITH_CMS. */
801 static BOOL CSignerInfo_Construct(CMSG_CMS_SIGNER_INFO *info,
802 const CMSG_SIGNER_ENCODE_INFO_WITH_CMS *in)
804 BOOL ret;
806 if (in->cbSize == sizeof(CMSG_SIGNER_ENCODE_INFO))
808 info->dwVersion = CMSG_SIGNER_INFO_V1;
809 ret = CRYPT_ConstructBlob(&info->SignerId.IssuerSerialNumber.Issuer,
810 &in->pCertInfo->Issuer);
811 if (ret)
812 ret = CRYPT_ConstructBlob(
813 &info->SignerId.IssuerSerialNumber.SerialNumber,
814 &in->pCertInfo->SerialNumber);
815 info->SignerId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
816 info->HashEncryptionAlgorithm.pszObjId =
817 in->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId;
818 if (ret)
819 ret = CRYPT_ConstructBlob(&info->HashEncryptionAlgorithm.Parameters,
820 &in->pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters);
822 else
824 const CRYPT_ALGORITHM_IDENTIFIER *pEncrAlg;
826 /* Implicitly in->cbSize == sizeof(CMSG_SIGNER_ENCODE_INFO_WITH_CMS).
827 * See CRYPT_IsValidSigner.
829 if (!in->SignerId.dwIdChoice)
831 info->dwVersion = CMSG_SIGNER_INFO_V1;
832 ret = CRYPT_ConstructBlob(&info->SignerId.IssuerSerialNumber.Issuer,
833 &in->pCertInfo->Issuer);
834 if (ret)
835 ret = CRYPT_ConstructBlob(
836 &info->SignerId.IssuerSerialNumber.SerialNumber,
837 &in->pCertInfo->SerialNumber);
838 info->SignerId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
840 else if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
842 info->dwVersion = CMSG_SIGNER_INFO_V1;
843 info->SignerId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
844 ret = CRYPT_ConstructBlob(&info->SignerId.IssuerSerialNumber.Issuer,
845 &in->SignerId.IssuerSerialNumber.Issuer);
846 if (ret)
847 ret = CRYPT_ConstructBlob(
848 &info->SignerId.IssuerSerialNumber.SerialNumber,
849 &in->SignerId.IssuerSerialNumber.SerialNumber);
851 else
853 /* Implicitly dwIdChoice == CERT_ID_KEY_IDENTIFIER */
854 info->dwVersion = CMSG_SIGNER_INFO_V3;
855 info->SignerId.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
856 ret = CRYPT_ConstructBlob(&info->SignerId.KeyId,
857 &in->SignerId.KeyId);
859 pEncrAlg = in->HashEncryptionAlgorithm.pszObjId ?
860 &in->HashEncryptionAlgorithm :
861 &in->pCertInfo->SubjectPublicKeyInfo.Algorithm;
862 info->HashEncryptionAlgorithm.pszObjId = pEncrAlg->pszObjId;
863 if (ret)
864 ret = CRYPT_ConstructBlob(&info->HashEncryptionAlgorithm.Parameters,
865 &pEncrAlg->Parameters);
867 /* Assumption: algorithm IDs will point to static strings, not
868 * stack-based ones, so copying the pointer values is safe.
870 info->HashAlgorithm.pszObjId = in->HashAlgorithm.pszObjId;
871 if (ret)
872 ret = CRYPT_ConstructBlob(&info->HashAlgorithm.Parameters,
873 &in->HashAlgorithm.Parameters);
874 if (ret)
875 ret = CRYPT_ConstructAttributes(&info->AuthAttrs,
876 (CRYPT_ATTRIBUTES *)&in->cAuthAttr);
877 if (ret)
878 ret = CRYPT_ConstructAttributes(&info->UnauthAttrs,
879 (CRYPT_ATTRIBUTES *)&in->cUnauthAttr);
880 return ret;
883 static void CSignerInfo_Free(CMSG_CMS_SIGNER_INFO *info)
885 DWORD i, j;
887 if (info->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
889 CryptMemFree(info->SignerId.IssuerSerialNumber.Issuer.pbData);
890 CryptMemFree(info->SignerId.IssuerSerialNumber.SerialNumber.pbData);
892 else
893 CryptMemFree(info->SignerId.KeyId.pbData);
894 CryptMemFree(info->HashAlgorithm.Parameters.pbData);
895 CryptMemFree(info->HashEncryptionAlgorithm.Parameters.pbData);
896 CryptMemFree(info->EncryptedHash.pbData);
897 for (i = 0; i < info->AuthAttrs.cAttr; i++)
899 for (j = 0; j < info->AuthAttrs.rgAttr[i].cValue; j++)
900 CryptMemFree(info->AuthAttrs.rgAttr[i].rgValue[j].pbData);
901 CryptMemFree(info->AuthAttrs.rgAttr[i].rgValue);
902 CryptMemFree(info->AuthAttrs.rgAttr[i].pszObjId);
904 CryptMemFree(info->AuthAttrs.rgAttr);
905 for (i = 0; i < info->UnauthAttrs.cAttr; i++)
907 for (j = 0; j < info->UnauthAttrs.rgAttr[i].cValue; j++)
908 CryptMemFree(info->UnauthAttrs.rgAttr[i].rgValue[j].pbData);
909 CryptMemFree(info->UnauthAttrs.rgAttr[i].rgValue);
910 CryptMemFree(info->UnauthAttrs.rgAttr[i].pszObjId);
912 CryptMemFree(info->UnauthAttrs.rgAttr);
915 typedef struct _CSignerHandles
917 HCRYPTHASH contentHash;
918 HCRYPTHASH authAttrHash;
919 } CSignerHandles;
921 typedef struct _CSignedMsgData
923 CRYPT_SIGNED_INFO *info;
924 DWORD cSignerHandle;
925 CSignerHandles *signerHandles;
926 } CSignedMsgData;
928 /* Constructs the signer handles for the signerIndex'th signer of msg_data.
929 * Assumes signerIndex is a valid index, and that msg_data's info has already
930 * been constructed.
932 static BOOL CSignedMsgData_ConstructSignerHandles(CSignedMsgData *msg_data,
933 DWORD signerIndex, HCRYPTPROV *crypt_prov, DWORD *flags)
935 ALG_ID algID;
936 BOOL ret;
938 algID = CertOIDToAlgId(
939 msg_data->info->rgSignerInfo[signerIndex].HashAlgorithm.pszObjId);
941 if (!*crypt_prov)
943 *crypt_prov = I_CryptGetDefaultCryptProv(algID);
944 if (!*crypt_prov) return FALSE;
945 *flags &= ~CMSG_CRYPT_RELEASE_CONTEXT_FLAG;
948 ret = CryptCreateHash(*crypt_prov, algID, 0, 0,
949 &msg_data->signerHandles->contentHash);
950 if (ret && msg_data->info->rgSignerInfo[signerIndex].AuthAttrs.cAttr > 0)
951 ret = CryptCreateHash(*crypt_prov, algID, 0, 0,
952 &msg_data->signerHandles->authAttrHash);
953 return ret;
956 /* Allocates a CSignedMsgData's handles. Assumes its info has already been
957 * constructed.
959 static BOOL CSignedMsgData_AllocateHandles(CSignedMsgData *msg_data)
961 BOOL ret = TRUE;
963 if (msg_data->info->cSignerInfo)
965 msg_data->signerHandles =
966 CryptMemAlloc(msg_data->info->cSignerInfo * sizeof(CSignerHandles));
967 if (msg_data->signerHandles)
969 msg_data->cSignerHandle = msg_data->info->cSignerInfo;
970 memset(msg_data->signerHandles, 0,
971 msg_data->info->cSignerInfo * sizeof(CSignerHandles));
973 else
975 msg_data->cSignerHandle = 0;
976 ret = FALSE;
979 else
981 msg_data->cSignerHandle = 0;
982 msg_data->signerHandles = NULL;
984 return ret;
987 static void CSignedMsgData_CloseHandles(CSignedMsgData *msg_data)
989 DWORD i;
991 for (i = 0; i < msg_data->cSignerHandle; i++)
993 if (msg_data->signerHandles[i].contentHash)
994 CryptDestroyHash(msg_data->signerHandles[i].contentHash);
995 if (msg_data->signerHandles[i].authAttrHash)
996 CryptDestroyHash(msg_data->signerHandles[i].authAttrHash);
998 CryptMemFree(msg_data->signerHandles);
999 msg_data->signerHandles = NULL;
1000 msg_data->cSignerHandle = 0;
1003 static BOOL CSignedMsgData_UpdateHash(CSignedMsgData *msg_data,
1004 const BYTE *pbData, DWORD cbData)
1006 DWORD i;
1007 BOOL ret = TRUE;
1009 for (i = 0; ret && i < msg_data->cSignerHandle; i++)
1010 ret = CryptHashData(msg_data->signerHandles[i].contentHash, pbData,
1011 cbData, 0);
1012 return ret;
1015 static BOOL CRYPT_AppendAttribute(CRYPT_ATTRIBUTES *out,
1016 const CRYPT_ATTRIBUTE *in)
1018 BOOL ret = FALSE;
1020 out->rgAttr = CryptMemRealloc(out->rgAttr,
1021 (out->cAttr + 1) * sizeof(CRYPT_ATTRIBUTE));
1022 if (out->rgAttr)
1024 ret = CRYPT_ConstructAttribute(&out->rgAttr[out->cAttr], in);
1025 if (ret)
1026 out->cAttr++;
1028 return ret;
1031 static BOOL CSignedMsgData_AppendMessageDigestAttribute(
1032 CSignedMsgData *msg_data, DWORD signerIndex)
1034 BOOL ret;
1035 CRYPT_HASH_BLOB hash = { 0, NULL }, encodedHash = { 0, NULL };
1036 char messageDigest[] = szOID_RSA_messageDigest;
1037 CRYPT_ATTRIBUTE messageDigestAttr = { messageDigest, 1, &encodedHash };
1039 if (!(ret = extract_hash(msg_data->signerHandles[signerIndex].contentHash, &hash.pbData, &hash.cbData)))
1040 return FALSE;
1042 ret = CRYPT_AsnEncodeOctets(0, NULL, &hash, CRYPT_ENCODE_ALLOC_FLAG, NULL, (LPBYTE)&encodedHash.pbData,
1043 &encodedHash.cbData);
1044 if (ret)
1046 ret = CRYPT_AppendAttribute(
1047 &msg_data->info->rgSignerInfo[signerIndex].AuthAttrs,
1048 &messageDigestAttr);
1049 LocalFree(encodedHash.pbData);
1051 CryptMemFree(hash.pbData);
1052 return ret;
1055 typedef enum {
1056 Sign,
1057 Verify
1058 } SignOrVerify;
1060 static BOOL CSignedMsgData_UpdateAuthenticatedAttributes(
1061 CSignedMsgData *msg_data, SignOrVerify flag)
1063 DWORD i;
1064 BOOL ret = TRUE;
1066 TRACE("(%p)\n", msg_data);
1068 for (i = 0; ret && i < msg_data->info->cSignerInfo; i++)
1070 if (msg_data->info->rgSignerInfo[i].AuthAttrs.cAttr)
1072 if (flag == Sign)
1074 BYTE oid_rsa_data_encoded[] = { 0x06,0x09,0x2a,0x86,0x48,0x86,
1075 0xf7,0x0d,0x01,0x07,0x01 };
1076 CRYPT_DATA_BLOB content = { sizeof(oid_rsa_data_encoded),
1077 oid_rsa_data_encoded };
1078 char contentType[] = szOID_RSA_contentType;
1079 CRYPT_ATTRIBUTE contentTypeAttr = { contentType, 1, &content };
1081 /* FIXME: does this depend on inner OID? */
1082 ret = CRYPT_AppendAttribute(
1083 &msg_data->info->rgSignerInfo[i].AuthAttrs, &contentTypeAttr);
1084 if (ret)
1085 ret = CSignedMsgData_AppendMessageDigestAttribute(msg_data,
1088 if (ret)
1090 LPBYTE encodedAttrs;
1091 DWORD size;
1093 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, PKCS_ATTRIBUTES,
1094 &msg_data->info->rgSignerInfo[i].AuthAttrs,
1095 CRYPT_ENCODE_ALLOC_FLAG, NULL, &encodedAttrs, &size);
1096 if (ret)
1098 ret = CryptHashData(
1099 msg_data->signerHandles[i].authAttrHash, encodedAttrs,
1100 size, 0);
1101 LocalFree(encodedAttrs);
1106 TRACE("returning %d\n", ret);
1107 return ret;
1110 static void CRYPT_ReverseBytes(CRYPT_HASH_BLOB *hash)
1112 DWORD i;
1113 BYTE tmp;
1115 for (i = 0; i < hash->cbData / 2; i++)
1117 tmp = hash->pbData[hash->cbData - i - 1];
1118 hash->pbData[hash->cbData - i - 1] = hash->pbData[i];
1119 hash->pbData[i] = tmp;
1123 static BOOL CSignedMsgData_Sign(CSignedMsgData *msg_data)
1125 DWORD i;
1126 BOOL ret = TRUE;
1128 TRACE("(%p)\n", msg_data);
1130 for (i = 0; ret && i < msg_data->info->cSignerInfo; i++)
1132 HCRYPTHASH hash;
1133 DWORD keySpec = msg_data->info->signerKeySpec[i];
1135 if (!keySpec)
1136 keySpec = AT_SIGNATURE;
1137 if (msg_data->info->rgSignerInfo[i].AuthAttrs.cAttr)
1138 hash = msg_data->signerHandles[i].authAttrHash;
1139 else
1140 hash = msg_data->signerHandles[i].contentHash;
1141 ret = CryptSignHashW(hash, keySpec, NULL, 0, NULL,
1142 &msg_data->info->rgSignerInfo[i].EncryptedHash.cbData);
1143 if (ret)
1145 msg_data->info->rgSignerInfo[i].EncryptedHash.pbData =
1146 CryptMemAlloc(
1147 msg_data->info->rgSignerInfo[i].EncryptedHash.cbData);
1148 if (msg_data->info->rgSignerInfo[i].EncryptedHash.pbData)
1150 ret = CryptSignHashW(hash, keySpec, NULL, 0,
1151 msg_data->info->rgSignerInfo[i].EncryptedHash.pbData,
1152 &msg_data->info->rgSignerInfo[i].EncryptedHash.cbData);
1153 if (ret)
1154 CRYPT_ReverseBytes(
1155 &msg_data->info->rgSignerInfo[i].EncryptedHash);
1157 else
1158 ret = FALSE;
1161 return ret;
1164 static BOOL CSignedMsgData_Update(CSignedMsgData *msg_data,
1165 const BYTE *pbData, DWORD cbData, BOOL fFinal, SignOrVerify flag)
1167 BOOL ret = CSignedMsgData_UpdateHash(msg_data, pbData, cbData);
1169 if (ret && fFinal)
1171 ret = CSignedMsgData_UpdateAuthenticatedAttributes(msg_data, flag);
1172 if (ret && flag == Sign)
1173 ret = CSignedMsgData_Sign(msg_data);
1175 return ret;
1178 typedef struct _CSignedEncodeMsg
1180 CryptMsgBase base;
1181 LPSTR innerOID;
1182 CRYPT_DATA_BLOB data;
1183 CSignedMsgData msg_data;
1184 } CSignedEncodeMsg;
1186 static void CSignedEncodeMsg_Close(HCRYPTMSG hCryptMsg)
1188 CSignedEncodeMsg *msg = hCryptMsg;
1189 DWORD i;
1191 CryptMemFree(msg->innerOID);
1192 CryptMemFree(msg->data.pbData);
1193 CRYPT_FreeBlobArray(msg->msg_data.info->cCertEncoded,
1194 msg->msg_data.info->rgCertEncoded);
1195 CRYPT_FreeBlobArray(msg->msg_data.info->cCrlEncoded,
1196 msg->msg_data.info->rgCrlEncoded);
1197 for (i = 0; i < msg->msg_data.info->cSignerInfo; i++)
1198 CSignerInfo_Free(&msg->msg_data.info->rgSignerInfo[i]);
1199 CSignedMsgData_CloseHandles(&msg->msg_data);
1200 CryptMemFree(msg->msg_data.info->signerKeySpec);
1201 CryptMemFree(msg->msg_data.info->rgSignerInfo);
1202 CryptMemFree(msg->msg_data.info);
1205 static BOOL CSignedEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
1206 DWORD dwIndex, void *pvData, DWORD *pcbData)
1208 CSignedEncodeMsg *msg = hCryptMsg;
1209 BOOL ret = FALSE;
1211 switch (dwParamType)
1213 case CMSG_CONTENT_PARAM:
1215 CRYPT_CONTENT_INFO info;
1217 ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0, NULL,
1218 &info.Content.cbData);
1219 if (ret)
1221 info.Content.pbData = CryptMemAlloc(info.Content.cbData);
1222 if (info.Content.pbData)
1224 ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0,
1225 info.Content.pbData, &info.Content.cbData);
1226 if (ret)
1228 char oid_rsa_signed[] = szOID_RSA_signedData;
1230 info.pszObjId = oid_rsa_signed;
1231 ret = CryptEncodeObjectEx(X509_ASN_ENCODING,
1232 PKCS_CONTENT_INFO, &info, 0, NULL, pvData, pcbData);
1234 CryptMemFree(info.Content.pbData);
1236 else
1237 ret = FALSE;
1239 break;
1241 case CMSG_BARE_CONTENT_PARAM:
1243 CRYPT_SIGNED_INFO info;
1244 BOOL freeContent = FALSE;
1246 info = *msg->msg_data.info;
1247 if (!msg->innerOID || !strcmp(msg->innerOID, szOID_RSA_data))
1249 char oid_rsa_data[] = szOID_RSA_data;
1251 /* Quirk: OID is only encoded messages if an update has happened */
1252 if (msg->base.state != MsgStateInit)
1253 info.content.pszObjId = oid_rsa_data;
1254 else
1255 info.content.pszObjId = NULL;
1256 if (msg->data.cbData)
1258 CRYPT_DATA_BLOB blob = { msg->data.cbData, msg->data.pbData };
1260 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING,
1261 &blob, CRYPT_ENCODE_ALLOC_FLAG, NULL,
1262 &info.content.Content.pbData, &info.content.Content.cbData);
1263 freeContent = TRUE;
1265 else
1267 info.content.Content.cbData = 0;
1268 info.content.Content.pbData = NULL;
1269 ret = TRUE;
1272 else
1274 info.content.pszObjId = msg->innerOID;
1275 info.content.Content.cbData = msg->data.cbData;
1276 info.content.Content.pbData = msg->data.pbData;
1277 ret = TRUE;
1279 if (ret)
1281 ret = CRYPT_AsnEncodeCMSSignedInfo(&info, pvData, pcbData);
1282 if (freeContent)
1283 LocalFree(info.content.Content.pbData);
1285 break;
1287 case CMSG_COMPUTED_HASH_PARAM:
1288 if (dwIndex >= msg->msg_data.cSignerHandle)
1289 SetLastError(CRYPT_E_INVALID_INDEX);
1290 else
1291 ret = CryptGetHashParam(
1292 msg->msg_data.signerHandles[dwIndex].contentHash, HP_HASHVAL,
1293 pvData, pcbData, 0);
1294 break;
1295 case CMSG_ENCODED_SIGNER:
1296 if (dwIndex >= msg->msg_data.info->cSignerInfo)
1297 SetLastError(CRYPT_E_INVALID_INDEX);
1298 else
1299 ret = CryptEncodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
1300 CMS_SIGNER_INFO, &msg->msg_data.info->rgSignerInfo[dwIndex], 0,
1301 NULL, pvData, pcbData);
1302 break;
1303 case CMSG_VERSION_PARAM:
1304 ret = CRYPT_CopyParam(pvData, pcbData, &msg->msg_data.info->version,
1305 sizeof(msg->msg_data.info->version));
1306 break;
1307 default:
1308 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
1310 return ret;
1313 static BOOL CSignedEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
1314 DWORD cbData, BOOL fFinal)
1316 CSignedEncodeMsg *msg = hCryptMsg;
1317 BOOL ret = FALSE;
1319 if (msg->base.state == MsgStateFinalized)
1320 SetLastError(CRYPT_E_MSG_ERROR);
1321 else if (msg->base.streamed || (msg->base.open_flags & CMSG_DETACHED_FLAG))
1323 ret = CSignedMsgData_Update(&msg->msg_data, pbData, cbData, fFinal,
1324 Sign);
1325 if (msg->base.streamed)
1326 FIXME("streamed partial stub\n");
1327 msg->base.state = fFinal ? MsgStateFinalized : MsgStateUpdated;
1329 else
1331 if (!fFinal)
1332 SetLastError(CRYPT_E_MSG_ERROR);
1333 else
1335 if (cbData)
1337 msg->data.pbData = CryptMemAlloc(cbData);
1338 if (msg->data.pbData)
1340 memcpy(msg->data.pbData, pbData, cbData);
1341 msg->data.cbData = cbData;
1342 ret = TRUE;
1345 else
1346 ret = TRUE;
1347 if (ret)
1348 ret = CSignedMsgData_Update(&msg->msg_data, pbData, cbData,
1349 fFinal, Sign);
1350 msg->base.state = MsgStateFinalized;
1353 return ret;
1356 static HCRYPTMSG CSignedEncodeMsg_Open(DWORD dwFlags,
1357 const void *pvMsgEncodeInfo, LPCSTR pszInnerContentObjID,
1358 PCMSG_STREAM_INFO pStreamInfo)
1360 const CMSG_SIGNED_ENCODE_INFO_WITH_CMS *info = pvMsgEncodeInfo;
1361 DWORD i;
1362 CSignedEncodeMsg *msg;
1364 if (info->cbSize != sizeof(CMSG_SIGNED_ENCODE_INFO) &&
1365 info->cbSize != sizeof(CMSG_SIGNED_ENCODE_INFO_WITH_CMS))
1367 SetLastError(E_INVALIDARG);
1368 return NULL;
1370 if (info->cbSize == sizeof(CMSG_SIGNED_ENCODE_INFO_WITH_CMS) &&
1371 info->cAttrCertEncoded)
1373 FIXME("CMSG_SIGNED_ENCODE_INFO with CMS fields unsupported\n");
1374 return NULL;
1376 for (i = 0; i < info->cSigners; i++)
1377 if (!CRYPT_IsValidSigner(&info->rgSigners[i]))
1378 return NULL;
1379 msg = CryptMemAlloc(sizeof(CSignedEncodeMsg));
1380 if (msg)
1382 BOOL ret = TRUE;
1384 CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo,
1385 CSignedEncodeMsg_Close, CSignedEncodeMsg_GetParam,
1386 CSignedEncodeMsg_Update, CRYPT_DefaultMsgControl);
1387 if (pszInnerContentObjID)
1389 msg->innerOID = CryptMemAlloc(strlen(pszInnerContentObjID) + 1);
1390 if (msg->innerOID)
1391 strcpy(msg->innerOID, pszInnerContentObjID);
1392 else
1393 ret = FALSE;
1395 else
1396 msg->innerOID = NULL;
1397 msg->data.cbData = 0;
1398 msg->data.pbData = NULL;
1399 if (ret)
1400 msg->msg_data.info = CryptMemAlloc(sizeof(CRYPT_SIGNED_INFO));
1401 else
1402 msg->msg_data.info = NULL;
1403 if (msg->msg_data.info)
1405 memset(msg->msg_data.info, 0, sizeof(CRYPT_SIGNED_INFO));
1406 msg->msg_data.info->version = CMSG_SIGNED_DATA_V1;
1408 else
1409 ret = FALSE;
1410 if (ret)
1412 if (info->cSigners)
1414 msg->msg_data.info->rgSignerInfo =
1415 CryptMemAlloc(info->cSigners * sizeof(CMSG_CMS_SIGNER_INFO));
1416 if (msg->msg_data.info->rgSignerInfo)
1418 msg->msg_data.info->cSignerInfo = info->cSigners;
1419 memset(msg->msg_data.info->rgSignerInfo, 0,
1420 msg->msg_data.info->cSignerInfo *
1421 sizeof(CMSG_CMS_SIGNER_INFO));
1422 ret = CSignedMsgData_AllocateHandles(&msg->msg_data);
1423 msg->msg_data.info->signerKeySpec = CryptMemAlloc(info->cSigners * sizeof(DWORD));
1424 if (!msg->msg_data.info->signerKeySpec)
1425 ret = FALSE;
1426 for (i = 0; ret && i < msg->msg_data.info->cSignerInfo; i++)
1428 if (info->rgSigners[i].SignerId.dwIdChoice ==
1429 CERT_ID_KEY_IDENTIFIER)
1430 msg->msg_data.info->version = CMSG_SIGNED_DATA_V3;
1431 ret = CSignerInfo_Construct(
1432 &msg->msg_data.info->rgSignerInfo[i],
1433 &info->rgSigners[i]);
1434 if (ret)
1436 ret = CSignedMsgData_ConstructSignerHandles(
1437 &msg->msg_data, i, &info->rgSigners[i].hCryptProv, &dwFlags);
1438 if (dwFlags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG)
1439 CryptReleaseContext(info->rgSigners[i].hCryptProv,
1442 msg->msg_data.info->signerKeySpec[i] =
1443 info->rgSigners[i].dwKeySpec;
1446 else
1447 ret = FALSE;
1449 else
1451 msg->msg_data.info->cSignerInfo = 0;
1452 msg->msg_data.signerHandles = NULL;
1453 msg->msg_data.cSignerHandle = 0;
1456 if (ret)
1457 ret = CRYPT_ConstructBlobArray(&msg->msg_data.info->cCertEncoded,
1458 &msg->msg_data.info->rgCertEncoded, info->cCertEncoded,
1459 info->rgCertEncoded);
1460 if (ret)
1461 ret = CRYPT_ConstructBlobArray(&msg->msg_data.info->cCrlEncoded,
1462 &msg->msg_data.info->rgCrlEncoded, info->cCrlEncoded,
1463 info->rgCrlEncoded);
1464 if (!ret)
1466 CSignedEncodeMsg_Close(msg);
1467 CryptMemFree(msg);
1468 msg = NULL;
1471 return msg;
1474 typedef struct _CMSG_ENVELOPED_ENCODE_INFO_WITH_CMS
1476 DWORD cbSize;
1477 HCRYPTPROV_LEGACY hCryptProv;
1478 CRYPT_ALGORITHM_IDENTIFIER ContentEncryptionAlgorithm;
1479 void *pvEncryptionAuxInfo;
1480 DWORD cRecipients;
1481 PCERT_INFO *rgpRecipientCert;
1482 PCMSG_RECIPIENT_ENCODE_INFO rgCmsRecipients;
1483 DWORD cCertEncoded;
1484 PCERT_BLOB rgCertEncoded;
1485 DWORD cCrlEncoded;
1486 PCRL_BLOB rgCrlEncoded;
1487 DWORD cAttrCertEncoded;
1488 PCERT_BLOB rgAttrCertEncoded;
1489 DWORD cUnprotectedAttr;
1490 PCRYPT_ATTRIBUTE rgUnprotectedAttr;
1491 } CMSG_ENVELOPED_ENCODE_INFO_WITH_CMS;
1493 typedef struct _CEnvelopedEncodeMsg
1495 CryptMsgBase base;
1496 CRYPT_ALGORITHM_IDENTIFIER algo;
1497 HCRYPTPROV prov;
1498 HCRYPTKEY key;
1499 DWORD cRecipientInfo;
1500 CMSG_KEY_TRANS_RECIPIENT_INFO *recipientInfo;
1501 CRYPT_DATA_BLOB data;
1502 } CEnvelopedEncodeMsg;
1504 static BOOL CRYPT_ConstructAlgorithmId(CRYPT_ALGORITHM_IDENTIFIER *out,
1505 const CRYPT_ALGORITHM_IDENTIFIER *in)
1507 out->pszObjId = CryptMemAlloc(strlen(in->pszObjId) + 1);
1508 if (out->pszObjId)
1510 strcpy(out->pszObjId, in->pszObjId);
1511 return CRYPT_ConstructBlob(&out->Parameters, &in->Parameters);
1513 else
1514 return FALSE;
1517 static BOOL CRYPT_ConstructBitBlob(CRYPT_BIT_BLOB *out, const CRYPT_BIT_BLOB *in)
1519 out->cbData = in->cbData;
1520 out->cUnusedBits = in->cUnusedBits;
1521 if (out->cbData)
1523 out->pbData = CryptMemAlloc(out->cbData);
1524 if (out->pbData)
1525 memcpy(out->pbData, in->pbData, out->cbData);
1526 else
1527 return FALSE;
1529 else
1530 out->pbData = NULL;
1531 return TRUE;
1534 static BOOL CRYPT_GenKey(CMSG_CONTENT_ENCRYPT_INFO *info, ALG_ID algID)
1536 static HCRYPTOIDFUNCSET set = NULL;
1537 PFN_CMSG_GEN_CONTENT_ENCRYPT_KEY genKeyFunc = NULL;
1538 HCRYPTOIDFUNCADDR hFunc;
1539 BOOL ret;
1541 if (!set)
1542 set = CryptInitOIDFunctionSet(CMSG_OID_GEN_CONTENT_ENCRYPT_KEY_FUNC, 0);
1543 CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING,
1544 info->ContentEncryptionAlgorithm.pszObjId, 0, (void **)&genKeyFunc, &hFunc);
1545 if (genKeyFunc)
1547 ret = genKeyFunc(info, 0, NULL);
1548 CryptFreeOIDFunctionAddress(hFunc, 0);
1550 else
1551 ret = CryptGenKey(info->hCryptProv, algID, CRYPT_EXPORTABLE,
1552 &info->hContentEncryptKey);
1553 return ret;
1556 static BOOL WINAPI CRYPT_ExportKeyTrans(
1557 PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo,
1558 PCMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO pKeyTransEncodeInfo,
1559 PCMSG_KEY_TRANS_ENCRYPT_INFO pKeyTransEncryptInfo,
1560 DWORD dwFlags, void *pvReserved)
1562 CERT_PUBLIC_KEY_INFO keyInfo;
1563 HCRYPTKEY expKey;
1564 BOOL ret;
1566 ret = CRYPT_ConstructAlgorithmId(&keyInfo.Algorithm,
1567 &pKeyTransEncodeInfo->KeyEncryptionAlgorithm);
1568 if (ret)
1569 ret = CRYPT_ConstructBitBlob(&keyInfo.PublicKey,
1570 &pKeyTransEncodeInfo->RecipientPublicKey);
1571 if (ret)
1572 ret = CryptImportPublicKeyInfo(pKeyTransEncodeInfo->hCryptProv,
1573 X509_ASN_ENCODING, &keyInfo, &expKey);
1574 if (ret)
1576 DWORD size;
1578 ret = CryptExportKey(pContentEncryptInfo->hContentEncryptKey, expKey,
1579 SIMPLEBLOB, 0, NULL, &size);
1580 if (ret)
1582 BYTE *keyBlob;
1584 keyBlob = CryptMemAlloc(size);
1585 if (keyBlob)
1587 ret = CryptExportKey(pContentEncryptInfo->hContentEncryptKey,
1588 expKey, SIMPLEBLOB, 0, keyBlob, &size);
1589 if (ret)
1591 DWORD head = sizeof(BLOBHEADER) + sizeof(ALG_ID);
1593 pKeyTransEncryptInfo->EncryptedKey.pbData =
1594 CryptMemAlloc(size - head);
1595 if (pKeyTransEncryptInfo->EncryptedKey.pbData)
1597 DWORD i, k = 0;
1599 pKeyTransEncryptInfo->EncryptedKey.cbData = size - head;
1600 for (i = size - 1; i >= head; --i, ++k)
1601 pKeyTransEncryptInfo->EncryptedKey.pbData[k] =
1602 keyBlob[i];
1604 else
1605 ret = FALSE;
1607 CryptMemFree(keyBlob);
1609 else
1610 ret = FALSE;
1612 CryptDestroyKey(expKey);
1615 CryptMemFree(keyInfo.PublicKey.pbData);
1616 CryptMemFree(keyInfo.Algorithm.pszObjId);
1617 CryptMemFree(keyInfo.Algorithm.Parameters.pbData);
1618 return ret;
1621 static BOOL CRYPT_ExportEncryptedKey(CMSG_CONTENT_ENCRYPT_INFO *info, DWORD i,
1622 CRYPT_DATA_BLOB *key)
1624 static HCRYPTOIDFUNCSET set = NULL;
1625 PFN_CMSG_EXPORT_KEY_TRANS exportKeyFunc = NULL;
1626 HCRYPTOIDFUNCADDR hFunc = NULL;
1627 CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO *encodeInfo =
1628 info->rgCmsRecipients[i].pKeyTrans;
1629 CMSG_KEY_TRANS_ENCRYPT_INFO encryptInfo;
1630 BOOL ret;
1632 memset(&encryptInfo, 0, sizeof(encryptInfo));
1633 encryptInfo.cbSize = sizeof(encryptInfo);
1634 encryptInfo.dwRecipientIndex = i;
1635 ret = CRYPT_ConstructAlgorithmId(&encryptInfo.KeyEncryptionAlgorithm,
1636 &encodeInfo->KeyEncryptionAlgorithm);
1638 if (!set)
1639 set = CryptInitOIDFunctionSet(CMSG_OID_EXPORT_KEY_TRANS_FUNC, 0);
1640 CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING,
1641 encryptInfo.KeyEncryptionAlgorithm.pszObjId, 0, (void **)&exportKeyFunc,
1642 &hFunc);
1643 if (!exportKeyFunc)
1644 exportKeyFunc = CRYPT_ExportKeyTrans;
1645 if (ret)
1647 ret = exportKeyFunc(info, encodeInfo, &encryptInfo, 0, NULL);
1648 if (ret)
1650 key->cbData = encryptInfo.EncryptedKey.cbData;
1651 key->pbData = encryptInfo.EncryptedKey.pbData;
1654 if (hFunc)
1655 CryptFreeOIDFunctionAddress(hFunc, 0);
1657 CryptMemFree(encryptInfo.KeyEncryptionAlgorithm.pszObjId);
1658 CryptMemFree(encryptInfo.KeyEncryptionAlgorithm.Parameters.pbData);
1659 return ret;
1662 static LPVOID WINAPI mem_alloc(size_t size)
1664 return CryptMemAlloc(size);
1667 static VOID WINAPI mem_free(LPVOID pv)
1669 CryptMemFree(pv);
1673 static BOOL CContentEncryptInfo_Construct(CMSG_CONTENT_ENCRYPT_INFO *info,
1674 const CMSG_ENVELOPED_ENCODE_INFO_WITH_CMS *in, HCRYPTPROV prov)
1676 BOOL ret;
1678 info->cbSize = sizeof(CMSG_CONTENT_ENCRYPT_INFO);
1679 info->hCryptProv = prov;
1680 ret = CRYPT_ConstructAlgorithmId(&info->ContentEncryptionAlgorithm,
1681 &in->ContentEncryptionAlgorithm);
1682 info->pvEncryptionAuxInfo = in->pvEncryptionAuxInfo;
1683 info->cRecipients = in->cRecipients;
1684 if (ret)
1686 info->rgCmsRecipients = CryptMemAlloc(in->cRecipients *
1687 sizeof(CMSG_RECIPIENT_ENCODE_INFO));
1688 if (info->rgCmsRecipients)
1690 DWORD i;
1692 for (i = 0; ret && i < in->cRecipients; ++i)
1694 CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO *encodeInfo;
1695 CERT_INFO *cert = in->rgpRecipientCert[i];
1697 info->rgCmsRecipients[i].dwRecipientChoice =
1698 CMSG_KEY_TRANS_RECIPIENT;
1699 encodeInfo = CryptMemAlloc(sizeof(*encodeInfo));
1700 info->rgCmsRecipients[i].pKeyTrans = encodeInfo;
1701 if (encodeInfo)
1703 encodeInfo->cbSize = sizeof(*encodeInfo);
1704 ret = CRYPT_ConstructAlgorithmId(
1705 &encodeInfo->KeyEncryptionAlgorithm,
1706 &cert->SubjectPublicKeyInfo.Algorithm);
1707 encodeInfo->pvKeyEncryptionAuxInfo = NULL;
1708 encodeInfo->hCryptProv = prov;
1709 if (ret)
1710 ret = CRYPT_ConstructBitBlob(
1711 &encodeInfo->RecipientPublicKey,
1712 &cert->SubjectPublicKeyInfo.PublicKey);
1713 if (ret)
1714 ret = CRYPT_ConstructBlob(
1715 &encodeInfo->RecipientId.IssuerSerialNumber.Issuer,
1716 &cert->Issuer);
1717 if (ret)
1718 ret = CRYPT_ConstructBlob(
1719 &encodeInfo->RecipientId.IssuerSerialNumber.SerialNumber,
1720 &cert->SerialNumber);
1722 else
1723 ret = FALSE;
1726 else
1727 ret = FALSE;
1729 info->pfnAlloc = mem_alloc;
1730 info->pfnFree = mem_free;
1731 return ret;
1734 static void CContentEncryptInfo_Free(CMSG_CONTENT_ENCRYPT_INFO *info)
1736 CryptMemFree(info->ContentEncryptionAlgorithm.pszObjId);
1737 CryptMemFree(info->ContentEncryptionAlgorithm.Parameters.pbData);
1738 if (info->rgCmsRecipients)
1740 DWORD i;
1742 for (i = 0; i < info->cRecipients; ++i)
1744 CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO *encodeInfo =
1745 info->rgCmsRecipients[i].pKeyTrans;
1747 CryptMemFree(encodeInfo->KeyEncryptionAlgorithm.pszObjId);
1748 CryptMemFree(encodeInfo->KeyEncryptionAlgorithm.Parameters.pbData);
1749 CryptMemFree(encodeInfo->RecipientPublicKey.pbData);
1750 CryptMemFree(
1751 encodeInfo->RecipientId.IssuerSerialNumber.Issuer.pbData);
1752 CryptMemFree(
1753 encodeInfo->RecipientId.IssuerSerialNumber.SerialNumber.pbData);
1754 CryptMemFree(encodeInfo);
1756 CryptMemFree(info->rgCmsRecipients);
1760 static BOOL CRecipientInfo_Construct(CMSG_KEY_TRANS_RECIPIENT_INFO *info,
1761 const CERT_INFO *cert, CRYPT_DATA_BLOB *key)
1763 BOOL ret;
1765 info->dwVersion = CMSG_KEY_TRANS_PKCS_1_5_VERSION;
1766 info->RecipientId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
1767 ret = CRYPT_ConstructBlob(&info->RecipientId.IssuerSerialNumber.Issuer,
1768 &cert->Issuer);
1769 if (ret)
1770 ret = CRYPT_ConstructBlob(
1771 &info->RecipientId.IssuerSerialNumber.SerialNumber,
1772 &cert->SerialNumber);
1773 if (ret)
1774 ret = CRYPT_ConstructAlgorithmId(&info->KeyEncryptionAlgorithm,
1775 &cert->SubjectPublicKeyInfo.Algorithm);
1776 info->EncryptedKey.cbData = key->cbData;
1777 info->EncryptedKey.pbData = key->pbData;
1778 return ret;
1781 static void CRecipientInfo_Free(CMSG_KEY_TRANS_RECIPIENT_INFO *info)
1783 CryptMemFree(info->RecipientId.IssuerSerialNumber.Issuer.pbData);
1784 CryptMemFree(info->RecipientId.IssuerSerialNumber.SerialNumber.pbData);
1785 CryptMemFree(info->KeyEncryptionAlgorithm.pszObjId);
1786 CryptMemFree(info->KeyEncryptionAlgorithm.Parameters.pbData);
1787 CryptMemFree(info->EncryptedKey.pbData);
1790 static void CEnvelopedEncodeMsg_Close(HCRYPTMSG hCryptMsg)
1792 CEnvelopedEncodeMsg *msg = hCryptMsg;
1794 CryptMemFree(msg->algo.pszObjId);
1795 CryptMemFree(msg->algo.Parameters.pbData);
1796 if (msg->base.open_flags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG)
1797 CryptReleaseContext(msg->prov, 0);
1798 CryptDestroyKey(msg->key);
1799 if (msg->recipientInfo)
1801 DWORD i;
1803 for (i = 0; i < msg->cRecipientInfo; ++i)
1804 CRecipientInfo_Free(&msg->recipientInfo[i]);
1805 CryptMemFree(msg->recipientInfo);
1807 CryptMemFree(msg->data.pbData);
1810 static BOOL CEnvelopedEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
1811 DWORD dwIndex, void *pvData, DWORD *pcbData)
1813 CEnvelopedEncodeMsg *msg = hCryptMsg;
1814 BOOL ret = FALSE;
1816 switch (dwParamType)
1818 case CMSG_BARE_CONTENT_PARAM:
1819 if (msg->base.streamed)
1820 SetLastError(E_INVALIDARG);
1821 else
1823 char oid_rsa_data[] = szOID_RSA_data;
1824 CRYPT_ENVELOPED_DATA envelopedData = {
1825 CMSG_ENVELOPED_DATA_PKCS_1_5_VERSION, msg->cRecipientInfo,
1826 msg->recipientInfo, { oid_rsa_data, {
1827 msg->algo.pszObjId,
1828 { msg->algo.Parameters.cbData, msg->algo.Parameters.pbData }
1830 { msg->data.cbData, msg->data.pbData }
1834 ret = CRYPT_AsnEncodePKCSEnvelopedData(&envelopedData, pvData,
1835 pcbData);
1837 break;
1838 case CMSG_CONTENT_PARAM:
1840 CRYPT_CONTENT_INFO info;
1842 ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0, NULL,
1843 &info.Content.cbData);
1844 if (ret)
1846 info.Content.pbData = CryptMemAlloc(info.Content.cbData);
1847 if (info.Content.pbData)
1849 ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0,
1850 info.Content.pbData, &info.Content.cbData);
1851 if (ret)
1853 char oid_rsa_enveloped[] = szOID_RSA_envelopedData;
1855 info.pszObjId = oid_rsa_enveloped;
1856 ret = CryptEncodeObjectEx(X509_ASN_ENCODING,
1857 PKCS_CONTENT_INFO, &info, 0, NULL, pvData, pcbData);
1859 CryptMemFree(info.Content.pbData);
1861 else
1862 ret = FALSE;
1864 break;
1866 default:
1867 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
1869 return ret;
1872 static BOOL CEnvelopedEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
1873 DWORD cbData, BOOL fFinal)
1875 CEnvelopedEncodeMsg *msg = hCryptMsg;
1876 BOOL ret = FALSE;
1878 if (msg->base.state == MsgStateFinalized)
1879 SetLastError(CRYPT_E_MSG_ERROR);
1880 else if (msg->base.streamed)
1882 FIXME("streamed stub\n");
1883 msg->base.state = fFinal ? MsgStateFinalized : MsgStateUpdated;
1884 ret = TRUE;
1886 else
1888 if (!fFinal)
1890 if (msg->base.open_flags & CMSG_DETACHED_FLAG)
1891 SetLastError(E_INVALIDARG);
1892 else
1893 SetLastError(CRYPT_E_MSG_ERROR);
1895 else
1897 if (cbData)
1899 DWORD dataLen = cbData;
1901 msg->data.cbData = cbData;
1902 msg->data.pbData = CryptMemAlloc(cbData);
1903 if (msg->data.pbData)
1905 memcpy(msg->data.pbData, pbData, cbData);
1906 ret = CryptEncrypt(msg->key, 0, TRUE, 0, msg->data.pbData,
1907 &dataLen, msg->data.cbData);
1908 msg->data.cbData = dataLen;
1909 if (dataLen > cbData)
1911 msg->data.pbData = CryptMemRealloc(msg->data.pbData,
1912 dataLen);
1913 if (msg->data.pbData)
1915 dataLen = cbData;
1916 ret = CryptEncrypt(msg->key, 0, TRUE, 0,
1917 msg->data.pbData, &dataLen, msg->data.cbData);
1919 else
1920 ret = FALSE;
1922 if (!ret)
1923 CryptMemFree(msg->data.pbData);
1925 else
1926 ret = FALSE;
1927 if (!ret)
1929 msg->data.cbData = 0;
1930 msg->data.pbData = NULL;
1933 else
1934 ret = TRUE;
1935 msg->base.state = MsgStateFinalized;
1938 return ret;
1941 static HCRYPTMSG CEnvelopedEncodeMsg_Open(DWORD dwFlags,
1942 const void *pvMsgEncodeInfo, LPCSTR pszInnerContentObjID,
1943 PCMSG_STREAM_INFO pStreamInfo)
1945 CEnvelopedEncodeMsg *msg;
1946 const CMSG_ENVELOPED_ENCODE_INFO_WITH_CMS *info = pvMsgEncodeInfo;
1947 HCRYPTPROV prov;
1948 ALG_ID algID;
1950 if (info->cbSize != sizeof(CMSG_ENVELOPED_ENCODE_INFO) &&
1951 info->cbSize != sizeof(CMSG_ENVELOPED_ENCODE_INFO_WITH_CMS))
1953 SetLastError(E_INVALIDARG);
1954 return NULL;
1956 if (info->cbSize == sizeof(CMSG_ENVELOPED_ENCODE_INFO_WITH_CMS))
1957 FIXME("CMS fields unsupported\n");
1958 if (!(algID = CertOIDToAlgId(info->ContentEncryptionAlgorithm.pszObjId)))
1960 SetLastError(CRYPT_E_UNKNOWN_ALGO);
1961 return NULL;
1963 if (info->cRecipients && !info->rgpRecipientCert)
1965 SetLastError(E_INVALIDARG);
1966 return NULL;
1968 if (info->hCryptProv)
1969 prov = info->hCryptProv;
1970 else
1972 prov = I_CryptGetDefaultCryptProv(0);
1973 dwFlags &= ~CMSG_CRYPT_RELEASE_CONTEXT_FLAG;
1975 msg = CryptMemAlloc(sizeof(CEnvelopedEncodeMsg));
1976 if (msg)
1978 CRYPT_DATA_BLOB encryptedKey = { 0, NULL };
1979 CMSG_CONTENT_ENCRYPT_INFO encryptInfo;
1980 BOOL ret;
1981 DWORD i;
1983 CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo,
1984 CEnvelopedEncodeMsg_Close, CEnvelopedEncodeMsg_GetParam,
1985 CEnvelopedEncodeMsg_Update, CRYPT_DefaultMsgControl);
1986 ret = CRYPT_ConstructAlgorithmId(&msg->algo,
1987 &info->ContentEncryptionAlgorithm);
1988 msg->prov = prov;
1989 msg->data.cbData = 0;
1990 msg->data.pbData = NULL;
1991 msg->cRecipientInfo = info->cRecipients;
1992 msg->recipientInfo = CryptMemAlloc(info->cRecipients *
1993 sizeof(CMSG_KEY_TRANS_RECIPIENT_INFO));
1994 if (!msg->recipientInfo)
1995 ret = FALSE;
1996 memset(&encryptInfo, 0, sizeof(encryptInfo));
1997 if (ret)
1999 ret = CContentEncryptInfo_Construct(&encryptInfo, info, prov);
2000 if (ret)
2002 ret = CRYPT_GenKey(&encryptInfo, algID);
2003 if (ret)
2004 msg->key = encryptInfo.hContentEncryptKey;
2007 for (i = 0; ret && i < msg->cRecipientInfo; ++i)
2009 ret = CRYPT_ExportEncryptedKey(&encryptInfo, i, &encryptedKey);
2010 if (ret)
2011 ret = CRecipientInfo_Construct(&msg->recipientInfo[i],
2012 info->rgpRecipientCert[i], &encryptedKey);
2014 CContentEncryptInfo_Free(&encryptInfo);
2015 if (!ret)
2017 CryptMsgClose(msg);
2018 msg = NULL;
2021 if (!msg && (dwFlags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG))
2022 CryptReleaseContext(prov, 0);
2023 return msg;
2026 HCRYPTMSG WINAPI CryptMsgOpenToEncode(DWORD dwMsgEncodingType, DWORD dwFlags,
2027 DWORD dwMsgType, const void *pvMsgEncodeInfo, LPSTR pszInnerContentObjID,
2028 PCMSG_STREAM_INFO pStreamInfo)
2030 HCRYPTMSG msg = NULL;
2032 TRACE("(%08lx, %08lx, %08lx, %p, %s, %p)\n", dwMsgEncodingType, dwFlags,
2033 dwMsgType, pvMsgEncodeInfo, debugstr_a(pszInnerContentObjID), pStreamInfo);
2035 if (GET_CMSG_ENCODING_TYPE(dwMsgEncodingType) != PKCS_7_ASN_ENCODING)
2037 SetLastError(E_INVALIDARG);
2038 return NULL;
2040 switch (dwMsgType)
2042 case CMSG_DATA:
2043 msg = CDataEncodeMsg_Open(dwFlags, pvMsgEncodeInfo,
2044 pszInnerContentObjID, pStreamInfo);
2045 break;
2046 case CMSG_HASHED:
2047 msg = CHashEncodeMsg_Open(dwFlags, pvMsgEncodeInfo,
2048 pszInnerContentObjID, pStreamInfo);
2049 break;
2050 case CMSG_SIGNED:
2051 msg = CSignedEncodeMsg_Open(dwFlags, pvMsgEncodeInfo,
2052 pszInnerContentObjID, pStreamInfo);
2053 break;
2054 case CMSG_ENVELOPED:
2055 msg = CEnvelopedEncodeMsg_Open(dwFlags, pvMsgEncodeInfo,
2056 pszInnerContentObjID, pStreamInfo);
2057 break;
2058 case CMSG_SIGNED_AND_ENVELOPED:
2059 case CMSG_ENCRYPTED:
2060 /* defined but invalid, fall through */
2061 default:
2062 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2064 return msg;
2067 typedef struct _CEnvelopedDecodeMsg
2069 CRYPT_ENVELOPED_DATA *data;
2070 HCRYPTPROV crypt_prov;
2071 CRYPT_DATA_BLOB content;
2072 BOOL decrypted;
2073 } CEnvelopedDecodeMsg;
2075 typedef struct _CDecodeMsg
2077 CryptMsgBase base;
2078 DWORD type;
2079 HCRYPTPROV crypt_prov;
2080 union {
2081 HCRYPTHASH hash;
2082 CSignedMsgData signed_data;
2083 CEnvelopedDecodeMsg enveloped_data;
2084 } u;
2085 CRYPT_DATA_BLOB msg_data;
2086 CRYPT_DATA_BLOB detached_data;
2087 CONTEXT_PROPERTY_LIST *properties;
2088 } CDecodeMsg;
2090 static void CDecodeMsg_Close(HCRYPTMSG hCryptMsg)
2092 CDecodeMsg *msg = hCryptMsg;
2094 if (msg->crypt_prov && msg->base.open_flags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG)
2095 CryptReleaseContext(msg->crypt_prov, 0);
2096 switch (msg->type)
2098 case CMSG_HASHED:
2099 if (msg->u.hash)
2100 CryptDestroyHash(msg->u.hash);
2101 break;
2102 case CMSG_ENVELOPED:
2103 if (msg->u.enveloped_data.crypt_prov)
2104 CryptReleaseContext(msg->u.enveloped_data.crypt_prov, 0);
2105 LocalFree(msg->u.enveloped_data.data);
2106 CryptMemFree(msg->u.enveloped_data.content.pbData);
2107 break;
2108 case CMSG_SIGNED:
2109 if (msg->u.signed_data.info)
2111 LocalFree(msg->u.signed_data.info);
2112 CSignedMsgData_CloseHandles(&msg->u.signed_data);
2114 break;
2116 CryptMemFree(msg->msg_data.pbData);
2117 CryptMemFree(msg->detached_data.pbData);
2118 ContextPropertyList_Free(msg->properties);
2121 static BOOL CDecodeMsg_CopyData(CRYPT_DATA_BLOB *blob, const BYTE *pbData,
2122 DWORD cbData)
2124 BOOL ret = TRUE;
2126 if (cbData)
2128 if (blob->cbData)
2129 blob->pbData = CryptMemRealloc(blob->pbData,
2130 blob->cbData + cbData);
2131 else
2132 blob->pbData = CryptMemAlloc(cbData);
2133 if (blob->pbData)
2135 memcpy(blob->pbData + blob->cbData, pbData, cbData);
2136 blob->cbData += cbData;
2138 else
2139 ret = FALSE;
2141 return ret;
2144 static BOOL CDecodeMsg_DecodeDataContent(CDecodeMsg *msg, const CRYPT_DER_BLOB *blob)
2146 BOOL ret;
2147 CRYPT_DATA_BLOB *data;
2148 DWORD size;
2150 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING,
2151 blob->pbData, blob->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &data, &size);
2152 if (ret)
2154 ret = ContextPropertyList_SetProperty(msg->properties,
2155 CMSG_CONTENT_PARAM, data->pbData, data->cbData);
2156 LocalFree(data);
2158 return ret;
2161 static void CDecodeMsg_SaveAlgorithmID(CDecodeMsg *msg, DWORD param,
2162 const CRYPT_ALGORITHM_IDENTIFIER *id)
2164 static const BYTE nullParams[] = { ASN_NULL, 0 };
2165 CRYPT_ALGORITHM_IDENTIFIER *copy;
2166 DWORD len = sizeof(CRYPT_ALGORITHM_IDENTIFIER);
2168 /* Linearize algorithm id */
2169 len += strlen(id->pszObjId) + 1;
2170 len += id->Parameters.cbData;
2171 copy = CryptMemAlloc(len);
2172 if (copy)
2174 copy->pszObjId =
2175 (LPSTR)((BYTE *)copy + sizeof(CRYPT_ALGORITHM_IDENTIFIER));
2176 strcpy(copy->pszObjId, id->pszObjId);
2177 copy->Parameters.pbData = (BYTE *)copy->pszObjId + strlen(id->pszObjId)
2178 + 1;
2179 /* Trick: omit NULL parameters */
2180 if (id->Parameters.cbData == sizeof(nullParams) &&
2181 !memcmp(id->Parameters.pbData, nullParams, sizeof(nullParams)))
2183 copy->Parameters.cbData = 0;
2184 len -= sizeof(nullParams);
2186 else
2187 copy->Parameters.cbData = id->Parameters.cbData;
2188 if (copy->Parameters.cbData)
2189 memcpy(copy->Parameters.pbData, id->Parameters.pbData,
2190 id->Parameters.cbData);
2191 ContextPropertyList_SetProperty(msg->properties, param, (BYTE *)copy,
2192 len);
2193 CryptMemFree(copy);
2197 static inline void CRYPT_FixUpAlgorithmID(CRYPT_ALGORITHM_IDENTIFIER *id)
2199 id->pszObjId = (LPSTR)((BYTE *)id + sizeof(CRYPT_ALGORITHM_IDENTIFIER));
2200 id->Parameters.pbData = (BYTE *)id->pszObjId + strlen(id->pszObjId) + 1;
2203 static BOOL CDecodeMsg_DecodeHashedContent(CDecodeMsg *msg,
2204 const CRYPT_DER_BLOB *blob)
2206 BOOL ret;
2207 CRYPT_DIGESTED_DATA *digestedData;
2208 DWORD size;
2210 ret = CRYPT_AsnDecodePKCSDigestedData(blob->pbData, blob->cbData,
2211 CRYPT_DECODE_ALLOC_FLAG, NULL, (CRYPT_DIGESTED_DATA *)&digestedData,
2212 &size);
2213 if (ret)
2215 ContextPropertyList_SetProperty(msg->properties, CMSG_VERSION_PARAM,
2216 (const BYTE *)&digestedData->version, sizeof(digestedData->version));
2217 CDecodeMsg_SaveAlgorithmID(msg, CMSG_HASH_ALGORITHM_PARAM,
2218 &digestedData->DigestAlgorithm);
2219 ContextPropertyList_SetProperty(msg->properties,
2220 CMSG_INNER_CONTENT_TYPE_PARAM,
2221 (const BYTE *)digestedData->ContentInfo.pszObjId,
2222 digestedData->ContentInfo.pszObjId ?
2223 strlen(digestedData->ContentInfo.pszObjId) + 1 : 0);
2224 if (!(msg->base.open_flags & CMSG_DETACHED_FLAG))
2226 if (digestedData->ContentInfo.Content.cbData)
2227 CDecodeMsg_DecodeDataContent(msg,
2228 &digestedData->ContentInfo.Content);
2229 else
2230 ContextPropertyList_SetProperty(msg->properties,
2231 CMSG_CONTENT_PARAM, NULL, 0);
2233 ContextPropertyList_SetProperty(msg->properties, CMSG_HASH_DATA_PARAM,
2234 digestedData->hash.pbData, digestedData->hash.cbData);
2235 LocalFree(digestedData);
2237 return ret;
2240 static BOOL CDecodeMsg_DecodeEnvelopedContent(CDecodeMsg *msg,
2241 const CRYPT_DER_BLOB *blob)
2243 BOOL ret;
2244 CRYPT_ENVELOPED_DATA *envelopedData;
2245 DWORD size;
2247 ret = CRYPT_AsnDecodePKCSEnvelopedData(blob->pbData, blob->cbData,
2248 CRYPT_DECODE_ALLOC_FLAG, NULL, (CRYPT_ENVELOPED_DATA *)&envelopedData,
2249 &size);
2250 if (ret)
2251 msg->u.enveloped_data.data = envelopedData;
2252 return ret;
2255 static BOOL CDecodeMsg_DecodeSignedContent(CDecodeMsg *msg,
2256 const CRYPT_DER_BLOB *blob)
2258 BOOL ret;
2259 CRYPT_SIGNED_INFO *signedInfo;
2260 DWORD size;
2262 ret = CRYPT_AsnDecodeCMSSignedInfo(blob->pbData, blob->cbData,
2263 CRYPT_DECODE_ALLOC_FLAG, NULL, (CRYPT_SIGNED_INFO *)&signedInfo,
2264 &size);
2265 if (ret)
2266 msg->u.signed_data.info = signedInfo;
2267 return ret;
2270 /* Decodes the content in blob as the type given, and updates the value
2271 * (type, parameters, etc.) of msg based on what blob contains.
2272 * It doesn't just use msg's type, to allow a recursive call from an implicitly
2273 * typed message once the outer content info has been decoded.
2275 static BOOL CDecodeMsg_DecodeContent(CDecodeMsg *msg, const CRYPT_DER_BLOB *blob,
2276 DWORD type)
2278 BOOL ret;
2280 switch (type)
2282 case CMSG_DATA:
2283 if ((ret = CDecodeMsg_DecodeDataContent(msg, blob)))
2284 msg->type = CMSG_DATA;
2285 break;
2286 case CMSG_HASHED:
2287 if ((ret = CDecodeMsg_DecodeHashedContent(msg, blob)))
2288 msg->type = CMSG_HASHED;
2289 break;
2290 case CMSG_ENVELOPED:
2291 if ((ret = CDecodeMsg_DecodeEnvelopedContent(msg, blob)))
2292 msg->type = CMSG_ENVELOPED;
2293 break;
2294 case CMSG_SIGNED:
2295 if ((ret = CDecodeMsg_DecodeSignedContent(msg, blob)))
2296 msg->type = CMSG_SIGNED;
2297 break;
2298 default:
2300 CRYPT_CONTENT_INFO *info;
2301 DWORD size;
2303 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, PKCS_CONTENT_INFO,
2304 msg->msg_data.pbData, msg->msg_data.cbData, CRYPT_DECODE_ALLOC_FLAG,
2305 NULL, &info, &size);
2306 if (ret)
2308 if (!strcmp(info->pszObjId, szOID_RSA_data))
2309 ret = CDecodeMsg_DecodeContent(msg, &info->Content, CMSG_DATA);
2310 else if (!strcmp(info->pszObjId, szOID_RSA_digestedData))
2311 ret = CDecodeMsg_DecodeContent(msg, &info->Content,
2312 CMSG_HASHED);
2313 else if (!strcmp(info->pszObjId, szOID_RSA_envelopedData))
2314 ret = CDecodeMsg_DecodeContent(msg, &info->Content,
2315 CMSG_ENVELOPED);
2316 else if (!strcmp(info->pszObjId, szOID_RSA_signedData))
2317 ret = CDecodeMsg_DecodeContent(msg, &info->Content,
2318 CMSG_SIGNED);
2319 else
2321 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2322 ret = FALSE;
2324 LocalFree(info);
2328 return ret;
2331 static BOOL CDecodeMsg_FinalizeHashedContent(CDecodeMsg *msg,
2332 CRYPT_DER_BLOB *blob)
2334 CRYPT_ALGORITHM_IDENTIFIER *hashAlgoID = NULL;
2335 DWORD size = 0;
2336 ALG_ID algID = 0;
2337 BOOL ret;
2339 CryptMsgGetParam(msg, CMSG_HASH_ALGORITHM_PARAM, 0, NULL, &size);
2340 hashAlgoID = CryptMemAlloc(size);
2341 ret = CryptMsgGetParam(msg, CMSG_HASH_ALGORITHM_PARAM, 0, hashAlgoID,
2342 &size);
2343 if (ret)
2344 algID = CertOIDToAlgId(hashAlgoID->pszObjId);
2346 if (!msg->crypt_prov)
2348 msg->crypt_prov = I_CryptGetDefaultCryptProv(algID);
2349 if (msg->crypt_prov)
2350 msg->base.open_flags &= ~CMSG_CRYPT_RELEASE_CONTEXT_FLAG;
2353 ret = CryptCreateHash(msg->crypt_prov, algID, 0, 0, &msg->u.hash);
2354 if (ret)
2356 CRYPT_DATA_BLOB content;
2358 if (msg->base.open_flags & CMSG_DETACHED_FLAG)
2360 /* Unlike for non-detached messages, the data were never stored as
2361 * the content param, but were saved in msg->detached_data instead.
2363 content.pbData = msg->detached_data.pbData;
2364 content.cbData = msg->detached_data.cbData;
2366 else
2367 ret = ContextPropertyList_FindProperty(msg->properties,
2368 CMSG_CONTENT_PARAM, &content);
2369 if (ret)
2370 ret = CryptHashData(msg->u.hash, content.pbData, content.cbData, 0);
2372 CryptMemFree(hashAlgoID);
2373 return ret;
2376 static BOOL CDecodeMsg_FinalizeEnvelopedContent(CDecodeMsg *msg,
2377 CRYPT_DER_BLOB *blob)
2379 CRYPT_DATA_BLOB *content;
2381 if (msg->base.open_flags & CMSG_DETACHED_FLAG)
2382 content = &msg->detached_data;
2383 else
2384 content =
2385 &msg->u.enveloped_data.data->encryptedContentInfo.encryptedContent;
2387 return CRYPT_ConstructBlob(&msg->u.enveloped_data.content, content);
2390 static BOOL CDecodeMsg_FinalizeSignedContent(CDecodeMsg *msg,
2391 CRYPT_DER_BLOB *blob)
2393 BOOL ret;
2394 DWORD i, size;
2396 ret = CSignedMsgData_AllocateHandles(&msg->u.signed_data);
2397 for (i = 0; ret && i < msg->u.signed_data.info->cSignerInfo; i++)
2398 ret = CSignedMsgData_ConstructSignerHandles(&msg->u.signed_data, i,
2399 &msg->crypt_prov, &msg->base.open_flags);
2400 if (ret)
2402 CRYPT_DATA_BLOB *content;
2404 /* Now that we have all the content, update the hash handles with
2405 * it. If the message is a detached message, the content is stored
2406 * in msg->detached_data rather than in the signed message's
2407 * content.
2409 if (msg->base.open_flags & CMSG_DETACHED_FLAG)
2410 content = &msg->detached_data;
2411 else
2412 content = &msg->u.signed_data.info->content.Content;
2413 if (content->cbData)
2415 /* If the message is not detached, have to decode the message's
2416 * content if the type is szOID_RSA_data.
2418 if (!(msg->base.open_flags & CMSG_DETACHED_FLAG) &&
2419 !strcmp(msg->u.signed_data.info->content.pszObjId,
2420 szOID_RSA_data))
2422 CRYPT_DATA_BLOB *rsa_blob;
2424 ret = CryptDecodeObjectEx(X509_ASN_ENCODING,
2425 X509_OCTET_STRING, content->pbData, content->cbData,
2426 CRYPT_DECODE_ALLOC_FLAG, NULL, &rsa_blob, &size);
2427 if (ret)
2429 ret = CSignedMsgData_Update(&msg->u.signed_data,
2430 rsa_blob->pbData, rsa_blob->cbData, TRUE, Verify);
2431 LocalFree(rsa_blob);
2434 else
2435 ret = CSignedMsgData_Update(&msg->u.signed_data,
2436 content->pbData, content->cbData, TRUE, Verify);
2439 return ret;
2442 static BOOL CDecodeMsg_FinalizeContent(CDecodeMsg *msg, CRYPT_DER_BLOB *blob)
2444 BOOL ret = FALSE;
2446 switch (msg->type)
2448 case CMSG_HASHED:
2449 ret = CDecodeMsg_FinalizeHashedContent(msg, blob);
2450 break;
2451 case CMSG_ENVELOPED:
2452 ret = CDecodeMsg_FinalizeEnvelopedContent(msg, blob);
2453 break;
2454 case CMSG_SIGNED:
2455 ret = CDecodeMsg_FinalizeSignedContent(msg, blob);
2456 break;
2457 default:
2458 ret = TRUE;
2460 return ret;
2463 static BOOL CDecodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
2464 DWORD cbData, BOOL fFinal)
2466 CDecodeMsg *msg = hCryptMsg;
2467 BOOL ret = FALSE;
2469 TRACE("(%p, %p, %ld, %d)\n", hCryptMsg, pbData, cbData, fFinal);
2471 if (msg->base.state == MsgStateFinalized)
2472 SetLastError(CRYPT_E_MSG_ERROR);
2473 else if (msg->base.streamed)
2475 FIXME("(%p, %p, %ld, %d): streamed update stub\n", hCryptMsg, pbData,
2476 cbData, fFinal);
2477 switch (msg->base.state)
2479 case MsgStateInit:
2480 ret = CDecodeMsg_CopyData(&msg->msg_data, pbData, cbData);
2481 if (fFinal)
2483 if (msg->base.open_flags & CMSG_DETACHED_FLAG)
2484 msg->base.state = MsgStateDataFinalized;
2485 else
2486 msg->base.state = MsgStateFinalized;
2488 else
2489 msg->base.state = MsgStateUpdated;
2490 break;
2491 case MsgStateUpdated:
2492 ret = CDecodeMsg_CopyData(&msg->msg_data, pbData, cbData);
2493 if (fFinal)
2495 if (msg->base.open_flags & CMSG_DETACHED_FLAG)
2496 msg->base.state = MsgStateDataFinalized;
2497 else
2498 msg->base.state = MsgStateFinalized;
2500 break;
2501 case MsgStateDataFinalized:
2502 ret = CDecodeMsg_CopyData(&msg->detached_data, pbData, cbData);
2503 if (fFinal)
2504 msg->base.state = MsgStateFinalized;
2505 break;
2506 default:
2507 SetLastError(CRYPT_E_MSG_ERROR);
2508 break;
2511 else
2513 if (!fFinal)
2514 SetLastError(CRYPT_E_MSG_ERROR);
2515 else
2517 switch (msg->base.state)
2519 case MsgStateInit:
2520 ret = CDecodeMsg_CopyData(&msg->msg_data, pbData, cbData);
2521 if (msg->base.open_flags & CMSG_DETACHED_FLAG)
2522 msg->base.state = MsgStateDataFinalized;
2523 else
2524 msg->base.state = MsgStateFinalized;
2525 break;
2526 case MsgStateDataFinalized:
2527 ret = CDecodeMsg_CopyData(&msg->detached_data, pbData, cbData);
2528 msg->base.state = MsgStateFinalized;
2529 break;
2530 default:
2531 SetLastError(CRYPT_E_MSG_ERROR);
2535 if (ret && fFinal &&
2536 ((msg->base.open_flags & CMSG_DETACHED_FLAG && msg->base.state ==
2537 MsgStateDataFinalized) ||
2538 (!(msg->base.open_flags & CMSG_DETACHED_FLAG) && msg->base.state ==
2539 MsgStateFinalized)))
2540 ret = CDecodeMsg_DecodeContent(msg, &msg->msg_data, msg->type);
2541 if (ret && msg->base.state == MsgStateFinalized)
2542 ret = CDecodeMsg_FinalizeContent(msg, &msg->msg_data);
2543 return ret;
2546 static BOOL CDecodeHashMsg_GetParam(CDecodeMsg *msg, DWORD dwParamType,
2547 DWORD dwIndex, void *pvData, DWORD *pcbData)
2549 BOOL ret = FALSE;
2551 switch (dwParamType)
2553 case CMSG_TYPE_PARAM:
2554 ret = CRYPT_CopyParam(pvData, pcbData, &msg->type, sizeof(msg->type));
2555 break;
2556 case CMSG_HASH_ALGORITHM_PARAM:
2558 CRYPT_DATA_BLOB blob;
2560 ret = ContextPropertyList_FindProperty(msg->properties, dwParamType,
2561 &blob);
2562 if (ret)
2564 ret = CRYPT_CopyParam(pvData, pcbData, blob.pbData, blob.cbData);
2565 if (ret && pvData)
2566 CRYPT_FixUpAlgorithmID(pvData);
2568 else
2569 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2570 break;
2572 case CMSG_COMPUTED_HASH_PARAM:
2573 ret = CryptGetHashParam(msg->u.hash, HP_HASHVAL, pvData, pcbData, 0);
2574 break;
2575 default:
2577 CRYPT_DATA_BLOB blob;
2579 ret = ContextPropertyList_FindProperty(msg->properties, dwParamType,
2580 &blob);
2581 if (ret)
2582 ret = CRYPT_CopyParam(pvData, pcbData, blob.pbData, blob.cbData);
2583 else
2584 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2587 return ret;
2590 /* nextData is an in/out parameter - on input it's the memory location in
2591 * which a copy of in's data should be made, and on output it's the memory
2592 * location immediately after out's copy of in's data.
2594 static inline void CRYPT_CopyBlob(CRYPT_DATA_BLOB *out,
2595 const CRYPT_DATA_BLOB *in, LPBYTE *nextData)
2597 out->cbData = in->cbData;
2598 if (in->cbData)
2600 out->pbData = *nextData;
2601 memcpy(out->pbData, in->pbData, in->cbData);
2602 *nextData += in->cbData;
2606 static inline void CRYPT_CopyAlgorithmId(CRYPT_ALGORITHM_IDENTIFIER *out,
2607 const CRYPT_ALGORITHM_IDENTIFIER *in, LPBYTE *nextData)
2609 if (in->pszObjId)
2611 out->pszObjId = (LPSTR)*nextData;
2612 strcpy(out->pszObjId, in->pszObjId);
2613 *nextData += strlen(out->pszObjId) + 1;
2615 CRYPT_CopyBlob(&out->Parameters, &in->Parameters, nextData);
2618 static inline void CRYPT_CopyAttributes(CRYPT_ATTRIBUTES *out,
2619 const CRYPT_ATTRIBUTES *in, LPBYTE *nextData)
2621 out->cAttr = in->cAttr;
2622 if (in->cAttr)
2624 DWORD i;
2626 *nextData = POINTER_ALIGN_DWORD_PTR(*nextData);
2627 out->rgAttr = (CRYPT_ATTRIBUTE *)*nextData;
2628 *nextData += in->cAttr * sizeof(CRYPT_ATTRIBUTE);
2629 for (i = 0; i < in->cAttr; i++)
2631 if (in->rgAttr[i].pszObjId)
2633 out->rgAttr[i].pszObjId = (LPSTR)*nextData;
2634 strcpy(out->rgAttr[i].pszObjId, in->rgAttr[i].pszObjId);
2635 *nextData += strlen(in->rgAttr[i].pszObjId) + 1;
2637 if (in->rgAttr[i].cValue)
2639 DWORD j;
2641 out->rgAttr[i].cValue = in->rgAttr[i].cValue;
2642 *nextData = POINTER_ALIGN_DWORD_PTR(*nextData);
2643 out->rgAttr[i].rgValue = (PCRYPT_DATA_BLOB)*nextData;
2644 *nextData += in->rgAttr[i].cValue * sizeof(CRYPT_DATA_BLOB);
2645 for (j = 0; j < in->rgAttr[i].cValue; j++)
2646 CRYPT_CopyBlob(&out->rgAttr[i].rgValue[j],
2647 &in->rgAttr[i].rgValue[j], nextData);
2653 static DWORD CRYPT_SizeOfAttributes(const CRYPT_ATTRIBUTES *attr)
2655 DWORD size = attr->cAttr * sizeof(CRYPT_ATTRIBUTE), i, j;
2657 for (i = 0; i < attr->cAttr; i++)
2659 if (attr->rgAttr[i].pszObjId)
2660 size += strlen(attr->rgAttr[i].pszObjId) + 1;
2661 /* align pointer */
2662 size = ALIGN_DWORD_PTR(size);
2663 size += attr->rgAttr[i].cValue * sizeof(CRYPT_DATA_BLOB);
2664 for (j = 0; j < attr->rgAttr[i].cValue; j++)
2665 size += attr->rgAttr[i].rgValue[j].cbData;
2667 /* align pointer again to be conservative */
2668 size = ALIGN_DWORD_PTR(size);
2669 return size;
2672 static DWORD CRYPT_SizeOfKeyIdAsIssuerAndSerial(const CRYPT_DATA_BLOB *keyId)
2674 static char oid_key_rdn[] = szOID_KEYID_RDN;
2675 DWORD size = 0;
2676 CERT_RDN_ATTR attr;
2677 CERT_RDN rdn = { 1, &attr };
2678 CERT_NAME_INFO name = { 1, &rdn };
2680 attr.pszObjId = oid_key_rdn;
2681 attr.dwValueType = CERT_RDN_OCTET_STRING;
2682 attr.Value.cbData = keyId->cbData;
2683 attr.Value.pbData = keyId->pbData;
2684 if (CryptEncodeObject(X509_ASN_ENCODING, X509_NAME, &name, NULL, &size))
2685 size++; /* Only include size of special zero serial number on success */
2686 return size;
2689 static BOOL CRYPT_CopyKeyIdAsIssuerAndSerial(CERT_NAME_BLOB *issuer,
2690 CRYPT_INTEGER_BLOB *serialNumber, const CRYPT_DATA_BLOB *keyId, DWORD encodedLen,
2691 LPBYTE *nextData)
2693 static char oid_key_rdn[] = szOID_KEYID_RDN;
2694 CERT_RDN_ATTR attr;
2695 CERT_RDN rdn = { 1, &attr };
2696 CERT_NAME_INFO name = { 1, &rdn };
2697 BOOL ret;
2699 /* Encode special zero serial number */
2700 serialNumber->cbData = 1;
2701 serialNumber->pbData = *nextData;
2702 **nextData = 0;
2703 (*nextData)++;
2704 /* Encode issuer */
2705 issuer->pbData = *nextData;
2706 attr.pszObjId = oid_key_rdn;
2707 attr.dwValueType = CERT_RDN_OCTET_STRING;
2708 attr.Value.cbData = keyId->cbData;
2709 attr.Value.pbData = keyId->pbData;
2710 ret = CryptEncodeObject(X509_ASN_ENCODING, X509_NAME, &name, *nextData,
2711 &encodedLen);
2712 if (ret)
2714 *nextData += encodedLen;
2715 issuer->cbData = encodedLen;
2717 return ret;
2720 static BOOL CRYPT_CopySignerInfo(void *pvData, DWORD *pcbData,
2721 const CMSG_CMS_SIGNER_INFO *in)
2723 DWORD size = sizeof(CMSG_SIGNER_INFO), rdnSize = 0;
2724 BOOL ret;
2726 TRACE("(%p, %ld, %p)\n", pvData, pvData ? *pcbData : 0, in);
2728 if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
2730 size += in->SignerId.IssuerSerialNumber.Issuer.cbData;
2731 size += in->SignerId.IssuerSerialNumber.SerialNumber.cbData;
2733 else
2735 rdnSize = CRYPT_SizeOfKeyIdAsIssuerAndSerial(&in->SignerId.KeyId);
2736 size += rdnSize;
2738 if (in->HashAlgorithm.pszObjId)
2739 size += strlen(in->HashAlgorithm.pszObjId) + 1;
2740 size += in->HashAlgorithm.Parameters.cbData;
2741 if (in->HashEncryptionAlgorithm.pszObjId)
2742 size += strlen(in->HashEncryptionAlgorithm.pszObjId) + 1;
2743 size += in->HashEncryptionAlgorithm.Parameters.cbData;
2744 size += in->EncryptedHash.cbData;
2745 /* align pointer */
2746 size = ALIGN_DWORD_PTR(size);
2747 size += CRYPT_SizeOfAttributes(&in->AuthAttrs);
2748 size += CRYPT_SizeOfAttributes(&in->UnauthAttrs);
2749 if (!pvData)
2751 ret = TRUE;
2753 else if (*pcbData < size)
2755 SetLastError(ERROR_MORE_DATA);
2756 ret = FALSE;
2758 else
2760 LPBYTE nextData = (BYTE *)pvData + sizeof(CMSG_SIGNER_INFO);
2761 CMSG_SIGNER_INFO *out = pvData;
2763 ret = TRUE;
2764 out->dwVersion = in->dwVersion;
2765 if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
2767 CRYPT_CopyBlob(&out->Issuer,
2768 &in->SignerId.IssuerSerialNumber.Issuer, &nextData);
2769 CRYPT_CopyBlob(&out->SerialNumber,
2770 &in->SignerId.IssuerSerialNumber.SerialNumber, &nextData);
2772 else
2773 ret = CRYPT_CopyKeyIdAsIssuerAndSerial(&out->Issuer, &out->SerialNumber,
2774 &in->SignerId.KeyId, rdnSize, &nextData);
2775 if (ret)
2777 CRYPT_CopyAlgorithmId(&out->HashAlgorithm, &in->HashAlgorithm,
2778 &nextData);
2779 CRYPT_CopyAlgorithmId(&out->HashEncryptionAlgorithm,
2780 &in->HashEncryptionAlgorithm, &nextData);
2781 CRYPT_CopyBlob(&out->EncryptedHash, &in->EncryptedHash, &nextData);
2782 nextData = POINTER_ALIGN_DWORD_PTR(nextData);
2783 CRYPT_CopyAttributes(&out->AuthAttrs, &in->AuthAttrs, &nextData);
2784 CRYPT_CopyAttributes(&out->UnauthAttrs, &in->UnauthAttrs, &nextData);
2787 *pcbData = size;
2788 TRACE("returning %d\n", ret);
2789 return ret;
2792 static BOOL CRYPT_CopyCMSSignerInfo(void *pvData, DWORD *pcbData,
2793 const CMSG_CMS_SIGNER_INFO *in)
2795 DWORD size = sizeof(CMSG_CMS_SIGNER_INFO);
2796 BOOL ret;
2798 TRACE("(%p, %ld, %p)\n", pvData, pvData ? *pcbData : 0, in);
2800 if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
2802 size += in->SignerId.IssuerSerialNumber.Issuer.cbData;
2803 size += in->SignerId.IssuerSerialNumber.SerialNumber.cbData;
2805 else
2806 size += in->SignerId.KeyId.cbData;
2807 if (in->HashAlgorithm.pszObjId)
2808 size += strlen(in->HashAlgorithm.pszObjId) + 1;
2809 size += in->HashAlgorithm.Parameters.cbData;
2810 if (in->HashEncryptionAlgorithm.pszObjId)
2811 size += strlen(in->HashEncryptionAlgorithm.pszObjId) + 1;
2812 size += in->HashEncryptionAlgorithm.Parameters.cbData;
2813 size += in->EncryptedHash.cbData;
2814 /* align pointer */
2815 size = ALIGN_DWORD_PTR(size);
2816 size += CRYPT_SizeOfAttributes(&in->AuthAttrs);
2817 size += CRYPT_SizeOfAttributes(&in->UnauthAttrs);
2818 if (!pvData)
2820 *pcbData = size;
2821 ret = TRUE;
2823 else if (*pcbData < size)
2825 *pcbData = size;
2826 SetLastError(ERROR_MORE_DATA);
2827 ret = FALSE;
2829 else
2831 LPBYTE nextData = (BYTE *)pvData + sizeof(CMSG_CMS_SIGNER_INFO);
2832 CMSG_CMS_SIGNER_INFO *out = pvData;
2834 out->dwVersion = in->dwVersion;
2835 out->SignerId.dwIdChoice = in->SignerId.dwIdChoice;
2836 if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
2838 CRYPT_CopyBlob(&out->SignerId.IssuerSerialNumber.Issuer,
2839 &in->SignerId.IssuerSerialNumber.Issuer, &nextData);
2840 CRYPT_CopyBlob(&out->SignerId.IssuerSerialNumber.SerialNumber,
2841 &in->SignerId.IssuerSerialNumber.SerialNumber, &nextData);
2843 else
2844 CRYPT_CopyBlob(&out->SignerId.KeyId, &in->SignerId.KeyId, &nextData);
2845 CRYPT_CopyAlgorithmId(&out->HashAlgorithm, &in->HashAlgorithm,
2846 &nextData);
2847 CRYPT_CopyAlgorithmId(&out->HashEncryptionAlgorithm,
2848 &in->HashEncryptionAlgorithm, &nextData);
2849 CRYPT_CopyBlob(&out->EncryptedHash, &in->EncryptedHash, &nextData);
2850 nextData = POINTER_ALIGN_DWORD_PTR(nextData);
2851 CRYPT_CopyAttributes(&out->AuthAttrs, &in->AuthAttrs, &nextData);
2852 CRYPT_CopyAttributes(&out->UnauthAttrs, &in->UnauthAttrs, &nextData);
2853 ret = TRUE;
2855 TRACE("returning %d\n", ret);
2856 return ret;
2859 static BOOL CRYPT_CopySignerCertInfo(void *pvData, DWORD *pcbData,
2860 const CMSG_CMS_SIGNER_INFO *in)
2862 DWORD size = sizeof(CERT_INFO), rdnSize = 0;
2863 BOOL ret;
2865 TRACE("(%p, %ld, %p)\n", pvData, pvData ? *pcbData : 0, in);
2867 if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
2869 size += in->SignerId.IssuerSerialNumber.Issuer.cbData;
2870 size += in->SignerId.IssuerSerialNumber.SerialNumber.cbData;
2872 else
2874 rdnSize = CRYPT_SizeOfKeyIdAsIssuerAndSerial(&in->SignerId.KeyId);
2875 size += rdnSize;
2877 if (!pvData)
2879 *pcbData = size;
2880 ret = TRUE;
2882 else if (*pcbData < size)
2884 *pcbData = size;
2885 SetLastError(ERROR_MORE_DATA);
2886 ret = FALSE;
2888 else
2890 LPBYTE nextData = (BYTE *)pvData + sizeof(CERT_INFO);
2891 CERT_INFO *out = pvData;
2893 memset(out, 0, sizeof(CERT_INFO));
2894 if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
2896 CRYPT_CopyBlob(&out->Issuer,
2897 &in->SignerId.IssuerSerialNumber.Issuer, &nextData);
2898 CRYPT_CopyBlob(&out->SerialNumber,
2899 &in->SignerId.IssuerSerialNumber.SerialNumber, &nextData);
2900 ret = TRUE;
2902 else
2903 ret = CRYPT_CopyKeyIdAsIssuerAndSerial(&out->Issuer, &out->SerialNumber,
2904 &in->SignerId.KeyId, rdnSize, &nextData);
2906 TRACE("returning %d\n", ret);
2907 return ret;
2910 static BOOL CRYPT_CopyRecipientInfo(void *pvData, DWORD *pcbData,
2911 const CERT_ISSUER_SERIAL_NUMBER *in)
2913 DWORD size = sizeof(CERT_INFO);
2914 BOOL ret;
2916 TRACE("(%p, %ld, %p)\n", pvData, pvData ? *pcbData : 0, in);
2918 size += in->SerialNumber.cbData;
2919 size += in->Issuer.cbData;
2920 if (!pvData)
2922 *pcbData = size;
2923 ret = TRUE;
2925 else if (*pcbData < size)
2927 *pcbData = size;
2928 SetLastError(ERROR_MORE_DATA);
2929 ret = FALSE;
2931 else
2933 LPBYTE nextData = (BYTE *)pvData + sizeof(CERT_INFO);
2934 CERT_INFO *out = pvData;
2936 CRYPT_CopyBlob(&out->SerialNumber, &in->SerialNumber, &nextData);
2937 CRYPT_CopyBlob(&out->Issuer, &in->Issuer, &nextData);
2938 ret = TRUE;
2940 TRACE("returning %d\n", ret);
2941 return ret;
2944 static BOOL CDecodeEnvelopedMsg_GetParam(CDecodeMsg *msg, DWORD dwParamType,
2945 DWORD dwIndex, void *pvData, DWORD *pcbData)
2947 BOOL ret = FALSE;
2949 switch (dwParamType)
2951 case CMSG_TYPE_PARAM:
2952 ret = CRYPT_CopyParam(pvData, pcbData, &msg->type, sizeof(msg->type));
2953 break;
2954 case CMSG_CONTENT_PARAM:
2955 if (msg->u.enveloped_data.data)
2956 ret = CRYPT_CopyParam(pvData, pcbData,
2957 msg->u.enveloped_data.content.pbData,
2958 msg->u.enveloped_data.content.cbData);
2959 else
2960 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2961 break;
2962 case CMSG_RECIPIENT_COUNT_PARAM:
2963 if (msg->u.enveloped_data.data)
2964 ret = CRYPT_CopyParam(pvData, pcbData,
2965 &msg->u.enveloped_data.data->cRecipientInfo, sizeof(DWORD));
2966 else
2967 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2968 break;
2969 case CMSG_RECIPIENT_INFO_PARAM:
2970 if (msg->u.enveloped_data.data)
2972 if (dwIndex < msg->u.enveloped_data.data->cRecipientInfo)
2974 PCMSG_KEY_TRANS_RECIPIENT_INFO recipientInfo =
2975 &msg->u.enveloped_data.data->rgRecipientInfo[dwIndex];
2977 ret = CRYPT_CopyRecipientInfo(pvData, pcbData,
2978 &recipientInfo->RecipientId.IssuerSerialNumber);
2980 else
2981 SetLastError(CRYPT_E_INVALID_INDEX);
2983 else
2984 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2985 break;
2986 default:
2987 FIXME("unimplemented for %ld\n", dwParamType);
2988 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2990 return ret;
2993 static BOOL CRYPT_CopyAttr(void *pvData, DWORD *pcbData, const CRYPT_ATTRIBUTES *attr)
2995 DWORD size;
2996 BOOL ret;
2998 TRACE("(%p, %ld, %p)\n", pvData, pvData ? *pcbData : 0, attr);
3000 size = CRYPT_SizeOfAttributes(attr);
3001 if (!pvData)
3003 *pcbData = size;
3004 ret = TRUE;
3006 else if (*pcbData < size)
3008 *pcbData = size;
3009 SetLastError(ERROR_MORE_DATA);
3010 ret = FALSE;
3012 else
3013 ret = CRYPT_ConstructAttributes(pvData, attr);
3015 TRACE("returning %d\n", ret);
3016 return ret;
3019 static BOOL CDecodeSignedMsg_GetParam(CDecodeMsg *msg, DWORD dwParamType,
3020 DWORD dwIndex, void *pvData, DWORD *pcbData)
3022 BOOL ret = FALSE;
3024 switch (dwParamType)
3026 case CMSG_TYPE_PARAM:
3027 ret = CRYPT_CopyParam(pvData, pcbData, &msg->type, sizeof(msg->type));
3028 break;
3029 case CMSG_CONTENT_PARAM:
3030 if (msg->u.signed_data.info)
3032 if (!strcmp(msg->u.signed_data.info->content.pszObjId,
3033 szOID_RSA_data))
3035 CRYPT_DATA_BLOB *blob;
3036 DWORD size;
3038 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING,
3039 msg->u.signed_data.info->content.Content.pbData,
3040 msg->u.signed_data.info->content.Content.cbData,
3041 CRYPT_DECODE_ALLOC_FLAG, NULL, &blob, &size);
3042 if (ret)
3044 ret = CRYPT_CopyParam(pvData, pcbData, blob->pbData,
3045 blob->cbData);
3046 LocalFree(blob);
3049 else
3050 ret = CRYPT_CopyParam(pvData, pcbData,
3051 msg->u.signed_data.info->content.Content.pbData,
3052 msg->u.signed_data.info->content.Content.cbData);
3054 else
3055 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
3056 break;
3057 case CMSG_INNER_CONTENT_TYPE_PARAM:
3058 if (msg->u.signed_data.info)
3059 ret = CRYPT_CopyParam(pvData, pcbData,
3060 msg->u.signed_data.info->content.pszObjId,
3061 strlen(msg->u.signed_data.info->content.pszObjId) + 1);
3062 else
3063 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
3064 break;
3065 case CMSG_SIGNER_COUNT_PARAM:
3066 if (msg->u.signed_data.info)
3067 ret = CRYPT_CopyParam(pvData, pcbData,
3068 &msg->u.signed_data.info->cSignerInfo, sizeof(DWORD));
3069 else
3070 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
3071 break;
3072 case CMSG_SIGNER_INFO_PARAM:
3073 if (msg->u.signed_data.info)
3075 if (dwIndex >= msg->u.signed_data.info->cSignerInfo)
3076 SetLastError(CRYPT_E_INVALID_INDEX);
3077 else
3078 ret = CRYPT_CopySignerInfo(pvData, pcbData,
3079 &msg->u.signed_data.info->rgSignerInfo[dwIndex]);
3081 else
3082 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
3083 break;
3084 case CMSG_SIGNER_CERT_INFO_PARAM:
3085 if (msg->u.signed_data.info)
3087 if (dwIndex >= msg->u.signed_data.info->cSignerInfo)
3088 SetLastError(CRYPT_E_INVALID_INDEX);
3089 else
3090 ret = CRYPT_CopySignerCertInfo(pvData, pcbData,
3091 &msg->u.signed_data.info->rgSignerInfo[dwIndex]);
3093 else
3094 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
3095 break;
3096 case CMSG_CERT_COUNT_PARAM:
3097 if (msg->u.signed_data.info)
3098 ret = CRYPT_CopyParam(pvData, pcbData,
3099 &msg->u.signed_data.info->cCertEncoded, sizeof(DWORD));
3100 else
3101 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
3102 break;
3103 case CMSG_CERT_PARAM:
3104 if (msg->u.signed_data.info)
3106 if (dwIndex >= msg->u.signed_data.info->cCertEncoded)
3107 SetLastError(CRYPT_E_INVALID_INDEX);
3108 else
3109 ret = CRYPT_CopyParam(pvData, pcbData,
3110 msg->u.signed_data.info->rgCertEncoded[dwIndex].pbData,
3111 msg->u.signed_data.info->rgCertEncoded[dwIndex].cbData);
3113 else
3114 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
3115 break;
3116 case CMSG_CRL_COUNT_PARAM:
3117 if (msg->u.signed_data.info)
3118 ret = CRYPT_CopyParam(pvData, pcbData,
3119 &msg->u.signed_data.info->cCrlEncoded, sizeof(DWORD));
3120 else
3121 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
3122 break;
3123 case CMSG_CRL_PARAM:
3124 if (msg->u.signed_data.info)
3126 if (dwIndex >= msg->u.signed_data.info->cCrlEncoded)
3127 SetLastError(CRYPT_E_INVALID_INDEX);
3128 else
3129 ret = CRYPT_CopyParam(pvData, pcbData,
3130 msg->u.signed_data.info->rgCrlEncoded[dwIndex].pbData,
3131 msg->u.signed_data.info->rgCrlEncoded[dwIndex].cbData);
3133 else
3134 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
3135 break;
3136 case CMSG_COMPUTED_HASH_PARAM:
3137 if (msg->u.signed_data.info)
3139 if (dwIndex >= msg->u.signed_data.cSignerHandle)
3140 SetLastError(CRYPT_E_INVALID_INDEX);
3141 else
3142 ret = CryptGetHashParam(
3143 msg->u.signed_data.signerHandles[dwIndex].contentHash,
3144 HP_HASHVAL, pvData, pcbData, 0);
3146 else
3147 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
3148 break;
3149 case CMSG_ENCODED_MESSAGE:
3150 if (msg->msg_data.pbData)
3151 ret = CRYPT_CopyParam(pvData, pcbData, msg->msg_data.pbData, msg->msg_data.cbData);
3152 else
3153 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
3154 break;
3155 case CMSG_ENCODED_SIGNER:
3156 if (msg->u.signed_data.info)
3158 if (dwIndex >= msg->u.signed_data.info->cSignerInfo)
3159 SetLastError(CRYPT_E_INVALID_INDEX);
3160 else
3161 ret = CryptEncodeObjectEx(
3162 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, CMS_SIGNER_INFO,
3163 &msg->u.signed_data.info->rgSignerInfo[dwIndex], 0, NULL,
3164 pvData, pcbData);
3166 else
3167 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
3168 break;
3169 case CMSG_ATTR_CERT_COUNT_PARAM:
3170 if (msg->u.signed_data.info)
3172 DWORD attrCertCount = 0;
3174 ret = CRYPT_CopyParam(pvData, pcbData,
3175 &attrCertCount, sizeof(DWORD));
3177 else
3178 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
3179 break;
3180 case CMSG_ATTR_CERT_PARAM:
3181 if (msg->u.signed_data.info)
3182 SetLastError(CRYPT_E_INVALID_INDEX);
3183 else
3184 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
3185 break;
3186 case CMSG_CMS_SIGNER_INFO_PARAM:
3187 if (msg->u.signed_data.info)
3189 if (dwIndex >= msg->u.signed_data.info->cSignerInfo)
3190 SetLastError(CRYPT_E_INVALID_INDEX);
3191 else
3192 ret = CRYPT_CopyCMSSignerInfo(pvData, pcbData,
3193 &msg->u.signed_data.info->rgSignerInfo[dwIndex]);
3195 else
3196 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
3197 break;
3198 case CMSG_SIGNER_AUTH_ATTR_PARAM:
3199 if (msg->u.signed_data.info)
3201 if (dwIndex >= msg->u.signed_data.info->cSignerInfo)
3202 SetLastError(CRYPT_E_INVALID_INDEX);
3203 else
3204 ret = CRYPT_CopyAttr(pvData, pcbData,
3205 &msg->u.signed_data.info->rgSignerInfo[dwIndex].AuthAttrs);
3207 else
3208 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
3209 break;
3210 case CMSG_SIGNER_UNAUTH_ATTR_PARAM:
3211 if (msg->u.signed_data.info)
3213 if (dwIndex >= msg->u.signed_data.info->cSignerInfo)
3214 SetLastError(CRYPT_E_INVALID_INDEX);
3215 else
3216 ret = CRYPT_CopyAttr(pvData, pcbData,
3217 &msg->u.signed_data.info->rgSignerInfo[dwIndex].UnauthAttrs);
3219 else
3220 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
3221 break;
3222 default:
3223 FIXME("unimplemented for %ld\n", dwParamType);
3224 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
3226 return ret;
3229 static BOOL CDecodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
3230 DWORD dwIndex, void *pvData, DWORD *pcbData)
3232 CDecodeMsg *msg = hCryptMsg;
3233 BOOL ret = FALSE;
3235 switch (msg->type)
3237 case CMSG_HASHED:
3238 ret = CDecodeHashMsg_GetParam(msg, dwParamType, dwIndex, pvData,
3239 pcbData);
3240 break;
3241 case CMSG_ENVELOPED:
3242 ret = CDecodeEnvelopedMsg_GetParam(msg, dwParamType, dwIndex, pvData,
3243 pcbData);
3244 break;
3245 case CMSG_SIGNED:
3246 ret = CDecodeSignedMsg_GetParam(msg, dwParamType, dwIndex, pvData,
3247 pcbData);
3248 break;
3249 default:
3250 switch (dwParamType)
3252 case CMSG_TYPE_PARAM:
3253 ret = CRYPT_CopyParam(pvData, pcbData, &msg->type,
3254 sizeof(msg->type));
3255 break;
3256 default:
3258 CRYPT_DATA_BLOB blob;
3260 ret = ContextPropertyList_FindProperty(msg->properties, dwParamType,
3261 &blob);
3262 if (ret)
3263 ret = CRYPT_CopyParam(pvData, pcbData, blob.pbData,
3264 blob.cbData);
3265 else
3266 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
3270 return ret;
3273 static BOOL CDecodeHashMsg_VerifyHash(CDecodeMsg *msg)
3275 BOOL ret;
3276 CRYPT_DATA_BLOB hashBlob;
3278 ret = ContextPropertyList_FindProperty(msg->properties,
3279 CMSG_HASH_DATA_PARAM, &hashBlob);
3280 if (ret)
3282 DWORD computedHashSize = 0;
3284 ret = CDecodeHashMsg_GetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, NULL,
3285 &computedHashSize);
3286 if (hashBlob.cbData == computedHashSize)
3288 LPBYTE computedHash = CryptMemAlloc(computedHashSize);
3290 if (computedHash)
3292 ret = CDecodeHashMsg_GetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0,
3293 computedHash, &computedHashSize);
3294 if (ret)
3296 if (memcmp(hashBlob.pbData, computedHash, hashBlob.cbData))
3298 SetLastError(CRYPT_E_HASH_VALUE);
3299 ret = FALSE;
3302 CryptMemFree(computedHash);
3304 else
3306 SetLastError(ERROR_OUTOFMEMORY);
3307 ret = FALSE;
3310 else
3312 SetLastError(CRYPT_E_HASH_VALUE);
3313 ret = FALSE;
3316 return ret;
3319 static BOOL cng_verify_msg_signature(CMSG_CMS_SIGNER_INFO *signer, HCRYPTHASH hash, CERT_PUBLIC_KEY_INFO *key_info)
3321 BYTE *hash_value, *sig_value = NULL;
3322 DWORD hash_len, sig_len;
3323 BCRYPT_KEY_HANDLE key;
3324 BOOL ret = FALSE;
3325 NTSTATUS status;
3327 if (!CryptImportPublicKeyInfoEx2(X509_ASN_ENCODING, key_info, 0, NULL, &key)) return FALSE;
3328 if (!extract_hash(hash, &hash_value, &hash_len)) goto done;
3329 if (!cng_prepare_signature(key_info->Algorithm.pszObjId, signer->EncryptedHash.pbData,
3330 signer->EncryptedHash.cbData, &sig_value, &sig_len)) goto done;
3331 status = BCryptVerifySignature(key, NULL, hash_value, hash_len, sig_value, sig_len, 0);
3332 if (status)
3334 FIXME("Failed to verify signature: %08lx.\n", status);
3335 SetLastError(RtlNtStatusToDosError(status));
3337 ret = !status;
3338 done:
3339 CryptMemFree(sig_value);
3340 CryptMemFree(hash_value);
3341 BCryptDestroyKey(key);
3342 return ret;
3345 static BOOL CDecodeSignedMsg_VerifySignatureWithKey(CDecodeMsg *msg,
3346 HCRYPTPROV prov, DWORD signerIndex, PCERT_PUBLIC_KEY_INFO keyInfo)
3348 HCRYPTHASH hash;
3349 HCRYPTKEY key;
3350 BOOL ret;
3351 ALG_ID alg_id = 0;
3353 if (msg->u.signed_data.info->rgSignerInfo[signerIndex].AuthAttrs.cAttr)
3354 hash = msg->u.signed_data.signerHandles[signerIndex].authAttrHash;
3355 else
3356 hash = msg->u.signed_data.signerHandles[signerIndex].contentHash;
3358 if (keyInfo->Algorithm.pszObjId) alg_id = CertOIDToAlgId(keyInfo->Algorithm.pszObjId);
3359 if (alg_id == CALG_OID_INFO_PARAMETERS || alg_id == CALG_OID_INFO_CNG_ONLY)
3360 return cng_verify_msg_signature(&msg->u.signed_data.info->rgSignerInfo[signerIndex], hash, keyInfo);
3362 if (!prov)
3363 prov = msg->crypt_prov;
3364 ret = CryptImportPublicKeyInfo(prov, X509_ASN_ENCODING, keyInfo, &key);
3365 if (ret)
3367 CRYPT_HASH_BLOB reversedHash;
3369 ret = CRYPT_ConstructBlob(&reversedHash,
3370 &msg->u.signed_data.info->rgSignerInfo[signerIndex].EncryptedHash);
3371 if (ret)
3373 CRYPT_ReverseBytes(&reversedHash);
3374 ret = CryptVerifySignatureW(hash, reversedHash.pbData,
3375 reversedHash.cbData, key, NULL, 0);
3376 CryptMemFree(reversedHash.pbData);
3378 CryptDestroyKey(key);
3380 return ret;
3383 static BOOL CDecodeSignedMsg_VerifySignature(CDecodeMsg *msg, PCERT_INFO info)
3385 BOOL ret = FALSE;
3386 DWORD i;
3388 if (!msg->u.signed_data.signerHandles)
3390 SetLastError(NTE_BAD_SIGNATURE);
3391 return FALSE;
3393 for (i = 0; !ret && i < msg->u.signed_data.info->cSignerInfo; i++)
3395 PCMSG_CMS_SIGNER_INFO signerInfo =
3396 &msg->u.signed_data.info->rgSignerInfo[i];
3398 if (signerInfo->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
3400 ret = CertCompareCertificateName(X509_ASN_ENCODING,
3401 &signerInfo->SignerId.IssuerSerialNumber.Issuer,
3402 &info->Issuer);
3403 if (ret)
3405 ret = CertCompareIntegerBlob(
3406 &signerInfo->SignerId.IssuerSerialNumber.SerialNumber,
3407 &info->SerialNumber);
3408 if (ret)
3409 break;
3412 else
3414 FIXME("signer %ld: unimplemented for key id\n", i);
3417 if (ret)
3418 ret = CDecodeSignedMsg_VerifySignatureWithKey(msg, 0, i,
3419 &info->SubjectPublicKeyInfo);
3420 else
3421 SetLastError(CRYPT_E_SIGNER_NOT_FOUND);
3423 return ret;
3426 static BOOL CDecodeSignedMsg_VerifySignatureEx(CDecodeMsg *msg,
3427 PCMSG_CTRL_VERIFY_SIGNATURE_EX_PARA para)
3429 BOOL ret = FALSE;
3431 if (para->cbSize != sizeof(CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA))
3432 SetLastError(ERROR_INVALID_PARAMETER);
3433 else if (para->dwSignerIndex >= msg->u.signed_data.info->cSignerInfo)
3434 SetLastError(CRYPT_E_SIGNER_NOT_FOUND);
3435 else if (!msg->u.signed_data.signerHandles)
3436 SetLastError(NTE_BAD_SIGNATURE);
3437 else
3439 switch (para->dwSignerType)
3441 case CMSG_VERIFY_SIGNER_PUBKEY:
3442 ret = CDecodeSignedMsg_VerifySignatureWithKey(msg,
3443 para->hCryptProv, para->dwSignerIndex, para->pvSigner);
3444 break;
3445 case CMSG_VERIFY_SIGNER_CERT:
3447 PCCERT_CONTEXT cert = para->pvSigner;
3449 ret = CDecodeSignedMsg_VerifySignatureWithKey(msg, para->hCryptProv,
3450 para->dwSignerIndex, &cert->pCertInfo->SubjectPublicKeyInfo);
3451 break;
3453 default:
3454 FIXME("unimplemented for signer type %ld\n", para->dwSignerType);
3455 SetLastError(CRYPT_E_SIGNER_NOT_FOUND);
3458 return ret;
3461 static BOOL WINAPI CRYPT_ImportKeyTrans(
3462 PCRYPT_ALGORITHM_IDENTIFIER pContentEncryptionAlgorithm,
3463 PCMSG_CTRL_KEY_TRANS_DECRYPT_PARA pKeyTransDecryptPara, DWORD dwFlags,
3464 void *pvReserved, HCRYPTKEY *phContentEncryptKey)
3466 BOOL ret;
3467 HCRYPTKEY key;
3469 ret = CryptGetUserKey(pKeyTransDecryptPara->hCryptProv,
3470 pKeyTransDecryptPara->dwKeySpec ? pKeyTransDecryptPara->dwKeySpec :
3471 AT_KEYEXCHANGE, &key);
3472 if (ret)
3474 CMSG_KEY_TRANS_RECIPIENT_INFO *info =
3475 &pKeyTransDecryptPara->pKeyTrans[pKeyTransDecryptPara->dwRecipientIndex];
3476 CRYPT_DATA_BLOB *encryptedKey = &info->EncryptedKey;
3477 DWORD size = encryptedKey->cbData + sizeof(BLOBHEADER) + sizeof(ALG_ID);
3478 BYTE *keyBlob = CryptMemAlloc(size);
3480 if (keyBlob)
3482 DWORD i, k = size - 1;
3483 BLOBHEADER *blobHeader = (BLOBHEADER *)keyBlob;
3484 ALG_ID *algID = (ALG_ID *)(keyBlob + sizeof(BLOBHEADER));
3486 blobHeader->bType = SIMPLEBLOB;
3487 blobHeader->bVersion = CUR_BLOB_VERSION;
3488 blobHeader->reserved = 0;
3489 blobHeader->aiKeyAlg = CertOIDToAlgId(
3490 pContentEncryptionAlgorithm->pszObjId);
3491 *algID = CertOIDToAlgId(info->KeyEncryptionAlgorithm.pszObjId);
3492 for (i = 0; i < encryptedKey->cbData; ++i, --k)
3493 keyBlob[k] = encryptedKey->pbData[i];
3495 ret = CryptImportKey(pKeyTransDecryptPara->hCryptProv, keyBlob,
3496 size, key, 0, phContentEncryptKey);
3497 CryptMemFree(keyBlob);
3499 else
3500 ret = FALSE;
3501 CryptDestroyKey(key);
3503 return ret;
3506 static BOOL CRYPT_ImportEncryptedKey(PCRYPT_ALGORITHM_IDENTIFIER contEncrAlg,
3507 PCMSG_CTRL_DECRYPT_PARA para, PCMSG_KEY_TRANS_RECIPIENT_INFO info,
3508 HCRYPTKEY *key)
3510 static HCRYPTOIDFUNCSET set = NULL;
3511 PFN_CMSG_IMPORT_KEY_TRANS importKeyFunc = NULL;
3512 HCRYPTOIDFUNCADDR hFunc = NULL;
3513 CMSG_CTRL_KEY_TRANS_DECRYPT_PARA decryptPara;
3514 BOOL ret;
3516 memset(&decryptPara, 0, sizeof(decryptPara));
3517 decryptPara.cbSize = sizeof(decryptPara);
3518 decryptPara.hCryptProv = para->hCryptProv;
3519 decryptPara.dwKeySpec = para->dwKeySpec;
3520 decryptPara.pKeyTrans = info;
3521 decryptPara.dwRecipientIndex = para->dwRecipientIndex;
3523 if (!set)
3524 set = CryptInitOIDFunctionSet(CMSG_OID_IMPORT_KEY_TRANS_FUNC, 0);
3525 CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, contEncrAlg->pszObjId, 0,
3526 (void **)&importKeyFunc, &hFunc);
3527 if (!importKeyFunc)
3528 importKeyFunc = CRYPT_ImportKeyTrans;
3529 ret = importKeyFunc(contEncrAlg, &decryptPara, 0, NULL, key);
3530 if (hFunc)
3531 CryptFreeOIDFunctionAddress(hFunc, 0);
3532 return ret;
3535 static BOOL CDecodeEnvelopedMsg_CrtlDecrypt(CDecodeMsg *msg,
3536 PCMSG_CTRL_DECRYPT_PARA para)
3538 BOOL ret = FALSE;
3539 CEnvelopedDecodeMsg *enveloped_data = &msg->u.enveloped_data;
3540 CRYPT_ENVELOPED_DATA *data = enveloped_data->data;
3542 if (para->cbSize != sizeof(CMSG_CTRL_DECRYPT_PARA))
3543 SetLastError(E_INVALIDARG);
3544 else if (!data)
3545 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
3546 else if (para->dwRecipientIndex >= data->cRecipientInfo)
3547 SetLastError(CRYPT_E_INVALID_INDEX);
3548 else if (enveloped_data->decrypted)
3549 SetLastError(CRYPT_E_ALREADY_DECRYPTED);
3550 else if (!para->hCryptProv)
3551 SetLastError(ERROR_INVALID_PARAMETER);
3552 else if (enveloped_data->content.cbData)
3554 HCRYPTKEY key;
3556 ret = CRYPT_ImportEncryptedKey(
3557 &data->encryptedContentInfo.contentEncryptionAlgorithm, para,
3558 data->rgRecipientInfo, &key);
3559 if (ret)
3561 ret = CryptDecrypt(key, 0, TRUE, 0, enveloped_data->content.pbData,
3562 &enveloped_data->content.cbData);
3563 CryptDestroyKey(key);
3566 else
3567 ret = TRUE;
3568 if (ret)
3569 enveloped_data->decrypted = TRUE;
3570 return ret;
3573 static BOOL CDecodeMsg_Control(HCRYPTMSG hCryptMsg, DWORD dwFlags,
3574 DWORD dwCtrlType, const void *pvCtrlPara)
3576 CDecodeMsg *msg = hCryptMsg;
3577 BOOL ret = FALSE;
3579 switch (dwCtrlType)
3581 case CMSG_CTRL_VERIFY_SIGNATURE:
3582 switch (msg->type)
3584 case CMSG_SIGNED:
3585 ret = CDecodeSignedMsg_VerifySignature(msg, (PCERT_INFO)pvCtrlPara);
3586 break;
3587 default:
3588 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
3590 break;
3591 case CMSG_CTRL_DECRYPT:
3592 switch (msg->type)
3594 case CMSG_ENVELOPED:
3595 ret = CDecodeEnvelopedMsg_CrtlDecrypt(msg,
3596 (PCMSG_CTRL_DECRYPT_PARA)pvCtrlPara);
3597 if (ret && (dwFlags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG))
3598 msg->u.enveloped_data.crypt_prov =
3599 ((PCMSG_CTRL_DECRYPT_PARA)pvCtrlPara)->hCryptProv;
3600 break;
3601 default:
3602 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
3604 break;
3605 case CMSG_CTRL_VERIFY_HASH:
3606 switch (msg->type)
3608 case CMSG_HASHED:
3609 ret = CDecodeHashMsg_VerifyHash(msg);
3610 break;
3611 default:
3612 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
3614 break;
3615 case CMSG_CTRL_VERIFY_SIGNATURE_EX:
3616 switch (msg->type)
3618 case CMSG_SIGNED:
3619 ret = CDecodeSignedMsg_VerifySignatureEx(msg,
3620 (PCMSG_CTRL_VERIFY_SIGNATURE_EX_PARA)pvCtrlPara);
3621 break;
3622 default:
3623 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
3625 break;
3626 default:
3627 SetLastError(CRYPT_E_CONTROL_TYPE);
3629 return ret;
3632 HCRYPTMSG WINAPI CryptMsgOpenToDecode(DWORD dwMsgEncodingType, DWORD dwFlags,
3633 DWORD dwMsgType, HCRYPTPROV_LEGACY hCryptProv, PCERT_INFO pRecipientInfo,
3634 PCMSG_STREAM_INFO pStreamInfo)
3636 CDecodeMsg *msg;
3638 TRACE("(%08lx, %08lx, %08lx, %08Ix, %p, %p)\n", dwMsgEncodingType,
3639 dwFlags, dwMsgType, hCryptProv, pRecipientInfo, pStreamInfo);
3641 if (GET_CMSG_ENCODING_TYPE(dwMsgEncodingType) != PKCS_7_ASN_ENCODING)
3643 SetLastError(E_INVALIDARG);
3644 return NULL;
3646 msg = CryptMemAlloc(sizeof(CDecodeMsg));
3647 if (msg)
3649 CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo,
3650 CDecodeMsg_Close, CDecodeMsg_GetParam, CDecodeMsg_Update,
3651 CDecodeMsg_Control);
3652 msg->type = dwMsgType;
3653 msg->crypt_prov = hCryptProv;
3654 memset(&msg->u, 0, sizeof(msg->u));
3655 msg->msg_data.cbData = 0;
3656 msg->msg_data.pbData = NULL;
3657 msg->detached_data.cbData = 0;
3658 msg->detached_data.pbData = NULL;
3659 msg->properties = ContextPropertyList_Create();
3661 return msg;
3664 HCRYPTMSG WINAPI CryptMsgDuplicate(HCRYPTMSG hCryptMsg)
3666 TRACE("(%p)\n", hCryptMsg);
3668 if (hCryptMsg)
3670 CryptMsgBase *msg = hCryptMsg;
3672 InterlockedIncrement(&msg->ref);
3674 return hCryptMsg;
3677 BOOL WINAPI CryptMsgClose(HCRYPTMSG hCryptMsg)
3679 TRACE("(%p)\n", hCryptMsg);
3681 if (hCryptMsg)
3683 CryptMsgBase *msg = hCryptMsg;
3685 if (InterlockedDecrement(&msg->ref) == 0)
3687 TRACE("freeing %p\n", msg);
3688 if (msg->close)
3689 msg->close(msg);
3690 CryptMemFree(msg);
3693 return TRUE;
3696 BOOL WINAPI CryptMsgUpdate(HCRYPTMSG hCryptMsg, const BYTE *pbData,
3697 DWORD cbData, BOOL fFinal)
3699 CryptMsgBase *msg = hCryptMsg;
3701 TRACE("(%p, %p, %ld, %d)\n", hCryptMsg, pbData, cbData, fFinal);
3703 return msg->update(hCryptMsg, pbData, cbData, fFinal);
3706 BOOL WINAPI CryptMsgGetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
3707 DWORD dwIndex, void *pvData, DWORD *pcbData)
3709 CryptMsgBase *msg = hCryptMsg;
3711 TRACE("(%p, %ld, %ld, %p, %p)\n", hCryptMsg, dwParamType, dwIndex,
3712 pvData, pcbData);
3713 return msg->get_param(hCryptMsg, dwParamType, dwIndex, pvData, pcbData);
3716 BOOL WINAPI CryptMsgControl(HCRYPTMSG hCryptMsg, DWORD dwFlags,
3717 DWORD dwCtrlType, const void *pvCtrlPara)
3719 CryptMsgBase *msg = hCryptMsg;
3721 TRACE("(%p, %08lx, %ld, %p)\n", hCryptMsg, dwFlags, dwCtrlType,
3722 pvCtrlPara);
3723 return msg->control(hCryptMsg, dwFlags, dwCtrlType, pvCtrlPara);
3726 static CERT_INFO *CRYPT_GetSignerCertInfoFromMsg(HCRYPTMSG msg,
3727 DWORD dwSignerIndex)
3729 CERT_INFO *certInfo = NULL;
3730 DWORD size;
3732 if (CryptMsgGetParam(msg, CMSG_SIGNER_CERT_INFO_PARAM, dwSignerIndex, NULL,
3733 &size))
3735 certInfo = CryptMemAlloc(size);
3736 if (certInfo)
3738 if (!CryptMsgGetParam(msg, CMSG_SIGNER_CERT_INFO_PARAM,
3739 dwSignerIndex, certInfo, &size))
3741 CryptMemFree(certInfo);
3742 certInfo = NULL;
3746 return certInfo;
3749 BOOL WINAPI CryptMsgGetAndVerifySigner(HCRYPTMSG hCryptMsg, DWORD cSignerStore,
3750 HCERTSTORE *rghSignerStore, DWORD dwFlags, PCCERT_CONTEXT *ppSigner,
3751 DWORD *pdwSignerIndex)
3753 HCERTSTORE store;
3754 DWORD i, signerIndex = 0;
3755 PCCERT_CONTEXT signerCert = NULL;
3756 BOOL ret = FALSE;
3758 TRACE("(%p, %ld, %p, %08lx, %p, %p)\n", hCryptMsg, cSignerStore,
3759 rghSignerStore, dwFlags, ppSigner, pdwSignerIndex);
3761 /* Clear output parameters */
3762 if (ppSigner)
3763 *ppSigner = NULL;
3764 if (pdwSignerIndex && !(dwFlags & CMSG_USE_SIGNER_INDEX_FLAG))
3765 *pdwSignerIndex = 0;
3767 /* Create store to search for signer certificates */
3768 store = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
3769 CERT_STORE_CREATE_NEW_FLAG, NULL);
3770 if (!(dwFlags & CMSG_TRUSTED_SIGNER_FLAG))
3772 HCERTSTORE msgStore = CertOpenStore(CERT_STORE_PROV_MSG, 0, 0, 0,
3773 hCryptMsg);
3775 CertAddStoreToCollection(store, msgStore, 0, 0);
3776 CertCloseStore(msgStore, 0);
3778 for (i = 0; i < cSignerStore; i++)
3779 CertAddStoreToCollection(store, rghSignerStore[i], 0, 0);
3781 /* Find signer cert */
3782 if (dwFlags & CMSG_USE_SIGNER_INDEX_FLAG)
3784 CERT_INFO *signer = CRYPT_GetSignerCertInfoFromMsg(hCryptMsg,
3785 *pdwSignerIndex);
3787 if (signer)
3789 signerIndex = *pdwSignerIndex;
3790 signerCert = CertFindCertificateInStore(store, X509_ASN_ENCODING,
3791 0, CERT_FIND_SUBJECT_CERT, signer, NULL);
3792 CryptMemFree(signer);
3795 else
3797 DWORD count, size = sizeof(count);
3799 if (CryptMsgGetParam(hCryptMsg, CMSG_SIGNER_COUNT_PARAM, 0, &count,
3800 &size))
3802 for (i = 0; !signerCert && i < count; i++)
3804 CERT_INFO *signer = CRYPT_GetSignerCertInfoFromMsg(hCryptMsg,
3807 if (signer)
3809 signerCert = CertFindCertificateInStore(store,
3810 X509_ASN_ENCODING, 0, CERT_FIND_SUBJECT_CERT, signer,
3811 NULL);
3812 if (signerCert)
3813 signerIndex = i;
3814 CryptMemFree(signer);
3818 if (!signerCert)
3819 SetLastError(CRYPT_E_NO_TRUSTED_SIGNER);
3821 if (signerCert)
3823 if (!(dwFlags & CMSG_SIGNER_ONLY_FLAG))
3824 ret = CryptMsgControl(hCryptMsg, 0, CMSG_CTRL_VERIFY_SIGNATURE,
3825 signerCert->pCertInfo);
3826 else
3827 ret = TRUE;
3828 if (ret)
3830 if (ppSigner)
3831 *ppSigner = CertDuplicateCertificateContext(signerCert);
3832 if (pdwSignerIndex)
3833 *pdwSignerIndex = signerIndex;
3835 CertFreeCertificateContext(signerCert);
3838 CertCloseStore(store, 0);
3839 return ret;
3842 BOOL WINAPI CryptMsgVerifyCountersignatureEncoded(HCRYPTPROV_LEGACY hCryptProv,
3843 DWORD dwEncodingType, BYTE *pbSignerInfo, DWORD cbSignerInfo,
3844 PBYTE pbSignerInfoCountersignature, DWORD cbSignerInfoCountersignature,
3845 CERT_INFO *pciCountersigner)
3847 FIXME("(%08Ix, %08lx, %p, %ld, %p, %ld, %p): stub\n", hCryptProv,
3848 dwEncodingType, pbSignerInfo, cbSignerInfo, pbSignerInfoCountersignature,
3849 cbSignerInfoCountersignature, pciCountersigner);
3850 return FALSE;
3853 BOOL WINAPI CryptMsgVerifyCountersignatureEncodedEx(HCRYPTPROV_LEGACY hCryptProv,
3854 DWORD dwEncodingType, PBYTE pbSignerInfo, DWORD cbSignerInfo,
3855 PBYTE pbSignerInfoCountersignature, DWORD cbSignerInfoCountersignature,
3856 DWORD dwSignerType, void *pvSigner, DWORD dwFlags, void *pvReserved)
3858 FIXME("(%08Ix, %08lx, %p, %ld, %p, %ld, %ld, %p, %08lx, %p): stub\n", hCryptProv,
3859 dwEncodingType, pbSignerInfo, cbSignerInfo, pbSignerInfoCountersignature,
3860 cbSignerInfoCountersignature, dwSignerType, pvSigner, dwFlags, pvReserved);
3861 return FALSE;
3864 BOOL WINAPI CryptMsgEncodeAndSignCTL(DWORD dwMsgEncodingType,
3865 PCTL_INFO pCtlInfo, PCMSG_SIGNED_ENCODE_INFO pSignInfo, DWORD dwFlags,
3866 BYTE *pbEncoded, DWORD *pcbEncoded)
3868 BOOL ret;
3869 BYTE *pbCtlContent;
3870 DWORD cbCtlContent;
3872 TRACE("(%08lx, %p, %p, %08lx, %p, %p)\n", dwMsgEncodingType, pCtlInfo,
3873 pSignInfo, dwFlags, pbEncoded, pcbEncoded);
3875 if (dwFlags)
3877 FIXME("unimplemented for flags %08lx\n", dwFlags);
3878 return FALSE;
3880 if ((ret = CryptEncodeObjectEx(dwMsgEncodingType, PKCS_CTL, pCtlInfo,
3881 CRYPT_ENCODE_ALLOC_FLAG, NULL, &pbCtlContent, &cbCtlContent)))
3883 ret = CryptMsgSignCTL(dwMsgEncodingType, pbCtlContent, cbCtlContent,
3884 pSignInfo, dwFlags, pbEncoded, pcbEncoded);
3885 LocalFree(pbCtlContent);
3887 return ret;
3890 BOOL WINAPI CryptMsgSignCTL(DWORD dwMsgEncodingType, BYTE *pbCtlContent,
3891 DWORD cbCtlContent, PCMSG_SIGNED_ENCODE_INFO pSignInfo, DWORD dwFlags,
3892 BYTE *pbEncoded, DWORD *pcbEncoded)
3894 static char oid_ctl[] = szOID_CTL;
3895 BOOL ret;
3896 HCRYPTMSG msg;
3898 TRACE("(%08lx, %p, %ld, %p, %08lx, %p, %p)\n", dwMsgEncodingType,
3899 pbCtlContent, cbCtlContent, pSignInfo, dwFlags, pbEncoded, pcbEncoded);
3901 if (dwFlags)
3903 FIXME("unimplemented for flags %08lx\n", dwFlags);
3904 return FALSE;
3906 msg = CryptMsgOpenToEncode(dwMsgEncodingType, 0, CMSG_SIGNED, pSignInfo,
3907 oid_ctl, NULL);
3908 if (msg)
3910 ret = CryptMsgUpdate(msg, pbCtlContent, cbCtlContent, TRUE);
3911 if (ret)
3912 ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, pbEncoded,
3913 pcbEncoded);
3914 CryptMsgClose(msg);
3916 else
3917 ret = FALSE;
3918 return ret;