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