ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

msg.c
Go to the documentation of this file.
00001 /*
00002  * Copyright 2007 Juan Lang
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Lesser General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2.1 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Lesser General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Lesser General Public
00015  * License along with this library; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00017  */
00018 
00019 #include "config.h"
00020 #include "wine/port.h"
00021 
00022 #include <stdarg.h>
00023 #define NONAMELESSUNION
00024 #include "windef.h"
00025 #include "winbase.h"
00026 #include "wincrypt.h"
00027 #include "snmp.h"
00028 
00029 #include "wine/debug.h"
00030 #include "wine/exception.h"
00031 #include "crypt32_private.h"
00032 
00033 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
00034 
00035 /* Called when a message's ref count reaches zero.  Free any message-specific
00036  * data here.
00037  */
00038 typedef void (*CryptMsgCloseFunc)(HCRYPTMSG msg);
00039 
00040 typedef BOOL (*CryptMsgGetParamFunc)(HCRYPTMSG hCryptMsg, DWORD dwParamType,
00041  DWORD dwIndex, void *pvData, DWORD *pcbData);
00042 
00043 typedef BOOL (*CryptMsgUpdateFunc)(HCRYPTMSG hCryptMsg, const BYTE *pbData,
00044  DWORD cbData, BOOL fFinal);
00045 
00046 typedef BOOL (*CryptMsgControlFunc)(HCRYPTMSG hCryptMsg, DWORD dwFlags,
00047  DWORD dwCtrlType, const void *pvCtrlPara);
00048 
00049 static BOOL CRYPT_DefaultMsgControl(HCRYPTMSG hCryptMsg, DWORD dwFlags,
00050  DWORD dwCtrlType, const void *pvCtrlPara)
00051 {
00052     TRACE("(%p, %08x, %d, %p)\n", hCryptMsg, dwFlags, dwCtrlType, pvCtrlPara);
00053     SetLastError(E_INVALIDARG);
00054     return FALSE;
00055 }
00056 
00057 typedef enum _CryptMsgState {
00058     MsgStateInit,
00059     MsgStateUpdated,
00060     MsgStateDataFinalized,
00061     MsgStateFinalized
00062 } CryptMsgState;
00063 
00064 typedef struct _CryptMsgBase
00065 {
00066     LONG                 ref;
00067     DWORD                open_flags;
00068     BOOL                 streamed;
00069     CMSG_STREAM_INFO     stream_info;
00070     CryptMsgState        state;
00071     CryptMsgCloseFunc    close;
00072     CryptMsgUpdateFunc   update;
00073     CryptMsgGetParamFunc get_param;
00074     CryptMsgControlFunc  control;
00075 } CryptMsgBase;
00076 
00077 static inline void CryptMsgBase_Init(CryptMsgBase *msg, DWORD dwFlags,
00078  PCMSG_STREAM_INFO pStreamInfo, CryptMsgCloseFunc close,
00079  CryptMsgGetParamFunc get_param, CryptMsgUpdateFunc update,
00080  CryptMsgControlFunc control)
00081 {
00082     msg->ref = 1;
00083     msg->open_flags = dwFlags;
00084     if (pStreamInfo)
00085     {
00086         msg->streamed = TRUE;
00087         msg->stream_info = *pStreamInfo;
00088     }
00089     else
00090     {
00091         msg->streamed = FALSE;
00092         memset(&msg->stream_info, 0, sizeof(msg->stream_info));
00093     }
00094     msg->close = close;
00095     msg->get_param = get_param;
00096     msg->update = update;
00097     msg->control = control;
00098     msg->state = MsgStateInit;
00099 }
00100 
00101 typedef struct _CDataEncodeMsg
00102 {
00103     CryptMsgBase base;
00104     DWORD        bare_content_len;
00105     LPBYTE       bare_content;
00106 } CDataEncodeMsg;
00107 
00108 static const BYTE empty_data_content[] = { 0x04,0x00 };
00109 
00110 static void CDataEncodeMsg_Close(HCRYPTMSG hCryptMsg)
00111 {
00112     CDataEncodeMsg *msg = hCryptMsg;
00113 
00114     if (msg->bare_content != empty_data_content)
00115         LocalFree(msg->bare_content);
00116 }
00117 
00118 static BOOL WINAPI CRYPT_EncodeContentLength(DWORD dwCertEncodingType,
00119  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
00120  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
00121 {
00122     DWORD dataLen = *(DWORD *)pvStructInfo;
00123     DWORD lenBytes;
00124     BOOL ret = TRUE;
00125 
00126     /* Trick:  report bytes needed based on total message length, even though
00127      * the message isn't available yet.  The caller will use the length
00128      * reported here to encode its length.
00129      */
00130     CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
00131     if (!pbEncoded)
00132         *pcbEncoded = 1 + lenBytes + dataLen;
00133     else
00134     {
00135         if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
00136          pcbEncoded, 1 + lenBytes)))
00137         {
00138             if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
00139                 pbEncoded = *(BYTE **)pbEncoded;
00140             *pbEncoded++ = ASN_OCTETSTRING;
00141             CRYPT_EncodeLen(dataLen, pbEncoded,
00142              &lenBytes);
00143         }
00144     }
00145     return ret;
00146 }
00147 
00148 static BOOL CRYPT_EncodeDataContentInfoHeader(const CDataEncodeMsg *msg,
00149  CRYPT_DATA_BLOB *header)
00150 {
00151     BOOL ret;
00152 
00153     if (msg->base.streamed && msg->base.stream_info.cbContent == 0xffffffff)
00154     {
00155         static const BYTE headerValue[] = { 0x30,0x80,0x06,0x09,0x2a,0x86,0x48,
00156          0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x80,0x24,0x80 };
00157 
00158         header->pbData = LocalAlloc(0, sizeof(headerValue));
00159         if (header->pbData)
00160         {
00161             header->cbData = sizeof(headerValue);
00162             memcpy(header->pbData, headerValue, sizeof(headerValue));
00163             ret = TRUE;
00164         }
00165         else
00166             ret = FALSE;
00167     }
00168     else
00169     {
00170         struct AsnConstructedItem constructed = { 0,
00171          &msg->base.stream_info.cbContent, CRYPT_EncodeContentLength };
00172         struct AsnEncodeSequenceItem items[2] = {
00173          { szOID_RSA_data, CRYPT_AsnEncodeOid, 0 },
00174          { &constructed,   CRYPT_AsnEncodeConstructed, 0 },
00175         };
00176 
00177         ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items,
00178          sizeof(items) / sizeof(items[0]), CRYPT_ENCODE_ALLOC_FLAG, NULL,
00179          (LPBYTE)&header->pbData, &header->cbData);
00180         if (ret)
00181         {
00182             /* Trick:  subtract the content length from the reported length,
00183              * as the actual content hasn't come yet.
00184              */
00185             header->cbData -= msg->base.stream_info.cbContent;
00186         }
00187     }
00188     return ret;
00189 }
00190 
00191 static BOOL CDataEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
00192  DWORD cbData, BOOL fFinal)
00193 {
00194     CDataEncodeMsg *msg = hCryptMsg;
00195     BOOL ret = FALSE;
00196 
00197     if (msg->base.state == MsgStateFinalized)
00198         SetLastError(CRYPT_E_MSG_ERROR);
00199     else if (msg->base.streamed)
00200     {
00201         __TRY
00202         {
00203             if (msg->base.state != MsgStateUpdated)
00204             {
00205                 CRYPT_DATA_BLOB header;
00206 
00207                 ret = CRYPT_EncodeDataContentInfoHeader(msg, &header);
00208                 if (ret)
00209                 {
00210                     ret = msg->base.stream_info.pfnStreamOutput(
00211                      msg->base.stream_info.pvArg, header.pbData, header.cbData,
00212                      FALSE);
00213                     LocalFree(header.pbData);
00214                 }
00215             }
00216             /* Curiously, every indefinite-length streamed update appears to
00217              * get its own tag and length, regardless of fFinal.
00218              */
00219             if (msg->base.stream_info.cbContent == 0xffffffff)
00220             {
00221                 BYTE *header;
00222                 DWORD headerLen;
00223 
00224                 ret = CRYPT_EncodeContentLength(X509_ASN_ENCODING, NULL,
00225                  &cbData, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&header,
00226                  &headerLen);
00227                 if (ret)
00228                 {
00229                     ret = msg->base.stream_info.pfnStreamOutput(
00230                      msg->base.stream_info.pvArg, header, headerLen,
00231                      FALSE);
00232                     LocalFree(header);
00233                 }
00234             }
00235             if (!fFinal)
00236             {
00237                 ret = msg->base.stream_info.pfnStreamOutput(
00238                  msg->base.stream_info.pvArg, (BYTE *)pbData, cbData,
00239                  FALSE);
00240                 msg->base.state = MsgStateUpdated;
00241             }
00242             else
00243             {
00244                 msg->base.state = MsgStateFinalized;
00245                 if (msg->base.stream_info.cbContent == 0xffffffff)
00246                 {
00247                     BYTE indefinite_trailer[6] = { 0 };
00248 
00249                     ret = msg->base.stream_info.pfnStreamOutput(
00250                      msg->base.stream_info.pvArg, (BYTE *)pbData, cbData,
00251                      FALSE);
00252                     if (ret)
00253                         ret = msg->base.stream_info.pfnStreamOutput(
00254                          msg->base.stream_info.pvArg, indefinite_trailer,
00255                          sizeof(indefinite_trailer), TRUE);
00256                 }
00257                 else
00258                     ret = msg->base.stream_info.pfnStreamOutput(
00259                      msg->base.stream_info.pvArg, (BYTE *)pbData, cbData, TRUE);
00260             }
00261         }
00262         __EXCEPT_PAGE_FAULT
00263         {
00264             SetLastError(STATUS_ACCESS_VIOLATION);
00265             ret = FALSE;
00266         }
00267         __ENDTRY;
00268     }
00269     else
00270     {
00271         if (!fFinal)
00272         {
00273             if (msg->base.open_flags & CMSG_DETACHED_FLAG)
00274                 SetLastError(E_INVALIDARG);
00275             else
00276                 SetLastError(CRYPT_E_MSG_ERROR);
00277         }
00278         else
00279         {
00280             CRYPT_DATA_BLOB blob = { cbData, (LPBYTE)pbData };
00281 
00282             msg->base.state = MsgStateFinalized;
00283             /* non-streamed data messages don't allow non-final updates,
00284              * don't bother checking whether data already exist, they can't.
00285              */
00286             ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING,
00287              &blob, CRYPT_ENCODE_ALLOC_FLAG, NULL, &msg->bare_content,
00288              &msg->bare_content_len);
00289         }
00290     }
00291     return ret;
00292 }
00293 
00294 static BOOL CRYPT_CopyParam(void *pvData, DWORD *pcbData, const void *src,
00295  DWORD len)
00296 {
00297     BOOL ret = TRUE;
00298 
00299     if (!pvData)
00300         *pcbData = len;
00301     else if (*pcbData < len)
00302     {
00303         *pcbData = len;
00304         SetLastError(ERROR_MORE_DATA);
00305         ret = FALSE;
00306     }
00307     else
00308     {
00309         *pcbData = len;
00310         memcpy(pvData, src, len);
00311     }
00312     return ret;
00313 }
00314 
00315 static BOOL CDataEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
00316  DWORD dwIndex, void *pvData, DWORD *pcbData)
00317 {
00318     CDataEncodeMsg *msg = hCryptMsg;
00319     BOOL ret = FALSE;
00320 
00321     switch (dwParamType)
00322     {
00323     case CMSG_CONTENT_PARAM:
00324         if (msg->base.streamed)
00325             SetLastError(E_INVALIDARG);
00326         else
00327         {
00328             CRYPT_CONTENT_INFO info;
00329             char rsa_data[] = "1.2.840.113549.1.7.1";
00330 
00331             info.pszObjId = rsa_data;
00332             info.Content.cbData = msg->bare_content_len;
00333             info.Content.pbData = msg->bare_content;
00334             ret = CryptEncodeObject(X509_ASN_ENCODING, PKCS_CONTENT_INFO, &info,
00335              pvData, pcbData);
00336         }
00337         break;
00338     case CMSG_BARE_CONTENT_PARAM:
00339         if (msg->base.streamed)
00340             SetLastError(E_INVALIDARG);
00341         else
00342             ret = CRYPT_CopyParam(pvData, pcbData, msg->bare_content,
00343              msg->bare_content_len);
00344         break;
00345     default:
00346         SetLastError(CRYPT_E_INVALID_MSG_TYPE);
00347     }
00348     return ret;
00349 }
00350 
00351 static HCRYPTMSG CDataEncodeMsg_Open(DWORD dwFlags, const void *pvMsgEncodeInfo,
00352  LPSTR pszInnerContentObjID, PCMSG_STREAM_INFO pStreamInfo)
00353 {
00354     CDataEncodeMsg *msg;
00355 
00356     if (pvMsgEncodeInfo)
00357     {
00358         SetLastError(E_INVALIDARG);
00359         return NULL;
00360     }
00361     msg = CryptMemAlloc(sizeof(CDataEncodeMsg));
00362     if (msg)
00363     {
00364         CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo,
00365          CDataEncodeMsg_Close, CDataEncodeMsg_GetParam, CDataEncodeMsg_Update,
00366          CRYPT_DefaultMsgControl);
00367         msg->bare_content_len = sizeof(empty_data_content);
00368         msg->bare_content = (LPBYTE)empty_data_content;
00369     }
00370     return msg;
00371 }
00372 
00373 typedef struct _CHashEncodeMsg
00374 {
00375     CryptMsgBase    base;
00376     HCRYPTPROV      prov;
00377     HCRYPTHASH      hash;
00378     CRYPT_DATA_BLOB data;
00379 } CHashEncodeMsg;
00380 
00381 static void CHashEncodeMsg_Close(HCRYPTMSG hCryptMsg)
00382 {
00383     CHashEncodeMsg *msg = hCryptMsg;
00384 
00385     CryptMemFree(msg->data.pbData);
00386     CryptDestroyHash(msg->hash);
00387     if (msg->base.open_flags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG)
00388         CryptReleaseContext(msg->prov, 0);
00389 }
00390 
00391 static BOOL CRYPT_EncodePKCSDigestedData(CHashEncodeMsg *msg, void *pvData,
00392  DWORD *pcbData)
00393 {
00394     BOOL ret;
00395     ALG_ID algID;
00396     DWORD size = sizeof(algID);
00397 
00398     ret = CryptGetHashParam(msg->hash, HP_ALGID, (BYTE *)&algID, &size, 0);
00399     if (ret)
00400     {
00401         CRYPT_DIGESTED_DATA digestedData = { 0 };
00402         char oid_rsa_data[] = szOID_RSA_data;
00403 
00404         digestedData.version = CMSG_HASHED_DATA_PKCS_1_5_VERSION;
00405         digestedData.DigestAlgorithm.pszObjId = (LPSTR)CertAlgIdToOID(algID);
00406         /* FIXME: what about digestedData.DigestAlgorithm.Parameters? */
00407         /* Quirk:  OID is only encoded messages if an update has happened */
00408         if (msg->base.state != MsgStateInit)
00409             digestedData.ContentInfo.pszObjId = oid_rsa_data;
00410         if (!(msg->base.open_flags & CMSG_DETACHED_FLAG) && msg->data.cbData)
00411         {
00412             ret = CRYPT_AsnEncodeOctets(0, NULL, &msg->data,
00413              CRYPT_ENCODE_ALLOC_FLAG, NULL,
00414              (LPBYTE)&digestedData.ContentInfo.Content.pbData,
00415              &digestedData.ContentInfo.Content.cbData);
00416         }
00417         if (msg->base.state == MsgStateFinalized)
00418         {
00419             size = sizeof(DWORD);
00420             ret = CryptGetHashParam(msg->hash, HP_HASHSIZE,
00421              (LPBYTE)&digestedData.hash.cbData, &size, 0);
00422             if (ret)
00423             {
00424                 digestedData.hash.pbData = CryptMemAlloc(
00425                  digestedData.hash.cbData);
00426                 ret = CryptGetHashParam(msg->hash, HP_HASHVAL,
00427                  digestedData.hash.pbData, &digestedData.hash.cbData, 0);
00428             }
00429         }
00430         if (ret)
00431             ret = CRYPT_AsnEncodePKCSDigestedData(&digestedData, pvData,
00432              pcbData);
00433         CryptMemFree(digestedData.hash.pbData);
00434         LocalFree(digestedData.ContentInfo.Content.pbData);
00435     }
00436     return ret;
00437 }
00438 
00439 static BOOL CHashEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
00440  DWORD dwIndex, void *pvData, DWORD *pcbData)
00441 {
00442     CHashEncodeMsg *msg = hCryptMsg;
00443     BOOL ret = FALSE;
00444 
00445     TRACE("(%p, %d, %d, %p, %p)\n", hCryptMsg, dwParamType, dwIndex,
00446      pvData, pcbData);
00447 
00448     switch (dwParamType)
00449     {
00450     case CMSG_BARE_CONTENT_PARAM:
00451         if (msg->base.streamed)
00452             SetLastError(E_INVALIDARG);
00453         else
00454             ret = CRYPT_EncodePKCSDigestedData(msg, pvData, pcbData);
00455         break;
00456     case CMSG_CONTENT_PARAM:
00457     {
00458         CRYPT_CONTENT_INFO info;
00459 
00460         ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0, NULL,
00461          &info.Content.cbData);
00462         if (ret)
00463         {
00464             info.Content.pbData = CryptMemAlloc(info.Content.cbData);
00465             if (info.Content.pbData)
00466             {
00467                 ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0,
00468                  info.Content.pbData, &info.Content.cbData);
00469                 if (ret)
00470                 {
00471                     char oid_rsa_hashed[] = szOID_RSA_hashedData;
00472 
00473                     info.pszObjId = oid_rsa_hashed;
00474                     ret = CryptEncodeObjectEx(X509_ASN_ENCODING,
00475                      PKCS_CONTENT_INFO, &info, 0, NULL, pvData, pcbData);
00476                 }
00477                 CryptMemFree(info.Content.pbData);
00478             }
00479             else
00480                 ret = FALSE;
00481         }
00482         break;
00483     }
00484     case CMSG_COMPUTED_HASH_PARAM:
00485         ret = CryptGetHashParam(msg->hash, HP_HASHVAL, pvData, pcbData, 0);
00486         break;
00487     case CMSG_VERSION_PARAM:
00488         if (msg->base.state != MsgStateFinalized)
00489             SetLastError(CRYPT_E_MSG_ERROR);
00490         else
00491         {
00492             DWORD version = CMSG_HASHED_DATA_PKCS_1_5_VERSION;
00493 
00494             /* Since the data are always encoded as octets, the version is
00495              * always 0 (see rfc3852, section 7)
00496              */
00497             ret = CRYPT_CopyParam(pvData, pcbData, &version, sizeof(version));
00498         }
00499         break;
00500     default:
00501         SetLastError(CRYPT_E_INVALID_MSG_TYPE);
00502     }
00503     return ret;
00504 }
00505 
00506 static BOOL CHashEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
00507  DWORD cbData, BOOL fFinal)
00508 {
00509     CHashEncodeMsg *msg = hCryptMsg;
00510     BOOL ret = FALSE;
00511 
00512     TRACE("(%p, %p, %d, %d)\n", hCryptMsg, pbData, cbData, fFinal);
00513 
00514     if (msg->base.state == MsgStateFinalized)
00515         SetLastError(CRYPT_E_MSG_ERROR);
00516     else if (msg->base.streamed || (msg->base.open_flags & CMSG_DETACHED_FLAG))
00517     {
00518         /* Doesn't do much, as stream output is never called, and you
00519          * can't get the content.
00520          */
00521         ret = CryptHashData(msg->hash, pbData, cbData, 0);
00522         msg->base.state = fFinal ? MsgStateFinalized : MsgStateUpdated;
00523     }
00524     else
00525     {
00526         if (!fFinal)
00527             SetLastError(CRYPT_E_MSG_ERROR);
00528         else
00529         {
00530             ret = CryptHashData(msg->hash, pbData, cbData, 0);
00531             if (ret)
00532             {
00533                 msg->data.pbData = CryptMemAlloc(cbData);
00534                 if (msg->data.pbData)
00535                 {
00536                     memcpy(msg->data.pbData + msg->data.cbData, pbData, cbData);
00537                     msg->data.cbData += cbData;
00538                 }
00539                 else
00540                     ret = FALSE;
00541             }
00542             msg->base.state = MsgStateFinalized;
00543         }
00544     }
00545     return ret;
00546 }
00547 
00548 static HCRYPTMSG CHashEncodeMsg_Open(DWORD dwFlags, const void *pvMsgEncodeInfo,
00549  LPSTR pszInnerContentObjID, PCMSG_STREAM_INFO pStreamInfo)
00550 {
00551     CHashEncodeMsg *msg;
00552     const CMSG_HASHED_ENCODE_INFO *info = pvMsgEncodeInfo;
00553     HCRYPTPROV prov;
00554     ALG_ID algID;
00555 
00556     if (info->cbSize != sizeof(CMSG_HASHED_ENCODE_INFO))
00557     {
00558         SetLastError(E_INVALIDARG);
00559         return NULL;
00560     }
00561     if (!(algID = CertOIDToAlgId(info->HashAlgorithm.pszObjId)))
00562     {
00563         SetLastError(CRYPT_E_UNKNOWN_ALGO);
00564         return NULL;
00565     }
00566     if (info->hCryptProv)
00567         prov = info->hCryptProv;
00568     else
00569     {
00570         prov = CRYPT_GetDefaultProvider();
00571         dwFlags &= ~CMSG_CRYPT_RELEASE_CONTEXT_FLAG;
00572     }
00573     msg = CryptMemAlloc(sizeof(CHashEncodeMsg));
00574     if (msg)
00575     {
00576         CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo,
00577          CHashEncodeMsg_Close, CHashEncodeMsg_GetParam, CHashEncodeMsg_Update,
00578          CRYPT_DefaultMsgControl);
00579         msg->prov = prov;
00580         msg->data.cbData = 0;
00581         msg->data.pbData = NULL;
00582         if (!CryptCreateHash(prov, algID, 0, 0, &msg->hash))
00583         {
00584             CryptMsgClose(msg);
00585             msg = NULL;
00586         }
00587     }
00588     return msg;
00589 }
00590 
00591 typedef struct _CMSG_SIGNER_ENCODE_INFO_WITH_CMS
00592 {
00593     DWORD                      cbSize;
00594     PCERT_INFO                 pCertInfo;
00595     HCRYPTPROV                 hCryptProv;
00596     DWORD                      dwKeySpec;
00597     CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm;
00598     void                      *pvHashAuxInfo;
00599     DWORD                      cAuthAttr;
00600     PCRYPT_ATTRIBUTE           rgAuthAttr;
00601     DWORD                      cUnauthAttr;
00602     PCRYPT_ATTRIBUTE           rgUnauthAttr;
00603     CERT_ID                    SignerId;
00604     CRYPT_ALGORITHM_IDENTIFIER HashEncryptionAlgorithm;
00605     void                      *pvHashEncryptionAuxInfo;
00606 } CMSG_SIGNER_ENCODE_INFO_WITH_CMS, *PCMSG_SIGNER_ENCODE_INFO_WITH_CMS;
00607 
00608 typedef struct _CMSG_SIGNED_ENCODE_INFO_WITH_CMS
00609 {
00610     DWORD                             cbSize;
00611     DWORD                             cSigners;
00612     PCMSG_SIGNER_ENCODE_INFO_WITH_CMS rgSigners;
00613     DWORD                             cCertEncoded;
00614     PCERT_BLOB                        rgCertEncoded;
00615     DWORD                             cCrlEncoded;
00616     PCRL_BLOB                         rgCrlEncoded;
00617     DWORD                             cAttrCertEncoded;
00618     PCERT_BLOB                        rgAttrCertEncoded;
00619 } CMSG_SIGNED_ENCODE_INFO_WITH_CMS, *PCMSG_SIGNED_ENCODE_INFO_WITH_CMS;
00620 
00621 static BOOL CRYPT_IsValidSigner(const CMSG_SIGNER_ENCODE_INFO_WITH_CMS *signer)
00622 {
00623     if (signer->cbSize != sizeof(CMSG_SIGNER_ENCODE_INFO) &&
00624      signer->cbSize != sizeof(CMSG_SIGNER_ENCODE_INFO_WITH_CMS))
00625     {
00626         SetLastError(E_INVALIDARG);
00627         return FALSE;
00628     }
00629     if (signer->cbSize == sizeof(CMSG_SIGNER_ENCODE_INFO))
00630     {
00631         if (!signer->pCertInfo->SerialNumber.cbData)
00632         {
00633             SetLastError(E_INVALIDARG);
00634             return FALSE;
00635         }
00636         if (!signer->pCertInfo->Issuer.cbData)
00637         {
00638             SetLastError(E_INVALIDARG);
00639             return FALSE;
00640         }
00641     }
00642     else if (signer->cbSize == sizeof(CMSG_SIGNER_ENCODE_INFO_WITH_CMS))
00643     {
00644         switch (signer->SignerId.dwIdChoice)
00645         {
00646         case 0:
00647             if (!signer->pCertInfo->SerialNumber.cbData)
00648             {
00649                 SetLastError(E_INVALIDARG);
00650                 return FALSE;
00651             }
00652             if (!signer->pCertInfo->Issuer.cbData)
00653             {
00654                 SetLastError(E_INVALIDARG);
00655                 return FALSE;
00656             }
00657             break;
00658         case CERT_ID_ISSUER_SERIAL_NUMBER:
00659             if (!signer->SignerId.u.IssuerSerialNumber.SerialNumber.cbData)
00660             {
00661                 SetLastError(E_INVALIDARG);
00662                 return FALSE;
00663             }
00664             if (!signer->SignerId.u.IssuerSerialNumber.Issuer.cbData)
00665             {
00666                 SetLastError(E_INVALIDARG);
00667                 return FALSE;
00668             }
00669             break;
00670         case CERT_ID_KEY_IDENTIFIER:
00671             if (!signer->SignerId.u.KeyId.cbData)
00672             {
00673                 SetLastError(E_INVALIDARG);
00674                 return FALSE;
00675             }
00676             break;
00677         default:
00678             SetLastError(E_INVALIDARG);
00679         }
00680         if (signer->HashEncryptionAlgorithm.pszObjId)
00681         {
00682             FIXME("CMSG_SIGNER_ENCODE_INFO with CMS fields unsupported\n");
00683             return FALSE;
00684         }
00685     }
00686     if (!signer->hCryptProv)
00687     {
00688         SetLastError(E_INVALIDARG);
00689         return FALSE;
00690     }
00691     if (!CertOIDToAlgId(signer->HashAlgorithm.pszObjId))
00692     {
00693         SetLastError(CRYPT_E_UNKNOWN_ALGO);
00694         return FALSE;
00695     }
00696     return TRUE;
00697 }
00698 
00699 static BOOL CRYPT_ConstructBlob(CRYPT_DATA_BLOB *out, const CRYPT_DATA_BLOB *in)
00700 {
00701     BOOL ret = TRUE;
00702 
00703     out->cbData = in->cbData;
00704     if (out->cbData)
00705     {
00706         out->pbData = CryptMemAlloc(out->cbData);
00707         if (out->pbData)
00708             memcpy(out->pbData, in->pbData, out->cbData);
00709         else
00710             ret = FALSE;
00711     }
00712     else
00713         out->pbData = NULL;
00714     return ret;
00715 }
00716 
00717 static BOOL CRYPT_ConstructBlobArray(DWORD *outCBlobs,
00718  PCRYPT_DATA_BLOB *outPBlobs, DWORD cBlobs, const CRYPT_DATA_BLOB *pBlobs)
00719 {
00720     BOOL ret = TRUE;
00721 
00722     *outCBlobs = cBlobs;
00723     if (cBlobs)
00724     {
00725         *outPBlobs = CryptMemAlloc(cBlobs * sizeof(CRYPT_DATA_BLOB));
00726         if (*outPBlobs)
00727         {
00728             DWORD i;
00729 
00730             memset(*outPBlobs, 0, cBlobs * sizeof(CRYPT_DATA_BLOB));
00731             for (i = 0; ret && i < cBlobs; i++)
00732                 ret = CRYPT_ConstructBlob(&(*outPBlobs)[i], &pBlobs[i]);
00733         }
00734         else
00735             ret = FALSE;
00736     }
00737     return ret;
00738 }
00739 
00740 static void CRYPT_FreeBlobArray(DWORD cBlobs, PCRYPT_DATA_BLOB blobs)
00741 {
00742     DWORD i;
00743 
00744     for (i = 0; i < cBlobs; i++)
00745         CryptMemFree(blobs[i].pbData);
00746     CryptMemFree(blobs);
00747 }
00748 
00749 static BOOL CRYPT_ConstructAttribute(CRYPT_ATTRIBUTE *out,
00750  const CRYPT_ATTRIBUTE *in)
00751 {
00752     BOOL ret;
00753 
00754     out->pszObjId = CryptMemAlloc(strlen(in->pszObjId) + 1);
00755     if (out->pszObjId)
00756     {
00757         strcpy(out->pszObjId, in->pszObjId);
00758         ret = CRYPT_ConstructBlobArray(&out->cValue, &out->rgValue,
00759          in->cValue, in->rgValue);
00760     }
00761     else
00762         ret = FALSE;
00763     return ret;
00764 }
00765 
00766 static BOOL CRYPT_ConstructAttributes(CRYPT_ATTRIBUTES *out,
00767  const CRYPT_ATTRIBUTES *in)
00768 {
00769     BOOL ret = TRUE;
00770 
00771     out->cAttr = in->cAttr;
00772     if (out->cAttr)
00773     {
00774         out->rgAttr = CryptMemAlloc(out->cAttr * sizeof(CRYPT_ATTRIBUTE));
00775         if (out->rgAttr)
00776         {
00777             DWORD i;
00778 
00779             memset(out->rgAttr, 0, out->cAttr * sizeof(CRYPT_ATTRIBUTE));
00780             for (i = 0; ret && i < out->cAttr; i++)
00781                 ret = CRYPT_ConstructAttribute(&out->rgAttr[i], &in->rgAttr[i]);
00782         }
00783         else
00784             ret = FALSE;
00785     }
00786     else
00787         out->rgAttr = NULL;
00788     return ret;
00789 }
00790 
00791 /* Constructs a CMSG_CMS_SIGNER_INFO from a CMSG_SIGNER_ENCODE_INFO_WITH_CMS. */
00792 static BOOL CSignerInfo_Construct(CMSG_CMS_SIGNER_INFO *info,
00793  const CMSG_SIGNER_ENCODE_INFO_WITH_CMS *in)
00794 {
00795     BOOL ret;
00796 
00797     if (in->cbSize == sizeof(CMSG_SIGNER_ENCODE_INFO))
00798     {
00799         info->dwVersion = CMSG_SIGNER_INFO_V1;
00800         ret = CRYPT_ConstructBlob(&info->SignerId.u.IssuerSerialNumber.Issuer,
00801          &in->pCertInfo->Issuer);
00802         if (ret)
00803             ret = CRYPT_ConstructBlob(
00804              &info->SignerId.u.IssuerSerialNumber.SerialNumber,
00805              &in->pCertInfo->SerialNumber);
00806         info->SignerId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
00807         info->HashEncryptionAlgorithm.pszObjId =
00808          in->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId;
00809         if (ret)
00810             ret = CRYPT_ConstructBlob(&info->HashEncryptionAlgorithm.Parameters,
00811              &in->pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters);
00812     }
00813     else
00814     {
00815         const CRYPT_ALGORITHM_IDENTIFIER *pEncrAlg;
00816 
00817         /* Implicitly in->cbSize == sizeof(CMSG_SIGNER_ENCODE_INFO_WITH_CMS).
00818          * See CRYPT_IsValidSigner.
00819          */
00820         if (!in->SignerId.dwIdChoice)
00821         {
00822             info->dwVersion = CMSG_SIGNER_INFO_V1;
00823             ret = CRYPT_ConstructBlob(&info->SignerId.u.IssuerSerialNumber.Issuer,
00824              &in->pCertInfo->Issuer);
00825             if (ret)
00826                 ret = CRYPT_ConstructBlob(
00827                  &info->SignerId.u.IssuerSerialNumber.SerialNumber,
00828                  &in->pCertInfo->SerialNumber);
00829             info->SignerId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
00830         }
00831         else if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
00832         {
00833             info->dwVersion = CMSG_SIGNER_INFO_V1;
00834             info->SignerId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
00835             ret = CRYPT_ConstructBlob(&info->SignerId.u.IssuerSerialNumber.Issuer,
00836              &in->SignerId.u.IssuerSerialNumber.Issuer);
00837             if (ret)
00838                 ret = CRYPT_ConstructBlob(
00839                  &info->SignerId.u.IssuerSerialNumber.SerialNumber,
00840                  &in->SignerId.u.IssuerSerialNumber.SerialNumber);
00841         }
00842         else
00843         {
00844             /* Implicitly dwIdChoice == CERT_ID_KEY_IDENTIFIER */
00845             info->dwVersion = CMSG_SIGNER_INFO_V3;
00846             info->SignerId.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
00847             ret = CRYPT_ConstructBlob(&info->SignerId.u.KeyId,
00848              &in->SignerId.u.KeyId);
00849         }
00850         pEncrAlg = in->HashEncryptionAlgorithm.pszObjId ?
00851          &in->HashEncryptionAlgorithm :
00852          &in->pCertInfo->SubjectPublicKeyInfo.Algorithm;
00853         info->HashEncryptionAlgorithm.pszObjId = pEncrAlg->pszObjId;
00854         if (ret)
00855             ret = CRYPT_ConstructBlob(&info->HashEncryptionAlgorithm.Parameters,
00856              &pEncrAlg->Parameters);
00857     }
00858     /* Assumption:  algorithm IDs will point to static strings, not
00859      * stack-based ones, so copying the pointer values is safe.
00860      */
00861     info->HashAlgorithm.pszObjId = in->HashAlgorithm.pszObjId;
00862     if (ret)
00863         ret = CRYPT_ConstructBlob(&info->HashAlgorithm.Parameters,
00864          &in->HashAlgorithm.Parameters);
00865     if (ret)
00866         ret = CRYPT_ConstructAttributes(&info->AuthAttrs,
00867          (CRYPT_ATTRIBUTES *)&in->cAuthAttr);
00868     if (ret)
00869         ret = CRYPT_ConstructAttributes(&info->UnauthAttrs,
00870          (CRYPT_ATTRIBUTES *)&in->cUnauthAttr);
00871     return ret;
00872 }
00873 
00874 static void CSignerInfo_Free(CMSG_CMS_SIGNER_INFO *info)
00875 {
00876     DWORD i, j;
00877 
00878     if (info->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
00879     {
00880         CryptMemFree(info->SignerId.u.IssuerSerialNumber.Issuer.pbData);
00881         CryptMemFree(info->SignerId.u.IssuerSerialNumber.SerialNumber.pbData);
00882     }
00883     else
00884         CryptMemFree(info->SignerId.u.KeyId.pbData);
00885     CryptMemFree(info->HashAlgorithm.Parameters.pbData);
00886     CryptMemFree(info->HashEncryptionAlgorithm.Parameters.pbData);
00887     CryptMemFree(info->EncryptedHash.pbData);
00888     for (i = 0; i < info->AuthAttrs.cAttr; i++)
00889     {
00890         for (j = 0; j < info->AuthAttrs.rgAttr[i].cValue; j++)
00891             CryptMemFree(info->AuthAttrs.rgAttr[i].rgValue[j].pbData);
00892         CryptMemFree(info->AuthAttrs.rgAttr[i].rgValue);
00893         CryptMemFree(info->AuthAttrs.rgAttr[i].pszObjId);
00894     }
00895     CryptMemFree(info->AuthAttrs.rgAttr);
00896     for (i = 0; i < info->UnauthAttrs.cAttr; i++)
00897     {
00898         for (j = 0; j < info->UnauthAttrs.rgAttr[i].cValue; j++)
00899             CryptMemFree(info->UnauthAttrs.rgAttr[i].rgValue[j].pbData);
00900         CryptMemFree(info->UnauthAttrs.rgAttr[i].rgValue);
00901         CryptMemFree(info->UnauthAttrs.rgAttr[i].pszObjId);
00902     }
00903     CryptMemFree(info->UnauthAttrs.rgAttr);
00904 }
00905 
00906 typedef struct _CSignerHandles
00907 {
00908     HCRYPTHASH contentHash;
00909     HCRYPTHASH authAttrHash;
00910 } CSignerHandles;
00911 
00912 typedef struct _CSignedMsgData
00913 {
00914     CRYPT_SIGNED_INFO *info;
00915     DWORD              cSignerHandle;
00916     CSignerHandles    *signerHandles;
00917 } CSignedMsgData;
00918 
00919 /* Constructs the signer handles for the signerIndex'th signer of msg_data.
00920  * Assumes signerIndex is a valid idnex, and that msg_data's info has already
00921  * been constructed.
00922  */
00923 static BOOL CSignedMsgData_ConstructSignerHandles(CSignedMsgData *msg_data,
00924  DWORD signerIndex, HCRYPTPROV crypt_prov)
00925 {
00926     ALG_ID algID;
00927     BOOL ret;
00928 
00929     algID = CertOIDToAlgId(
00930      msg_data->info->rgSignerInfo[signerIndex].HashAlgorithm.pszObjId);
00931     ret = CryptCreateHash(crypt_prov, algID, 0, 0,
00932      &msg_data->signerHandles->contentHash);
00933     if (ret && msg_data->info->rgSignerInfo[signerIndex].AuthAttrs.cAttr > 0)
00934         ret = CryptCreateHash(crypt_prov, algID, 0, 0,
00935          &msg_data->signerHandles->authAttrHash);
00936     return ret;
00937 }
00938 
00939 /* Allocates a CSignedMsgData's handles.  Assumes its info has already been
00940  * constructed.
00941  */
00942 static BOOL CSignedMsgData_AllocateHandles(CSignedMsgData *msg_data)
00943 {
00944     BOOL ret = TRUE;
00945 
00946     if (msg_data->info->cSignerInfo)
00947     {
00948         msg_data->signerHandles =
00949          CryptMemAlloc(msg_data->info->cSignerInfo * sizeof(CSignerHandles));
00950         if (msg_data->signerHandles)
00951         {
00952             msg_data->cSignerHandle = msg_data->info->cSignerInfo;
00953             memset(msg_data->signerHandles, 0,
00954              msg_data->info->cSignerInfo * sizeof(CSignerHandles));
00955         }
00956         else
00957         {
00958             msg_data->cSignerHandle = 0;
00959             ret = FALSE;
00960         }
00961     }
00962     else
00963     {
00964         msg_data->cSignerHandle = 0;
00965         msg_data->signerHandles = NULL;
00966     }
00967     return ret;
00968 }
00969 
00970 static void CSignedMsgData_CloseHandles(CSignedMsgData *msg_data)
00971 {
00972     DWORD i;
00973 
00974     for (i = 0; i < msg_data->cSignerHandle; i++)
00975     {
00976         if (msg_data->signerHandles[i].contentHash)
00977             CryptDestroyHash(msg_data->signerHandles[i].contentHash);
00978         if (msg_data->signerHandles[i].authAttrHash)
00979             CryptDestroyHash(msg_data->signerHandles[i].authAttrHash);
00980     }
00981     CryptMemFree(msg_data->signerHandles);
00982     msg_data->signerHandles = NULL;
00983     msg_data->cSignerHandle = 0;
00984 }
00985 
00986 static BOOL CSignedMsgData_UpdateHash(CSignedMsgData *msg_data,
00987  const BYTE *pbData, DWORD cbData)
00988 {
00989     DWORD i;
00990     BOOL ret = TRUE;
00991 
00992     for (i = 0; ret && i < msg_data->cSignerHandle; i++)
00993         ret = CryptHashData(msg_data->signerHandles[i].contentHash, pbData,
00994          cbData, 0);
00995     return ret;
00996 }
00997 
00998 static BOOL CRYPT_AppendAttribute(CRYPT_ATTRIBUTES *out,
00999  const CRYPT_ATTRIBUTE *in)
01000 {
01001     BOOL ret = FALSE;
01002 
01003     out->rgAttr = CryptMemRealloc(out->rgAttr,
01004      (out->cAttr + 1) * sizeof(CRYPT_ATTRIBUTE));
01005     if (out->rgAttr)
01006     {
01007         ret = CRYPT_ConstructAttribute(&out->rgAttr[out->cAttr], in);
01008         if (ret)
01009             out->cAttr++;
01010     }
01011     return ret;
01012 }
01013 
01014 static BOOL CSignedMsgData_AppendMessageDigestAttribute(
01015  CSignedMsgData *msg_data, DWORD signerIndex)
01016 {
01017     BOOL ret;
01018     DWORD size;
01019     CRYPT_HASH_BLOB hash = { 0, NULL }, encodedHash = { 0, NULL };
01020     char messageDigest[] = szOID_RSA_messageDigest;
01021     CRYPT_ATTRIBUTE messageDigestAttr = { messageDigest, 1, &encodedHash };
01022 
01023     size = sizeof(DWORD);
01024     ret = CryptGetHashParam(
01025      msg_data->signerHandles[signerIndex].contentHash, HP_HASHSIZE,
01026      (LPBYTE)&hash.cbData, &size, 0);
01027     if (ret)
01028     {
01029         hash.pbData = CryptMemAlloc(hash.cbData);
01030         ret = CryptGetHashParam(
01031          msg_data->signerHandles[signerIndex].contentHash, HP_HASHVAL,
01032          hash.pbData, &hash.cbData, 0);
01033         if (ret)
01034         {
01035             ret = CRYPT_AsnEncodeOctets(0, NULL, &hash, CRYPT_ENCODE_ALLOC_FLAG,
01036              NULL, (LPBYTE)&encodedHash.pbData, &encodedHash.cbData);
01037             if (ret)
01038             {
01039                 ret = CRYPT_AppendAttribute(
01040                  &msg_data->info->rgSignerInfo[signerIndex].AuthAttrs,
01041                  &messageDigestAttr);
01042                 LocalFree(encodedHash.pbData);
01043             }
01044         }
01045         CryptMemFree(hash.pbData);
01046     }
01047     return ret;
01048 }
01049 
01050 typedef enum {
01051     Sign,
01052     Verify
01053 } SignOrVerify;
01054 
01055 static BOOL CSignedMsgData_UpdateAuthenticatedAttributes(
01056  CSignedMsgData *msg_data, SignOrVerify flag)
01057 {
01058     DWORD i;
01059     BOOL ret = TRUE;
01060 
01061     TRACE("(%p)\n", msg_data);
01062 
01063     for (i = 0; ret && i < msg_data->info->cSignerInfo; i++)
01064     {
01065         if (msg_data->info->rgSignerInfo[i].AuthAttrs.cAttr)
01066         {
01067             if (flag == Sign)
01068             {
01069                 BYTE oid_rsa_data_encoded[] = { 0x06,0x09,0x2a,0x86,0x48,0x86,
01070                  0xf7,0x0d,0x01,0x07,0x01 };
01071                 CRYPT_DATA_BLOB content = { sizeof(oid_rsa_data_encoded),
01072                  oid_rsa_data_encoded };
01073                 char contentType[] = szOID_RSA_contentType;
01074                 CRYPT_ATTRIBUTE contentTypeAttr = { contentType, 1, &content };
01075 
01076                 /* FIXME: does this depend on inner OID? */
01077                 ret = CRYPT_AppendAttribute(
01078                  &msg_data->info->rgSignerInfo[i].AuthAttrs, &contentTypeAttr);
01079                 if (ret)
01080                     ret = CSignedMsgData_AppendMessageDigestAttribute(msg_data,
01081                      i);
01082             }
01083             if (ret)
01084             {
01085                 LPBYTE encodedAttrs;
01086                 DWORD size;
01087 
01088                 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, PKCS_ATTRIBUTES,
01089                  &msg_data->info->rgSignerInfo[i].AuthAttrs,
01090                  CRYPT_ENCODE_ALLOC_FLAG, NULL, &encodedAttrs, &size);
01091                 if (ret)
01092                 {
01093                     ret = CryptHashData(
01094                      msg_data->signerHandles[i].authAttrHash, encodedAttrs,
01095                      size, 0);
01096                     LocalFree(encodedAttrs);
01097                 }
01098             }
01099         }
01100     }
01101     TRACE("returning %d\n", ret);
01102     return ret;
01103 }
01104 
01105 static void CRYPT_ReverseBytes(CRYPT_HASH_BLOB *hash)
01106 {
01107     DWORD i;
01108     BYTE tmp;
01109 
01110     for (i = 0; i < hash->cbData / 2; i++)
01111     {
01112         tmp = hash->pbData[hash->cbData - i - 1];
01113         hash->pbData[hash->cbData - i - 1] = hash->pbData[i];
01114         hash->pbData[i] = tmp;
01115     }
01116 }
01117 
01118 static BOOL CSignedMsgData_Sign(CSignedMsgData *msg_data)
01119 {
01120     DWORD i;
01121     BOOL ret = TRUE;
01122 
01123     TRACE("(%p)\n", msg_data);
01124 
01125     for (i = 0; ret && i < msg_data->info->cSignerInfo; i++)
01126     {
01127         HCRYPTHASH hash;
01128 
01129         if (msg_data->info->rgSignerInfo[i].AuthAttrs.cAttr)
01130             hash = msg_data->signerHandles[i].authAttrHash;
01131         else
01132             hash = msg_data->signerHandles[i].contentHash;
01133         ret = CryptSignHashW(hash, AT_SIGNATURE, NULL, 0, NULL,
01134          &msg_data->info->rgSignerInfo[i].EncryptedHash.cbData);
01135         if (ret)
01136         {
01137             msg_data->info->rgSignerInfo[i].EncryptedHash.pbData =
01138              CryptMemAlloc(
01139              msg_data->info->rgSignerInfo[i].EncryptedHash.cbData);
01140             if (msg_data->info->rgSignerInfo[i].EncryptedHash.pbData)
01141             {
01142                 ret = CryptSignHashW(hash, AT_SIGNATURE, NULL, 0,
01143                  msg_data->info->rgSignerInfo[i].EncryptedHash.pbData,
01144                  &msg_data->info->rgSignerInfo[i].EncryptedHash.cbData);
01145                 if (ret)
01146                     CRYPT_ReverseBytes(
01147                      &msg_data->info->rgSignerInfo[i].EncryptedHash);
01148             }
01149             else
01150                 ret = FALSE;
01151         }
01152     }
01153     return ret;
01154 }
01155 
01156 static BOOL CSignedMsgData_Update(CSignedMsgData *msg_data,
01157  const BYTE *pbData, DWORD cbData, BOOL fFinal, SignOrVerify flag)
01158 {
01159     BOOL ret = CSignedMsgData_UpdateHash(msg_data, pbData, cbData);
01160 
01161     if (ret && fFinal)
01162     {
01163         ret = CSignedMsgData_UpdateAuthenticatedAttributes(msg_data, flag);
01164         if (ret && flag == Sign)
01165             ret = CSignedMsgData_Sign(msg_data);
01166     }
01167     return ret;
01168 }
01169 
01170 typedef struct _CSignedEncodeMsg
01171 {
01172     CryptMsgBase    base;
01173     LPSTR           innerOID;
01174     CRYPT_DATA_BLOB data;
01175     CSignedMsgData  msg_data;
01176 } CSignedEncodeMsg;
01177 
01178 static void CSignedEncodeMsg_Close(HCRYPTMSG hCryptMsg)
01179 {
01180     CSignedEncodeMsg *msg = hCryptMsg;
01181     DWORD i;
01182 
01183     CryptMemFree(msg->innerOID);
01184     CryptMemFree(msg->data.pbData);
01185     CRYPT_FreeBlobArray(msg->msg_data.info->cCertEncoded,
01186      msg->msg_data.info->rgCertEncoded);
01187     CRYPT_FreeBlobArray(msg->msg_data.info->cCrlEncoded,
01188      msg->msg_data.info->rgCrlEncoded);
01189     for (i = 0; i < msg->msg_data.info->cSignerInfo; i++)
01190         CSignerInfo_Free(&msg->msg_data.info->rgSignerInfo[i]);
01191     CSignedMsgData_CloseHandles(&msg->msg_data);
01192     CryptMemFree(msg->msg_data.info->rgSignerInfo);
01193     CryptMemFree(msg->msg_data.info);
01194 }
01195 
01196 static BOOL CSignedEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
01197  DWORD dwIndex, void *pvData, DWORD *pcbData)
01198 {
01199     CSignedEncodeMsg *msg = hCryptMsg;
01200     BOOL ret = FALSE;
01201 
01202     switch (dwParamType)
01203     {
01204     case CMSG_CONTENT_PARAM:
01205     {
01206         CRYPT_CONTENT_INFO info;
01207 
01208         ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0, NULL,
01209          &info.Content.cbData);
01210         if (ret)
01211         {
01212             info.Content.pbData = CryptMemAlloc(info.Content.cbData);
01213             if (info.Content.pbData)
01214             {
01215                 ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0,
01216                  info.Content.pbData, &info.Content.cbData);
01217                 if (ret)
01218                 {
01219                     char oid_rsa_signed[] = szOID_RSA_signedData;
01220 
01221                     info.pszObjId = oid_rsa_signed;
01222                     ret = CryptEncodeObjectEx(X509_ASN_ENCODING,
01223                      PKCS_CONTENT_INFO, &info, 0, NULL, pvData, pcbData);
01224                 }
01225                 CryptMemFree(info.Content.pbData);
01226             }
01227             else
01228                 ret = FALSE;
01229         }
01230         break;
01231     }
01232     case CMSG_BARE_CONTENT_PARAM:
01233     {
01234         CRYPT_SIGNED_INFO info;
01235         BOOL freeContent = FALSE;
01236 
01237         info = *msg->msg_data.info;
01238         if (!msg->innerOID || !strcmp(msg->innerOID, szOID_RSA_data))
01239         {
01240             char oid_rsa_data[] = szOID_RSA_data;
01241 
01242             /* Quirk:  OID is only encoded messages if an update has happened */
01243             if (msg->base.state != MsgStateInit)
01244                 info.content.pszObjId = oid_rsa_data;
01245             else
01246                 info.content.pszObjId = NULL;
01247             if (msg->data.cbData)
01248             {
01249                 CRYPT_DATA_BLOB blob = { msg->data.cbData, msg->data.pbData };
01250 
01251                 ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING,
01252                  &blob, CRYPT_ENCODE_ALLOC_FLAG, NULL,
01253                  &info.content.Content.pbData, &info.content.Content.cbData);
01254                 freeContent = TRUE;
01255             }
01256             else
01257             {
01258                 info.content.Content.cbData = 0;
01259                 info.content.Content.pbData = NULL;
01260                 ret = TRUE;
01261             }
01262         }
01263         else
01264         {
01265             info.content.pszObjId = msg->innerOID;
01266             info.content.Content.cbData = msg->data.cbData;
01267             info.content.Content.pbData = msg->data.pbData;
01268             ret = TRUE;
01269         }
01270         if (ret)
01271         {
01272             ret = CRYPT_AsnEncodeCMSSignedInfo(&info, pvData, pcbData);
01273             if (freeContent)
01274                 LocalFree(info.content.Content.pbData);
01275         }
01276         break;
01277     }
01278     case CMSG_COMPUTED_HASH_PARAM:
01279         if (dwIndex >= msg->msg_data.cSignerHandle)
01280             SetLastError(CRYPT_E_INVALID_INDEX);
01281         else
01282             ret = CryptGetHashParam(
01283              msg->msg_data.signerHandles[dwIndex].contentHash, HP_HASHVAL,
01284              pvData, pcbData, 0);
01285         break;
01286     case CMSG_ENCODED_SIGNER:
01287         if (dwIndex >= msg->msg_data.info->cSignerInfo)
01288             SetLastError(CRYPT_E_INVALID_INDEX);
01289         else
01290             ret = CryptEncodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
01291              CMS_SIGNER_INFO, &msg->msg_data.info->rgSignerInfo[dwIndex], 0,
01292              NULL, pvData, pcbData);
01293         break;
01294     case CMSG_VERSION_PARAM:
01295         ret = CRYPT_CopyParam(pvData, pcbData, &msg->msg_data.info->version,
01296          sizeof(msg->msg_data.info->version));
01297         break;
01298     default:
01299         SetLastError(CRYPT_E_INVALID_MSG_TYPE);
01300     }
01301     return ret;
01302 }
01303 
01304 static BOOL CSignedEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
01305  DWORD cbData, BOOL fFinal)
01306 {
01307     CSignedEncodeMsg *msg = hCryptMsg;
01308     BOOL ret = FALSE;
01309 
01310     if (msg->base.state == MsgStateFinalized)
01311         SetLastError(CRYPT_E_MSG_ERROR);
01312     else if (msg->base.streamed || (msg->base.open_flags & CMSG_DETACHED_FLAG))
01313     {
01314         ret = CSignedMsgData_Update(&msg->msg_data, pbData, cbData, fFinal,
01315          Sign);
01316         if (msg->base.streamed)
01317             FIXME("streamed partial stub\n");
01318         msg->base.state = fFinal ? MsgStateFinalized : MsgStateUpdated;
01319     }
01320     else
01321     {
01322         if (!fFinal)
01323             SetLastError(CRYPT_E_MSG_ERROR);
01324         else
01325         {
01326             if (cbData)
01327             {
01328                 msg->data.pbData = CryptMemAlloc(cbData);
01329                 if (msg->data.pbData)
01330                 {
01331                     memcpy(msg->data.pbData, pbData, cbData);
01332                     msg->data.cbData = cbData;
01333                     ret = TRUE;
01334                 }
01335             }
01336             else
01337                 ret = TRUE;
01338             if (ret)
01339                 ret = CSignedMsgData_Update(&msg->msg_data, pbData, cbData,
01340                  fFinal, Sign);
01341             msg->base.state = MsgStateFinalized;
01342         }
01343     }
01344     return ret;
01345 }
01346 
01347 static HCRYPTMSG CSignedEncodeMsg_Open(DWORD dwFlags,
01348  const void *pvMsgEncodeInfo, LPCSTR pszInnerContentObjID,
01349  PCMSG_STREAM_INFO pStreamInfo)
01350 {
01351     const CMSG_SIGNED_ENCODE_INFO_WITH_CMS *info = pvMsgEncodeInfo;
01352     DWORD i;
01353     CSignedEncodeMsg *msg;
01354 
01355     if (info->cbSize != sizeof(CMSG_SIGNED_ENCODE_INFO) &&
01356      info->cbSize != sizeof(CMSG_SIGNED_ENCODE_INFO_WITH_CMS))
01357     {
01358         SetLastError(E_INVALIDARG);
01359         return NULL;
01360     }
01361     if (info->cbSize == sizeof(CMSG_SIGNED_ENCODE_INFO_WITH_CMS) &&
01362      info->cAttrCertEncoded)
01363     {
01364         FIXME("CMSG_SIGNED_ENCODE_INFO with CMS fields unsupported\n");
01365         return NULL;
01366     }
01367     for (i = 0; i < info->cSigners; i++)
01368         if (!CRYPT_IsValidSigner(&info->rgSigners[i]))
01369             return NULL;
01370     msg = CryptMemAlloc(sizeof(CSignedEncodeMsg));
01371     if (msg)
01372     {
01373         BOOL ret = TRUE;
01374 
01375         CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo,
01376          CSignedEncodeMsg_Close, CSignedEncodeMsg_GetParam,
01377          CSignedEncodeMsg_Update, CRYPT_DefaultMsgControl);
01378         if (pszInnerContentObjID)
01379         {
01380             msg->innerOID = CryptMemAlloc(strlen(pszInnerContentObjID) + 1);
01381             if (msg->innerOID)
01382                 strcpy(msg->innerOID, pszInnerContentObjID);
01383             else
01384                 ret = FALSE;
01385         }
01386         else
01387             msg->innerOID = NULL;
01388         msg->data.cbData = 0;
01389         msg->data.pbData = NULL;
01390         if (ret)
01391             msg->msg_data.info = CryptMemAlloc(sizeof(CRYPT_SIGNED_INFO));
01392         else
01393             msg->msg_data.info = NULL;
01394         if (msg->msg_data.info)
01395         {
01396             memset(msg->msg_data.info, 0, sizeof(CRYPT_SIGNED_INFO));
01397             msg->msg_data.info->version = CMSG_SIGNED_DATA_V1;
01398         }
01399         else
01400             ret = FALSE;
01401         if (ret)
01402         {
01403             if (info->cSigners)
01404             {
01405                 msg->msg_data.info->rgSignerInfo =
01406                  CryptMemAlloc(info->cSigners * sizeof(CMSG_CMS_SIGNER_INFO));
01407                 if (msg->msg_data.info->rgSignerInfo)
01408                 {
01409                     msg->msg_data.info->cSignerInfo = info->cSigners;
01410                     memset(msg->msg_data.info->rgSignerInfo, 0,
01411                      msg->msg_data.info->cSignerInfo *
01412                      sizeof(CMSG_CMS_SIGNER_INFO));
01413                     ret = CSignedMsgData_AllocateHandles(&msg->msg_data);
01414                     for (i = 0; ret && i < msg->msg_data.info->cSignerInfo; i++)
01415                     {
01416                         if (info->rgSigners[i].SignerId.dwIdChoice ==
01417                          CERT_ID_KEY_IDENTIFIER)
01418                             msg->msg_data.info->version = CMSG_SIGNED_DATA_V3;
01419                         ret = CSignerInfo_Construct(
01420                          &msg->msg_data.info->rgSignerInfo[i],
01421                          &info->rgSigners[i]);
01422                         if (ret)
01423                         {
01424                             ret = CSignedMsgData_ConstructSignerHandles(
01425                              &msg->msg_data, i, info->rgSigners[i].hCryptProv);
01426                             if (dwFlags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG)
01427                                 CryptReleaseContext(info->rgSigners[i].hCryptProv,
01428                                  0);
01429                         }
01430                     }
01431                 }
01432                 else
01433                     ret = FALSE;
01434             }
01435             else
01436             {
01437                 msg->msg_data.info->cSignerInfo = 0;
01438                 msg->msg_data.signerHandles = NULL;
01439                 msg->msg_data.cSignerHandle = 0;
01440             }
01441         }
01442         if (ret)
01443             ret = CRYPT_ConstructBlobArray(&msg->msg_data.info->cCertEncoded,
01444              &msg->msg_data.info->rgCertEncoded, info->cCertEncoded,
01445              info->rgCertEncoded);
01446         if (ret)
01447             ret = CRYPT_ConstructBlobArray(&msg->msg_data.info->cCrlEncoded,
01448              &msg->msg_data.info->rgCrlEncoded, info->cCrlEncoded,
01449              info->rgCrlEncoded);
01450         if (!ret)
01451         {
01452             CSignedEncodeMsg_Close(msg);
01453             msg = NULL;
01454         }
01455     }
01456     return msg;
01457 }
01458 
01459 typedef struct _CMSG_ENVELOPED_ENCODE_INFO_WITH_CMS
01460 {
01461     DWORD                       cbSize;
01462     HCRYPTPROV_LEGACY           hCryptProv;
01463     CRYPT_ALGORITHM_IDENTIFIER  ContentEncryptionAlgorithm;
01464     void                       *pvEncryptionAuxInfo;
01465     DWORD                       cRecipients;
01466     PCERT_INFO                 *rgpRecipientCert;
01467     PCMSG_RECIPIENT_ENCODE_INFO rgCmsRecipients;
01468     DWORD                       cCertEncoded;
01469     PCERT_BLOB                  rgCertEncoded;
01470     DWORD                       cCrlEncoded;
01471     PCRL_BLOB                   rgCrlEncoded;
01472     DWORD                       cAttrCertEncoded;
01473     PCERT_BLOB                  rgAttrCertEncoded;
01474     DWORD                       cUnprotectedAttr;
01475     PCRYPT_ATTRIBUTE            rgUnprotectedAttr;
01476 } CMSG_ENVELOPED_ENCODE_INFO_WITH_CMS, *PCMSG_ENVELOPED_ENCODE_INFO_WITH_CMS;
01477 
01478 typedef struct _CEnvelopedEncodeMsg
01479 {
01480     CryptMsgBase                   base;
01481     CRYPT_ALGORITHM_IDENTIFIER     algo;
01482     HCRYPTPROV                     prov;
01483     HCRYPTKEY                      key;
01484     DWORD                          cRecipientInfo;
01485     CMSG_KEY_TRANS_RECIPIENT_INFO *recipientInfo;
01486     CRYPT_DATA_BLOB                data;
01487 } CEnvelopedEncodeMsg;
01488 
01489 static BOOL CRYPT_ConstructAlgorithmId(CRYPT_ALGORITHM_IDENTIFIER *out,
01490  const CRYPT_ALGORITHM_IDENTIFIER *in)
01491 {
01492     out->pszObjId = CryptMemAlloc(strlen(in->pszObjId) + 1);
01493     if (out->pszObjId)
01494     {
01495         strcpy(out->pszObjId, in->pszObjId);
01496         return CRYPT_ConstructBlob(&out->Parameters, &in->Parameters);
01497     }
01498     else
01499         return FALSE;
01500 }
01501 
01502 static BOOL CRYPT_ConstructBitBlob(CRYPT_BIT_BLOB *out, const CRYPT_BIT_BLOB *in)
01503 {
01504     out->cbData = in->cbData;
01505     out->cUnusedBits = in->cUnusedBits;
01506     if (out->cbData)
01507     {
01508         out->pbData = CryptMemAlloc(out->cbData);
01509         if (out->pbData)
01510             memcpy(out->pbData, in->pbData, out->cbData);
01511         else
01512             return FALSE;
01513     }
01514     else
01515         out->pbData = NULL;
01516     return TRUE;
01517 }
01518 
01519 static BOOL CRYPT_GenKey(CMSG_CONTENT_ENCRYPT_INFO *info, ALG_ID algID)
01520 {
01521     static HCRYPTOIDFUNCSET set = NULL;
01522     PFN_CMSG_GEN_CONTENT_ENCRYPT_KEY genKeyFunc = NULL;
01523     HCRYPTOIDFUNCADDR hFunc;
01524     BOOL ret;
01525 
01526     if (!set)
01527         set = CryptInitOIDFunctionSet(CMSG_OID_GEN_CONTENT_ENCRYPT_KEY_FUNC, 0);
01528     CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING,
01529      info->ContentEncryptionAlgorithm.pszObjId, 0, (void **)&genKeyFunc, &hFunc);
01530     if (genKeyFunc)
01531     {
01532         ret = genKeyFunc(info, 0, NULL);
01533         CryptFreeOIDFunctionAddress(hFunc, 0);
01534     }
01535     else
01536         ret = CryptGenKey(info->hCryptProv, algID, CRYPT_EXPORTABLE,
01537          &info->hContentEncryptKey);
01538     return ret;
01539 }
01540 
01541 static BOOL WINAPI CRYPT_ExportKeyTrans(
01542  PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo,
01543  PCMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO pKeyTransEncodeInfo,
01544  PCMSG_KEY_TRANS_ENCRYPT_INFO pKeyTransEncryptInfo,
01545  DWORD dwFlags, void *pvReserved)
01546 {
01547     CERT_PUBLIC_KEY_INFO keyInfo;
01548     HCRYPTKEY expKey;
01549     BOOL ret;
01550 
01551     ret = CRYPT_ConstructAlgorithmId(&keyInfo.Algorithm,
01552         &pKeyTransEncodeInfo->KeyEncryptionAlgorithm);
01553     if (ret)
01554         CRYPT_ConstructBitBlob(&keyInfo.PublicKey,
01555          &pKeyTransEncodeInfo->RecipientPublicKey);
01556 
01557     if (ret)
01558         ret = CryptImportPublicKeyInfo(pKeyTransEncodeInfo->hCryptProv,
01559          X509_ASN_ENCODING, &keyInfo, &expKey);
01560     if (ret)
01561     {
01562         DWORD size;
01563 
01564         ret = CryptExportKey(pContentEncryptInfo->hContentEncryptKey, expKey,
01565          SIMPLEBLOB, 0, NULL, &size);
01566         if (ret)
01567         {
01568             BYTE *keyBlob;
01569 
01570             keyBlob = CryptMemAlloc(size);
01571             if (keyBlob)
01572             {
01573                 ret = CryptExportKey(pContentEncryptInfo->hContentEncryptKey,
01574                  expKey, SIMPLEBLOB, 0, keyBlob, &size);
01575                 if (ret)
01576                 {
01577                     DWORD head = sizeof(BLOBHEADER) + sizeof(ALG_ID);
01578 
01579                     pKeyTransEncryptInfo->EncryptedKey.pbData =
01580                      CryptMemAlloc(size - head);
01581                     if (pKeyTransEncryptInfo->EncryptedKey.pbData)
01582                     {
01583                         DWORD i, k = 0;
01584 
01585                         pKeyTransEncryptInfo->EncryptedKey.cbData = size - head;
01586                         for (i = size - 1; i >= head; --i, ++k)
01587                             pKeyTransEncryptInfo->EncryptedKey.pbData[k] =
01588                              keyBlob[i];
01589                     }
01590                     else
01591                         ret = FALSE;
01592                 }
01593                 CryptMemFree(keyBlob);
01594             }
01595             else
01596                 ret = FALSE;
01597         }
01598         CryptDestroyKey(expKey);
01599     }
01600 
01601     CryptMemFree(keyInfo.PublicKey.pbData);
01602     CryptMemFree(keyInfo.Algorithm.pszObjId);
01603     CryptMemFree(keyInfo.Algorithm.Parameters.pbData);
01604     return ret;
01605 }
01606 
01607 static BOOL CRYPT_ExportEncryptedKey(CMSG_CONTENT_ENCRYPT_INFO *info, DWORD i,
01608  CRYPT_DATA_BLOB *key)
01609 {
01610     static HCRYPTOIDFUNCSET set = NULL;
01611     PFN_CMSG_EXPORT_KEY_TRANS exportKeyFunc = NULL;
01612     HCRYPTOIDFUNCADDR hFunc = NULL;
01613     CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO *encodeInfo =
01614      info->rgCmsRecipients[i].u.pKeyTrans;
01615     CMSG_KEY_TRANS_ENCRYPT_INFO encryptInfo;
01616     BOOL ret;
01617 
01618     memset(&encryptInfo, 0, sizeof(encryptInfo));
01619     encryptInfo.cbSize = sizeof(encryptInfo);
01620     encryptInfo.dwRecipientIndex = i;
01621     ret = CRYPT_ConstructAlgorithmId(&encryptInfo.KeyEncryptionAlgorithm,
01622      &encodeInfo->KeyEncryptionAlgorithm);
01623 
01624     if (!set)
01625         set = CryptInitOIDFunctionSet(CMSG_OID_EXPORT_KEY_TRANS_FUNC, 0);
01626     CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING,
01627      encryptInfo.KeyEncryptionAlgorithm.pszObjId, 0, (void **)&exportKeyFunc,
01628      &hFunc);
01629     if (!exportKeyFunc)
01630         exportKeyFunc = CRYPT_ExportKeyTrans;
01631     if (ret)
01632     {
01633         ret = exportKeyFunc(info, encodeInfo, &encryptInfo, 0, NULL);
01634         if (ret)
01635         {
01636             key->cbData = encryptInfo.EncryptedKey.cbData;
01637             key->pbData = encryptInfo.EncryptedKey.pbData;
01638         }
01639     }
01640     if (hFunc)
01641         CryptFreeOIDFunctionAddress(hFunc, 0);
01642 
01643     CryptMemFree(encryptInfo.KeyEncryptionAlgorithm.pszObjId);
01644     CryptMemFree(encryptInfo.KeyEncryptionAlgorithm.Parameters.pbData);
01645     return ret;
01646 }
01647 
01648 static LPVOID WINAPI mem_alloc(size_t size)
01649 {
01650     return HeapAlloc(GetProcessHeap(), 0, size);
01651 }
01652 
01653 static VOID WINAPI mem_free(LPVOID pv)
01654 {
01655     HeapFree(GetProcessHeap(), 0, pv);
01656 }
01657 
01658 
01659 static BOOL CContentEncryptInfo_Construct(CMSG_CONTENT_ENCRYPT_INFO *info,
01660  const CMSG_ENVELOPED_ENCODE_INFO_WITH_CMS *in, HCRYPTPROV prov)
01661 {
01662     BOOL ret;
01663 
01664     info->cbSize = sizeof(CMSG_CONTENT_ENCRYPT_INFO);
01665     info->hCryptProv = prov;
01666     ret = CRYPT_ConstructAlgorithmId(&info->ContentEncryptionAlgorithm,
01667      &in->ContentEncryptionAlgorithm);
01668     info->pvEncryptionAuxInfo = in->pvEncryptionAuxInfo;
01669     info->cRecipients = in->cRecipients;
01670     if (ret)
01671     {
01672         info->rgCmsRecipients = CryptMemAlloc(in->cRecipients *
01673          sizeof(CMSG_RECIPIENT_ENCODE_INFO));
01674         if (info->rgCmsRecipients)
01675         {
01676             DWORD i;
01677 
01678             for (i = 0; ret && i < in->cRecipients; ++i)
01679             {
01680                 CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO *encodeInfo;
01681                 CERT_INFO *cert = in->rgpRecipientCert[i];
01682 
01683                 info->rgCmsRecipients[i].dwRecipientChoice =
01684                  CMSG_KEY_TRANS_RECIPIENT;
01685                 encodeInfo = CryptMemAlloc(sizeof(*encodeInfo));
01686                 info->rgCmsRecipients[i].u.pKeyTrans = encodeInfo;
01687                 if (encodeInfo)
01688                 {
01689                     encodeInfo->cbSize = sizeof(*encodeInfo);
01690                     ret = CRYPT_ConstructAlgorithmId(
01691                      &encodeInfo->KeyEncryptionAlgorithm,
01692                      &cert->SubjectPublicKeyInfo.Algorithm);
01693                     encodeInfo->pvKeyEncryptionAuxInfo = NULL;
01694                     encodeInfo->hCryptProv = prov;
01695                     if (ret)
01696                         ret = CRYPT_ConstructBitBlob(
01697                          &encodeInfo->RecipientPublicKey,
01698                          &cert->SubjectPublicKeyInfo.PublicKey);
01699                     if (ret)
01700                         ret = CRYPT_ConstructBlob(
01701                          &encodeInfo->RecipientId.u.IssuerSerialNumber.Issuer,
01702                          &cert->Issuer);
01703                     if (ret)
01704                         ret = CRYPT_ConstructBlob(
01705                          &encodeInfo->RecipientId.u.IssuerSerialNumber.SerialNumber,
01706                          &cert->SerialNumber);
01707                 }
01708                 else
01709                     ret = FALSE;
01710             }
01711         }
01712         else
01713             ret = FALSE;
01714     }
01715     info->pfnAlloc = mem_alloc;
01716     info->pfnFree = mem_free;
01717     return ret;
01718 }
01719 
01720 static void CContentEncryptInfo_Free(CMSG_CONTENT_ENCRYPT_INFO *info)
01721 {
01722     CryptMemFree(info->ContentEncryptionAlgorithm.pszObjId);
01723     CryptMemFree(info->ContentEncryptionAlgorithm.Parameters.pbData);
01724     if (info->rgCmsRecipients)
01725     {
01726         DWORD i;
01727 
01728         for (i = 0; i < info->cRecipients; ++i)
01729         {
01730             CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO *encodeInfo =
01731              info->rgCmsRecipients[i].u.pKeyTrans;
01732 
01733             CryptMemFree(encodeInfo->KeyEncryptionAlgorithm.pszObjId);
01734             CryptMemFree(encodeInfo->KeyEncryptionAlgorithm.Parameters.pbData);
01735             CryptMemFree(encodeInfo->RecipientPublicKey.pbData);
01736             CryptMemFree(
01737              encodeInfo->RecipientId.u.IssuerSerialNumber.Issuer.pbData);
01738             CryptMemFree(
01739              encodeInfo->RecipientId.u.IssuerSerialNumber.SerialNumber.pbData);
01740             CryptMemFree(encodeInfo);
01741         }
01742         CryptMemFree(info->rgCmsRecipients);
01743     }
01744 }
01745 
01746 static BOOL CRecipientInfo_Construct(CMSG_KEY_TRANS_RECIPIENT_INFO *info,
01747  const CERT_INFO *cert, CRYPT_DATA_BLOB *key)
01748 {
01749     BOOL ret;
01750 
01751     info->dwVersion = CMSG_KEY_TRANS_PKCS_1_5_VERSION;
01752     info->RecipientId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
01753     ret = CRYPT_ConstructBlob(&info->RecipientId.u.IssuerSerialNumber.Issuer,
01754      &cert->Issuer);
01755     if (ret)
01756         ret = CRYPT_ConstructBlob(
01757          &info->RecipientId.u.IssuerSerialNumber.SerialNumber,
01758          &cert->SerialNumber);
01759     if (ret)
01760         ret = CRYPT_ConstructAlgorithmId(&info->KeyEncryptionAlgorithm,
01761          &cert->SubjectPublicKeyInfo.Algorithm);
01762     info->EncryptedKey.cbData = key->cbData;
01763     info->EncryptedKey.pbData = key->pbData;
01764     return ret;
01765 }
01766 
01767 static void CRecipientInfo_Free(CMSG_KEY_TRANS_RECIPIENT_INFO *info)
01768 {
01769     CryptMemFree(info->RecipientId.u.IssuerSerialNumber.Issuer.pbData);
01770     CryptMemFree(info->RecipientId.u.IssuerSerialNumber.SerialNumber.pbData);
01771     CryptMemFree(info->KeyEncryptionAlgorithm.pszObjId);
01772     CryptMemFree(info->KeyEncryptionAlgorithm.Parameters.pbData);
01773     CryptMemFree(info->EncryptedKey.pbData);
01774 }
01775 
01776 static void CEnvelopedEncodeMsg_Close(HCRYPTMSG hCryptMsg)
01777 {
01778     CEnvelopedEncodeMsg *msg = hCryptMsg;
01779 
01780     CryptMemFree(msg->algo.pszObjId);
01781     CryptMemFree(msg->algo.Parameters.pbData);
01782     if (msg->base.open_flags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG)
01783         CryptReleaseContext(msg->prov, 0);
01784     CryptDestroyKey(msg->key);
01785     if (msg->recipientInfo)
01786     {
01787         DWORD i;
01788 
01789         for (i = 0; i < msg->cRecipientInfo; ++i)
01790             CRecipientInfo_Free(&msg->recipientInfo[i]);
01791         CryptMemFree(msg->recipientInfo);
01792     }
01793     CryptMemFree(msg->data.pbData);
01794 }
01795 
01796 static BOOL CEnvelopedEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
01797  DWORD dwIndex, void *pvData, DWORD *pcbData)
01798 {
01799     CEnvelopedEncodeMsg *msg = hCryptMsg;
01800     BOOL ret = FALSE;
01801 
01802     switch (dwParamType)
01803     {
01804     case CMSG_BARE_CONTENT_PARAM:
01805         if (msg->base.streamed)
01806             SetLastError(E_INVALIDARG);
01807         else
01808         {
01809             char oid_rsa_data[] = szOID_RSA_data;
01810             CRYPT_ENVELOPED_DATA envelopedData = {
01811              CMSG_ENVELOPED_DATA_PKCS_1_5_VERSION, msg->cRecipientInfo,
01812              msg->recipientInfo, { oid_rsa_data, {
01813                msg->algo.pszObjId,
01814                { msg->algo.Parameters.cbData, msg->algo.Parameters.pbData }
01815               },
01816               { msg->data.cbData, msg->data.pbData }
01817              }
01818             };
01819 
01820             ret = CRYPT_AsnEncodePKCSEnvelopedData(&envelopedData, pvData,
01821              pcbData);
01822         }
01823         break;
01824     case CMSG_CONTENT_PARAM:
01825     {
01826         CRYPT_CONTENT_INFO info;
01827 
01828         ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0, NULL,
01829          &info.Content.cbData);
01830         if (ret)
01831         {
01832             info.Content.pbData = CryptMemAlloc(info.Content.cbData);
01833             if (info.Content.pbData)
01834             {
01835                 ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0,
01836                  info.Content.pbData, &info.Content.cbData);
01837                 if (ret)
01838                 {
01839                     char oid_rsa_enveloped[] = szOID_RSA_envelopedData;
01840 
01841                     info.pszObjId = oid_rsa_enveloped;
01842                     ret = CryptEncodeObjectEx(X509_ASN_ENCODING,
01843                      PKCS_CONTENT_INFO, &info, 0, NULL, pvData, pcbData);
01844                 }
01845                 CryptMemFree(info.Content.pbData);
01846             }
01847             else
01848                 ret = FALSE;
01849         }
01850         break;
01851     }
01852     default:
01853         SetLastError(CRYPT_E_INVALID_MSG_TYPE);
01854     }
01855     return ret;
01856 }
01857 
01858 static BOOL CEnvelopedEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
01859  DWORD cbData, BOOL fFinal)
01860 {
01861     CEnvelopedEncodeMsg *msg = hCryptMsg;
01862     BOOL ret = FALSE;
01863 
01864     if (msg->base.state == MsgStateFinalized)
01865         SetLastError(CRYPT_E_MSG_ERROR);
01866     else if (msg->base.streamed)
01867     {
01868         FIXME("streamed stub\n");
01869         msg->base.state = fFinal ? MsgStateFinalized : MsgStateUpdated;
01870         ret = TRUE;
01871     }
01872     else
01873     {
01874         if (!fFinal)
01875         {
01876             if (msg->base.open_flags & CMSG_DETACHED_FLAG)
01877                 SetLastError(E_INVALIDARG);
01878             else
01879                 SetLastError(CRYPT_E_MSG_ERROR);
01880         }
01881         else
01882         {
01883             if (cbData)
01884             {
01885                 DWORD dataLen = cbData;
01886 
01887                 msg->data.cbData = cbData;
01888                 msg->data.pbData = CryptMemAlloc(cbData);
01889                 if (msg->data.pbData)
01890                 {
01891                     memcpy(msg->data.pbData, pbData, cbData);
01892                     ret = CryptEncrypt(msg->key, 0, TRUE, 0, msg->data.pbData,
01893                      &dataLen, msg->data.cbData);
01894                     msg->data.cbData = dataLen;
01895                     if (dataLen > cbData)
01896                     {
01897                         msg->data.pbData = CryptMemRealloc(msg->data.pbData,
01898                          dataLen);
01899                         if (msg->data.pbData)
01900                         {
01901                             dataLen = cbData;
01902                             ret = CryptEncrypt(msg->key, 0, TRUE, 0,
01903                              msg->data.pbData, &dataLen, msg->data.cbData);
01904                         }
01905                         else
01906                             ret = FALSE;
01907                     }
01908                     if (!ret)
01909                         CryptMemFree(msg->data.pbData);
01910                 }
01911                 else
01912                     ret = FALSE;
01913                 if (!ret)
01914                 {
01915                     msg->data.cbData = 0;
01916                     msg->data.pbData = NULL;
01917                 }
01918             }
01919             else
01920                 ret = TRUE;
01921             msg->base.state = MsgStateFinalized;
01922         }
01923     }
01924     return ret;
01925 }
01926 
01927 static HCRYPTMSG CEnvelopedEncodeMsg_Open(DWORD dwFlags,
01928  const void *pvMsgEncodeInfo, LPCSTR pszInnerContentObjID,
01929  PCMSG_STREAM_INFO pStreamInfo)
01930 {
01931     CEnvelopedEncodeMsg *msg;
01932     const CMSG_ENVELOPED_ENCODE_INFO_WITH_CMS *info = pvMsgEncodeInfo;
01933     HCRYPTPROV prov;
01934     ALG_ID algID;
01935 
01936     if (info->cbSize != sizeof(CMSG_ENVELOPED_ENCODE_INFO) &&
01937      info->cbSize != sizeof(CMSG_ENVELOPED_ENCODE_INFO_WITH_CMS))
01938     {
01939         SetLastError(E_INVALIDARG);
01940         return NULL;
01941     }
01942     if (info->cbSize == sizeof(CMSG_ENVELOPED_ENCODE_INFO_WITH_CMS))
01943         FIXME("CMS fields unsupported\n");
01944     if (!(algID = CertOIDToAlgId(info->ContentEncryptionAlgorithm.pszObjId)))
01945     {
01946         SetLastError(CRYPT_E_UNKNOWN_ALGO);
01947         return NULL;
01948     }
01949     if (info->cRecipients && !info->rgpRecipientCert)
01950     {
01951         SetLastError(E_INVALIDARG);
01952         return NULL;
01953     }
01954     if (info->hCryptProv)
01955         prov = info->hCryptProv;
01956     else
01957     {
01958         prov = CRYPT_GetDefaultProvider();
01959         dwFlags &= ~CMSG_CRYPT_RELEASE_CONTEXT_FLAG;
01960     }
01961     msg = CryptMemAlloc(sizeof(CEnvelopedEncodeMsg));
01962     if (msg)
01963     {
01964         CRYPT_DATA_BLOB encryptedKey = { 0, NULL };
01965         CMSG_CONTENT_ENCRYPT_INFO encryptInfo;
01966         BOOL ret;
01967         DWORD i;
01968 
01969         CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo,
01970          CEnvelopedEncodeMsg_Close, CEnvelopedEncodeMsg_GetParam,
01971          CEnvelopedEncodeMsg_Update, CRYPT_DefaultMsgControl);
01972         ret = CRYPT_ConstructAlgorithmId(&msg->algo,
01973          &info->ContentEncryptionAlgorithm);
01974         msg->prov = prov;
01975         msg->data.cbData = 0;
01976         msg->data.pbData = NULL;
01977         msg->cRecipientInfo = info->cRecipients;
01978         msg->recipientInfo = CryptMemAlloc(info->cRecipients *
01979          sizeof(CMSG_KEY_TRANS_RECIPIENT_INFO));
01980         if (!msg->recipientInfo)
01981             ret = FALSE;
01982         memset(&encryptInfo, 0, sizeof(encryptInfo));
01983         if (ret)
01984         {
01985             ret = CContentEncryptInfo_Construct(&encryptInfo, info, prov);
01986             if (ret)
01987             {
01988                 ret = CRYPT_GenKey(&encryptInfo, algID);
01989                 if (ret)
01990                     msg->key = encryptInfo.hContentEncryptKey;
01991             }
01992         }
01993         for (i = 0; ret && i < msg->cRecipientInfo; ++i)
01994         {
01995             ret = CRYPT_ExportEncryptedKey(&encryptInfo, i, &encryptedKey);
01996             if (ret)
01997                 ret = CRecipientInfo_Construct(&msg->recipientInfo[i],
01998                  info->rgpRecipientCert[i], &encryptedKey);
01999         }
02000         CContentEncryptInfo_Free(&encryptInfo);
02001         if (!ret)
02002         {
02003             CryptMsgClose(msg);
02004             msg = NULL;
02005         }
02006     }
02007     if (!msg && (dwFlags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG))
02008         CryptReleaseContext(prov, 0);
02009     return msg;
02010 }
02011 
02012 HCRYPTMSG WINAPI CryptMsgOpenToEncode(DWORD dwMsgEncodingType, DWORD dwFlags,
02013  DWORD dwMsgType, const void *pvMsgEncodeInfo, LPSTR pszInnerContentObjID,
02014  PCMSG_STREAM_INFO pStreamInfo)
02015 {
02016     HCRYPTMSG msg = NULL;
02017 
02018     TRACE("(%08x, %08x, %08x, %p, %s, %p)\n", dwMsgEncodingType, dwFlags,
02019      dwMsgType, pvMsgEncodeInfo, debugstr_a(pszInnerContentObjID), pStreamInfo);
02020 
02021     if (GET_CMSG_ENCODING_TYPE(dwMsgEncodingType) != PKCS_7_ASN_ENCODING)
02022     {
02023         SetLastError(E_INVALIDARG);
02024         return NULL;
02025     }
02026     switch (dwMsgType)
02027     {
02028     case CMSG_DATA:
02029         msg = CDataEncodeMsg_Open(dwFlags, pvMsgEncodeInfo,
02030          pszInnerContentObjID, pStreamInfo);
02031         break;
02032     case CMSG_HASHED:
02033         msg = CHashEncodeMsg_Open(dwFlags, pvMsgEncodeInfo,
02034          pszInnerContentObjID, pStreamInfo);
02035         break;
02036     case CMSG_SIGNED:
02037         msg = CSignedEncodeMsg_Open(dwFlags, pvMsgEncodeInfo,
02038          pszInnerContentObjID, pStreamInfo);
02039         break;
02040     case CMSG_ENVELOPED:
02041         msg = CEnvelopedEncodeMsg_Open(dwFlags, pvMsgEncodeInfo,
02042          pszInnerContentObjID, pStreamInfo);
02043         break;
02044     case CMSG_SIGNED_AND_ENVELOPED:
02045     case CMSG_ENCRYPTED:
02046         /* defined but invalid, fall through */
02047     default:
02048         SetLastError(CRYPT_E_INVALID_MSG_TYPE);
02049     }
02050     return msg;
02051 }
02052 
02053 typedef struct _CEnvelopedDecodeMsg
02054 {
02055     CRYPT_ENVELOPED_DATA *data;
02056     HCRYPTPROV            crypt_prov;
02057     CRYPT_DATA_BLOB       content;
02058     BOOL                  decrypted;
02059 } CEnvelopedDecodeMsg;
02060 
02061 typedef struct _CDecodeMsg
02062 {
02063     CryptMsgBase           base;
02064     DWORD                  type;
02065     HCRYPTPROV             crypt_prov;
02066     union {
02067         HCRYPTHASH          hash;
02068         CSignedMsgData      signed_data;
02069         CEnvelopedDecodeMsg enveloped_data;
02070     } u;
02071     CRYPT_DATA_BLOB        msg_data;
02072     CRYPT_DATA_BLOB        detached_data;
02073     PCONTEXT_PROPERTY_LIST properties;
02074 } CDecodeMsg;
02075 
02076 static void CDecodeMsg_Close(HCRYPTMSG hCryptMsg)
02077 {
02078     CDecodeMsg *msg = hCryptMsg;
02079 
02080     if (msg->base.open_flags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG)
02081         CryptReleaseContext(msg->crypt_prov, 0);
02082     switch (msg->type)
02083     {
02084     case CMSG_HASHED:
02085         if (msg->u.hash)
02086             CryptDestroyHash(msg->u.hash);
02087         break;
02088     case CMSG_ENVELOPED:
02089         if (msg->u.enveloped_data.crypt_prov)
02090             CryptReleaseContext(msg->u.enveloped_data.crypt_prov, 0);
02091         LocalFree(msg->u.enveloped_data.data);
02092         CryptMemFree(msg->u.enveloped_data.content.pbData);
02093         break;
02094     case CMSG_SIGNED:
02095         if (msg->u.signed_data.info)
02096         {
02097             LocalFree(msg->u.signed_data.info);
02098             CSignedMsgData_CloseHandles(&msg->u.signed_data);
02099         }
02100         break;
02101     }
02102     CryptMemFree(msg->msg_data.pbData);
02103     CryptMemFree(msg->detached_data.pbData);
02104     ContextPropertyList_Free(msg->properties);
02105 }
02106 
02107 static BOOL CDecodeMsg_CopyData(CRYPT_DATA_BLOB *blob, const BYTE *pbData,
02108  DWORD cbData)
02109 {
02110     BOOL ret = TRUE;
02111 
02112     if (cbData)
02113     {
02114         if (blob->cbData)
02115             blob->pbData = CryptMemRealloc(blob->pbData,
02116              blob->cbData + cbData);
02117         else
02118             blob->pbData = CryptMemAlloc(cbData);
02119         if (blob->pbData)
02120         {
02121             memcpy(blob->pbData + blob->cbData, pbData, cbData);
02122             blob->cbData += cbData;
02123         }
02124         else
02125             ret = FALSE;
02126     }
02127     return ret;
02128 }
02129 
02130 static BOOL CDecodeMsg_DecodeDataContent(CDecodeMsg *msg, const CRYPT_DER_BLOB *blob)
02131 {
02132     BOOL ret;
02133     CRYPT_DATA_BLOB *data;
02134     DWORD size;
02135 
02136     ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING,
02137      blob->pbData, blob->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &data, &size);
02138     if (ret)
02139     {
02140         ret = ContextPropertyList_SetProperty(msg->properties,
02141          CMSG_CONTENT_PARAM, data->pbData, data->cbData);
02142         LocalFree(data);
02143     }
02144     return ret;
02145 }
02146 
02147 static void CDecodeMsg_SaveAlgorithmID(CDecodeMsg *msg, DWORD param,
02148  const CRYPT_ALGORITHM_IDENTIFIER *id)
02149 {
02150     static const BYTE nullParams[] = { ASN_NULL, 0 };
02151     CRYPT_ALGORITHM_IDENTIFIER *copy;
02152     DWORD len = sizeof(CRYPT_ALGORITHM_IDENTIFIER);
02153 
02154     /* Linearize algorithm id */
02155     len += strlen(id->pszObjId) + 1;
02156     len += id->Parameters.cbData;
02157     copy = CryptMemAlloc(len);
02158     if (copy)
02159     {
02160         copy->pszObjId =
02161          (LPSTR)((BYTE *)copy + sizeof(CRYPT_ALGORITHM_IDENTIFIER));
02162         strcpy(copy->pszObjId, id->pszObjId);
02163         copy->Parameters.pbData = (BYTE *)copy->pszObjId + strlen(id->pszObjId)
02164          + 1;
02165         /* Trick:  omit NULL parameters */
02166         if (id->Parameters.cbData == sizeof(nullParams) &&
02167          !memcmp(id->Parameters.pbData, nullParams, sizeof(nullParams)))
02168         {
02169             copy->Parameters.cbData = 0;
02170             len -= sizeof(nullParams);
02171         }
02172         else
02173             copy->Parameters.cbData = id->Parameters.cbData;
02174         if (copy->Parameters.cbData)
02175             memcpy(copy->Parameters.pbData, id->Parameters.pbData,
02176              id->Parameters.cbData);
02177         ContextPropertyList_SetProperty(msg->properties, param, (BYTE *)copy,
02178          len);
02179         CryptMemFree(copy);
02180     }
02181 }
02182 
02183 static inline void CRYPT_FixUpAlgorithmID(CRYPT_ALGORITHM_IDENTIFIER *id)
02184 {
02185     id->pszObjId = (LPSTR)((BYTE *)id + sizeof(CRYPT_ALGORITHM_IDENTIFIER));
02186     id->Parameters.pbData = (BYTE *)id->pszObjId + strlen(id->pszObjId) + 1;
02187 }
02188 
02189 static BOOL CDecodeMsg_DecodeHashedContent(CDecodeMsg *msg,
02190  const CRYPT_DER_BLOB *blob)
02191 {
02192     BOOL ret;
02193     CRYPT_DIGESTED_DATA *digestedData;
02194     DWORD size;
02195 
02196     ret = CRYPT_AsnDecodePKCSDigestedData(blob->pbData, blob->cbData,
02197      CRYPT_DECODE_ALLOC_FLAG, NULL, (CRYPT_DIGESTED_DATA *)&digestedData,
02198      &size);
02199     if (ret)
02200     {
02201         ContextPropertyList_SetProperty(msg->properties, CMSG_VERSION_PARAM,
02202          (const BYTE *)&digestedData->version, sizeof(digestedData->version));
02203         CDecodeMsg_SaveAlgorithmID(msg, CMSG_HASH_ALGORITHM_PARAM,
02204          &digestedData->DigestAlgorithm);
02205         ContextPropertyList_SetProperty(msg->properties,
02206          CMSG_INNER_CONTENT_TYPE_PARAM,
02207          (const BYTE *)digestedData->ContentInfo.pszObjId,
02208          digestedData->ContentInfo.pszObjId ?
02209          strlen(digestedData->ContentInfo.pszObjId) + 1 : 0);
02210         if (!(msg->base.open_flags & CMSG_DETACHED_FLAG))
02211         {
02212             if (digestedData->ContentInfo.Content.cbData)
02213                 CDecodeMsg_DecodeDataContent(msg,
02214                  &digestedData->ContentInfo.Content);
02215             else
02216                 ContextPropertyList_SetProperty(msg->properties,
02217                  CMSG_CONTENT_PARAM, NULL, 0);
02218         }
02219         ContextPropertyList_SetProperty(msg->properties, CMSG_HASH_DATA_PARAM,
02220          digestedData->hash.pbData, digestedData->hash.cbData);
02221         LocalFree(digestedData);
02222     }
02223     return ret;
02224 }
02225 
02226 static BOOL CDecodeMsg_DecodeEnvelopedContent(CDecodeMsg *msg,
02227  const CRYPT_DER_BLOB *blob)
02228 {
02229     BOOL ret;
02230     CRYPT_ENVELOPED_DATA *envelopedData;
02231     DWORD size;
02232 
02233     ret = CRYPT_AsnDecodePKCSEnvelopedData(blob->pbData, blob->cbData,
02234      CRYPT_DECODE_ALLOC_FLAG, NULL, (CRYPT_ENVELOPED_DATA *)&envelopedData,
02235      &size);
02236     if (ret)
02237         msg->u.enveloped_data.data = envelopedData;
02238     return ret;
02239 }
02240 
02241 static BOOL CDecodeMsg_DecodeSignedContent(CDecodeMsg *msg,
02242  const CRYPT_DER_BLOB *blob)
02243 {
02244     BOOL ret;
02245     CRYPT_SIGNED_INFO *signedInfo;
02246     DWORD size;
02247 
02248     ret = CRYPT_AsnDecodeCMSSignedInfo(blob->pbData, blob->cbData,
02249      CRYPT_DECODE_ALLOC_FLAG, NULL, (CRYPT_SIGNED_INFO *)&signedInfo,
02250      &size);
02251     if (ret)
02252         msg->u.signed_data.info = signedInfo;
02253     return ret;
02254 }
02255 
02256 /* Decodes the content in blob as the type given, and updates the value
02257  * (type, parameters, etc.) of msg based on what blob contains.
02258  * It doesn't just use msg's type, to allow a recursive call from an implicitly
02259  * typed message once the outer content info has been decoded.
02260  */
02261 static BOOL CDecodeMsg_DecodeContent(CDecodeMsg *msg, const CRYPT_DER_BLOB *blob,
02262  DWORD type)
02263 {
02264     BOOL ret;
02265 
02266     switch (type)
02267     {
02268     case CMSG_DATA:
02269         if ((ret = CDecodeMsg_DecodeDataContent(msg, blob)))
02270             msg->type = CMSG_DATA;
02271         break;
02272     case CMSG_HASHED:
02273         if ((ret = CDecodeMsg_DecodeHashedContent(msg, blob)))
02274             msg->type = CMSG_HASHED;
02275         break;
02276     case CMSG_ENVELOPED:
02277         if ((ret = CDecodeMsg_DecodeEnvelopedContent(msg, blob)))
02278             msg->type = CMSG_ENVELOPED;
02279         break;
02280     case CMSG_SIGNED:
02281         if ((ret = CDecodeMsg_DecodeSignedContent(msg, blob)))
02282             msg->type = CMSG_SIGNED;
02283         break;
02284     default:
02285     {
02286         CRYPT_CONTENT_INFO *info;
02287         DWORD size;
02288 
02289         ret = CryptDecodeObjectEx(X509_ASN_ENCODING, PKCS_CONTENT_INFO,
02290          msg->msg_data.pbData, msg->msg_data.cbData, CRYPT_DECODE_ALLOC_FLAG,
02291          NULL, &info, &size);
02292         if (ret)
02293         {
02294             if (!strcmp(info->pszObjId, szOID_RSA_data))
02295                 ret = CDecodeMsg_DecodeContent(msg, &info->Content, CMSG_DATA);
02296             else if (!strcmp(info->pszObjId, szOID_RSA_digestedData))
02297                 ret = CDecodeMsg_DecodeContent(msg, &info->Content,
02298                  CMSG_HASHED);
02299             else if (!strcmp(info->pszObjId, szOID_RSA_envelopedData))
02300                 ret = CDecodeMsg_DecodeContent(msg, &info->Content,
02301                  CMSG_ENVELOPED);
02302             else if (!strcmp(info->pszObjId, szOID_RSA_signedData))
02303                 ret = CDecodeMsg_DecodeContent(msg, &info->Content,
02304                  CMSG_SIGNED);
02305             else
02306             {
02307                 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
02308                 ret = FALSE;
02309             }
02310             LocalFree(info);
02311         }
02312     }
02313     }
02314     return ret;
02315 }
02316 
02317 static BOOL CDecodeMsg_FinalizeHashedContent(CDecodeMsg *msg,
02318  CRYPT_DER_BLOB *blob)
02319 {
02320     CRYPT_ALGORITHM_IDENTIFIER *hashAlgoID = NULL;
02321     DWORD size = 0;
02322     ALG_ID algID = 0;
02323     BOOL ret;
02324 
02325     CryptMsgGetParam(msg, CMSG_HASH_ALGORITHM_PARAM, 0, NULL, &size);
02326     hashAlgoID = CryptMemAlloc(size);
02327     ret = CryptMsgGetParam(msg, CMSG_HASH_ALGORITHM_PARAM, 0, hashAlgoID,
02328      &size);
02329     if (ret)
02330         algID = CertOIDToAlgId(hashAlgoID->pszObjId);
02331     ret = CryptCreateHash(msg->crypt_prov, algID, 0, 0, &msg->u.hash);
02332     if (ret)
02333     {
02334         CRYPT_DATA_BLOB content;
02335 
02336         if (msg->base.open_flags & CMSG_DETACHED_FLAG)
02337         {
02338             /* Unlike for non-detached messages, the data were never stored as
02339              * the content param, but were saved in msg->detached_data instead.
02340              */
02341             content.pbData = msg->detached_data.pbData;
02342             content.cbData = msg->detached_data.cbData;
02343         }
02344         else
02345             ret = ContextPropertyList_FindProperty(msg->properties,
02346              CMSG_CONTENT_PARAM, &content);
02347         if (ret)
02348             ret = CryptHashData(msg->u.hash, content.pbData, content.cbData, 0);
02349     }
02350     CryptMemFree(hashAlgoID);
02351     return ret;
02352 }
02353 
02354 static BOOL CDecodeMsg_FinalizeEnvelopedContent(CDecodeMsg *msg,
02355  CRYPT_DER_BLOB *blob)
02356 {
02357     CRYPT_DATA_BLOB *content;
02358 
02359     if (msg->base.open_flags & CMSG_DETACHED_FLAG)
02360         content = &msg->detached_data;
02361     else
02362         content =
02363          &msg->u.enveloped_data.data->encryptedContentInfo.encryptedContent;
02364 
02365     return CRYPT_ConstructBlob(&msg->u.enveloped_data.content, content);
02366 }
02367 
02368 static BOOL CDecodeMsg_FinalizeSignedContent(CDecodeMsg *msg,
02369  CRYPT_DER_BLOB *blob)
02370 {
02371     BOOL ret;
02372     DWORD i, size;
02373 
02374     ret = CSignedMsgData_AllocateHandles(&msg->u.signed_data);
02375     for (i = 0; ret && i < msg->u.signed_data.info->cSignerInfo; i++)
02376         ret = CSignedMsgData_ConstructSignerHandles(&msg->u.signed_data, i,
02377          msg->crypt_prov);
02378     if (ret)
02379     {
02380         CRYPT_DATA_BLOB *content;
02381 
02382         /* Now that we have all the content, update the hash handles with
02383          * it.  If the message is a detached message, the content is stored
02384          * in msg->detached_data rather than in the signed message's
02385          * content.
02386          */
02387         if (msg->base.open_flags & CMSG_DETACHED_FLAG)
02388             content = &msg->detached_data;
02389         else
02390             content = &msg->u.signed_data.info->content.Content;
02391         if (content->cbData)
02392         {
02393             /* If the message is not detached, have to decode the message's
02394              * content if the type is szOID_RSA_data.
02395              */
02396             if (!(msg->base.open_flags & CMSG_DETACHED_FLAG) &&
02397              !strcmp(msg->u.signed_data.info->content.pszObjId,
02398              szOID_RSA_data))
02399             {
02400                 CRYPT_DATA_BLOB *blob;
02401 
02402                 ret = CryptDecodeObjectEx(X509_ASN_ENCODING,
02403                  X509_OCTET_STRING, content->pbData, content->cbData,
02404                  CRYPT_DECODE_ALLOC_FLAG, NULL, &blob, &size);
02405                 if (ret)
02406                 {
02407                     ret = CSignedMsgData_Update(&msg->u.signed_data,
02408                      blob->pbData, blob->cbData, TRUE, Verify);
02409                     LocalFree(blob);
02410                 }
02411             }
02412             else
02413                 ret = CSignedMsgData_Update(&msg->u.signed_data,
02414                  content->pbData, content->cbData, TRUE, Verify);
02415         }
02416     }
02417     return ret;
02418 }
02419 
02420 static BOOL CDecodeMsg_FinalizeContent(CDecodeMsg *msg, CRYPT_DER_BLOB *blob)
02421 {
02422     BOOL ret = FALSE;
02423 
02424     switch (msg->type)
02425     {
02426     case CMSG_HASHED:
02427         ret = CDecodeMsg_FinalizeHashedContent(msg, blob);
02428         break;
02429     case CMSG_ENVELOPED:
02430         ret = CDecodeMsg_FinalizeEnvelopedContent(msg, blob);
02431         break;
02432     case CMSG_SIGNED:
02433         ret = CDecodeMsg_FinalizeSignedContent(msg, blob);
02434         break;
02435     default:
02436         ret = TRUE;
02437     }
02438     return ret;
02439 }
02440 
02441 static BOOL CDecodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData,
02442  DWORD cbData, BOOL fFinal)
02443 {
02444     CDecodeMsg *msg = hCryptMsg;
02445     BOOL ret = FALSE;
02446 
02447     TRACE("(%p, %p, %d, %d)\n", hCryptMsg, pbData, cbData, fFinal);
02448 
02449     if (msg->base.state == MsgStateFinalized)
02450         SetLastError(CRYPT_E_MSG_ERROR);
02451     else if (msg->base.streamed)
02452     {
02453         FIXME("(%p, %p, %d, %d): streamed update stub\n", hCryptMsg, pbData,
02454          cbData, fFinal);
02455         switch (msg->base.state)
02456         {
02457         case MsgStateInit:
02458             ret = CDecodeMsg_CopyData(&msg->msg_data, pbData, cbData);
02459             if (fFinal)
02460             {
02461                 if (msg->base.open_flags & CMSG_DETACHED_FLAG)
02462                     msg->base.state = MsgStateDataFinalized;
02463                 else
02464                     msg->base.state = MsgStateFinalized;
02465             }
02466             else
02467                 msg->base.state = MsgStateUpdated;
02468             break;
02469         case MsgStateUpdated:
02470             ret = CDecodeMsg_CopyData(&msg->msg_data, pbData, cbData);
02471             if (fFinal)
02472             {
02473                 if (msg->base.open_flags & CMSG_DETACHED_FLAG)
02474                     msg->base.state = MsgStateDataFinalized;
02475                 else
02476                     msg->base.state = MsgStateFinalized;
02477             }
02478             break;
02479         case MsgStateDataFinalized:
02480             ret = CDecodeMsg_CopyData(&msg->detached_data, pbData, cbData);
02481             if (fFinal)
02482                 msg->base.state = MsgStateFinalized;
02483             break;
02484         default:
02485             SetLastError(CRYPT_E_MSG_ERROR);
02486             break;
02487         }
02488     }
02489     else
02490     {
02491         if (!fFinal)
02492             SetLastError(CRYPT_E_MSG_ERROR);
02493         else
02494         {
02495             switch (msg->base.state)
02496             {
02497             case MsgStateInit:
02498                 ret = CDecodeMsg_CopyData(&msg->msg_data, pbData, cbData);
02499                 if (msg->base.open_flags & CMSG_DETACHED_FLAG)
02500                     msg->base.state = MsgStateDataFinalized;
02501                 else
02502                     msg->base.state = MsgStateFinalized;
02503                 break;
02504             case MsgStateDataFinalized:
02505                 ret = CDecodeMsg_CopyData(&msg->detached_data, pbData, cbData);
02506                 msg->base.state = MsgStateFinalized;
02507                 break;
02508             default:
02509                 SetLastError(CRYPT_E_MSG_ERROR);
02510             }
02511         }
02512     }
02513     if (ret && fFinal &&
02514      ((msg->base.open_flags & CMSG_DETACHED_FLAG && msg->base.state ==
02515      MsgStateDataFinalized) ||
02516      (!(msg->base.open_flags & CMSG_DETACHED_FLAG) && msg->base.state ==
02517      MsgStateFinalized)))
02518         ret = CDecodeMsg_DecodeContent(msg, &msg->msg_data, msg->type);
02519     if (ret && msg->base.state == MsgStateFinalized)
02520         ret = CDecodeMsg_FinalizeContent(msg, &msg->msg_data);
02521     return ret;
02522 }
02523 
02524 static BOOL CDecodeHashMsg_GetParam(CDecodeMsg *msg, DWORD dwParamType,
02525  DWORD dwIndex, void *pvData, DWORD *pcbData)
02526 {
02527     BOOL ret = FALSE;
02528 
02529     switch (dwParamType)
02530     {
02531     case CMSG_TYPE_PARAM:
02532         ret = CRYPT_CopyParam(pvData, pcbData, &msg->type, sizeof(msg->type));
02533         break;
02534     case CMSG_HASH_ALGORITHM_PARAM:
02535     {
02536         CRYPT_DATA_BLOB blob;
02537 
02538         ret = ContextPropertyList_FindProperty(msg->properties, dwParamType,
02539          &blob);
02540         if (ret)
02541         {
02542             ret = CRYPT_CopyParam(pvData, pcbData, blob.pbData, blob.cbData);
02543             if (ret && pvData)
02544                 CRYPT_FixUpAlgorithmID(pvData);
02545         }
02546         else
02547             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
02548         break;
02549     }
02550     case CMSG_COMPUTED_HASH_PARAM:
02551         ret = CryptGetHashParam(msg->u.hash, HP_HASHVAL, pvData, pcbData, 0);
02552         break;
02553     default:
02554     {
02555         CRYPT_DATA_BLOB blob;
02556 
02557         ret = ContextPropertyList_FindProperty(msg->properties, dwParamType,
02558          &blob);
02559         if (ret)
02560             ret = CRYPT_CopyParam(pvData, pcbData, blob.pbData, blob.cbData);
02561         else
02562             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
02563     }
02564     }
02565     return ret;
02566 }
02567 
02568 /* nextData is an in/out parameter - on input it's the memory location in
02569  * which a copy of in's data should be made, and on output it's the memory
02570  * location immediately after out's copy of in's data.
02571  */
02572 static inline void CRYPT_CopyBlob(CRYPT_DATA_BLOB *out,
02573  const CRYPT_DATA_BLOB *in, LPBYTE *nextData)
02574 {
02575     out->cbData = in->cbData;
02576     if (in->cbData)
02577     {
02578         out->pbData = *nextData;
02579         memcpy(out->pbData, in->pbData, in->cbData);
02580         *nextData += in->cbData;
02581     }
02582 }
02583 
02584 static inline void CRYPT_CopyAlgorithmId(CRYPT_ALGORITHM_IDENTIFIER *out,
02585  const CRYPT_ALGORITHM_IDENTIFIER *in, LPBYTE *nextData)
02586 {
02587     if (in->pszObjId)
02588     {
02589         out->pszObjId = (LPSTR)*nextData;
02590         strcpy(out->pszObjId, in->pszObjId);
02591         *nextData += strlen(out->pszObjId) + 1;
02592     }
02593     CRYPT_CopyBlob(&out->Parameters, &in->Parameters, nextData);
02594 }
02595 
02596 static inline void CRYPT_CopyAttributes(CRYPT_ATTRIBUTES *out,
02597  const CRYPT_ATTRIBUTES *in, LPBYTE *nextData)
02598 {
02599     out->cAttr = in->cAttr;
02600     if (in->cAttr)
02601     {
02602         DWORD i;
02603 
02604         *nextData = POINTER_ALIGN_DWORD_PTR(*nextData);
02605         out->rgAttr = (CRYPT_ATTRIBUTE *)*nextData;
02606         *nextData += in->cAttr * sizeof(CRYPT_ATTRIBUTE);
02607         for (i = 0; i < in->cAttr; i++)
02608         {
02609             if (in->rgAttr[i].pszObjId)
02610             {
02611                 out->rgAttr[i].pszObjId = (LPSTR)*nextData;
02612                 strcpy(out->rgAttr[i].pszObjId, in->rgAttr[i].pszObjId);
02613                 *nextData += strlen(in->rgAttr[i].pszObjId) + 1;
02614             }
02615             if (in->rgAttr[i].cValue)
02616             {
02617                 DWORD j;
02618 
02619                 out->rgAttr[i].cValue = in->rgAttr[i].cValue;
02620                 *nextData = POINTER_ALIGN_DWORD_PTR(*nextData);
02621                 out->rgAttr[i].rgValue = (PCRYPT_DATA_BLOB)*nextData;
02622                 *nextData += in->rgAttr[i].cValue * sizeof(CRYPT_DATA_BLOB);
02623                 for (j = 0; j < in->rgAttr[i].cValue; j++)
02624                     CRYPT_CopyBlob(&out->rgAttr[i].rgValue[j],
02625                      &in->rgAttr[i].rgValue[j], nextData);
02626             }
02627         }
02628     }
02629 }
02630 
02631 static DWORD CRYPT_SizeOfAttributes(const CRYPT_ATTRIBUTES *attr)
02632 {
02633     DWORD size = attr->cAttr * sizeof(CRYPT_ATTRIBUTE), i, j;
02634 
02635     for (i = 0; i < attr->cAttr; i++)
02636     {
02637         if (attr->rgAttr[i].pszObjId)
02638             size += strlen(attr->rgAttr[i].pszObjId) + 1;
02639         /* align pointer */
02640         size = ALIGN_DWORD_PTR(size);
02641         size += attr->rgAttr[i].cValue * sizeof(CRYPT_DATA_BLOB);
02642         for (j = 0; j < attr->rgAttr[i].cValue; j++)
02643             size += attr->rgAttr[i].rgValue[j].cbData;
02644     }
02645     /* align pointer again to be conservative */
02646     size = ALIGN_DWORD_PTR(size);
02647     return size;
02648 }
02649 
02650 static DWORD CRYPT_SizeOfKeyIdAsIssuerAndSerial(const CRYPT_DATA_BLOB *keyId)
02651 {
02652     static char oid_key_rdn[] = szOID_KEYID_RDN;
02653     DWORD size = 0;
02654     CERT_RDN_ATTR attr;
02655     CERT_RDN rdn = { 1, &attr };
02656     CERT_NAME_INFO name = { 1, &rdn };
02657 
02658     attr.pszObjId = oid_key_rdn;
02659     attr.dwValueType = CERT_RDN_OCTET_STRING;
02660     attr.Value.cbData = keyId->cbData;
02661     attr.Value.pbData = keyId->pbData;
02662     if (CryptEncodeObject(X509_ASN_ENCODING, X509_NAME, &name, NULL, &size))
02663         size++; /* Only include size of special zero serial number on success */
02664     return size;
02665 }
02666 
02667 static BOOL CRYPT_CopyKeyIdAsIssuerAndSerial(CERT_NAME_BLOB *issuer,
02668  CRYPT_INTEGER_BLOB *serialNumber, const CRYPT_DATA_BLOB *keyId, DWORD encodedLen,
02669  LPBYTE *nextData)
02670 {
02671     static char oid_key_rdn[] = szOID_KEYID_RDN;
02672     CERT_RDN_ATTR attr;
02673     CERT_RDN rdn = { 1, &attr };
02674     CERT_NAME_INFO name = { 1, &rdn };
02675     BOOL ret;
02676 
02677     /* Encode special zero serial number */
02678     serialNumber->cbData = 1;
02679     serialNumber->pbData = *nextData;
02680     **nextData = 0;
02681     (*nextData)++;
02682     /* Encode issuer */
02683     issuer->pbData = *nextData;
02684     attr.pszObjId = oid_key_rdn;
02685     attr.dwValueType = CERT_RDN_OCTET_STRING;
02686     attr.Value.cbData = keyId->cbData;
02687     attr.Value.pbData = keyId->pbData;
02688     ret = CryptEncodeObject(X509_ASN_ENCODING, X509_NAME, &name, *nextData,
02689      &encodedLen);
02690     if (ret)
02691     {
02692         *nextData += encodedLen;
02693         issuer->cbData = encodedLen;
02694     }
02695     return ret;
02696 }
02697 
02698 static BOOL CRYPT_CopySignerInfo(void *pvData, DWORD *pcbData,
02699  const CMSG_CMS_SIGNER_INFO *in)
02700 {
02701     DWORD size = sizeof(CMSG_SIGNER_INFO), rdnSize = 0;
02702     BOOL ret;
02703 
02704     TRACE("(%p, %d, %p)\n", pvData, pvData ? *pcbData : 0, in);
02705 
02706     if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
02707     {
02708         size += in->SignerId.u.IssuerSerialNumber.Issuer.cbData;
02709         size += in->SignerId.u.IssuerSerialNumber.SerialNumber.cbData;
02710     }
02711     else
02712     {
02713         rdnSize = CRYPT_SizeOfKeyIdAsIssuerAndSerial(&in->SignerId.u.KeyId);
02714         size += rdnSize;
02715     }
02716     if (in->HashAlgorithm.pszObjId)
02717         size += strlen(in->HashAlgorithm.pszObjId) + 1;
02718     size += in->HashAlgorithm.Parameters.cbData;
02719     if (in->HashEncryptionAlgorithm.pszObjId)
02720         size += strlen(in->HashEncryptionAlgorithm.pszObjId) + 1;
02721     size += in->HashEncryptionAlgorithm.Parameters.cbData;
02722     size += in->EncryptedHash.cbData;
02723     /* align pointer */
02724     size = ALIGN_DWORD_PTR(size);
02725     size += CRYPT_SizeOfAttributes(&in->AuthAttrs);
02726     size += CRYPT_SizeOfAttributes(&in->UnauthAttrs);
02727     if (!pvData)
02728     {
02729         *pcbData = size;
02730         ret = TRUE;
02731     }
02732     else if (*pcbData < size)
02733     {
02734         *pcbData = size;
02735         SetLastError(ERROR_MORE_DATA);
02736         ret = FALSE;
02737     }
02738     else
02739     {
02740         LPBYTE nextData = (BYTE *)pvData + sizeof(CMSG_SIGNER_INFO);
02741         CMSG_SIGNER_INFO *out = pvData;
02742 
02743         ret = TRUE;
02744         out->dwVersion = in->dwVersion;
02745         if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
02746         {
02747             CRYPT_CopyBlob(&out->Issuer,
02748              &in->SignerId.u.IssuerSerialNumber.Issuer, &nextData);
02749             CRYPT_CopyBlob(&out->SerialNumber,
02750              &in->SignerId.u.IssuerSerialNumber.SerialNumber, &nextData);
02751         }
02752         else
02753             ret = CRYPT_CopyKeyIdAsIssuerAndSerial(&out->Issuer, &out->SerialNumber,
02754              &in->SignerId.u.KeyId, rdnSize, &nextData);
02755         if (ret)
02756         {
02757             CRYPT_CopyAlgorithmId(&out->HashAlgorithm, &in->HashAlgorithm,
02758              &nextData);
02759             CRYPT_CopyAlgorithmId(&out->HashEncryptionAlgorithm,
02760              &in->HashEncryptionAlgorithm, &nextData);
02761             CRYPT_CopyBlob(&out->EncryptedHash, &in->EncryptedHash, &nextData);
02762             nextData = POINTER_ALIGN_DWORD_PTR(nextData);
02763             CRYPT_CopyAttributes(&out->AuthAttrs, &in->AuthAttrs, &nextData);
02764             CRYPT_CopyAttributes(&out->UnauthAttrs, &in->UnauthAttrs, &nextData);
02765         }
02766     }
02767     TRACE("returning %d\n", ret);
02768     return ret;
02769 }
02770 
02771 static BOOL CRYPT_CopyCMSSignerInfo(void *pvData, DWORD *pcbData,
02772  const CMSG_CMS_SIGNER_INFO *in)
02773 {
02774     DWORD size = sizeof(CMSG_CMS_SIGNER_INFO);
02775     BOOL ret;
02776 
02777     TRACE("(%p, %d, %p)\n", pvData, pvData ? *pcbData : 0, in);
02778 
02779     if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
02780     {
02781         size += in->SignerId.u.IssuerSerialNumber.Issuer.cbData;
02782         size += in->SignerId.u.IssuerSerialNumber.SerialNumber.cbData;
02783     }
02784     else
02785         size += in->SignerId.u.KeyId.cbData;
02786     if (in->HashAlgorithm.pszObjId)
02787         size += strlen(in->HashAlgorithm.pszObjId) + 1;
02788     size += in->HashAlgorithm.Parameters.cbData;
02789     if (in->HashEncryptionAlgorithm.pszObjId)
02790         size += strlen(in->HashEncryptionAlgorithm.pszObjId) + 1;
02791     size += in->HashEncryptionAlgorithm.Parameters.cbData;
02792     size += in->EncryptedHash.cbData;
02793     /* align pointer */
02794     size = ALIGN_DWORD_PTR(size);
02795     size += CRYPT_SizeOfAttributes(&in->AuthAttrs);
02796     size += CRYPT_SizeOfAttributes(&in->UnauthAttrs);
02797     if (!pvData)
02798     {
02799         *pcbData = size;
02800         ret = TRUE;
02801     }
02802     else if (*pcbData < size)
02803     {
02804         *pcbData = size;
02805         SetLastError(ERROR_MORE_DATA);
02806         ret = FALSE;
02807     }
02808     else
02809     {
02810         LPBYTE nextData = (BYTE *)pvData + sizeof(CMSG_CMS_SIGNER_INFO);
02811         CMSG_CMS_SIGNER_INFO *out = pvData;
02812 
02813         out->dwVersion = in->dwVersion;
02814         out->SignerId.dwIdChoice = in->SignerId.dwIdChoice;
02815         if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
02816         {
02817             CRYPT_CopyBlob(&out->SignerId.u.IssuerSerialNumber.Issuer,
02818              &in->SignerId.u.IssuerSerialNumber.Issuer, &nextData);
02819             CRYPT_CopyBlob(&out->SignerId.u.IssuerSerialNumber.SerialNumber,
02820              &in->SignerId.u.IssuerSerialNumber.SerialNumber, &nextData);
02821         }
02822         else
02823             CRYPT_CopyBlob(&out->SignerId.u.KeyId, &in->SignerId.u.KeyId, &nextData);
02824         CRYPT_CopyAlgorithmId(&out->HashAlgorithm, &in->HashAlgorithm,
02825          &nextData);
02826         CRYPT_CopyAlgorithmId(&out->HashEncryptionAlgorithm,
02827          &in->HashEncryptionAlgorithm, &nextData);
02828         CRYPT_CopyBlob(&out->EncryptedHash, &in->EncryptedHash, &nextData);
02829         nextData = POINTER_ALIGN_DWORD_PTR(nextData);
02830         CRYPT_CopyAttributes(&out->AuthAttrs, &in->AuthAttrs, &nextData);
02831         CRYPT_CopyAttributes(&out->UnauthAttrs, &in->UnauthAttrs, &nextData);
02832         ret = TRUE;
02833     }
02834     TRACE("returning %d\n", ret);
02835     return ret;
02836 }
02837 
02838 static BOOL CRYPT_CopySignerCertInfo(void *pvData, DWORD *pcbData,
02839  const CMSG_CMS_SIGNER_INFO *in)
02840 {
02841     DWORD size = sizeof(CERT_INFO), rdnSize = 0;
02842     BOOL ret;
02843 
02844     TRACE("(%p, %d, %p)\n", pvData, pvData ? *pcbData : 0, in);
02845 
02846     if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
02847     {
02848         size += in->SignerId.u.IssuerSerialNumber.Issuer.cbData;
02849         size += in->SignerId.u.IssuerSerialNumber.SerialNumber.cbData;
02850     }
02851     else
02852     {
02853         rdnSize = CRYPT_SizeOfKeyIdAsIssuerAndSerial(&in->SignerId.u.KeyId);
02854         size += rdnSize;
02855     }
02856     if (!pvData)
02857     {
02858         *pcbData = size;
02859         ret = TRUE;
02860     }
02861     else if (*pcbData < size)
02862     {
02863         *pcbData = size;
02864         SetLastError(ERROR_MORE_DATA);
02865         ret = FALSE;
02866     }
02867     else
02868     {
02869         LPBYTE nextData = (BYTE *)pvData + sizeof(CERT_INFO);
02870         CERT_INFO *out = pvData;
02871 
02872         memset(out, 0, sizeof(CERT_INFO));
02873         if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
02874         {
02875             CRYPT_CopyBlob(&out->Issuer,
02876              &in->SignerId.u.IssuerSerialNumber.Issuer, &nextData);
02877             CRYPT_CopyBlob(&out->SerialNumber,
02878              &in->SignerId.u.IssuerSerialNumber.SerialNumber, &nextData);
02879             ret = TRUE;
02880         }
02881         else
02882             ret = CRYPT_CopyKeyIdAsIssuerAndSerial(&out->Issuer, &out->SerialNumber,
02883              &in->SignerId.u.KeyId, rdnSize, &nextData);
02884     }
02885     TRACE("returning %d\n", ret);
02886     return ret;
02887 }
02888 
02889 static BOOL CRYPT_CopyRecipientInfo(void *pvData, DWORD *pcbData,
02890  const CERT_ISSUER_SERIAL_NUMBER *in)
02891 {
02892     DWORD size = sizeof(CERT_INFO);
02893     BOOL ret;
02894 
02895     TRACE("(%p, %d, %p)\n", pvData, pvData ? *pcbData : 0, in);
02896 
02897     size += in->SerialNumber.cbData;
02898     size += in->Issuer.cbData;
02899     if (!pvData)
02900     {
02901         *pcbData = size;
02902         ret = TRUE;
02903     }
02904     else if (*pcbData < size)
02905     {
02906         *pcbData = size;
02907         SetLastError(ERROR_MORE_DATA);
02908         ret = FALSE;
02909     }
02910     else
02911     {
02912         LPBYTE nextData = (BYTE *)pvData + sizeof(CERT_INFO);
02913         CERT_INFO *out = pvData;
02914 
02915         CRYPT_CopyBlob(&out->SerialNumber, &in->SerialNumber, &nextData);
02916         CRYPT_CopyBlob(&out->Issuer, &in->Issuer, &nextData);
02917         ret = TRUE;
02918     }
02919     TRACE("returning %d\n", ret);
02920     return ret;
02921 }
02922 
02923 static BOOL CDecodeEnvelopedMsg_GetParam(CDecodeMsg *msg, DWORD dwParamType,
02924  DWORD dwIndex, void *pvData, DWORD *pcbData)
02925 {
02926     BOOL ret = FALSE;
02927 
02928     switch (dwParamType)
02929     {
02930     case CMSG_TYPE_PARAM:
02931         ret = CRYPT_CopyParam(pvData, pcbData, &msg->type, sizeof(msg->type));
02932         break;
02933     case CMSG_CONTENT_PARAM:
02934         if (msg->u.enveloped_data.data)
02935             ret = CRYPT_CopyParam(pvData, pcbData,
02936              msg->u.enveloped_data.content.pbData,
02937              msg->u.enveloped_data.content.cbData);
02938         else
02939             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
02940         break;
02941     case CMSG_RECIPIENT_COUNT_PARAM:
02942         if (msg->u.enveloped_data.data)
02943             ret = CRYPT_CopyParam(pvData, pcbData,
02944              &msg->u.enveloped_data.data->cRecipientInfo, sizeof(DWORD));
02945         else
02946             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
02947         break;
02948     case CMSG_RECIPIENT_INFO_PARAM:
02949         if (msg->u.enveloped_data.data)
02950         {
02951             if (dwIndex < msg->u.enveloped_data.data->cRecipientInfo)
02952             {
02953                 PCMSG_KEY_TRANS_RECIPIENT_INFO recipientInfo =
02954                  &msg->u.enveloped_data.data->rgRecipientInfo[dwIndex];
02955 
02956                 ret = CRYPT_CopyRecipientInfo(pvData, pcbData,
02957                  &recipientInfo->RecipientId.u.IssuerSerialNumber);
02958             }
02959             else
02960                 SetLastError(CRYPT_E_INVALID_INDEX);
02961         }
02962         else
02963             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
02964         break;
02965     default:
02966         FIXME("unimplemented for %d\n", dwParamType);
02967         SetLastError(CRYPT_E_INVALID_MSG_TYPE);
02968     }
02969     return ret;
02970 }
02971 
02972 static BOOL CDecodeSignedMsg_GetParam(CDecodeMsg *msg, DWORD dwParamType,
02973  DWORD dwIndex, void *pvData, DWORD *pcbData)
02974 {
02975     BOOL ret = FALSE;
02976 
02977     switch (dwParamType)
02978     {
02979     case CMSG_TYPE_PARAM:
02980         ret = CRYPT_CopyParam(pvData, pcbData, &msg->type, sizeof(msg->type));
02981         break;
02982     case CMSG_CONTENT_PARAM:
02983         if (msg->u.signed_data.info)
02984         {
02985             if (!strcmp(msg->u.signed_data.info->content.pszObjId,
02986              szOID_RSA_data))
02987             {
02988                 CRYPT_DATA_BLOB *blob;
02989                 DWORD size;
02990 
02991                 ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING,
02992                  msg->u.signed_data.info->content.Content.pbData,
02993                  msg->u.signed_data.info->content.Content.cbData,
02994                  CRYPT_DECODE_ALLOC_FLAG, NULL, &blob, &size);
02995                 if (ret)
02996                 {
02997                     ret = CRYPT_CopyParam(pvData, pcbData, blob->pbData,
02998                      blob->cbData);
02999                     LocalFree(blob);
03000                 }
03001             }
03002             else
03003                 ret = CRYPT_CopyParam(pvData, pcbData,
03004                  msg->u.signed_data.info->content.Content.pbData,
03005                  msg->u.signed_data.info->content.Content.cbData);
03006         }
03007         else
03008             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
03009         break;
03010     case CMSG_INNER_CONTENT_TYPE_PARAM:
03011         if (msg->u.signed_data.info)
03012             ret = CRYPT_CopyParam(pvData, pcbData,
03013              msg->u.signed_data.info->content.pszObjId,
03014              strlen(msg->u.signed_data.info->content.pszObjId) + 1);
03015         else
03016             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
03017         break;
03018     case CMSG_SIGNER_COUNT_PARAM:
03019         if (msg->u.signed_data.info)
03020             ret = CRYPT_CopyParam(pvData, pcbData,
03021              &msg->u.signed_data.info->cSignerInfo, sizeof(DWORD));
03022         else
03023             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
03024         break;
03025     case CMSG_SIGNER_INFO_PARAM:
03026         if (msg->u.signed_data.info)
03027         {
03028             if (dwIndex >= msg->u.signed_data.info->cSignerInfo)
03029                 SetLastError(CRYPT_E_INVALID_INDEX);
03030             else
03031                 ret = CRYPT_CopySignerInfo(pvData, pcbData,
03032                  &msg->u.signed_data.info->rgSignerInfo[dwIndex]);
03033         }
03034         else
03035             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
03036         break;
03037     case CMSG_SIGNER_CERT_INFO_PARAM:
03038         if (msg->u.signed_data.info)
03039         {
03040             if (dwIndex >= msg->u.signed_data.info->cSignerInfo)
03041                 SetLastError(CRYPT_E_INVALID_INDEX);
03042             else
03043                 ret = CRYPT_CopySignerCertInfo(pvData, pcbData,
03044                  &msg->u.signed_data.info->rgSignerInfo[dwIndex]);
03045         }
03046         else
03047             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
03048         break;
03049     case CMSG_CERT_COUNT_PARAM:
03050         if (msg->u.signed_data.info)
03051             ret = CRYPT_CopyParam(pvData, pcbData,
03052              &msg->u.signed_data.info->cCertEncoded, sizeof(DWORD));
03053         else
03054             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
03055         break;
03056     case CMSG_CERT_PARAM:
03057         if (msg->u.signed_data.info)
03058         {
03059             if (dwIndex >= msg->u.signed_data.info->cCertEncoded)
03060                 SetLastError(CRYPT_E_INVALID_INDEX);
03061             else
03062                 ret = CRYPT_CopyParam(pvData, pcbData,
03063                  msg->u.signed_data.info->rgCertEncoded[dwIndex].pbData,
03064                  msg->u.signed_data.info->rgCertEncoded[dwIndex].cbData);
03065         }
03066         else
03067             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
03068         break;
03069     case CMSG_CRL_COUNT_PARAM:
03070         if (msg->u.signed_data.info)
03071             ret = CRYPT_CopyParam(pvData, pcbData,
03072              &msg->u.signed_data.info->cCrlEncoded, sizeof(DWORD));
03073         else
03074             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
03075         break;
03076     case CMSG_CRL_PARAM:
03077         if (msg->u.signed_data.info)
03078         {
03079             if (dwIndex >= msg->u.signed_data.info->cCrlEncoded)
03080                 SetLastError(CRYPT_E_INVALID_INDEX);
03081             else
03082                 ret = CRYPT_CopyParam(pvData, pcbData,
03083                  msg->u.signed_data.info->rgCrlEncoded[dwIndex].pbData,
03084                  msg->u.signed_data.info->rgCrlEncoded[dwIndex].cbData);
03085         }
03086         else
03087             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
03088         break;
03089     case CMSG_COMPUTED_HASH_PARAM:
03090         if (msg->u.signed_data.info)
03091         {
03092             if (dwIndex >= msg->u.signed_data.cSignerHandle)
03093                 SetLastError(CRYPT_E_INVALID_INDEX);
03094             else
03095                 ret = CryptGetHashParam(
03096                  msg->u.signed_data.signerHandles[dwIndex].contentHash,
03097                  HP_HASHVAL, pvData, pcbData, 0);
03098         }
03099         else
03100             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
03101         break;
03102     case CMSG_ENCODED_SIGNER:
03103         if (msg->u.signed_data.info)
03104         {
03105             if (dwIndex >= msg->u.signed_data.info->cSignerInfo)
03106                 SetLastError(CRYPT_E_INVALID_INDEX);
03107             else
03108                 ret = CryptEncodeObjectEx(
03109                  X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, CMS_SIGNER_INFO,
03110                  &msg->u.signed_data.info->rgSignerInfo[dwIndex], 0, NULL,
03111                  pvData, pcbData);
03112         }
03113         else
03114             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
03115         break;
03116     case CMSG_ATTR_CERT_COUNT_PARAM:
03117         if (msg->u.signed_data.info)
03118         {
03119             DWORD attrCertCount = 0;
03120 
03121             ret = CRYPT_CopyParam(pvData, pcbData,
03122              &attrCertCount, sizeof(DWORD));
03123         }
03124         else
03125             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
03126         break;
03127     case CMSG_ATTR_CERT_PARAM:
03128         if (msg->u.signed_data.info)
03129             SetLastError(CRYPT_E_INVALID_INDEX);
03130         else
03131             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
03132         break;
03133     case CMSG_CMS_SIGNER_INFO_PARAM:
03134         if (msg->u.signed_data.info)
03135         {
03136             if (dwIndex >= msg->u.signed_data.info->cSignerInfo)
03137                 SetLastError(CRYPT_E_INVALID_INDEX);
03138             else
03139                 ret = CRYPT_CopyCMSSignerInfo(pvData, pcbData,
03140                  &msg->u.signed_data.info->rgSignerInfo[dwIndex]);
03141         }
03142         else
03143             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
03144         break;
03145     default:
03146         FIXME("unimplemented for %d\n", dwParamType);
03147         SetLastError(CRYPT_E_INVALID_MSG_TYPE);
03148     }
03149     return ret;
03150 }
03151 
03152 static BOOL CDecodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
03153  DWORD dwIndex, void *pvData, DWORD *pcbData)
03154 {
03155     CDecodeMsg *msg = hCryptMsg;
03156     BOOL ret = FALSE;
03157 
03158     switch (msg->type)
03159     {
03160     case CMSG_HASHED:
03161         ret = CDecodeHashMsg_GetParam(msg, dwParamType, dwIndex, pvData,
03162          pcbData);
03163         break;
03164     case CMSG_ENVELOPED:
03165         ret = CDecodeEnvelopedMsg_GetParam(msg, dwParamType, dwIndex, pvData,
03166          pcbData);
03167         break;
03168     case CMSG_SIGNED:
03169         ret = CDecodeSignedMsg_GetParam(msg, dwParamType, dwIndex, pvData,
03170          pcbData);
03171         break;
03172     default:
03173         switch (dwParamType)
03174         {
03175         case CMSG_TYPE_PARAM:
03176             ret = CRYPT_CopyParam(pvData, pcbData, &msg->type,
03177              sizeof(msg->type));
03178             break;
03179         default:
03180         {
03181             CRYPT_DATA_BLOB blob;
03182 
03183             ret = ContextPropertyList_FindProperty(msg->properties, dwParamType,
03184              &blob);
03185             if (ret)
03186                 ret = CRYPT_CopyParam(pvData, pcbData, blob.pbData,
03187                  blob.cbData);
03188             else
03189                 SetLastError(CRYPT_E_INVALID_MSG_TYPE);
03190         }
03191         }
03192     }
03193     return ret;
03194 }
03195 
03196 static BOOL CDecodeHashMsg_VerifyHash(CDecodeMsg *msg)
03197 {
03198     BOOL ret;
03199     CRYPT_DATA_BLOB hashBlob;
03200 
03201     ret = ContextPropertyList_FindProperty(msg->properties,
03202      CMSG_HASH_DATA_PARAM, &hashBlob);
03203     if (ret)
03204     {
03205         DWORD computedHashSize = 0;
03206 
03207         ret = CDecodeHashMsg_GetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, NULL,
03208          &computedHashSize);
03209         if (hashBlob.cbData == computedHashSize)
03210         {
03211             LPBYTE computedHash = CryptMemAlloc(computedHashSize);
03212 
03213             if (computedHash)
03214             {
03215                 ret = CDecodeHashMsg_GetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0,
03216                  computedHash, &computedHashSize);
03217                 if (ret)
03218                 {
03219                     if (memcmp(hashBlob.pbData, computedHash, hashBlob.cbData))
03220                     {
03221                         SetLastError(CRYPT_E_HASH_VALUE);
03222                         ret = FALSE;
03223                     }
03224                 }
03225                 CryptMemFree(computedHash);
03226             }
03227             else
03228             {
03229                 SetLastError(ERROR_OUTOFMEMORY);
03230                 ret = FALSE;
03231             }
03232         }
03233         else
03234         {
03235             SetLastError(CRYPT_E_HASH_VALUE);
03236             ret = FALSE;
03237         }
03238     }
03239     return ret;
03240 }
03241 
03242 static BOOL CDecodeSignedMsg_VerifySignatureWithKey(CDecodeMsg *msg,
03243  HCRYPTPROV prov, DWORD signerIndex, PCERT_PUBLIC_KEY_INFO keyInfo)
03244 {
03245     HCRYPTKEY key;
03246     BOOL ret;
03247 
03248     if (!prov)
03249         prov = msg->crypt_prov;
03250     ret = CryptImportPublicKeyInfo(prov, X509_ASN_ENCODING, keyInfo, &key);
03251     if (ret)
03252     {
03253         HCRYPTHASH hash;
03254         CRYPT_HASH_BLOB reversedHash;
03255 
03256         if (msg->u.signed_data.info->rgSignerInfo[signerIndex].AuthAttrs.cAttr)
03257             hash = msg->u.signed_data.signerHandles[signerIndex].authAttrHash;
03258         else
03259             hash = msg->u.signed_data.signerHandles[signerIndex].contentHash;
03260         ret = CRYPT_ConstructBlob(&reversedHash,
03261          &msg->u.signed_data.info->rgSignerInfo[signerIndex].EncryptedHash);
03262         if (ret)
03263         {
03264             CRYPT_ReverseBytes(&reversedHash);
03265             ret = CryptVerifySignatureW(hash, reversedHash.pbData,
03266              reversedHash.cbData, key, NULL, 0);
03267             CryptMemFree(reversedHash.pbData);
03268         }
03269         CryptDestroyKey(key);
03270     }
03271     return ret;
03272 }
03273 
03274 static BOOL CDecodeSignedMsg_VerifySignature(CDecodeMsg *msg, PCERT_INFO info)
03275 {
03276     BOOL ret = FALSE;
03277     DWORD i;
03278 
03279     if (!msg->u.signed_data.signerHandles)
03280     {
03281         SetLastError(NTE_BAD_SIGNATURE);
03282         return FALSE;
03283     }
03284     for (i = 0; !ret && i < msg->u.signed_data.info->cSignerInfo; i++)
03285     {
03286         PCMSG_CMS_SIGNER_INFO signerInfo =
03287          &msg->u.signed_data.info->rgSignerInfo[i];
03288 
03289         if (signerInfo->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
03290         {
03291             ret = CertCompareCertificateName(X509_ASN_ENCODING,
03292              &signerInfo->SignerId.u.IssuerSerialNumber.Issuer,
03293              &info->Issuer);
03294             if (ret)
03295             {
03296                 ret = CertCompareIntegerBlob(
03297                  &signerInfo->SignerId.u.IssuerSerialNumber.SerialNumber,
03298                  &info->SerialNumber);
03299                 if (ret)
03300                     break;
03301             }
03302         }
03303         else
03304         {
03305             FIXME("signer %d: unimplemented for key id\n", i);
03306         }
03307     }
03308     if (ret)
03309         ret = CDecodeSignedMsg_VerifySignatureWithKey(msg, 0, i,
03310          &info->SubjectPublicKeyInfo);
03311     else
03312         SetLastError(CRYPT_E_SIGNER_NOT_FOUND);
03313 
03314     return ret;
03315 }
03316 
03317 static BOOL CDecodeSignedMsg_VerifySignatureEx(CDecodeMsg *msg,
03318  PCMSG_CTRL_VERIFY_SIGNATURE_EX_PARA para)
03319 {
03320     BOOL ret = FALSE;
03321 
03322     if (para->cbSize != sizeof(CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA))
03323         SetLastError(ERROR_INVALID_PARAMETER);
03324     else if (para->dwSignerIndex >= msg->u.signed_data.info->cSignerInfo)
03325         SetLastError(CRYPT_E_SIGNER_NOT_FOUND);
03326     else if (!msg->u.signed_data.signerHandles)
03327         SetLastError(NTE_BAD_SIGNATURE);
03328     else
03329     {
03330         switch (para->dwSignerType)
03331         {
03332         case CMSG_VERIFY_SIGNER_PUBKEY:
03333             ret = CDecodeSignedMsg_VerifySignatureWithKey(msg,
03334              para->hCryptProv, para->dwSignerIndex, para->pvSigner);
03335             break;
03336         case CMSG_VERIFY_SIGNER_CERT:
03337         {
03338             PCCERT_CONTEXT cert = para->pvSigner;
03339 
03340             ret = CDecodeSignedMsg_VerifySignatureWithKey(msg, para->hCryptProv,
03341              para->dwSignerIndex, &cert->pCertInfo->SubjectPublicKeyInfo);
03342             break;
03343         }
03344         default:
03345             FIXME("unimplemented for signer type %d\n", para->dwSignerType);
03346             SetLastError(CRYPT_E_SIGNER_NOT_FOUND);
03347         }
03348     }
03349     return ret;
03350 }
03351 
03352 static BOOL WINAPI CRYPT_ImportKeyTrans(
03353  PCRYPT_ALGORITHM_IDENTIFIER pContentEncryptionAlgorithm,
03354  PCMSG_CTRL_KEY_TRANS_DECRYPT_PARA pKeyTransDecryptPara, DWORD dwFlags,
03355  void *pvReserved, HCRYPTKEY *phContentEncryptKey)
03356 {
03357     BOOL ret;
03358     HCRYPTKEY key;
03359 
03360     ret = CryptGetUserKey(pKeyTransDecryptPara->hCryptProv,
03361      pKeyTransDecryptPara->dwKeySpec ? pKeyTransDecryptPara->dwKeySpec :
03362      AT_KEYEXCHANGE, &key);
03363     if (ret)
03364     {
03365         CMSG_KEY_TRANS_RECIPIENT_INFO *info =
03366          &pKeyTransDecryptPara->pKeyTrans[pKeyTransDecryptPara->dwRecipientIndex];
03367         CRYPT_DATA_BLOB *encryptedKey = &info->EncryptedKey;
03368         DWORD size = encryptedKey->cbData + sizeof(BLOBHEADER) + sizeof(ALG_ID);
03369         BYTE *keyBlob = CryptMemAlloc(size);
03370 
03371         if (keyBlob)
03372         {
03373             DWORD i, k = size - 1;
03374             BLOBHEADER *blobHeader = (BLOBHEADER *)keyBlob;
03375             ALG_ID *algID = (ALG_ID *)(keyBlob + sizeof(BLOBHEADER));
03376 
03377             blobHeader->bType = SIMPLEBLOB;
03378             blobHeader->bVersion = CUR_BLOB_VERSION;
03379             blobHeader->reserved = 0;
03380             blobHeader->aiKeyAlg = CertOIDToAlgId(
03381              pContentEncryptionAlgorithm->pszObjId);
03382             *algID = CertOIDToAlgId(info->KeyEncryptionAlgorithm.pszObjId);
03383             for (i = 0; i < encryptedKey->cbData; ++i, --k)
03384                 keyBlob[k] = encryptedKey->pbData[i];
03385 
03386             ret = CryptImportKey(pKeyTransDecryptPara->hCryptProv, keyBlob,
03387              size, key, 0, phContentEncryptKey);
03388             CryptMemFree(keyBlob);
03389         }
03390         else
03391             ret = FALSE;
03392         CryptDestroyKey(key);
03393     }
03394     return ret;
03395 }
03396 
03397 static BOOL CRYPT_ImportEncryptedKey(PCRYPT_ALGORITHM_IDENTIFIER contEncrAlg,
03398  PCMSG_CTRL_DECRYPT_PARA para, PCMSG_KEY_TRANS_RECIPIENT_INFO info,
03399  HCRYPTKEY *key)
03400 {
03401     static HCRYPTOIDFUNCSET set = NULL;
03402     PFN_CMSG_IMPORT_KEY_TRANS importKeyFunc = NULL;
03403     HCRYPTOIDFUNCADDR hFunc = NULL;
03404     CMSG_CTRL_KEY_TRANS_DECRYPT_PARA decryptPara;
03405     BOOL ret;
03406 
03407     memset(&decryptPara, 0, sizeof(decryptPara));
03408     decryptPara.cbSize = sizeof(decryptPara);
03409     decryptPara.hCryptProv = para->hCryptProv;
03410     decryptPara.dwKeySpec = para->dwKeySpec;
03411     decryptPara.pKeyTrans = info;
03412     decryptPara.dwRecipientIndex = para->dwRecipientIndex;
03413 
03414     if (!set)
03415         set = CryptInitOIDFunctionSet(CMSG_OID_IMPORT_KEY_TRANS_FUNC, 0);
03416     CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, contEncrAlg->pszObjId, 0,
03417      (void **)&importKeyFunc, &hFunc);
03418     if (!importKeyFunc)
03419         importKeyFunc = CRYPT_ImportKeyTrans;
03420     ret = importKeyFunc(contEncrAlg, &decryptPara, 0, NULL, key);
03421     if (hFunc)
03422         CryptFreeOIDFunctionAddress(hFunc, 0);
03423     return ret;
03424 }
03425 
03426 static BOOL CDecodeEnvelopedMsg_CrtlDecrypt(CDecodeMsg *msg,
03427  PCMSG_CTRL_DECRYPT_PARA para)
03428 {
03429     BOOL ret = FALSE;
03430     CEnvelopedDecodeMsg *enveloped_data = &msg->u.enveloped_data;
03431     CRYPT_ENVELOPED_DATA *data = enveloped_data->data;
03432 
03433     if (para->cbSize != sizeof(CMSG_CTRL_DECRYPT_PARA))
03434         SetLastError(E_INVALIDARG);
03435     else if (!data)
03436         SetLastError(CRYPT_E_INVALID_MSG_TYPE);
03437     else if (para->dwRecipientIndex >= data->cRecipientInfo)
03438         SetLastError(CRYPT_E_INVALID_INDEX);
03439     else if (enveloped_data->decrypted)
03440         SetLastError(CRYPT_E_ALREADY_DECRYPTED);
03441     else if (!para->hCryptProv)
03442         SetLastError(ERROR_INVALID_PARAMETER);
03443     else if (enveloped_data->content.cbData)
03444     {
03445         HCRYPTKEY key;
03446 
03447         ret = CRYPT_ImportEncryptedKey(
03448          &data->encryptedContentInfo.contentEncryptionAlgorithm, para,
03449          data->rgRecipientInfo, &key);
03450         if (ret)
03451         {
03452             ret = CryptDecrypt(key, 0, TRUE, 0, enveloped_data->content.pbData,
03453              &enveloped_data->content.cbData);
03454             CryptDestroyKey(key);
03455         }
03456     }
03457     else
03458         ret = TRUE;
03459     if (ret)
03460         enveloped_data->decrypted = TRUE;
03461     return ret;
03462 }
03463 
03464 static BOOL CDecodeMsg_Control(HCRYPTMSG hCryptMsg, DWORD dwFlags,
03465  DWORD dwCtrlType, const void *pvCtrlPara)
03466 {
03467     CDecodeMsg *msg = hCryptMsg;
03468     BOOL ret = FALSE;
03469 
03470     switch (dwCtrlType)
03471     {
03472     case CMSG_CTRL_VERIFY_SIGNATURE:
03473         switch (msg->type)
03474         {
03475         case CMSG_SIGNED:
03476             ret = CDecodeSignedMsg_VerifySignature(msg, (PCERT_INFO)pvCtrlPara);
03477             break;
03478         default:
03479             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
03480         }
03481         break;
03482     case CMSG_CTRL_DECRYPT:
03483         switch (msg->type)
03484         {
03485         case CMSG_ENVELOPED:
03486             ret = CDecodeEnvelopedMsg_CrtlDecrypt(msg,
03487              (PCMSG_CTRL_DECRYPT_PARA)pvCtrlPara);
03488             if (ret && (dwFlags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG))
03489                 msg->u.enveloped_data.crypt_prov =
03490                  ((PCMSG_CTRL_DECRYPT_PARA)pvCtrlPara)->hCryptProv;
03491             break;
03492         default:
03493             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
03494         }
03495         break;
03496     case CMSG_CTRL_VERIFY_HASH:
03497         switch (msg->type)
03498         {
03499         case CMSG_HASHED:
03500             ret = CDecodeHashMsg_VerifyHash(msg);
03501             break;
03502         default:
03503             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
03504         }
03505         break;
03506     case CMSG_CTRL_VERIFY_SIGNATURE_EX:
03507         switch (msg->type)
03508         {
03509         case CMSG_SIGNED:
03510             ret = CDecodeSignedMsg_VerifySignatureEx(msg,
03511              (PCMSG_CTRL_VERIFY_SIGNATURE_EX_PARA)pvCtrlPara);
03512             break;
03513         default:
03514             SetLastError(CRYPT_E_INVALID_MSG_TYPE);
03515         }
03516         break;
03517     default:
03518         SetLastError(CRYPT_E_CONTROL_TYPE);
03519     }
03520     return ret;
03521 }
03522 
03523 HCRYPTMSG WINAPI CryptMsgOpenToDecode(DWORD dwMsgEncodingType, DWORD dwFlags,
03524  DWORD dwMsgType, HCRYPTPROV_LEGACY hCryptProv, PCERT_INFO pRecipientInfo,
03525  PCMSG_STREAM_INFO pStreamInfo)
03526 {
03527     CDecodeMsg *msg;
03528 
03529     TRACE("(%08x, %08x, %08x, %08lx, %p, %p)\n", dwMsgEncodingType,
03530      dwFlags, dwMsgType, hCryptProv, pRecipientInfo, pStreamInfo);
03531 
03532     if (GET_CMSG_ENCODING_TYPE(dwMsgEncodingType) != PKCS_7_ASN_ENCODING)
03533     {
03534         SetLastError(E_INVALIDARG);
03535         return NULL;
03536     }
03537     msg = CryptMemAlloc(sizeof(CDecodeMsg));
03538     if (msg)
03539     {
03540         CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo,
03541          CDecodeMsg_Close, CDecodeMsg_GetParam, CDecodeMsg_Update,
03542          CDecodeMsg_Control);
03543         msg->type = dwMsgType;
03544         if (hCryptProv)
03545             msg->crypt_prov = hCryptProv;
03546         else
03547         {
03548             msg->crypt_prov = CRYPT_GetDefaultProvider();
03549             msg->base.open_flags &= ~CMSG_CRYPT_RELEASE_CONTEXT_FLAG;
03550         }
03551         memset(&msg->u, 0, sizeof(msg->u));
03552         msg->msg_data.cbData = 0;
03553         msg->msg_data.pbData = NULL;
03554         msg->detached_data.cbData = 0;
03555         msg->detached_data.pbData = NULL;
03556         msg->properties = ContextPropertyList_Create();
03557     }
03558     return msg;
03559 }
03560 
03561 HCRYPTMSG WINAPI CryptMsgDuplicate(HCRYPTMSG hCryptMsg)
03562 {
03563     TRACE("(%p)\n", hCryptMsg);
03564 
03565     if (hCryptMsg)
03566     {
03567         CryptMsgBase *msg = hCryptMsg;
03568 
03569         InterlockedIncrement(&msg->ref);
03570     }
03571     return hCryptMsg;
03572 }
03573 
03574 BOOL WINAPI CryptMsgClose(HCRYPTMSG hCryptMsg)
03575 {
03576     TRACE("(%p)\n", hCryptMsg);
03577 
03578     if (hCryptMsg)
03579     {
03580         CryptMsgBase *msg = hCryptMsg;
03581 
03582         if (InterlockedDecrement(&msg->ref) == 0)
03583         {
03584             TRACE("freeing %p\n", msg);
03585             if (msg->close)
03586                 msg->close(msg);
03587             CryptMemFree(msg);
03588         }
03589     }
03590     return TRUE;
03591 }
03592 
03593 BOOL WINAPI CryptMsgUpdate(HCRYPTMSG hCryptMsg, const BYTE *pbData,
03594  DWORD cbData, BOOL fFinal)
03595 {
03596     CryptMsgBase *msg = hCryptMsg;
03597 
03598     TRACE("(%p, %p, %d, %d)\n", hCryptMsg, pbData, cbData, fFinal);
03599 
03600     return msg->update(hCryptMsg, pbData, cbData, fFinal);
03601 }
03602 
03603 BOOL WINAPI CryptMsgGetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType,
03604  DWORD dwIndex, void *pvData, DWORD *pcbData)
03605 {
03606     CryptMsgBase *msg = hCryptMsg;
03607 
03608     TRACE("(%p, %d, %d, %p, %p)\n", hCryptMsg, dwParamType, dwIndex,
03609      pvData, pcbData);
03610     return msg->get_param(hCryptMsg, dwParamType, dwIndex, pvData, pcbData);
03611 }
03612 
03613 BOOL WINAPI CryptMsgControl(HCRYPTMSG hCryptMsg, DWORD dwFlags,
03614  DWORD dwCtrlType, const void *pvCtrlPara)
03615 {
03616     CryptMsgBase *msg = hCryptMsg;
03617 
03618     TRACE("(%p, %08x, %d, %p)\n", hCryptMsg, dwFlags, dwCtrlType,
03619      pvCtrlPara);
03620     return msg->control(hCryptMsg, dwFlags, dwCtrlType, pvCtrlPara);
03621 }
03622 
03623 static CERT_INFO *CRYPT_GetSignerCertInfoFromMsg(HCRYPTMSG msg,
03624  DWORD dwSignerIndex)
03625 {
03626     CERT_INFO *certInfo = NULL;
03627     DWORD size;
03628 
03629     if (CryptMsgGetParam(msg, CMSG_SIGNER_CERT_INFO_PARAM, dwSignerIndex, NULL,
03630      &size))
03631     {
03632         certInfo = CryptMemAlloc(size);
03633         if (certInfo)
03634         {
03635             if (!CryptMsgGetParam(msg, CMSG_SIGNER_CERT_INFO_PARAM,
03636              dwSignerIndex, certInfo, &size))
03637             {
03638                 CryptMemFree(certInfo);
03639                 certInfo = NULL;
03640             }
03641         }
03642     }
03643     return certInfo;
03644 }
03645 
03646 BOOL WINAPI CryptMsgGetAndVerifySigner(HCRYPTMSG hCryptMsg, DWORD cSignerStore,
03647  HCERTSTORE *rghSignerStore, DWORD dwFlags, PCCERT_CONTEXT *ppSigner,
03648  DWORD *pdwSignerIndex)
03649 {
03650     HCERTSTORE store;
03651     DWORD i, signerIndex = 0;
03652     PCCERT_CONTEXT signerCert = NULL;
03653     BOOL ret = FALSE;
03654 
03655     TRACE("(%p, %d, %p, %08x, %p, %p)\n", hCryptMsg, cSignerStore,
03656      rghSignerStore, dwFlags, ppSigner, pdwSignerIndex);
03657 
03658     /* Clear output parameters */
03659     if (ppSigner)
03660         *ppSigner = NULL;
03661     if (pdwSignerIndex && !(dwFlags & CMSG_USE_SIGNER_INDEX_FLAG))
03662         *pdwSignerIndex = 0;
03663 
03664     /* Create store to search for signer certificates */
03665     store = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
03666      CERT_STORE_CREATE_NEW_FLAG, NULL);
03667     if (!(dwFlags & CMSG_TRUSTED_SIGNER_FLAG))
03668     {
03669         HCERTSTORE msgStore = CertOpenStore(CERT_STORE_PROV_MSG, 0, 0, 0,
03670          hCryptMsg);
03671 
03672         CertAddStoreToCollection(store, msgStore, 0, 0);
03673         CertCloseStore(msgStore, 0);
03674     }
03675     for (i = 0; i < cSignerStore; i++)
03676         CertAddStoreToCollection(store, rghSignerStore[i], 0, 0);
03677 
03678     /* Find signer cert */
03679     if (dwFlags & CMSG_USE_SIGNER_INDEX_FLAG)
03680     {
03681         CERT_INFO *signer = CRYPT_GetSignerCertInfoFromMsg(hCryptMsg,
03682          *pdwSignerIndex);
03683 
03684         if (signer)
03685         {
03686             signerIndex = *pdwSignerIndex;
03687             signerCert = CertFindCertificateInStore(store, X509_ASN_ENCODING,
03688              0, CERT_FIND_SUBJECT_CERT, signer, NULL);
03689             CryptMemFree(signer);
03690         }
03691     }
03692     else
03693     {
03694         DWORD count, size = sizeof(count);
03695 
03696         if (CryptMsgGetParam(hCryptMsg, CMSG_SIGNER_COUNT_PARAM, 0, &count,
03697          &size))
03698         {
03699             for (i = 0; !signerCert && i < count; i++)
03700             {
03701                 CERT_INFO *signer = CRYPT_GetSignerCertInfoFromMsg(hCryptMsg,
03702                  i);
03703 
03704                 if (signer)
03705                 {
03706                     signerCert = CertFindCertificateInStore(store,
03707                      X509_ASN_ENCODING, 0, CERT_FIND_SUBJECT_CERT, signer,
03708                      NULL);
03709                     if (signerCert)
03710                         signerIndex = i;
03711                     CryptMemFree(signer);
03712                 }
03713             }
03714         }
03715         if (!signerCert)
03716             SetLastError(CRYPT_E_NO_TRUSTED_SIGNER);
03717     }
03718     if (signerCert)
03719     {
03720         if (!(dwFlags & CMSG_SIGNER_ONLY_FLAG))
03721             ret = CryptMsgControl(hCryptMsg, 0, CMSG_CTRL_VERIFY_SIGNATURE,
03722              signerCert->pCertInfo);
03723         else
03724             ret = TRUE;
03725         if (ret)
03726         {
03727             if (ppSigner)
03728                 *ppSigner = CertDuplicateCertificateContext(signerCert);
03729             if (pdwSignerIndex)
03730                 *pdwSignerIndex = signerIndex;
03731         }
03732         CertFreeCertificateContext(signerCert);
03733     }
03734 
03735     CertCloseStore(store, 0);
03736     return ret;
03737 }
03738 
03739 BOOL WINAPI CryptMsgVerifyCountersignatureEncodedEx(HCRYPTPROV_LEGACY hCryptProv,
03740  DWORD dwEncodingType, PBYTE pbSignerInfo, DWORD cbSignerInfo,
03741  PBYTE pbSignerInfoCountersignature, DWORD cbSignerInfoCountersignature,
03742  DWORD dwSignerType, void *pvSigner, DWORD dwFlags, void *pvReserved)
03743 {
03744     FIXME("(%08lx, %08x, %p, %d, %p, %d, %d, %p, %08x, %p): stub\n", hCryptProv,
03745      dwEncodingType, pbSignerInfo, cbSignerInfo, pbSignerInfoCountersignature,
03746      cbSignerInfoCountersignature, dwSignerType, pvSigner, dwFlags, pvReserved);
03747     return FALSE;
03748 }
03749 
03750 BOOL WINAPI CryptMsgEncodeAndSignCTL(DWORD dwMsgEncodingType,
03751  PCTL_INFO pCtlInfo, PCMSG_SIGNED_ENCODE_INFO pSignInfo, DWORD dwFlags,
03752  BYTE *pbEncoded, DWORD *pcbEncoded)
03753 {
03754     BOOL ret;
03755     BYTE *pbCtlContent;
03756     DWORD cbCtlContent;
03757 
03758     TRACE("(%08x, %p, %p, %08x, %p, %p)\n", dwMsgEncodingType, pCtlInfo,
03759      pSignInfo, dwFlags, pbEncoded, pcbEncoded);
03760 
03761     if (dwFlags)
03762     {
03763         FIXME("unimplemented for flags %08x\n", dwFlags);
03764         return FALSE;
03765     }
03766     if ((ret = CryptEncodeObjectEx(dwMsgEncodingType, PKCS_CTL, pCtlInfo,
03767      CRYPT_ENCODE_ALLOC_FLAG, NULL, &pbCtlContent, &cbCtlContent)))
03768     {
03769         ret = CryptMsgSignCTL(dwMsgEncodingType, pbCtlContent, cbCtlContent,
03770          pSignInfo, dwFlags, pbEncoded, pcbEncoded);
03771         LocalFree(pbCtlContent);
03772     }
03773     return ret;
03774 }
03775 
03776 BOOL WINAPI CryptMsgSignCTL(DWORD dwMsgEncodingType, BYTE *pbCtlContent,
03777  DWORD cbCtlContent, PCMSG_SIGNED_ENCODE_INFO pSignInfo, DWORD dwFlags,
03778  BYTE *pbEncoded, DWORD *pcbEncoded)
03779 {
03780     static char oid_ctl[] = szOID_CTL;
03781     BOOL ret;
03782     HCRYPTMSG msg;
03783 
03784     TRACE("(%08x, %p, %d, %p, %08x, %p, %p)\n", dwMsgEncodingType,
03785      pbCtlContent, cbCtlContent, pSignInfo, dwFlags, pbEncoded, pcbEncoded);
03786 
03787     if (dwFlags)
03788     {
03789         FIXME("unimplemented for flags %08x\n", dwFlags);
03790         return FALSE;
03791     }
03792     msg = CryptMsgOpenToEncode(dwMsgEncodingType, 0, CMSG_SIGNED, pSignInfo,
03793      oid_ctl, NULL);
03794     if (msg)
03795     {
03796         ret = CryptMsgUpdate(msg, pbCtlContent, cbCtlContent, TRUE);
03797         if (ret)
03798             ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, pbEncoded,
03799              pcbEncoded);
03800         CryptMsgClose(msg);
03801     }
03802     else
03803         ret = FALSE;
03804     return ret;
03805 }

Generated on Sat May 26 2012 04:21:53 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.