d3d9: Add an IDirect3D9Ex stub.
[wine] / dlls / crypt32 / msg.c
1 /*
2  * Copyright 2007 Juan Lang
3  *
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.
8  *
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.
13  *
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
17  */
18 #include <stdarg.h>
19 #include "windef.h"
20 #include "winbase.h"
21 #include "wincrypt.h"
22 #include "snmp.h"
23
24 #include "wine/debug.h"
25 #include "wine/exception.h"
26 #include "crypt32_private.h"
27
28 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
29
30 /* Called when a message's ref count reaches zero.  Free any message-specific
31  * data here.
32  */
33 typedef void (*CryptMsgCloseFunc)(HCRYPTMSG msg);
34
35 typedef BOOL (*CryptMsgGetParamFunc)(HCRYPTMSG hCryptMsg, DWORD dwParamType,
36  DWORD dwIndex, void *pvData, DWORD *pcbData);
37
38 typedef BOOL (*CryptMsgUpdateFunc)(HCRYPTMSG hCryptMsg, const BYTE *pbData,
39  DWORD cbData, BOOL fFinal);
40
41 typedef BOOL (*CryptMsgControlFunc)(HCRYPTMSG hCryptMsg, DWORD dwFlags,
42  DWORD dwCtrlType, const void *pvCtrlPara);
43
44 BOOL CRYPT_DefaultMsgControl(HCRYPTMSG hCryptMsg, DWORD dwFlags,
45  DWORD dwCtrlType, const void *pvCtrlPara)
46 {
47     TRACE("(%p, %08x, %d, %p)\n", hCryptMsg, dwFlags, dwCtrlType, pvCtrlPara);
48     SetLastError(E_INVALIDARG);
49     return FALSE;
50 }
51
52 typedef enum _CryptMsgState {
53     MsgStateInit,
54     MsgStateUpdated,
55     MsgStateFinalized
56 } CryptMsgState;
57
58 typedef struct _CryptMsgBase
59 {
60     LONG                 ref;
61     DWORD                open_flags;
62     BOOL                 streamed;
63     CMSG_STREAM_INFO     stream_info;
64     CryptMsgState        state;
65     CryptMsgCloseFunc    close;
66     CryptMsgUpdateFunc   update;
67     CryptMsgGetParamFunc get_param;
68     CryptMsgControlFunc  control;
69 } CryptMsgBase;
70
71 static inline void CryptMsgBase_Init(CryptMsgBase *msg, DWORD dwFlags,
72  PCMSG_STREAM_INFO pStreamInfo, CryptMsgCloseFunc close,
73  CryptMsgGetParamFunc get_param, CryptMsgUpdateFunc update,
74  CryptMsgControlFunc control)
75 {
76     msg->ref = 1;
77     msg->open_flags = dwFlags;
78     if (pStreamInfo)
79     {
80         msg->streamed = TRUE;
81         msg->stream_info = *pStreamInfo;
82     }
83     else
84     {
85         msg->streamed = FALSE;
86         memset(&msg->stream_info, 0, sizeof(msg->stream_info));
87     }
88     msg->close = close;
89     msg->get_param = get_param;
90     msg->update = update;
91     msg->control = control;
92     msg->state = MsgStateInit;
93 }
94
95 typedef struct _CDataEncodeMsg
96 {
97     CryptMsgBase base;
98     DWORD        bare_content_len;
99     LPBYTE       bare_content;
100 } CDataEncodeMsg;
101
102 static const BYTE empty_data_content[] = { 0x04,0x00 };
103
104 static void CDataEncodeMsg_Close(HCRYPTMSG hCryptMsg)
105 {
106     CDataEncodeMsg *msg = (CDataEncodeMsg *)hCryptMsg;
107
108     if (msg->bare_content != empty_data_content)
109         LocalFree(msg->bare_content);
110 }
111
112 static BOOL WINAPI CRYPT_EncodeContentLength(DWORD dwCertEncodingType,
113  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
114  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
115 {
116     DWORD dataLen = *(DWORD *)pvStructInfo;
117     DWORD lenBytes;
118     BOOL ret = TRUE;
119
120     /* Trick:  report bytes needed based on total message length, even though
121      * the message isn't available yet.  The caller will use the length
122      * reported here to encode its length.
123      */
124     CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
125     if (!pbEncoded)
126         *pcbEncoded = 1 + lenBytes + dataLen;
127     else
128     {
129         if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
130          pcbEncoded, 1 + lenBytes)))
131         {
132             if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
133                 pbEncoded = *(BYTE **)pbEncoded;
134             *pbEncoded++ = ASN_OCTETSTRING;
135             CRYPT_EncodeLen(dataLen, pbEncoded,
136              &lenBytes);
137         }
138     }
139     return ret;
140 }
141
142 static BOOL CRYPT_EncodeDataContentInfoHeader(CDataEncodeMsg *msg,
143  CRYPT_DATA_BLOB *header)
144 {
145     BOOL ret;
146
147     if (msg->base.streamed && msg->base.stream_info.cbContent == 0xffffffff)
148     {
149         static const BYTE headerValue[] = { 0x30,0x80,0x06,0x09,0x2a,0x86,0x48,
150          0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x80,0x24,0x80 };
151
152         header->pbData = LocalAlloc(0, sizeof(headerValue));
153         if (header->pbData)
154         {
155             header->cbData = sizeof(headerValue);
156             memcpy(header->pbData, headerValue, sizeof(headerValue));
157             ret = TRUE;
158         }
159         else
160             ret = FALSE;
161     }
162     else
163     {
164         struct AsnConstructedItem constructed = { 0,
165          &msg->base.stream_info.cbContent, CRYPT_EncodeContentLength };
166         struct AsnEncodeSequenceItem items[2] = {
167          { szOID_RSA_data, CRYPT_AsnEncodeOid, 0 },
168          { &constructed,   CRYPT_AsnEncodeConstructed, 0 },
169         };
170
171         ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items,
172          sizeof(items) / sizeof(items[0]), CRYPT_ENCODE_ALLOC_FLAG, NULL,
173          (LPBYTE)&header->pbData, &header->cbData);
174         if (ret)
175         {
176             /* Trick:  subtract the content length from the reported length,
177              * as the actual content hasn't come yet.
178              */
179             header->cbData -= msg->base.stream_info.cbContent;
180         }
181     }
182     return ret;
183 }
184
185 static BOOL CDataEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
186  DWORD cbData, BOOL fFinal)
187 {
188     CDataEncodeMsg *msg = (CDataEncodeMsg *)hCryptMsg;
189     BOOL ret = FALSE;
190
191     if (msg->base.streamed)
192     {
193         __TRY
194         {
195             if (msg->base.state != MsgStateUpdated)
196             {
197                 CRYPT_DATA_BLOB header;
198
199                 ret = CRYPT_EncodeDataContentInfoHeader(msg, &header);
200                 if (ret)
201                 {
202                     ret = msg->base.stream_info.pfnStreamOutput(
203                      msg->base.stream_info.pvArg, header.pbData, header.cbData,
204                      FALSE);
205                     LocalFree(header.pbData);
206                 }
207             }
208             /* Curiously, every indefinite-length streamed update appears to
209              * get its own tag and length, regardless of fFinal.
210              */
211             if (msg->base.stream_info.cbContent == 0xffffffff)
212             {
213                 BYTE *header;
214                 DWORD headerLen;
215
216                 ret = CRYPT_EncodeContentLength(X509_ASN_ENCODING, NULL,
217                  &cbData, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&header,
218                  &headerLen);
219                 if (ret)
220                 {
221                     ret = msg->base.stream_info.pfnStreamOutput(
222                      msg->base.stream_info.pvArg, header, headerLen,
223                      FALSE);
224                     LocalFree(header);
225                 }
226             }
227             if (!fFinal)
228                 ret = msg->base.stream_info.pfnStreamOutput(
229                  msg->base.stream_info.pvArg, (BYTE *)pbData, cbData,
230                  FALSE);
231             else
232             {
233                 if (msg->base.stream_info.cbContent == 0xffffffff)
234                 {
235                     BYTE indefinite_trailer[6] = { 0 };
236
237                     ret = msg->base.stream_info.pfnStreamOutput(
238                      msg->base.stream_info.pvArg, (BYTE *)pbData, cbData,
239                      FALSE);
240                     if (ret)
241                         ret = msg->base.stream_info.pfnStreamOutput(
242                          msg->base.stream_info.pvArg, indefinite_trailer,
243                          sizeof(indefinite_trailer), TRUE);
244                 }
245                 else
246                     ret = msg->base.stream_info.pfnStreamOutput(
247                      msg->base.stream_info.pvArg, (BYTE *)pbData, cbData, TRUE);
248             }
249         }
250         __EXCEPT_PAGE_FAULT
251         {
252             SetLastError(STATUS_ACCESS_VIOLATION);
253             ret = FALSE;
254         }
255         __ENDTRY;
256     }
257     else
258     {
259         if (!fFinal)
260         {
261             if (msg->base.open_flags & CMSG_DETACHED_FLAG)
262                 SetLastError(E_INVALIDARG);
263             else
264                 SetLastError(CRYPT_E_MSG_ERROR);
265         }
266         else
267         {
268             if (!cbData)
269                 SetLastError(E_INVALIDARG);
270             else
271             {
272                 CRYPT_DATA_BLOB blob = { cbData, (LPBYTE)pbData };
273
274                 /* non-streamed data messages don't allow non-final updates,
275                  * don't bother checking whether data already exist, they can't.
276                  */
277                 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING,
278                  &blob, CRYPT_ENCODE_ALLOC_FLAG, NULL, &msg->bare_content,
279                  &msg->bare_content_len);
280             }
281         }
282     }
283     return ret;
284 }
285
286 static BOOL CRYPT_CopyParam(void *pvData, DWORD *pcbData, const void *src,
287  DWORD len)
288 {
289     BOOL ret = TRUE;
290
291     if (!pvData)
292         *pcbData = len;
293     else if (*pcbData < len)
294     {
295         *pcbData = len;
296         SetLastError(ERROR_MORE_DATA);
297         ret = FALSE;
298     }
299     else
300     {
301         *pcbData = len;
302         memcpy(pvData, src, len);
303     }
304     return ret;
305 }
306
307 static BOOL CDataEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
308  DWORD dwIndex, void *pvData, DWORD *pcbData)
309 {
310     CDataEncodeMsg *msg = (CDataEncodeMsg *)hCryptMsg;
311     BOOL ret = FALSE;
312
313     switch (dwParamType)
314     {
315     case CMSG_CONTENT_PARAM:
316         if (msg->base.streamed)
317             SetLastError(E_INVALIDARG);
318         else
319         {
320             CRYPT_CONTENT_INFO info;
321             char rsa_data[] = "1.2.840.113549.1.7.1";
322
323             info.pszObjId = rsa_data;
324             info.Content.cbData = msg->bare_content_len;
325             info.Content.pbData = msg->bare_content;
326             ret = CryptEncodeObject(X509_ASN_ENCODING, PKCS_CONTENT_INFO, &info,
327              pvData, pcbData);
328         }
329         break;
330     case CMSG_BARE_CONTENT_PARAM:
331         if (msg->base.streamed)
332             SetLastError(E_INVALIDARG);
333         else
334             ret = CRYPT_CopyParam(pvData, pcbData, msg->bare_content,
335              msg->bare_content_len);
336         break;
337     default:
338         SetLastError(CRYPT_E_INVALID_MSG_TYPE);
339     }
340     return ret;
341 }
342
343 static HCRYPTMSG CDataEncodeMsg_Open(DWORD dwFlags, const void *pvMsgEncodeInfo,
344  LPSTR pszInnerContentObjID, PCMSG_STREAM_INFO pStreamInfo)
345 {
346     CDataEncodeMsg *msg;
347
348     if (pvMsgEncodeInfo)
349     {
350         SetLastError(E_INVALIDARG);
351         return NULL;
352     }
353     msg = CryptMemAlloc(sizeof(CDataEncodeMsg));
354     if (msg)
355     {
356         CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo,
357          CDataEncodeMsg_Close, CDataEncodeMsg_GetParam, CDataEncodeMsg_Update,
358          CRYPT_DefaultMsgControl);
359         msg->bare_content_len = sizeof(empty_data_content);
360         msg->bare_content = (LPBYTE)empty_data_content;
361     }
362     return (HCRYPTMSG)msg;
363 }
364
365 typedef struct _CHashEncodeMsg
366 {
367     CryptMsgBase    base;
368     HCRYPTPROV      prov;
369     HCRYPTHASH      hash;
370     CRYPT_DATA_BLOB data;
371 } CHashEncodeMsg;
372
373 static void CHashEncodeMsg_Close(HCRYPTMSG hCryptMsg)
374 {
375     CHashEncodeMsg *msg = (CHashEncodeMsg *)hCryptMsg;
376
377     CryptMemFree(msg->data.pbData);
378     CryptDestroyHash(msg->hash);
379     if (msg->base.open_flags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG)
380         CryptReleaseContext(msg->prov, 0);
381 }
382
383 static BOOL CRYPT_EncodePKCSDigestedData(CHashEncodeMsg *msg, void *pvData,
384  DWORD *pcbData)
385 {
386     BOOL ret;
387     ALG_ID algID;
388     DWORD size = sizeof(algID);
389
390     ret = CryptGetHashParam(msg->hash, HP_ALGID, (BYTE *)&algID, &size, 0);
391     if (ret)
392     {
393         CRYPT_DIGESTED_DATA digestedData = { 0 };
394         char oid_rsa_data[] = szOID_RSA_data;
395
396         digestedData.version = CMSG_HASHED_DATA_PKCS_1_5_VERSION;
397         digestedData.DigestAlgorithm.pszObjId = (LPSTR)CertAlgIdToOID(algID);
398         /* FIXME: what about digestedData.DigestAlgorithm.Parameters? */
399         /* Quirk:  OID is only encoded messages if an update has happened */
400         if (msg->base.state != MsgStateInit)
401             digestedData.ContentInfo.pszObjId = oid_rsa_data;
402         if (!(msg->base.open_flags & CMSG_DETACHED_FLAG) && msg->data.cbData)
403         {
404             ret = CRYPT_AsnEncodeOctets(0, NULL, &msg->data,
405              CRYPT_ENCODE_ALLOC_FLAG, NULL,
406              (LPBYTE)&digestedData.ContentInfo.Content.pbData,
407              &digestedData.ContentInfo.Content.cbData);
408         }
409         if (msg->base.state == MsgStateFinalized)
410         {
411             size = sizeof(DWORD);
412             ret = CryptGetHashParam(msg->hash, HP_HASHSIZE,
413              (LPBYTE)&digestedData.hash.cbData, &size, 0);
414             if (ret)
415             {
416                 digestedData.hash.pbData = CryptMemAlloc(
417                  digestedData.hash.cbData);
418                 ret = CryptGetHashParam(msg->hash, HP_HASHVAL,
419                  digestedData.hash.pbData, &digestedData.hash.cbData, 0);
420             }
421         }
422         if (ret)
423             ret = CRYPT_AsnEncodePKCSDigestedData(&digestedData, pvData,
424              pcbData);
425         CryptMemFree(digestedData.hash.pbData);
426         LocalFree(digestedData.ContentInfo.Content.pbData);
427     }
428     return ret;
429 }
430
431 static BOOL CHashEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
432  DWORD dwIndex, void *pvData, DWORD *pcbData)
433 {
434     CHashEncodeMsg *msg = (CHashEncodeMsg *)hCryptMsg;
435     BOOL ret = FALSE;
436
437     TRACE("(%p, %d, %d, %p, %p)\n", hCryptMsg, dwParamType, dwIndex,
438      pvData, pcbData);
439
440     switch (dwParamType)
441     {
442     case CMSG_BARE_CONTENT_PARAM:
443         if (msg->base.streamed)
444             SetLastError(E_INVALIDARG);
445         else
446             ret = CRYPT_EncodePKCSDigestedData(msg, pvData, pcbData);
447         break;
448     case CMSG_CONTENT_PARAM:
449     {
450         CRYPT_CONTENT_INFO info;
451
452         ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0, NULL,
453          &info.Content.cbData);
454         if (ret)
455         {
456             info.Content.pbData = CryptMemAlloc(info.Content.cbData);
457             if (info.Content.pbData)
458             {
459                 ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0,
460                  info.Content.pbData, &info.Content.cbData);
461                 if (ret)
462                 {
463                     char oid_rsa_hashed[] = szOID_RSA_hashedData;
464
465                     info.pszObjId = oid_rsa_hashed;
466                     ret = CryptEncodeObjectEx(X509_ASN_ENCODING,
467                      PKCS_CONTENT_INFO, &info, 0, NULL, pvData, pcbData);
468                 }
469                 CryptMemFree(info.Content.pbData);
470             }
471             else
472                 ret = FALSE;
473         }
474         break;
475     }
476     case CMSG_COMPUTED_HASH_PARAM:
477         ret = CryptGetHashParam(msg->hash, HP_HASHVAL, (BYTE *)pvData, pcbData,
478          0);
479         break;
480     case CMSG_VERSION_PARAM:
481         if (msg->base.state != MsgStateFinalized)
482             SetLastError(CRYPT_E_MSG_ERROR);
483         else
484         {
485             DWORD version = CMSG_HASHED_DATA_PKCS_1_5_VERSION;
486
487             /* Since the data are always encoded as octets, the version is
488              * always 0 (see rfc3852, section 7)
489              */
490             ret = CRYPT_CopyParam(pvData, pcbData, &version, sizeof(version));
491         }
492         break;
493     default:
494         SetLastError(CRYPT_E_INVALID_MSG_TYPE);
495     }
496     return ret;
497 }
498
499 static BOOL CHashEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
500  DWORD cbData, BOOL fFinal)
501 {
502     CHashEncodeMsg *msg = (CHashEncodeMsg *)hCryptMsg;
503     BOOL ret = FALSE;
504
505     TRACE("(%p, %p, %d, %d)\n", hCryptMsg, pbData, cbData, fFinal);
506
507     if (msg->base.streamed || (msg->base.open_flags & CMSG_DETACHED_FLAG))
508     {
509         /* Doesn't do much, as stream output is never called, and you
510          * can't get the content.
511          */
512         ret = CryptHashData(msg->hash, pbData, cbData, 0);
513     }
514     else
515     {
516         if (!fFinal)
517             SetLastError(CRYPT_E_MSG_ERROR);
518         else
519         {
520             ret = CryptHashData(msg->hash, pbData, cbData, 0);
521             if (ret)
522             {
523                 msg->data.pbData = CryptMemAlloc(cbData);
524                 if (msg->data.pbData)
525                 {
526                     memcpy(msg->data.pbData + msg->data.cbData, pbData, cbData);
527                     msg->data.cbData += cbData;
528                 }
529                 else
530                     ret = FALSE;
531             }
532         }
533     }
534     return ret;
535 }
536
537 static HCRYPTMSG CHashEncodeMsg_Open(DWORD dwFlags, const void *pvMsgEncodeInfo,
538  LPSTR pszInnerContentObjID, PCMSG_STREAM_INFO pStreamInfo)
539 {
540     CHashEncodeMsg *msg;
541     const CMSG_HASHED_ENCODE_INFO *info =
542      (const CMSG_HASHED_ENCODE_INFO *)pvMsgEncodeInfo;
543     HCRYPTPROV prov;
544     ALG_ID algID;
545
546     if (info->cbSize != sizeof(CMSG_HASHED_ENCODE_INFO))
547     {
548         SetLastError(E_INVALIDARG);
549         return NULL;
550     }
551     if (!(algID = CertOIDToAlgId(info->HashAlgorithm.pszObjId)))
552     {
553         SetLastError(CRYPT_E_UNKNOWN_ALGO);
554         return NULL;
555     }
556     if (info->hCryptProv)
557         prov = info->hCryptProv;
558     else
559     {
560         prov = CRYPT_GetDefaultProvider();
561         dwFlags &= ~CMSG_CRYPT_RELEASE_CONTEXT_FLAG;
562     }
563     msg = CryptMemAlloc(sizeof(CHashEncodeMsg));
564     if (msg)
565     {
566         CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo,
567          CHashEncodeMsg_Close, CHashEncodeMsg_GetParam, CHashEncodeMsg_Update,
568          CRYPT_DefaultMsgControl);
569         msg->prov = prov;
570         msg->data.cbData = 0;
571         msg->data.pbData = NULL;
572         if (!CryptCreateHash(prov, algID, 0, 0, &msg->hash))
573         {
574             CryptMsgClose(msg);
575             msg = NULL;
576         }
577     }
578     return (HCRYPTMSG)msg;
579 }
580
581 typedef struct _CMSG_SIGNER_ENCODE_INFO_WITH_CMS
582 {
583     DWORD                      cbSize;
584     PCERT_INFO                 pCertInfo;
585     HCRYPTPROV                 hCryptProv;
586     DWORD                      dwKeySpec;
587     CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm;
588     void                      *pvHashAuxInfo;
589     DWORD                      cAuthAttr;
590     PCRYPT_ATTRIBUTE           rgAuthAttr;
591     DWORD                      cUnauthAttr;
592     PCRYPT_ATTRIBUTE           rgUnauthAttr;
593     CERT_ID                    SignerId;
594     CRYPT_ALGORITHM_IDENTIFIER HashEncryptionAlgorithm;
595     void                      *pvHashEncryptionAuxInfo;
596 } CMSG_SIGNER_ENCODE_INFO_WITH_CMS, *PCMSG_SIGNER_ENCODE_INFO_WITH_CMS;
597
598 typedef struct _CMSG_SIGNED_ENCODE_INFO_WITH_CMS
599 {
600     DWORD                             cbSize;
601     DWORD                             cSigners;
602     PCMSG_SIGNER_ENCODE_INFO_WITH_CMS rgSigners;
603     DWORD                             cCertEncoded;
604     PCERT_BLOB                        rgCertEncoded;
605     DWORD                             cCrlEncoded;
606     PCRL_BLOB                         rgCrlEncoded;
607     DWORD                             cAttrCertEncoded;
608     PCERT_BLOB                        rgAttrCertEncoded;
609 } CMSG_SIGNED_ENCODE_INFO_WITH_CMS, *PCMSG_SIGNED_ENCODE_INFO_WITH_CMS;
610
611 static BOOL CRYPT_IsValidSigner(CMSG_SIGNER_ENCODE_INFO_WITH_CMS *signer)
612 {
613     if (signer->cbSize != sizeof(CMSG_SIGNER_ENCODE_INFO) &&
614      signer->cbSize != sizeof(CMSG_SIGNER_ENCODE_INFO_WITH_CMS))
615     {
616         SetLastError(E_INVALIDARG);
617         return FALSE;
618     }
619     if (signer->cbSize == sizeof(CMSG_SIGNER_ENCODE_INFO_WITH_CMS))
620     {
621         FIXME("CMSG_SIGNER_ENCODE_INFO with CMS fields unsupported\n");
622         return FALSE;
623     }
624     if (!signer->pCertInfo->SerialNumber.cbData)
625     {
626         SetLastError(E_INVALIDARG);
627         return FALSE;
628     }
629     if (!signer->pCertInfo->Issuer.cbData)
630     {
631         SetLastError(E_INVALIDARG);
632         return FALSE;
633     }
634     if (!signer->hCryptProv)
635     {
636         SetLastError(E_INVALIDARG);
637         return FALSE;
638     }
639     if (!CertOIDToAlgId(signer->HashAlgorithm.pszObjId))
640     {
641         SetLastError(CRYPT_E_UNKNOWN_ALGO);
642         return FALSE;
643     }
644     return TRUE;
645 }
646
647 static BOOL CRYPT_ConstructBlob(CRYPT_DATA_BLOB *out, const CRYPT_DATA_BLOB *in)
648 {
649     BOOL ret = TRUE;
650
651     out->cbData = in->cbData;
652     if (out->cbData)
653     {
654         out->pbData = CryptMemAlloc(out->cbData);
655         if (out->pbData)
656             memcpy(out->pbData, in->pbData, out->cbData);
657         else
658             ret = FALSE;
659     }
660     else
661         out->pbData = NULL;
662     return ret;
663 }
664
665 typedef struct _BlobArray
666 {
667     DWORD            cBlobs;
668     PCRYPT_DATA_BLOB blobs;
669 } BlobArray;
670
671 static BOOL CRYPT_ConstructBlobArray(BlobArray *out, const BlobArray *in)
672 {
673     BOOL ret = TRUE;
674
675     out->cBlobs = in->cBlobs;
676     if (out->cBlobs)
677     {
678         out->blobs = CryptMemAlloc(out->cBlobs * sizeof(CRYPT_DATA_BLOB));
679         if (out->blobs)
680         {
681             DWORD i;
682
683             memset(out->blobs, 0, out->cBlobs * sizeof(CRYPT_DATA_BLOB));
684             for (i = 0; ret && i < out->cBlobs; i++)
685                 ret = CRYPT_ConstructBlob(&out->blobs[i], &in->blobs[i]);
686         }
687         else
688             ret = FALSE;
689     }
690     return ret;
691 }
692
693 static void CRYPT_FreeBlobArray(BlobArray *array)
694 {
695     DWORD i;
696
697     for (i = 0; i < array->cBlobs; i++)
698         CryptMemFree(array->blobs[i].pbData);
699     CryptMemFree(array->blobs);
700 }
701
702 static BOOL CRYPT_ConstructAttribute(CRYPT_ATTRIBUTE *out,
703  const CRYPT_ATTRIBUTE *in)
704 {
705     BOOL ret;
706
707     out->pszObjId = CryptMemAlloc(strlen(in->pszObjId) + 1);
708     if (out->pszObjId)
709     {
710         strcpy(out->pszObjId, in->pszObjId);
711         ret = CRYPT_ConstructBlobArray((BlobArray *)&out->cValue,
712          (const BlobArray *)&in->cValue);
713     }
714     else
715         ret = FALSE;
716     return ret;
717 }
718
719 static BOOL CRYPT_ConstructAttributes(CRYPT_ATTRIBUTES *out,
720  const CRYPT_ATTRIBUTES *in)
721 {
722     BOOL ret = TRUE;
723
724     out->cAttr = in->cAttr;
725     if (out->cAttr)
726     {
727         out->rgAttr = CryptMemAlloc(out->cAttr * sizeof(CRYPT_ATTRIBUTE));
728         if (out->rgAttr)
729         {
730             DWORD i;
731
732             memset(out->rgAttr, 0, out->cAttr * sizeof(CRYPT_ATTRIBUTE));
733             for (i = 0; ret && i < out->cAttr; i++)
734                 ret = CRYPT_ConstructAttribute(&out->rgAttr[i], &in->rgAttr[i]);
735         }
736         else
737             ret = FALSE;
738     }
739     else
740         out->rgAttr = NULL;
741     return ret;
742 }
743
744 /* Constructs a CMSG_SIGNER_INFO from a CMSG_SIGNER_ENCODE_INFO_WITH_CMS. */
745 static BOOL CSignerInfo_Construct(CMSG_SIGNER_INFO *info,
746  CMSG_SIGNER_ENCODE_INFO_WITH_CMS *in)
747 {
748     BOOL ret;
749
750     /* Note: needs to change if CMS fields are supported */
751     info->dwVersion = CMSG_SIGNER_INFO_V1;
752     ret = CRYPT_ConstructBlob(&info->Issuer, &in->pCertInfo->Issuer);
753     if (ret)
754         ret = CRYPT_ConstructBlob(&info->SerialNumber,
755          &in->pCertInfo->SerialNumber);
756     /* Assumption:  algorithm IDs will point to static strings, not
757      * stack-based ones, so copying the pointer values is safe.
758      */
759     info->HashAlgorithm.pszObjId = in->HashAlgorithm.pszObjId;
760     if (ret)
761         ret = CRYPT_ConstructBlob(&info->HashAlgorithm.Parameters,
762          &in->HashAlgorithm.Parameters);
763     memset(&info->HashEncryptionAlgorithm, 0,
764      sizeof(info->HashEncryptionAlgorithm));
765     if (ret)
766         ret = CRYPT_ConstructAttributes(&info->AuthAttrs,
767          (CRYPT_ATTRIBUTES *)&in->cAuthAttr);
768     if (ret)
769         ret = CRYPT_ConstructAttributes(&info->UnauthAttrs,
770          (CRYPT_ATTRIBUTES *)&in->cUnauthAttr);
771     return ret;
772 }
773
774 static void CSignerInfo_Free(CMSG_SIGNER_INFO *info)
775 {
776     DWORD i, j;
777
778     CryptMemFree(info->Issuer.pbData);
779     CryptMemFree(info->SerialNumber.pbData);
780     CryptMemFree(info->HashAlgorithm.Parameters.pbData);
781     CryptMemFree(info->EncryptedHash.pbData);
782     for (i = 0; i < info->AuthAttrs.cAttr; i++)
783     {
784         for (j = 0; j < info->AuthAttrs.rgAttr[i].cValue; j++)
785             CryptMemFree(info->AuthAttrs.rgAttr[i].rgValue[j].pbData);
786         CryptMemFree(info->AuthAttrs.rgAttr[i].rgValue);
787         CryptMemFree(info->AuthAttrs.rgAttr[i].pszObjId);
788     }
789     CryptMemFree(info->AuthAttrs.rgAttr);
790     for (i = 0; i < info->UnauthAttrs.cAttr; i++)
791     {
792         for (j = 0; j < info->UnauthAttrs.rgAttr[i].cValue; j++)
793             CryptMemFree(info->UnauthAttrs.rgAttr[i].rgValue[j].pbData);
794         CryptMemFree(info->UnauthAttrs.rgAttr[i].rgValue);
795         CryptMemFree(info->UnauthAttrs.rgAttr[i].pszObjId);
796     }
797     CryptMemFree(info->UnauthAttrs.rgAttr);
798 }
799
800 typedef struct _CSignerHandles
801 {
802     HCRYPTHASH contentHash;
803     HCRYPTHASH authAttrHash;
804 } CSignerHandles;
805
806 typedef struct _CSignedMsgData
807 {
808     CRYPT_SIGNED_INFO *info;
809     DWORD              cSignerHandle;
810     CSignerHandles    *signerHandles;
811 } CSignedMsgData;
812
813 /* Constructs the signer handles for the signerIndex'th signer of msg_data.
814  * Assumes signerIndex is a valid idnex, and that msg_data's info has already
815  * been constructed.
816  */
817 static BOOL CSignedMsgData_ConstructSignerHandles(CSignedMsgData *msg_data,
818  DWORD signerIndex, HCRYPTPROV crypt_prov)
819 {
820     ALG_ID algID;
821     BOOL ret;
822
823     algID = CertOIDToAlgId(
824      msg_data->info->rgSignerInfo[signerIndex].HashAlgorithm.pszObjId);
825     ret = CryptCreateHash(crypt_prov, algID, 0, 0,
826      &msg_data->signerHandles->contentHash);
827     if (ret && msg_data->info->rgSignerInfo[signerIndex].AuthAttrs.cAttr > 0)
828         ret = CryptCreateHash(crypt_prov, algID, 0, 0,
829          &msg_data->signerHandles->authAttrHash);
830     return ret;
831 }
832
833 /* Allocates a CSignedMsgData's handles.  Assumes its info has already been
834  * constructed.
835  */
836 static BOOL CSignedMsgData_AllocateHandles(CSignedMsgData *msg_data)
837 {
838     BOOL ret = TRUE;
839
840     if (msg_data->info->cSignerInfo)
841     {
842         msg_data->signerHandles =
843          CryptMemAlloc(msg_data->info->cSignerInfo * sizeof(CSignerHandles));
844         if (msg_data->signerHandles)
845         {
846             msg_data->cSignerHandle = msg_data->info->cSignerInfo;
847             memset(msg_data->signerHandles, 0,
848              msg_data->info->cSignerInfo * sizeof(CSignerHandles));
849         }
850         else
851         {
852             msg_data->cSignerHandle = 0;
853             ret = FALSE;
854         }
855     }
856     else
857     {
858         msg_data->cSignerHandle = 0;
859         msg_data->signerHandles = NULL;
860     }
861     return ret;
862 }
863
864 static void CSignedMsgData_CloseHandles(CSignedMsgData *msg_data)
865 {
866     DWORD i;
867
868     for (i = 0; i < msg_data->cSignerHandle; i++)
869     {
870         if (msg_data->signerHandles[i].contentHash)
871             CryptDestroyHash(msg_data->signerHandles[i].contentHash);
872         if (msg_data->signerHandles[i].authAttrHash)
873             CryptDestroyHash(msg_data->signerHandles[i].authAttrHash);
874     }
875     CryptMemFree(msg_data->signerHandles);
876     msg_data->signerHandles = NULL;
877     msg_data->cSignerHandle = 0;
878 }
879
880 static BOOL CSignedMsgData_UpdateHash(CSignedMsgData *msg_data,
881  const BYTE *pbData, DWORD cbData)
882 {
883     DWORD i;
884     BOOL ret = TRUE;
885
886     for (i = 0; ret && i < msg_data->cSignerHandle; i++)
887         ret = CryptHashData(msg_data->signerHandles[i].contentHash, pbData,
888          cbData, 0);
889     return ret;
890 }
891
892 static BOOL CRYPT_AppendAttribute(CRYPT_ATTRIBUTES *out,
893  const CRYPT_ATTRIBUTE *in)
894 {
895     BOOL ret = FALSE;
896
897     out->rgAttr = CryptMemRealloc(out->rgAttr,
898      (out->cAttr + 1) * sizeof(CRYPT_ATTRIBUTE));
899     if (out->rgAttr)
900     {
901         ret = CRYPT_ConstructAttribute(&out->rgAttr[out->cAttr], in);
902         if (ret)
903             out->cAttr++;
904     }
905     return ret;
906 }
907
908 static BOOL CSignedMsgData_AppendMessageDigestAttribute(
909  CSignedMsgData *msg_data, DWORD signerIndex)
910 {
911     BOOL ret;
912     DWORD size;
913     CRYPT_HASH_BLOB hash = { 0, NULL }, encodedHash = { 0, NULL };
914     char messageDigest[] = szOID_RSA_messageDigest;
915     CRYPT_ATTRIBUTE messageDigestAttr = { messageDigest, 1, &encodedHash };
916
917     size = sizeof(DWORD);
918     ret = CryptGetHashParam(
919      msg_data->signerHandles[signerIndex].contentHash, HP_HASHSIZE,
920      (LPBYTE)&hash.cbData, &size, 0);
921     if (ret)
922     {
923         hash.pbData = CryptMemAlloc(hash.cbData);
924         ret = CryptGetHashParam(
925          msg_data->signerHandles[signerIndex].contentHash, HP_HASHVAL,
926          hash.pbData, &hash.cbData, 0);
927         if (ret)
928         {
929             ret = CRYPT_AsnEncodeOctets(0, NULL, &hash, CRYPT_ENCODE_ALLOC_FLAG,
930              NULL, (LPBYTE)&encodedHash.pbData, &encodedHash.cbData);
931             if (ret)
932             {
933                 ret = CRYPT_AppendAttribute(
934                  &msg_data->info->rgSignerInfo[signerIndex].AuthAttrs,
935                  &messageDigestAttr);
936                 LocalFree(encodedHash.pbData);
937             }
938         }
939         CryptMemFree(hash.pbData);
940     }
941     return ret;
942 }
943
944 typedef enum {
945     Sign,
946     Verify
947 } SignOrVerify;
948
949 static BOOL CSignedMsgData_UpdateAuthenticatedAttributes(
950  CSignedMsgData *msg_data, SignOrVerify flag)
951 {
952     DWORD i;
953     BOOL ret = TRUE;
954
955     TRACE("(%p)\n", msg_data);
956
957     for (i = 0; ret && i < msg_data->info->cSignerInfo; i++)
958     {
959         if (msg_data->info->rgSignerInfo[i].AuthAttrs.cAttr)
960         {
961             if (flag == Sign)
962             {
963                 BYTE oid_rsa_data_encoded[] = { 0x06,0x09,0x2a,0x86,0x48,0x86,
964                  0xf7,0x0d,0x01,0x07,0x01 };
965                 CRYPT_DATA_BLOB content = { sizeof(oid_rsa_data_encoded),
966                  oid_rsa_data_encoded };
967                 char contentType[] = szOID_RSA_contentType;
968                 CRYPT_ATTRIBUTE contentTypeAttr = { contentType, 1, &content };
969
970                 /* FIXME: does this depend on inner OID? */
971                 ret = CRYPT_AppendAttribute(
972                  &msg_data->info->rgSignerInfo[i].AuthAttrs, &contentTypeAttr);
973                 if (ret)
974                     ret = CSignedMsgData_AppendMessageDigestAttribute(msg_data,
975                      i);
976             }
977             if (ret)
978             {
979                 LPBYTE encodedAttrs;
980                 DWORD size;
981
982                 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, PKCS_ATTRIBUTES,
983                  &msg_data->info->rgSignerInfo[i].AuthAttrs,
984                  CRYPT_ENCODE_ALLOC_FLAG, NULL, (LPBYTE)&encodedAttrs, &size);
985                 if (ret)
986                 {
987                     ret = CryptHashData(
988                      msg_data->signerHandles[i].authAttrHash, encodedAttrs,
989                      size, 0);
990                     LocalFree(encodedAttrs);
991                 }
992             }
993         }
994     }
995     TRACE("returning %d\n", ret);
996     return ret;
997 }
998
999 static void CRYPT_ReverseBytes(CRYPT_HASH_BLOB *hash)
1000 {
1001     DWORD i;
1002     BYTE tmp;
1003
1004     for (i = 0; i < hash->cbData / 2; i++)
1005     {
1006         tmp = hash->pbData[hash->cbData - i - 1];
1007         hash->pbData[hash->cbData - i - 1] = hash->pbData[i];
1008         hash->pbData[i] = tmp;
1009     }
1010 }
1011
1012 static BOOL CSignedMsgData_Sign(CSignedMsgData *msg_data)
1013 {
1014     DWORD i;
1015     BOOL ret = TRUE;
1016
1017     TRACE("(%p)\n", msg_data);
1018
1019     for (i = 0; ret && i < msg_data->info->cSignerInfo; i++)
1020     {
1021         HCRYPTHASH hash;
1022
1023         if (msg_data->info->rgSignerInfo[i].AuthAttrs.cAttr)
1024             hash = msg_data->signerHandles[i].authAttrHash;
1025         else
1026             hash = msg_data->signerHandles[i].contentHash;
1027         ret = CryptSignHashW(hash, AT_SIGNATURE, NULL, 0, NULL,
1028          &msg_data->info->rgSignerInfo[i].EncryptedHash.cbData);
1029         if (ret)
1030         {
1031             msg_data->info->rgSignerInfo[i].EncryptedHash.pbData =
1032              CryptMemAlloc(
1033              msg_data->info->rgSignerInfo[i].EncryptedHash.cbData);
1034             if (msg_data->info->rgSignerInfo[i].EncryptedHash.pbData)
1035             {
1036                 ret = CryptSignHashW(hash, AT_SIGNATURE, NULL, 0,
1037                  msg_data->info->rgSignerInfo[i].EncryptedHash.pbData,
1038                  &msg_data->info->rgSignerInfo[i].EncryptedHash.cbData);
1039                 if (ret)
1040                     CRYPT_ReverseBytes(
1041                      &msg_data->info->rgSignerInfo[i].EncryptedHash);
1042             }
1043             else
1044                 ret = FALSE;
1045         }
1046     }
1047     return ret;
1048 }
1049
1050 static BOOL CSignedMsgData_Update(CSignedMsgData *msg_data,
1051  const BYTE *pbData, DWORD cbData, BOOL fFinal, SignOrVerify flag)
1052 {
1053     BOOL ret = CSignedMsgData_UpdateHash(msg_data, pbData, cbData);
1054
1055     if (ret && fFinal)
1056     {
1057         ret = CSignedMsgData_UpdateAuthenticatedAttributes(msg_data, flag);
1058         if (ret && flag == Sign)
1059             ret = CSignedMsgData_Sign(msg_data);
1060     }
1061     return ret;
1062 }
1063
1064 typedef struct _CSignedEncodeMsg
1065 {
1066     CryptMsgBase    base;
1067     CRYPT_DATA_BLOB data;
1068     CSignedMsgData  msg_data;
1069 } CSignedEncodeMsg;
1070
1071 static void CSignedEncodeMsg_Close(HCRYPTMSG hCryptMsg)
1072 {
1073     CSignedEncodeMsg *msg = (CSignedEncodeMsg *)hCryptMsg;
1074     DWORD i;
1075
1076     CryptMemFree(msg->data.pbData);
1077     CRYPT_FreeBlobArray((BlobArray *)&msg->msg_data.info->cCertEncoded);
1078     CRYPT_FreeBlobArray((BlobArray *)&msg->msg_data.info->cCrlEncoded);
1079     for (i = 0; i < msg->msg_data.info->cSignerInfo; i++)
1080         CSignerInfo_Free(&msg->msg_data.info->rgSignerInfo[i]);
1081     CSignedMsgData_CloseHandles(&msg->msg_data);
1082     CryptMemFree(msg->msg_data.info->rgSignerInfo);
1083     CryptMemFree(msg->msg_data.info);
1084 }
1085
1086 static BOOL CSignedEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
1087  DWORD dwIndex, void *pvData, DWORD *pcbData)
1088 {
1089     CSignedEncodeMsg *msg = (CSignedEncodeMsg *)hCryptMsg;
1090     BOOL ret = FALSE;
1091
1092     switch (dwParamType)
1093     {
1094     case CMSG_CONTENT_PARAM:
1095     {
1096         CRYPT_CONTENT_INFO info;
1097
1098         ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0, NULL,
1099          &info.Content.cbData);
1100         if (ret)
1101         {
1102             info.Content.pbData = CryptMemAlloc(info.Content.cbData);
1103             if (info.Content.pbData)
1104             {
1105                 ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0,
1106                  info.Content.pbData, &info.Content.cbData);
1107                 if (ret)
1108                 {
1109                     char oid_rsa_signed[] = szOID_RSA_signedData;
1110
1111                     info.pszObjId = oid_rsa_signed;
1112                     ret = CryptEncodeObjectEx(X509_ASN_ENCODING,
1113                      PKCS_CONTENT_INFO, &info, 0, NULL, pvData, pcbData);
1114                 }
1115                 CryptMemFree(info.Content.pbData);
1116             }
1117             else
1118                 ret = FALSE;
1119         }
1120         break;
1121     }
1122     case CMSG_BARE_CONTENT_PARAM:
1123     {
1124         CRYPT_SIGNED_INFO info;
1125         char oid_rsa_data[] = szOID_RSA_data;
1126
1127         info = *msg->msg_data.info;
1128         /* Quirk:  OID is only encoded messages if an update has happened */
1129         if (msg->base.state != MsgStateInit)
1130             info.content.pszObjId = oid_rsa_data;
1131         else
1132             info.content.pszObjId = NULL;
1133         if (msg->data.cbData)
1134         {
1135             CRYPT_DATA_BLOB blob = { msg->data.cbData, msg->data.pbData };
1136
1137             ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING,
1138              &blob, CRYPT_ENCODE_ALLOC_FLAG, NULL,
1139              &info.content.Content.pbData, &info.content.Content.cbData);
1140         }
1141         else
1142         {
1143             info.content.Content.cbData = 0;
1144             info.content.Content.pbData = NULL;
1145             ret = TRUE;
1146         }
1147         if (ret)
1148         {
1149             ret = CRYPT_AsnEncodePKCSSignedInfo(&info, pvData, pcbData);
1150             LocalFree(info.content.Content.pbData);
1151         }
1152         break;
1153     }
1154     case CMSG_COMPUTED_HASH_PARAM:
1155         if (dwIndex >= msg->msg_data.cSignerHandle)
1156             SetLastError(CRYPT_E_INVALID_INDEX);
1157         else
1158             ret = CryptGetHashParam(
1159              msg->msg_data.signerHandles[dwIndex].contentHash, HP_HASHVAL,
1160              pvData, pcbData, 0);
1161         break;
1162     case CMSG_ENCODED_SIGNER:
1163         if (dwIndex >= msg->msg_data.info->cSignerInfo)
1164             SetLastError(CRYPT_E_INVALID_INDEX);
1165         else
1166             ret = CryptEncodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
1167              PKCS7_SIGNER_INFO, &msg->msg_data.info->rgSignerInfo[dwIndex], 0,
1168              NULL, pvData, pcbData);
1169         break;
1170     case CMSG_VERSION_PARAM:
1171         ret = CRYPT_CopyParam(pvData, pcbData, &msg->msg_data.info->version,
1172          sizeof(msg->msg_data.info->version));
1173         break;
1174     default:
1175         SetLastError(CRYPT_E_INVALID_MSG_TYPE);
1176     }
1177     return ret;
1178 }
1179
1180 static BOOL CSignedEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
1181  DWORD cbData, BOOL fFinal)
1182 {
1183     CSignedEncodeMsg *msg = (CSignedEncodeMsg *)hCryptMsg;
1184     BOOL ret = FALSE;
1185
1186     if (msg->base.streamed || (msg->base.open_flags & CMSG_DETACHED_FLAG))
1187     {
1188         ret = CSignedMsgData_Update(&msg->msg_data, pbData, cbData, fFinal,
1189          Sign);
1190         if (msg->base.streamed)
1191             FIXME("streamed partial stub\n");
1192     }
1193     else
1194     {
1195         if (!fFinal)
1196             SetLastError(CRYPT_E_MSG_ERROR);
1197         else
1198         {
1199             if (cbData)
1200             {
1201                 msg->data.pbData = CryptMemAlloc(cbData);
1202                 if (msg->data.pbData)
1203                 {
1204                     memcpy(msg->data.pbData, pbData, cbData);
1205                     msg->data.cbData = cbData;
1206                     ret = TRUE;
1207                 }
1208             }
1209             else
1210                 ret = TRUE;
1211             if (ret)
1212                 ret = CSignedMsgData_Update(&msg->msg_data, pbData, cbData,
1213                  fFinal, Sign);
1214         }
1215     }
1216     return ret;
1217 }
1218
1219 static HCRYPTMSG CSignedEncodeMsg_Open(DWORD dwFlags,
1220  const void *pvMsgEncodeInfo, LPSTR pszInnerContentObjID,
1221  PCMSG_STREAM_INFO pStreamInfo)
1222 {
1223     const CMSG_SIGNED_ENCODE_INFO_WITH_CMS *info =
1224      (const CMSG_SIGNED_ENCODE_INFO_WITH_CMS *)pvMsgEncodeInfo;
1225     DWORD i;
1226     CSignedEncodeMsg *msg;
1227
1228     if (info->cbSize != sizeof(CMSG_SIGNED_ENCODE_INFO) &&
1229      info->cbSize != sizeof(CMSG_SIGNED_ENCODE_INFO_WITH_CMS))
1230     {
1231         SetLastError(E_INVALIDARG);
1232         return NULL;
1233     }
1234     if (info->cbSize == sizeof(CMSG_SIGNED_ENCODE_INFO_WITH_CMS))
1235     {
1236         FIXME("CMSG_SIGNED_ENCODE_INFO with CMS fields unsupported\n");
1237         return NULL;
1238     }
1239     for (i = 0; i < info->cSigners; i++)
1240         if (!CRYPT_IsValidSigner(&info->rgSigners[i]))
1241             return NULL;
1242     msg = CryptMemAlloc(sizeof(CSignedEncodeMsg));
1243     if (msg)
1244     {
1245         BOOL ret = TRUE;
1246
1247         CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo,
1248          CSignedEncodeMsg_Close, CSignedEncodeMsg_GetParam,
1249          CSignedEncodeMsg_Update, CRYPT_DefaultMsgControl);
1250         msg->data.cbData = 0;
1251         msg->data.pbData = NULL;
1252         msg->msg_data.info = CryptMemAlloc(sizeof(CRYPT_SIGNED_INFO));
1253         if (msg->msg_data.info)
1254         {
1255             memset(msg->msg_data.info, 0, sizeof(CRYPT_SIGNED_INFO));
1256             msg->msg_data.info->version = CMSG_SIGNED_DATA_V1;
1257         }
1258         else
1259             ret = FALSE;
1260         if (ret)
1261         {
1262             if (info->cSigners)
1263             {
1264                 msg->msg_data.info->rgSignerInfo =
1265                  CryptMemAlloc(info->cSigners * sizeof(CMSG_SIGNER_INFO));
1266                 if (msg->msg_data.info->rgSignerInfo)
1267                 {
1268                     msg->msg_data.info->cSignerInfo = info->cSigners;
1269                     memset(msg->msg_data.info->rgSignerInfo, 0,
1270                      msg->msg_data.info->cSignerInfo * sizeof(CMSG_SIGNER_INFO));
1271                     ret = CSignedMsgData_AllocateHandles(&msg->msg_data);
1272                     for (i = 0; ret && i < msg->msg_data.info->cSignerInfo; i++)
1273                     {
1274                         ret = CSignerInfo_Construct(
1275                          &msg->msg_data.info->rgSignerInfo[i],
1276                          &info->rgSigners[i]);
1277                         if (ret)
1278                         {
1279                             ret = CSignedMsgData_ConstructSignerHandles(
1280                              &msg->msg_data, i, info->rgSigners[i].hCryptProv);
1281                             if (dwFlags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG)
1282                                 CryptReleaseContext(info->rgSigners[i].hCryptProv,
1283                                  0);
1284                         }
1285                     }
1286                 }
1287                 else
1288                     ret = FALSE;
1289             }
1290             else
1291             {
1292                 msg->msg_data.info->cSignerInfo = 0;
1293                 msg->msg_data.signerHandles = NULL;
1294                 msg->msg_data.cSignerHandle = 0;
1295             }
1296         }
1297         if (ret)
1298             ret = CRYPT_ConstructBlobArray(
1299              (BlobArray *)&msg->msg_data.info->cCertEncoded,
1300              (const BlobArray *)&info->cCertEncoded);
1301         if (ret)
1302             ret = CRYPT_ConstructBlobArray(
1303              (BlobArray *)&msg->msg_data.info->cCrlEncoded,
1304              (const BlobArray *)&info->cCrlEncoded);
1305         if (!ret)
1306         {
1307             CSignedEncodeMsg_Close(msg);
1308             msg = NULL;
1309         }
1310     }
1311     return msg;
1312 }
1313
1314 static inline const char *MSG_TYPE_STR(DWORD type)
1315 {
1316     switch (type)
1317     {
1318 #define _x(x) case (x): return #x
1319         _x(CMSG_DATA);
1320         _x(CMSG_SIGNED);
1321         _x(CMSG_ENVELOPED);
1322         _x(CMSG_SIGNED_AND_ENVELOPED);
1323         _x(CMSG_HASHED);
1324         _x(CMSG_ENCRYPTED);
1325 #undef _x
1326         default:
1327             return wine_dbg_sprintf("unknown (%d)", type);
1328     }
1329 }
1330
1331 HCRYPTMSG WINAPI CryptMsgOpenToEncode(DWORD dwMsgEncodingType, DWORD dwFlags,
1332  DWORD dwMsgType, const void *pvMsgEncodeInfo, LPSTR pszInnerContentObjID,
1333  PCMSG_STREAM_INFO pStreamInfo)
1334 {
1335     HCRYPTMSG msg = NULL;
1336
1337     TRACE("(%08x, %08x, %08x, %p, %s, %p)\n", dwMsgEncodingType, dwFlags,
1338      dwMsgType, pvMsgEncodeInfo, debugstr_a(pszInnerContentObjID), pStreamInfo);
1339
1340     if (GET_CMSG_ENCODING_TYPE(dwMsgEncodingType) != PKCS_7_ASN_ENCODING)
1341     {
1342         SetLastError(E_INVALIDARG);
1343         return NULL;
1344     }
1345     switch (dwMsgType)
1346     {
1347     case CMSG_DATA:
1348         msg = CDataEncodeMsg_Open(dwFlags, pvMsgEncodeInfo,
1349          pszInnerContentObjID, pStreamInfo);
1350         break;
1351     case CMSG_HASHED:
1352         msg = CHashEncodeMsg_Open(dwFlags, pvMsgEncodeInfo,
1353          pszInnerContentObjID, pStreamInfo);
1354         break;
1355     case CMSG_SIGNED:
1356         msg = CSignedEncodeMsg_Open(dwFlags, pvMsgEncodeInfo,
1357          pszInnerContentObjID, pStreamInfo);
1358         break;
1359     case CMSG_ENVELOPED:
1360         FIXME("unimplemented for type %s\n", MSG_TYPE_STR(dwMsgType));
1361         break;
1362     case CMSG_SIGNED_AND_ENVELOPED:
1363     case CMSG_ENCRYPTED:
1364         /* defined but invalid, fall through */
1365     default:
1366         SetLastError(CRYPT_E_INVALID_MSG_TYPE);
1367     }
1368     return msg;
1369 }
1370
1371 typedef struct _CDecodeMsg
1372 {
1373     CryptMsgBase           base;
1374     DWORD                  type;
1375     HCRYPTPROV             crypt_prov;
1376     union {
1377         HCRYPTHASH     hash;
1378         CSignedMsgData signed_data;
1379     } u;
1380     CRYPT_DATA_BLOB        msg_data;
1381     PCONTEXT_PROPERTY_LIST properties;
1382 } CDecodeMsg;
1383
1384 static void CDecodeMsg_Close(HCRYPTMSG hCryptMsg)
1385 {
1386     CDecodeMsg *msg = (CDecodeMsg *)hCryptMsg;
1387
1388     if (msg->base.open_flags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG)
1389         CryptReleaseContext(msg->crypt_prov, 0);
1390     switch (msg->type)
1391     {
1392     case CMSG_HASHED:
1393         if (msg->u.hash)
1394             CryptDestroyHash(msg->u.hash);
1395         break;
1396     case CMSG_SIGNED:
1397         if (msg->u.signed_data.info)
1398         {
1399             LocalFree(msg->u.signed_data.info);
1400             CSignedMsgData_CloseHandles(&msg->u.signed_data);
1401         }
1402         break;
1403     }
1404     CryptMemFree(msg->msg_data.pbData);
1405     ContextPropertyList_Free(msg->properties);
1406 }
1407
1408 static BOOL CDecodeMsg_CopyData(CDecodeMsg *msg, const BYTE *pbData,
1409  DWORD cbData)
1410 {
1411     BOOL ret = TRUE;
1412
1413     if (cbData)
1414     {
1415         if (msg->msg_data.cbData)
1416             msg->msg_data.pbData = CryptMemRealloc(msg->msg_data.pbData,
1417              msg->msg_data.cbData + cbData);
1418         else
1419             msg->msg_data.pbData = CryptMemAlloc(cbData);
1420         if (msg->msg_data.pbData)
1421         {
1422             memcpy(msg->msg_data.pbData + msg->msg_data.cbData, pbData, cbData);
1423             msg->msg_data.cbData += cbData;
1424         }
1425         else
1426             ret = FALSE;
1427     }
1428     return ret;
1429 }
1430
1431 static BOOL CDecodeMsg_DecodeDataContent(CDecodeMsg *msg, CRYPT_DER_BLOB *blob)
1432 {
1433     BOOL ret;
1434     CRYPT_DATA_BLOB *data;
1435     DWORD size;
1436
1437     ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING,
1438      blob->pbData, blob->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, (LPBYTE)&data,
1439      &size);
1440     if (ret)
1441     {
1442         ret = ContextPropertyList_SetProperty(msg->properties,
1443          CMSG_CONTENT_PARAM, data->pbData, data->cbData);
1444         LocalFree(data);
1445     }
1446     return ret;
1447 }
1448
1449 static void CDecodeMsg_SaveAlgorithmID(CDecodeMsg *msg, DWORD param,
1450  const CRYPT_ALGORITHM_IDENTIFIER *id)
1451 {
1452     static const BYTE nullParams[] = { ASN_NULL, 0 };
1453     CRYPT_ALGORITHM_IDENTIFIER *copy;
1454     DWORD len = sizeof(CRYPT_ALGORITHM_IDENTIFIER);
1455
1456     /* Linearize algorithm id */
1457     len += strlen(id->pszObjId) + 1;
1458     len += id->Parameters.cbData;
1459     copy = CryptMemAlloc(len);
1460     if (copy)
1461     {
1462         copy->pszObjId =
1463          (LPSTR)((BYTE *)copy + sizeof(CRYPT_ALGORITHM_IDENTIFIER));
1464         strcpy(copy->pszObjId, id->pszObjId);
1465         copy->Parameters.pbData = (BYTE *)copy->pszObjId + strlen(id->pszObjId)
1466          + 1;
1467         /* Trick:  omit NULL parameters */
1468         if (id->Parameters.cbData == sizeof(nullParams) &&
1469          !memcmp(id->Parameters.pbData, nullParams, sizeof(nullParams)))
1470         {
1471             copy->Parameters.cbData = 0;
1472             len -= sizeof(nullParams);
1473         }
1474         else
1475             copy->Parameters.cbData = id->Parameters.cbData;
1476         if (copy->Parameters.cbData)
1477             memcpy(copy->Parameters.pbData, id->Parameters.pbData,
1478              id->Parameters.cbData);
1479         ContextPropertyList_SetProperty(msg->properties, param, (BYTE *)copy,
1480          len);
1481         CryptMemFree(copy);
1482     }
1483 }
1484
1485 static inline void CRYPT_FixUpAlgorithmID(CRYPT_ALGORITHM_IDENTIFIER *id)
1486 {
1487     id->pszObjId = (LPSTR)((BYTE *)id + sizeof(CRYPT_ALGORITHM_IDENTIFIER));
1488     id->Parameters.pbData = (BYTE *)id->pszObjId + strlen(id->pszObjId) + 1;
1489 }
1490
1491 static BOOL CDecodeMsg_DecodeHashedContent(CDecodeMsg *msg,
1492  CRYPT_DER_BLOB *blob)
1493 {
1494     BOOL ret;
1495     CRYPT_DIGESTED_DATA *digestedData;
1496     DWORD size;
1497
1498     ret = CRYPT_AsnDecodePKCSDigestedData(blob->pbData, blob->cbData,
1499      CRYPT_DECODE_ALLOC_FLAG, NULL, (CRYPT_DIGESTED_DATA *)&digestedData,
1500      &size);
1501     if (ret)
1502     {
1503         ContextPropertyList_SetProperty(msg->properties, CMSG_VERSION_PARAM,
1504          (const BYTE *)&digestedData->version, sizeof(digestedData->version));
1505         CDecodeMsg_SaveAlgorithmID(msg, CMSG_HASH_ALGORITHM_PARAM,
1506          &digestedData->DigestAlgorithm);
1507         ContextPropertyList_SetProperty(msg->properties,
1508          CMSG_INNER_CONTENT_TYPE_PARAM,
1509          (const BYTE *)digestedData->ContentInfo.pszObjId,
1510          digestedData->ContentInfo.pszObjId ?
1511          strlen(digestedData->ContentInfo.pszObjId) + 1 : 0);
1512         if (digestedData->ContentInfo.Content.cbData)
1513             CDecodeMsg_DecodeDataContent(msg,
1514              &digestedData->ContentInfo.Content);
1515         else
1516             ContextPropertyList_SetProperty(msg->properties,
1517              CMSG_CONTENT_PARAM, NULL, 0);
1518         ContextPropertyList_SetProperty(msg->properties, CMSG_HASH_DATA_PARAM,
1519          digestedData->hash.pbData, digestedData->hash.cbData);
1520         LocalFree(digestedData);
1521     }
1522     return ret;
1523 }
1524
1525 static BOOL CDecodeMsg_DecodeSignedContent(CDecodeMsg *msg,
1526  CRYPT_DER_BLOB *blob)
1527 {
1528     BOOL ret;
1529     CRYPT_SIGNED_INFO *signedInfo;
1530     DWORD size;
1531
1532     ret = CRYPT_AsnDecodePKCSSignedInfo(blob->pbData, blob->cbData,
1533      CRYPT_DECODE_ALLOC_FLAG, NULL, (CRYPT_SIGNED_INFO *)&signedInfo,
1534      &size);
1535     if (ret)
1536     {
1537         DWORD i;
1538
1539         msg->u.signed_data.info = signedInfo;
1540         ret = CSignedMsgData_AllocateHandles(&msg->u.signed_data);
1541         for (i = 0; ret && i < msg->u.signed_data.info->cSignerInfo; i++)
1542             ret = CSignedMsgData_ConstructSignerHandles(&msg->u.signed_data, i,
1543              msg->crypt_prov);
1544         if (ret)
1545         {
1546             /* Now that we have all the content, update the hash handles with
1547              * it.  Have to decode it if the type is szOID_RSA_data.
1548              */
1549             if (msg->u.signed_data.info->content.Content.cbData)
1550             {
1551                 if (!strcmp(msg->u.signed_data.info->content.pszObjId,
1552                  szOID_RSA_data))
1553                 {
1554                     CRYPT_DATA_BLOB *blob;
1555
1556                     ret = CryptDecodeObjectEx(X509_ASN_ENCODING,
1557                      X509_OCTET_STRING,
1558                      msg->u.signed_data.info->content.Content.pbData,
1559                      msg->u.signed_data.info->content.Content.cbData,
1560                      CRYPT_DECODE_ALLOC_FLAG, NULL, (LPBYTE)&blob, &size);
1561                     if (ret)
1562                     {
1563                         ret = CSignedMsgData_Update(&msg->u.signed_data,
1564                          blob->pbData, blob->cbData, TRUE, Verify);
1565                         LocalFree(blob);
1566                     }
1567                 }
1568                 else
1569                     ret = CSignedMsgData_Update(&msg->u.signed_data,
1570                      msg->u.signed_data.info->content.Content.pbData,
1571                      msg->u.signed_data.info->content.Content.cbData, TRUE,
1572                      Verify);
1573             }
1574         }
1575     }
1576     return ret;
1577 }
1578 /* Decodes the content in blob as the type given, and updates the value
1579  * (type, parameters, etc.) of msg based on what blob contains.
1580  * It doesn't just use msg's type, to allow a recursive call from an implicitly
1581  * typed message once the outer content info has been decoded.
1582  */
1583 static BOOL CDecodeMsg_DecodeContent(CDecodeMsg *msg, CRYPT_DER_BLOB *blob,
1584  DWORD type)
1585 {
1586     BOOL ret;
1587
1588     switch (type)
1589     {
1590     case CMSG_DATA:
1591         if ((ret = CDecodeMsg_DecodeDataContent(msg, blob)))
1592             msg->type = CMSG_DATA;
1593         break;
1594     case CMSG_HASHED:
1595         if ((ret = CDecodeMsg_DecodeHashedContent(msg, blob)))
1596             msg->type = CMSG_HASHED;
1597         break;
1598     case CMSG_ENVELOPED:
1599         FIXME("unimplemented for type %s\n", MSG_TYPE_STR(type));
1600         ret = TRUE;
1601         break;
1602     case CMSG_SIGNED:
1603         if ((ret = CDecodeMsg_DecodeSignedContent(msg, blob)))
1604             msg->type = CMSG_SIGNED;
1605         break;
1606     default:
1607     {
1608         CRYPT_CONTENT_INFO *info;
1609         DWORD size;
1610
1611         ret = CryptDecodeObjectEx(X509_ASN_ENCODING, PKCS_CONTENT_INFO,
1612          msg->msg_data.pbData, msg->msg_data.cbData, CRYPT_DECODE_ALLOC_FLAG,
1613          NULL, (LPBYTE)&info, &size);
1614         if (ret)
1615         {
1616             if (!strcmp(info->pszObjId, szOID_RSA_data))
1617                 ret = CDecodeMsg_DecodeContent(msg, &info->Content, CMSG_DATA);
1618             else if (!strcmp(info->pszObjId, szOID_RSA_digestedData))
1619                 ret = CDecodeMsg_DecodeContent(msg, &info->Content,
1620                  CMSG_HASHED);
1621             else if (!strcmp(info->pszObjId, szOID_RSA_envelopedData))
1622                 ret = CDecodeMsg_DecodeContent(msg, &info->Content,
1623                  CMSG_ENVELOPED);
1624             else if (!strcmp(info->pszObjId, szOID_RSA_signedData))
1625                 ret = CDecodeMsg_DecodeContent(msg, &info->Content,
1626                  CMSG_SIGNED);
1627             else
1628             {
1629                 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
1630                 ret = FALSE;
1631             }
1632             LocalFree(info);
1633         }
1634     }
1635     }
1636     return ret;
1637 }
1638
1639 static BOOL CDecodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
1640  DWORD cbData, BOOL fFinal)
1641 {
1642     CDecodeMsg *msg = (CDecodeMsg *)hCryptMsg;
1643     BOOL ret = FALSE;
1644
1645     TRACE("(%p, %p, %d, %d)\n", hCryptMsg, pbData, cbData, fFinal);
1646
1647     if (msg->base.streamed)
1648     {
1649         ret = CDecodeMsg_CopyData(msg, pbData, cbData);
1650         FIXME("(%p, %p, %d, %d): streamed update stub\n", hCryptMsg, pbData,
1651          cbData, fFinal);
1652     }
1653     else
1654     {
1655         if (!fFinal)
1656             SetLastError(CRYPT_E_MSG_ERROR);
1657         else
1658         {
1659             ret = CDecodeMsg_CopyData(msg, pbData, cbData);
1660             if (ret)
1661                 ret = CDecodeMsg_DecodeContent(msg, &msg->msg_data, msg->type);
1662
1663         }
1664     }
1665     return ret;
1666 }
1667
1668 static BOOL CDecodeHashMsg_GetParam(CDecodeMsg *msg, DWORD dwParamType,
1669  DWORD dwIndex, void *pvData, DWORD *pcbData)
1670 {
1671     BOOL ret = FALSE;
1672
1673     switch (dwParamType)
1674     {
1675     case CMSG_TYPE_PARAM:
1676         ret = CRYPT_CopyParam(pvData, pcbData, &msg->type, sizeof(msg->type));
1677         break;
1678     case CMSG_HASH_ALGORITHM_PARAM:
1679     {
1680         CRYPT_DATA_BLOB blob;
1681
1682         ret = ContextPropertyList_FindProperty(msg->properties, dwParamType,
1683          &blob);
1684         if (ret)
1685         {
1686             ret = CRYPT_CopyParam(pvData, pcbData, blob.pbData, blob.cbData);
1687             if (ret && pvData)
1688                 CRYPT_FixUpAlgorithmID((CRYPT_ALGORITHM_IDENTIFIER *)pvData);
1689         }
1690         else
1691             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
1692         break;
1693     }
1694     case CMSG_COMPUTED_HASH_PARAM:
1695         if (!msg->u.hash)
1696         {
1697             CRYPT_ALGORITHM_IDENTIFIER *hashAlgoID = NULL;
1698             DWORD size = 0;
1699             ALG_ID algID = 0;
1700
1701             CryptMsgGetParam(msg, CMSG_HASH_ALGORITHM_PARAM, 0, NULL, &size);
1702             hashAlgoID = CryptMemAlloc(size);
1703             ret = CryptMsgGetParam(msg, CMSG_HASH_ALGORITHM_PARAM, 0,
1704              hashAlgoID, &size);
1705             if (ret)
1706                 algID = CertOIDToAlgId(hashAlgoID->pszObjId);
1707             ret = CryptCreateHash(msg->crypt_prov, algID, 0, 0, &msg->u.hash);
1708             if (ret)
1709             {
1710                 CRYPT_DATA_BLOB content;
1711
1712                 ret = ContextPropertyList_FindProperty(msg->properties,
1713                  CMSG_CONTENT_PARAM, &content);
1714                 if (ret)
1715                     ret = CryptHashData(msg->u.hash, content.pbData,
1716                      content.cbData, 0);
1717             }
1718             CryptMemFree(hashAlgoID);
1719         }
1720         else
1721             ret = TRUE;
1722         if (ret)
1723             ret = CryptGetHashParam(msg->u.hash, HP_HASHVAL, pvData, pcbData,
1724              0);
1725         break;
1726     default:
1727     {
1728         CRYPT_DATA_BLOB blob;
1729
1730         ret = ContextPropertyList_FindProperty(msg->properties, dwParamType,
1731          &blob);
1732         if (ret)
1733             ret = CRYPT_CopyParam(pvData, pcbData, blob.pbData, blob.cbData);
1734         else
1735             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
1736     }
1737     }
1738     return ret;
1739 }
1740
1741 /* nextData is an in/out parameter - on input it's the memory location in
1742  * which a copy of in's data should be made, and on output it's the memory
1743  * location immediately after out's copy of in's data.
1744  */
1745 static inline void CRYPT_CopyBlob(CRYPT_DATA_BLOB *out,
1746  const CRYPT_DATA_BLOB *in, LPBYTE *nextData)
1747 {
1748     out->cbData = in->cbData;
1749     if (in->cbData)
1750     {
1751         out->pbData = *nextData;
1752         memcpy(out->pbData, in->pbData, in->cbData);
1753         *nextData += in->cbData;
1754     }
1755 }
1756
1757 static inline void CRYPT_CopyAlgorithmId(CRYPT_ALGORITHM_IDENTIFIER *out,
1758  const CRYPT_ALGORITHM_IDENTIFIER *in, LPBYTE *nextData)
1759 {
1760     if (in->pszObjId)
1761     {
1762         out->pszObjId = (LPSTR)*nextData;
1763         strcpy(out->pszObjId, in->pszObjId);
1764         *nextData += strlen(out->pszObjId) + 1;
1765     }
1766     CRYPT_CopyBlob(&out->Parameters, &in->Parameters, nextData);
1767 }
1768
1769 static inline void CRYPT_CopyAttributes(CRYPT_ATTRIBUTES *out,
1770  const CRYPT_ATTRIBUTES *in, LPBYTE *nextData)
1771 {
1772     out->cAttr = in->cAttr;
1773     if (in->cAttr)
1774     {
1775         DWORD i;
1776
1777         if ((*nextData - (LPBYTE)0) % sizeof(DWORD_PTR))
1778             *nextData += (*nextData - (LPBYTE)0) % sizeof(DWORD_PTR);
1779         out->rgAttr = (CRYPT_ATTRIBUTE *)*nextData;
1780         *nextData += in->cAttr * sizeof(CRYPT_ATTRIBUTE);
1781         for (i = 0; i < in->cAttr; i++)
1782         {
1783             if (in->rgAttr[i].pszObjId)
1784             {
1785                 out->rgAttr[i].pszObjId = (LPSTR)*nextData;
1786                 strcpy(out->rgAttr[i].pszObjId, in->rgAttr[i].pszObjId);
1787                 *nextData += strlen(in->rgAttr[i].pszObjId) + 1;
1788             }
1789             if (in->rgAttr[i].cValue)
1790             {
1791                 DWORD j;
1792
1793                 out->rgAttr[i].cValue = in->rgAttr[i].cValue;
1794                 if ((*nextData - (LPBYTE)0) % sizeof(DWORD_PTR))
1795                     *nextData += (*nextData - (LPBYTE)0) % sizeof(DWORD_PTR);
1796                 out->rgAttr[i].rgValue = (PCRYPT_DATA_BLOB)*nextData;
1797                 *nextData += in->rgAttr[i].cValue * sizeof(CRYPT_DATA_BLOB);
1798                 for (j = 0; j < in->rgAttr[i].cValue; j++)
1799                     CRYPT_CopyBlob(&out->rgAttr[i].rgValue[j],
1800                      &in->rgAttr[i].rgValue[j], nextData);
1801             }
1802         }
1803     }
1804 }
1805
1806 static DWORD CRYPT_SizeOfAttributes(const CRYPT_ATTRIBUTES *attr)
1807 {
1808     DWORD size = attr->cAttr * sizeof(CRYPT_ATTRIBUTE), i, j;
1809
1810     for (i = 0; i < attr->cAttr; i++)
1811     {
1812         if (attr->rgAttr[i].pszObjId)
1813             size += strlen(attr->rgAttr[i].pszObjId) + 1;
1814         /* align pointer */
1815         if (size % sizeof(DWORD_PTR))
1816             size += size % sizeof(DWORD_PTR);
1817         size += attr->rgAttr[i].cValue * sizeof(CRYPT_DATA_BLOB);
1818         for (j = 0; j < attr->rgAttr[i].cValue; j++)
1819             size += attr->rgAttr[i].rgValue[j].cbData;
1820     }
1821     /* align pointer again to be conservative */
1822     if (size % sizeof(DWORD_PTR))
1823         size += size % sizeof(DWORD_PTR);
1824     return size;
1825 }
1826
1827 static BOOL CRYPT_CopySignerInfo(void *pvData, DWORD *pcbData,
1828  const CMSG_SIGNER_INFO *in)
1829 {
1830     DWORD size = sizeof(CMSG_SIGNER_INFO);
1831     BOOL ret;
1832
1833     TRACE("(%p, %d, %p)\n", pvData, pvData ? *pcbData : 0, in);
1834
1835     size += in->Issuer.cbData;
1836     size += in->SerialNumber.cbData;
1837     if (in->HashAlgorithm.pszObjId)
1838         size += strlen(in->HashAlgorithm.pszObjId) + 1;
1839     size += in->HashAlgorithm.Parameters.cbData;
1840     if (in->HashEncryptionAlgorithm.pszObjId)
1841         size += strlen(in->HashEncryptionAlgorithm.pszObjId) + 1;
1842     size += in->HashEncryptionAlgorithm.Parameters.cbData;
1843     size += in->EncryptedHash.cbData;
1844     /* align pointer */
1845     if (size % sizeof(DWORD_PTR))
1846         size += size % sizeof(DWORD_PTR);
1847     size += CRYPT_SizeOfAttributes(&in->AuthAttrs);
1848     size += CRYPT_SizeOfAttributes(&in->UnauthAttrs);
1849     if (!pvData)
1850     {
1851         *pcbData = size;
1852         ret = TRUE;
1853     }
1854     else if (*pcbData < size)
1855     {
1856         *pcbData = size;
1857         SetLastError(ERROR_MORE_DATA);
1858         ret = FALSE;
1859     }
1860     else
1861     {
1862         LPBYTE nextData = (BYTE *)pvData + sizeof(CMSG_SIGNER_INFO);
1863         CMSG_SIGNER_INFO *out = (CMSG_SIGNER_INFO *)pvData;
1864
1865         out->dwVersion = in->dwVersion;
1866         CRYPT_CopyBlob(&out->Issuer, &in->Issuer, &nextData);
1867         CRYPT_CopyBlob(&out->SerialNumber, &in->SerialNumber, &nextData);
1868         CRYPT_CopyAlgorithmId(&out->HashAlgorithm, &in->HashAlgorithm,
1869          &nextData);
1870         CRYPT_CopyAlgorithmId(&out->HashEncryptionAlgorithm,
1871          &in->HashEncryptionAlgorithm, &nextData);
1872         CRYPT_CopyBlob(&out->EncryptedHash, &in->EncryptedHash, &nextData);
1873         /* align pointer */
1874         if ((nextData - (LPBYTE)0) % sizeof(DWORD_PTR))
1875             nextData += (nextData - (LPBYTE)0) % sizeof(DWORD_PTR);
1876         CRYPT_CopyAttributes(&out->AuthAttrs, &in->AuthAttrs, &nextData);
1877         CRYPT_CopyAttributes(&out->UnauthAttrs, &in->UnauthAttrs, &nextData);
1878         ret = TRUE;
1879     }
1880     TRACE("returning %d\n", ret);
1881     return ret;
1882 }
1883
1884 static BOOL CRYPT_CopySignerCertInfo(void *pvData, DWORD *pcbData,
1885  const CMSG_SIGNER_INFO *in)
1886 {
1887     DWORD size = sizeof(CERT_INFO);
1888     BOOL ret;
1889
1890     TRACE("(%p, %d, %p)\n", pvData, pvData ? *pcbData : 0, in);
1891
1892     size += in->Issuer.cbData;
1893     size += in->SerialNumber.cbData;
1894     if (!pvData)
1895     {
1896         *pcbData = size;
1897         ret = TRUE;
1898     }
1899     else if (*pcbData < size)
1900     {
1901         *pcbData = size;
1902         SetLastError(ERROR_MORE_DATA);
1903         ret = FALSE;
1904     }
1905     else
1906     {
1907         LPBYTE nextData = (BYTE *)pvData + sizeof(CERT_INFO);
1908         CERT_INFO *out = (CERT_INFO *)pvData;
1909
1910         memset(out, 0, sizeof(CERT_INFO));
1911         CRYPT_CopyBlob(&out->Issuer, &in->Issuer, &nextData);
1912         CRYPT_CopyBlob(&out->SerialNumber, &in->SerialNumber, &nextData);
1913         ret = TRUE;
1914     }
1915     TRACE("returning %d\n", ret);
1916     return ret;
1917 }
1918
1919 static BOOL CDecodeSignedMsg_GetParam(CDecodeMsg *msg, DWORD dwParamType,
1920  DWORD dwIndex, void *pvData, DWORD *pcbData)
1921 {
1922     BOOL ret = FALSE;
1923
1924     switch (dwParamType)
1925     {
1926     case CMSG_TYPE_PARAM:
1927         ret = CRYPT_CopyParam(pvData, pcbData, &msg->type, sizeof(msg->type));
1928         break;
1929     case CMSG_CONTENT_PARAM:
1930         if (msg->u.signed_data.info)
1931         {
1932             if (!strcmp(msg->u.signed_data.info->content.pszObjId,
1933              szOID_RSA_data))
1934             {
1935                 CRYPT_DATA_BLOB *blob;
1936                 DWORD size;
1937
1938                 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING,
1939                  msg->u.signed_data.info->content.Content.pbData,
1940                  msg->u.signed_data.info->content.Content.cbData,
1941                  CRYPT_DECODE_ALLOC_FLAG, NULL, (LPBYTE)&blob, &size);
1942                 if (ret)
1943                 {
1944                     ret = CRYPT_CopyParam(pvData, pcbData, blob->pbData,
1945                      blob->cbData);
1946                     LocalFree(blob);
1947                 }
1948             }
1949             else
1950                 ret = CRYPT_CopyParam(pvData, pcbData,
1951                  msg->u.signed_data.info->content.Content.pbData,
1952                  msg->u.signed_data.info->content.Content.cbData);
1953         }
1954         else
1955             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
1956         break;
1957     case CMSG_INNER_CONTENT_TYPE_PARAM:
1958         if (msg->u.signed_data.info)
1959             ret = CRYPT_CopyParam(pvData, pcbData,
1960              msg->u.signed_data.info->content.pszObjId,
1961              strlen(msg->u.signed_data.info->content.pszObjId) + 1);
1962         else
1963             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
1964         break;
1965     case CMSG_SIGNER_COUNT_PARAM:
1966         if (msg->u.signed_data.info)
1967             ret = CRYPT_CopyParam(pvData, pcbData,
1968              &msg->u.signed_data.info->cSignerInfo, sizeof(DWORD));
1969         else
1970             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
1971         break;
1972     case CMSG_SIGNER_INFO_PARAM:
1973         if (msg->u.signed_data.info)
1974         {
1975             if (dwIndex >= msg->u.signed_data.info->cSignerInfo)
1976                 SetLastError(CRYPT_E_INVALID_INDEX);
1977             else
1978                 ret = CRYPT_CopySignerInfo(pvData, pcbData,
1979                  &msg->u.signed_data.info->rgSignerInfo[dwIndex]);
1980         }
1981         else
1982             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
1983         break;
1984     case CMSG_SIGNER_CERT_INFO_PARAM:
1985         if (msg->u.signed_data.info)
1986         {
1987             if (dwIndex >= msg->u.signed_data.info->cSignerInfo)
1988                 SetLastError(CRYPT_E_INVALID_INDEX);
1989             else
1990                 ret = CRYPT_CopySignerCertInfo(pvData, pcbData,
1991                  &msg->u.signed_data.info->rgSignerInfo[dwIndex]);
1992         }
1993         else
1994             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
1995         break;
1996     case CMSG_CERT_COUNT_PARAM:
1997         if (msg->u.signed_data.info)
1998             ret = CRYPT_CopyParam(pvData, pcbData,
1999              &msg->u.signed_data.info->cCertEncoded, sizeof(DWORD));
2000         else
2001             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2002         break;
2003     case CMSG_CERT_PARAM:
2004         if (msg->u.signed_data.info)
2005         {
2006             if (dwIndex >= msg->u.signed_data.info->cCertEncoded)
2007                 SetLastError(CRYPT_E_INVALID_INDEX);
2008             else
2009                 ret = CRYPT_CopyParam(pvData, pcbData,
2010                  msg->u.signed_data.info->rgCertEncoded[dwIndex].pbData,
2011                  msg->u.signed_data.info->rgCertEncoded[dwIndex].cbData);
2012         }
2013         else
2014             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2015         break;
2016     case CMSG_CRL_COUNT_PARAM:
2017         if (msg->u.signed_data.info)
2018             ret = CRYPT_CopyParam(pvData, pcbData,
2019              &msg->u.signed_data.info->cCrlEncoded, sizeof(DWORD));
2020         else
2021             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2022         break;
2023     case CMSG_CRL_PARAM:
2024         if (msg->u.signed_data.info)
2025         {
2026             if (dwIndex >= msg->u.signed_data.info->cCrlEncoded)
2027                 SetLastError(CRYPT_E_INVALID_INDEX);
2028             else
2029                 ret = CRYPT_CopyParam(pvData, pcbData,
2030                  msg->u.signed_data.info->rgCrlEncoded[dwIndex].pbData,
2031                  msg->u.signed_data.info->rgCrlEncoded[dwIndex].cbData);
2032         }
2033         else
2034             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2035         break;
2036     case CMSG_COMPUTED_HASH_PARAM:
2037         if (msg->u.signed_data.info)
2038         {
2039             if (dwIndex >= msg->u.signed_data.cSignerHandle)
2040                 SetLastError(CRYPT_E_INVALID_INDEX);
2041             else
2042                 ret = CryptGetHashParam(
2043                  msg->u.signed_data.signerHandles[dwIndex].contentHash,
2044                  HP_HASHVAL, pvData, pcbData, 0);
2045         }
2046         else
2047             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2048         break;
2049     case CMSG_ATTR_CERT_COUNT_PARAM:
2050         if (msg->u.signed_data.info)
2051         {
2052             DWORD attrCertCount = 0;
2053
2054             ret = CRYPT_CopyParam(pvData, pcbData,
2055              &attrCertCount, sizeof(DWORD));
2056         }
2057         else
2058             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2059         break;
2060     case CMSG_ATTR_CERT_PARAM:
2061         if (msg->u.signed_data.info)
2062             SetLastError(CRYPT_E_INVALID_INDEX);
2063         else
2064             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2065         break;
2066     default:
2067         FIXME("unimplemented for %d\n", dwParamType);
2068         SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2069     }
2070     return ret;
2071 }
2072
2073 static BOOL CDecodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
2074  DWORD dwIndex, void *pvData, DWORD *pcbData)
2075 {
2076     CDecodeMsg *msg = (CDecodeMsg *)hCryptMsg;
2077     BOOL ret = FALSE;
2078
2079     switch (msg->type)
2080     {
2081     case CMSG_HASHED:
2082         ret = CDecodeHashMsg_GetParam(msg, dwParamType, dwIndex, pvData,
2083          pcbData);
2084         break;
2085     case CMSG_SIGNED:
2086         ret = CDecodeSignedMsg_GetParam(msg, dwParamType, dwIndex, pvData,
2087          pcbData);
2088         break;
2089     default:
2090         switch (dwParamType)
2091         {
2092         case CMSG_TYPE_PARAM:
2093             ret = CRYPT_CopyParam(pvData, pcbData, &msg->type,
2094              sizeof(msg->type));
2095             break;
2096         default:
2097         {
2098             CRYPT_DATA_BLOB blob;
2099
2100             ret = ContextPropertyList_FindProperty(msg->properties, dwParamType,
2101              &blob);
2102             if (ret)
2103                 ret = CRYPT_CopyParam(pvData, pcbData, blob.pbData,
2104                  blob.cbData);
2105             else
2106                 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2107         }
2108         }
2109     }
2110     return ret;
2111 }
2112
2113 static BOOL CDecodeHashMsg_VerifyHash(CDecodeMsg *msg)
2114 {
2115     BOOL ret;
2116     CRYPT_DATA_BLOB hashBlob;
2117
2118     ret = ContextPropertyList_FindProperty(msg->properties,
2119      CMSG_HASH_DATA_PARAM, &hashBlob);
2120     if (ret)
2121     {
2122         DWORD computedHashSize = 0;
2123
2124         ret = CDecodeHashMsg_GetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, NULL,
2125          &computedHashSize);
2126         if (hashBlob.cbData == computedHashSize)
2127         {
2128             LPBYTE computedHash = CryptMemAlloc(computedHashSize);
2129
2130             if (computedHash)
2131             {
2132                 ret = CDecodeHashMsg_GetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0,
2133                  computedHash, &computedHashSize);
2134                 if (ret)
2135                     ret = !memcmp(hashBlob.pbData, computedHash,
2136                      hashBlob.cbData);
2137                 CryptMemFree(computedHash);
2138             }
2139             else
2140                 ret = FALSE;
2141         }
2142     }
2143     return ret;
2144 }
2145
2146 static BOOL CDecodeSignedMsg_VerifySignatureWithKey(CDecodeMsg *msg,
2147  HCRYPTPROV prov, DWORD signerIndex, PCERT_PUBLIC_KEY_INFO keyInfo)
2148 {
2149     HCRYPTKEY key;
2150     BOOL ret;
2151
2152     if (!prov)
2153         prov = msg->crypt_prov;
2154     ret = CryptImportPublicKeyInfo(prov, X509_ASN_ENCODING, keyInfo, &key);
2155     if (ret)
2156     {
2157         HCRYPTHASH hash;
2158         CRYPT_HASH_BLOB reversedHash;
2159
2160         if (msg->u.signed_data.info->rgSignerInfo[signerIndex].AuthAttrs.cAttr)
2161             hash = msg->u.signed_data.signerHandles[signerIndex].authAttrHash;
2162         else
2163             hash = msg->u.signed_data.signerHandles[signerIndex].contentHash;
2164         ret = CRYPT_ConstructBlob(&reversedHash,
2165          &msg->u.signed_data.info->rgSignerInfo[signerIndex].EncryptedHash);
2166         if (ret)
2167         {
2168             CRYPT_ReverseBytes(&reversedHash);
2169             ret = CryptVerifySignatureW(hash, reversedHash.pbData,
2170              reversedHash.cbData, key, NULL, 0);
2171             CryptMemFree(reversedHash.pbData);
2172         }
2173         CryptDestroyKey(key);
2174     }
2175     return ret;
2176 }
2177
2178 static BOOL CDecodeSignedMsg_VerifySignature(CDecodeMsg *msg, PCERT_INFO info)
2179 {
2180     BOOL ret = FALSE;
2181     DWORD i;
2182
2183     for (i = 0; !ret && i < msg->u.signed_data.info->cSignerInfo; i++)
2184     {
2185         ret = CertCompareCertificateName(X509_ASN_ENCODING,
2186          &msg->u.signed_data.info->rgSignerInfo[i].Issuer, &info->Issuer);
2187         if (ret)
2188         {
2189             ret = CertCompareIntegerBlob(
2190              &msg->u.signed_data.info->rgSignerInfo[i].SerialNumber,
2191              &info->SerialNumber);
2192             if (ret)
2193                 break;
2194         }
2195     }
2196     if (ret)
2197         ret = CDecodeSignedMsg_VerifySignatureWithKey(msg, 0, i,
2198          &info->SubjectPublicKeyInfo);
2199     else
2200         SetLastError(CRYPT_E_SIGNER_NOT_FOUND);
2201
2202     return ret;
2203 }
2204
2205 static BOOL CDecodeSignedMsg_VerifySignatureEx(CDecodeMsg *msg,
2206  PCMSG_CTRL_VERIFY_SIGNATURE_EX_PARA para)
2207 {
2208     BOOL ret = FALSE;
2209
2210     if (para->cbSize != sizeof(CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA))
2211         SetLastError(ERROR_INVALID_PARAMETER);
2212     else if (para->dwSignerIndex >= msg->u.signed_data.info->cSignerInfo)
2213         SetLastError(CRYPT_E_SIGNER_NOT_FOUND);
2214     else
2215     {
2216         switch (para->dwSignerType)
2217         {
2218         case CMSG_VERIFY_SIGNER_PUBKEY:
2219             ret = CDecodeSignedMsg_VerifySignatureWithKey(msg,
2220              para->hCryptProv, para->dwSignerIndex,
2221              (PCERT_PUBLIC_KEY_INFO)para->pvSigner);
2222             break;
2223         case CMSG_VERIFY_SIGNER_CERT:
2224         {
2225             PCCERT_CONTEXT cert = (PCCERT_CONTEXT)para->pvSigner;
2226
2227             ret = CDecodeSignedMsg_VerifySignatureWithKey(msg, para->hCryptProv,
2228              para->dwSignerIndex, &cert->pCertInfo->SubjectPublicKeyInfo);
2229             break;
2230         }
2231         default:
2232             FIXME("unimplemented for signer type %d\n", para->dwSignerType);
2233             SetLastError(CRYPT_E_SIGNER_NOT_FOUND);
2234         }
2235     }
2236     return ret;
2237 }
2238
2239 static BOOL CDecodeMsg_Control(HCRYPTMSG hCryptMsg, DWORD dwFlags,
2240  DWORD dwCtrlType, const void *pvCtrlPara)
2241 {
2242     CDecodeMsg *msg = (CDecodeMsg *)hCryptMsg;
2243     BOOL ret = FALSE;
2244
2245     switch (dwCtrlType)
2246     {
2247     case CMSG_CTRL_VERIFY_SIGNATURE:
2248         switch (msg->type)
2249         {
2250         case CMSG_SIGNED:
2251             ret = CDecodeSignedMsg_VerifySignature(msg, (PCERT_INFO)pvCtrlPara);
2252             break;
2253         default:
2254             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2255         }
2256         break;
2257     case CMSG_CTRL_DECRYPT:
2258         switch (msg->type)
2259         {
2260         default:
2261             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2262         }
2263         break;
2264     case CMSG_CTRL_VERIFY_HASH:
2265         switch (msg->type)
2266         {
2267         case CMSG_HASHED:
2268             ret = CDecodeHashMsg_VerifyHash(msg);
2269             break;
2270         default:
2271             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2272         }
2273         break;
2274     case CMSG_CTRL_VERIFY_SIGNATURE_EX:
2275         switch (msg->type)
2276         {
2277         case CMSG_SIGNED:
2278             ret = CDecodeSignedMsg_VerifySignatureEx(msg,
2279              (PCMSG_CTRL_VERIFY_SIGNATURE_EX_PARA)pvCtrlPara);
2280             break;
2281         default:
2282             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2283         }
2284         break;
2285     default:
2286         SetLastError(CRYPT_E_CONTROL_TYPE);
2287     }
2288     return ret;
2289 }
2290
2291 HCRYPTMSG WINAPI CryptMsgOpenToDecode(DWORD dwMsgEncodingType, DWORD dwFlags,
2292  DWORD dwMsgType, HCRYPTPROV_LEGACY hCryptProv, PCERT_INFO pRecipientInfo,
2293  PCMSG_STREAM_INFO pStreamInfo)
2294 {
2295     CDecodeMsg *msg;
2296
2297     TRACE("(%08x, %08x, %08x, %08lx, %p, %p)\n", dwMsgEncodingType,
2298      dwFlags, dwMsgType, hCryptProv, pRecipientInfo, pStreamInfo);
2299
2300     if (GET_CMSG_ENCODING_TYPE(dwMsgEncodingType) != PKCS_7_ASN_ENCODING)
2301     {
2302         SetLastError(E_INVALIDARG);
2303         return NULL;
2304     }
2305     msg = CryptMemAlloc(sizeof(CDecodeMsg));
2306     if (msg)
2307     {
2308         CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo,
2309          CDecodeMsg_Close, CDecodeMsg_GetParam, CDecodeMsg_Update,
2310          CDecodeMsg_Control);
2311         msg->type = dwMsgType;
2312         if (hCryptProv)
2313             msg->crypt_prov = hCryptProv;
2314         else
2315         {
2316             msg->crypt_prov = CRYPT_GetDefaultProvider();
2317             msg->base.open_flags &= ~CMSG_CRYPT_RELEASE_CONTEXT_FLAG;
2318         }
2319         memset(&msg->u, 0, sizeof(msg->u));
2320         msg->msg_data.cbData = 0;
2321         msg->msg_data.pbData = NULL;
2322         msg->properties = ContextPropertyList_Create();
2323     }
2324     return msg;
2325 }
2326
2327 HCRYPTMSG WINAPI CryptMsgDuplicate(HCRYPTMSG hCryptMsg)
2328 {
2329     TRACE("(%p)\n", hCryptMsg);
2330
2331     if (hCryptMsg)
2332     {
2333         CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg;
2334
2335         InterlockedIncrement(&msg->ref);
2336     }
2337     return hCryptMsg;
2338 }
2339
2340 BOOL WINAPI CryptMsgClose(HCRYPTMSG hCryptMsg)
2341 {
2342     TRACE("(%p)\n", hCryptMsg);
2343
2344     if (hCryptMsg)
2345     {
2346         CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg;
2347
2348         if (InterlockedDecrement(&msg->ref) == 0)
2349         {
2350             TRACE("freeing %p\n", msg);
2351             if (msg->close)
2352                 msg->close(msg);
2353             CryptMemFree(msg);
2354         }
2355     }
2356     return TRUE;
2357 }
2358
2359 BOOL WINAPI CryptMsgUpdate(HCRYPTMSG hCryptMsg, const BYTE *pbData,
2360  DWORD cbData, BOOL fFinal)
2361 {
2362     CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg;
2363     BOOL ret = FALSE;
2364
2365     TRACE("(%p, %p, %d, %d)\n", hCryptMsg, pbData, cbData, fFinal);
2366
2367     if (msg->state == MsgStateFinalized)
2368         SetLastError(CRYPT_E_MSG_ERROR);
2369     else
2370     {
2371         ret = msg->update(hCryptMsg, pbData, cbData, fFinal);
2372         msg->state = MsgStateUpdated;
2373         if (fFinal)
2374             msg->state = MsgStateFinalized;
2375     }
2376     return ret;
2377 }
2378
2379 BOOL WINAPI CryptMsgGetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
2380  DWORD dwIndex, void *pvData, DWORD *pcbData)
2381 {
2382     CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg;
2383
2384     TRACE("(%p, %d, %d, %p, %p)\n", hCryptMsg, dwParamType, dwIndex,
2385      pvData, pcbData);
2386     return msg->get_param(hCryptMsg, dwParamType, dwIndex, pvData, pcbData);
2387 }
2388
2389 BOOL WINAPI CryptMsgControl(HCRYPTMSG hCryptMsg, DWORD dwFlags,
2390  DWORD dwCtrlType, const void *pvCtrlPara)
2391 {
2392     CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg;
2393
2394     TRACE("(%p, %08x, %d, %p)\n", hCryptMsg, dwFlags, dwCtrlType,
2395      pvCtrlPara);
2396     return msg->control(hCryptMsg, dwFlags, dwCtrlType, pvCtrlPara);
2397 }
2398
2399 HCERTSTORE WINAPI CryptGetMessageCertificates(DWORD dwMsgAndCertEncodingType,
2400  HCRYPTPROV_LEGACY hCryptProv, DWORD dwFlags, const BYTE* pbSignedBlob,
2401  DWORD cbSignedBlob)
2402 {
2403     CRYPT_DATA_BLOB blob = { cbSignedBlob, (LPBYTE)pbSignedBlob };
2404
2405     TRACE("(%08x, %ld, %d08x %p, %d)\n", dwMsgAndCertEncodingType, hCryptProv,
2406      dwFlags, pbSignedBlob, cbSignedBlob);
2407
2408     return CertOpenStore(CERT_STORE_PROV_PKCS7, dwMsgAndCertEncodingType,
2409      hCryptProv, dwFlags, &blob);
2410 }
2411
2412 LONG WINAPI CryptGetMessageSignerCount(DWORD dwMsgEncodingType,
2413  const BYTE *pbSignedBlob, DWORD cbSignedBlob)
2414 {
2415     HCRYPTMSG msg;
2416     LONG count = -1;
2417
2418     TRACE("(%08x, %p, %d)\n", dwMsgEncodingType, pbSignedBlob, cbSignedBlob);
2419
2420     msg = CryptMsgOpenToDecode(dwMsgEncodingType, 0, 0, 0, NULL, NULL);
2421     if (msg)
2422     {
2423         if (CryptMsgUpdate(msg, pbSignedBlob, cbSignedBlob, TRUE))
2424         {
2425             DWORD size = sizeof(count);
2426
2427             CryptMsgGetParam(msg, CMSG_SIGNER_COUNT_PARAM, 0, &count, &size);
2428         }
2429         CryptMsgClose(msg);
2430     }
2431     return count;
2432 }
2433
2434 static CERT_INFO *CRYPT_GetSignerCertInfoFromMsg(HCRYPTMSG msg,
2435  DWORD dwSignerIndex)
2436 {
2437     CERT_INFO *certInfo = NULL;
2438     DWORD size;
2439
2440     if (CryptMsgGetParam(msg, CMSG_SIGNER_CERT_INFO_PARAM, dwSignerIndex, NULL,
2441      &size))
2442     {
2443         certInfo = CryptMemAlloc(size);
2444         if (certInfo)
2445         {
2446             if (!CryptMsgGetParam(msg, CMSG_SIGNER_CERT_INFO_PARAM,
2447              dwSignerIndex, certInfo, &size))
2448             {
2449                 CryptMemFree(certInfo);
2450                 certInfo = NULL;
2451             }
2452         }
2453     }
2454     return certInfo;
2455 }
2456
2457 static PCCERT_CONTEXT WINAPI CRYPT_DefaultGetSignerCertificate(void *pvGetArg,
2458  DWORD dwCertEncodingType, PCERT_INFO pSignerId, HCERTSTORE hMsgCertStore)
2459 {
2460     return CertFindCertificateInStore(hMsgCertStore, dwCertEncodingType, 0,
2461      CERT_FIND_SUBJECT_CERT, pSignerId, NULL);
2462 }
2463
2464 static inline PCCERT_CONTEXT CRYPT_GetSignerCertificate(HCRYPTMSG msg,
2465  PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara, PCERT_INFO certInfo, HCERTSTORE store)
2466 {
2467     PFN_CRYPT_GET_SIGNER_CERTIFICATE getCert;
2468
2469     if (pVerifyPara->pfnGetSignerCertificate)
2470         getCert = pVerifyPara->pfnGetSignerCertificate;
2471     else
2472         getCert = CRYPT_DefaultGetSignerCertificate;
2473     return getCert(pVerifyPara->pvGetArg,
2474      pVerifyPara->dwMsgAndCertEncodingType, certInfo, store);
2475 }
2476
2477 BOOL WINAPI CryptVerifyMessageSignature(PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara,
2478  DWORD dwSignerIndex, const BYTE* pbSignedBlob, DWORD cbSignedBlob,
2479  BYTE* pbDecoded, DWORD* pcbDecoded, PCCERT_CONTEXT* ppSignerCert)
2480 {
2481     BOOL ret = FALSE;
2482     DWORD size;
2483     CRYPT_CONTENT_INFO *contentInfo;
2484
2485     TRACE("(%p, %d, %p, %d, %p, %p, %p)\n",
2486      pVerifyPara, dwSignerIndex, pbSignedBlob, cbSignedBlob,
2487      pbDecoded, pcbDecoded, ppSignerCert);
2488
2489     if (ppSignerCert)
2490         *ppSignerCert = NULL;
2491     if (pcbDecoded)
2492         *pcbDecoded = 0;
2493     if (!pVerifyPara ||
2494      pVerifyPara->cbSize != sizeof(CRYPT_VERIFY_MESSAGE_PARA) ||
2495      GET_CMSG_ENCODING_TYPE(pVerifyPara->dwMsgAndCertEncodingType) !=
2496      PKCS_7_ASN_ENCODING)
2497     {
2498         SetLastError(E_INVALIDARG);
2499         return FALSE;
2500     }
2501
2502     ret = CryptDecodeObjectEx(pVerifyPara->dwMsgAndCertEncodingType,
2503      PKCS_CONTENT_INFO, pbSignedBlob, cbSignedBlob,
2504      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
2505      (LPBYTE)&contentInfo, &size);
2506     if (ret)
2507     {
2508         if (strcmp(contentInfo->pszObjId, szOID_RSA_signedData))
2509         {
2510             SetLastError(CRYPT_E_UNEXPECTED_MSG_TYPE);
2511             ret = FALSE;
2512         }
2513         else
2514         {
2515             HCRYPTMSG msg = CryptMsgOpenToDecode(
2516              pVerifyPara->dwMsgAndCertEncodingType, 0, CMSG_SIGNED,
2517              pVerifyPara->hCryptProv, NULL, NULL);
2518
2519             if (msg)
2520             {
2521                 ret = CryptMsgUpdate(msg, contentInfo->Content.pbData,
2522                  contentInfo->Content.cbData, TRUE);
2523                 if (ret && pcbDecoded)
2524                     ret = CRYPT_CopyParam(pbDecoded, pcbDecoded,
2525                      contentInfo->Content.pbData, contentInfo->Content.cbData);
2526                 if (ret)
2527                 {
2528                     CERT_INFO *certInfo = CRYPT_GetSignerCertInfoFromMsg(msg,
2529                      dwSignerIndex);
2530
2531                     ret = FALSE;
2532                     if (certInfo)
2533                     {
2534                         HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MSG,
2535                          pVerifyPara->dwMsgAndCertEncodingType,
2536                          pVerifyPara->hCryptProv, 0, msg);
2537
2538                         if (store)
2539                         {
2540                             PCCERT_CONTEXT cert = CRYPT_GetSignerCertificate(
2541                              msg, pVerifyPara, certInfo, store);
2542
2543                             if (cert)
2544                             {
2545                                 ret = CryptMsgControl(msg, 0,
2546                                  CMSG_CTRL_VERIFY_SIGNATURE, cert->pCertInfo);
2547                                 if (ret && ppSignerCert)
2548                                     *ppSignerCert = cert;
2549                                 else
2550                                     CertFreeCertificateContext(cert);
2551                             }
2552                             CertCloseStore(store, 0);
2553                         }
2554                     }
2555                     CryptMemFree(certInfo);
2556                 }
2557                 CryptMsgClose(msg);
2558             }
2559         }
2560         LocalFree(contentInfo);
2561     }
2562     TRACE("returning %d\n", ret);
2563     return ret;
2564 }