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