quartz/tests: Skip some tests on NT4.
[wine.git] / dlls / wintrust / crypt.c
blobe2129dffc60ab9c9de3b37a4596d67fa1e0fa30a
1 /*
2 * WinTrust Cryptography functions
4 * Copyright 2006 James Hawkins
5 * Copyright 2000-2002 Stuart Caie
6 * Copyright 2002 Patrik Stridvall
7 * Copyright 2003 Greg Turner
8 * Copyright 2008 Juan Lang
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wintrust.h"
30 #include "mscat.h"
31 #include "mssip.h"
32 #include "imagehlp.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(wintrust);
38 /***********************************************************************
39 * CryptCATAdminAcquireContext (WINTRUST.@)
41 * Get a catalog administrator context handle.
43 * PARAMS
44 * catAdmin [O] Pointer to the context handle.
45 * sysSystem [I] Pointer to a GUID for the needed subsystem.
46 * dwFlags [I] Reserved.
48 * RETURNS
49 * Success: TRUE. catAdmin contains the context handle.
50 * Failure: FALSE.
53 BOOL WINAPI CryptCATAdminAcquireContext(HCATADMIN* catAdmin,
54 const GUID *sysSystem, DWORD dwFlags )
56 FIXME("%p %s %x\n", catAdmin, debugstr_guid(sysSystem), dwFlags);
58 if (!catAdmin)
60 SetLastError(ERROR_INVALID_PARAMETER);
61 return FALSE;
64 *catAdmin = (HCATADMIN)0xdeadbeef;
66 return TRUE;
69 /***********************************************************************
70 * CryptCATAdminAddCatalog (WINTRUST.@)
72 BOOL WINAPI CryptCATAdminAddCatalog(HCATADMIN catAdmin, PWSTR catalogFile,
73 PWSTR selectBaseName, DWORD flags)
75 FIXME("%p %s %s %d\n", catAdmin, debugstr_w(catalogFile),
76 debugstr_w(selectBaseName), flags);
77 return TRUE;
80 /***********************************************************************
81 * CryptCATAdminCalcHashFromFileHandle (WINTRUST.@)
83 BOOL WINAPI CryptCATAdminCalcHashFromFileHandle(HANDLE hFile, DWORD* pcbHash,
84 BYTE* pbHash, DWORD dwFlags )
86 FIXME("%p %p %p %x\n", hFile, pcbHash, pbHash, dwFlags);
88 if (pbHash && pcbHash) memset(pbHash, 0, *pcbHash);
89 return TRUE;
92 /***********************************************************************
93 * CryptCATAdminEnumCatalogFromHash (WINTRUST.@)
95 HCATINFO WINAPI CryptCATAdminEnumCatalogFromHash(HCATADMIN hCatAdmin,
96 BYTE* pbHash,
97 DWORD cbHash,
98 DWORD dwFlags,
99 HCATINFO* phPrevCatInfo )
101 FIXME("%p %p %d %d %p\n", hCatAdmin, pbHash, cbHash, dwFlags, phPrevCatInfo);
102 return NULL;
105 /***********************************************************************
106 * CryptCATAdminReleaseCatalogContext (WINTRUST.@)
108 * Release a catalog context handle.
110 * PARAMS
111 * hCatAdmin [I] Context handle.
112 * hCatInfo [I] Catalog handle.
113 * dwFlags [I] Reserved.
115 * RETURNS
116 * Success: TRUE.
117 * Failure: FAIL.
120 BOOL WINAPI CryptCATAdminReleaseCatalogContext(HCATADMIN hCatAdmin,
121 HCATINFO hCatInfo,
122 DWORD dwFlags)
124 FIXME("%p %p %x\n", hCatAdmin, hCatInfo, dwFlags);
125 return TRUE;
128 /***********************************************************************
129 * CryptCATAdminReleaseContext (WINTRUST.@)
131 * Release a catalog administrator context handle.
133 * PARAMS
134 * catAdmin [I] Context handle.
135 * dwFlags [I] Reserved.
137 * RETURNS
138 * Success: TRUE.
139 * Failure: FAIL.
142 BOOL WINAPI CryptCATAdminReleaseContext(HCATADMIN hCatAdmin, DWORD dwFlags )
144 FIXME("%p %x\n", hCatAdmin, dwFlags);
145 return TRUE;
148 /***********************************************************************
149 * CryptCATAdminRemoveCatalog (WINTRUST.@)
151 * Remove a catalog file.
153 * PARAMS
154 * catAdmin [I] Context handle.
155 * pwszCatalogFile [I] Catalog file.
156 * dwFlags [I] Reserved.
158 * RETURNS
159 * Success: TRUE.
160 * Failure: FALSE.
163 BOOL WINAPI CryptCATAdminRemoveCatalog(HCATADMIN hCatAdmin, LPCWSTR pwszCatalogFile, DWORD dwFlags)
165 FIXME("%p %s %x\n", hCatAdmin, debugstr_w(pwszCatalogFile), dwFlags);
166 return DeleteFileW(pwszCatalogFile);
169 /***********************************************************************
170 * CryptCATClose (WINTRUST.@)
172 BOOL WINAPI CryptCATClose(HANDLE hCatalog)
174 FIXME("(%p) stub\n", hCatalog);
175 return TRUE;
178 /***********************************************************************
179 * CryptCATEnumerateMember (WINTRUST.@)
181 CRYPTCATMEMBER *WINAPI CryptCATEnumerateMember(HANDLE hCatalog, CRYPTCATMEMBER* pPrevMember)
183 FIXME("(%p, %p) stub\n", hCatalog, pPrevMember);
184 return NULL;
187 /***********************************************************************
188 * CryptCATOpen (WINTRUST.@)
190 HANDLE WINAPI CryptCATOpen(LPWSTR pwszFileName, DWORD fdwOpenFlags, HCRYPTPROV hProv,
191 DWORD dwPublicVersion, DWORD dwEncodingType)
193 FIXME("(%s, %d, %ld, %d, %d) stub\n", debugstr_w(pwszFileName), fdwOpenFlags,
194 hProv, dwPublicVersion, dwEncodingType);
195 return 0;
198 /***********************************************************************
199 * CryptSIPCreateIndirectData (WINTRUST.@)
201 BOOL WINAPI CryptSIPCreateIndirectData(SIP_SUBJECTINFO* pSubjectInfo, DWORD* pcbIndirectData,
202 SIP_INDIRECT_DATA* pIndirectData)
204 FIXME("(%p %p %p) stub\n", pSubjectInfo, pcbIndirectData, pIndirectData);
206 return FALSE;
209 static BOOL WINTRUST_GetSignedMsgFromPEFile(SIP_SUBJECTINFO *pSubjectInfo,
210 DWORD *pdwEncodingType, DWORD dwIndex, DWORD *pcbSignedDataMsg,
211 BYTE *pbSignedDataMsg)
213 BOOL ret;
214 WIN_CERTIFICATE *pCert = NULL;
216 TRACE("(%p %p %d %p %p)\n", pSubjectInfo, pdwEncodingType, dwIndex,
217 pcbSignedDataMsg, pbSignedDataMsg);
219 if (!pbSignedDataMsg)
221 WIN_CERTIFICATE cert;
223 /* app hasn't passed buffer, just get the length */
224 ret = ImageGetCertificateHeader(pSubjectInfo->hFile, dwIndex, &cert);
225 if (ret)
226 *pcbSignedDataMsg = cert.dwLength;
228 else
230 DWORD len = 0;
232 ret = ImageGetCertificateData(pSubjectInfo->hFile, dwIndex, NULL, &len);
233 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
234 goto error;
235 pCert = HeapAlloc(GetProcessHeap(), 0, len);
236 if (!pCert)
238 ret = FALSE;
239 goto error;
241 ret = ImageGetCertificateData(pSubjectInfo->hFile, dwIndex, pCert,
242 &len);
243 if (!ret)
244 goto error;
245 if (*pcbSignedDataMsg < pCert->dwLength)
247 *pcbSignedDataMsg = pCert->dwLength;
248 SetLastError(ERROR_INSUFFICIENT_BUFFER);
249 ret = FALSE;
251 else
253 memcpy(pbSignedDataMsg, pCert->bCertificate, pCert->dwLength);
254 switch (pCert->wCertificateType)
256 case WIN_CERT_TYPE_X509:
257 *pdwEncodingType = X509_ASN_ENCODING;
258 break;
259 case WIN_CERT_TYPE_PKCS_SIGNED_DATA:
260 *pdwEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
261 break;
262 default:
263 FIXME("don't know what to do for encoding type %d\n",
264 pCert->wCertificateType);
265 *pdwEncodingType = 0;
269 error:
270 HeapFree(GetProcessHeap(), 0, pCert);
271 return ret;
274 /* structure offsets */
275 #define cfhead_Signature (0x00)
276 #define cfhead_CabinetSize (0x08)
277 #define cfhead_MinorVersion (0x18)
278 #define cfhead_MajorVersion (0x19)
279 #define cfhead_Flags (0x1E)
280 #define cfhead_SIZEOF (0x24)
281 #define cfheadext_HeaderReserved (0x00)
282 #define cfheadext_SIZEOF (0x04)
283 #define cfsigninfo_CertOffset (0x04)
284 #define cfsigninfo_CertSize (0x08)
285 #define cfsigninfo_SIZEOF (0x0C)
287 /* flags */
288 #define cfheadRESERVE_PRESENT (0x0004)
290 /* endian-neutral reading of little-endian data */
291 #define EndGetI32(a) ((((a)[3])<<24)|(((a)[2])<<16)|(((a)[1])<<8)|((a)[0]))
292 #define EndGetI16(a) ((((a)[1])<<8)|((a)[0]))
294 /* For documentation purposes only: this is the structure in the reserved
295 * area of a signed cabinet file. The cert offset indicates where in the
296 * cabinet file the signature resides, and the count indicates its size.
298 typedef struct _CAB_SIGNINFO
300 WORD unk0; /* always 0? */
301 WORD unk1; /* always 0x0010? */
302 DWORD dwCertOffset;
303 DWORD cbCertBlock;
304 } CAB_SIGNINFO, *PCAB_SIGNINFO;
306 static BOOL WINTRUST_GetSignedMsgFromCabFile(SIP_SUBJECTINFO *pSubjectInfo,
307 DWORD *pdwEncodingType, DWORD dwIndex, DWORD *pcbSignedDataMsg,
308 BYTE *pbSignedDataMsg)
310 int header_resv;
311 LONG base_offset, cabsize;
312 USHORT flags;
313 BYTE buf[64];
314 DWORD cert_offset, cert_size, dwRead;
316 TRACE("(%p %p %d %p %p)\n", pSubjectInfo, pdwEncodingType, dwIndex,
317 pcbSignedDataMsg, pbSignedDataMsg);
320 * FIXME: I just noticed that I am memorizing the initial file pointer
321 * offset and restoring it before reading in the rest of the header
322 * information in the cabinet. Perhaps that's correct -- that is, perhaps
323 * this API is supposed to support "streaming" cabinets which are embedded
324 * in other files, or cabinets which begin at file offsets other than zero.
325 * Otherwise, I should instead go to the absolute beginning of the file.
326 * (Either way, the semantics of wine's FDICopy require me to leave the
327 * file pointer where it is afterwards -- If Windows does not do so, we
328 * ought to duplicate the native behavior in the FDIIsCabinet API, not here.
330 * So, the answer lies in Windows; will native cabinet.dll recognize a
331 * cabinet "file" embedded in another file? Note that cabextract.c does
332 * support this, which implies that Microsoft's might. I haven't tried it
333 * yet so I don't know. ATM, most of wine's FDI cabinet routines (except
334 * this one) would not work in this way. To fix it, we could just make the
335 * various references to absolute file positions in the code relative to an
336 * initial "beginning" offset. Because the FDICopy API doesn't take a
337 * file-handle like this one, we would therein need to search through the
338 * file for the beginning of the cabinet (as we also do in cabextract.c).
339 * Note that this limits us to a maximum of one cabinet per. file: the first.
341 * So, in summary: either the code below is wrong, or the rest of fdi.c is
342 * wrong... I cannot imagine that both are correct ;) One of these flaws
343 * should be fixed after determining the behavior on Windows. We ought
344 * to check both FDIIsCabinet and FDICopy for the right behavior.
346 * -gmt
349 /* get basic offset & size info */
350 base_offset = SetFilePointer(pSubjectInfo->hFile, 0L, NULL, SEEK_CUR);
352 if (SetFilePointer(pSubjectInfo->hFile, 0, NULL, SEEK_END) == -1)
354 TRACE("seek error\n");
355 return FALSE;
358 cabsize = SetFilePointer(pSubjectInfo->hFile, 0L, NULL, SEEK_CUR);
359 if ((cabsize == -1) || (base_offset == -1) ||
360 (SetFilePointer(pSubjectInfo->hFile, base_offset, NULL, SEEK_SET) == -1))
362 TRACE("seek error\n");
363 return FALSE;
366 /* read in the CFHEADER */
367 if (!ReadFile(pSubjectInfo->hFile, buf, cfhead_SIZEOF, &dwRead, NULL) ||
368 dwRead != cfhead_SIZEOF)
370 TRACE("reading header failed\n");
371 return FALSE;
374 /* check basic MSCF signature */
375 if (EndGetI32(buf+cfhead_Signature) != 0x4643534d)
377 WARN("cabinet signature not present\n");
378 return FALSE;
381 /* Ignore the number of folders and files and the set and cabinet IDs */
383 /* check the header revision */
384 if ((buf[cfhead_MajorVersion] > 1) ||
385 (buf[cfhead_MajorVersion] == 1 && buf[cfhead_MinorVersion] > 3))
387 WARN("cabinet format version > 1.3\n");
388 return FALSE;
391 /* pull the flags out */
392 flags = EndGetI16(buf+cfhead_Flags);
394 if (!(flags & cfheadRESERVE_PRESENT))
396 TRACE("no header present, not signed\n");
397 return FALSE;
400 if (!ReadFile(pSubjectInfo->hFile, buf, cfheadext_SIZEOF, &dwRead, NULL) ||
401 dwRead != cfheadext_SIZEOF)
403 ERR("bunk reserve-sizes?\n");
404 return FALSE;
407 header_resv = EndGetI16(buf+cfheadext_HeaderReserved);
408 if (!header_resv)
410 TRACE("no header_resv, not signed\n");
411 return FALSE;
413 else if (header_resv < cfsigninfo_SIZEOF)
415 TRACE("header_resv too small, not signed\n");
416 return FALSE;
419 if (header_resv > 60000)
421 WARN("WARNING; header reserved space > 60000\n");
424 if (!ReadFile(pSubjectInfo->hFile, buf, cfsigninfo_SIZEOF, &dwRead, NULL) ||
425 dwRead != cfsigninfo_SIZEOF)
427 ERR("couldn't read reserve\n");
428 return FALSE;
431 cert_offset = EndGetI32(buf+cfsigninfo_CertOffset);
432 TRACE("cert_offset: %d\n", cert_offset);
433 cert_size = EndGetI32(buf+cfsigninfo_CertSize);
434 TRACE("cert_size: %d\n", cert_size);
436 /* The redundant checks are to avoid wraparound */
437 if (cert_offset > cabsize || cert_size > cabsize ||
438 cert_offset + cert_size > cabsize)
440 WARN("offset beyond file, not attempting to read\n");
441 return FALSE;
444 SetFilePointer(pSubjectInfo->hFile, base_offset, NULL, SEEK_SET);
445 if (!pbSignedDataMsg)
447 *pcbSignedDataMsg = cert_size;
448 return TRUE;
450 if (*pcbSignedDataMsg < cert_size)
452 *pcbSignedDataMsg = cert_size;
453 SetLastError(ERROR_INSUFFICIENT_BUFFER);
454 return FALSE;
456 if (SetFilePointer(pSubjectInfo->hFile, cert_offset, NULL, SEEK_SET) == -1)
458 ERR("couldn't seek to cert location\n");
459 return FALSE;
461 if (!ReadFile(pSubjectInfo->hFile, pbSignedDataMsg, cert_size, &dwRead,
462 NULL) || dwRead != cert_size)
464 ERR("couldn't read cert\n");
465 return FALSE;
467 /* The encoding of the files I've seen appears to be in ASN.1
468 * format, and there isn't a field indicating the type, so assume it
469 * always is.
471 *pdwEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
472 return TRUE;
475 /***********************************************************************
476 * CryptSIPGetSignedDataMsg (WINTRUST.@)
478 BOOL WINAPI CryptSIPGetSignedDataMsg(SIP_SUBJECTINFO* pSubjectInfo, DWORD* pdwEncodingType,
479 DWORD dwIndex, DWORD* pcbSignedDataMsg, BYTE* pbSignedDataMsg)
481 static const GUID unknown = { 0xC689AAB8, 0x8E78, 0x11D0, { 0x8C,0x47,
482 0x00,0xC0,0x4F,0xC2,0x95,0xEE } };
483 static const GUID cabGUID = { 0xC689AABA, 0x8E78, 0x11D0, { 0x8C,0x47,
484 0x00,0xC0,0x4F,0xC2,0x95,0xEE } };
485 BOOL ret;
487 TRACE("(%p %p %d %p %p)\n", pSubjectInfo, pdwEncodingType, dwIndex,
488 pcbSignedDataMsg, pbSignedDataMsg);
490 if (!memcmp(pSubjectInfo->pgSubjectType, &unknown, sizeof(unknown)))
491 ret = WINTRUST_GetSignedMsgFromPEFile(pSubjectInfo, pdwEncodingType,
492 dwIndex, pcbSignedDataMsg, pbSignedDataMsg);
493 else if (!memcmp(pSubjectInfo->pgSubjectType, &cabGUID, sizeof(cabGUID)))
494 ret = WINTRUST_GetSignedMsgFromCabFile(pSubjectInfo, pdwEncodingType,
495 dwIndex, pcbSignedDataMsg, pbSignedDataMsg);
496 else
498 FIXME("unimplemented for subject type %s\n",
499 debugstr_guid(pSubjectInfo->pgSubjectType));
500 ret = FALSE;
503 TRACE("returning %d\n", ret);
504 return ret;
507 /***********************************************************************
508 * CryptSIPPutSignedDataMsg (WINTRUST.@)
510 BOOL WINAPI CryptSIPPutSignedDataMsg(SIP_SUBJECTINFO* pSubjectInfo, DWORD pdwEncodingType,
511 DWORD* pdwIndex, DWORD cbSignedDataMsg, BYTE* pbSignedDataMsg)
513 FIXME("(%p %d %p %d %p) stub\n", pSubjectInfo, pdwEncodingType, pdwIndex,
514 cbSignedDataMsg, pbSignedDataMsg);
516 return FALSE;
519 /***********************************************************************
520 * CryptSIPRemoveSignedDataMsg (WINTRUST.@)
522 BOOL WINAPI CryptSIPRemoveSignedDataMsg(SIP_SUBJECTINFO* pSubjectInfo,
523 DWORD dwIndex)
525 FIXME("(%p %d) stub\n", pSubjectInfo, dwIndex);
527 return FALSE;
530 /***********************************************************************
531 * CryptSIPVerifyIndirectData (WINTRUST.@)
533 BOOL WINAPI CryptSIPVerifyIndirectData(SIP_SUBJECTINFO* pSubjectInfo,
534 SIP_INDIRECT_DATA* pIndirectData)
536 FIXME("(%p %p) stub\n", pSubjectInfo, pIndirectData);
538 return FALSE;