comctl32/tests: Destroy the window after the tests.
[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     CRYPT_DATA_BLOB data;
1173     CSignedMsgData  msg_data;
1174 } CSignedEncodeMsg;
1175
1176 static void CSignedEncodeMsg_Close(HCRYPTMSG hCryptMsg)
1177 {
1178     CSignedEncodeMsg *msg = (CSignedEncodeMsg *)hCryptMsg;
1179     DWORD i;
1180
1181     CryptMemFree(msg->data.pbData);
1182     CRYPT_FreeBlobArray((BlobArray *)&msg->msg_data.info->cCertEncoded);
1183     CRYPT_FreeBlobArray((BlobArray *)&msg->msg_data.info->cCrlEncoded);
1184     for (i = 0; i < msg->msg_data.info->cSignerInfo; i++)
1185         CSignerInfo_Free(&msg->msg_data.info->rgSignerInfo[i]);
1186     CSignedMsgData_CloseHandles(&msg->msg_data);
1187     CryptMemFree(msg->msg_data.info->rgSignerInfo);
1188     CryptMemFree(msg->msg_data.info);
1189 }
1190
1191 static BOOL CSignedEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
1192  DWORD dwIndex, void *pvData, DWORD *pcbData)
1193 {
1194     CSignedEncodeMsg *msg = (CSignedEncodeMsg *)hCryptMsg;
1195     BOOL ret = FALSE;
1196
1197     switch (dwParamType)
1198     {
1199     case CMSG_CONTENT_PARAM:
1200     {
1201         CRYPT_CONTENT_INFO info;
1202
1203         ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0, NULL,
1204          &info.Content.cbData);
1205         if (ret)
1206         {
1207             info.Content.pbData = CryptMemAlloc(info.Content.cbData);
1208             if (info.Content.pbData)
1209             {
1210                 ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0,
1211                  info.Content.pbData, &info.Content.cbData);
1212                 if (ret)
1213                 {
1214                     char oid_rsa_signed[] = szOID_RSA_signedData;
1215
1216                     info.pszObjId = oid_rsa_signed;
1217                     ret = CryptEncodeObjectEx(X509_ASN_ENCODING,
1218                      PKCS_CONTENT_INFO, &info, 0, NULL, pvData, pcbData);
1219                 }
1220                 CryptMemFree(info.Content.pbData);
1221             }
1222             else
1223                 ret = FALSE;
1224         }
1225         break;
1226     }
1227     case CMSG_BARE_CONTENT_PARAM:
1228     {
1229         CRYPT_SIGNED_INFO info;
1230         char oid_rsa_data[] = szOID_RSA_data;
1231
1232         info = *msg->msg_data.info;
1233         /* Quirk:  OID is only encoded messages if an update has happened */
1234         if (msg->base.state != MsgStateInit)
1235             info.content.pszObjId = oid_rsa_data;
1236         else
1237             info.content.pszObjId = NULL;
1238         if (msg->data.cbData)
1239         {
1240             CRYPT_DATA_BLOB blob = { msg->data.cbData, msg->data.pbData };
1241
1242             ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING,
1243              &blob, CRYPT_ENCODE_ALLOC_FLAG, NULL,
1244              &info.content.Content.pbData, &info.content.Content.cbData);
1245         }
1246         else
1247         {
1248             info.content.Content.cbData = 0;
1249             info.content.Content.pbData = NULL;
1250             ret = TRUE;
1251         }
1252         if (ret)
1253         {
1254             ret = CRYPT_AsnEncodeCMSSignedInfo(&info, pvData, pcbData);
1255             LocalFree(info.content.Content.pbData);
1256         }
1257         break;
1258     }
1259     case CMSG_COMPUTED_HASH_PARAM:
1260         if (dwIndex >= msg->msg_data.cSignerHandle)
1261             SetLastError(CRYPT_E_INVALID_INDEX);
1262         else
1263             ret = CryptGetHashParam(
1264              msg->msg_data.signerHandles[dwIndex].contentHash, HP_HASHVAL,
1265              pvData, pcbData, 0);
1266         break;
1267     case CMSG_ENCODED_SIGNER:
1268         if (dwIndex >= msg->msg_data.info->cSignerInfo)
1269             SetLastError(CRYPT_E_INVALID_INDEX);
1270         else
1271             ret = CryptEncodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
1272              CMS_SIGNER_INFO, &msg->msg_data.info->rgSignerInfo[dwIndex], 0,
1273              NULL, pvData, pcbData);
1274         break;
1275     case CMSG_VERSION_PARAM:
1276         ret = CRYPT_CopyParam(pvData, pcbData, &msg->msg_data.info->version,
1277          sizeof(msg->msg_data.info->version));
1278         break;
1279     default:
1280         SetLastError(CRYPT_E_INVALID_MSG_TYPE);
1281     }
1282     return ret;
1283 }
1284
1285 static BOOL CSignedEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
1286  DWORD cbData, BOOL fFinal)
1287 {
1288     CSignedEncodeMsg *msg = (CSignedEncodeMsg *)hCryptMsg;
1289     BOOL ret = FALSE;
1290
1291     if (msg->base.state == MsgStateFinalized)
1292         SetLastError(CRYPT_E_MSG_ERROR);
1293     else if (msg->base.streamed || (msg->base.open_flags & CMSG_DETACHED_FLAG))
1294     {
1295         ret = CSignedMsgData_Update(&msg->msg_data, pbData, cbData, fFinal,
1296          Sign);
1297         if (msg->base.streamed)
1298             FIXME("streamed partial stub\n");
1299         msg->base.state = fFinal ? MsgStateFinalized : MsgStateUpdated;
1300     }
1301     else
1302     {
1303         if (!fFinal)
1304             SetLastError(CRYPT_E_MSG_ERROR);
1305         else
1306         {
1307             if (cbData)
1308             {
1309                 msg->data.pbData = CryptMemAlloc(cbData);
1310                 if (msg->data.pbData)
1311                 {
1312                     memcpy(msg->data.pbData, pbData, cbData);
1313                     msg->data.cbData = cbData;
1314                     ret = TRUE;
1315                 }
1316             }
1317             else
1318                 ret = TRUE;
1319             if (ret)
1320                 ret = CSignedMsgData_Update(&msg->msg_data, pbData, cbData,
1321                  fFinal, Sign);
1322             msg->base.state = MsgStateFinalized;
1323         }
1324     }
1325     return ret;
1326 }
1327
1328 static HCRYPTMSG CSignedEncodeMsg_Open(DWORD dwFlags,
1329  const void *pvMsgEncodeInfo, LPSTR pszInnerContentObjID,
1330  PCMSG_STREAM_INFO pStreamInfo)
1331 {
1332     const CMSG_SIGNED_ENCODE_INFO_WITH_CMS *info =
1333      (const CMSG_SIGNED_ENCODE_INFO_WITH_CMS *)pvMsgEncodeInfo;
1334     DWORD i;
1335     CSignedEncodeMsg *msg;
1336
1337     if (info->cbSize != sizeof(CMSG_SIGNED_ENCODE_INFO) &&
1338      info->cbSize != sizeof(CMSG_SIGNED_ENCODE_INFO_WITH_CMS))
1339     {
1340         SetLastError(E_INVALIDARG);
1341         return NULL;
1342     }
1343     if (info->cbSize == sizeof(CMSG_SIGNED_ENCODE_INFO_WITH_CMS) &&
1344      info->cAttrCertEncoded)
1345     {
1346         FIXME("CMSG_SIGNED_ENCODE_INFO with CMS fields unsupported\n");
1347         return NULL;
1348     }
1349     for (i = 0; i < info->cSigners; i++)
1350         if (!CRYPT_IsValidSigner(&info->rgSigners[i]))
1351             return NULL;
1352     msg = CryptMemAlloc(sizeof(CSignedEncodeMsg));
1353     if (msg)
1354     {
1355         BOOL ret = TRUE;
1356
1357         CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo,
1358          CSignedEncodeMsg_Close, CSignedEncodeMsg_GetParam,
1359          CSignedEncodeMsg_Update, CRYPT_DefaultMsgControl);
1360         msg->data.cbData = 0;
1361         msg->data.pbData = NULL;
1362         msg->msg_data.info = CryptMemAlloc(sizeof(CRYPT_SIGNED_INFO));
1363         if (msg->msg_data.info)
1364         {
1365             memset(msg->msg_data.info, 0, sizeof(CRYPT_SIGNED_INFO));
1366             msg->msg_data.info->version = CMSG_SIGNED_DATA_V1;
1367         }
1368         else
1369             ret = FALSE;
1370         if (ret)
1371         {
1372             if (info->cSigners)
1373             {
1374                 msg->msg_data.info->rgSignerInfo =
1375                  CryptMemAlloc(info->cSigners * sizeof(CMSG_CMS_SIGNER_INFO));
1376                 if (msg->msg_data.info->rgSignerInfo)
1377                 {
1378                     msg->msg_data.info->cSignerInfo = info->cSigners;
1379                     memset(msg->msg_data.info->rgSignerInfo, 0,
1380                      msg->msg_data.info->cSignerInfo *
1381                      sizeof(CMSG_CMS_SIGNER_INFO));
1382                     ret = CSignedMsgData_AllocateHandles(&msg->msg_data);
1383                     for (i = 0; ret && i < msg->msg_data.info->cSignerInfo; i++)
1384                     {
1385                         if (info->rgSigners[i].SignerId.dwIdChoice ==
1386                          CERT_ID_KEY_IDENTIFIER)
1387                             msg->msg_data.info->version = CMSG_SIGNED_DATA_V3;
1388                         ret = CSignerInfo_Construct(
1389                          &msg->msg_data.info->rgSignerInfo[i],
1390                          &info->rgSigners[i]);
1391                         if (ret)
1392                         {
1393                             ret = CSignedMsgData_ConstructSignerHandles(
1394                              &msg->msg_data, i, info->rgSigners[i].hCryptProv);
1395                             if (dwFlags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG)
1396                                 CryptReleaseContext(info->rgSigners[i].hCryptProv,
1397                                  0);
1398                         }
1399                     }
1400                 }
1401                 else
1402                     ret = FALSE;
1403             }
1404             else
1405             {
1406                 msg->msg_data.info->cSignerInfo = 0;
1407                 msg->msg_data.signerHandles = NULL;
1408                 msg->msg_data.cSignerHandle = 0;
1409             }
1410         }
1411         if (ret)
1412             ret = CRYPT_ConstructBlobArray(
1413              (BlobArray *)&msg->msg_data.info->cCertEncoded,
1414              (const BlobArray *)&info->cCertEncoded);
1415         if (ret)
1416             ret = CRYPT_ConstructBlobArray(
1417              (BlobArray *)&msg->msg_data.info->cCrlEncoded,
1418              (const BlobArray *)&info->cCrlEncoded);
1419         if (!ret)
1420         {
1421             CSignedEncodeMsg_Close(msg);
1422             msg = NULL;
1423         }
1424     }
1425     return msg;
1426 }
1427
1428 HCRYPTMSG WINAPI CryptMsgOpenToEncode(DWORD dwMsgEncodingType, DWORD dwFlags,
1429  DWORD dwMsgType, const void *pvMsgEncodeInfo, LPSTR pszInnerContentObjID,
1430  PCMSG_STREAM_INFO pStreamInfo)
1431 {
1432     HCRYPTMSG msg = NULL;
1433
1434     TRACE("(%08x, %08x, %08x, %p, %s, %p)\n", dwMsgEncodingType, dwFlags,
1435      dwMsgType, pvMsgEncodeInfo, debugstr_a(pszInnerContentObjID), pStreamInfo);
1436
1437     if (GET_CMSG_ENCODING_TYPE(dwMsgEncodingType) != PKCS_7_ASN_ENCODING)
1438     {
1439         SetLastError(E_INVALIDARG);
1440         return NULL;
1441     }
1442     switch (dwMsgType)
1443     {
1444     case CMSG_DATA:
1445         msg = CDataEncodeMsg_Open(dwFlags, pvMsgEncodeInfo,
1446          pszInnerContentObjID, pStreamInfo);
1447         break;
1448     case CMSG_HASHED:
1449         msg = CHashEncodeMsg_Open(dwFlags, pvMsgEncodeInfo,
1450          pszInnerContentObjID, pStreamInfo);
1451         break;
1452     case CMSG_SIGNED:
1453         msg = CSignedEncodeMsg_Open(dwFlags, pvMsgEncodeInfo,
1454          pszInnerContentObjID, pStreamInfo);
1455         break;
1456     case CMSG_ENVELOPED:
1457         FIXME("unimplemented for type CMSG_ENVELOPED\n");
1458         break;
1459     case CMSG_SIGNED_AND_ENVELOPED:
1460     case CMSG_ENCRYPTED:
1461         /* defined but invalid, fall through */
1462     default:
1463         SetLastError(CRYPT_E_INVALID_MSG_TYPE);
1464     }
1465     return msg;
1466 }
1467
1468 typedef struct _CDecodeMsg
1469 {
1470     CryptMsgBase           base;
1471     DWORD                  type;
1472     HCRYPTPROV             crypt_prov;
1473     union {
1474         HCRYPTHASH     hash;
1475         CSignedMsgData signed_data;
1476     } u;
1477     CRYPT_DATA_BLOB        msg_data;
1478     CRYPT_DATA_BLOB        detached_data;
1479     PCONTEXT_PROPERTY_LIST properties;
1480 } CDecodeMsg;
1481
1482 static void CDecodeMsg_Close(HCRYPTMSG hCryptMsg)
1483 {
1484     CDecodeMsg *msg = (CDecodeMsg *)hCryptMsg;
1485
1486     if (msg->base.open_flags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG)
1487         CryptReleaseContext(msg->crypt_prov, 0);
1488     switch (msg->type)
1489     {
1490     case CMSG_HASHED:
1491         if (msg->u.hash)
1492             CryptDestroyHash(msg->u.hash);
1493         break;
1494     case CMSG_SIGNED:
1495         if (msg->u.signed_data.info)
1496         {
1497             LocalFree(msg->u.signed_data.info);
1498             CSignedMsgData_CloseHandles(&msg->u.signed_data);
1499         }
1500         break;
1501     }
1502     CryptMemFree(msg->msg_data.pbData);
1503     CryptMemFree(msg->detached_data.pbData);
1504     ContextPropertyList_Free(msg->properties);
1505 }
1506
1507 static BOOL CDecodeMsg_CopyData(CRYPT_DATA_BLOB *blob, const BYTE *pbData,
1508  DWORD cbData)
1509 {
1510     BOOL ret = TRUE;
1511
1512     if (cbData)
1513     {
1514         if (blob->cbData)
1515             blob->pbData = CryptMemRealloc(blob->pbData,
1516              blob->cbData + cbData);
1517         else
1518             blob->pbData = CryptMemAlloc(cbData);
1519         if (blob->pbData)
1520         {
1521             memcpy(blob->pbData + blob->cbData, pbData, cbData);
1522             blob->cbData += cbData;
1523         }
1524         else
1525             ret = FALSE;
1526     }
1527     return ret;
1528 }
1529
1530 static BOOL CDecodeMsg_DecodeDataContent(CDecodeMsg *msg, CRYPT_DER_BLOB *blob)
1531 {
1532     BOOL ret;
1533     CRYPT_DATA_BLOB *data;
1534     DWORD size;
1535
1536     ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING,
1537      blob->pbData, blob->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, (LPBYTE)&data,
1538      &size);
1539     if (ret)
1540     {
1541         ret = ContextPropertyList_SetProperty(msg->properties,
1542          CMSG_CONTENT_PARAM, data->pbData, data->cbData);
1543         LocalFree(data);
1544     }
1545     return ret;
1546 }
1547
1548 static void CDecodeMsg_SaveAlgorithmID(CDecodeMsg *msg, DWORD param,
1549  const CRYPT_ALGORITHM_IDENTIFIER *id)
1550 {
1551     static const BYTE nullParams[] = { ASN_NULL, 0 };
1552     CRYPT_ALGORITHM_IDENTIFIER *copy;
1553     DWORD len = sizeof(CRYPT_ALGORITHM_IDENTIFIER);
1554
1555     /* Linearize algorithm id */
1556     len += strlen(id->pszObjId) + 1;
1557     len += id->Parameters.cbData;
1558     copy = CryptMemAlloc(len);
1559     if (copy)
1560     {
1561         copy->pszObjId =
1562          (LPSTR)((BYTE *)copy + sizeof(CRYPT_ALGORITHM_IDENTIFIER));
1563         strcpy(copy->pszObjId, id->pszObjId);
1564         copy->Parameters.pbData = (BYTE *)copy->pszObjId + strlen(id->pszObjId)
1565          + 1;
1566         /* Trick:  omit NULL parameters */
1567         if (id->Parameters.cbData == sizeof(nullParams) &&
1568          !memcmp(id->Parameters.pbData, nullParams, sizeof(nullParams)))
1569         {
1570             copy->Parameters.cbData = 0;
1571             len -= sizeof(nullParams);
1572         }
1573         else
1574             copy->Parameters.cbData = id->Parameters.cbData;
1575         if (copy->Parameters.cbData)
1576             memcpy(copy->Parameters.pbData, id->Parameters.pbData,
1577              id->Parameters.cbData);
1578         ContextPropertyList_SetProperty(msg->properties, param, (BYTE *)copy,
1579          len);
1580         CryptMemFree(copy);
1581     }
1582 }
1583
1584 static inline void CRYPT_FixUpAlgorithmID(CRYPT_ALGORITHM_IDENTIFIER *id)
1585 {
1586     id->pszObjId = (LPSTR)((BYTE *)id + sizeof(CRYPT_ALGORITHM_IDENTIFIER));
1587     id->Parameters.pbData = (BYTE *)id->pszObjId + strlen(id->pszObjId) + 1;
1588 }
1589
1590 static BOOL CDecodeMsg_DecodeHashedContent(CDecodeMsg *msg,
1591  CRYPT_DER_BLOB *blob)
1592 {
1593     BOOL ret;
1594     CRYPT_DIGESTED_DATA *digestedData;
1595     DWORD size;
1596
1597     ret = CRYPT_AsnDecodePKCSDigestedData(blob->pbData, blob->cbData,
1598      CRYPT_DECODE_ALLOC_FLAG, NULL, (CRYPT_DIGESTED_DATA *)&digestedData,
1599      &size);
1600     if (ret)
1601     {
1602         ContextPropertyList_SetProperty(msg->properties, CMSG_VERSION_PARAM,
1603          (const BYTE *)&digestedData->version, sizeof(digestedData->version));
1604         CDecodeMsg_SaveAlgorithmID(msg, CMSG_HASH_ALGORITHM_PARAM,
1605          &digestedData->DigestAlgorithm);
1606         ContextPropertyList_SetProperty(msg->properties,
1607          CMSG_INNER_CONTENT_TYPE_PARAM,
1608          (const BYTE *)digestedData->ContentInfo.pszObjId,
1609          digestedData->ContentInfo.pszObjId ?
1610          strlen(digestedData->ContentInfo.pszObjId) + 1 : 0);
1611         if (!(msg->base.open_flags & CMSG_DETACHED_FLAG))
1612         {
1613             if (digestedData->ContentInfo.Content.cbData)
1614                 CDecodeMsg_DecodeDataContent(msg,
1615                  &digestedData->ContentInfo.Content);
1616             else
1617                 ContextPropertyList_SetProperty(msg->properties,
1618                  CMSG_CONTENT_PARAM, NULL, 0);
1619         }
1620         ContextPropertyList_SetProperty(msg->properties, CMSG_HASH_DATA_PARAM,
1621          digestedData->hash.pbData, digestedData->hash.cbData);
1622         LocalFree(digestedData);
1623     }
1624     return ret;
1625 }
1626
1627 static BOOL CDecodeMsg_DecodeSignedContent(CDecodeMsg *msg,
1628  CRYPT_DER_BLOB *blob)
1629 {
1630     BOOL ret;
1631     CRYPT_SIGNED_INFO *signedInfo;
1632     DWORD size;
1633
1634     ret = CRYPT_AsnDecodeCMSSignedInfo(blob->pbData, blob->cbData,
1635      CRYPT_DECODE_ALLOC_FLAG, NULL, (CRYPT_SIGNED_INFO *)&signedInfo,
1636      &size);
1637     if (ret)
1638         msg->u.signed_data.info = signedInfo;
1639     return ret;
1640 }
1641
1642 /* Decodes the content in blob as the type given, and updates the value
1643  * (type, parameters, etc.) of msg based on what blob contains.
1644  * It doesn't just use msg's type, to allow a recursive call from an implicitly
1645  * typed message once the outer content info has been decoded.
1646  */
1647 static BOOL CDecodeMsg_DecodeContent(CDecodeMsg *msg, CRYPT_DER_BLOB *blob,
1648  DWORD type)
1649 {
1650     BOOL ret;
1651
1652     switch (type)
1653     {
1654     case CMSG_DATA:
1655         if ((ret = CDecodeMsg_DecodeDataContent(msg, blob)))
1656             msg->type = CMSG_DATA;
1657         break;
1658     case CMSG_HASHED:
1659         if ((ret = CDecodeMsg_DecodeHashedContent(msg, blob)))
1660             msg->type = CMSG_HASHED;
1661         break;
1662     case CMSG_ENVELOPED:
1663         FIXME("unimplemented for type CMSG_ENVELOPED\n");
1664         ret = TRUE;
1665         break;
1666     case CMSG_SIGNED:
1667         if ((ret = CDecodeMsg_DecodeSignedContent(msg, blob)))
1668             msg->type = CMSG_SIGNED;
1669         break;
1670     default:
1671     {
1672         CRYPT_CONTENT_INFO *info;
1673         DWORD size;
1674
1675         ret = CryptDecodeObjectEx(X509_ASN_ENCODING, PKCS_CONTENT_INFO,
1676          msg->msg_data.pbData, msg->msg_data.cbData, CRYPT_DECODE_ALLOC_FLAG,
1677          NULL, (LPBYTE)&info, &size);
1678         if (ret)
1679         {
1680             if (!strcmp(info->pszObjId, szOID_RSA_data))
1681                 ret = CDecodeMsg_DecodeContent(msg, &info->Content, CMSG_DATA);
1682             else if (!strcmp(info->pszObjId, szOID_RSA_digestedData))
1683                 ret = CDecodeMsg_DecodeContent(msg, &info->Content,
1684                  CMSG_HASHED);
1685             else if (!strcmp(info->pszObjId, szOID_RSA_envelopedData))
1686                 ret = CDecodeMsg_DecodeContent(msg, &info->Content,
1687                  CMSG_ENVELOPED);
1688             else if (!strcmp(info->pszObjId, szOID_RSA_signedData))
1689                 ret = CDecodeMsg_DecodeContent(msg, &info->Content,
1690                  CMSG_SIGNED);
1691             else
1692             {
1693                 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
1694                 ret = FALSE;
1695             }
1696             LocalFree(info);
1697         }
1698     }
1699     }
1700     return ret;
1701 }
1702
1703 static BOOL CDecodeMsg_FinalizeHashedContent(CDecodeMsg *msg,
1704  CRYPT_DER_BLOB *blob)
1705 {
1706     CRYPT_ALGORITHM_IDENTIFIER *hashAlgoID = NULL;
1707     DWORD size = 0;
1708     ALG_ID algID = 0;
1709     BOOL ret;
1710
1711     CryptMsgGetParam(msg, CMSG_HASH_ALGORITHM_PARAM, 0, NULL, &size);
1712     hashAlgoID = CryptMemAlloc(size);
1713     ret = CryptMsgGetParam(msg, CMSG_HASH_ALGORITHM_PARAM, 0, hashAlgoID,
1714      &size);
1715     if (ret)
1716         algID = CertOIDToAlgId(hashAlgoID->pszObjId);
1717     ret = CryptCreateHash(msg->crypt_prov, algID, 0, 0, &msg->u.hash);
1718     if (ret)
1719     {
1720         CRYPT_DATA_BLOB content;
1721
1722         if (msg->base.open_flags & CMSG_DETACHED_FLAG)
1723         {
1724             /* Unlike for non-detached messages, the data were never stored as
1725              * the content param, but were saved in msg->detached_data instead.
1726              */
1727             content.pbData = msg->detached_data.pbData;
1728             content.cbData = msg->detached_data.cbData;
1729         }
1730         else
1731             ret = ContextPropertyList_FindProperty(msg->properties,
1732              CMSG_CONTENT_PARAM, &content);
1733         if (ret)
1734             ret = CryptHashData(msg->u.hash, content.pbData, content.cbData, 0);
1735     }
1736     CryptMemFree(hashAlgoID);
1737     return ret;
1738 }
1739
1740 static BOOL CDecodeMsg_FinalizeSignedContent(CDecodeMsg *msg,
1741  CRYPT_DER_BLOB *blob)
1742 {
1743     BOOL ret;
1744     DWORD i, size;
1745
1746     ret = CSignedMsgData_AllocateHandles(&msg->u.signed_data);
1747     for (i = 0; ret && i < msg->u.signed_data.info->cSignerInfo; i++)
1748         ret = CSignedMsgData_ConstructSignerHandles(&msg->u.signed_data, i,
1749          msg->crypt_prov);
1750     if (ret)
1751     {
1752         CRYPT_DATA_BLOB *content;
1753
1754         /* Now that we have all the content, update the hash handles with
1755          * it.  If the message is a detached message, the content is stored
1756          * in msg->detached_data rather than in the signed message's
1757          * content.
1758          */
1759         if (msg->base.open_flags & CMSG_DETACHED_FLAG)
1760             content = &msg->detached_data;
1761         else
1762             content = &msg->u.signed_data.info->content.Content;
1763         if (content->cbData)
1764         {
1765             /* If the message is not detached, have to decode the message's
1766              * content if the type is szOID_RSA_data.
1767              */
1768             if (!(msg->base.open_flags & CMSG_DETACHED_FLAG) &&
1769              !strcmp(msg->u.signed_data.info->content.pszObjId,
1770              szOID_RSA_data))
1771             {
1772                 CRYPT_DATA_BLOB *blob;
1773
1774                 ret = CryptDecodeObjectEx(X509_ASN_ENCODING,
1775                  X509_OCTET_STRING, content->pbData, content->cbData,
1776                  CRYPT_DECODE_ALLOC_FLAG, NULL, (LPBYTE)&blob, &size);
1777                 if (ret)
1778                 {
1779                     ret = CSignedMsgData_Update(&msg->u.signed_data,
1780                      blob->pbData, blob->cbData, TRUE, Verify);
1781                     LocalFree(blob);
1782                 }
1783             }
1784             else
1785                 ret = CSignedMsgData_Update(&msg->u.signed_data,
1786                  content->pbData, content->cbData, TRUE, Verify);
1787         }
1788     }
1789     return ret;
1790 }
1791
1792 static BOOL CDecodeMsg_FinalizeContent(CDecodeMsg *msg, CRYPT_DER_BLOB *blob)
1793 {
1794     BOOL ret = FALSE;
1795
1796     switch (msg->type)
1797     {
1798     case CMSG_HASHED:
1799         ret = CDecodeMsg_FinalizeHashedContent(msg, blob);
1800         break;
1801     case CMSG_SIGNED:
1802         ret = CDecodeMsg_FinalizeSignedContent(msg, blob);
1803         break;
1804     default:
1805         ret = TRUE;
1806     }
1807     return ret;
1808 }
1809
1810 static BOOL CDecodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
1811  DWORD cbData, BOOL fFinal)
1812 {
1813     CDecodeMsg *msg = (CDecodeMsg *)hCryptMsg;
1814     BOOL ret = FALSE;
1815
1816     TRACE("(%p, %p, %d, %d)\n", hCryptMsg, pbData, cbData, fFinal);
1817
1818     if (msg->base.state == MsgStateFinalized)
1819         SetLastError(CRYPT_E_MSG_ERROR);
1820     else if (msg->base.streamed)
1821     {
1822         FIXME("(%p, %p, %d, %d): streamed update stub\n", hCryptMsg, pbData,
1823          cbData, fFinal);
1824         switch (msg->base.state)
1825         {
1826         case MsgStateInit:
1827             ret = CDecodeMsg_CopyData(&msg->msg_data, pbData, cbData);
1828             if (fFinal)
1829             {
1830                 if (msg->base.open_flags & CMSG_DETACHED_FLAG)
1831                     msg->base.state = MsgStateDataFinalized;
1832                 else
1833                     msg->base.state = MsgStateFinalized;
1834             }
1835             else
1836                 msg->base.state = MsgStateUpdated;
1837             break;
1838         case MsgStateUpdated:
1839             ret = CDecodeMsg_CopyData(&msg->msg_data, pbData, cbData);
1840             if (fFinal)
1841             {
1842                 if (msg->base.open_flags & CMSG_DETACHED_FLAG)
1843                     msg->base.state = MsgStateDataFinalized;
1844                 else
1845                     msg->base.state = MsgStateFinalized;
1846             }
1847             break;
1848         case MsgStateDataFinalized:
1849             ret = CDecodeMsg_CopyData(&msg->detached_data, pbData, cbData);
1850             if (fFinal)
1851                 msg->base.state = MsgStateFinalized;
1852             break;
1853         default:
1854             SetLastError(CRYPT_E_MSG_ERROR);
1855             break;
1856         }
1857     }
1858     else
1859     {
1860         if (!fFinal)
1861             SetLastError(CRYPT_E_MSG_ERROR);
1862         else
1863         {
1864             switch (msg->base.state)
1865             {
1866             case MsgStateInit:
1867                 ret = CDecodeMsg_CopyData(&msg->msg_data, pbData, cbData);
1868                 if (msg->base.open_flags & CMSG_DETACHED_FLAG)
1869                     msg->base.state = MsgStateDataFinalized;
1870                 else
1871                     msg->base.state = MsgStateFinalized;
1872                 break;
1873             case MsgStateDataFinalized:
1874                 ret = CDecodeMsg_CopyData(&msg->detached_data, pbData, cbData);
1875                 msg->base.state = MsgStateFinalized;
1876                 break;
1877             default:
1878                 SetLastError(CRYPT_E_MSG_ERROR);
1879             }
1880         }
1881     }
1882     if (ret && fFinal &&
1883      ((msg->base.open_flags & CMSG_DETACHED_FLAG && msg->base.state ==
1884      MsgStateDataFinalized) ||
1885      (!(msg->base.open_flags & CMSG_DETACHED_FLAG) && msg->base.state ==
1886      MsgStateFinalized)))
1887         ret = CDecodeMsg_DecodeContent(msg, &msg->msg_data, msg->type);
1888     if (ret && msg->base.state == MsgStateFinalized)
1889         ret = CDecodeMsg_FinalizeContent(msg, &msg->msg_data);
1890     return ret;
1891 }
1892
1893 static BOOL CDecodeHashMsg_GetParam(CDecodeMsg *msg, DWORD dwParamType,
1894  DWORD dwIndex, void *pvData, DWORD *pcbData)
1895 {
1896     BOOL ret = FALSE;
1897
1898     switch (dwParamType)
1899     {
1900     case CMSG_TYPE_PARAM:
1901         ret = CRYPT_CopyParam(pvData, pcbData, &msg->type, sizeof(msg->type));
1902         break;
1903     case CMSG_HASH_ALGORITHM_PARAM:
1904     {
1905         CRYPT_DATA_BLOB blob;
1906
1907         ret = ContextPropertyList_FindProperty(msg->properties, dwParamType,
1908          &blob);
1909         if (ret)
1910         {
1911             ret = CRYPT_CopyParam(pvData, pcbData, blob.pbData, blob.cbData);
1912             if (ret && pvData)
1913                 CRYPT_FixUpAlgorithmID((CRYPT_ALGORITHM_IDENTIFIER *)pvData);
1914         }
1915         else
1916             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
1917         break;
1918     }
1919     case CMSG_COMPUTED_HASH_PARAM:
1920         ret = CryptGetHashParam(msg->u.hash, HP_HASHVAL, pvData, pcbData, 0);
1921         break;
1922     default:
1923     {
1924         CRYPT_DATA_BLOB blob;
1925
1926         ret = ContextPropertyList_FindProperty(msg->properties, dwParamType,
1927          &blob);
1928         if (ret)
1929             ret = CRYPT_CopyParam(pvData, pcbData, blob.pbData, blob.cbData);
1930         else
1931             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
1932     }
1933     }
1934     return ret;
1935 }
1936
1937 /* nextData is an in/out parameter - on input it's the memory location in
1938  * which a copy of in's data should be made, and on output it's the memory
1939  * location immediately after out's copy of in's data.
1940  */
1941 static inline void CRYPT_CopyBlob(CRYPT_DATA_BLOB *out,
1942  const CRYPT_DATA_BLOB *in, LPBYTE *nextData)
1943 {
1944     out->cbData = in->cbData;
1945     if (in->cbData)
1946     {
1947         out->pbData = *nextData;
1948         memcpy(out->pbData, in->pbData, in->cbData);
1949         *nextData += in->cbData;
1950     }
1951 }
1952
1953 static inline void CRYPT_CopyAlgorithmId(CRYPT_ALGORITHM_IDENTIFIER *out,
1954  const CRYPT_ALGORITHM_IDENTIFIER *in, LPBYTE *nextData)
1955 {
1956     if (in->pszObjId)
1957     {
1958         out->pszObjId = (LPSTR)*nextData;
1959         strcpy(out->pszObjId, in->pszObjId);
1960         *nextData += strlen(out->pszObjId) + 1;
1961     }
1962     CRYPT_CopyBlob(&out->Parameters, &in->Parameters, nextData);
1963 }
1964
1965 static inline void CRYPT_CopyAttributes(CRYPT_ATTRIBUTES *out,
1966  const CRYPT_ATTRIBUTES *in, LPBYTE *nextData)
1967 {
1968     out->cAttr = in->cAttr;
1969     if (in->cAttr)
1970     {
1971         DWORD i;
1972
1973         *nextData = POINTER_ALIGN_DWORD_PTR(*nextData);
1974         out->rgAttr = (CRYPT_ATTRIBUTE *)*nextData;
1975         *nextData += in->cAttr * sizeof(CRYPT_ATTRIBUTE);
1976         for (i = 0; i < in->cAttr; i++)
1977         {
1978             if (in->rgAttr[i].pszObjId)
1979             {
1980                 out->rgAttr[i].pszObjId = (LPSTR)*nextData;
1981                 strcpy(out->rgAttr[i].pszObjId, in->rgAttr[i].pszObjId);
1982                 *nextData += strlen(in->rgAttr[i].pszObjId) + 1;
1983             }
1984             if (in->rgAttr[i].cValue)
1985             {
1986                 DWORD j;
1987
1988                 out->rgAttr[i].cValue = in->rgAttr[i].cValue;
1989                 *nextData = POINTER_ALIGN_DWORD_PTR(*nextData);
1990                 out->rgAttr[i].rgValue = (PCRYPT_DATA_BLOB)*nextData;
1991                 *nextData += in->rgAttr[i].cValue * sizeof(CRYPT_DATA_BLOB);
1992                 for (j = 0; j < in->rgAttr[i].cValue; j++)
1993                     CRYPT_CopyBlob(&out->rgAttr[i].rgValue[j],
1994                      &in->rgAttr[i].rgValue[j], nextData);
1995             }
1996         }
1997     }
1998 }
1999
2000 static DWORD CRYPT_SizeOfAttributes(const CRYPT_ATTRIBUTES *attr)
2001 {
2002     DWORD size = attr->cAttr * sizeof(CRYPT_ATTRIBUTE), i, j;
2003
2004     for (i = 0; i < attr->cAttr; i++)
2005     {
2006         if (attr->rgAttr[i].pszObjId)
2007             size += strlen(attr->rgAttr[i].pszObjId) + 1;
2008         /* align pointer */
2009         size = ALIGN_DWORD_PTR(size);
2010         size += attr->rgAttr[i].cValue * sizeof(CRYPT_DATA_BLOB);
2011         for (j = 0; j < attr->rgAttr[i].cValue; j++)
2012             size += attr->rgAttr[i].rgValue[j].cbData;
2013     }
2014     /* align pointer again to be conservative */
2015     size = ALIGN_DWORD_PTR(size);
2016     return size;
2017 }
2018
2019 static DWORD CRYPT_SizeOfKeyIdAsIssuerAndSerial(const CRYPT_DATA_BLOB *keyId)
2020 {
2021     static char oid_key_rdn[] = szOID_KEYID_RDN;
2022     DWORD size = 0;
2023     CERT_RDN_ATTR attr;
2024     CERT_RDN rdn = { 1, &attr };
2025     CERT_NAME_INFO name = { 1, &rdn };
2026
2027     attr.pszObjId = oid_key_rdn;
2028     attr.dwValueType = CERT_RDN_OCTET_STRING;
2029     attr.Value.cbData = keyId->cbData;
2030     attr.Value.pbData = keyId->pbData;
2031     if (CryptEncodeObject(X509_ASN_ENCODING, X509_NAME, &name, NULL, &size))
2032         size++; /* Only include size of special zero serial number on success */
2033     return size;
2034 }
2035
2036 static BOOL CRYPT_CopyKeyIdAsIssuerAndSerial(CERT_NAME_BLOB *issuer,
2037  CRYPT_INTEGER_BLOB *serialNumber, const CRYPT_DATA_BLOB *keyId, DWORD encodedLen,
2038  LPBYTE *nextData)
2039 {
2040     static char oid_key_rdn[] = szOID_KEYID_RDN;
2041     CERT_RDN_ATTR attr;
2042     CERT_RDN rdn = { 1, &attr };
2043     CERT_NAME_INFO name = { 1, &rdn };
2044     BOOL ret;
2045
2046     /* Encode special zero serial number */
2047     serialNumber->cbData = 1;
2048     serialNumber->pbData = *nextData;
2049     **nextData = 0;
2050     (*nextData)++;
2051     /* Encode issuer */
2052     issuer->pbData = *nextData;
2053     attr.pszObjId = oid_key_rdn;
2054     attr.dwValueType = CERT_RDN_OCTET_STRING;
2055     attr.Value.cbData = keyId->cbData;
2056     attr.Value.pbData = keyId->pbData;
2057     ret = CryptEncodeObject(X509_ASN_ENCODING, X509_NAME, &name, *nextData,
2058      &encodedLen);
2059     if (ret)
2060     {
2061         *nextData += encodedLen;
2062         issuer->cbData = encodedLen;
2063     }
2064     return ret;
2065 }
2066
2067 static BOOL CRYPT_CopySignerInfo(void *pvData, DWORD *pcbData,
2068  const CMSG_CMS_SIGNER_INFO *in)
2069 {
2070     DWORD size = sizeof(CMSG_SIGNER_INFO), rdnSize = 0;
2071     BOOL ret;
2072
2073     TRACE("(%p, %d, %p)\n", pvData, pvData ? *pcbData : 0, in);
2074
2075     if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
2076     {
2077         size += in->SignerId.u.IssuerSerialNumber.Issuer.cbData;
2078         size += in->SignerId.u.IssuerSerialNumber.SerialNumber.cbData;
2079     }
2080     else
2081     {
2082         rdnSize = CRYPT_SizeOfKeyIdAsIssuerAndSerial(&in->SignerId.u.KeyId);
2083         size += rdnSize;
2084     }
2085     if (in->HashAlgorithm.pszObjId)
2086         size += strlen(in->HashAlgorithm.pszObjId) + 1;
2087     size += in->HashAlgorithm.Parameters.cbData;
2088     if (in->HashEncryptionAlgorithm.pszObjId)
2089         size += strlen(in->HashEncryptionAlgorithm.pszObjId) + 1;
2090     size += in->HashEncryptionAlgorithm.Parameters.cbData;
2091     size += in->EncryptedHash.cbData;
2092     /* align pointer */
2093     size = ALIGN_DWORD_PTR(size);
2094     size += CRYPT_SizeOfAttributes(&in->AuthAttrs);
2095     size += CRYPT_SizeOfAttributes(&in->UnauthAttrs);
2096     if (!pvData)
2097     {
2098         *pcbData = size;
2099         ret = TRUE;
2100     }
2101     else if (*pcbData < size)
2102     {
2103         *pcbData = size;
2104         SetLastError(ERROR_MORE_DATA);
2105         ret = FALSE;
2106     }
2107     else
2108     {
2109         LPBYTE nextData = (BYTE *)pvData + sizeof(CMSG_SIGNER_INFO);
2110         CMSG_SIGNER_INFO *out = (CMSG_SIGNER_INFO *)pvData;
2111
2112         ret = TRUE;
2113         out->dwVersion = in->dwVersion;
2114         if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
2115         {
2116             CRYPT_CopyBlob(&out->Issuer,
2117              &in->SignerId.u.IssuerSerialNumber.Issuer, &nextData);
2118             CRYPT_CopyBlob(&out->SerialNumber,
2119              &in->SignerId.u.IssuerSerialNumber.SerialNumber, &nextData);
2120         }
2121         else
2122             ret = CRYPT_CopyKeyIdAsIssuerAndSerial(&out->Issuer, &out->SerialNumber,
2123              &in->SignerId.u.KeyId, rdnSize, &nextData);
2124         if (ret)
2125         {
2126             CRYPT_CopyAlgorithmId(&out->HashAlgorithm, &in->HashAlgorithm,
2127              &nextData);
2128             CRYPT_CopyAlgorithmId(&out->HashEncryptionAlgorithm,
2129              &in->HashEncryptionAlgorithm, &nextData);
2130             CRYPT_CopyBlob(&out->EncryptedHash, &in->EncryptedHash, &nextData);
2131             nextData = POINTER_ALIGN_DWORD_PTR(nextData);
2132             CRYPT_CopyAttributes(&out->AuthAttrs, &in->AuthAttrs, &nextData);
2133             CRYPT_CopyAttributes(&out->UnauthAttrs, &in->UnauthAttrs, &nextData);
2134         }
2135     }
2136     TRACE("returning %d\n", ret);
2137     return ret;
2138 }
2139
2140 static BOOL CRYPT_CopyCMSSignerInfo(void *pvData, DWORD *pcbData,
2141  const CMSG_CMS_SIGNER_INFO *in)
2142 {
2143     DWORD size = sizeof(CMSG_CMS_SIGNER_INFO);
2144     BOOL ret;
2145
2146     TRACE("(%p, %d, %p)\n", pvData, pvData ? *pcbData : 0, in);
2147
2148     if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
2149     {
2150         size += in->SignerId.u.IssuerSerialNumber.Issuer.cbData;
2151         size += in->SignerId.u.IssuerSerialNumber.SerialNumber.cbData;
2152     }
2153     else
2154         size += in->SignerId.u.KeyId.cbData;
2155     if (in->HashAlgorithm.pszObjId)
2156         size += strlen(in->HashAlgorithm.pszObjId) + 1;
2157     size += in->HashAlgorithm.Parameters.cbData;
2158     if (in->HashEncryptionAlgorithm.pszObjId)
2159         size += strlen(in->HashEncryptionAlgorithm.pszObjId) + 1;
2160     size += in->HashEncryptionAlgorithm.Parameters.cbData;
2161     size += in->EncryptedHash.cbData;
2162     /* align pointer */
2163     size = ALIGN_DWORD_PTR(size);
2164     size += CRYPT_SizeOfAttributes(&in->AuthAttrs);
2165     size += CRYPT_SizeOfAttributes(&in->UnauthAttrs);
2166     if (!pvData)
2167     {
2168         *pcbData = size;
2169         ret = TRUE;
2170     }
2171     else if (*pcbData < size)
2172     {
2173         *pcbData = size;
2174         SetLastError(ERROR_MORE_DATA);
2175         ret = FALSE;
2176     }
2177     else
2178     {
2179         LPBYTE nextData = (BYTE *)pvData + sizeof(CMSG_CMS_SIGNER_INFO);
2180         CMSG_CMS_SIGNER_INFO *out = (CMSG_CMS_SIGNER_INFO *)pvData;
2181
2182         out->dwVersion = in->dwVersion;
2183         out->SignerId.dwIdChoice = in->SignerId.dwIdChoice;
2184         if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
2185         {
2186             CRYPT_CopyBlob(&out->SignerId.u.IssuerSerialNumber.Issuer,
2187              &in->SignerId.u.IssuerSerialNumber.Issuer, &nextData);
2188             CRYPT_CopyBlob(&out->SignerId.u.IssuerSerialNumber.SerialNumber,
2189              &in->SignerId.u.IssuerSerialNumber.SerialNumber, &nextData);
2190         }
2191         else
2192             CRYPT_CopyBlob(&out->SignerId.u.KeyId, &in->SignerId.u.KeyId, &nextData);
2193         CRYPT_CopyAlgorithmId(&out->HashAlgorithm, &in->HashAlgorithm,
2194          &nextData);
2195         CRYPT_CopyAlgorithmId(&out->HashEncryptionAlgorithm,
2196          &in->HashEncryptionAlgorithm, &nextData);
2197         CRYPT_CopyBlob(&out->EncryptedHash, &in->EncryptedHash, &nextData);
2198         nextData = POINTER_ALIGN_DWORD_PTR(nextData);
2199         CRYPT_CopyAttributes(&out->AuthAttrs, &in->AuthAttrs, &nextData);
2200         CRYPT_CopyAttributes(&out->UnauthAttrs, &in->UnauthAttrs, &nextData);
2201         ret = TRUE;
2202     }
2203     TRACE("returning %d\n", ret);
2204     return ret;
2205 }
2206
2207 static BOOL CRYPT_CopySignerCertInfo(void *pvData, DWORD *pcbData,
2208  const CMSG_CMS_SIGNER_INFO *in)
2209 {
2210     DWORD size = sizeof(CERT_INFO), rdnSize = 0;
2211     BOOL ret;
2212
2213     TRACE("(%p, %d, %p)\n", pvData, pvData ? *pcbData : 0, in);
2214
2215     if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
2216     {
2217         size += in->SignerId.u.IssuerSerialNumber.Issuer.cbData;
2218         size += in->SignerId.u.IssuerSerialNumber.SerialNumber.cbData;
2219     }
2220     else
2221     {
2222         rdnSize = CRYPT_SizeOfKeyIdAsIssuerAndSerial(&in->SignerId.u.KeyId);
2223         size += rdnSize;
2224     }
2225     if (!pvData)
2226     {
2227         *pcbData = size;
2228         ret = TRUE;
2229     }
2230     else if (*pcbData < size)
2231     {
2232         *pcbData = size;
2233         SetLastError(ERROR_MORE_DATA);
2234         ret = FALSE;
2235     }
2236     else
2237     {
2238         LPBYTE nextData = (BYTE *)pvData + sizeof(CERT_INFO);
2239         CERT_INFO *out = (CERT_INFO *)pvData;
2240
2241         memset(out, 0, sizeof(CERT_INFO));
2242         if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
2243         {
2244             CRYPT_CopyBlob(&out->Issuer,
2245              &in->SignerId.u.IssuerSerialNumber.Issuer, &nextData);
2246             CRYPT_CopyBlob(&out->SerialNumber,
2247              &in->SignerId.u.IssuerSerialNumber.SerialNumber, &nextData);
2248             ret = TRUE;
2249         }
2250         else
2251             ret = CRYPT_CopyKeyIdAsIssuerAndSerial(&out->Issuer, &out->SerialNumber,
2252              &in->SignerId.u.KeyId, rdnSize, &nextData);
2253     }
2254     TRACE("returning %d\n", ret);
2255     return ret;
2256 }
2257
2258 static BOOL CDecodeSignedMsg_GetParam(CDecodeMsg *msg, DWORD dwParamType,
2259  DWORD dwIndex, void *pvData, DWORD *pcbData)
2260 {
2261     BOOL ret = FALSE;
2262
2263     switch (dwParamType)
2264     {
2265     case CMSG_TYPE_PARAM:
2266         ret = CRYPT_CopyParam(pvData, pcbData, &msg->type, sizeof(msg->type));
2267         break;
2268     case CMSG_CONTENT_PARAM:
2269         if (msg->u.signed_data.info)
2270         {
2271             if (!strcmp(msg->u.signed_data.info->content.pszObjId,
2272              szOID_RSA_data))
2273             {
2274                 CRYPT_DATA_BLOB *blob;
2275                 DWORD size;
2276
2277                 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING,
2278                  msg->u.signed_data.info->content.Content.pbData,
2279                  msg->u.signed_data.info->content.Content.cbData,
2280                  CRYPT_DECODE_ALLOC_FLAG, NULL, (LPBYTE)&blob, &size);
2281                 if (ret)
2282                 {
2283                     ret = CRYPT_CopyParam(pvData, pcbData, blob->pbData,
2284                      blob->cbData);
2285                     LocalFree(blob);
2286                 }
2287             }
2288             else
2289                 ret = CRYPT_CopyParam(pvData, pcbData,
2290                  msg->u.signed_data.info->content.Content.pbData,
2291                  msg->u.signed_data.info->content.Content.cbData);
2292         }
2293         else
2294             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2295         break;
2296     case CMSG_INNER_CONTENT_TYPE_PARAM:
2297         if (msg->u.signed_data.info)
2298             ret = CRYPT_CopyParam(pvData, pcbData,
2299              msg->u.signed_data.info->content.pszObjId,
2300              strlen(msg->u.signed_data.info->content.pszObjId) + 1);
2301         else
2302             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2303         break;
2304     case CMSG_SIGNER_COUNT_PARAM:
2305         if (msg->u.signed_data.info)
2306             ret = CRYPT_CopyParam(pvData, pcbData,
2307              &msg->u.signed_data.info->cSignerInfo, sizeof(DWORD));
2308         else
2309             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2310         break;
2311     case CMSG_SIGNER_INFO_PARAM:
2312         if (msg->u.signed_data.info)
2313         {
2314             if (dwIndex >= msg->u.signed_data.info->cSignerInfo)
2315                 SetLastError(CRYPT_E_INVALID_INDEX);
2316             else
2317                 ret = CRYPT_CopySignerInfo(pvData, pcbData,
2318                  &msg->u.signed_data.info->rgSignerInfo[dwIndex]);
2319         }
2320         else
2321             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2322         break;
2323     case CMSG_SIGNER_CERT_INFO_PARAM:
2324         if (msg->u.signed_data.info)
2325         {
2326             if (dwIndex >= msg->u.signed_data.info->cSignerInfo)
2327                 SetLastError(CRYPT_E_INVALID_INDEX);
2328             else
2329                 ret = CRYPT_CopySignerCertInfo(pvData, pcbData,
2330                  &msg->u.signed_data.info->rgSignerInfo[dwIndex]);
2331         }
2332         else
2333             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2334         break;
2335     case CMSG_CERT_COUNT_PARAM:
2336         if (msg->u.signed_data.info)
2337             ret = CRYPT_CopyParam(pvData, pcbData,
2338              &msg->u.signed_data.info->cCertEncoded, sizeof(DWORD));
2339         else
2340             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2341         break;
2342     case CMSG_CERT_PARAM:
2343         if (msg->u.signed_data.info)
2344         {
2345             if (dwIndex >= msg->u.signed_data.info->cCertEncoded)
2346                 SetLastError(CRYPT_E_INVALID_INDEX);
2347             else
2348                 ret = CRYPT_CopyParam(pvData, pcbData,
2349                  msg->u.signed_data.info->rgCertEncoded[dwIndex].pbData,
2350                  msg->u.signed_data.info->rgCertEncoded[dwIndex].cbData);
2351         }
2352         else
2353             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2354         break;
2355     case CMSG_CRL_COUNT_PARAM:
2356         if (msg->u.signed_data.info)
2357             ret = CRYPT_CopyParam(pvData, pcbData,
2358              &msg->u.signed_data.info->cCrlEncoded, sizeof(DWORD));
2359         else
2360             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2361         break;
2362     case CMSG_CRL_PARAM:
2363         if (msg->u.signed_data.info)
2364         {
2365             if (dwIndex >= msg->u.signed_data.info->cCrlEncoded)
2366                 SetLastError(CRYPT_E_INVALID_INDEX);
2367             else
2368                 ret = CRYPT_CopyParam(pvData, pcbData,
2369                  msg->u.signed_data.info->rgCrlEncoded[dwIndex].pbData,
2370                  msg->u.signed_data.info->rgCrlEncoded[dwIndex].cbData);
2371         }
2372         else
2373             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2374         break;
2375     case CMSG_COMPUTED_HASH_PARAM:
2376         if (msg->u.signed_data.info)
2377         {
2378             if (dwIndex >= msg->u.signed_data.cSignerHandle)
2379                 SetLastError(CRYPT_E_INVALID_INDEX);
2380             else
2381                 ret = CryptGetHashParam(
2382                  msg->u.signed_data.signerHandles[dwIndex].contentHash,
2383                  HP_HASHVAL, pvData, pcbData, 0);
2384         }
2385         else
2386             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2387         break;
2388     case CMSG_ATTR_CERT_COUNT_PARAM:
2389         if (msg->u.signed_data.info)
2390         {
2391             DWORD attrCertCount = 0;
2392
2393             ret = CRYPT_CopyParam(pvData, pcbData,
2394              &attrCertCount, sizeof(DWORD));
2395         }
2396         else
2397             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2398         break;
2399     case CMSG_ATTR_CERT_PARAM:
2400         if (msg->u.signed_data.info)
2401             SetLastError(CRYPT_E_INVALID_INDEX);
2402         else
2403             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2404         break;
2405     case CMSG_CMS_SIGNER_INFO_PARAM:
2406         if (msg->u.signed_data.info)
2407         {
2408             if (dwIndex >= msg->u.signed_data.info->cSignerInfo)
2409                 SetLastError(CRYPT_E_INVALID_INDEX);
2410             else
2411                 ret = CRYPT_CopyCMSSignerInfo(pvData, pcbData,
2412                  &msg->u.signed_data.info->rgSignerInfo[dwIndex]);
2413         }
2414         else
2415             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2416         break;
2417     default:
2418         FIXME("unimplemented for %d\n", dwParamType);
2419         SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2420     }
2421     return ret;
2422 }
2423
2424 static BOOL CDecodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
2425  DWORD dwIndex, void *pvData, DWORD *pcbData)
2426 {
2427     CDecodeMsg *msg = (CDecodeMsg *)hCryptMsg;
2428     BOOL ret = FALSE;
2429
2430     switch (msg->type)
2431     {
2432     case CMSG_HASHED:
2433         ret = CDecodeHashMsg_GetParam(msg, dwParamType, dwIndex, pvData,
2434          pcbData);
2435         break;
2436     case CMSG_SIGNED:
2437         ret = CDecodeSignedMsg_GetParam(msg, dwParamType, dwIndex, pvData,
2438          pcbData);
2439         break;
2440     default:
2441         switch (dwParamType)
2442         {
2443         case CMSG_TYPE_PARAM:
2444             ret = CRYPT_CopyParam(pvData, pcbData, &msg->type,
2445              sizeof(msg->type));
2446             break;
2447         default:
2448         {
2449             CRYPT_DATA_BLOB blob;
2450
2451             ret = ContextPropertyList_FindProperty(msg->properties, dwParamType,
2452              &blob);
2453             if (ret)
2454                 ret = CRYPT_CopyParam(pvData, pcbData, blob.pbData,
2455                  blob.cbData);
2456             else
2457                 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2458         }
2459         }
2460     }
2461     return ret;
2462 }
2463
2464 static BOOL CDecodeHashMsg_VerifyHash(CDecodeMsg *msg)
2465 {
2466     BOOL ret;
2467     CRYPT_DATA_BLOB hashBlob;
2468
2469     ret = ContextPropertyList_FindProperty(msg->properties,
2470      CMSG_HASH_DATA_PARAM, &hashBlob);
2471     if (ret)
2472     {
2473         DWORD computedHashSize = 0;
2474
2475         ret = CDecodeHashMsg_GetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, NULL,
2476          &computedHashSize);
2477         if (hashBlob.cbData == computedHashSize)
2478         {
2479             LPBYTE computedHash = CryptMemAlloc(computedHashSize);
2480
2481             if (computedHash)
2482             {
2483                 ret = CDecodeHashMsg_GetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0,
2484                  computedHash, &computedHashSize);
2485                 if (ret)
2486                 {
2487                     if (memcmp(hashBlob.pbData, computedHash, hashBlob.cbData))
2488                     {
2489                         SetLastError(CRYPT_E_HASH_VALUE);
2490                         ret = FALSE;
2491                     }
2492                 }
2493                 CryptMemFree(computedHash);
2494             }
2495             else
2496             {
2497                 SetLastError(ERROR_OUTOFMEMORY);
2498                 ret = FALSE;
2499             }
2500         }
2501         else
2502         {
2503             SetLastError(CRYPT_E_HASH_VALUE);
2504             ret = FALSE;
2505         }
2506     }
2507     return ret;
2508 }
2509
2510 static BOOL CDecodeSignedMsg_VerifySignatureWithKey(CDecodeMsg *msg,
2511  HCRYPTPROV prov, DWORD signerIndex, PCERT_PUBLIC_KEY_INFO keyInfo)
2512 {
2513     HCRYPTKEY key;
2514     BOOL ret;
2515
2516     if (!prov)
2517         prov = msg->crypt_prov;
2518     ret = CryptImportPublicKeyInfo(prov, X509_ASN_ENCODING, keyInfo, &key);
2519     if (ret)
2520     {
2521         HCRYPTHASH hash;
2522         CRYPT_HASH_BLOB reversedHash;
2523
2524         if (msg->u.signed_data.info->rgSignerInfo[signerIndex].AuthAttrs.cAttr)
2525             hash = msg->u.signed_data.signerHandles[signerIndex].authAttrHash;
2526         else
2527             hash = msg->u.signed_data.signerHandles[signerIndex].contentHash;
2528         ret = CRYPT_ConstructBlob(&reversedHash,
2529          &msg->u.signed_data.info->rgSignerInfo[signerIndex].EncryptedHash);
2530         if (ret)
2531         {
2532             CRYPT_ReverseBytes(&reversedHash);
2533             ret = CryptVerifySignatureW(hash, reversedHash.pbData,
2534              reversedHash.cbData, key, NULL, 0);
2535             CryptMemFree(reversedHash.pbData);
2536         }
2537         CryptDestroyKey(key);
2538     }
2539     return ret;
2540 }
2541
2542 static BOOL CDecodeSignedMsg_VerifySignature(CDecodeMsg *msg, PCERT_INFO info)
2543 {
2544     BOOL ret = FALSE;
2545     DWORD i;
2546
2547     if (!msg->u.signed_data.signerHandles)
2548     {
2549         SetLastError(NTE_BAD_SIGNATURE);
2550         return FALSE;
2551     }
2552     for (i = 0; !ret && i < msg->u.signed_data.info->cSignerInfo; i++)
2553     {
2554         PCMSG_CMS_SIGNER_INFO signerInfo =
2555          &msg->u.signed_data.info->rgSignerInfo[i];
2556
2557         if (signerInfo->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
2558         {
2559             ret = CertCompareCertificateName(X509_ASN_ENCODING,
2560              &signerInfo->SignerId.u.IssuerSerialNumber.Issuer,
2561              &info->Issuer);
2562             if (ret)
2563             {
2564                 ret = CertCompareIntegerBlob(
2565                  &signerInfo->SignerId.u.IssuerSerialNumber.SerialNumber,
2566                  &info->SerialNumber);
2567                 if (ret)
2568                     break;
2569             }
2570         }
2571         else
2572         {
2573             FIXME("signer %d: unimplemented for key id\n", i);
2574         }
2575     }
2576     if (ret)
2577         ret = CDecodeSignedMsg_VerifySignatureWithKey(msg, 0, i,
2578          &info->SubjectPublicKeyInfo);
2579     else
2580         SetLastError(CRYPT_E_SIGNER_NOT_FOUND);
2581
2582     return ret;
2583 }
2584
2585 static BOOL CDecodeSignedMsg_VerifySignatureEx(CDecodeMsg *msg,
2586  PCMSG_CTRL_VERIFY_SIGNATURE_EX_PARA para)
2587 {
2588     BOOL ret = FALSE;
2589
2590     if (para->cbSize != sizeof(CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA))
2591         SetLastError(ERROR_INVALID_PARAMETER);
2592     else if (para->dwSignerIndex >= msg->u.signed_data.info->cSignerInfo)
2593         SetLastError(CRYPT_E_SIGNER_NOT_FOUND);
2594     else if (!msg->u.signed_data.signerHandles)
2595         SetLastError(NTE_BAD_SIGNATURE);
2596     else
2597     {
2598         switch (para->dwSignerType)
2599         {
2600         case CMSG_VERIFY_SIGNER_PUBKEY:
2601             ret = CDecodeSignedMsg_VerifySignatureWithKey(msg,
2602              para->hCryptProv, para->dwSignerIndex,
2603              (PCERT_PUBLIC_KEY_INFO)para->pvSigner);
2604             break;
2605         case CMSG_VERIFY_SIGNER_CERT:
2606         {
2607             PCCERT_CONTEXT cert = (PCCERT_CONTEXT)para->pvSigner;
2608
2609             ret = CDecodeSignedMsg_VerifySignatureWithKey(msg, para->hCryptProv,
2610              para->dwSignerIndex, &cert->pCertInfo->SubjectPublicKeyInfo);
2611             break;
2612         }
2613         default:
2614             FIXME("unimplemented for signer type %d\n", para->dwSignerType);
2615             SetLastError(CRYPT_E_SIGNER_NOT_FOUND);
2616         }
2617     }
2618     return ret;
2619 }
2620
2621 static BOOL CDecodeMsg_Control(HCRYPTMSG hCryptMsg, DWORD dwFlags,
2622  DWORD dwCtrlType, const void *pvCtrlPara)
2623 {
2624     CDecodeMsg *msg = (CDecodeMsg *)hCryptMsg;
2625     BOOL ret = FALSE;
2626
2627     switch (dwCtrlType)
2628     {
2629     case CMSG_CTRL_VERIFY_SIGNATURE:
2630         switch (msg->type)
2631         {
2632         case CMSG_SIGNED:
2633             ret = CDecodeSignedMsg_VerifySignature(msg, (PCERT_INFO)pvCtrlPara);
2634             break;
2635         default:
2636             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2637         }
2638         break;
2639     case CMSG_CTRL_DECRYPT:
2640         switch (msg->type)
2641         {
2642         default:
2643             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2644         }
2645         break;
2646     case CMSG_CTRL_VERIFY_HASH:
2647         switch (msg->type)
2648         {
2649         case CMSG_HASHED:
2650             ret = CDecodeHashMsg_VerifyHash(msg);
2651             break;
2652         default:
2653             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2654         }
2655         break;
2656     case CMSG_CTRL_VERIFY_SIGNATURE_EX:
2657         switch (msg->type)
2658         {
2659         case CMSG_SIGNED:
2660             ret = CDecodeSignedMsg_VerifySignatureEx(msg,
2661              (PCMSG_CTRL_VERIFY_SIGNATURE_EX_PARA)pvCtrlPara);
2662             break;
2663         default:
2664             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
2665         }
2666         break;
2667     default:
2668         SetLastError(CRYPT_E_CONTROL_TYPE);
2669     }
2670     return ret;
2671 }
2672
2673 HCRYPTMSG WINAPI CryptMsgOpenToDecode(DWORD dwMsgEncodingType, DWORD dwFlags,
2674  DWORD dwMsgType, HCRYPTPROV_LEGACY hCryptProv, PCERT_INFO pRecipientInfo,
2675  PCMSG_STREAM_INFO pStreamInfo)
2676 {
2677     CDecodeMsg *msg;
2678
2679     TRACE("(%08x, %08x, %08x, %08lx, %p, %p)\n", dwMsgEncodingType,
2680      dwFlags, dwMsgType, hCryptProv, pRecipientInfo, pStreamInfo);
2681
2682     if (GET_CMSG_ENCODING_TYPE(dwMsgEncodingType) != PKCS_7_ASN_ENCODING)
2683     {
2684         SetLastError(E_INVALIDARG);
2685         return NULL;
2686     }
2687     msg = CryptMemAlloc(sizeof(CDecodeMsg));
2688     if (msg)
2689     {
2690         CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo,
2691          CDecodeMsg_Close, CDecodeMsg_GetParam, CDecodeMsg_Update,
2692          CDecodeMsg_Control);
2693         msg->type = dwMsgType;
2694         if (hCryptProv)
2695             msg->crypt_prov = hCryptProv;
2696         else
2697         {
2698             msg->crypt_prov = CRYPT_GetDefaultProvider();
2699             msg->base.open_flags &= ~CMSG_CRYPT_RELEASE_CONTEXT_FLAG;
2700         }
2701         memset(&msg->u, 0, sizeof(msg->u));
2702         msg->msg_data.cbData = 0;
2703         msg->msg_data.pbData = NULL;
2704         msg->detached_data.cbData = 0;
2705         msg->detached_data.pbData = NULL;
2706         msg->properties = ContextPropertyList_Create();
2707     }
2708     return msg;
2709 }
2710
2711 HCRYPTMSG WINAPI CryptMsgDuplicate(HCRYPTMSG hCryptMsg)
2712 {
2713     TRACE("(%p)\n", hCryptMsg);
2714
2715     if (hCryptMsg)
2716     {
2717         CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg;
2718
2719         InterlockedIncrement(&msg->ref);
2720     }
2721     return hCryptMsg;
2722 }
2723
2724 BOOL WINAPI CryptMsgClose(HCRYPTMSG hCryptMsg)
2725 {
2726     TRACE("(%p)\n", hCryptMsg);
2727
2728     if (hCryptMsg)
2729     {
2730         CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg;
2731
2732         if (InterlockedDecrement(&msg->ref) == 0)
2733         {
2734             TRACE("freeing %p\n", msg);
2735             if (msg->close)
2736                 msg->close(msg);
2737             CryptMemFree(msg);
2738         }
2739     }
2740     return TRUE;
2741 }
2742
2743 BOOL WINAPI CryptMsgUpdate(HCRYPTMSG hCryptMsg, const BYTE *pbData,
2744  DWORD cbData, BOOL fFinal)
2745 {
2746     CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg;
2747
2748     TRACE("(%p, %p, %d, %d)\n", hCryptMsg, pbData, cbData, fFinal);
2749
2750     return msg->update(hCryptMsg, pbData, cbData, fFinal);
2751 }
2752
2753 BOOL WINAPI CryptMsgGetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
2754  DWORD dwIndex, void *pvData, DWORD *pcbData)
2755 {
2756     CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg;
2757
2758     TRACE("(%p, %d, %d, %p, %p)\n", hCryptMsg, dwParamType, dwIndex,
2759      pvData, pcbData);
2760     return msg->get_param(hCryptMsg, dwParamType, dwIndex, pvData, pcbData);
2761 }
2762
2763 BOOL WINAPI CryptMsgControl(HCRYPTMSG hCryptMsg, DWORD dwFlags,
2764  DWORD dwCtrlType, const void *pvCtrlPara)
2765 {
2766     CryptMsgBase *msg = (CryptMsgBase *)hCryptMsg;
2767
2768     TRACE("(%p, %08x, %d, %p)\n", hCryptMsg, dwFlags, dwCtrlType,
2769      pvCtrlPara);
2770     return msg->control(hCryptMsg, dwFlags, dwCtrlType, pvCtrlPara);
2771 }
2772
2773 static CERT_INFO *CRYPT_GetSignerCertInfoFromMsg(HCRYPTMSG msg,
2774  DWORD dwSignerIndex)
2775 {
2776     CERT_INFO *certInfo = NULL;
2777     DWORD size;
2778
2779     if (CryptMsgGetParam(msg, CMSG_SIGNER_CERT_INFO_PARAM, dwSignerIndex, NULL,
2780      &size))
2781     {
2782         certInfo = CryptMemAlloc(size);
2783         if (certInfo)
2784         {
2785             if (!CryptMsgGetParam(msg, CMSG_SIGNER_CERT_INFO_PARAM,
2786              dwSignerIndex, certInfo, &size))
2787             {
2788                 CryptMemFree(certInfo);
2789                 certInfo = NULL;
2790             }
2791         }
2792     }
2793     return certInfo;
2794 }
2795
2796 BOOL WINAPI CryptMsgGetAndVerifySigner(HCRYPTMSG hCryptMsg, DWORD cSignerStore,
2797  HCERTSTORE *rghSignerStore, DWORD dwFlags, PCCERT_CONTEXT *ppSigner,
2798  DWORD *pdwSignerIndex)
2799 {
2800     HCERTSTORE store;
2801     DWORD i, signerIndex = 0;
2802     PCCERT_CONTEXT signerCert = NULL;
2803     BOOL ret = FALSE;
2804
2805     TRACE("(%p, %d, %p, %08x, %p, %p)\n", hCryptMsg, cSignerStore,
2806      rghSignerStore, dwFlags, ppSigner, pdwSignerIndex);
2807
2808     /* Clear output parameters */
2809     if (ppSigner)
2810         *ppSigner = NULL;
2811     if (pdwSignerIndex && !(dwFlags & CMSG_USE_SIGNER_INDEX_FLAG))
2812         *pdwSignerIndex = 0;
2813
2814     /* Create store to search for signer certificates */
2815     store = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
2816      CERT_STORE_CREATE_NEW_FLAG, NULL);
2817     if (!(dwFlags & CMSG_TRUSTED_SIGNER_FLAG))
2818     {
2819         HCERTSTORE msgStore = CertOpenStore(CERT_STORE_PROV_MSG, 0, 0, 0,
2820          hCryptMsg);
2821
2822         CertAddStoreToCollection(store, msgStore, 0, 0);
2823         CertCloseStore(msgStore, 0);
2824     }
2825     for (i = 0; i < cSignerStore; i++)
2826         CertAddStoreToCollection(store, rghSignerStore[i], 0, 0);
2827
2828     /* Find signer cert */
2829     if (dwFlags & CMSG_USE_SIGNER_INDEX_FLAG)
2830     {
2831         CERT_INFO *signer = CRYPT_GetSignerCertInfoFromMsg(hCryptMsg,
2832          *pdwSignerIndex);
2833
2834         if (signer)
2835         {
2836             signerIndex = *pdwSignerIndex;
2837             signerCert = CertFindCertificateInStore(store, X509_ASN_ENCODING,
2838              0, CERT_FIND_SUBJECT_CERT, signer, NULL);
2839             CryptMemFree(signer);
2840         }
2841     }
2842     else
2843     {
2844         DWORD count, size = sizeof(count);
2845
2846         if (CryptMsgGetParam(hCryptMsg, CMSG_SIGNER_COUNT_PARAM, 0, &count,
2847          &size))
2848         {
2849             for (i = 0; !signerCert && i < count; i++)
2850             {
2851                 CERT_INFO *signer = CRYPT_GetSignerCertInfoFromMsg(hCryptMsg,
2852                  i);
2853
2854                 if (signer)
2855                 {
2856                     signerCert = CertFindCertificateInStore(store,
2857                      X509_ASN_ENCODING, 0, CERT_FIND_SUBJECT_CERT, signer,
2858                      NULL);
2859                     if (signerCert)
2860                         signerIndex = i;
2861                     CryptMemFree(signer);
2862                 }
2863             }
2864         }
2865         if (!signerCert)
2866             SetLastError(CRYPT_E_NO_TRUSTED_SIGNER);
2867     }
2868     if (signerCert)
2869     {
2870         if (!(dwFlags & CMSG_SIGNER_ONLY_FLAG))
2871             ret = CryptMsgControl(hCryptMsg, 0, CMSG_CTRL_VERIFY_SIGNATURE,
2872              signerCert->pCertInfo);
2873         else
2874             ret = TRUE;
2875         if (ret)
2876         {
2877             if (ppSigner)
2878                 *ppSigner = CertDuplicateCertificateContext(signerCert);
2879             if (pdwSignerIndex)
2880                 *pdwSignerIndex = signerIndex;
2881         }
2882         CertFreeCertificateContext(signerCert);
2883     }
2884
2885     CertCloseStore(store, 0);
2886     return ret;
2887 }
2888
2889 BOOL WINAPI CryptMsgVerifyCountersignatureEncodedEx(HCRYPTPROV_LEGACY hCryptProv,
2890  DWORD dwEncodingType, PBYTE pbSignerInfo, DWORD cbSignerInfo,
2891  PBYTE pbSignerInfoCountersignature, DWORD cbSignerInfoCountersignature,
2892  DWORD dwSignerType, void *pvSigner, DWORD dwFlags, void *pvReserved)
2893 {
2894     FIXME("(%08lx, %08x, %p, %d, %p, %d, %d, %p, %08x, %p): stub\n", hCryptProv,
2895      dwEncodingType, pbSignerInfo, cbSignerInfo, pbSignerInfoCountersignature,
2896      cbSignerInfoCountersignature, dwSignerType, pvSigner, dwFlags, pvReserved);
2897     return FALSE;
2898 }