Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840/* * Copyright 2007 Juan Lang * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
#include "config.h"#include "wine/port.h"
#include <stdarg.h>#define NONAMELESSUNION#include "windef.h"#include "winbase.h"#include "wincrypt.h"#include "snmp.h"
#include "wine/debug.h"#include "wine/exception.h"#include "crypt32_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(crypt);
/* Called when a message's ref count reaches zero. Free any message-specific * data here. */typedef void (*CryptMsgCloseFunc)(HCRYPTMSG msg);
typedef BOOL (*CryptMsgGetParamFunc)(HCRYPTMSG hCryptMsg, DWORD dwParamType, DWORD dwIndex, void *pvData, DWORD *pcbData);
typedef BOOL (*CryptMsgUpdateFunc)(HCRYPTMSG hCryptMsg, const BYTE *pbData, DWORD cbData, BOOL fFinal);
typedef BOOL (*CryptMsgControlFunc)(HCRYPTMSG hCryptMsg, DWORD dwFlags, DWORD dwCtrlType, const void *pvCtrlPara);
static BOOL CRYPT_DefaultMsgControl(HCRYPTMSG hCryptMsg, DWORD dwFlags, DWORD dwCtrlType, const void *pvCtrlPara){ TRACE("(%p, %08x, %d, %p)\n", hCryptMsg, dwFlags, dwCtrlType, pvCtrlPara); SetLastError(E_INVALIDARG); return FALSE;}
typedef enum _CryptMsgState { MsgStateInit, MsgStateUpdated, MsgStateDataFinalized, MsgStateFinalized} CryptMsgState;
typedef struct _CryptMsgBase{ LONG ref; DWORD open_flags; BOOL streamed; CMSG_STREAM_INFO stream_info; CryptMsgState state; CryptMsgCloseFunc close; CryptMsgUpdateFunc update; CryptMsgGetParamFunc get_param; CryptMsgControlFunc control;} CryptMsgBase;
static inline void CryptMsgBase_Init(CryptMsgBase *msg, DWORD dwFlags, PCMSG_STREAM_INFO pStreamInfo, CryptMsgCloseFunc close, CryptMsgGetParamFunc get_param, CryptMsgUpdateFunc update, CryptMsgControlFunc control){ msg->ref = 1; msg->open_flags = dwFlags; if (pStreamInfo) { msg->streamed = TRUE; msg->stream_info = *pStreamInfo; } else { msg->streamed = FALSE; memset(&msg->stream_info, 0, sizeof(msg->stream_info)); } msg->close = close; msg->get_param = get_param; msg->update = update; msg->control = control; msg->state = MsgStateInit;}
typedef struct _CDataEncodeMsg{ CryptMsgBase base; DWORD bare_content_len; LPBYTE bare_content;} CDataEncodeMsg;
static const BYTE empty_data_content[] = { 0x04,0x00 };
static void CDataEncodeMsg_Close(HCRYPTMSG hCryptMsg){ CDataEncodeMsg *msg = hCryptMsg;
if (msg->bare_content != empty_data_content) LocalFree(msg->bare_content);}
static BOOL WINAPI CRYPT_EncodeContentLength(DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded){ DWORD dataLen = *(DWORD *)pvStructInfo; DWORD lenBytes; BOOL ret = TRUE;
/* Trick: report bytes needed based on total message length, even though * the message isn't available yet. The caller will use the length * reported here to encode its length. */ CRYPT_EncodeLen(dataLen, NULL, &lenBytes); if (!pbEncoded) *pcbEncoded = 1 + lenBytes + dataLen; else { if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded, 1 + lenBytes))) { if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG) pbEncoded = *(BYTE **)pbEncoded; *pbEncoded++ = ASN_OCTETSTRING; CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes); } } return ret;}
static BOOL CRYPT_EncodeDataContentInfoHeader(const CDataEncodeMsg *msg, CRYPT_DATA_BLOB *header){ BOOL ret;
if (msg->base.streamed && msg->base.stream_info.cbContent == 0xffffffff) { static const BYTE headerValue[] = { 0x30,0x80,0x06,0x09,0x2a,0x86,0x48, 0x86,0xf7,0x0d,0x01,0x07,0x01,0xa0,0x80,0x24,0x80 };
header->pbData = LocalAlloc(0, sizeof(headerValue)); if (header->pbData) { header->cbData = sizeof(headerValue); memcpy(header->pbData, headerValue, sizeof(headerValue)); ret = TRUE; } else ret = FALSE; } else { struct AsnConstructedItem constructed = { 0, &msg->base.stream_info.cbContent, CRYPT_EncodeContentLength }; struct AsnEncodeSequenceItem items[2] = { { szOID_RSA_data, CRYPT_AsnEncodeOid, 0 }, { &constructed, CRYPT_AsnEncodeConstructed, 0 }, };
ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, ARRAY_SIZE(items), CRYPT_ENCODE_ALLOC_FLAG, NULL, (LPBYTE)&header->pbData, &header->cbData); if (ret) { /* Trick: subtract the content length from the reported length, * as the actual content hasn't come yet. */ header->cbData -= msg->base.stream_info.cbContent; } } return ret;}
static BOOL CDataEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData, DWORD cbData, BOOL fFinal){ CDataEncodeMsg *msg = hCryptMsg; BOOL ret = FALSE;
if (msg->base.state == MsgStateFinalized) SetLastError(CRYPT_E_MSG_ERROR); else if (msg->base.streamed) { __TRY { if (msg->base.state != MsgStateUpdated) { CRYPT_DATA_BLOB header;
ret = CRYPT_EncodeDataContentInfoHeader(msg, &header); if (ret) { ret = msg->base.stream_info.pfnStreamOutput( msg->base.stream_info.pvArg, header.pbData, header.cbData, FALSE); LocalFree(header.pbData); } } /* Curiously, every indefinite-length streamed update appears to * get its own tag and length, regardless of fFinal. */ if (msg->base.stream_info.cbContent == 0xffffffff) { BYTE *header; DWORD headerLen;
ret = CRYPT_EncodeContentLength(X509_ASN_ENCODING, NULL, &cbData, CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&header, &headerLen); if (ret) { ret = msg->base.stream_info.pfnStreamOutput( msg->base.stream_info.pvArg, header, headerLen, FALSE); LocalFree(header); } } if (!fFinal) { ret = msg->base.stream_info.pfnStreamOutput( msg->base.stream_info.pvArg, (BYTE *)pbData, cbData, FALSE); msg->base.state = MsgStateUpdated; } else { msg->base.state = MsgStateFinalized; if (msg->base.stream_info.cbContent == 0xffffffff) { BYTE indefinite_trailer[6] = { 0 };
ret = msg->base.stream_info.pfnStreamOutput( msg->base.stream_info.pvArg, (BYTE *)pbData, cbData, FALSE); if (ret) ret = msg->base.stream_info.pfnStreamOutput( msg->base.stream_info.pvArg, indefinite_trailer, sizeof(indefinite_trailer), TRUE); } else ret = msg->base.stream_info.pfnStreamOutput( msg->base.stream_info.pvArg, (BYTE *)pbData, cbData, TRUE); } } __EXCEPT_PAGE_FAULT { SetLastError(STATUS_ACCESS_VIOLATION); ret = FALSE; } __ENDTRY; } else { if (!fFinal) { if (msg->base.open_flags & CMSG_DETACHED_FLAG) SetLastError(E_INVALIDARG); else SetLastError(CRYPT_E_MSG_ERROR); } else { CRYPT_DATA_BLOB blob = { cbData, (LPBYTE)pbData };
msg->base.state = MsgStateFinalized; /* non-streamed data messages don't allow non-final updates, * don't bother checking whether data already exist, they can't. */ ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING, &blob, CRYPT_ENCODE_ALLOC_FLAG, NULL, &msg->bare_content, &msg->bare_content_len); } } return ret;}
static BOOL CRYPT_CopyParam(void *pvData, DWORD *pcbData, const void *src, DWORD len){ BOOL ret = TRUE;
if (!pvData) *pcbData = len; else if (*pcbData < len) { *pcbData = len; SetLastError(ERROR_MORE_DATA); ret = FALSE; } else { *pcbData = len; memcpy(pvData, src, len); } return ret;}
static BOOL CDataEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType, DWORD dwIndex, void *pvData, DWORD *pcbData){ CDataEncodeMsg *msg = hCryptMsg; BOOL ret = FALSE;
switch (dwParamType) { case CMSG_CONTENT_PARAM: if (msg->base.streamed) SetLastError(E_INVALIDARG); else { CRYPT_CONTENT_INFO info; char rsa_data[] = "1.2.840.113549.1.7.1";
info.pszObjId = rsa_data; info.Content.cbData = msg->bare_content_len; info.Content.pbData = msg->bare_content; ret = CryptEncodeObject(X509_ASN_ENCODING, PKCS_CONTENT_INFO, &info, pvData, pcbData); } break; case CMSG_BARE_CONTENT_PARAM: if (msg->base.streamed) SetLastError(E_INVALIDARG); else ret = CRYPT_CopyParam(pvData, pcbData, msg->bare_content, msg->bare_content_len); break; default: SetLastError(CRYPT_E_INVALID_MSG_TYPE); } return ret;}
static HCRYPTMSG CDataEncodeMsg_Open(DWORD dwFlags, const void *pvMsgEncodeInfo, LPSTR pszInnerContentObjID, PCMSG_STREAM_INFO pStreamInfo){ CDataEncodeMsg *msg;
if (pvMsgEncodeInfo) { SetLastError(E_INVALIDARG); return NULL; } msg = CryptMemAlloc(sizeof(CDataEncodeMsg)); if (msg) { CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo, CDataEncodeMsg_Close, CDataEncodeMsg_GetParam, CDataEncodeMsg_Update, CRYPT_DefaultMsgControl); msg->bare_content_len = sizeof(empty_data_content); msg->bare_content = (LPBYTE)empty_data_content; } return msg;}
typedef struct _CHashEncodeMsg{ CryptMsgBase base; HCRYPTPROV prov; HCRYPTHASH hash; CRYPT_DATA_BLOB data;} CHashEncodeMsg;
static void CHashEncodeMsg_Close(HCRYPTMSG hCryptMsg){ CHashEncodeMsg *msg = hCryptMsg;
CryptMemFree(msg->data.pbData); CryptDestroyHash(msg->hash); if (msg->base.open_flags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG) CryptReleaseContext(msg->prov, 0);}
static BOOL CRYPT_EncodePKCSDigestedData(CHashEncodeMsg *msg, void *pvData, DWORD *pcbData){ BOOL ret; ALG_ID algID; DWORD size = sizeof(algID);
ret = CryptGetHashParam(msg->hash, HP_ALGID, (BYTE *)&algID, &size, 0); if (ret) { CRYPT_DIGESTED_DATA digestedData = { 0 }; char oid_rsa_data[] = szOID_RSA_data;
digestedData.version = CMSG_HASHED_DATA_PKCS_1_5_VERSION; digestedData.DigestAlgorithm.pszObjId = (LPSTR)CertAlgIdToOID(algID); /* FIXME: what about digestedData.DigestAlgorithm.Parameters? */ /* Quirk: OID is only encoded messages if an update has happened */ if (msg->base.state != MsgStateInit) digestedData.ContentInfo.pszObjId = oid_rsa_data; if (!(msg->base.open_flags & CMSG_DETACHED_FLAG) && msg->data.cbData) { ret = CRYPT_AsnEncodeOctets(0, NULL, &msg->data, CRYPT_ENCODE_ALLOC_FLAG, NULL, (LPBYTE)&digestedData.ContentInfo.Content.pbData, &digestedData.ContentInfo.Content.cbData); } if (msg->base.state == MsgStateFinalized) { size = sizeof(DWORD); ret = CryptGetHashParam(msg->hash, HP_HASHSIZE, (LPBYTE)&digestedData.hash.cbData, &size, 0); if (ret) { digestedData.hash.pbData = CryptMemAlloc( digestedData.hash.cbData); ret = CryptGetHashParam(msg->hash, HP_HASHVAL, digestedData.hash.pbData, &digestedData.hash.cbData, 0); } } if (ret) ret = CRYPT_AsnEncodePKCSDigestedData(&digestedData, pvData, pcbData); CryptMemFree(digestedData.hash.pbData); LocalFree(digestedData.ContentInfo.Content.pbData); } return ret;}
static BOOL CHashEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType, DWORD dwIndex, void *pvData, DWORD *pcbData){ CHashEncodeMsg *msg = hCryptMsg; BOOL ret = FALSE;
TRACE("(%p, %d, %d, %p, %p)\n", hCryptMsg, dwParamType, dwIndex, pvData, pcbData);
switch (dwParamType) { case CMSG_BARE_CONTENT_PARAM: if (msg->base.streamed) SetLastError(E_INVALIDARG); else ret = CRYPT_EncodePKCSDigestedData(msg, pvData, pcbData); break; case CMSG_CONTENT_PARAM: { CRYPT_CONTENT_INFO info;
ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0, NULL, &info.Content.cbData); if (ret) { info.Content.pbData = CryptMemAlloc(info.Content.cbData); if (info.Content.pbData) { ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0, info.Content.pbData, &info.Content.cbData); if (ret) { char oid_rsa_hashed[] = szOID_RSA_hashedData;
info.pszObjId = oid_rsa_hashed; ret = CryptEncodeObjectEx(X509_ASN_ENCODING, PKCS_CONTENT_INFO, &info, 0, NULL, pvData, pcbData); } CryptMemFree(info.Content.pbData); } else ret = FALSE; } break; } case CMSG_COMPUTED_HASH_PARAM: ret = CryptGetHashParam(msg->hash, HP_HASHVAL, pvData, pcbData, 0); break; case CMSG_VERSION_PARAM: if (msg->base.state != MsgStateFinalized) SetLastError(CRYPT_E_MSG_ERROR); else { DWORD version = CMSG_HASHED_DATA_PKCS_1_5_VERSION;
/* Since the data are always encoded as octets, the version is * always 0 (see rfc3852, section 7) */ ret = CRYPT_CopyParam(pvData, pcbData, &version, sizeof(version)); } break; default: SetLastError(CRYPT_E_INVALID_MSG_TYPE); } return ret;}
static BOOL CHashEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData, DWORD cbData, BOOL fFinal){ CHashEncodeMsg *msg = hCryptMsg; BOOL ret = FALSE;
TRACE("(%p, %p, %d, %d)\n", hCryptMsg, pbData, cbData, fFinal);
if (msg->base.state == MsgStateFinalized) SetLastError(CRYPT_E_MSG_ERROR); else if (msg->base.streamed || (msg->base.open_flags & CMSG_DETACHED_FLAG)) { /* Doesn't do much, as stream output is never called, and you * can't get the content. */ ret = CryptHashData(msg->hash, pbData, cbData, 0); msg->base.state = fFinal ? MsgStateFinalized : MsgStateUpdated; } else { if (!fFinal) SetLastError(CRYPT_E_MSG_ERROR); else { ret = CryptHashData(msg->hash, pbData, cbData, 0); if (ret) { msg->data.pbData = CryptMemAlloc(cbData); if (msg->data.pbData) { memcpy(msg->data.pbData + msg->data.cbData, pbData, cbData); msg->data.cbData += cbData; } else ret = FALSE; } msg->base.state = MsgStateFinalized; } } return ret;}
static HCRYPTMSG CHashEncodeMsg_Open(DWORD dwFlags, const void *pvMsgEncodeInfo, LPSTR pszInnerContentObjID, PCMSG_STREAM_INFO pStreamInfo){ CHashEncodeMsg *msg; const CMSG_HASHED_ENCODE_INFO *info = pvMsgEncodeInfo; HCRYPTPROV prov; ALG_ID algID;
if (info->cbSize != sizeof(CMSG_HASHED_ENCODE_INFO)) { SetLastError(E_INVALIDARG); return NULL; } if (!(algID = CertOIDToAlgId(info->HashAlgorithm.pszObjId))) { SetLastError(CRYPT_E_UNKNOWN_ALGO); return NULL; } if (info->hCryptProv) prov = info->hCryptProv; else { prov = I_CryptGetDefaultCryptProv(algID); if (!prov) { SetLastError(E_INVALIDARG); return NULL; } dwFlags &= ~CMSG_CRYPT_RELEASE_CONTEXT_FLAG; } msg = CryptMemAlloc(sizeof(CHashEncodeMsg)); if (msg) { CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo, CHashEncodeMsg_Close, CHashEncodeMsg_GetParam, CHashEncodeMsg_Update, CRYPT_DefaultMsgControl); msg->prov = prov; msg->data.cbData = 0; msg->data.pbData = NULL; if (!CryptCreateHash(prov, algID, 0, 0, &msg->hash)) { CryptMsgClose(msg); msg = NULL; } } return msg;}
typedef struct _CMSG_SIGNER_ENCODE_INFO_WITH_CMS{ DWORD cbSize; PCERT_INFO pCertInfo; HCRYPTPROV hCryptProv; DWORD dwKeySpec; CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm; void *pvHashAuxInfo; DWORD cAuthAttr; PCRYPT_ATTRIBUTE rgAuthAttr; DWORD cUnauthAttr; PCRYPT_ATTRIBUTE rgUnauthAttr; CERT_ID SignerId; CRYPT_ALGORITHM_IDENTIFIER HashEncryptionAlgorithm; void *pvHashEncryptionAuxInfo;} CMSG_SIGNER_ENCODE_INFO_WITH_CMS;
typedef struct _CMSG_SIGNED_ENCODE_INFO_WITH_CMS{ DWORD cbSize; DWORD cSigners; CMSG_SIGNER_ENCODE_INFO_WITH_CMS *rgSigners; DWORD cCertEncoded; PCERT_BLOB rgCertEncoded; DWORD cCrlEncoded; PCRL_BLOB rgCrlEncoded; DWORD cAttrCertEncoded; PCERT_BLOB rgAttrCertEncoded;} CMSG_SIGNED_ENCODE_INFO_WITH_CMS;
static BOOL CRYPT_IsValidSigner(const CMSG_SIGNER_ENCODE_INFO_WITH_CMS *signer){ if (signer->cbSize != sizeof(CMSG_SIGNER_ENCODE_INFO) && signer->cbSize != sizeof(CMSG_SIGNER_ENCODE_INFO_WITH_CMS)) { SetLastError(E_INVALIDARG); return FALSE; } if (signer->cbSize == sizeof(CMSG_SIGNER_ENCODE_INFO)) { if (!signer->pCertInfo->SerialNumber.cbData) { SetLastError(E_INVALIDARG); return FALSE; } if (!signer->pCertInfo->Issuer.cbData) { SetLastError(E_INVALIDARG); return FALSE; } } else if (signer->cbSize == sizeof(CMSG_SIGNER_ENCODE_INFO_WITH_CMS)) { switch (signer->SignerId.dwIdChoice) { case 0: if (!signer->pCertInfo->SerialNumber.cbData) { SetLastError(E_INVALIDARG); return FALSE; } if (!signer->pCertInfo->Issuer.cbData) { SetLastError(E_INVALIDARG); return FALSE; } break; case CERT_ID_ISSUER_SERIAL_NUMBER: if (!signer->SignerId.u.IssuerSerialNumber.SerialNumber.cbData) { SetLastError(E_INVALIDARG); return FALSE; } if (!signer->SignerId.u.IssuerSerialNumber.Issuer.cbData) { SetLastError(E_INVALIDARG); return FALSE; } break; case CERT_ID_KEY_IDENTIFIER: if (!signer->SignerId.u.KeyId.cbData) { SetLastError(E_INVALIDARG); return FALSE; } break; default: SetLastError(E_INVALIDARG); } if (signer->HashEncryptionAlgorithm.pszObjId) { FIXME("CMSG_SIGNER_ENCODE_INFO with CMS fields unsupported\n"); return FALSE; } } if (!signer->hCryptProv) { SetLastError(E_INVALIDARG); return FALSE; } if (!CertOIDToAlgId(signer->HashAlgorithm.pszObjId)) { SetLastError(CRYPT_E_UNKNOWN_ALGO); return FALSE; } return TRUE;}
static BOOL CRYPT_ConstructBlob(CRYPT_DATA_BLOB *out, const CRYPT_DATA_BLOB *in){ BOOL ret = TRUE;
out->cbData = in->cbData; if (out->cbData) { out->pbData = CryptMemAlloc(out->cbData); if (out->pbData) memcpy(out->pbData, in->pbData, out->cbData); else ret = FALSE; } else out->pbData = NULL; return ret;}
static BOOL CRYPT_ConstructBlobArray(DWORD *outCBlobs, PCRYPT_DATA_BLOB *outPBlobs, DWORD cBlobs, const CRYPT_DATA_BLOB *pBlobs){ BOOL ret = TRUE;
*outCBlobs = cBlobs; if (cBlobs) { *outPBlobs = CryptMemAlloc(cBlobs * sizeof(CRYPT_DATA_BLOB)); if (*outPBlobs) { DWORD i;
memset(*outPBlobs, 0, cBlobs * sizeof(CRYPT_DATA_BLOB)); for (i = 0; ret && i < cBlobs; i++) ret = CRYPT_ConstructBlob(&(*outPBlobs)[i], &pBlobs[i]); } else ret = FALSE; } return ret;}
static void CRYPT_FreeBlobArray(DWORD cBlobs, PCRYPT_DATA_BLOB blobs){ DWORD i;
for (i = 0; i < cBlobs; i++) CryptMemFree(blobs[i].pbData); CryptMemFree(blobs);}
static BOOL CRYPT_ConstructAttribute(CRYPT_ATTRIBUTE *out, const CRYPT_ATTRIBUTE *in){ BOOL ret;
out->pszObjId = CryptMemAlloc(strlen(in->pszObjId) + 1); if (out->pszObjId) { strcpy(out->pszObjId, in->pszObjId); ret = CRYPT_ConstructBlobArray(&out->cValue, &out->rgValue, in->cValue, in->rgValue); } else ret = FALSE; return ret;}
static BOOL CRYPT_ConstructAttributes(CRYPT_ATTRIBUTES *out, const CRYPT_ATTRIBUTES *in){ BOOL ret = TRUE;
out->cAttr = in->cAttr; if (out->cAttr) { out->rgAttr = CryptMemAlloc(out->cAttr * sizeof(CRYPT_ATTRIBUTE)); if (out->rgAttr) { DWORD i;
memset(out->rgAttr, 0, out->cAttr * sizeof(CRYPT_ATTRIBUTE)); for (i = 0; ret && i < out->cAttr; i++) ret = CRYPT_ConstructAttribute(&out->rgAttr[i], &in->rgAttr[i]); } else ret = FALSE; } else out->rgAttr = NULL; return ret;}
/* Constructs a CMSG_CMS_SIGNER_INFO from a CMSG_SIGNER_ENCODE_INFO_WITH_CMS. */static BOOL CSignerInfo_Construct(CMSG_CMS_SIGNER_INFO *info, const CMSG_SIGNER_ENCODE_INFO_WITH_CMS *in){ BOOL ret;
if (in->cbSize == sizeof(CMSG_SIGNER_ENCODE_INFO)) { info->dwVersion = CMSG_SIGNER_INFO_V1; ret = CRYPT_ConstructBlob(&info->SignerId.u.IssuerSerialNumber.Issuer, &in->pCertInfo->Issuer); if (ret) ret = CRYPT_ConstructBlob( &info->SignerId.u.IssuerSerialNumber.SerialNumber, &in->pCertInfo->SerialNumber); info->SignerId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER; info->HashEncryptionAlgorithm.pszObjId = in->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId; if (ret) ret = CRYPT_ConstructBlob(&info->HashEncryptionAlgorithm.Parameters, &in->pCertInfo->SubjectPublicKeyInfo.Algorithm.Parameters); } else { const CRYPT_ALGORITHM_IDENTIFIER *pEncrAlg;
/* Implicitly in->cbSize == sizeof(CMSG_SIGNER_ENCODE_INFO_WITH_CMS). * See CRYPT_IsValidSigner. */ if (!in->SignerId.dwIdChoice) { info->dwVersion = CMSG_SIGNER_INFO_V1; ret = CRYPT_ConstructBlob(&info->SignerId.u.IssuerSerialNumber.Issuer, &in->pCertInfo->Issuer); if (ret) ret = CRYPT_ConstructBlob( &info->SignerId.u.IssuerSerialNumber.SerialNumber, &in->pCertInfo->SerialNumber); info->SignerId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER; } else if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER) { info->dwVersion = CMSG_SIGNER_INFO_V1; info->SignerId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER; ret = CRYPT_ConstructBlob(&info->SignerId.u.IssuerSerialNumber.Issuer, &in->SignerId.u.IssuerSerialNumber.Issuer); if (ret) ret = CRYPT_ConstructBlob( &info->SignerId.u.IssuerSerialNumber.SerialNumber, &in->SignerId.u.IssuerSerialNumber.SerialNumber); } else { /* Implicitly dwIdChoice == CERT_ID_KEY_IDENTIFIER */ info->dwVersion = CMSG_SIGNER_INFO_V3; info->SignerId.dwIdChoice = CERT_ID_KEY_IDENTIFIER; ret = CRYPT_ConstructBlob(&info->SignerId.u.KeyId, &in->SignerId.u.KeyId); } pEncrAlg = in->HashEncryptionAlgorithm.pszObjId ? &in->HashEncryptionAlgorithm : &in->pCertInfo->SubjectPublicKeyInfo.Algorithm; info->HashEncryptionAlgorithm.pszObjId = pEncrAlg->pszObjId; if (ret) ret = CRYPT_ConstructBlob(&info->HashEncryptionAlgorithm.Parameters, &pEncrAlg->Parameters); } /* Assumption: algorithm IDs will point to static strings, not * stack-based ones, so copying the pointer values is safe. */ info->HashAlgorithm.pszObjId = in->HashAlgorithm.pszObjId; if (ret) ret = CRYPT_ConstructBlob(&info->HashAlgorithm.Parameters, &in->HashAlgorithm.Parameters); if (ret) ret = CRYPT_ConstructAttributes(&info->AuthAttrs, (CRYPT_ATTRIBUTES *)&in->cAuthAttr); if (ret) ret = CRYPT_ConstructAttributes(&info->UnauthAttrs, (CRYPT_ATTRIBUTES *)&in->cUnauthAttr); return ret;}
static void CSignerInfo_Free(CMSG_CMS_SIGNER_INFO *info){ DWORD i, j;
if (info->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER) { CryptMemFree(info->SignerId.u.IssuerSerialNumber.Issuer.pbData); CryptMemFree(info->SignerId.u.IssuerSerialNumber.SerialNumber.pbData); } else CryptMemFree(info->SignerId.u.KeyId.pbData); CryptMemFree(info->HashAlgorithm.Parameters.pbData); CryptMemFree(info->HashEncryptionAlgorithm.Parameters.pbData); CryptMemFree(info->EncryptedHash.pbData); for (i = 0; i < info->AuthAttrs.cAttr; i++) { for (j = 0; j < info->AuthAttrs.rgAttr[i].cValue; j++) CryptMemFree(info->AuthAttrs.rgAttr[i].rgValue[j].pbData); CryptMemFree(info->AuthAttrs.rgAttr[i].rgValue); CryptMemFree(info->AuthAttrs.rgAttr[i].pszObjId); } CryptMemFree(info->AuthAttrs.rgAttr); for (i = 0; i < info->UnauthAttrs.cAttr; i++) { for (j = 0; j < info->UnauthAttrs.rgAttr[i].cValue; j++) CryptMemFree(info->UnauthAttrs.rgAttr[i].rgValue[j].pbData); CryptMemFree(info->UnauthAttrs.rgAttr[i].rgValue); CryptMemFree(info->UnauthAttrs.rgAttr[i].pszObjId); } CryptMemFree(info->UnauthAttrs.rgAttr);}
typedef struct _CSignerHandles{ HCRYPTHASH contentHash; HCRYPTHASH authAttrHash;} CSignerHandles;
typedef struct _CSignedMsgData{ CRYPT_SIGNED_INFO *info; DWORD cSignerHandle; CSignerHandles *signerHandles;} CSignedMsgData;
/* Constructs the signer handles for the signerIndex'th signer of msg_data. * Assumes signerIndex is a valid idnex, and that msg_data's info has already * been constructed. */static BOOL CSignedMsgData_ConstructSignerHandles(CSignedMsgData *msg_data, DWORD signerIndex, HCRYPTPROV *crypt_prov, DWORD *flags){ ALG_ID algID; BOOL ret;
algID = CertOIDToAlgId( msg_data->info->rgSignerInfo[signerIndex].HashAlgorithm.pszObjId);
if (!*crypt_prov) { *crypt_prov = I_CryptGetDefaultCryptProv(algID); if (!*crypt_prov) return FALSE; *flags &= ~CMSG_CRYPT_RELEASE_CONTEXT_FLAG; }
ret = CryptCreateHash(*crypt_prov, algID, 0, 0, &msg_data->signerHandles->contentHash); if (ret && msg_data->info->rgSignerInfo[signerIndex].AuthAttrs.cAttr > 0) ret = CryptCreateHash(*crypt_prov, algID, 0, 0, &msg_data->signerHandles->authAttrHash); return ret;}
/* Allocates a CSignedMsgData's handles. Assumes its info has already been * constructed. */static BOOL CSignedMsgData_AllocateHandles(CSignedMsgData *msg_data){ BOOL ret = TRUE;
if (msg_data->info->cSignerInfo) { msg_data->signerHandles = CryptMemAlloc(msg_data->info->cSignerInfo * sizeof(CSignerHandles)); if (msg_data->signerHandles) { msg_data->cSignerHandle = msg_data->info->cSignerInfo; memset(msg_data->signerHandles, 0, msg_data->info->cSignerInfo * sizeof(CSignerHandles)); } else { msg_data->cSignerHandle = 0; ret = FALSE; } } else { msg_data->cSignerHandle = 0; msg_data->signerHandles = NULL; } return ret;}
static void CSignedMsgData_CloseHandles(CSignedMsgData *msg_data){ DWORD i;
for (i = 0; i < msg_data->cSignerHandle; i++) { if (msg_data->signerHandles[i].contentHash) CryptDestroyHash(msg_data->signerHandles[i].contentHash); if (msg_data->signerHandles[i].authAttrHash) CryptDestroyHash(msg_data->signerHandles[i].authAttrHash); } CryptMemFree(msg_data->signerHandles); msg_data->signerHandles = NULL; msg_data->cSignerHandle = 0;}
static BOOL CSignedMsgData_UpdateHash(CSignedMsgData *msg_data, const BYTE *pbData, DWORD cbData){ DWORD i; BOOL ret = TRUE;
for (i = 0; ret && i < msg_data->cSignerHandle; i++) ret = CryptHashData(msg_data->signerHandles[i].contentHash, pbData, cbData, 0); return ret;}
static BOOL CRYPT_AppendAttribute(CRYPT_ATTRIBUTES *out, const CRYPT_ATTRIBUTE *in){ BOOL ret = FALSE;
out->rgAttr = CryptMemRealloc(out->rgAttr, (out->cAttr + 1) * sizeof(CRYPT_ATTRIBUTE)); if (out->rgAttr) { ret = CRYPT_ConstructAttribute(&out->rgAttr[out->cAttr], in); if (ret) out->cAttr++; } return ret;}
static BOOL CSignedMsgData_AppendMessageDigestAttribute( CSignedMsgData *msg_data, DWORD signerIndex){ BOOL ret; DWORD size; CRYPT_HASH_BLOB hash = { 0, NULL }, encodedHash = { 0, NULL }; char messageDigest[] = szOID_RSA_messageDigest; CRYPT_ATTRIBUTE messageDigestAttr = { messageDigest, 1, &encodedHash };
size = sizeof(DWORD); ret = CryptGetHashParam( msg_data->signerHandles[signerIndex].contentHash, HP_HASHSIZE, (LPBYTE)&hash.cbData, &size, 0); if (ret) { hash.pbData = CryptMemAlloc(hash.cbData); ret = CryptGetHashParam( msg_data->signerHandles[signerIndex].contentHash, HP_HASHVAL, hash.pbData, &hash.cbData, 0); if (ret) { ret = CRYPT_AsnEncodeOctets(0, NULL, &hash, CRYPT_ENCODE_ALLOC_FLAG, NULL, (LPBYTE)&encodedHash.pbData, &encodedHash.cbData); if (ret) { ret = CRYPT_AppendAttribute( &msg_data->info->rgSignerInfo[signerIndex].AuthAttrs, &messageDigestAttr); LocalFree(encodedHash.pbData); } } CryptMemFree(hash.pbData); } return ret;}
typedef enum { Sign, Verify} SignOrVerify;
static BOOL CSignedMsgData_UpdateAuthenticatedAttributes( CSignedMsgData *msg_data, SignOrVerify flag){ DWORD i; BOOL ret = TRUE;
TRACE("(%p)\n", msg_data);
for (i = 0; ret && i < msg_data->info->cSignerInfo; i++) { if (msg_data->info->rgSignerInfo[i].AuthAttrs.cAttr) { if (flag == Sign) { BYTE oid_rsa_data_encoded[] = { 0x06,0x09,0x2a,0x86,0x48,0x86, 0xf7,0x0d,0x01,0x07,0x01 }; CRYPT_DATA_BLOB content = { sizeof(oid_rsa_data_encoded), oid_rsa_data_encoded }; char contentType[] = szOID_RSA_contentType; CRYPT_ATTRIBUTE contentTypeAttr = { contentType, 1, &content };
/* FIXME: does this depend on inner OID? */ ret = CRYPT_AppendAttribute( &msg_data->info->rgSignerInfo[i].AuthAttrs, &contentTypeAttr); if (ret) ret = CSignedMsgData_AppendMessageDigestAttribute(msg_data, i); } if (ret) { LPBYTE encodedAttrs; DWORD size;
ret = CryptEncodeObjectEx(X509_ASN_ENCODING, PKCS_ATTRIBUTES, &msg_data->info->rgSignerInfo[i].AuthAttrs, CRYPT_ENCODE_ALLOC_FLAG, NULL, &encodedAttrs, &size); if (ret) { ret = CryptHashData( msg_data->signerHandles[i].authAttrHash, encodedAttrs, size, 0); LocalFree(encodedAttrs); } } } } TRACE("returning %d\n", ret); return ret;}
static void CRYPT_ReverseBytes(CRYPT_HASH_BLOB *hash){ DWORD i; BYTE tmp;
for (i = 0; i < hash->cbData / 2; i++) { tmp = hash->pbData[hash->cbData - i - 1]; hash->pbData[hash->cbData - i - 1] = hash->pbData[i]; hash->pbData[i] = tmp; }}
static BOOL CSignedMsgData_Sign(CSignedMsgData *msg_data){ DWORD i; BOOL ret = TRUE;
TRACE("(%p)\n", msg_data);
for (i = 0; ret && i < msg_data->info->cSignerInfo; i++) { HCRYPTHASH hash; DWORD keySpec = msg_data->info->signerKeySpec[i];
if (!keySpec) keySpec = AT_SIGNATURE; if (msg_data->info->rgSignerInfo[i].AuthAttrs.cAttr) hash = msg_data->signerHandles[i].authAttrHash; else hash = msg_data->signerHandles[i].contentHash; ret = CryptSignHashW(hash, keySpec, NULL, 0, NULL, &msg_data->info->rgSignerInfo[i].EncryptedHash.cbData); if (ret) { msg_data->info->rgSignerInfo[i].EncryptedHash.pbData = CryptMemAlloc( msg_data->info->rgSignerInfo[i].EncryptedHash.cbData); if (msg_data->info->rgSignerInfo[i].EncryptedHash.pbData) { ret = CryptSignHashW(hash, keySpec, NULL, 0, msg_data->info->rgSignerInfo[i].EncryptedHash.pbData, &msg_data->info->rgSignerInfo[i].EncryptedHash.cbData); if (ret) CRYPT_ReverseBytes( &msg_data->info->rgSignerInfo[i].EncryptedHash); } else ret = FALSE; } } return ret;}
static BOOL CSignedMsgData_Update(CSignedMsgData *msg_data, const BYTE *pbData, DWORD cbData, BOOL fFinal, SignOrVerify flag){ BOOL ret = CSignedMsgData_UpdateHash(msg_data, pbData, cbData);
if (ret && fFinal) { ret = CSignedMsgData_UpdateAuthenticatedAttributes(msg_data, flag); if (ret && flag == Sign) ret = CSignedMsgData_Sign(msg_data); } return ret;}
typedef struct _CSignedEncodeMsg{ CryptMsgBase base; LPSTR innerOID; CRYPT_DATA_BLOB data; CSignedMsgData msg_data;} CSignedEncodeMsg;
static void CSignedEncodeMsg_Close(HCRYPTMSG hCryptMsg){ CSignedEncodeMsg *msg = hCryptMsg; DWORD i;
CryptMemFree(msg->innerOID); CryptMemFree(msg->data.pbData); CRYPT_FreeBlobArray(msg->msg_data.info->cCertEncoded, msg->msg_data.info->rgCertEncoded); CRYPT_FreeBlobArray(msg->msg_data.info->cCrlEncoded, msg->msg_data.info->rgCrlEncoded); for (i = 0; i < msg->msg_data.info->cSignerInfo; i++) CSignerInfo_Free(&msg->msg_data.info->rgSignerInfo[i]); CSignedMsgData_CloseHandles(&msg->msg_data); CryptMemFree(msg->msg_data.info->signerKeySpec); CryptMemFree(msg->msg_data.info->rgSignerInfo); CryptMemFree(msg->msg_data.info);}
static BOOL CSignedEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType, DWORD dwIndex, void *pvData, DWORD *pcbData){ CSignedEncodeMsg *msg = hCryptMsg; BOOL ret = FALSE;
switch (dwParamType) { case CMSG_CONTENT_PARAM: { CRYPT_CONTENT_INFO info;
ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0, NULL, &info.Content.cbData); if (ret) { info.Content.pbData = CryptMemAlloc(info.Content.cbData); if (info.Content.pbData) { ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0, info.Content.pbData, &info.Content.cbData); if (ret) { char oid_rsa_signed[] = szOID_RSA_signedData;
info.pszObjId = oid_rsa_signed; ret = CryptEncodeObjectEx(X509_ASN_ENCODING, PKCS_CONTENT_INFO, &info, 0, NULL, pvData, pcbData); } CryptMemFree(info.Content.pbData); } else ret = FALSE; } break; } case CMSG_BARE_CONTENT_PARAM: { CRYPT_SIGNED_INFO info; BOOL freeContent = FALSE;
info = *msg->msg_data.info; if (!msg->innerOID || !strcmp(msg->innerOID, szOID_RSA_data)) { char oid_rsa_data[] = szOID_RSA_data;
/* Quirk: OID is only encoded messages if an update has happened */ if (msg->base.state != MsgStateInit) info.content.pszObjId = oid_rsa_data; else info.content.pszObjId = NULL; if (msg->data.cbData) { CRYPT_DATA_BLOB blob = { msg->data.cbData, msg->data.pbData };
ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING, &blob, CRYPT_ENCODE_ALLOC_FLAG, NULL, &info.content.Content.pbData, &info.content.Content.cbData); freeContent = TRUE; } else { info.content.Content.cbData = 0; info.content.Content.pbData = NULL; ret = TRUE; } } else { info.content.pszObjId = msg->innerOID; info.content.Content.cbData = msg->data.cbData; info.content.Content.pbData = msg->data.pbData; ret = TRUE; } if (ret) { ret = CRYPT_AsnEncodeCMSSignedInfo(&info, pvData, pcbData); if (freeContent) LocalFree(info.content.Content.pbData); } break; } case CMSG_COMPUTED_HASH_PARAM: if (dwIndex >= msg->msg_data.cSignerHandle) SetLastError(CRYPT_E_INVALID_INDEX); else ret = CryptGetHashParam( msg->msg_data.signerHandles[dwIndex].contentHash, HP_HASHVAL, pvData, pcbData, 0); break; case CMSG_ENCODED_SIGNER: if (dwIndex >= msg->msg_data.info->cSignerInfo) SetLastError(CRYPT_E_INVALID_INDEX); else ret = CryptEncodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, CMS_SIGNER_INFO, &msg->msg_data.info->rgSignerInfo[dwIndex], 0, NULL, pvData, pcbData); break; case CMSG_VERSION_PARAM: ret = CRYPT_CopyParam(pvData, pcbData, &msg->msg_data.info->version, sizeof(msg->msg_data.info->version)); break; default: SetLastError(CRYPT_E_INVALID_MSG_TYPE); } return ret;}
static BOOL CSignedEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData, DWORD cbData, BOOL fFinal){ CSignedEncodeMsg *msg = hCryptMsg; BOOL ret = FALSE;
if (msg->base.state == MsgStateFinalized) SetLastError(CRYPT_E_MSG_ERROR); else if (msg->base.streamed || (msg->base.open_flags & CMSG_DETACHED_FLAG)) { ret = CSignedMsgData_Update(&msg->msg_data, pbData, cbData, fFinal, Sign); if (msg->base.streamed) FIXME("streamed partial stub\n"); msg->base.state = fFinal ? MsgStateFinalized : MsgStateUpdated; } else { if (!fFinal) SetLastError(CRYPT_E_MSG_ERROR); else { if (cbData) { msg->data.pbData = CryptMemAlloc(cbData); if (msg->data.pbData) { memcpy(msg->data.pbData, pbData, cbData); msg->data.cbData = cbData; ret = TRUE; } } else ret = TRUE; if (ret) ret = CSignedMsgData_Update(&msg->msg_data, pbData, cbData, fFinal, Sign); msg->base.state = MsgStateFinalized; } } return ret;}
static HCRYPTMSG CSignedEncodeMsg_Open(DWORD dwFlags, const void *pvMsgEncodeInfo, LPCSTR pszInnerContentObjID, PCMSG_STREAM_INFO pStreamInfo){ const CMSG_SIGNED_ENCODE_INFO_WITH_CMS *info = pvMsgEncodeInfo; DWORD i; CSignedEncodeMsg *msg;
if (info->cbSize != sizeof(CMSG_SIGNED_ENCODE_INFO) && info->cbSize != sizeof(CMSG_SIGNED_ENCODE_INFO_WITH_CMS)) { SetLastError(E_INVALIDARG); return NULL; } if (info->cbSize == sizeof(CMSG_SIGNED_ENCODE_INFO_WITH_CMS) && info->cAttrCertEncoded) { FIXME("CMSG_SIGNED_ENCODE_INFO with CMS fields unsupported\n"); return NULL; } for (i = 0; i < info->cSigners; i++) if (!CRYPT_IsValidSigner(&info->rgSigners[i])) return NULL; msg = CryptMemAlloc(sizeof(CSignedEncodeMsg)); if (msg) { BOOL ret = TRUE;
CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo, CSignedEncodeMsg_Close, CSignedEncodeMsg_GetParam, CSignedEncodeMsg_Update, CRYPT_DefaultMsgControl); if (pszInnerContentObjID) { msg->innerOID = CryptMemAlloc(strlen(pszInnerContentObjID) + 1); if (msg->innerOID) strcpy(msg->innerOID, pszInnerContentObjID); else ret = FALSE; } else msg->innerOID = NULL; msg->data.cbData = 0; msg->data.pbData = NULL; if (ret) msg->msg_data.info = CryptMemAlloc(sizeof(CRYPT_SIGNED_INFO)); else msg->msg_data.info = NULL; if (msg->msg_data.info) { memset(msg->msg_data.info, 0, sizeof(CRYPT_SIGNED_INFO)); msg->msg_data.info->version = CMSG_SIGNED_DATA_V1; } else ret = FALSE; if (ret) { if (info->cSigners) { msg->msg_data.info->rgSignerInfo = CryptMemAlloc(info->cSigners * sizeof(CMSG_CMS_SIGNER_INFO)); if (msg->msg_data.info->rgSignerInfo) { msg->msg_data.info->cSignerInfo = info->cSigners; memset(msg->msg_data.info->rgSignerInfo, 0, msg->msg_data.info->cSignerInfo * sizeof(CMSG_CMS_SIGNER_INFO)); ret = CSignedMsgData_AllocateHandles(&msg->msg_data); msg->msg_data.info->signerKeySpec = CryptMemAlloc(info->cSigners * sizeof(DWORD)); if (!msg->msg_data.info->signerKeySpec) ret = FALSE; for (i = 0; ret && i < msg->msg_data.info->cSignerInfo; i++) { if (info->rgSigners[i].SignerId.dwIdChoice == CERT_ID_KEY_IDENTIFIER) msg->msg_data.info->version = CMSG_SIGNED_DATA_V3; ret = CSignerInfo_Construct( &msg->msg_data.info->rgSignerInfo[i], &info->rgSigners[i]); if (ret) { ret = CSignedMsgData_ConstructSignerHandles( &msg->msg_data, i, &info->rgSigners[i].hCryptProv, &dwFlags); if (dwFlags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG) CryptReleaseContext(info->rgSigners[i].hCryptProv, 0); } msg->msg_data.info->signerKeySpec[i] = info->rgSigners[i].dwKeySpec; } } else ret = FALSE; } else { msg->msg_data.info->cSignerInfo = 0; msg->msg_data.signerHandles = NULL; msg->msg_data.cSignerHandle = 0; } } if (ret) ret = CRYPT_ConstructBlobArray(&msg->msg_data.info->cCertEncoded, &msg->msg_data.info->rgCertEncoded, info->cCertEncoded, info->rgCertEncoded); if (ret) ret = CRYPT_ConstructBlobArray(&msg->msg_data.info->cCrlEncoded, &msg->msg_data.info->rgCrlEncoded, info->cCrlEncoded, info->rgCrlEncoded); if (!ret) { CSignedEncodeMsg_Close(msg); CryptMemFree(msg); msg = NULL; } } return msg;}
typedef struct _CMSG_ENVELOPED_ENCODE_INFO_WITH_CMS{ DWORD cbSize; HCRYPTPROV_LEGACY hCryptProv; CRYPT_ALGORITHM_IDENTIFIER ContentEncryptionAlgorithm; void *pvEncryptionAuxInfo; DWORD cRecipients; PCERT_INFO *rgpRecipientCert; PCMSG_RECIPIENT_ENCODE_INFO rgCmsRecipients; DWORD cCertEncoded; PCERT_BLOB rgCertEncoded; DWORD cCrlEncoded; PCRL_BLOB rgCrlEncoded; DWORD cAttrCertEncoded; PCERT_BLOB rgAttrCertEncoded; DWORD cUnprotectedAttr; PCRYPT_ATTRIBUTE rgUnprotectedAttr;} CMSG_ENVELOPED_ENCODE_INFO_WITH_CMS;
typedef struct _CEnvelopedEncodeMsg{ CryptMsgBase base; CRYPT_ALGORITHM_IDENTIFIER algo; HCRYPTPROV prov; HCRYPTKEY key; DWORD cRecipientInfo; CMSG_KEY_TRANS_RECIPIENT_INFO *recipientInfo; CRYPT_DATA_BLOB data;} CEnvelopedEncodeMsg;
static BOOL CRYPT_ConstructAlgorithmId(CRYPT_ALGORITHM_IDENTIFIER *out, const CRYPT_ALGORITHM_IDENTIFIER *in){ out->pszObjId = CryptMemAlloc(strlen(in->pszObjId) + 1); if (out->pszObjId) { strcpy(out->pszObjId, in->pszObjId); return CRYPT_ConstructBlob(&out->Parameters, &in->Parameters); } else return FALSE;}
static BOOL CRYPT_ConstructBitBlob(CRYPT_BIT_BLOB *out, const CRYPT_BIT_BLOB *in){ out->cbData = in->cbData; out->cUnusedBits = in->cUnusedBits; if (out->cbData) { out->pbData = CryptMemAlloc(out->cbData); if (out->pbData) memcpy(out->pbData, in->pbData, out->cbData); else return FALSE; } else out->pbData = NULL; return TRUE;}
static BOOL CRYPT_GenKey(CMSG_CONTENT_ENCRYPT_INFO *info, ALG_ID algID){ static HCRYPTOIDFUNCSET set = NULL; PFN_CMSG_GEN_CONTENT_ENCRYPT_KEY genKeyFunc = NULL; HCRYPTOIDFUNCADDR hFunc; BOOL ret;
if (!set) set = CryptInitOIDFunctionSet(CMSG_OID_GEN_CONTENT_ENCRYPT_KEY_FUNC, 0); CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, info->ContentEncryptionAlgorithm.pszObjId, 0, (void **)&genKeyFunc, &hFunc); if (genKeyFunc) { ret = genKeyFunc(info, 0, NULL); CryptFreeOIDFunctionAddress(hFunc, 0); } else ret = CryptGenKey(info->hCryptProv, algID, CRYPT_EXPORTABLE, &info->hContentEncryptKey); return ret;}
static BOOL WINAPI CRYPT_ExportKeyTrans( PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo, PCMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO pKeyTransEncodeInfo, PCMSG_KEY_TRANS_ENCRYPT_INFO pKeyTransEncryptInfo, DWORD dwFlags, void *pvReserved){ CERT_PUBLIC_KEY_INFO keyInfo; HCRYPTKEY expKey; BOOL ret;
ret = CRYPT_ConstructAlgorithmId(&keyInfo.Algorithm, &pKeyTransEncodeInfo->KeyEncryptionAlgorithm); if (ret) ret = CRYPT_ConstructBitBlob(&keyInfo.PublicKey, &pKeyTransEncodeInfo->RecipientPublicKey); if (ret) ret = CryptImportPublicKeyInfo(pKeyTransEncodeInfo->hCryptProv, X509_ASN_ENCODING, &keyInfo, &expKey); if (ret) { DWORD size;
ret = CryptExportKey(pContentEncryptInfo->hContentEncryptKey, expKey, SIMPLEBLOB, 0, NULL, &size); if (ret) { BYTE *keyBlob;
keyBlob = CryptMemAlloc(size); if (keyBlob) { ret = CryptExportKey(pContentEncryptInfo->hContentEncryptKey, expKey, SIMPLEBLOB, 0, keyBlob, &size); if (ret) { DWORD head = sizeof(BLOBHEADER) + sizeof(ALG_ID);
pKeyTransEncryptInfo->EncryptedKey.pbData = CryptMemAlloc(size - head); if (pKeyTransEncryptInfo->EncryptedKey.pbData) { DWORD i, k = 0;
pKeyTransEncryptInfo->EncryptedKey.cbData = size - head; for (i = size - 1; i >= head; --i, ++k) pKeyTransEncryptInfo->EncryptedKey.pbData[k] = keyBlob[i]; } else ret = FALSE; } CryptMemFree(keyBlob); } else ret = FALSE; } CryptDestroyKey(expKey); }
CryptMemFree(keyInfo.PublicKey.pbData); CryptMemFree(keyInfo.Algorithm.pszObjId); CryptMemFree(keyInfo.Algorithm.Parameters.pbData); return ret;}
static BOOL CRYPT_ExportEncryptedKey(CMSG_CONTENT_ENCRYPT_INFO *info, DWORD i, CRYPT_DATA_BLOB *key){ static HCRYPTOIDFUNCSET set = NULL; PFN_CMSG_EXPORT_KEY_TRANS exportKeyFunc = NULL; HCRYPTOIDFUNCADDR hFunc = NULL; CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO *encodeInfo = info->rgCmsRecipients[i].u.pKeyTrans; CMSG_KEY_TRANS_ENCRYPT_INFO encryptInfo; BOOL ret;
memset(&encryptInfo, 0, sizeof(encryptInfo)); encryptInfo.cbSize = sizeof(encryptInfo); encryptInfo.dwRecipientIndex = i; ret = CRYPT_ConstructAlgorithmId(&encryptInfo.KeyEncryptionAlgorithm, &encodeInfo->KeyEncryptionAlgorithm);
if (!set) set = CryptInitOIDFunctionSet(CMSG_OID_EXPORT_KEY_TRANS_FUNC, 0); CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, encryptInfo.KeyEncryptionAlgorithm.pszObjId, 0, (void **)&exportKeyFunc, &hFunc); if (!exportKeyFunc) exportKeyFunc = CRYPT_ExportKeyTrans; if (ret) { ret = exportKeyFunc(info, encodeInfo, &encryptInfo, 0, NULL); if (ret) { key->cbData = encryptInfo.EncryptedKey.cbData; key->pbData = encryptInfo.EncryptedKey.pbData; } } if (hFunc) CryptFreeOIDFunctionAddress(hFunc, 0);
CryptMemFree(encryptInfo.KeyEncryptionAlgorithm.pszObjId); CryptMemFree(encryptInfo.KeyEncryptionAlgorithm.Parameters.pbData); return ret;}
static LPVOID WINAPI mem_alloc(size_t size){ return HeapAlloc(GetProcessHeap(), 0, size);}
static VOID WINAPI mem_free(LPVOID pv){ HeapFree(GetProcessHeap(), 0, pv);}
static BOOL CContentEncryptInfo_Construct(CMSG_CONTENT_ENCRYPT_INFO *info, const CMSG_ENVELOPED_ENCODE_INFO_WITH_CMS *in, HCRYPTPROV prov){ BOOL ret;
info->cbSize = sizeof(CMSG_CONTENT_ENCRYPT_INFO); info->hCryptProv = prov; ret = CRYPT_ConstructAlgorithmId(&info->ContentEncryptionAlgorithm, &in->ContentEncryptionAlgorithm); info->pvEncryptionAuxInfo = in->pvEncryptionAuxInfo; info->cRecipients = in->cRecipients; if (ret) { info->rgCmsRecipients = CryptMemAlloc(in->cRecipients * sizeof(CMSG_RECIPIENT_ENCODE_INFO)); if (info->rgCmsRecipients) { DWORD i;
for (i = 0; ret && i < in->cRecipients; ++i) { CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO *encodeInfo; CERT_INFO *cert = in->rgpRecipientCert[i];
info->rgCmsRecipients[i].dwRecipientChoice = CMSG_KEY_TRANS_RECIPIENT; encodeInfo = CryptMemAlloc(sizeof(*encodeInfo)); info->rgCmsRecipients[i].u.pKeyTrans = encodeInfo; if (encodeInfo) { encodeInfo->cbSize = sizeof(*encodeInfo); ret = CRYPT_ConstructAlgorithmId( &encodeInfo->KeyEncryptionAlgorithm, &cert->SubjectPublicKeyInfo.Algorithm); encodeInfo->pvKeyEncryptionAuxInfo = NULL; encodeInfo->hCryptProv = prov; if (ret) ret = CRYPT_ConstructBitBlob( &encodeInfo->RecipientPublicKey, &cert->SubjectPublicKeyInfo.PublicKey); if (ret) ret = CRYPT_ConstructBlob( &encodeInfo->RecipientId.u.IssuerSerialNumber.Issuer, &cert->Issuer); if (ret) ret = CRYPT_ConstructBlob( &encodeInfo->RecipientId.u.IssuerSerialNumber.SerialNumber, &cert->SerialNumber); } else ret = FALSE; } } else ret = FALSE; } info->pfnAlloc = mem_alloc; info->pfnFree = mem_free; return ret;}
static void CContentEncryptInfo_Free(CMSG_CONTENT_ENCRYPT_INFO *info){ CryptMemFree(info->ContentEncryptionAlgorithm.pszObjId); CryptMemFree(info->ContentEncryptionAlgorithm.Parameters.pbData); if (info->rgCmsRecipients) { DWORD i;
for (i = 0; i < info->cRecipients; ++i) { CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO *encodeInfo = info->rgCmsRecipients[i].u.pKeyTrans;
CryptMemFree(encodeInfo->KeyEncryptionAlgorithm.pszObjId); CryptMemFree(encodeInfo->KeyEncryptionAlgorithm.Parameters.pbData); CryptMemFree(encodeInfo->RecipientPublicKey.pbData); CryptMemFree( encodeInfo->RecipientId.u.IssuerSerialNumber.Issuer.pbData); CryptMemFree( encodeInfo->RecipientId.u.IssuerSerialNumber.SerialNumber.pbData); CryptMemFree(encodeInfo); } CryptMemFree(info->rgCmsRecipients); }}
static BOOL CRecipientInfo_Construct(CMSG_KEY_TRANS_RECIPIENT_INFO *info, const CERT_INFO *cert, CRYPT_DATA_BLOB *key){ BOOL ret;
info->dwVersion = CMSG_KEY_TRANS_PKCS_1_5_VERSION; info->RecipientId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER; ret = CRYPT_ConstructBlob(&info->RecipientId.u.IssuerSerialNumber.Issuer, &cert->Issuer); if (ret) ret = CRYPT_ConstructBlob( &info->RecipientId.u.IssuerSerialNumber.SerialNumber, &cert->SerialNumber); if (ret) ret = CRYPT_ConstructAlgorithmId(&info->KeyEncryptionAlgorithm, &cert->SubjectPublicKeyInfo.Algorithm); info->EncryptedKey.cbData = key->cbData; info->EncryptedKey.pbData = key->pbData; return ret;}
static void CRecipientInfo_Free(CMSG_KEY_TRANS_RECIPIENT_INFO *info){ CryptMemFree(info->RecipientId.u.IssuerSerialNumber.Issuer.pbData); CryptMemFree(info->RecipientId.u.IssuerSerialNumber.SerialNumber.pbData); CryptMemFree(info->KeyEncryptionAlgorithm.pszObjId); CryptMemFree(info->KeyEncryptionAlgorithm.Parameters.pbData); CryptMemFree(info->EncryptedKey.pbData);}
static void CEnvelopedEncodeMsg_Close(HCRYPTMSG hCryptMsg){ CEnvelopedEncodeMsg *msg = hCryptMsg;
CryptMemFree(msg->algo.pszObjId); CryptMemFree(msg->algo.Parameters.pbData); if (msg->base.open_flags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG) CryptReleaseContext(msg->prov, 0); CryptDestroyKey(msg->key); if (msg->recipientInfo) { DWORD i;
for (i = 0; i < msg->cRecipientInfo; ++i) CRecipientInfo_Free(&msg->recipientInfo[i]); CryptMemFree(msg->recipientInfo); } CryptMemFree(msg->data.pbData);}
static BOOL CEnvelopedEncodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType, DWORD dwIndex, void *pvData, DWORD *pcbData){ CEnvelopedEncodeMsg *msg = hCryptMsg; BOOL ret = FALSE;
switch (dwParamType) { case CMSG_BARE_CONTENT_PARAM: if (msg->base.streamed) SetLastError(E_INVALIDARG); else { char oid_rsa_data[] = szOID_RSA_data; CRYPT_ENVELOPED_DATA envelopedData = { CMSG_ENVELOPED_DATA_PKCS_1_5_VERSION, msg->cRecipientInfo, msg->recipientInfo, { oid_rsa_data, { msg->algo.pszObjId, { msg->algo.Parameters.cbData, msg->algo.Parameters.pbData } }, { msg->data.cbData, msg->data.pbData } } };
ret = CRYPT_AsnEncodePKCSEnvelopedData(&envelopedData, pvData, pcbData); } break; case CMSG_CONTENT_PARAM: { CRYPT_CONTENT_INFO info;
ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0, NULL, &info.Content.cbData); if (ret) { info.Content.pbData = CryptMemAlloc(info.Content.cbData); if (info.Content.pbData) { ret = CryptMsgGetParam(hCryptMsg, CMSG_BARE_CONTENT_PARAM, 0, info.Content.pbData, &info.Content.cbData); if (ret) { char oid_rsa_enveloped[] = szOID_RSA_envelopedData;
info.pszObjId = oid_rsa_enveloped; ret = CryptEncodeObjectEx(X509_ASN_ENCODING, PKCS_CONTENT_INFO, &info, 0, NULL, pvData, pcbData); } CryptMemFree(info.Content.pbData); } else ret = FALSE; } break; } default: SetLastError(CRYPT_E_INVALID_MSG_TYPE); } return ret;}
static BOOL CEnvelopedEncodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData, DWORD cbData, BOOL fFinal){ CEnvelopedEncodeMsg *msg = hCryptMsg; BOOL ret = FALSE;
if (msg->base.state == MsgStateFinalized) SetLastError(CRYPT_E_MSG_ERROR); else if (msg->base.streamed) { FIXME("streamed stub\n"); msg->base.state = fFinal ? MsgStateFinalized : MsgStateUpdated; ret = TRUE; } else { if (!fFinal) { if (msg->base.open_flags & CMSG_DETACHED_FLAG) SetLastError(E_INVALIDARG); else SetLastError(CRYPT_E_MSG_ERROR); } else { if (cbData) { DWORD dataLen = cbData;
msg->data.cbData = cbData; msg->data.pbData = CryptMemAlloc(cbData); if (msg->data.pbData) { memcpy(msg->data.pbData, pbData, cbData); ret = CryptEncrypt(msg->key, 0, TRUE, 0, msg->data.pbData, &dataLen, msg->data.cbData); msg->data.cbData = dataLen; if (dataLen > cbData) { msg->data.pbData = CryptMemRealloc(msg->data.pbData, dataLen); if (msg->data.pbData) { dataLen = cbData; ret = CryptEncrypt(msg->key, 0, TRUE, 0, msg->data.pbData, &dataLen, msg->data.cbData); } else ret = FALSE; } if (!ret) CryptMemFree(msg->data.pbData); } else ret = FALSE; if (!ret) { msg->data.cbData = 0; msg->data.pbData = NULL; } } else ret = TRUE; msg->base.state = MsgStateFinalized; } } return ret;}
static HCRYPTMSG CEnvelopedEncodeMsg_Open(DWORD dwFlags, const void *pvMsgEncodeInfo, LPCSTR pszInnerContentObjID, PCMSG_STREAM_INFO pStreamInfo){ CEnvelopedEncodeMsg *msg; const CMSG_ENVELOPED_ENCODE_INFO_WITH_CMS *info = pvMsgEncodeInfo; HCRYPTPROV prov; ALG_ID algID;
if (info->cbSize != sizeof(CMSG_ENVELOPED_ENCODE_INFO) && info->cbSize != sizeof(CMSG_ENVELOPED_ENCODE_INFO_WITH_CMS)) { SetLastError(E_INVALIDARG); return NULL; } if (info->cbSize == sizeof(CMSG_ENVELOPED_ENCODE_INFO_WITH_CMS)) FIXME("CMS fields unsupported\n"); if (!(algID = CertOIDToAlgId(info->ContentEncryptionAlgorithm.pszObjId))) { SetLastError(CRYPT_E_UNKNOWN_ALGO); return NULL; } if (info->cRecipients && !info->rgpRecipientCert) { SetLastError(E_INVALIDARG); return NULL; } if (info->hCryptProv) prov = info->hCryptProv; else { prov = I_CryptGetDefaultCryptProv(0); dwFlags &= ~CMSG_CRYPT_RELEASE_CONTEXT_FLAG; } msg = CryptMemAlloc(sizeof(CEnvelopedEncodeMsg)); if (msg) { CRYPT_DATA_BLOB encryptedKey = { 0, NULL }; CMSG_CONTENT_ENCRYPT_INFO encryptInfo; BOOL ret; DWORD i;
CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo, CEnvelopedEncodeMsg_Close, CEnvelopedEncodeMsg_GetParam, CEnvelopedEncodeMsg_Update, CRYPT_DefaultMsgControl); ret = CRYPT_ConstructAlgorithmId(&msg->algo, &info->ContentEncryptionAlgorithm); msg->prov = prov; msg->data.cbData = 0; msg->data.pbData = NULL; msg->cRecipientInfo = info->cRecipients; msg->recipientInfo = CryptMemAlloc(info->cRecipients * sizeof(CMSG_KEY_TRANS_RECIPIENT_INFO)); if (!msg->recipientInfo) ret = FALSE; memset(&encryptInfo, 0, sizeof(encryptInfo)); if (ret) { ret = CContentEncryptInfo_Construct(&encryptInfo, info, prov); if (ret) { ret = CRYPT_GenKey(&encryptInfo, algID); if (ret) msg->key = encryptInfo.hContentEncryptKey; } } for (i = 0; ret && i < msg->cRecipientInfo; ++i) { ret = CRYPT_ExportEncryptedKey(&encryptInfo, i, &encryptedKey); if (ret) ret = CRecipientInfo_Construct(&msg->recipientInfo[i], info->rgpRecipientCert[i], &encryptedKey); } CContentEncryptInfo_Free(&encryptInfo); if (!ret) { CryptMsgClose(msg); msg = NULL; } } if (!msg && (dwFlags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG)) CryptReleaseContext(prov, 0); return msg;}
HCRYPTMSG WINAPI CryptMsgOpenToEncode(DWORD dwMsgEncodingType, DWORD dwFlags, DWORD dwMsgType, const void *pvMsgEncodeInfo, LPSTR pszInnerContentObjID, PCMSG_STREAM_INFO pStreamInfo){ HCRYPTMSG msg = NULL;
TRACE("(%08x, %08x, %08x, %p, %s, %p)\n", dwMsgEncodingType, dwFlags, dwMsgType, pvMsgEncodeInfo, debugstr_a(pszInnerContentObjID), pStreamInfo);
if (GET_CMSG_ENCODING_TYPE(dwMsgEncodingType) != PKCS_7_ASN_ENCODING) { SetLastError(E_INVALIDARG); return NULL; } switch (dwMsgType) { case CMSG_DATA: msg = CDataEncodeMsg_Open(dwFlags, pvMsgEncodeInfo, pszInnerContentObjID, pStreamInfo); break; case CMSG_HASHED: msg = CHashEncodeMsg_Open(dwFlags, pvMsgEncodeInfo, pszInnerContentObjID, pStreamInfo); break; case CMSG_SIGNED: msg = CSignedEncodeMsg_Open(dwFlags, pvMsgEncodeInfo, pszInnerContentObjID, pStreamInfo); break; case CMSG_ENVELOPED: msg = CEnvelopedEncodeMsg_Open(dwFlags, pvMsgEncodeInfo, pszInnerContentObjID, pStreamInfo); break; case CMSG_SIGNED_AND_ENVELOPED: case CMSG_ENCRYPTED: /* defined but invalid, fall through */ default: SetLastError(CRYPT_E_INVALID_MSG_TYPE); } return msg;}
typedef struct _CEnvelopedDecodeMsg{ CRYPT_ENVELOPED_DATA *data; HCRYPTPROV crypt_prov; CRYPT_DATA_BLOB content; BOOL decrypted;} CEnvelopedDecodeMsg;
typedef struct _CDecodeMsg{ CryptMsgBase base; DWORD type; HCRYPTPROV crypt_prov; union { HCRYPTHASH hash; CSignedMsgData signed_data; CEnvelopedDecodeMsg enveloped_data; } u; CRYPT_DATA_BLOB msg_data; CRYPT_DATA_BLOB detached_data; CONTEXT_PROPERTY_LIST *properties;} CDecodeMsg;
static void CDecodeMsg_Close(HCRYPTMSG hCryptMsg){ CDecodeMsg *msg = hCryptMsg;
if (msg->crypt_prov && msg->base.open_flags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG) CryptReleaseContext(msg->crypt_prov, 0); switch (msg->type) { case CMSG_HASHED: if (msg->u.hash) CryptDestroyHash(msg->u.hash); break; case CMSG_ENVELOPED: if (msg->u.enveloped_data.crypt_prov) CryptReleaseContext(msg->u.enveloped_data.crypt_prov, 0); LocalFree(msg->u.enveloped_data.data); CryptMemFree(msg->u.enveloped_data.content.pbData); break; case CMSG_SIGNED: if (msg->u.signed_data.info) { LocalFree(msg->u.signed_data.info); CSignedMsgData_CloseHandles(&msg->u.signed_data); } break; } CryptMemFree(msg->msg_data.pbData); CryptMemFree(msg->detached_data.pbData); ContextPropertyList_Free(msg->properties);}
static BOOL CDecodeMsg_CopyData(CRYPT_DATA_BLOB *blob, const BYTE *pbData, DWORD cbData){ BOOL ret = TRUE;
if (cbData) { if (blob->cbData) blob->pbData = CryptMemRealloc(blob->pbData, blob->cbData + cbData); else blob->pbData = CryptMemAlloc(cbData); if (blob->pbData) { memcpy(blob->pbData + blob->cbData, pbData, cbData); blob->cbData += cbData; } else ret = FALSE; } return ret;}
static BOOL CDecodeMsg_DecodeDataContent(CDecodeMsg *msg, const CRYPT_DER_BLOB *blob){ BOOL ret; CRYPT_DATA_BLOB *data; DWORD size;
ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING, blob->pbData, blob->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &data, &size); if (ret) { ret = ContextPropertyList_SetProperty(msg->properties, CMSG_CONTENT_PARAM, data->pbData, data->cbData); LocalFree(data); } return ret;}
static void CDecodeMsg_SaveAlgorithmID(CDecodeMsg *msg, DWORD param, const CRYPT_ALGORITHM_IDENTIFIER *id){ static const BYTE nullParams[] = { ASN_NULL, 0 }; CRYPT_ALGORITHM_IDENTIFIER *copy; DWORD len = sizeof(CRYPT_ALGORITHM_IDENTIFIER);
/* Linearize algorithm id */ len += strlen(id->pszObjId) + 1; len += id->Parameters.cbData; copy = CryptMemAlloc(len); if (copy) { copy->pszObjId = (LPSTR)((BYTE *)copy + sizeof(CRYPT_ALGORITHM_IDENTIFIER)); strcpy(copy->pszObjId, id->pszObjId); copy->Parameters.pbData = (BYTE *)copy->pszObjId + strlen(id->pszObjId) + 1; /* Trick: omit NULL parameters */ if (id->Parameters.cbData == sizeof(nullParams) && !memcmp(id->Parameters.pbData, nullParams, sizeof(nullParams))) { copy->Parameters.cbData = 0; len -= sizeof(nullParams); } else copy->Parameters.cbData = id->Parameters.cbData; if (copy->Parameters.cbData) memcpy(copy->Parameters.pbData, id->Parameters.pbData, id->Parameters.cbData); ContextPropertyList_SetProperty(msg->properties, param, (BYTE *)copy, len); CryptMemFree(copy); }}
static inline void CRYPT_FixUpAlgorithmID(CRYPT_ALGORITHM_IDENTIFIER *id){ id->pszObjId = (LPSTR)((BYTE *)id + sizeof(CRYPT_ALGORITHM_IDENTIFIER)); id->Parameters.pbData = (BYTE *)id->pszObjId + strlen(id->pszObjId) + 1;}
static BOOL CDecodeMsg_DecodeHashedContent(CDecodeMsg *msg, const CRYPT_DER_BLOB *blob){ BOOL ret; CRYPT_DIGESTED_DATA *digestedData; DWORD size;
ret = CRYPT_AsnDecodePKCSDigestedData(blob->pbData, blob->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, (CRYPT_DIGESTED_DATA *)&digestedData, &size); if (ret) { ContextPropertyList_SetProperty(msg->properties, CMSG_VERSION_PARAM, (const BYTE *)&digestedData->version, sizeof(digestedData->version)); CDecodeMsg_SaveAlgorithmID(msg, CMSG_HASH_ALGORITHM_PARAM, &digestedData->DigestAlgorithm); ContextPropertyList_SetProperty(msg->properties, CMSG_INNER_CONTENT_TYPE_PARAM, (const BYTE *)digestedData->ContentInfo.pszObjId, digestedData->ContentInfo.pszObjId ? strlen(digestedData->ContentInfo.pszObjId) + 1 : 0); if (!(msg->base.open_flags & CMSG_DETACHED_FLAG)) { if (digestedData->ContentInfo.Content.cbData) CDecodeMsg_DecodeDataContent(msg, &digestedData->ContentInfo.Content); else ContextPropertyList_SetProperty(msg->properties, CMSG_CONTENT_PARAM, NULL, 0); } ContextPropertyList_SetProperty(msg->properties, CMSG_HASH_DATA_PARAM, digestedData->hash.pbData, digestedData->hash.cbData); LocalFree(digestedData); } return ret;}
static BOOL CDecodeMsg_DecodeEnvelopedContent(CDecodeMsg *msg, const CRYPT_DER_BLOB *blob){ BOOL ret; CRYPT_ENVELOPED_DATA *envelopedData; DWORD size;
ret = CRYPT_AsnDecodePKCSEnvelopedData(blob->pbData, blob->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, (CRYPT_ENVELOPED_DATA *)&envelopedData, &size); if (ret) msg->u.enveloped_data.data = envelopedData; return ret;}
static BOOL CDecodeMsg_DecodeSignedContent(CDecodeMsg *msg, const CRYPT_DER_BLOB *blob){ BOOL ret; CRYPT_SIGNED_INFO *signedInfo; DWORD size;
ret = CRYPT_AsnDecodeCMSSignedInfo(blob->pbData, blob->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, (CRYPT_SIGNED_INFO *)&signedInfo, &size); if (ret) msg->u.signed_data.info = signedInfo; return ret;}
/* Decodes the content in blob as the type given, and updates the value * (type, parameters, etc.) of msg based on what blob contains. * It doesn't just use msg's type, to allow a recursive call from an implicitly * typed message once the outer content info has been decoded. */static BOOL CDecodeMsg_DecodeContent(CDecodeMsg *msg, const CRYPT_DER_BLOB *blob, DWORD type){ BOOL ret;
switch (type) { case CMSG_DATA: if ((ret = CDecodeMsg_DecodeDataContent(msg, blob))) msg->type = CMSG_DATA; break; case CMSG_HASHED: if ((ret = CDecodeMsg_DecodeHashedContent(msg, blob))) msg->type = CMSG_HASHED; break; case CMSG_ENVELOPED: if ((ret = CDecodeMsg_DecodeEnvelopedContent(msg, blob))) msg->type = CMSG_ENVELOPED; break; case CMSG_SIGNED: if ((ret = CDecodeMsg_DecodeSignedContent(msg, blob))) msg->type = CMSG_SIGNED; break; default: { CRYPT_CONTENT_INFO *info; DWORD size;
ret = CryptDecodeObjectEx(X509_ASN_ENCODING, PKCS_CONTENT_INFO, msg->msg_data.pbData, msg->msg_data.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size); if (ret) { if (!strcmp(info->pszObjId, szOID_RSA_data)) ret = CDecodeMsg_DecodeContent(msg, &info->Content, CMSG_DATA); else if (!strcmp(info->pszObjId, szOID_RSA_digestedData)) ret = CDecodeMsg_DecodeContent(msg, &info->Content, CMSG_HASHED); else if (!strcmp(info->pszObjId, szOID_RSA_envelopedData)) ret = CDecodeMsg_DecodeContent(msg, &info->Content, CMSG_ENVELOPED); else if (!strcmp(info->pszObjId, szOID_RSA_signedData)) ret = CDecodeMsg_DecodeContent(msg, &info->Content, CMSG_SIGNED); else { SetLastError(CRYPT_E_INVALID_MSG_TYPE); ret = FALSE; } LocalFree(info); } } } return ret;}
static BOOL CDecodeMsg_FinalizeHashedContent(CDecodeMsg *msg, CRYPT_DER_BLOB *blob){ CRYPT_ALGORITHM_IDENTIFIER *hashAlgoID = NULL; DWORD size = 0; ALG_ID algID = 0; BOOL ret;
CryptMsgGetParam(msg, CMSG_HASH_ALGORITHM_PARAM, 0, NULL, &size); hashAlgoID = CryptMemAlloc(size); ret = CryptMsgGetParam(msg, CMSG_HASH_ALGORITHM_PARAM, 0, hashAlgoID, &size); if (ret) algID = CertOIDToAlgId(hashAlgoID->pszObjId);
if (!msg->crypt_prov) { msg->crypt_prov = I_CryptGetDefaultCryptProv(algID); if (msg->crypt_prov) msg->base.open_flags &= ~CMSG_CRYPT_RELEASE_CONTEXT_FLAG; }
ret = CryptCreateHash(msg->crypt_prov, algID, 0, 0, &msg->u.hash); if (ret) { CRYPT_DATA_BLOB content;
if (msg->base.open_flags & CMSG_DETACHED_FLAG) { /* Unlike for non-detached messages, the data were never stored as * the content param, but were saved in msg->detached_data instead. */ content.pbData = msg->detached_data.pbData; content.cbData = msg->detached_data.cbData; } else ret = ContextPropertyList_FindProperty(msg->properties, CMSG_CONTENT_PARAM, &content); if (ret) ret = CryptHashData(msg->u.hash, content.pbData, content.cbData, 0); } CryptMemFree(hashAlgoID); return ret;}
static BOOL CDecodeMsg_FinalizeEnvelopedContent(CDecodeMsg *msg, CRYPT_DER_BLOB *blob){ CRYPT_DATA_BLOB *content;
if (msg->base.open_flags & CMSG_DETACHED_FLAG) content = &msg->detached_data; else content = &msg->u.enveloped_data.data->encryptedContentInfo.encryptedContent;
return CRYPT_ConstructBlob(&msg->u.enveloped_data.content, content);}
static BOOL CDecodeMsg_FinalizeSignedContent(CDecodeMsg *msg, CRYPT_DER_BLOB *blob){ BOOL ret; DWORD i, size;
ret = CSignedMsgData_AllocateHandles(&msg->u.signed_data); for (i = 0; ret && i < msg->u.signed_data.info->cSignerInfo; i++) ret = CSignedMsgData_ConstructSignerHandles(&msg->u.signed_data, i, &msg->crypt_prov, &msg->base.open_flags); if (ret) { CRYPT_DATA_BLOB *content;
/* Now that we have all the content, update the hash handles with * it. If the message is a detached message, the content is stored * in msg->detached_data rather than in the signed message's * content. */ if (msg->base.open_flags & CMSG_DETACHED_FLAG) content = &msg->detached_data; else content = &msg->u.signed_data.info->content.Content; if (content->cbData) { /* If the message is not detached, have to decode the message's * content if the type is szOID_RSA_data. */ if (!(msg->base.open_flags & CMSG_DETACHED_FLAG) && !strcmp(msg->u.signed_data.info->content.pszObjId, szOID_RSA_data)) { CRYPT_DATA_BLOB *rsa_blob;
ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING, content->pbData, content->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &rsa_blob, &size); if (ret) { ret = CSignedMsgData_Update(&msg->u.signed_data, rsa_blob->pbData, rsa_blob->cbData, TRUE, Verify); LocalFree(rsa_blob); } } else ret = CSignedMsgData_Update(&msg->u.signed_data, content->pbData, content->cbData, TRUE, Verify); } } return ret;}
static BOOL CDecodeMsg_FinalizeContent(CDecodeMsg *msg, CRYPT_DER_BLOB *blob){ BOOL ret = FALSE;
switch (msg->type) { case CMSG_HASHED: ret = CDecodeMsg_FinalizeHashedContent(msg, blob); break; case CMSG_ENVELOPED: ret = CDecodeMsg_FinalizeEnvelopedContent(msg, blob); break; case CMSG_SIGNED: ret = CDecodeMsg_FinalizeSignedContent(msg, blob); break; default: ret = TRUE; } return ret;}
static BOOL CDecodeMsg_Update(HCRYPTMSG hCryptMsg, const BYTE *pbData, DWORD cbData, BOOL fFinal){ CDecodeMsg *msg = hCryptMsg; BOOL ret = FALSE;
TRACE("(%p, %p, %d, %d)\n", hCryptMsg, pbData, cbData, fFinal);
if (msg->base.state == MsgStateFinalized) SetLastError(CRYPT_E_MSG_ERROR); else if (msg->base.streamed) { FIXME("(%p, %p, %d, %d): streamed update stub\n", hCryptMsg, pbData, cbData, fFinal); switch (msg->base.state) { case MsgStateInit: ret = CDecodeMsg_CopyData(&msg->msg_data, pbData, cbData); if (fFinal) { if (msg->base.open_flags & CMSG_DETACHED_FLAG) msg->base.state = MsgStateDataFinalized; else msg->base.state = MsgStateFinalized; } else msg->base.state = MsgStateUpdated; break; case MsgStateUpdated: ret = CDecodeMsg_CopyData(&msg->msg_data, pbData, cbData); if (fFinal) { if (msg->base.open_flags & CMSG_DETACHED_FLAG) msg->base.state = MsgStateDataFinalized; else msg->base.state = MsgStateFinalized; } break; case MsgStateDataFinalized: ret = CDecodeMsg_CopyData(&msg->detached_data, pbData, cbData); if (fFinal) msg->base.state = MsgStateFinalized; break; default: SetLastError(CRYPT_E_MSG_ERROR); break; } } else { if (!fFinal) SetLastError(CRYPT_E_MSG_ERROR); else { switch (msg->base.state) { case MsgStateInit: ret = CDecodeMsg_CopyData(&msg->msg_data, pbData, cbData); if (msg->base.open_flags & CMSG_DETACHED_FLAG) msg->base.state = MsgStateDataFinalized; else msg->base.state = MsgStateFinalized; break; case MsgStateDataFinalized: ret = CDecodeMsg_CopyData(&msg->detached_data, pbData, cbData); msg->base.state = MsgStateFinalized; break; default: SetLastError(CRYPT_E_MSG_ERROR); } } } if (ret && fFinal && ((msg->base.open_flags & CMSG_DETACHED_FLAG && msg->base.state == MsgStateDataFinalized) || (!(msg->base.open_flags & CMSG_DETACHED_FLAG) && msg->base.state == MsgStateFinalized))) ret = CDecodeMsg_DecodeContent(msg, &msg->msg_data, msg->type); if (ret && msg->base.state == MsgStateFinalized) ret = CDecodeMsg_FinalizeContent(msg, &msg->msg_data); return ret;}
static BOOL CDecodeHashMsg_GetParam(CDecodeMsg *msg, DWORD dwParamType, DWORD dwIndex, void *pvData, DWORD *pcbData){ BOOL ret = FALSE;
switch (dwParamType) { case CMSG_TYPE_PARAM: ret = CRYPT_CopyParam(pvData, pcbData, &msg->type, sizeof(msg->type)); break; case CMSG_HASH_ALGORITHM_PARAM: { CRYPT_DATA_BLOB blob;
ret = ContextPropertyList_FindProperty(msg->properties, dwParamType, &blob); if (ret) { ret = CRYPT_CopyParam(pvData, pcbData, blob.pbData, blob.cbData); if (ret && pvData) CRYPT_FixUpAlgorithmID(pvData); } else SetLastError(CRYPT_E_INVALID_MSG_TYPE); break; } case CMSG_COMPUTED_HASH_PARAM: ret = CryptGetHashParam(msg->u.hash, HP_HASHVAL, pvData, pcbData, 0); break; default: { CRYPT_DATA_BLOB blob;
ret = ContextPropertyList_FindProperty(msg->properties, dwParamType, &blob); if (ret) ret = CRYPT_CopyParam(pvData, pcbData, blob.pbData, blob.cbData); else SetLastError(CRYPT_E_INVALID_MSG_TYPE); } } return ret;}
/* nextData is an in/out parameter - on input it's the memory location in * which a copy of in's data should be made, and on output it's the memory * location immediately after out's copy of in's data. */static inline void CRYPT_CopyBlob(CRYPT_DATA_BLOB *out, const CRYPT_DATA_BLOB *in, LPBYTE *nextData){ out->cbData = in->cbData; if (in->cbData) { out->pbData = *nextData; memcpy(out->pbData, in->pbData, in->cbData); *nextData += in->cbData; }}
static inline void CRYPT_CopyAlgorithmId(CRYPT_ALGORITHM_IDENTIFIER *out, const CRYPT_ALGORITHM_IDENTIFIER *in, LPBYTE *nextData){ if (in->pszObjId) { out->pszObjId = (LPSTR)*nextData; strcpy(out->pszObjId, in->pszObjId); *nextData += strlen(out->pszObjId) + 1; } CRYPT_CopyBlob(&out->Parameters, &in->Parameters, nextData);}
static inline void CRYPT_CopyAttributes(CRYPT_ATTRIBUTES *out, const CRYPT_ATTRIBUTES *in, LPBYTE *nextData){ out->cAttr = in->cAttr; if (in->cAttr) { DWORD i;
*nextData = POINTER_ALIGN_DWORD_PTR(*nextData); out->rgAttr = (CRYPT_ATTRIBUTE *)*nextData; *nextData += in->cAttr * sizeof(CRYPT_ATTRIBUTE); for (i = 0; i < in->cAttr; i++) { if (in->rgAttr[i].pszObjId) { out->rgAttr[i].pszObjId = (LPSTR)*nextData; strcpy(out->rgAttr[i].pszObjId, in->rgAttr[i].pszObjId); *nextData += strlen(in->rgAttr[i].pszObjId) + 1; } if (in->rgAttr[i].cValue) { DWORD j;
out->rgAttr[i].cValue = in->rgAttr[i].cValue; *nextData = POINTER_ALIGN_DWORD_PTR(*nextData); out->rgAttr[i].rgValue = (PCRYPT_DATA_BLOB)*nextData; *nextData += in->rgAttr[i].cValue * sizeof(CRYPT_DATA_BLOB); for (j = 0; j < in->rgAttr[i].cValue; j++) CRYPT_CopyBlob(&out->rgAttr[i].rgValue[j], &in->rgAttr[i].rgValue[j], nextData); } } }}
static DWORD CRYPT_SizeOfAttributes(const CRYPT_ATTRIBUTES *attr){ DWORD size = attr->cAttr * sizeof(CRYPT_ATTRIBUTE), i, j;
for (i = 0; i < attr->cAttr; i++) { if (attr->rgAttr[i].pszObjId) size += strlen(attr->rgAttr[i].pszObjId) + 1; /* align pointer */ size = ALIGN_DWORD_PTR(size); size += attr->rgAttr[i].cValue * sizeof(CRYPT_DATA_BLOB); for (j = 0; j < attr->rgAttr[i].cValue; j++) size += attr->rgAttr[i].rgValue[j].cbData; } /* align pointer again to be conservative */ size = ALIGN_DWORD_PTR(size); return size;}
static DWORD CRYPT_SizeOfKeyIdAsIssuerAndSerial(const CRYPT_DATA_BLOB *keyId){ static char oid_key_rdn[] = szOID_KEYID_RDN; DWORD size = 0; CERT_RDN_ATTR attr; CERT_RDN rdn = { 1, &attr }; CERT_NAME_INFO name = { 1, &rdn };
attr.pszObjId = oid_key_rdn; attr.dwValueType = CERT_RDN_OCTET_STRING; attr.Value.cbData = keyId->cbData; attr.Value.pbData = keyId->pbData; if (CryptEncodeObject(X509_ASN_ENCODING, X509_NAME, &name, NULL, &size)) size++; /* Only include size of special zero serial number on success */ return size;}
static BOOL CRYPT_CopyKeyIdAsIssuerAndSerial(CERT_NAME_BLOB *issuer, CRYPT_INTEGER_BLOB *serialNumber, const CRYPT_DATA_BLOB *keyId, DWORD encodedLen, LPBYTE *nextData){ static char oid_key_rdn[] = szOID_KEYID_RDN; CERT_RDN_ATTR attr; CERT_RDN rdn = { 1, &attr }; CERT_NAME_INFO name = { 1, &rdn }; BOOL ret;
/* Encode special zero serial number */ serialNumber->cbData = 1; serialNumber->pbData = *nextData; **nextData = 0; (*nextData)++; /* Encode issuer */ issuer->pbData = *nextData; attr.pszObjId = oid_key_rdn; attr.dwValueType = CERT_RDN_OCTET_STRING; attr.Value.cbData = keyId->cbData; attr.Value.pbData = keyId->pbData; ret = CryptEncodeObject(X509_ASN_ENCODING, X509_NAME, &name, *nextData, &encodedLen); if (ret) { *nextData += encodedLen; issuer->cbData = encodedLen; } return ret;}
static BOOL CRYPT_CopySignerInfo(void *pvData, DWORD *pcbData, const CMSG_CMS_SIGNER_INFO *in){ DWORD size = sizeof(CMSG_SIGNER_INFO), rdnSize = 0; BOOL ret;
TRACE("(%p, %d, %p)\n", pvData, pvData ? *pcbData : 0, in);
if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER) { size += in->SignerId.u.IssuerSerialNumber.Issuer.cbData; size += in->SignerId.u.IssuerSerialNumber.SerialNumber.cbData; } else { rdnSize = CRYPT_SizeOfKeyIdAsIssuerAndSerial(&in->SignerId.u.KeyId); size += rdnSize; } if (in->HashAlgorithm.pszObjId) size += strlen(in->HashAlgorithm.pszObjId) + 1; size += in->HashAlgorithm.Parameters.cbData; if (in->HashEncryptionAlgorithm.pszObjId) size += strlen(in->HashEncryptionAlgorithm.pszObjId) + 1; size += in->HashEncryptionAlgorithm.Parameters.cbData; size += in->EncryptedHash.cbData; /* align pointer */ size = ALIGN_DWORD_PTR(size); size += CRYPT_SizeOfAttributes(&in->AuthAttrs); size += CRYPT_SizeOfAttributes(&in->UnauthAttrs); if (!pvData) { ret = TRUE; } else if (*pcbData < size) { SetLastError(ERROR_MORE_DATA); ret = FALSE; } else { LPBYTE nextData = (BYTE *)pvData + sizeof(CMSG_SIGNER_INFO); CMSG_SIGNER_INFO *out = pvData;
ret = TRUE; out->dwVersion = in->dwVersion; if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER) { CRYPT_CopyBlob(&out->Issuer, &in->SignerId.u.IssuerSerialNumber.Issuer, &nextData); CRYPT_CopyBlob(&out->SerialNumber, &in->SignerId.u.IssuerSerialNumber.SerialNumber, &nextData); } else ret = CRYPT_CopyKeyIdAsIssuerAndSerial(&out->Issuer, &out->SerialNumber, &in->SignerId.u.KeyId, rdnSize, &nextData); if (ret) { CRYPT_CopyAlgorithmId(&out->HashAlgorithm, &in->HashAlgorithm, &nextData); CRYPT_CopyAlgorithmId(&out->HashEncryptionAlgorithm, &in->HashEncryptionAlgorithm, &nextData); CRYPT_CopyBlob(&out->EncryptedHash, &in->EncryptedHash, &nextData); nextData = POINTER_ALIGN_DWORD_PTR(nextData); CRYPT_CopyAttributes(&out->AuthAttrs, &in->AuthAttrs, &nextData); CRYPT_CopyAttributes(&out->UnauthAttrs, &in->UnauthAttrs, &nextData); } } *pcbData = size; TRACE("returning %d\n", ret); return ret;}
static BOOL CRYPT_CopyCMSSignerInfo(void *pvData, DWORD *pcbData, const CMSG_CMS_SIGNER_INFO *in){ DWORD size = sizeof(CMSG_CMS_SIGNER_INFO); BOOL ret;
TRACE("(%p, %d, %p)\n", pvData, pvData ? *pcbData : 0, in);
if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER) { size += in->SignerId.u.IssuerSerialNumber.Issuer.cbData; size += in->SignerId.u.IssuerSerialNumber.SerialNumber.cbData; } else size += in->SignerId.u.KeyId.cbData; if (in->HashAlgorithm.pszObjId) size += strlen(in->HashAlgorithm.pszObjId) + 1; size += in->HashAlgorithm.Parameters.cbData; if (in->HashEncryptionAlgorithm.pszObjId) size += strlen(in->HashEncryptionAlgorithm.pszObjId) + 1; size += in->HashEncryptionAlgorithm.Parameters.cbData; size += in->EncryptedHash.cbData; /* align pointer */ size = ALIGN_DWORD_PTR(size); size += CRYPT_SizeOfAttributes(&in->AuthAttrs); size += CRYPT_SizeOfAttributes(&in->UnauthAttrs); if (!pvData) { *pcbData = size; ret = TRUE; } else if (*pcbData < size) { *pcbData = size; SetLastError(ERROR_MORE_DATA); ret = FALSE; } else { LPBYTE nextData = (BYTE *)pvData + sizeof(CMSG_CMS_SIGNER_INFO); CMSG_CMS_SIGNER_INFO *out = pvData;
out->dwVersion = in->dwVersion; out->SignerId.dwIdChoice = in->SignerId.dwIdChoice; if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER) { CRYPT_CopyBlob(&out->SignerId.u.IssuerSerialNumber.Issuer, &in->SignerId.u.IssuerSerialNumber.Issuer, &nextData); CRYPT_CopyBlob(&out->SignerId.u.IssuerSerialNumber.SerialNumber, &in->SignerId.u.IssuerSerialNumber.SerialNumber, &nextData); } else CRYPT_CopyBlob(&out->SignerId.u.KeyId, &in->SignerId.u.KeyId, &nextData); CRYPT_CopyAlgorithmId(&out->HashAlgorithm, &in->HashAlgorithm, &nextData); CRYPT_CopyAlgorithmId(&out->HashEncryptionAlgorithm, &in->HashEncryptionAlgorithm, &nextData); CRYPT_CopyBlob(&out->EncryptedHash, &in->EncryptedHash, &nextData); nextData = POINTER_ALIGN_DWORD_PTR(nextData); CRYPT_CopyAttributes(&out->AuthAttrs, &in->AuthAttrs, &nextData); CRYPT_CopyAttributes(&out->UnauthAttrs, &in->UnauthAttrs, &nextData); ret = TRUE; } TRACE("returning %d\n", ret); return ret;}
static BOOL CRYPT_CopySignerCertInfo(void *pvData, DWORD *pcbData, const CMSG_CMS_SIGNER_INFO *in){ DWORD size = sizeof(CERT_INFO), rdnSize = 0; BOOL ret;
TRACE("(%p, %d, %p)\n", pvData, pvData ? *pcbData : 0, in);
if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER) { size += in->SignerId.u.IssuerSerialNumber.Issuer.cbData; size += in->SignerId.u.IssuerSerialNumber.SerialNumber.cbData; } else { rdnSize = CRYPT_SizeOfKeyIdAsIssuerAndSerial(&in->SignerId.u.KeyId); size += rdnSize; } if (!pvData) { *pcbData = size; ret = TRUE; } else if (*pcbData < size) { *pcbData = size; SetLastError(ERROR_MORE_DATA); ret = FALSE; } else { LPBYTE nextData = (BYTE *)pvData + sizeof(CERT_INFO); CERT_INFO *out = pvData;
memset(out, 0, sizeof(CERT_INFO)); if (in->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER) { CRYPT_CopyBlob(&out->Issuer, &in->SignerId.u.IssuerSerialNumber.Issuer, &nextData); CRYPT_CopyBlob(&out->SerialNumber, &in->SignerId.u.IssuerSerialNumber.SerialNumber, &nextData); ret = TRUE; } else ret = CRYPT_CopyKeyIdAsIssuerAndSerial(&out->Issuer, &out->SerialNumber, &in->SignerId.u.KeyId, rdnSize, &nextData); } TRACE("returning %d\n", ret); return ret;}
static BOOL CRYPT_CopyRecipientInfo(void *pvData, DWORD *pcbData, const CERT_ISSUER_SERIAL_NUMBER *in){ DWORD size = sizeof(CERT_INFO); BOOL ret;
TRACE("(%p, %d, %p)\n", pvData, pvData ? *pcbData : 0, in);
size += in->SerialNumber.cbData; size += in->Issuer.cbData; if (!pvData) { *pcbData = size; ret = TRUE; } else if (*pcbData < size) { *pcbData = size; SetLastError(ERROR_MORE_DATA); ret = FALSE; } else { LPBYTE nextData = (BYTE *)pvData + sizeof(CERT_INFO); CERT_INFO *out = pvData;
CRYPT_CopyBlob(&out->SerialNumber, &in->SerialNumber, &nextData); CRYPT_CopyBlob(&out->Issuer, &in->Issuer, &nextData); ret = TRUE; } TRACE("returning %d\n", ret); return ret;}
static BOOL CDecodeEnvelopedMsg_GetParam(CDecodeMsg *msg, DWORD dwParamType, DWORD dwIndex, void *pvData, DWORD *pcbData){ BOOL ret = FALSE;
switch (dwParamType) { case CMSG_TYPE_PARAM: ret = CRYPT_CopyParam(pvData, pcbData, &msg->type, sizeof(msg->type)); break; case CMSG_CONTENT_PARAM: if (msg->u.enveloped_data.data) ret = CRYPT_CopyParam(pvData, pcbData, msg->u.enveloped_data.content.pbData, msg->u.enveloped_data.content.cbData); else SetLastError(CRYPT_E_INVALID_MSG_TYPE); break; case CMSG_RECIPIENT_COUNT_PARAM: if (msg->u.enveloped_data.data) ret = CRYPT_CopyParam(pvData, pcbData, &msg->u.enveloped_data.data->cRecipientInfo, sizeof(DWORD)); else SetLastError(CRYPT_E_INVALID_MSG_TYPE); break; case CMSG_RECIPIENT_INFO_PARAM: if (msg->u.enveloped_data.data) { if (dwIndex < msg->u.enveloped_data.data->cRecipientInfo) { PCMSG_KEY_TRANS_RECIPIENT_INFO recipientInfo = &msg->u.enveloped_data.data->rgRecipientInfo[dwIndex];
ret = CRYPT_CopyRecipientInfo(pvData, pcbData, &recipientInfo->RecipientId.u.IssuerSerialNumber); } else SetLastError(CRYPT_E_INVALID_INDEX); } else SetLastError(CRYPT_E_INVALID_MSG_TYPE); break; default: FIXME("unimplemented for %d\n", dwParamType); SetLastError(CRYPT_E_INVALID_MSG_TYPE); } return ret;}
static BOOL CDecodeSignedMsg_GetParam(CDecodeMsg *msg, DWORD dwParamType, DWORD dwIndex, void *pvData, DWORD *pcbData){ BOOL ret = FALSE;
switch (dwParamType) { case CMSG_TYPE_PARAM: ret = CRYPT_CopyParam(pvData, pcbData, &msg->type, sizeof(msg->type)); break; case CMSG_CONTENT_PARAM: if (msg->u.signed_data.info) { if (!strcmp(msg->u.signed_data.info->content.pszObjId, szOID_RSA_data)) { CRYPT_DATA_BLOB *blob; DWORD size;
ret = CryptDecodeObjectEx(X509_ASN_ENCODING, X509_OCTET_STRING, msg->u.signed_data.info->content.Content.pbData, msg->u.signed_data.info->content.Content.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &blob, &size); if (ret) { ret = CRYPT_CopyParam(pvData, pcbData, blob->pbData, blob->cbData); LocalFree(blob); } } else ret = CRYPT_CopyParam(pvData, pcbData, msg->u.signed_data.info->content.Content.pbData, msg->u.signed_data.info->content.Content.cbData); } else SetLastError(CRYPT_E_INVALID_MSG_TYPE); break; case CMSG_INNER_CONTENT_TYPE_PARAM: if (msg->u.signed_data.info) ret = CRYPT_CopyParam(pvData, pcbData, msg->u.signed_data.info->content.pszObjId, strlen(msg->u.signed_data.info->content.pszObjId) + 1); else SetLastError(CRYPT_E_INVALID_MSG_TYPE); break; case CMSG_SIGNER_COUNT_PARAM: if (msg->u.signed_data.info) ret = CRYPT_CopyParam(pvData, pcbData, &msg->u.signed_data.info->cSignerInfo, sizeof(DWORD)); else SetLastError(CRYPT_E_INVALID_MSG_TYPE); break; case CMSG_SIGNER_INFO_PARAM: if (msg->u.signed_data.info) { if (dwIndex >= msg->u.signed_data.info->cSignerInfo) SetLastError(CRYPT_E_INVALID_INDEX); else ret = CRYPT_CopySignerInfo(pvData, pcbData, &msg->u.signed_data.info->rgSignerInfo[dwIndex]); } else SetLastError(CRYPT_E_INVALID_MSG_TYPE); break; case CMSG_SIGNER_CERT_INFO_PARAM: if (msg->u.signed_data.info) { if (dwIndex >= msg->u.signed_data.info->cSignerInfo) SetLastError(CRYPT_E_INVALID_INDEX); else ret = CRYPT_CopySignerCertInfo(pvData, pcbData, &msg->u.signed_data.info->rgSignerInfo[dwIndex]); } else SetLastError(CRYPT_E_INVALID_MSG_TYPE); break; case CMSG_CERT_COUNT_PARAM: if (msg->u.signed_data.info) ret = CRYPT_CopyParam(pvData, pcbData, &msg->u.signed_data.info->cCertEncoded, sizeof(DWORD)); else SetLastError(CRYPT_E_INVALID_MSG_TYPE); break; case CMSG_CERT_PARAM: if (msg->u.signed_data.info) { if (dwIndex >= msg->u.signed_data.info->cCertEncoded) SetLastError(CRYPT_E_INVALID_INDEX); else ret = CRYPT_CopyParam(pvData, pcbData, msg->u.signed_data.info->rgCertEncoded[dwIndex].pbData, msg->u.signed_data.info->rgCertEncoded[dwIndex].cbData); } else SetLastError(CRYPT_E_INVALID_MSG_TYPE); break; case CMSG_CRL_COUNT_PARAM: if (msg->u.signed_data.info) ret = CRYPT_CopyParam(pvData, pcbData, &msg->u.signed_data.info->cCrlEncoded, sizeof(DWORD)); else SetLastError(CRYPT_E_INVALID_MSG_TYPE); break; case CMSG_CRL_PARAM: if (msg->u.signed_data.info) { if (dwIndex >= msg->u.signed_data.info->cCrlEncoded) SetLastError(CRYPT_E_INVALID_INDEX); else ret = CRYPT_CopyParam(pvData, pcbData, msg->u.signed_data.info->rgCrlEncoded[dwIndex].pbData, msg->u.signed_data.info->rgCrlEncoded[dwIndex].cbData); } else SetLastError(CRYPT_E_INVALID_MSG_TYPE); break; case CMSG_COMPUTED_HASH_PARAM: if (msg->u.signed_data.info) { if (dwIndex >= msg->u.signed_data.cSignerHandle) SetLastError(CRYPT_E_INVALID_INDEX); else ret = CryptGetHashParam( msg->u.signed_data.signerHandles[dwIndex].contentHash, HP_HASHVAL, pvData, pcbData, 0); } else SetLastError(CRYPT_E_INVALID_MSG_TYPE); break; case CMSG_ENCODED_SIGNER: if (msg->u.signed_data.info) { if (dwIndex >= msg->u.signed_data.info->cSignerInfo) SetLastError(CRYPT_E_INVALID_INDEX); else ret = CryptEncodeObjectEx( X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, CMS_SIGNER_INFO, &msg->u.signed_data.info->rgSignerInfo[dwIndex], 0, NULL, pvData, pcbData); } else SetLastError(CRYPT_E_INVALID_MSG_TYPE); break; case CMSG_ATTR_CERT_COUNT_PARAM: if (msg->u.signed_data.info) { DWORD attrCertCount = 0;
ret = CRYPT_CopyParam(pvData, pcbData, &attrCertCount, sizeof(DWORD)); } else SetLastError(CRYPT_E_INVALID_MSG_TYPE); break; case CMSG_ATTR_CERT_PARAM: if (msg->u.signed_data.info) SetLastError(CRYPT_E_INVALID_INDEX); else SetLastError(CRYPT_E_INVALID_MSG_TYPE); break; case CMSG_CMS_SIGNER_INFO_PARAM: if (msg->u.signed_data.info) { if (dwIndex >= msg->u.signed_data.info->cSignerInfo) SetLastError(CRYPT_E_INVALID_INDEX); else ret = CRYPT_CopyCMSSignerInfo(pvData, pcbData, &msg->u.signed_data.info->rgSignerInfo[dwIndex]); } else SetLastError(CRYPT_E_INVALID_MSG_TYPE); break; default: FIXME("unimplemented for %d\n", dwParamType); SetLastError(CRYPT_E_INVALID_MSG_TYPE); } return ret;}
static BOOL CDecodeMsg_GetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType, DWORD dwIndex, void *pvData, DWORD *pcbData){ CDecodeMsg *msg = hCryptMsg; BOOL ret = FALSE;
switch (msg->type) { case CMSG_HASHED: ret = CDecodeHashMsg_GetParam(msg, dwParamType, dwIndex, pvData, pcbData); break; case CMSG_ENVELOPED: ret = CDecodeEnvelopedMsg_GetParam(msg, dwParamType, dwIndex, pvData, pcbData); break; case CMSG_SIGNED: ret = CDecodeSignedMsg_GetParam(msg, dwParamType, dwIndex, pvData, pcbData); break; default: switch (dwParamType) { case CMSG_TYPE_PARAM: ret = CRYPT_CopyParam(pvData, pcbData, &msg->type, sizeof(msg->type)); break; default: { CRYPT_DATA_BLOB blob;
ret = ContextPropertyList_FindProperty(msg->properties, dwParamType, &blob); if (ret) ret = CRYPT_CopyParam(pvData, pcbData, blob.pbData, blob.cbData); else SetLastError(CRYPT_E_INVALID_MSG_TYPE); } } } return ret;}
static BOOL CDecodeHashMsg_VerifyHash(CDecodeMsg *msg){ BOOL ret; CRYPT_DATA_BLOB hashBlob;
ret = ContextPropertyList_FindProperty(msg->properties, CMSG_HASH_DATA_PARAM, &hashBlob); if (ret) { DWORD computedHashSize = 0;
ret = CDecodeHashMsg_GetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, NULL, &computedHashSize); if (hashBlob.cbData == computedHashSize) { LPBYTE computedHash = CryptMemAlloc(computedHashSize);
if (computedHash) { ret = CDecodeHashMsg_GetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0, computedHash, &computedHashSize); if (ret) { if (memcmp(hashBlob.pbData, computedHash, hashBlob.cbData)) { SetLastError(CRYPT_E_HASH_VALUE); ret = FALSE; } } CryptMemFree(computedHash); } else { SetLastError(ERROR_OUTOFMEMORY); ret = FALSE; } } else { SetLastError(CRYPT_E_HASH_VALUE); ret = FALSE; } } return ret;}
static BOOL CDecodeSignedMsg_VerifySignatureWithKey(CDecodeMsg *msg, HCRYPTPROV prov, DWORD signerIndex, PCERT_PUBLIC_KEY_INFO keyInfo){ HCRYPTKEY key; BOOL ret;
if (!prov) prov = msg->crypt_prov; ret = CryptImportPublicKeyInfo(prov, X509_ASN_ENCODING, keyInfo, &key); if (ret) { HCRYPTHASH hash; CRYPT_HASH_BLOB reversedHash;
if (msg->u.signed_data.info->rgSignerInfo[signerIndex].AuthAttrs.cAttr) hash = msg->u.signed_data.signerHandles[signerIndex].authAttrHash; else hash = msg->u.signed_data.signerHandles[signerIndex].contentHash; ret = CRYPT_ConstructBlob(&reversedHash, &msg->u.signed_data.info->rgSignerInfo[signerIndex].EncryptedHash); if (ret) { CRYPT_ReverseBytes(&reversedHash); ret = CryptVerifySignatureW(hash, reversedHash.pbData, reversedHash.cbData, key, NULL, 0); CryptMemFree(reversedHash.pbData); } CryptDestroyKey(key); } return ret;}
static BOOL CDecodeSignedMsg_VerifySignature(CDecodeMsg *msg, PCERT_INFO info){ BOOL ret = FALSE; DWORD i;
if (!msg->u.signed_data.signerHandles) { SetLastError(NTE_BAD_SIGNATURE); return FALSE; } for (i = 0; !ret && i < msg->u.signed_data.info->cSignerInfo; i++) { PCMSG_CMS_SIGNER_INFO signerInfo = &msg->u.signed_data.info->rgSignerInfo[i];
if (signerInfo->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER) { ret = CertCompareCertificateName(X509_ASN_ENCODING, &signerInfo->SignerId.u.IssuerSerialNumber.Issuer, &info->Issuer); if (ret) { ret = CertCompareIntegerBlob( &signerInfo->SignerId.u.IssuerSerialNumber.SerialNumber, &info->SerialNumber); if (ret) break; } } else { FIXME("signer %d: unimplemented for key id\n", i); } } if (ret) ret = CDecodeSignedMsg_VerifySignatureWithKey(msg, 0, i, &info->SubjectPublicKeyInfo); else SetLastError(CRYPT_E_SIGNER_NOT_FOUND);
return ret;}
static BOOL CDecodeSignedMsg_VerifySignatureEx(CDecodeMsg *msg, PCMSG_CTRL_VERIFY_SIGNATURE_EX_PARA para){ BOOL ret = FALSE;
if (para->cbSize != sizeof(CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA)) SetLastError(ERROR_INVALID_PARAMETER); else if (para->dwSignerIndex >= msg->u.signed_data.info->cSignerInfo) SetLastError(CRYPT_E_SIGNER_NOT_FOUND); else if (!msg->u.signed_data.signerHandles) SetLastError(NTE_BAD_SIGNATURE); else { switch (para->dwSignerType) { case CMSG_VERIFY_SIGNER_PUBKEY: ret = CDecodeSignedMsg_VerifySignatureWithKey(msg, para->hCryptProv, para->dwSignerIndex, para->pvSigner); break; case CMSG_VERIFY_SIGNER_CERT: { PCCERT_CONTEXT cert = para->pvSigner;
ret = CDecodeSignedMsg_VerifySignatureWithKey(msg, para->hCryptProv, para->dwSignerIndex, &cert->pCertInfo->SubjectPublicKeyInfo); break; } default: FIXME("unimplemented for signer type %d\n", para->dwSignerType); SetLastError(CRYPT_E_SIGNER_NOT_FOUND); } } return ret;}
static BOOL WINAPI CRYPT_ImportKeyTrans( PCRYPT_ALGORITHM_IDENTIFIER pContentEncryptionAlgorithm, PCMSG_CTRL_KEY_TRANS_DECRYPT_PARA pKeyTransDecryptPara, DWORD dwFlags, void *pvReserved, HCRYPTKEY *phContentEncryptKey){ BOOL ret; HCRYPTKEY key;
ret = CryptGetUserKey(pKeyTransDecryptPara->hCryptProv, pKeyTransDecryptPara->dwKeySpec ? pKeyTransDecryptPara->dwKeySpec : AT_KEYEXCHANGE, &key); if (ret) { CMSG_KEY_TRANS_RECIPIENT_INFO *info = &pKeyTransDecryptPara->pKeyTrans[pKeyTransDecryptPara->dwRecipientIndex]; CRYPT_DATA_BLOB *encryptedKey = &info->EncryptedKey; DWORD size = encryptedKey->cbData + sizeof(BLOBHEADER) + sizeof(ALG_ID); BYTE *keyBlob = CryptMemAlloc(size);
if (keyBlob) { DWORD i, k = size - 1; BLOBHEADER *blobHeader = (BLOBHEADER *)keyBlob; ALG_ID *algID = (ALG_ID *)(keyBlob + sizeof(BLOBHEADER));
blobHeader->bType = SIMPLEBLOB; blobHeader->bVersion = CUR_BLOB_VERSION; blobHeader->reserved = 0; blobHeader->aiKeyAlg = CertOIDToAlgId( pContentEncryptionAlgorithm->pszObjId); *algID = CertOIDToAlgId(info->KeyEncryptionAlgorithm.pszObjId); for (i = 0; i < encryptedKey->cbData; ++i, --k) keyBlob[k] = encryptedKey->pbData[i];
ret = CryptImportKey(pKeyTransDecryptPara->hCryptProv, keyBlob, size, key, 0, phContentEncryptKey); CryptMemFree(keyBlob); } else ret = FALSE; CryptDestroyKey(key); } return ret;}
static BOOL CRYPT_ImportEncryptedKey(PCRYPT_ALGORITHM_IDENTIFIER contEncrAlg, PCMSG_CTRL_DECRYPT_PARA para, PCMSG_KEY_TRANS_RECIPIENT_INFO info, HCRYPTKEY *key){ static HCRYPTOIDFUNCSET set = NULL; PFN_CMSG_IMPORT_KEY_TRANS importKeyFunc = NULL; HCRYPTOIDFUNCADDR hFunc = NULL; CMSG_CTRL_KEY_TRANS_DECRYPT_PARA decryptPara; BOOL ret;
memset(&decryptPara, 0, sizeof(decryptPara)); decryptPara.cbSize = sizeof(decryptPara); decryptPara.hCryptProv = para->hCryptProv; decryptPara.dwKeySpec = para->dwKeySpec; decryptPara.pKeyTrans = info; decryptPara.dwRecipientIndex = para->dwRecipientIndex;
if (!set) set = CryptInitOIDFunctionSet(CMSG_OID_IMPORT_KEY_TRANS_FUNC, 0); CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, contEncrAlg->pszObjId, 0, (void **)&importKeyFunc, &hFunc); if (!importKeyFunc) importKeyFunc = CRYPT_ImportKeyTrans; ret = importKeyFunc(contEncrAlg, &decryptPara, 0, NULL, key); if (hFunc) CryptFreeOIDFunctionAddress(hFunc, 0); return ret;}
static BOOL CDecodeEnvelopedMsg_CrtlDecrypt(CDecodeMsg *msg, PCMSG_CTRL_DECRYPT_PARA para){ BOOL ret = FALSE; CEnvelopedDecodeMsg *enveloped_data = &msg->u.enveloped_data; CRYPT_ENVELOPED_DATA *data = enveloped_data->data;
if (para->cbSize != sizeof(CMSG_CTRL_DECRYPT_PARA)) SetLastError(E_INVALIDARG); else if (!data) SetLastError(CRYPT_E_INVALID_MSG_TYPE); else if (para->dwRecipientIndex >= data->cRecipientInfo) SetLastError(CRYPT_E_INVALID_INDEX); else if (enveloped_data->decrypted) SetLastError(CRYPT_E_ALREADY_DECRYPTED); else if (!para->hCryptProv) SetLastError(ERROR_INVALID_PARAMETER); else if (enveloped_data->content.cbData) { HCRYPTKEY key;
ret = CRYPT_ImportEncryptedKey( &data->encryptedContentInfo.contentEncryptionAlgorithm, para, data->rgRecipientInfo, &key); if (ret) { ret = CryptDecrypt(key, 0, TRUE, 0, enveloped_data->content.pbData, &enveloped_data->content.cbData); CryptDestroyKey(key); } } else ret = TRUE; if (ret) enveloped_data->decrypted = TRUE; return ret;}
static BOOL CDecodeMsg_Control(HCRYPTMSG hCryptMsg, DWORD dwFlags, DWORD dwCtrlType, const void *pvCtrlPara){ CDecodeMsg *msg = hCryptMsg; BOOL ret = FALSE;
switch (dwCtrlType) { case CMSG_CTRL_VERIFY_SIGNATURE: switch (msg->type) { case CMSG_SIGNED: ret = CDecodeSignedMsg_VerifySignature(msg, (PCERT_INFO)pvCtrlPara); break; default: SetLastError(CRYPT_E_INVALID_MSG_TYPE); } break; case CMSG_CTRL_DECRYPT: switch (msg->type) { case CMSG_ENVELOPED: ret = CDecodeEnvelopedMsg_CrtlDecrypt(msg, (PCMSG_CTRL_DECRYPT_PARA)pvCtrlPara); if (ret && (dwFlags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG)) msg->u.enveloped_data.crypt_prov = ((PCMSG_CTRL_DECRYPT_PARA)pvCtrlPara)->hCryptProv; break; default: SetLastError(CRYPT_E_INVALID_MSG_TYPE); } break; case CMSG_CTRL_VERIFY_HASH: switch (msg->type) { case CMSG_HASHED: ret = CDecodeHashMsg_VerifyHash(msg); break; default: SetLastError(CRYPT_E_INVALID_MSG_TYPE); } break; case CMSG_CTRL_VERIFY_SIGNATURE_EX: switch (msg->type) { case CMSG_SIGNED: ret = CDecodeSignedMsg_VerifySignatureEx(msg, (PCMSG_CTRL_VERIFY_SIGNATURE_EX_PARA)pvCtrlPara); break; default: SetLastError(CRYPT_E_INVALID_MSG_TYPE); } break; default: SetLastError(CRYPT_E_CONTROL_TYPE); } return ret;}
HCRYPTMSG WINAPI CryptMsgOpenToDecode(DWORD dwMsgEncodingType, DWORD dwFlags, DWORD dwMsgType, HCRYPTPROV_LEGACY hCryptProv, PCERT_INFO pRecipientInfo, PCMSG_STREAM_INFO pStreamInfo){ CDecodeMsg *msg;
TRACE("(%08x, %08x, %08x, %08lx, %p, %p)\n", dwMsgEncodingType, dwFlags, dwMsgType, hCryptProv, pRecipientInfo, pStreamInfo);
if (GET_CMSG_ENCODING_TYPE(dwMsgEncodingType) != PKCS_7_ASN_ENCODING) { SetLastError(E_INVALIDARG); return NULL; } msg = CryptMemAlloc(sizeof(CDecodeMsg)); if (msg) { CryptMsgBase_Init((CryptMsgBase *)msg, dwFlags, pStreamInfo, CDecodeMsg_Close, CDecodeMsg_GetParam, CDecodeMsg_Update, CDecodeMsg_Control); msg->type = dwMsgType; msg->crypt_prov = hCryptProv; memset(&msg->u, 0, sizeof(msg->u)); msg->msg_data.cbData = 0; msg->msg_data.pbData = NULL; msg->detached_data.cbData = 0; msg->detached_data.pbData = NULL; msg->properties = ContextPropertyList_Create(); } return msg;}
HCRYPTMSG WINAPI CryptMsgDuplicate(HCRYPTMSG hCryptMsg){ TRACE("(%p)\n", hCryptMsg);
if (hCryptMsg) { CryptMsgBase *msg = hCryptMsg;
InterlockedIncrement(&msg->ref); } return hCryptMsg;}
BOOL WINAPI CryptMsgClose(HCRYPTMSG hCryptMsg){ TRACE("(%p)\n", hCryptMsg);
if (hCryptMsg) { CryptMsgBase *msg = hCryptMsg;
if (InterlockedDecrement(&msg->ref) == 0) { TRACE("freeing %p\n", msg); if (msg->close) msg->close(msg); CryptMemFree(msg); } } return TRUE;}
BOOL WINAPI CryptMsgUpdate(HCRYPTMSG hCryptMsg, const BYTE *pbData, DWORD cbData, BOOL fFinal){ CryptMsgBase *msg = hCryptMsg;
TRACE("(%p, %p, %d, %d)\n", hCryptMsg, pbData, cbData, fFinal);
return msg->update(hCryptMsg, pbData, cbData, fFinal);}
BOOL WINAPI CryptMsgGetParam(HCRYPTMSG hCryptMsg, DWORD dwParamType, DWORD dwIndex, void *pvData, DWORD *pcbData){ CryptMsgBase *msg = hCryptMsg;
TRACE("(%p, %d, %d, %p, %p)\n", hCryptMsg, dwParamType, dwIndex, pvData, pcbData); return msg->get_param(hCryptMsg, dwParamType, dwIndex, pvData, pcbData);}
BOOL WINAPI CryptMsgControl(HCRYPTMSG hCryptMsg, DWORD dwFlags, DWORD dwCtrlType, const void *pvCtrlPara){ CryptMsgBase *msg = hCryptMsg;
TRACE("(%p, %08x, %d, %p)\n", hCryptMsg, dwFlags, dwCtrlType, pvCtrlPara); return msg->control(hCryptMsg, dwFlags, dwCtrlType, pvCtrlPara);}
static CERT_INFO *CRYPT_GetSignerCertInfoFromMsg(HCRYPTMSG msg, DWORD dwSignerIndex){ CERT_INFO *certInfo = NULL; DWORD size;
if (CryptMsgGetParam(msg, CMSG_SIGNER_CERT_INFO_PARAM, dwSignerIndex, NULL, &size)) { certInfo = CryptMemAlloc(size); if (certInfo) { if (!CryptMsgGetParam(msg, CMSG_SIGNER_CERT_INFO_PARAM, dwSignerIndex, certInfo, &size)) { CryptMemFree(certInfo); certInfo = NULL; } } } return certInfo;}
BOOL WINAPI CryptMsgGetAndVerifySigner(HCRYPTMSG hCryptMsg, DWORD cSignerStore, HCERTSTORE *rghSignerStore, DWORD dwFlags, PCCERT_CONTEXT *ppSigner, DWORD *pdwSignerIndex){ HCERTSTORE store; DWORD i, signerIndex = 0; PCCERT_CONTEXT signerCert = NULL; BOOL ret = FALSE;
TRACE("(%p, %d, %p, %08x, %p, %p)\n", hCryptMsg, cSignerStore, rghSignerStore, dwFlags, ppSigner, pdwSignerIndex);
/* Clear output parameters */ if (ppSigner) *ppSigner = NULL; if (pdwSignerIndex && !(dwFlags & CMSG_USE_SIGNER_INDEX_FLAG)) *pdwSignerIndex = 0;
/* Create store to search for signer certificates */ store = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0, CERT_STORE_CREATE_NEW_FLAG, NULL); if (!(dwFlags & CMSG_TRUSTED_SIGNER_FLAG)) { HCERTSTORE msgStore = CertOpenStore(CERT_STORE_PROV_MSG, 0, 0, 0, hCryptMsg);
CertAddStoreToCollection(store, msgStore, 0, 0); CertCloseStore(msgStore, 0); } for (i = 0; i < cSignerStore; i++) CertAddStoreToCollection(store, rghSignerStore[i], 0, 0);
/* Find signer cert */ if (dwFlags & CMSG_USE_SIGNER_INDEX_FLAG) { CERT_INFO *signer = CRYPT_GetSignerCertInfoFromMsg(hCryptMsg, *pdwSignerIndex);
if (signer) { signerIndex = *pdwSignerIndex; signerCert = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, CERT_FIND_SUBJECT_CERT, signer, NULL); CryptMemFree(signer); } } else { DWORD count, size = sizeof(count);
if (CryptMsgGetParam(hCryptMsg, CMSG_SIGNER_COUNT_PARAM, 0, &count, &size)) { for (i = 0; !signerCert && i < count; i++) { CERT_INFO *signer = CRYPT_GetSignerCertInfoFromMsg(hCryptMsg, i);
if (signer) { signerCert = CertFindCertificateInStore(store, X509_ASN_ENCODING, 0, CERT_FIND_SUBJECT_CERT, signer, NULL); if (signerCert) signerIndex = i; CryptMemFree(signer); } } } if (!signerCert) SetLastError(CRYPT_E_NO_TRUSTED_SIGNER); } if (signerCert) { if (!(dwFlags & CMSG_SIGNER_ONLY_FLAG)) ret = CryptMsgControl(hCryptMsg, 0, CMSG_CTRL_VERIFY_SIGNATURE, signerCert->pCertInfo); else ret = TRUE; if (ret) { if (ppSigner) *ppSigner = CertDuplicateCertificateContext(signerCert); if (pdwSignerIndex) *pdwSignerIndex = signerIndex; } CertFreeCertificateContext(signerCert); }
CertCloseStore(store, 0); return ret;}
BOOL WINAPI CryptMsgVerifyCountersignatureEncoded(HCRYPTPROV_LEGACY hCryptProv, DWORD dwEncodingType, BYTE *pbSignerInfo, DWORD cbSignerInfo, PBYTE pbSignerInfoCountersignature, DWORD cbSignerInfoCountersignature, CERT_INFO *pciCountersigner){ FIXME("(%08lx, %08x, %p, %d, %p, %d, %p): stub\n", hCryptProv, dwEncodingType, pbSignerInfo, cbSignerInfo, pbSignerInfoCountersignature, cbSignerInfoCountersignature, pciCountersigner); return FALSE;}
BOOL WINAPI CryptMsgVerifyCountersignatureEncodedEx(HCRYPTPROV_LEGACY hCryptProv, DWORD dwEncodingType, PBYTE pbSignerInfo, DWORD cbSignerInfo, PBYTE pbSignerInfoCountersignature, DWORD cbSignerInfoCountersignature, DWORD dwSignerType, void *pvSigner, DWORD dwFlags, void *pvReserved){ FIXME("(%08lx, %08x, %p, %d, %p, %d, %d, %p, %08x, %p): stub\n", hCryptProv, dwEncodingType, pbSignerInfo, cbSignerInfo, pbSignerInfoCountersignature, cbSignerInfoCountersignature, dwSignerType, pvSigner, dwFlags, pvReserved); return FALSE;}
BOOL WINAPI CryptMsgEncodeAndSignCTL(DWORD dwMsgEncodingType, PCTL_INFO pCtlInfo, PCMSG_SIGNED_ENCODE_INFO pSignInfo, DWORD dwFlags, BYTE *pbEncoded, DWORD *pcbEncoded){ BOOL ret; BYTE *pbCtlContent; DWORD cbCtlContent;
TRACE("(%08x, %p, %p, %08x, %p, %p)\n", dwMsgEncodingType, pCtlInfo, pSignInfo, dwFlags, pbEncoded, pcbEncoded);
if (dwFlags) { FIXME("unimplemented for flags %08x\n", dwFlags); return FALSE; } if ((ret = CryptEncodeObjectEx(dwMsgEncodingType, PKCS_CTL, pCtlInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL, &pbCtlContent, &cbCtlContent))) { ret = CryptMsgSignCTL(dwMsgEncodingType, pbCtlContent, cbCtlContent, pSignInfo, dwFlags, pbEncoded, pcbEncoded); LocalFree(pbCtlContent); } return ret;}
BOOL WINAPI CryptMsgSignCTL(DWORD dwMsgEncodingType, BYTE *pbCtlContent, DWORD cbCtlContent, PCMSG_SIGNED_ENCODE_INFO pSignInfo, DWORD dwFlags, BYTE *pbEncoded, DWORD *pcbEncoded){ static char oid_ctl[] = szOID_CTL; BOOL ret; HCRYPTMSG msg;
TRACE("(%08x, %p, %d, %p, %08x, %p, %p)\n", dwMsgEncodingType, pbCtlContent, cbCtlContent, pSignInfo, dwFlags, pbEncoded, pcbEncoded);
if (dwFlags) { FIXME("unimplemented for flags %08x\n", dwFlags); return FALSE; } msg = CryptMsgOpenToEncode(dwMsgEncodingType, 0, CMSG_SIGNED, pSignInfo, oid_ctl, NULL); if (msg) { ret = CryptMsgUpdate(msg, pbCtlContent, cbCtlContent, TRUE); if (ret) ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, pbEncoded, pcbEncoded); CryptMsgClose(msg); } else ret = FALSE; return ret;}