user32/tests: Run the tests again on Win95.
[wine] / dlls / imagehlp / integrity.c
1 /*
2  *      IMAGEHLP library
3  *
4  *      Copyright 1998  Patrik Stridvall
5  *      Copyright 2003  Mike McCormack
6  *      Copyright 2009  Owen Rudge for CodeWeavers
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include <stdarg.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winerror.h"
28 #include "winternl.h"
29 #include "winnt.h"
30 #include "imagehlp.h"
31 #include "wine/debug.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(imagehlp);
34
35 /*
36  * These functions are partially documented at:
37  *   http://www.cs.auckland.ac.nz/~pgut001/pubs/authenticode.txt
38  */
39
40 #define HDR_FAIL   -1
41 #define HDR_NT32    0
42 #define HDR_NT64    1
43
44 /***********************************************************************
45  * IMAGEHLP_GetNTHeaders (INTERNAL)
46  *
47  * Return the IMAGE_NT_HEADERS for a PE file, after validating magic
48  * numbers and distinguishing between 32-bit and 64-bit files.
49  */
50 static int IMAGEHLP_GetNTHeaders(HANDLE handle, DWORD *pe_offset, IMAGE_NT_HEADERS32 *nt32, IMAGE_NT_HEADERS64 *nt64)
51 {
52     IMAGE_DOS_HEADER dos_hdr;
53     DWORD count;
54     BOOL r;
55
56     TRACE("handle %p\n", handle);
57
58     if ((!nt32) || (!nt64))
59         return HDR_FAIL;
60
61     /* read the DOS header */
62     count = SetFilePointer(handle, 0, NULL, FILE_BEGIN);
63
64     if (count == INVALID_SET_FILE_POINTER)
65         return HDR_FAIL;
66
67     count = 0;
68
69     r = ReadFile(handle, &dos_hdr, sizeof dos_hdr, &count, NULL);
70
71     if (!r)
72         return HDR_FAIL;
73
74     if (count != sizeof dos_hdr)
75         return HDR_FAIL;
76
77     /* verify magic number of 'MZ' */
78     if (dos_hdr.e_magic != 0x5A4D)
79         return HDR_FAIL;
80
81     if (pe_offset != NULL)
82         *pe_offset = dos_hdr.e_lfanew;
83
84     /* read the PE header */
85     count = SetFilePointer(handle, dos_hdr.e_lfanew, NULL, FILE_BEGIN);
86
87     if (count == INVALID_SET_FILE_POINTER)
88         return HDR_FAIL;
89
90     count = 0;
91
92     r = ReadFile(handle, nt32, sizeof(IMAGE_NT_HEADERS32), &count, NULL);
93
94     if (!r)
95         return HDR_FAIL;
96
97     if (count != sizeof(IMAGE_NT_HEADERS32))
98         return HDR_FAIL;
99
100     /* verify NT signature */
101     if (nt32->Signature != IMAGE_NT_SIGNATURE)
102         return HDR_FAIL;
103
104     /* check if we have a 32-bit or 64-bit executable */
105     switch (nt32->OptionalHeader.Magic)
106     {
107         case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
108             return HDR_NT32;
109
110         case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
111             /* Re-read as 64-bit */
112
113             count = SetFilePointer(handle, dos_hdr.e_lfanew, NULL, FILE_BEGIN);
114
115             if (count == INVALID_SET_FILE_POINTER)
116                 return HDR_FAIL;
117
118             count = 0;
119
120             r = ReadFile(handle, nt64, sizeof(IMAGE_NT_HEADERS64), &count, NULL);
121
122             if (!r)
123                 return HDR_FAIL;
124
125             if (count != sizeof(IMAGE_NT_HEADERS64))
126                 return HDR_FAIL;
127
128             /* verify NT signature */
129             if (nt64->Signature != IMAGE_NT_SIGNATURE)
130                 return HDR_FAIL;
131
132             return HDR_NT64;
133     }
134
135     return HDR_FAIL;
136 }
137
138 /***********************************************************************
139  * IMAGEHLP_GetSecurityDirOffset (INTERNAL)
140  *
141  * Read a file's PE header, and return the offset and size of the
142  *  security directory.
143  */
144 static BOOL IMAGEHLP_GetSecurityDirOffset( HANDLE handle,
145                                            DWORD *pdwOfs, DWORD *pdwSize )
146 {
147     IMAGE_NT_HEADERS32 nt_hdr32;
148     IMAGE_NT_HEADERS64 nt_hdr64;
149     IMAGE_DATA_DIRECTORY *sd;
150     int ret;
151
152     ret = IMAGEHLP_GetNTHeaders(handle, NULL, &nt_hdr32, &nt_hdr64);
153
154     if (ret == HDR_NT32)
155         sd = &nt_hdr32.OptionalHeader.DataDirectory[IMAGE_FILE_SECURITY_DIRECTORY];
156     else if (ret == HDR_NT64)
157         sd = &nt_hdr64.OptionalHeader.DataDirectory[IMAGE_FILE_SECURITY_DIRECTORY];
158     else
159         return FALSE;
160
161     TRACE("ret = %d size = %x addr = %x\n", ret, sd->Size, sd->VirtualAddress);
162
163     *pdwSize = sd->Size;
164     *pdwOfs = sd->VirtualAddress;
165
166     return TRUE;
167 }
168
169 /***********************************************************************
170  * IMAGEHLP_SetSecurityDirOffset (INTERNAL)
171  *
172  * Read a file's PE header, and update the offset and size of the
173  *  security directory.
174  */
175 static BOOL IMAGEHLP_SetSecurityDirOffset(HANDLE handle,
176                                           DWORD dwOfs, DWORD dwSize)
177 {
178     IMAGE_NT_HEADERS32 nt_hdr32;
179     IMAGE_NT_HEADERS64 nt_hdr64;
180     IMAGE_DATA_DIRECTORY *sd;
181     int ret, nt_hdr_size = 0;
182     DWORD pe_offset;
183     void *nt_hdr;
184     DWORD count;
185     BOOL r;
186
187     ret = IMAGEHLP_GetNTHeaders(handle, &pe_offset, &nt_hdr32, &nt_hdr64);
188
189     if (ret == HDR_NT32)
190     {
191         sd = &nt_hdr32.OptionalHeader.DataDirectory[IMAGE_FILE_SECURITY_DIRECTORY];
192
193         nt_hdr = &nt_hdr32;
194         nt_hdr_size = sizeof(IMAGE_NT_HEADERS32);
195     }
196     else if (ret == HDR_NT64)
197     {
198         sd = &nt_hdr64.OptionalHeader.DataDirectory[IMAGE_FILE_SECURITY_DIRECTORY];
199
200         nt_hdr = &nt_hdr64;
201         nt_hdr_size = sizeof(IMAGE_NT_HEADERS64);
202     }
203     else
204         return FALSE;
205
206     sd->Size = dwSize;
207     sd->VirtualAddress = dwOfs;
208
209     TRACE("size = %x addr = %x\n", sd->Size, sd->VirtualAddress);
210
211     /* write the header back again */
212     count = SetFilePointer(handle, pe_offset, NULL, FILE_BEGIN);
213
214     if (count == INVALID_SET_FILE_POINTER)
215         return FALSE;
216
217     count = 0;
218
219     r = WriteFile(handle, nt_hdr, nt_hdr_size, &count, NULL);
220
221     if (!r)
222         return FALSE;
223
224     if (count != nt_hdr_size)
225         return FALSE;
226
227     return TRUE;
228 }
229
230 /***********************************************************************
231  * IMAGEHLP_GetCertificateOffset (INTERNAL)
232  *
233  * Read a file's PE header, and return the offset and size of the 
234  *  security directory.
235  */
236 static BOOL IMAGEHLP_GetCertificateOffset( HANDLE handle, DWORD num,
237                                            DWORD *pdwOfs, DWORD *pdwSize )
238 {
239     DWORD size, count, offset, len, sd_VirtualAddr;
240     BOOL r;
241
242     r = IMAGEHLP_GetSecurityDirOffset( handle, &sd_VirtualAddr, &size );
243     if( !r )
244         return FALSE;
245
246     offset = 0;
247     /* take the n'th certificate */
248     while( 1 )
249     {
250         /* read the length of the current certificate */
251         count = SetFilePointer( handle, sd_VirtualAddr + offset,
252                                  NULL, FILE_BEGIN );
253         if( count == INVALID_SET_FILE_POINTER )
254             return FALSE;
255         r = ReadFile( handle, &len, sizeof len, &count, NULL );
256         if( !r )
257             return FALSE;
258         if( count != sizeof len )
259             return FALSE;
260
261         /* check the certificate is not too big or too small */
262         if( len < sizeof len )
263             return FALSE;
264         if( len > (size-offset) )
265             return FALSE;
266         if( !num-- )
267             break;
268
269         /* calculate the offset of the next certificate */
270         offset += len;
271
272         /* padded out to the nearest 8-byte boundary */
273         if( len % 8 )
274             offset += 8 - (len % 8);
275
276         if( offset >= size )
277             return FALSE;
278     }
279
280     *pdwOfs = sd_VirtualAddr + offset;
281     *pdwSize = len;
282
283     TRACE("len = %x addr = %x\n", len, sd_VirtualAddr + offset);
284
285     return TRUE;
286 }
287
288 /***********************************************************************
289  * IMAGEHLP_RecalculateChecksum (INTERNAL)
290  *
291  * Update the NT header checksum for the specified file.
292  */
293 static BOOL IMAGEHLP_RecalculateChecksum(HANDLE handle)
294 {
295     DWORD FileLength, count, HeaderSum, pe_offset, nt_hdr_size;
296     IMAGE_NT_HEADERS32 nt_hdr32;
297     IMAGE_NT_HEADERS64 nt_hdr64;
298     LPVOID BaseAddress;
299     HANDLE hMapping;
300     DWORD *CheckSum;
301     void *nt_hdr;
302     int ret;
303     BOOL r;
304
305     TRACE("handle %p\n", handle);
306
307     ret = IMAGEHLP_GetNTHeaders(handle, &pe_offset, &nt_hdr32, &nt_hdr64);
308
309     if (ret == HDR_NT32)
310     {
311         CheckSum = &nt_hdr32.OptionalHeader.CheckSum;
312
313         nt_hdr = &nt_hdr32;
314         nt_hdr_size = sizeof(IMAGE_NT_HEADERS32);
315     }
316     else if (ret == HDR_NT64)
317     {
318         CheckSum = &nt_hdr64.OptionalHeader.CheckSum;
319
320         nt_hdr = &nt_hdr64;
321         nt_hdr_size = sizeof(IMAGE_NT_HEADERS64);
322     }
323     else
324         return FALSE;
325
326     hMapping = CreateFileMappingW(handle, NULL, PAGE_READONLY, 0, 0, NULL);
327
328     if (!hMapping)
329         return FALSE;
330
331     BaseAddress = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
332
333     if (!BaseAddress)
334     {
335         CloseHandle(hMapping);
336         return FALSE;
337     }
338
339     FileLength = GetFileSize(handle, NULL);
340
341     *CheckSum = 0;
342     CheckSumMappedFile(BaseAddress, FileLength, &HeaderSum, CheckSum);
343
344     UnmapViewOfFile(BaseAddress);
345     CloseHandle(hMapping);
346
347     if (*CheckSum)
348     {
349         /* write the header back again */
350         count = SetFilePointer(handle, pe_offset, NULL, FILE_BEGIN);
351
352         if (count == INVALID_SET_FILE_POINTER)
353             return FALSE;
354
355         count = 0;
356
357         r = WriteFile(handle, nt_hdr, nt_hdr_size, &count, NULL);
358
359         if (!r)
360             return FALSE;
361
362         if (count != nt_hdr_size)
363             return FALSE;
364
365         return TRUE;
366     }
367
368     return FALSE;
369 }
370
371 /***********************************************************************
372  *              ImageAddCertificate (IMAGEHLP.@)
373  *
374  * Adds the specified certificate to the security directory of
375  * open PE file.
376  */
377
378 BOOL WINAPI ImageAddCertificate(
379   HANDLE FileHandle, LPWIN_CERTIFICATE Certificate, PDWORD Index)
380 {
381     DWORD size = 0, count = 0, offset = 0, sd_VirtualAddr = 0, index = 0;
382     WIN_CERTIFICATE hdr;
383     const size_t cert_hdr_size = sizeof hdr - sizeof hdr.bCertificate;
384     BOOL r;
385
386     TRACE("(%p, %p, %p)\n", FileHandle, Certificate, Index);
387
388     r = IMAGEHLP_GetSecurityDirOffset(FileHandle, &sd_VirtualAddr, &size);
389
390     /* If we've already got a security directory, find the end of it */
391     if ((r) && (sd_VirtualAddr != 0))
392     {
393         offset = 0;
394         index = 0;
395         count = 0;
396
397         /* Check if the security directory is at the end of the file.
398            If not, we should probably relocate it. */
399         if (GetFileSize(FileHandle, NULL) != sd_VirtualAddr + size)
400         {
401             FIXME("Security directory already present but not located at EOF, not adding certificate\n");
402
403             SetLastError(ERROR_NOT_SUPPORTED);
404             return FALSE;
405         }
406
407         while (offset < size)
408         {
409             /* read the length of the current certificate */
410             count = SetFilePointer (FileHandle, sd_VirtualAddr + offset,
411                                      NULL, FILE_BEGIN);
412
413             if (count == INVALID_SET_FILE_POINTER)
414                 return FALSE;
415
416             r = ReadFile(FileHandle, &hdr, cert_hdr_size, &count, NULL);
417
418             if (!r)
419                 return FALSE;
420
421             if (count != cert_hdr_size)
422                 return FALSE;
423
424             /* check the certificate is not too big or too small */
425             if (hdr.dwLength < cert_hdr_size)
426                 return FALSE;
427
428             if (hdr.dwLength > (size-offset))
429                 return FALSE;
430
431             /* next certificate */
432             offset += hdr.dwLength;
433
434             /* padded out to the nearest 8-byte boundary */
435             if (hdr.dwLength % 8)
436                 offset += 8 - (hdr.dwLength % 8);
437
438             index++;
439         }
440
441         count = SetFilePointer (FileHandle, sd_VirtualAddr + offset, NULL, FILE_BEGIN);
442
443         if (count == INVALID_SET_FILE_POINTER)
444             return FALSE;
445     }
446     else
447     {
448         sd_VirtualAddr = SetFilePointer(FileHandle, 0, NULL, FILE_END);
449
450         if (sd_VirtualAddr == INVALID_SET_FILE_POINTER)
451             return FALSE;
452     }
453
454     /* Write the certificate to the file */
455     r = WriteFile(FileHandle, Certificate, Certificate->dwLength, &count, NULL);
456
457     if (!r)
458         return FALSE;
459
460     /* Pad out if necessary */
461     if (Certificate->dwLength % 8)
462     {
463         char null[8];
464
465         ZeroMemory(null, 8);
466         WriteFile(FileHandle, null, 8 - (Certificate->dwLength % 8), NULL, NULL);
467
468         size += 8 - (Certificate->dwLength % 8);
469     }
470
471     size += Certificate->dwLength;
472
473     /* Update the security directory offset and size */
474     if (!IMAGEHLP_SetSecurityDirOffset(FileHandle, sd_VirtualAddr, size))
475         return FALSE;
476
477     if (!IMAGEHLP_RecalculateChecksum(FileHandle))
478         return FALSE;
479
480     return TRUE;
481 }
482
483 /***********************************************************************
484  *              ImageEnumerateCertificates (IMAGEHLP.@)
485  */
486 BOOL WINAPI ImageEnumerateCertificates(
487     HANDLE handle, WORD TypeFilter, PDWORD CertificateCount,
488     PDWORD Indices, DWORD IndexCount)
489 {
490     DWORD size, count, offset, sd_VirtualAddr, index;
491     WIN_CERTIFICATE hdr;
492     const size_t cert_hdr_size = sizeof hdr - sizeof hdr.bCertificate;
493     BOOL r;
494
495     TRACE("%p %hd %p %p %d\n",
496            handle, TypeFilter, CertificateCount, Indices, IndexCount);
497
498     r = IMAGEHLP_GetSecurityDirOffset( handle, &sd_VirtualAddr, &size );
499     if( !r )
500         return FALSE;
501
502     offset = 0;
503     index = 0;
504     *CertificateCount = 0;
505     while( offset < size )
506     {
507         /* read the length of the current certificate */
508         count = SetFilePointer( handle, sd_VirtualAddr + offset,
509                                  NULL, FILE_BEGIN );
510         if( count == INVALID_SET_FILE_POINTER )
511             return FALSE;
512         r = ReadFile( handle, &hdr, cert_hdr_size, &count, NULL );
513         if( !r )
514             return FALSE;
515         if( count != cert_hdr_size )
516             return FALSE;
517
518         TRACE("Size = %08x  id = %08hx\n",
519                hdr.dwLength, hdr.wCertificateType );
520
521         /* check the certificate is not too big or too small */
522         if( hdr.dwLength < cert_hdr_size )
523             return FALSE;
524         if( hdr.dwLength > (size-offset) )
525             return FALSE;
526        
527         if( (TypeFilter == CERT_SECTION_TYPE_ANY) ||
528             (TypeFilter == hdr.wCertificateType) )
529         {
530             (*CertificateCount)++;
531             if(Indices && *CertificateCount <= IndexCount)
532                 *Indices++ = index;
533         }
534
535         /* next certificate */
536         offset += hdr.dwLength;
537
538         /* padded out to the nearest 8-byte boundary */
539         if (hdr.dwLength % 8)
540             offset += 8 - (hdr.dwLength % 8);
541
542         index++;
543     }
544
545     return TRUE;
546 }
547
548 /***********************************************************************
549  *              ImageGetCertificateData (IMAGEHLP.@)
550  *
551  *  FIXME: not sure that I'm dealing with the Index the right way
552  */
553 BOOL WINAPI ImageGetCertificateData(
554                 HANDLE handle, DWORD Index,
555                 LPWIN_CERTIFICATE Certificate, PDWORD RequiredLength)
556 {
557     DWORD r, offset, ofs, size, count;
558
559     TRACE("%p %d %p %p\n", handle, Index, Certificate, RequiredLength);
560
561     if( !RequiredLength)
562     {
563         SetLastError( ERROR_INVALID_PARAMETER );
564         return FALSE;
565     }
566
567     if( !IMAGEHLP_GetCertificateOffset( handle, Index, &ofs, &size ) )
568         return FALSE;
569
570     if( *RequiredLength < size )
571     {
572         *RequiredLength = size;
573         SetLastError( ERROR_INSUFFICIENT_BUFFER );
574         return FALSE;
575     }
576
577     if( !Certificate )
578     {
579         SetLastError( ERROR_INVALID_PARAMETER );
580         return FALSE;
581     }
582
583     *RequiredLength = size;
584
585     offset = SetFilePointer( handle, ofs, NULL, FILE_BEGIN );
586     if( offset == INVALID_SET_FILE_POINTER )
587         return FALSE;
588
589     r = ReadFile( handle, Certificate, size, &count, NULL );
590     if( !r )
591         return FALSE;
592     if( count != size )
593         return FALSE;
594
595     TRACE("OK\n");
596     SetLastError( NO_ERROR );
597
598     return TRUE;
599 }
600
601 /***********************************************************************
602  *              ImageGetCertificateHeader (IMAGEHLP.@)
603  */
604 BOOL WINAPI ImageGetCertificateHeader(
605     HANDLE handle, DWORD index, LPWIN_CERTIFICATE pCert)
606 {
607     DWORD r, offset, ofs, size, count;
608     const size_t cert_hdr_size = sizeof *pCert - sizeof pCert->bCertificate;
609
610     TRACE("%p %d %p\n", handle, index, pCert);
611
612     if( !IMAGEHLP_GetCertificateOffset( handle, index, &ofs, &size ) )
613         return FALSE;
614
615     if( size < cert_hdr_size )
616         return FALSE;
617
618     offset = SetFilePointer( handle, ofs, NULL, FILE_BEGIN );
619     if( offset == INVALID_SET_FILE_POINTER )
620         return FALSE;
621
622     r = ReadFile( handle, pCert, cert_hdr_size, &count, NULL );
623     if( !r )
624         return FALSE;
625     if( count != cert_hdr_size )
626         return FALSE;
627
628     TRACE("OK\n");
629
630     return TRUE;
631 }
632
633 /***********************************************************************
634  *              ImageGetDigestStream (IMAGEHLP.@)
635  */
636 BOOL WINAPI ImageGetDigestStream(
637   HANDLE FileHandle, DWORD DigestLevel,
638   DIGEST_FUNCTION DigestFunction, DIGEST_HANDLE DigestHandle)
639 {
640   FIXME("(%p, %d, %p, %p): stub\n",
641     FileHandle, DigestLevel, DigestFunction, DigestHandle
642   );
643   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
644   return FALSE;
645 }
646
647 /***********************************************************************
648  *              ImageRemoveCertificate (IMAGEHLP.@)
649  */
650 BOOL WINAPI ImageRemoveCertificate(HANDLE FileHandle, DWORD Index)
651 {
652     DWORD size = 0, count = 0, sd_VirtualAddr = 0, offset = 0;
653     DWORD data_size = 0, cert_size = 0, cert_size_padded = 0, ret = 0;
654     LPVOID cert_data;
655     BOOL r;
656
657     TRACE("(%p, %d)\n", FileHandle, Index);
658
659     r = ImageEnumerateCertificates(FileHandle, CERT_SECTION_TYPE_ANY, &count, NULL, 0);
660
661     if ((!r) || (count == 0))
662         return FALSE;
663
664     if ((!IMAGEHLP_GetSecurityDirOffset(FileHandle, &sd_VirtualAddr, &size)) ||
665         (!IMAGEHLP_GetCertificateOffset(FileHandle, Index, &offset, &cert_size)))
666         return FALSE;
667
668     /* Ignore any padding we have, too */
669     if (cert_size % 8)
670         cert_size_padded = cert_size + (8 - (cert_size % 8));
671     else
672         cert_size_padded = cert_size;
673
674     data_size = size - (offset - sd_VirtualAddr) - cert_size_padded;
675
676     if (data_size == 0)
677     {
678         ret = SetFilePointer(FileHandle, sd_VirtualAddr, NULL, FILE_BEGIN);
679
680         if (ret == INVALID_SET_FILE_POINTER)
681             return FALSE;
682     }
683     else
684     {
685         cert_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, data_size);
686
687         if (!cert_data)
688             return FALSE;
689
690         ret = SetFilePointer(FileHandle, offset + cert_size_padded, NULL, FILE_BEGIN);
691
692         if (ret == INVALID_SET_FILE_POINTER)
693             goto error;
694
695         /* Read any subsequent certificates */
696         r = ReadFile(FileHandle, cert_data, data_size, &count, NULL);
697
698         if ((!r) || (count != data_size))
699             goto error;
700
701         SetFilePointer(FileHandle, offset, NULL, FILE_BEGIN);
702
703         /* Write them one index back */
704         r = WriteFile(FileHandle, cert_data, data_size, &count, NULL);
705
706         if ((!r) || (count != data_size))
707             goto error;
708
709         HeapFree(GetProcessHeap(), 0, cert_data);
710     }
711
712     /* If security directory is at end of file, trim the file */
713     if (GetFileSize(FileHandle, NULL) == sd_VirtualAddr + size)
714         SetEndOfFile(FileHandle);
715
716     if (count == 1)
717         r = IMAGEHLP_SetSecurityDirOffset(FileHandle, 0, 0);
718     else
719         r = IMAGEHLP_SetSecurityDirOffset(FileHandle, sd_VirtualAddr, size - cert_size_padded);
720
721     if (!r)
722         return FALSE;
723
724     if (!IMAGEHLP_RecalculateChecksum(FileHandle))
725         return FALSE;
726
727     return TRUE;
728
729 error:
730     HeapFree(GetProcessHeap(), 0, cert_data);
731     return FALSE;
732 }