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