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