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