2 * Copyright 2004-2006 Juan Lang
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "wine/debug.h"
24 #include "wine/exception.h"
25 #include "crypt32_private.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(crypt
);
29 /* An extended certificate property in serialized form is prefixed by this
32 typedef struct _WINE_CERT_PROP_HEADER
35 DWORD unknown
; /* always 1 */
37 } WINE_CERT_PROP_HEADER
, *PWINE_CERT_PROP_HEADER
;
39 static BOOL
CRYPT_SerializeStoreElement(const void *context
,
40 const BYTE
*encodedContext
, DWORD cbEncodedContext
, DWORD contextPropID
,
41 PCWINE_CONTEXT_INTERFACE contextInterface
, DWORD dwFlags
, BOOL omitHashes
,
42 BYTE
*pbElement
, DWORD
*pcbElement
)
46 TRACE("(%p, %p, %08x, %d, %p, %p)\n", context
, contextInterface
, dwFlags
,
47 omitHashes
, pbElement
, pcbElement
);
51 DWORD bytesNeeded
= sizeof(WINE_CERT_PROP_HEADER
) + cbEncodedContext
;
56 prop
= contextInterface
->enumProps(context
, prop
);
57 if (prop
&& (!omitHashes
|| !IS_CERT_HASH_PROP_ID(prop
)))
61 ret
= contextInterface
->getProp(context
, prop
, NULL
, &propSize
);
63 bytesNeeded
+= sizeof(WINE_CERT_PROP_HEADER
) + propSize
;
65 } while (ret
&& prop
!= 0);
69 *pcbElement
= bytesNeeded
;
72 else if (*pcbElement
< bytesNeeded
)
74 *pcbElement
= bytesNeeded
;
75 SetLastError(ERROR_MORE_DATA
);
80 PWINE_CERT_PROP_HEADER hdr
;
86 prop
= contextInterface
->enumProps(context
, prop
);
87 if (prop
&& (!omitHashes
|| !IS_CERT_HASH_PROP_ID(prop
)))
91 ret
= contextInterface
->getProp(context
, prop
, NULL
,
95 if (bufSize
< propSize
)
98 buf
= CryptMemRealloc(buf
, propSize
);
100 buf
= CryptMemAlloc(propSize
);
105 ret
= contextInterface
->getProp(context
, prop
, buf
,
109 hdr
= (PWINE_CERT_PROP_HEADER
)pbElement
;
113 pbElement
+= sizeof(WINE_CERT_PROP_HEADER
);
116 memcpy(pbElement
, buf
, propSize
);
117 pbElement
+= propSize
;
125 } while (ret
&& prop
!= 0);
128 hdr
= (PWINE_CERT_PROP_HEADER
)pbElement
;
129 hdr
->propID
= contextPropID
;
131 hdr
->cb
= cbEncodedContext
;
132 memcpy(pbElement
+ sizeof(WINE_CERT_PROP_HEADER
),
133 encodedContext
, cbEncodedContext
);
141 BOOL WINAPI
CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext
,
142 DWORD dwFlags
, BYTE
*pbElement
, DWORD
*pcbElement
)
144 return CRYPT_SerializeStoreElement(pCertContext
,
145 pCertContext
->pbCertEncoded
, pCertContext
->cbCertEncoded
,
146 CERT_CERT_PROP_ID
, pCertInterface
, dwFlags
, FALSE
, pbElement
, pcbElement
);
149 BOOL WINAPI
CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext
,
150 DWORD dwFlags
, BYTE
*pbElement
, DWORD
*pcbElement
)
152 return CRYPT_SerializeStoreElement(pCrlContext
,
153 pCrlContext
->pbCrlEncoded
, pCrlContext
->cbCrlEncoded
,
154 CERT_CRL_PROP_ID
, pCRLInterface
, dwFlags
, FALSE
, pbElement
, pcbElement
);
157 BOOL WINAPI
CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext
,
158 DWORD dwFlags
, BYTE
*pbElement
, DWORD
*pcbElement
)
160 return CRYPT_SerializeStoreElement(pCtlContext
,
161 pCtlContext
->pbCtlEncoded
, pCtlContext
->cbCtlEncoded
,
162 CERT_CTL_PROP_ID
, pCTLInterface
, dwFlags
, FALSE
, pbElement
, pcbElement
);
165 /* Looks for the property with ID propID in the buffer buf. Returns a pointer
166 * to its header if a valid header is found, NULL if not. Valid means the
167 * length of thte property won't overrun buf, and the unknown field is 1.
169 static const WINE_CERT_PROP_HEADER
*CRYPT_findPropID(const BYTE
*buf
,
170 DWORD size
, DWORD propID
)
172 const WINE_CERT_PROP_HEADER
*ret
= NULL
;
175 while (size
&& !ret
&& !done
)
177 if (size
< sizeof(WINE_CERT_PROP_HEADER
))
179 SetLastError(CRYPT_E_FILE_ERROR
);
184 const WINE_CERT_PROP_HEADER
*hdr
=
185 (const WINE_CERT_PROP_HEADER
*)buf
;
187 size
-= sizeof(WINE_CERT_PROP_HEADER
);
188 buf
+= sizeof(WINE_CERT_PROP_HEADER
);
191 SetLastError(E_INVALIDARG
);
194 else if (!hdr
->propID
)
196 /* assume a zero prop ID means the data are uninitialized, so
201 else if (hdr
->unknown
!= 1)
203 SetLastError(ERROR_FILE_NOT_FOUND
);
206 else if (hdr
->propID
== propID
)
218 static BOOL
CRYPT_ReadContextProp(
219 const WINE_CONTEXT_INTERFACE
*contextInterface
, const void *context
,
220 const WINE_CERT_PROP_HEADER
*hdr
, const BYTE
*pbElement
, DWORD cbElement
)
224 if (cbElement
< hdr
->cb
)
226 SetLastError(E_INVALIDARG
);
229 else if (hdr
->unknown
!= 1)
231 SetLastError(ERROR_FILE_NOT_FOUND
);
234 else if (hdr
->propID
!= CERT_CERT_PROP_ID
&&
235 hdr
->propID
!= CERT_CRL_PROP_ID
&& hdr
->propID
!= CERT_CTL_PROP_ID
)
237 /* Have to create a blob for most types, but not
242 case CERT_AUTO_ENROLL_PROP_ID
:
243 case CERT_CTL_USAGE_PROP_ID
:
244 case CERT_DESCRIPTION_PROP_ID
:
245 case CERT_FRIENDLY_NAME_PROP_ID
:
246 case CERT_HASH_PROP_ID
:
247 case CERT_KEY_IDENTIFIER_PROP_ID
:
248 case CERT_MD5_HASH_PROP_ID
:
249 case CERT_NEXT_UPDATE_LOCATION_PROP_ID
:
250 case CERT_PUBKEY_ALG_PARA_PROP_ID
:
251 case CERT_PVK_FILE_PROP_ID
:
252 case CERT_SIGNATURE_HASH_PROP_ID
:
253 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID
:
254 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID
:
255 case CERT_ENROLLMENT_PROP_ID
:
256 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID
:
257 case CERT_RENEWAL_PROP_ID
:
259 CRYPT_DATA_BLOB blob
= { hdr
->cb
,
262 ret
= contextInterface
->setProp(context
,
263 hdr
->propID
, 0, &blob
);
266 case CERT_DATE_STAMP_PROP_ID
:
267 ret
= contextInterface
->setProp(context
,
268 hdr
->propID
, 0, pbElement
);
270 case CERT_KEY_PROV_INFO_PROP_ID
:
272 PCRYPT_KEY_PROV_INFO info
=
273 (PCRYPT_KEY_PROV_INFO
)pbElement
;
275 CRYPT_FixKeyProvInfoPointers(info
);
276 ret
= contextInterface
->setProp(context
,
277 hdr
->propID
, 0, pbElement
);
286 /* ignore the context itself */
292 const void *CRYPT_ReadSerializedElement(const BYTE
*pbElement
, DWORD cbElement
,
293 DWORD dwContextTypeFlags
, DWORD
*pdwContentType
)
297 TRACE("(%p, %d, %08x, %p)\n", pbElement
, cbElement
, dwContextTypeFlags
,
302 SetLastError(ERROR_END_OF_MEDIA
);
308 const WINE_CONTEXT_INTERFACE
*contextInterface
= NULL
;
309 const WINE_CERT_PROP_HEADER
*hdr
= NULL
;
315 if (dwContextTypeFlags
== CERT_STORE_ALL_CONTEXT_FLAG
)
317 hdr
= CRYPT_findPropID(pbElement
, cbElement
, CERT_CERT_PROP_ID
);
319 type
= CERT_STORE_CERTIFICATE_CONTEXT
;
322 hdr
= CRYPT_findPropID(pbElement
, cbElement
, CERT_CRL_PROP_ID
);
324 type
= CERT_STORE_CRL_CONTEXT
;
327 hdr
= CRYPT_findPropID(pbElement
, cbElement
,
330 type
= CERT_STORE_CTL_CONTEXT
;
334 else if (dwContextTypeFlags
& CERT_STORE_CERTIFICATE_CONTEXT_FLAG
)
336 hdr
= CRYPT_findPropID(pbElement
, cbElement
, CERT_CERT_PROP_ID
);
337 type
= CERT_STORE_CERTIFICATE_CONTEXT
;
339 else if (dwContextTypeFlags
& CERT_STORE_CRL_CONTEXT_FLAG
)
341 hdr
= CRYPT_findPropID(pbElement
, cbElement
, CERT_CRL_PROP_ID
);
342 type
= CERT_STORE_CRL_CONTEXT
;
344 else if (dwContextTypeFlags
& CERT_STORE_CTL_CONTEXT_FLAG
)
346 hdr
= CRYPT_findPropID(pbElement
, cbElement
, CERT_CTL_PROP_ID
);
347 type
= CERT_STORE_CTL_CONTEXT
;
352 case CERT_STORE_CERTIFICATE_CONTEXT
:
353 contextInterface
= pCertInterface
;
355 case CERT_STORE_CRL_CONTEXT
:
356 contextInterface
= pCRLInterface
;
358 case CERT_STORE_CTL_CONTEXT
:
359 contextInterface
= pCTLInterface
;
362 SetLastError(E_INVALIDARG
);
369 context
= contextInterface
->create(X509_ASN_ENCODING
,
370 (BYTE
*)hdr
+ sizeof(WINE_CERT_PROP_HEADER
), hdr
->cb
);
373 BOOL noMoreProps
= FALSE
;
375 while (!noMoreProps
&& ret
)
377 if (cbElement
< sizeof(WINE_CERT_PROP_HEADER
))
381 const WINE_CERT_PROP_HEADER
*hdr
=
382 (const WINE_CERT_PROP_HEADER
*)pbElement
;
384 TRACE("prop is %d\n", hdr
->propID
);
385 cbElement
-= sizeof(WINE_CERT_PROP_HEADER
);
386 pbElement
+= sizeof(WINE_CERT_PROP_HEADER
);
389 /* Like in CRYPT_findPropID, stop if the propID is zero
394 ret
= CRYPT_ReadContextProp(contextInterface
, context
,
395 hdr
, pbElement
, cbElement
);
396 pbElement
+= hdr
->cb
;
397 cbElement
-= hdr
->cb
;
405 *pdwContentType
= type
;
409 contextInterface
->free(context
);
416 SetLastError(STATUS_ACCESS_VIOLATION
);
423 static const BYTE fileHeader
[] = { 0, 0, 0, 0, 'C','E','R','T' };
425 BOOL
CRYPT_ReadSerializedFile(HANDLE file
, HCERTSTORE store
)
427 BYTE fileHeaderBuf
[sizeof(fileHeader
)];
431 /* Failure reading is non-critical, we'll leave the store empty */
432 ret
= ReadFile(file
, fileHeaderBuf
, sizeof(fileHeaderBuf
), &read
, NULL
);
435 if (!memcmp(fileHeaderBuf
, fileHeader
, read
))
437 WINE_CERT_PROP_HEADER propHdr
;
438 const void *context
= NULL
;
439 const WINE_CONTEXT_INTERFACE
*contextInterface
= NULL
;
444 ret
= ReadFile(file
, &propHdr
, sizeof(propHdr
), &read
, NULL
);
445 if (ret
&& read
== sizeof(propHdr
))
447 if (contextInterface
&& context
&&
448 (propHdr
.propID
== CERT_CERT_PROP_ID
||
449 propHdr
.propID
== CERT_CRL_PROP_ID
||
450 propHdr
.propID
== CERT_CTL_PROP_ID
))
452 /* We have a new context, so free the existing one */
453 contextInterface
->free(context
);
455 if (propHdr
.cb
> bufSize
)
457 /* Not reusing realloc, because the old data aren't
461 buf
= CryptMemAlloc(propHdr
.cb
);
462 bufSize
= propHdr
.cb
;
466 ret
= ReadFile(file
, buf
, propHdr
.cb
, &read
, NULL
);
467 if (ret
&& read
== propHdr
.cb
)
469 if (propHdr
.propID
== CERT_CERT_PROP_ID
)
471 contextInterface
= pCertInterface
;
472 ret
= contextInterface
->addEncodedToStore(store
,
473 X509_ASN_ENCODING
, buf
, read
,
474 CERT_STORE_ADD_NEW
, &context
);
476 else if (propHdr
.propID
== CERT_CRL_PROP_ID
)
478 contextInterface
= pCRLInterface
;
479 ret
= contextInterface
->addEncodedToStore(store
,
480 X509_ASN_ENCODING
, buf
, read
,
481 CERT_STORE_ADD_NEW
, &context
);
483 else if (propHdr
.propID
== CERT_CTL_PROP_ID
)
485 contextInterface
= pCTLInterface
;
486 ret
= contextInterface
->addEncodedToStore(store
,
487 X509_ASN_ENCODING
, buf
, read
,
488 CERT_STORE_ADD_NEW
, &context
);
491 ret
= CRYPT_ReadContextProp(contextInterface
,
492 context
, &propHdr
, buf
, read
);
498 } while (ret
&& read
> 0);
499 if (contextInterface
&& context
)
501 /* Free the last context added */
502 contextInterface
->free(context
);
513 static BOOL WINAPI
CRYPT_SerializeCertNoHash(PCCERT_CONTEXT pCertContext
,
514 DWORD dwFlags
, BYTE
*pbElement
, DWORD
*pcbElement
)
516 return CRYPT_SerializeStoreElement(pCertContext
,
517 pCertContext
->pbCertEncoded
, pCertContext
->cbCertEncoded
,
518 CERT_CERT_PROP_ID
, pCertInterface
, dwFlags
, TRUE
, pbElement
, pcbElement
);
521 static BOOL WINAPI
CRYPT_SerializeCRLNoHash(PCCRL_CONTEXT pCrlContext
,
522 DWORD dwFlags
, BYTE
*pbElement
, DWORD
*pcbElement
)
524 return CRYPT_SerializeStoreElement(pCrlContext
,
525 pCrlContext
->pbCrlEncoded
, pCrlContext
->cbCrlEncoded
,
526 CERT_CRL_PROP_ID
, pCRLInterface
, dwFlags
, TRUE
, pbElement
, pcbElement
);
529 static BOOL WINAPI
CRYPT_SerializeCTLNoHash(PCCTL_CONTEXT pCtlContext
,
530 DWORD dwFlags
, BYTE
*pbElement
, DWORD
*pcbElement
)
532 return CRYPT_SerializeStoreElement(pCtlContext
,
533 pCtlContext
->pbCtlEncoded
, pCtlContext
->cbCtlEncoded
,
534 CERT_CTL_PROP_ID
, pCTLInterface
, dwFlags
, TRUE
, pbElement
, pcbElement
);
537 static BOOL
CRYPT_SerializeContextsToFile(HANDLE file
,
538 const WINE_CONTEXT_INTERFACE
*contextInterface
, HCERTSTORE store
)
540 const void *context
= NULL
;
544 context
= contextInterface
->enumContextsInStore(store
, context
);
550 ret
= contextInterface
->serialize(context
, 0, NULL
, &size
);
552 buf
= CryptMemAlloc(size
);
555 ret
= contextInterface
->serialize(context
, 0, buf
, &size
);
557 ret
= WriteFile(file
, buf
, size
, &size
, NULL
);
563 } while (ret
&& context
!= NULL
);
565 contextInterface
->free(context
);
569 BOOL
CRYPT_WriteSerializedFile(HANDLE file
, HCERTSTORE store
)
571 static const BYTE fileTrailer
[12] = { 0 };
572 WINE_CONTEXT_INTERFACE interface
;
576 SetFilePointer(file
, 0, NULL
, FILE_BEGIN
);
577 ret
= WriteFile(file
, fileHeader
, sizeof(fileHeader
), &size
, NULL
);
580 memcpy(&interface
, pCertInterface
, sizeof(interface
));
581 interface
.serialize
= (SerializeElementFunc
)CRYPT_SerializeCertNoHash
;
582 ret
= CRYPT_SerializeContextsToFile(file
, &interface
, store
);
586 memcpy(&interface
, pCRLInterface
, sizeof(interface
));
587 interface
.serialize
= (SerializeElementFunc
)CRYPT_SerializeCRLNoHash
;
588 ret
= CRYPT_SerializeContextsToFile(file
, &interface
, store
);
592 memcpy(&interface
, pCTLInterface
, sizeof(interface
));
593 interface
.serialize
= (SerializeElementFunc
)CRYPT_SerializeCTLNoHash
;
594 ret
= CRYPT_SerializeContextsToFile(file
, &interface
, store
);
597 ret
= WriteFile(file
, fileTrailer
, sizeof(fileTrailer
), &size
, NULL
);
601 BOOL WINAPI
CertAddSerializedElementToStore(HCERTSTORE hCertStore
,
602 const BYTE
*pbElement
, DWORD cbElement
, DWORD dwAddDisposition
, DWORD dwFlags
,
603 DWORD dwContextTypeFlags
, DWORD
*pdwContentType
, const void **ppvContext
)
609 TRACE("(%p, %p, %d, %08x, %08x, %08x, %p, %p)\n", hCertStore
,
610 pbElement
, cbElement
, dwAddDisposition
, dwFlags
, dwContextTypeFlags
,
611 pdwContentType
, ppvContext
);
613 /* Call the internal function, then delete the hashes. Tests show this
614 * function uses real hash values, not whatever's stored in the hash
617 context
= CRYPT_ReadSerializedElement(pbElement
, cbElement
,
618 dwContextTypeFlags
, &type
);
621 const WINE_CONTEXT_INTERFACE
*contextInterface
= NULL
;
625 case CERT_STORE_CERTIFICATE_CONTEXT
:
626 contextInterface
= pCertInterface
;
628 case CERT_STORE_CRL_CONTEXT
:
629 contextInterface
= pCRLInterface
;
631 case CERT_STORE_CTL_CONTEXT
:
632 contextInterface
= pCTLInterface
;
635 SetLastError(E_INVALIDARG
);
637 if (contextInterface
)
639 contextInterface
->setProp(context
, CERT_HASH_PROP_ID
, 0, NULL
);
640 contextInterface
->setProp(context
, CERT_MD5_HASH_PROP_ID
, 0, NULL
);
641 contextInterface
->setProp(context
, CERT_SIGNATURE_HASH_PROP_ID
, 0,
644 *pdwContentType
= type
;
645 ret
= contextInterface
->addContextToStore(hCertStore
, context
,
646 dwAddDisposition
, ppvContext
);
647 contextInterface
->free(context
);