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