~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/crypt32/cert.c

Version: ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  1 /*
  2  * Copyright 2004-2006 Juan Lang
  3  *
  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.
  8  *
  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.
 13  *
 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
 17  *
 18  */
 19 
 20 #include <assert.h>
 21 #include <stdarg.h>
 22 
 23 #define NONAMELESSUNION
 24 #include "windef.h"
 25 #include "winbase.h"
 26 #include "wincrypt.h"
 27 #include "winnls.h"
 28 #include "rpc.h"
 29 #include "wine/debug.h"
 30 #include "crypt32_private.h"
 31 
 32 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
 33 
 34 /* Internal version of CertGetCertificateContextProperty that gets properties
 35  * directly from the context (or the context it's linked to, depending on its
 36  * type.) Doesn't handle special-case properties, since they are handled by
 37  * CertGetCertificateContextProperty, and are particular to the store in which
 38  * the property exists (which is separate from the context.)
 39  */
 40 static BOOL WINAPI CertContext_GetProperty(void *context, DWORD dwPropId,
 41  void *pvData, DWORD *pcbData);
 42 
 43 /* Internal version of CertSetCertificateContextProperty that sets properties
 44  * directly on the context (or the context it's linked to, depending on its
 45  * type.) Doesn't handle special cases, since they're handled by
 46  * CertSetCertificateContextProperty anyway.
 47  */
 48 static BOOL WINAPI CertContext_SetProperty(void *context, DWORD dwPropId,
 49  DWORD dwFlags, const void *pvData);
 50 
 51 BOOL WINAPI CertAddEncodedCertificateToStore(HCERTSTORE hCertStore,
 52  DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded,
 53  DWORD dwAddDisposition, PCCERT_CONTEXT *ppCertContext)
 54 {
 55     PCCERT_CONTEXT cert = CertCreateCertificateContext(dwCertEncodingType,
 56      pbCertEncoded, cbCertEncoded);
 57     BOOL ret;
 58 
 59     TRACE("(%p, %08x, %p, %d, %08x, %p)\n", hCertStore, dwCertEncodingType,
 60      pbCertEncoded, cbCertEncoded, dwAddDisposition, ppCertContext);
 61 
 62     if (cert)
 63     {
 64         ret = CertAddCertificateContextToStore(hCertStore, cert,
 65          dwAddDisposition, ppCertContext);
 66         CertFreeCertificateContext(cert);
 67     }
 68     else
 69         ret = FALSE;
 70     return ret;
 71 }
 72 
 73 PCCERT_CONTEXT WINAPI CertCreateCertificateContext(DWORD dwCertEncodingType,
 74  const BYTE *pbCertEncoded, DWORD cbCertEncoded)
 75 {
 76     PCERT_CONTEXT cert = NULL;
 77     BOOL ret;
 78     PCERT_INFO certInfo = NULL;
 79     DWORD size = 0;
 80 
 81     TRACE("(%08x, %p, %d)\n", dwCertEncodingType, pbCertEncoded,
 82      cbCertEncoded);
 83 
 84     ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT_TO_BE_SIGNED,
 85      pbCertEncoded, cbCertEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL,
 86      (BYTE *)&certInfo, &size);
 87     if (ret)
 88     {
 89         BYTE *data = NULL;
 90 
 91         cert = (PCERT_CONTEXT)Context_CreateDataContext(sizeof(CERT_CONTEXT));
 92         if (!cert)
 93             goto end;
 94         data = CryptMemAlloc(cbCertEncoded);
 95         if (!data)
 96         {
 97             CryptMemFree(cert);
 98             cert = NULL;
 99             goto end;
100         }
101         memcpy(data, pbCertEncoded, cbCertEncoded);
102         cert->dwCertEncodingType = dwCertEncodingType;
103         cert->pbCertEncoded      = data;
104         cert->cbCertEncoded      = cbCertEncoded;
105         cert->pCertInfo          = certInfo;
106         cert->hCertStore         = 0;
107     }
108 
109 end:
110     return (PCCERT_CONTEXT)cert;
111 }
112 
113 PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext(
114  PCCERT_CONTEXT pCertContext)
115 {
116     TRACE("(%p)\n", pCertContext);
117     Context_AddRef((void *)pCertContext, sizeof(CERT_CONTEXT));
118     return pCertContext;
119 }
120 
121 static void CertDataContext_Free(void *context)
122 {
123     PCERT_CONTEXT certContext = (PCERT_CONTEXT)context;
124 
125     CryptMemFree(certContext->pbCertEncoded);
126     LocalFree(certContext->pCertInfo);
127 }
128 
129 BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext)
130 {
131     TRACE("(%p)\n", pCertContext);
132 
133     if (pCertContext)
134         Context_Release((void *)pCertContext, sizeof(CERT_CONTEXT),
135          CertDataContext_Free);
136     return TRUE;
137 }
138 
139 DWORD WINAPI CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext,
140  DWORD dwPropId)
141 {
142     PCONTEXT_PROPERTY_LIST properties = Context_GetProperties(
143      (void *)pCertContext, sizeof(CERT_CONTEXT));
144     DWORD ret;
145 
146     TRACE("(%p, %d)\n", pCertContext, dwPropId);
147 
148     if (properties)
149         ret = ContextPropertyList_EnumPropIDs(properties, dwPropId);
150     else
151         ret = 0;
152     return ret;
153 }
154 
155 static BOOL CertContext_GetHashProp(void *context, DWORD dwPropId,
156  ALG_ID algID, const BYTE *toHash, DWORD toHashLen, void *pvData,
157  DWORD *pcbData)
158 {
159     BOOL ret = CryptHashCertificate(0, algID, 0, toHash, toHashLen, pvData,
160      pcbData);
161     if (ret && pvData)
162     {
163         CRYPT_DATA_BLOB blob = { *pcbData, pvData };
164 
165         ret = CertContext_SetProperty(context, dwPropId, 0, &blob);
166     }
167     return ret;
168 }
169 
170 static BOOL CertContext_CopyParam(void *pvData, DWORD *pcbData, const void *pb,
171  DWORD cb)
172 {
173     BOOL ret = TRUE;
174 
175     if (!pvData)
176         *pcbData = cb;
177     else if (*pcbData < cb)
178     {
179         SetLastError(ERROR_MORE_DATA);
180         *pcbData = cb;
181         ret = FALSE;
182     }
183     else
184     {
185         memcpy(pvData, pb, cb);
186         *pcbData = cb;
187     }
188     return ret;
189 }
190 
191 static BOOL WINAPI CertContext_GetProperty(void *context, DWORD dwPropId,
192  void *pvData, DWORD *pcbData)
193 {
194     PCCERT_CONTEXT pCertContext = (PCCERT_CONTEXT)context;
195     PCONTEXT_PROPERTY_LIST properties =
196      Context_GetProperties(context, sizeof(CERT_CONTEXT));
197     BOOL ret;
198     CRYPT_DATA_BLOB blob;
199 
200     TRACE("(%p, %d, %p, %p)\n", context, dwPropId, pvData, pcbData);
201 
202     if (properties)
203         ret = ContextPropertyList_FindProperty(properties, dwPropId, &blob);
204     else
205         ret = FALSE;
206     if (ret)
207         ret = CertContext_CopyParam(pvData, pcbData, blob.pbData, blob.cbData);
208     else
209     {
210         /* Implicit properties */
211         switch (dwPropId)
212         {
213         case CERT_SHA1_HASH_PROP_ID:
214             ret = CertContext_GetHashProp(context, dwPropId, CALG_SHA1,
215              pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, pvData,
216              pcbData);
217             break;
218         case CERT_MD5_HASH_PROP_ID:
219             ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5,
220              pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, pvData,
221              pcbData);
222             break;
223         case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
224             ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5,
225              pCertContext->pCertInfo->Subject.pbData,
226              pCertContext->pCertInfo->Subject.cbData,
227              pvData, pcbData);
228             break;
229         case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
230             ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5,
231              pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
232              pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData,
233              pvData, pcbData);
234             break;
235         case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID:
236             ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5,
237              pCertContext->pCertInfo->SerialNumber.pbData,
238              pCertContext->pCertInfo->SerialNumber.cbData,
239              pvData, pcbData);
240             break;
241         case CERT_SIGNATURE_HASH_PROP_ID:
242             FIXME("CERT_SIGNATURE_HASH_PROP_ID unimplemented\n");
243             SetLastError(CRYPT_E_NOT_FOUND);
244             break;
245         case CERT_KEY_IDENTIFIER_PROP_ID:
246         {
247             PCERT_EXTENSION ext = CertFindExtension(
248              szOID_SUBJECT_KEY_IDENTIFIER, pCertContext->pCertInfo->cExtension,
249              pCertContext->pCertInfo->rgExtension);
250 
251             if (ext)
252             {
253                 CRYPT_DATA_BLOB value;
254                 DWORD size = sizeof(value);
255 
256                 ret = CryptDecodeObjectEx(X509_ASN_ENCODING,
257                  szOID_SUBJECT_KEY_IDENTIFIER, ext->Value.pbData,
258                  ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL, &value,
259                  &size);
260                 if (ret)
261                 {
262                     ret = CertContext_CopyParam(pvData, pcbData, value.pbData,
263                      value.cbData);
264                     CertContext_SetProperty(context, dwPropId, 0, &value);
265                 }
266             }
267             else
268                 SetLastError(ERROR_INVALID_DATA);
269             break;
270         }
271         default:
272             SetLastError(CRYPT_E_NOT_FOUND);
273         }
274     }
275     TRACE("returning %d\n", ret);
276     return ret;
277 }
278 
279 void CRYPT_FixKeyProvInfoPointers(PCRYPT_KEY_PROV_INFO info)
280 {
281     DWORD i, containerLen, provNameLen;
282     LPBYTE data = (LPBYTE)info + sizeof(CRYPT_KEY_PROV_INFO);
283 
284     info->pwszContainerName = (LPWSTR)data;
285     containerLen = (lstrlenW(info->pwszContainerName) + 1) * sizeof(WCHAR);
286     data += containerLen;
287 
288     info->pwszProvName = (LPWSTR)data;
289     provNameLen = (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR);
290     data += provNameLen;
291 
292     info->rgProvParam = (PCRYPT_KEY_PROV_PARAM)data;
293     data += info->cProvParam * sizeof(CRYPT_KEY_PROV_PARAM);
294 
295     for (i = 0; i < info->cProvParam; i++)
296     {
297         info->rgProvParam[i].pbData = data;
298         data += info->rgProvParam[i].cbData;
299     }
300 }
301 
302 BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
303  DWORD dwPropId, void *pvData, DWORD *pcbData)
304 {
305     BOOL ret;
306 
307     TRACE("(%p, %d, %p, %p)\n", pCertContext, dwPropId, pvData, pcbData);
308 
309     switch (dwPropId)
310     {
311     case 0:
312     case CERT_CERT_PROP_ID:
313     case CERT_CRL_PROP_ID:
314     case CERT_CTL_PROP_ID:
315         SetLastError(E_INVALIDARG);
316         ret = FALSE;
317         break;
318     case CERT_ACCESS_STATE_PROP_ID:
319         if (pCertContext->hCertStore)
320             ret = CertGetStoreProperty(pCertContext->hCertStore, dwPropId,
321              pvData, pcbData);
322         else
323         {
324             DWORD state = 0;
325 
326             ret = CertContext_CopyParam(pvData, pcbData, &state, sizeof(state));
327         }
328         break;
329     case CERT_KEY_PROV_HANDLE_PROP_ID:
330     {
331         CERT_KEY_CONTEXT keyContext;
332         DWORD size = sizeof(keyContext);
333 
334         ret = CertContext_GetProperty((void *)pCertContext,
335          CERT_KEY_CONTEXT_PROP_ID, &keyContext, &size);
336         if (ret)
337             ret = CertContext_CopyParam(pvData, pcbData, &keyContext.hCryptProv,
338              sizeof(keyContext.hCryptProv));
339         break;
340     }
341     case CERT_KEY_PROV_INFO_PROP_ID:
342         ret = CertContext_GetProperty((void *)pCertContext, dwPropId, pvData,
343          pcbData);
344         if (ret && pvData)
345             CRYPT_FixKeyProvInfoPointers((PCRYPT_KEY_PROV_INFO)pvData);
346         break;
347     default:
348         ret = CertContext_GetProperty((void *)pCertContext, dwPropId, pvData,
349          pcbData);
350     }
351 
352     TRACE("returning %d\n", ret);
353     return ret;
354 }
355 
356 /* Copies key provider info from from into to, where to is assumed to be a
357  * contiguous buffer of memory large enough for from and all its associated
358  * data, but whose pointers are uninitialized.
359  * Upon return, to contains a contiguous copy of from, packed in the following
360  * order:
361  * - CRYPT_KEY_PROV_INFO
362  * - pwszContainerName
363  * - pwszProvName
364  * - rgProvParam[0]...
365  */
366 static void CRYPT_CopyKeyProvInfo(PCRYPT_KEY_PROV_INFO to,
367  const CRYPT_KEY_PROV_INFO *from)
368 {
369     DWORD i;
370     LPBYTE nextData = (LPBYTE)to + sizeof(CRYPT_KEY_PROV_INFO);
371 
372     if (from->pwszContainerName)
373     {
374         to->pwszContainerName = (LPWSTR)nextData;
375         lstrcpyW(to->pwszContainerName, from->pwszContainerName);
376         nextData += (lstrlenW(from->pwszContainerName) + 1) * sizeof(WCHAR);
377     }
378     else
379         to->pwszContainerName = NULL;
380     if (from->pwszProvName)
381     {
382         to->pwszProvName = (LPWSTR)nextData;
383         lstrcpyW(to->pwszProvName, from->pwszProvName);
384         nextData += (lstrlenW(from->pwszProvName) + 1) * sizeof(WCHAR);
385     }
386     else
387         to->pwszProvName = NULL;
388     to->dwProvType = from->dwProvType;
389     to->dwFlags = from->dwFlags;
390     to->cProvParam = from->cProvParam;
391     to->rgProvParam = (PCRYPT_KEY_PROV_PARAM)nextData;
392     nextData += to->cProvParam * sizeof(CRYPT_KEY_PROV_PARAM);
393     to->dwKeySpec = from->dwKeySpec;
394     for (i = 0; i < to->cProvParam; i++)
395     {
396         memcpy(&to->rgProvParam[i], &from->rgProvParam[i],
397          sizeof(CRYPT_KEY_PROV_PARAM));
398         to->rgProvParam[i].pbData = nextData;
399         memcpy(to->rgProvParam[i].pbData, from->rgProvParam[i].pbData,
400          from->rgProvParam[i].cbData);
401         nextData += from->rgProvParam[i].cbData;
402     }
403 }
404 
405 static BOOL CertContext_SetKeyProvInfoProperty(PCONTEXT_PROPERTY_LIST properties,
406  const CRYPT_KEY_PROV_INFO *info)
407 {
408     BOOL ret;
409     LPBYTE buf = NULL;
410     DWORD size = sizeof(CRYPT_KEY_PROV_INFO), i, containerSize, provNameSize;
411 
412     if (info->pwszContainerName)
413         containerSize = (lstrlenW(info->pwszContainerName) + 1) * sizeof(WCHAR);
414     else
415         containerSize = 0;
416     if (info->pwszProvName)
417         provNameSize = (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR);
418     else
419         provNameSize = 0;
420     size += containerSize + provNameSize;
421     for (i = 0; i < info->cProvParam; i++)
422         size += sizeof(CRYPT_KEY_PROV_PARAM) + info->rgProvParam[i].cbData;
423     buf = CryptMemAlloc(size);
424     if (buf)
425     {
426         CRYPT_CopyKeyProvInfo((PCRYPT_KEY_PROV_INFO)buf, info);
427         ret = ContextPropertyList_SetProperty(properties,
428          CERT_KEY_PROV_INFO_PROP_ID, buf, size);
429         CryptMemFree(buf);
430     }
431     else
432         ret = FALSE;
433     return ret;
434 }
435 
436 static BOOL WINAPI CertContext_SetProperty(void *context, DWORD dwPropId,
437  DWORD dwFlags, const void *pvData)
438 {
439     PCONTEXT_PROPERTY_LIST properties =
440      Context_GetProperties(context, sizeof(CERT_CONTEXT));
441     BOOL ret;
442 
443     TRACE("(%p, %d, %08x, %p)\n", context, dwPropId, dwFlags, pvData);
444 
445     if (!properties)
446         ret = FALSE;
447     else
448     {
449         switch (dwPropId)
450         {
451         case CERT_AUTO_ENROLL_PROP_ID:
452         case CERT_CTL_USAGE_PROP_ID: /* same as CERT_ENHKEY_USAGE_PROP_ID */
453         case CERT_DESCRIPTION_PROP_ID:
454         case CERT_FRIENDLY_NAME_PROP_ID:
455         case CERT_HASH_PROP_ID:
456         case CERT_KEY_IDENTIFIER_PROP_ID:
457         case CERT_MD5_HASH_PROP_ID:
458         case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
459         case CERT_PUBKEY_ALG_PARA_PROP_ID:
460         case CERT_PVK_FILE_PROP_ID:
461         case CERT_SIGNATURE_HASH_PROP_ID:
462         case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
463         case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
464         case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
465         case CERT_ENROLLMENT_PROP_ID:
466         case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
467         case CERT_RENEWAL_PROP_ID:
468         {
469             if (pvData)
470             {
471                 const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvData;
472 
473                 ret = ContextPropertyList_SetProperty(properties, dwPropId,
474                  blob->pbData, blob->cbData);
475             }
476             else
477             {
478                 ContextPropertyList_RemoveProperty(properties, dwPropId);
479                 ret = TRUE;
480             }
481             break;
482         }
483         case CERT_DATE_STAMP_PROP_ID:
484             if (pvData)
485                 ret = ContextPropertyList_SetProperty(properties, dwPropId,
486                  (const BYTE *)pvData, sizeof(FILETIME));
487             else
488             {
489                 ContextPropertyList_RemoveProperty(properties, dwPropId);
490                 ret = TRUE;
491             }
492             break;
493         case CERT_KEY_CONTEXT_PROP_ID:
494         {
495             if (pvData)
496             {
497                 const CERT_KEY_CONTEXT *keyContext = (const CERT_KEY_CONTEXT *)pvData;
498 
499                 if (keyContext->cbSize != sizeof(CERT_KEY_CONTEXT))
500                 {
501                     SetLastError(E_INVALIDARG);
502                     ret = FALSE;
503                 }
504                 else
505                     ret = ContextPropertyList_SetProperty(properties, dwPropId,
506                      (const BYTE *)keyContext, keyContext->cbSize);
507             }
508             else
509             {
510                 ContextPropertyList_RemoveProperty(properties, dwPropId);
511                 ret = TRUE;
512             }
513             break;
514         }
515         case CERT_KEY_PROV_INFO_PROP_ID:
516             if (pvData)
517                 ret = CertContext_SetKeyProvInfoProperty(properties,
518                  (const CRYPT_KEY_PROV_INFO *)pvData);
519             else
520             {
521                 ContextPropertyList_RemoveProperty(properties, dwPropId);
522                 ret = TRUE;
523             }
524             break;
525         case CERT_KEY_PROV_HANDLE_PROP_ID:
526         {
527             CERT_KEY_CONTEXT keyContext;
528             DWORD size = sizeof(keyContext);
529 
530             ret = CertContext_GetProperty(context, CERT_KEY_CONTEXT_PROP_ID,
531              &keyContext, &size);
532             if (ret)
533             {
534                 if (!(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
535                     CryptReleaseContext(keyContext.hCryptProv, 0);
536                 if (pvData)
537                     keyContext.hCryptProv = *(const HCRYPTPROV *)pvData;
538                 else
539                     keyContext.hCryptProv = 0;
540                 ret = CertContext_SetProperty(context, CERT_KEY_CONTEXT_PROP_ID,
541                  0, &keyContext);
542             }
543             break;
544         }
545         default:
546             FIXME("%d: stub\n", dwPropId);
547             ret = FALSE;
548         }
549     }
550     TRACE("returning %d\n", ret);
551     return ret;
552 }
553 
554 BOOL WINAPI CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
555  DWORD dwPropId, DWORD dwFlags, const void *pvData)
556 {
557     BOOL ret;
558 
559     TRACE("(%p, %d, %08x, %p)\n", pCertContext, dwPropId, dwFlags, pvData);
560 
561     /* Handle special cases for "read-only"/invalid prop IDs.  Windows just
562      * crashes on most of these, I'll be safer.
563      */
564     switch (dwPropId)
565     {
566     case 0:
567     case CERT_ACCESS_STATE_PROP_ID:
568     case CERT_CERT_PROP_ID:
569     case CERT_CRL_PROP_ID:
570     case CERT_CTL_PROP_ID:
571         SetLastError(E_INVALIDARG);
572         return FALSE;
573     }
574     ret = CertContext_SetProperty((void *)pCertContext, dwPropId, dwFlags,
575      pvData);
576     TRACE("returning %d\n", ret);
577     return ret;
578 }
579 
580 /* Acquires the private key using the key provider info, retrieving info from
581  * the certificate if info is NULL.  The acquired provider is returned in
582  * *phCryptProv, and the key spec for the provider is returned in *pdwKeySpec.
583  */
584 static BOOL CRYPT_AcquirePrivateKeyFromProvInfo(PCCERT_CONTEXT pCert,
585  PCRYPT_KEY_PROV_INFO info, HCRYPTPROV *phCryptProv, DWORD *pdwKeySpec)
586 {
587     DWORD size = 0;
588     BOOL allocated = FALSE, ret = TRUE;
589 
590     if (!info)
591     {
592         ret = CertGetCertificateContextProperty(pCert,
593          CERT_KEY_PROV_INFO_PROP_ID, 0, &size);
594         if (ret)
595         {
596             info = (PCRYPT_KEY_PROV_INFO)HeapAlloc(GetProcessHeap(), 0, size);
597             if (info)
598             {
599                 ret = CertGetCertificateContextProperty(pCert,
600                  CERT_KEY_PROV_INFO_PROP_ID, info, &size);
601                 allocated = TRUE;
602             }
603         }
604         else
605             SetLastError(CRYPT_E_NO_KEY_PROPERTY);
606     }
607     if (ret)
608     {
609         ret = CryptAcquireContextW(phCryptProv, info->pwszContainerName,
610          info->pwszProvName, info->dwProvType, 0);
611         if (ret)
612         {
613             DWORD i;
614 
615             for (i = 0; i < info->cProvParam; i++)
616             {
617                 CryptSetProvParam(*phCryptProv,
618                  info->rgProvParam[i].dwParam, info->rgProvParam[i].pbData,
619                  info->rgProvParam[i].dwFlags);
620             }
621             *pdwKeySpec = info->dwKeySpec;
622         }
623         else
624             SetLastError(CRYPT_E_NO_KEY_PROPERTY);
625     }
626     if (allocated)
627         HeapFree(GetProcessHeap(), 0, info);
628     return ret;
629 }
630 
631 BOOL WINAPI CryptAcquireCertificatePrivateKey(PCCERT_CONTEXT pCert,
632  DWORD dwFlags, void *pvReserved, HCRYPTPROV_OR_NCRYPT_KEY_HANDLE *phCryptProv,
633  DWORD *pdwKeySpec, BOOL *pfCallerFreeProv)
634 {
635     BOOL ret = FALSE, cache = FALSE;
636     PCRYPT_KEY_PROV_INFO info = NULL;
637     CERT_KEY_CONTEXT keyContext;
638     DWORD size;
639 
640     TRACE("(%p, %08x, %p, %p, %p, %p)\n", pCert, dwFlags, pvReserved,
641      phCryptProv, pdwKeySpec, pfCallerFreeProv);
642 
643     if (dwFlags & CRYPT_ACQUIRE_USE_PROV_INFO_FLAG)
644     {
645         DWORD size = 0;
646 
647         ret = CertGetCertificateContextProperty(pCert,
648          CERT_KEY_PROV_INFO_PROP_ID, 0, &size);
649         if (ret)
650         {
651             info = (PCRYPT_KEY_PROV_INFO)HeapAlloc(
652              GetProcessHeap(), 0, size);
653             ret = CertGetCertificateContextProperty(pCert,
654              CERT_KEY_PROV_INFO_PROP_ID, info, &size);
655             if (ret)
656                 cache = info->dwFlags & CERT_SET_KEY_CONTEXT_PROP_ID;
657         }
658     }
659     else if (dwFlags & CRYPT_ACQUIRE_CACHE_FLAG)
660         cache = TRUE;
661     *phCryptProv = 0;
662     if (cache)
663     {
664         size = sizeof(keyContext);
665         ret = CertGetCertificateContextProperty(pCert, CERT_KEY_CONTEXT_PROP_ID,
666          &keyContext, &size);
667         if (ret)
668         {
669             *phCryptProv = keyContext.hCryptProv;
670             if (pdwKeySpec)
671                 *pdwKeySpec = keyContext.dwKeySpec;
672             if (pfCallerFreeProv)
673                 *pfCallerFreeProv = !cache;
674         }
675     }
676     if (!*phCryptProv)
677     {
678         ret = CRYPT_AcquirePrivateKeyFromProvInfo(pCert, info,
679          &keyContext.hCryptProv, &keyContext.dwKeySpec);
680         if (ret)
681         {
682             *phCryptProv = keyContext.hCryptProv;
683             if (pdwKeySpec)
684                 *pdwKeySpec = keyContext.dwKeySpec;
685             if (cache)
686             {
687                 keyContext.cbSize = sizeof(keyContext);
688                 if (CertSetCertificateContextProperty(pCert,
689                  CERT_KEY_CONTEXT_PROP_ID, 0, &keyContext))
690                 {
691                     if (pfCallerFreeProv)
692                         *pfCallerFreeProv = FALSE;
693                 }
694             }
695             else
696             {
697                 if (pfCallerFreeProv)
698                     *pfCallerFreeProv = TRUE;
699             }
700         }
701     }
702     HeapFree(GetProcessHeap(), 0, info);
703     return ret;
704 }
705 
706 BOOL WINAPI CertCompareCertificate(DWORD dwCertEncodingType,
707  PCERT_INFO pCertId1, PCERT_INFO pCertId2)
708 {
709     BOOL ret;
710 
711     TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pCertId1, pCertId2);
712 
713     ret = CertCompareCertificateName(dwCertEncodingType, &pCertId1->Issuer,
714      &pCertId2->Issuer) && CertCompareIntegerBlob(&pCertId1->SerialNumber,
715      &pCertId2->SerialNumber);
716     TRACE("returning %d\n", ret);
717     return ret;
718 }
719 
720 BOOL WINAPI CertCompareCertificateName(DWORD dwCertEncodingType,
721  PCERT_NAME_BLOB pCertName1, PCERT_NAME_BLOB pCertName2)
722 {
723     BOOL ret;
724 
725     TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pCertName1, pCertName2);
726 
727     if (pCertName1->cbData == pCertName2->cbData)
728     {
729         if (pCertName1->cbData)
730             ret = !memcmp(pCertName1->pbData, pCertName2->pbData,
731              pCertName1->cbData);
732         else
733             ret = TRUE;
734     }
735     else
736         ret = FALSE;
737     TRACE("returning %d\n", ret);
738     return ret;
739 }
740 
741 /* Returns the number of significant bytes in pInt, where a byte is
742  * insignificant if it's a leading 0 for positive numbers or a leading 0xff
743  * for negative numbers.  pInt is assumed to be little-endian.
744  */
745 static DWORD CRYPT_significantBytes(const CRYPT_INTEGER_BLOB *pInt)
746 {
747     DWORD ret = pInt->cbData;
748 
749     while (ret > 1)
750     {
751         if (pInt->pbData[ret - 2] <= 0x7f && pInt->pbData[ret - 1] == 0)
752             ret--;
753         else if (pInt->pbData[ret - 2] >= 0x80 && pInt->pbData[ret - 1] == 0xff)
754             ret--;
755         else
756             break;
757     }
758     return ret;
759 }
760 
761 BOOL WINAPI CertCompareIntegerBlob(PCRYPT_INTEGER_BLOB pInt1,
762  PCRYPT_INTEGER_BLOB pInt2)
763 {
764     BOOL ret;
765     DWORD cb1, cb2;
766 
767     TRACE("(%p, %p)\n", pInt1, pInt2);
768 
769     cb1 = CRYPT_significantBytes(pInt1);
770     cb2 = CRYPT_significantBytes(pInt2);
771     if (cb1 == cb2)
772     {
773         if (cb1)
774             ret = !memcmp(pInt1->pbData, pInt2->pbData, cb1);
775         else
776             ret = TRUE;
777     }
778     else
779         ret = FALSE;
780     TRACE("returning %d\n", ret);
781     return ret;
782 }
783 
784 BOOL WINAPI CertComparePublicKeyInfo(DWORD dwCertEncodingType,
785  PCERT_PUBLIC_KEY_INFO pPublicKey1, PCERT_PUBLIC_KEY_INFO pPublicKey2)
786 {
787     BOOL ret;
788 
789     TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pPublicKey1, pPublicKey2);
790 
791     if (pPublicKey1->PublicKey.cbData == pPublicKey2->PublicKey.cbData &&
792      pPublicKey1->PublicKey.cUnusedBits == pPublicKey2->PublicKey.cUnusedBits)
793     {
794         if (pPublicKey2->PublicKey.cbData)
795             ret = !memcmp(pPublicKey1->PublicKey.pbData,
796              pPublicKey2->PublicKey.pbData, pPublicKey1->PublicKey.cbData);
797         else
798             ret = TRUE;
799     }
800     else
801         ret = FALSE;
802     return ret;
803 }
804 
805 DWORD WINAPI CertGetPublicKeyLength(DWORD dwCertEncodingType,
806  PCERT_PUBLIC_KEY_INFO pPublicKey)
807 {
808     DWORD len = 0;
809 
810     TRACE("(%08x, %p)\n", dwCertEncodingType, pPublicKey);
811 
812     if (dwCertEncodingType != X509_ASN_ENCODING)
813     {
814         SetLastError(ERROR_FILE_NOT_FOUND);
815         return 0;
816     }
817     if (pPublicKey->Algorithm.pszObjId &&
818      !strcmp(pPublicKey->Algorithm.pszObjId, szOID_RSA_DH))
819     {
820         FIXME("unimplemented for DH public keys\n");
821         SetLastError(CRYPT_E_ASN1_BADTAG);
822     }
823     else
824     {
825         DWORD size;
826         PBYTE buf;
827         BOOL ret = CryptDecodeObjectEx(dwCertEncodingType,
828          RSA_CSP_PUBLICKEYBLOB, pPublicKey->PublicKey.pbData,
829          pPublicKey->PublicKey.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &buf,
830          &size);
831 
832         if (ret)
833         {
834             RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(buf + sizeof(BLOBHEADER));
835 
836             len = rsaPubKey->bitlen;
837             LocalFree(buf);
838         }
839     }
840     return len;
841 }
842 
843 typedef BOOL (*CertCompareFunc)(PCCERT_CONTEXT pCertContext, DWORD dwType,
844  DWORD dwFlags, const void *pvPara);
845 
846 static BOOL compare_cert_any(PCCERT_CONTEXT pCertContext, DWORD dwType,
847  DWORD dwFlags, const void *pvPara)
848 {
849     return TRUE;
850 }
851 
852 static BOOL compare_cert_by_md5_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
853  DWORD dwFlags, const void *pvPara)
854 {
855     BOOL ret;
856     BYTE hash[16];
857     DWORD size = sizeof(hash);
858 
859     ret = CertGetCertificateContextProperty(pCertContext,
860      CERT_MD5_HASH_PROP_ID, hash, &size);
861     if (ret)
862     {
863         const CRYPT_HASH_BLOB *pHash = (const CRYPT_HASH_BLOB *)pvPara;
864 
865         if (size == pHash->cbData)
866             ret = !memcmp(pHash->pbData, hash, size);
867         else
868             ret = FALSE;
869     }
870     return ret;
871 }
872 
873 static BOOL compare_cert_by_sha1_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
874  DWORD dwFlags, const void *pvPara)
875 {
876     BOOL ret;
877     BYTE hash[20];
878     DWORD size = sizeof(hash);
879 
880     ret = CertGetCertificateContextProperty(pCertContext,
881      CERT_SHA1_HASH_PROP_ID, hash, &size);
882     if (ret)
883     {
884         const CRYPT_HASH_BLOB *pHash = (const CRYPT_HASH_BLOB *)pvPara;
885 
886         if (size == pHash->cbData)
887             ret = !memcmp(pHash->pbData, hash, size);
888         else
889             ret = FALSE;
890     }
891     return ret;
892 }
893 
894 static BOOL compare_cert_by_name(PCCERT_CONTEXT pCertContext, DWORD dwType,
895  DWORD dwFlags, const void *pvPara)
896 {
897     CERT_NAME_BLOB *blob = (CERT_NAME_BLOB *)pvPara, *toCompare;
898     BOOL ret;
899 
900     if (dwType & CERT_INFO_SUBJECT_FLAG)
901         toCompare = &pCertContext->pCertInfo->Subject;
902     else
903         toCompare = &pCertContext->pCertInfo->Issuer;
904     ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
905      toCompare, blob);
906     return ret;
907 }
908 
909 static BOOL compare_cert_by_subject_cert(PCCERT_CONTEXT pCertContext,
910  DWORD dwType, DWORD dwFlags, const void *pvPara)
911 {
912     CERT_INFO *pCertInfo = (CERT_INFO *)pvPara;
913     BOOL ret;
914 
915     /* Matching serial number and subject match.. */
916     ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
917      &pCertInfo->Issuer, &pCertContext->pCertInfo->Subject);
918     if (ret)
919         ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber,
920          &pCertInfo->SerialNumber);
921     else
922     {
923         /* failing that, if the serial number and issuer match, we match */
924         ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber,
925          &pCertInfo->SerialNumber);
926         if (ret)
927             ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
928              &pCertInfo->Issuer, &pCertContext->pCertInfo->Issuer);
929     }
930     TRACE("returning %d\n", ret);
931     return ret;
932 }
933 
934 static BOOL compare_cert_by_cert_id(PCCERT_CONTEXT pCertContext, DWORD dwType,
935  DWORD dwFlags, const void *pvPara)
936 {
937     CERT_ID *id = (CERT_ID *)pvPara;
938     BOOL ret;
939 
940     switch (id->dwIdChoice)
941     {
942     case CERT_ID_ISSUER_SERIAL_NUMBER:
943         ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
944          &pCertContext->pCertInfo->Issuer, &id->u.IssuerSerialNumber.Issuer);
945         if (ret)
946             ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber,
947              &id->u.IssuerSerialNumber.SerialNumber);
948         break;
949     case CERT_ID_SHA1_HASH:
950         ret = compare_cert_by_sha1_hash(pCertContext, dwType, dwFlags,
951          &id->u.HashId);
952         break;
953     case CERT_ID_KEY_IDENTIFIER:
954     {
955         DWORD size = 0;
956 
957         ret = CertGetCertificateContextProperty(pCertContext,
958          CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size);
959         if (ret && size == id->u.KeyId.cbData)
960         {
961             LPBYTE buf = CryptMemAlloc(size);
962 
963             if (buf)
964             {
965                 CertGetCertificateContextProperty(pCertContext,
966