Implement ImageEnumerateCertificates and ImageGetCertificateHeader.
[wine] / dlls / imagehlp / integrity.c
1 /*
2  *      IMAGEHLP library
3  *
4  *      Copyright 1998  Patrik Stridvall
5  *      Copyright 2003  Mike McCormack
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include <stdarg.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winerror.h"
27 #include "winreg.h"
28 #include "winternl.h"
29 #include "winnt.h"
30 #include "ntstatus.h"
31 #include "imagehlp.h"
32 #include "wine/debug.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(imagehlp);
35
36 /*
37  * These functions are partially documented at:
38  *   http://www.cs.auckland.ac.nz/~pgut001/pubs/authenticode.txt
39  */
40
41 /***********************************************************************
42  * IMAGEHLP_GetSecurityDirOffset (INTERNAL)
43  *
44  * Read a file's PE header, and return the offset and size of the 
45  *  security directory.
46  */
47 static BOOL IMAGEHLP_GetSecurityDirOffset( HANDLE handle, 
48                                            DWORD *pdwOfs, DWORD *pdwSize )
49 {
50     IMAGE_DOS_HEADER dos_hdr;
51     IMAGE_NT_HEADERS nt_hdr;
52     DWORD count;
53     BOOL r;
54     IMAGE_DATA_DIRECTORY *sd;
55
56     TRACE("handle %p\n", handle );
57
58     /* read the DOS header */
59     count = SetFilePointer( handle, 0, NULL, FILE_BEGIN );
60     if( count == INVALID_SET_FILE_POINTER )
61         return FALSE;
62     count = 0;
63     r = ReadFile( handle, &dos_hdr, sizeof dos_hdr, &count, NULL );
64     if( !r )
65         return FALSE;
66     if( count != sizeof dos_hdr )
67         return FALSE;
68
69     /* read the PE header */
70     count = SetFilePointer( handle, dos_hdr.e_lfanew, NULL, FILE_BEGIN );
71     if( count == INVALID_SET_FILE_POINTER )
72         return FALSE;
73     count = 0;
74     r = ReadFile( handle, &nt_hdr, sizeof nt_hdr, &count, NULL );
75     if( !r )
76         return FALSE;
77     if( count != sizeof nt_hdr )
78         return FALSE;
79
80     sd = &nt_hdr.OptionalHeader.
81                     DataDirectory[IMAGE_FILE_SECURITY_DIRECTORY];
82
83     TRACE("size = %lx addr = %lx\n", sd->Size, sd->VirtualAddress);
84     *pdwSize = sd->Size;
85     *pdwOfs = sd->VirtualAddress;
86
87     return TRUE;
88 }
89
90 /***********************************************************************
91  * IMAGEHLP_GetCertificateOffset (INTERNAL)
92  *
93  * Read a file's PE header, and return the offset and size of the 
94  *  security directory.
95  */
96 static BOOL IMAGEHLP_GetCertificateOffset( HANDLE handle, DWORD num,
97                                            DWORD *pdwOfs, DWORD *pdwSize )
98 {
99     DWORD size, count, offset, len, sd_VirtualAddr;
100     BOOL r;
101
102     r = IMAGEHLP_GetSecurityDirOffset( handle, &sd_VirtualAddr, &size );
103     if( !r )
104         return FALSE;
105
106     offset = 0;
107     /* take the n'th certificate */
108     while( 1 )
109     {
110         /* read the length of the current certificate */
111         count = SetFilePointer( handle, sd_VirtualAddr + offset,
112                                  NULL, FILE_BEGIN );
113         if( count == INVALID_SET_FILE_POINTER )
114             return FALSE;
115         r = ReadFile( handle, &len, sizeof len, &count, NULL );
116         if( !r )
117             return FALSE;
118         if( count != sizeof len )
119             return FALSE;
120
121         /* check the certificate is not too big or too small */
122         if( len < sizeof len )
123             return FALSE;
124         if( len > (size-offset) )
125             return FALSE;
126         if( !num-- )
127             break;
128
129         /* calculate the offset of the next certificate */
130         offset += len;
131         if( offset >= size )
132             return FALSE;
133     }
134
135     *pdwOfs = sd_VirtualAddr + offset;
136     *pdwSize = len;
137
138     TRACE("len = %lx addr = %lx\n", len, sd_VirtualAddr + offset);
139
140     return TRUE;
141 }
142
143
144 /***********************************************************************
145  *              ImageAddCertificate (IMAGEHLP.@)
146  */
147
148 BOOL WINAPI ImageAddCertificate(
149   HANDLE FileHandle, PWIN_CERTIFICATE Certificate, PDWORD Index)
150 {
151   FIXME("(%p, %p, %p): stub\n",
152     FileHandle, Certificate, Index
153   );
154   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
155   return FALSE;
156 }
157
158 /***********************************************************************
159  *              ImageEnumerateCertificates (IMAGEHLP.@)
160  */
161 BOOL WINAPI ImageEnumerateCertificates(
162     HANDLE handle, WORD TypeFilter, PDWORD CertificateCount,
163     PDWORD Indices, DWORD IndexCount)
164 {
165     DWORD size, count, offset, sd_VirtualAddr;
166     WIN_CERTIFICATE hdr;
167     const size_t cert_hdr_size = sizeof hdr - sizeof hdr.bCertificate;
168     BOOL r;
169
170     TRACE("%p %hd %p %p %ld\n",
171            handle, TypeFilter, CertificateCount, Indices, IndexCount);
172
173     if( Indices )
174     {
175         FIXME("Indicies not handled!\n");
176         return FALSE;
177     }
178
179     r = IMAGEHLP_GetSecurityDirOffset( handle, &sd_VirtualAddr, &size );
180     if( !r )
181         return FALSE;
182
183     offset = 0;
184     *CertificateCount = 0;
185     while( offset < size )
186     {
187         /* read the length of the current certificate */
188         count = SetFilePointer( handle, sd_VirtualAddr + offset,
189                                  NULL, FILE_BEGIN );
190         if( count == INVALID_SET_FILE_POINTER )
191             return FALSE;
192         r = ReadFile( handle, &hdr, cert_hdr_size, &count, NULL );
193         if( !r )
194             return FALSE;
195         if( count != cert_hdr_size )
196             return FALSE;
197
198         TRACE("Size = %08lx  id = %08hx\n",
199                hdr.dwLength, hdr.wCertificateType );
200
201         /* check the certificate is not too big or too small */
202         if( hdr.dwLength < cert_hdr_size )
203             return FALSE;
204         if( hdr.dwLength > (size-offset) )
205             return FALSE;
206        
207         if( (TypeFilter == CERT_SECTION_TYPE_ANY) ||
208             (TypeFilter == hdr.wCertificateType) )
209         {
210             (*CertificateCount)++;
211         }
212
213         /* next certificate */
214         offset += hdr.dwLength;
215     }
216
217     return TRUE;
218 }
219
220 /***********************************************************************
221  *              ImageGetCertificateData (IMAGEHLP.@)
222  *
223  *  FIXME: not sure that I'm dealing with the Index the right way
224  */
225 BOOL WINAPI ImageGetCertificateData(
226                 HANDLE handle, DWORD Index,
227                 PWIN_CERTIFICATE Certificate, PDWORD RequiredLength)
228 {
229     DWORD r, offset, ofs, size, count;
230
231     TRACE("%p %ld %p %p\n", handle, Index, Certificate, RequiredLength);
232
233     if( !IMAGEHLP_GetCertificateOffset( handle, Index, &ofs, &size ) )
234         return FALSE;
235
236     if( !Certificate )
237     {
238         *RequiredLength = size;
239         return TRUE;
240     }
241
242     if( *RequiredLength < size )
243     {
244         *RequiredLength = size;
245         SetLastError( ERROR_INSUFFICIENT_BUFFER );
246         return FALSE;
247     }
248
249     *RequiredLength = size;
250
251     offset = SetFilePointer( handle, ofs, NULL, FILE_BEGIN );
252     if( offset == INVALID_SET_FILE_POINTER )
253         return FALSE;
254
255     r = ReadFile( handle, Certificate, size, &count, NULL );
256     if( !r )
257         return FALSE;
258     if( count != size )
259         return FALSE;
260
261     TRACE("OK\n");
262
263     return TRUE;
264 }
265
266 /***********************************************************************
267  *              ImageGetCertificateHeader (IMAGEHLP.@)
268  */
269 BOOL WINAPI ImageGetCertificateHeader(
270     HANDLE handle, DWORD index, PWIN_CERTIFICATE pCert)
271 {
272     DWORD r, offset, ofs, size, count;
273     const size_t cert_hdr_size = sizeof *pCert - sizeof pCert->bCertificate;
274
275     TRACE("%p %ld %p\n", handle, index, pCert);
276
277     if( !IMAGEHLP_GetCertificateOffset( handle, index, &ofs, &size ) )
278         return FALSE;
279
280     if( size < cert_hdr_size )
281         return FALSE;
282
283     offset = SetFilePointer( handle, ofs, NULL, FILE_BEGIN );
284     if( offset == INVALID_SET_FILE_POINTER )
285         return FALSE;
286
287     r = ReadFile( handle, pCert, cert_hdr_size, &count, NULL );
288     if( !r )
289         return FALSE;
290     if( count != cert_hdr_size )
291         return FALSE;
292
293     TRACE("OK\n");
294
295     return TRUE;
296 }
297
298 /***********************************************************************
299  *              ImageGetDigestStream (IMAGEHLP.@)
300  */
301 BOOL WINAPI ImageGetDigestStream(
302   HANDLE FileHandle, DWORD DigestLevel,
303   DIGEST_FUNCTION DigestFunction, DIGEST_HANDLE DigestHandle)
304 {
305   FIXME("(%p, %ld, %p, %p): stub\n",
306     FileHandle, DigestLevel, DigestFunction, DigestHandle
307   );
308   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
309   return FALSE;
310 }
311
312 /***********************************************************************
313  *              ImageRemoveCertificate (IMAGEHLP.@)
314  */
315 BOOL WINAPI ImageRemoveCertificate(HANDLE FileHandle, DWORD Index)
316 {
317   FIXME("(%p, %ld): stub\n", FileHandle, Index);
318   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
319   return FALSE;
320 }