~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/crypt32/msg.c

Version: ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~ [ wine-1.0-rc5 ] ~ [ wine-1.0-rc4 ] ~ [ wine-1.0-rc3 ] ~ [ wine-1.0-rc2 ] ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  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         {