| /* |
| * Copyright 2008 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 <stdarg.h> |
| #include "windef.h" |
| #include "winbase.h" |
| #include "wincrypt.h" |
| #include "mssip.h" |
| #define COBJMACROS |
| #include "objbase.h" |
| #include "wine/debug.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(msisip); |
| |
| BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) |
| { |
| TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved); |
| |
| switch (fdwReason) |
| { |
| case DLL_WINE_PREATTACH: |
| return FALSE; /* prefer native version */ |
| case DLL_PROCESS_ATTACH: |
| DisableThreadLibraryCalls(hinstDLL); |
| break; |
| case DLL_PROCESS_DETACH: |
| break; |
| default: |
| break; |
| } |
| |
| return TRUE; |
| } |
| |
| static GUID mySubject = { 0x000c10f1, 0x0000, 0x0000, |
| { 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 }}; |
| |
| /*********************************************************************** |
| * DllRegisterServer (MSISIP.@) |
| */ |
| HRESULT WINAPI DllRegisterServer(void) |
| { |
| static WCHAR msisip[] = { 'M','S','I','S','I','P','.','D','L','L',0 }; |
| static WCHAR getSignedDataMsg[] = { 'M','s','i','S','I','P','G','e','t', |
| 'S','i','g','n','e','d','D','a','t','a','M','s','g',0 }; |
| static WCHAR putSignedDataMsg[] = { 'M','s','i','S','I','P','P','u','t', |
| 'S','i','g','n','e','d','D','a','t','a','M','s','g',0 }; |
| static WCHAR createIndirectData[] = { 'M','s','i','S','I','P', |
| 'C','r','e','a','t','e','I','n','d','i','r','e','c','t','D','a','t','a', |
| 0 }; |
| static WCHAR verifyIndirectData[] = { 'M','s','i','S','I','P', |
| 'V','e','r','i','f','y','I','n','d','i','r','e','c','t','D','a','t','a', |
| 0 }; |
| static WCHAR removeSignedDataMsg[] = { 'M','s','i','S','I','P','R','e','m', |
| 'o','v','e','S','i','g','n','e','d','D','a','t','a','M','s','g', 0 }; |
| static WCHAR isMyTypeOfFile[] = { 'M','s','i','S','I','P', |
| 'I','s','M','y','T','y','p','e','O','f','F','i','l','e',0 }; |
| |
| SIP_ADD_NEWPROVIDER prov; |
| |
| memset(&prov, 0, sizeof(prov)); |
| prov.cbStruct = sizeof(prov); |
| prov.pwszDLLFileName = msisip; |
| prov.pgSubject = &mySubject; |
| prov.pwszGetFuncName = getSignedDataMsg; |
| prov.pwszPutFuncName = putSignedDataMsg; |
| prov.pwszCreateFuncName = createIndirectData; |
| prov.pwszVerifyFuncName = verifyIndirectData; |
| prov.pwszRemoveFuncName = removeSignedDataMsg; |
| prov.pwszIsFunctionNameFmt2 = isMyTypeOfFile; |
| return CryptSIPAddProvider(&prov) ? S_OK : S_FALSE; |
| } |
| |
| /*********************************************************************** |
| * DllUnregisterServer (MSISIP.@) |
| */ |
| HRESULT WINAPI DllUnregisterServer(void) |
| { |
| CryptSIPRemoveProvider(&mySubject); |
| return S_OK; |
| } |
| |
| /*********************************************************************** |
| * MsiSIPGetSignedDataMsg (MSISIP.@) |
| */ |
| BOOL WINAPI MsiSIPGetSignedDataMsg(SIP_SUBJECTINFO *pSubjectInfo, |
| DWORD *pdwEncodingType, DWORD dwIndex, DWORD *pcbSignedDataMsg, |
| BYTE *pbSignedDataMsg) |
| { |
| static const WCHAR digitalSig[] = { 5,'D','i','g','i','t','a','l', |
| 'S','i','g','n','a','t','u','r','e',0 }; |
| BOOL ret = FALSE; |
| IStorage *stg = NULL; |
| HRESULT r; |
| IStream *stm = NULL; |
| BYTE hdr[2], len[sizeof(DWORD)]; |
| DWORD count, lenBytes, dataBytes; |
| |
| TRACE("(%p %p %d %p %p)\n", pSubjectInfo, pdwEncodingType, dwIndex, |
| pcbSignedDataMsg, pbSignedDataMsg); |
| |
| r = StgOpenStorage(pSubjectInfo->pwsFileName, NULL, |
| STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg); |
| if (FAILED(r)) |
| { |
| TRACE("couldn't open %s\n", debugstr_w(pSubjectInfo->pwsFileName)); |
| goto end; |
| } |
| |
| r = IStorage_OpenStream(stg, digitalSig, 0, |
| STGM_READ|STGM_SHARE_EXCLUSIVE, 0, &stm); |
| if (FAILED(r)) |
| { |
| TRACE("couldn't find digital signature stream\n"); |
| goto freestorage; |
| } |
| |
| r = IStream_Read(stm, hdr, sizeof(hdr), &count); |
| if (FAILED(r) || count != sizeof(hdr)) |
| goto freestream; |
| if (hdr[0] != 0x30) |
| { |
| WARN("unexpected data in digital sig: 0x%02x%02x\n", hdr[0], hdr[1]); |
| goto freestream; |
| } |
| |
| /* Read the asn.1 length from the stream. Only supports definite-length |
| * values, which DER-encoded signatures should be. |
| */ |
| if (hdr[1] == 0x80) |
| { |
| WARN("indefinite-length encoding not supported!\n"); |
| goto freestream; |
| } |
| else if (hdr[1] & 0x80) |
| { |
| DWORD temp; |
| LPBYTE ptr; |
| |
| lenBytes = hdr[1] & 0x7f; |
| if (lenBytes > sizeof(DWORD)) |
| { |
| WARN("asn.1 length too long (%d)\n", lenBytes); |
| goto freestream; |
| } |
| r = IStream_Read(stm, len, lenBytes, &count); |
| if (FAILED(r) || count != lenBytes) |
| goto freestream; |
| dataBytes = 0; |
| temp = lenBytes; |
| ptr = len; |
| while (temp--) |
| { |
| dataBytes <<= 8; |
| dataBytes |= *ptr++; |
| } |
| } |
| else |
| { |
| lenBytes = 0; |
| dataBytes = hdr[1]; |
| } |
| |
| if (!pbSignedDataMsg) |
| { |
| *pcbSignedDataMsg = 2 + lenBytes + dataBytes; |
| ret = TRUE; |
| } |
| else if (*pcbSignedDataMsg < 2 + lenBytes + dataBytes) |
| { |
| SetLastError(ERROR_INSUFFICIENT_BUFFER); |
| *pcbSignedDataMsg = 2 + lenBytes + dataBytes; |
| } |
| else |
| { |
| LPBYTE ptr = pbSignedDataMsg; |
| |
| memcpy(ptr, hdr, sizeof(hdr)); |
| ptr += sizeof(hdr); |
| if (lenBytes) |
| { |
| memcpy(ptr, len, lenBytes); |
| ptr += lenBytes; |
| } |
| r = IStream_Read(stm, ptr, dataBytes, &count); |
| if (SUCCEEDED(r) && count == dataBytes) |
| { |
| *pdwEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING; |
| *pcbSignedDataMsg = 2 + lenBytes + dataBytes; |
| ret = TRUE; |
| } |
| } |
| |
| freestream: |
| IStream_Release(stm); |
| freestorage: |
| IStorage_Release(stg); |
| end: |
| |
| TRACE("returning %d\n", ret); |
| return ret; |
| } |
| |
| /*********************************************************************** |
| * MsiSIPIsMyTypeOfFile (MSISIP.@) |
| */ |
| BOOL WINAPI MsiSIPIsMyTypeOfFile(WCHAR *name, GUID *subject) |
| { |
| static const WCHAR msi[] = { '.','m','s','i',0 }; |
| static const WCHAR msp[] = { '.','m','s','p',0 }; |
| BOOL ret = FALSE; |
| |
| TRACE("(%s, %p)\n", debugstr_w(name), subject); |
| |
| if (lstrlenW(name) < lstrlenW(msi)) |
| return FALSE; |
| else if (lstrcmpiW(name + lstrlenW(name) - lstrlenW(msi), msi) && |
| lstrcmpiW(name + lstrlenW(name) - lstrlenW(msp), msp)) |
| return FALSE; |
| else |
| { |
| IStorage *stg = NULL; |
| HRESULT r = StgOpenStorage(name, NULL, |
| STGM_DIRECT|STGM_READ|STGM_SHARE_DENY_WRITE, NULL, 0, &stg); |
| |
| if (SUCCEEDED(r)) |
| { |
| IStorage_Release(stg); |
| *subject = mySubject; |
| ret = TRUE; |
| } |
| } |
| return ret; |
| } |