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