ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

cert.c
Go to the documentation of this file.
00001 /*
00002  * Copyright 2004-2006 Juan Lang
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Lesser General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2.1 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Lesser General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Lesser General Public
00015  * License along with this library; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00017  *
00018  */
00019 
00020 #include <assert.h>
00021 #include <stdarg.h>
00022 
00023 #define NONAMELESSUNION
00024 #include "windef.h"
00025 #include "winbase.h"
00026 #include "wincrypt.h"
00027 #include "winnls.h"
00028 #include "rpc.h"
00029 #include "wine/debug.h"
00030 #include "wine/unicode.h"
00031 #include "crypt32_private.h"
00032 
00033 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
00034 
00035 /* Internal version of CertGetCertificateContextProperty that gets properties
00036  * directly from the context (or the context it's linked to, depending on its
00037  * type.) Doesn't handle special-case properties, since they are handled by
00038  * CertGetCertificateContextProperty, and are particular to the store in which
00039  * the property exists (which is separate from the context.)
00040  */
00041 static BOOL CertContext_GetProperty(void *context, DWORD dwPropId,
00042  void *pvData, DWORD *pcbData);
00043 
00044 /* Internal version of CertSetCertificateContextProperty that sets properties
00045  * directly on the context (or the context it's linked to, depending on its
00046  * type.) Doesn't handle special cases, since they're handled by
00047  * CertSetCertificateContextProperty anyway.
00048  */
00049 static BOOL CertContext_SetProperty(void *context, DWORD dwPropId,
00050  DWORD dwFlags, const void *pvData);
00051 
00052 BOOL WINAPI CertAddEncodedCertificateToStore(HCERTSTORE hCertStore,
00053  DWORD dwCertEncodingType, const BYTE *pbCertEncoded, DWORD cbCertEncoded,
00054  DWORD dwAddDisposition, PCCERT_CONTEXT *ppCertContext)
00055 {
00056     PCCERT_CONTEXT cert = CertCreateCertificateContext(dwCertEncodingType,
00057      pbCertEncoded, cbCertEncoded);
00058     BOOL ret;
00059 
00060     TRACE("(%p, %08x, %p, %d, %08x, %p)\n", hCertStore, dwCertEncodingType,
00061      pbCertEncoded, cbCertEncoded, dwAddDisposition, ppCertContext);
00062 
00063     if (cert)
00064     {
00065         ret = CertAddCertificateContextToStore(hCertStore, cert,
00066          dwAddDisposition, ppCertContext);
00067         CertFreeCertificateContext(cert);
00068     }
00069     else
00070         ret = FALSE;
00071     return ret;
00072 }
00073 
00074 BOOL WINAPI CertAddEncodedCertificateToSystemStoreA(LPCSTR pszCertStoreName,
00075  const BYTE *pbCertEncoded, DWORD cbCertEncoded)
00076 {
00077     HCERTSTORE store;
00078     BOOL ret = FALSE;
00079 
00080     TRACE("(%s, %p, %d)\n", debugstr_a(pszCertStoreName), pbCertEncoded,
00081      cbCertEncoded);
00082 
00083     store = CertOpenSystemStoreA(0, pszCertStoreName);
00084     if (store)
00085     {
00086         ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
00087          pbCertEncoded, cbCertEncoded, CERT_STORE_ADD_USE_EXISTING, NULL);
00088         CertCloseStore(store, 0);
00089     }
00090     return ret;
00091 }
00092 
00093 BOOL WINAPI CertAddEncodedCertificateToSystemStoreW(LPCWSTR pszCertStoreName,
00094  const BYTE *pbCertEncoded, DWORD cbCertEncoded)
00095 {
00096     HCERTSTORE store;
00097     BOOL ret = FALSE;
00098 
00099     TRACE("(%s, %p, %d)\n", debugstr_w(pszCertStoreName), pbCertEncoded,
00100      cbCertEncoded);
00101 
00102     store = CertOpenSystemStoreW(0, pszCertStoreName);
00103     if (store)
00104     {
00105         ret = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
00106          pbCertEncoded, cbCertEncoded, CERT_STORE_ADD_USE_EXISTING, NULL);
00107         CertCloseStore(store, 0);
00108     }
00109     return ret;
00110 }
00111 
00112 BOOL WINAPI CertAddCertificateLinkToStore(HCERTSTORE hCertStore,
00113  PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition,
00114  PCCERT_CONTEXT *ppCertContext)
00115 {
00116     static int calls;
00117     PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
00118 
00119     if (!(calls++))
00120         FIXME("(%p, %p, %08x, %p): semi-stub\n", hCertStore, pCertContext,
00121          dwAddDisposition, ppCertContext);
00122     if (store->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
00123         return FALSE;
00124     if (store->type == StoreTypeCollection)
00125     {
00126         SetLastError(E_INVALIDARG);
00127         return FALSE;
00128     }
00129     return CertAddCertificateContextToStore(hCertStore, pCertContext,
00130      dwAddDisposition, ppCertContext);
00131 }
00132 
00133 PCCERT_CONTEXT WINAPI CertCreateCertificateContext(DWORD dwCertEncodingType,
00134  const BYTE *pbCertEncoded, DWORD cbCertEncoded)
00135 {
00136     PCERT_CONTEXT cert = NULL;
00137     BOOL ret;
00138     PCERT_INFO certInfo = NULL;
00139     DWORD size = 0;
00140 
00141     TRACE("(%08x, %p, %d)\n", dwCertEncodingType, pbCertEncoded,
00142      cbCertEncoded);
00143 
00144     if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING)
00145     {
00146         SetLastError(E_INVALIDARG);
00147         return NULL;
00148     }
00149 
00150     ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT_TO_BE_SIGNED,
00151      pbCertEncoded, cbCertEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL,
00152      &certInfo, &size);
00153     if (ret)
00154     {
00155         BYTE *data = NULL;
00156 
00157         cert = Context_CreateDataContext(sizeof(CERT_CONTEXT));
00158         if (!cert)
00159             goto end;
00160         data = CryptMemAlloc(cbCertEncoded);
00161         if (!data)
00162         {
00163             CertFreeCertificateContext(cert);
00164             cert = NULL;
00165             goto end;
00166         }
00167         memcpy(data, pbCertEncoded, cbCertEncoded);
00168         cert->dwCertEncodingType = dwCertEncodingType;
00169         cert->pbCertEncoded      = data;
00170         cert->cbCertEncoded      = cbCertEncoded;
00171         cert->pCertInfo          = certInfo;
00172         cert->hCertStore         = 0;
00173     }
00174 
00175 end:
00176     return cert;
00177 }
00178 
00179 PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext(
00180  PCCERT_CONTEXT pCertContext)
00181 {
00182     TRACE("(%p)\n", pCertContext);
00183 
00184     if (!pCertContext)
00185         return NULL;
00186 
00187     Context_AddRef((void *)pCertContext, sizeof(CERT_CONTEXT));
00188     return pCertContext;
00189 }
00190 
00191 static void CertDataContext_Free(void *context)
00192 {
00193     PCERT_CONTEXT certContext = context;
00194 
00195     CryptMemFree(certContext->pbCertEncoded);
00196     LocalFree(certContext->pCertInfo);
00197 }
00198 
00199 BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext)
00200 {
00201     BOOL ret = TRUE;
00202 
00203     TRACE("(%p)\n", pCertContext);
00204 
00205     if (pCertContext)
00206         ret = Context_Release((void *)pCertContext, sizeof(CERT_CONTEXT),
00207          CertDataContext_Free);
00208     return ret;
00209 }
00210 
00211 DWORD WINAPI CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext,
00212  DWORD dwPropId)
00213 {
00214     PCONTEXT_PROPERTY_LIST properties = Context_GetProperties(
00215      pCertContext, sizeof(CERT_CONTEXT));
00216     DWORD ret;
00217 
00218     TRACE("(%p, %d)\n", pCertContext, dwPropId);
00219 
00220     if (properties)
00221         ret = ContextPropertyList_EnumPropIDs(properties, dwPropId);
00222     else
00223         ret = 0;
00224     return ret;
00225 }
00226 
00227 static BOOL CertContext_GetHashProp(void *context, DWORD dwPropId,
00228  ALG_ID algID, const BYTE *toHash, DWORD toHashLen, void *pvData,
00229  DWORD *pcbData)
00230 {
00231     BOOL ret = CryptHashCertificate(0, algID, 0, toHash, toHashLen, pvData,
00232      pcbData);
00233     if (ret && pvData)
00234     {
00235         CRYPT_DATA_BLOB blob = { *pcbData, pvData };
00236 
00237         ret = CertContext_SetProperty(context, dwPropId, 0, &blob);
00238     }
00239     return ret;
00240 }
00241 
00242 static BOOL CertContext_CopyParam(void *pvData, DWORD *pcbData, const void *pb,
00243  DWORD cb)
00244 {
00245     BOOL ret = TRUE;
00246 
00247     if (!pvData)
00248         *pcbData = cb;
00249     else if (*pcbData < cb)
00250     {
00251         SetLastError(ERROR_MORE_DATA);
00252         *pcbData = cb;
00253         ret = FALSE;
00254     }
00255     else
00256     {
00257         memcpy(pvData, pb, cb);
00258         *pcbData = cb;
00259     }
00260     return ret;
00261 }
00262 
00263 static BOOL CertContext_GetProperty(void *context, DWORD dwPropId,
00264  void *pvData, DWORD *pcbData)
00265 {
00266     PCCERT_CONTEXT pCertContext = context;
00267     PCONTEXT_PROPERTY_LIST properties =
00268      Context_GetProperties(context, sizeof(CERT_CONTEXT));
00269     BOOL ret;
00270     CRYPT_DATA_BLOB blob;
00271 
00272     TRACE("(%p, %d, %p, %p)\n", context, dwPropId, pvData, pcbData);
00273 
00274     if (properties)
00275         ret = ContextPropertyList_FindProperty(properties, dwPropId, &blob);
00276     else
00277         ret = FALSE;
00278     if (ret)
00279         ret = CertContext_CopyParam(pvData, pcbData, blob.pbData, blob.cbData);
00280     else
00281     {
00282         /* Implicit properties */
00283         switch (dwPropId)
00284         {
00285         case CERT_SHA1_HASH_PROP_ID:
00286             ret = CertContext_GetHashProp(context, dwPropId, CALG_SHA1,
00287              pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, pvData,
00288              pcbData);
00289             break;
00290         case CERT_MD5_HASH_PROP_ID:
00291             ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5,
00292              pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, pvData,
00293              pcbData);
00294             break;
00295         case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
00296             ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5,
00297              pCertContext->pCertInfo->Subject.pbData,
00298              pCertContext->pCertInfo->Subject.cbData,
00299              pvData, pcbData);
00300             break;
00301         case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
00302             ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5,
00303              pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
00304              pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData,
00305              pvData, pcbData);
00306             break;
00307         case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID:
00308             ret = CertContext_GetHashProp(context, dwPropId, CALG_MD5,
00309              pCertContext->pCertInfo->SerialNumber.pbData,
00310              pCertContext->pCertInfo->SerialNumber.cbData,
00311              pvData, pcbData);
00312             break;
00313         case CERT_SIGNATURE_HASH_PROP_ID:
00314             ret = CryptHashToBeSigned(0, pCertContext->dwCertEncodingType,
00315              pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, pvData,
00316              pcbData);
00317             if (ret && pvData)
00318             {
00319                 CRYPT_DATA_BLOB blob = { *pcbData, pvData };
00320 
00321                 ret = CertContext_SetProperty(context, dwPropId, 0, &blob);
00322             }
00323             break;
00324         case CERT_KEY_IDENTIFIER_PROP_ID:
00325         {
00326             PCERT_EXTENSION ext = CertFindExtension(
00327              szOID_SUBJECT_KEY_IDENTIFIER, pCertContext->pCertInfo->cExtension,
00328              pCertContext->pCertInfo->rgExtension);
00329 
00330             if (ext)
00331             {
00332                 CRYPT_DATA_BLOB value;
00333                 DWORD size = sizeof(value);
00334 
00335                 ret = CryptDecodeObjectEx(X509_ASN_ENCODING,
00336                  szOID_SUBJECT_KEY_IDENTIFIER, ext->Value.pbData,
00337                  ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL, &value,
00338                  &size);
00339                 if (ret)
00340                 {
00341                     ret = CertContext_CopyParam(pvData, pcbData, value.pbData,
00342                      value.cbData);
00343                     CertContext_SetProperty(context, dwPropId, 0, &value);
00344                 }
00345             }
00346             else
00347                 SetLastError(ERROR_INVALID_DATA);
00348             break;
00349         }
00350         default:
00351             SetLastError(CRYPT_E_NOT_FOUND);
00352         }
00353     }
00354     TRACE("returning %d\n", ret);
00355     return ret;
00356 }
00357 
00358 void CRYPT_FixKeyProvInfoPointers(PCRYPT_KEY_PROV_INFO info)
00359 {
00360     DWORD i, containerLen, provNameLen;
00361     LPBYTE data = (LPBYTE)info + sizeof(CRYPT_KEY_PROV_INFO);
00362 
00363     info->pwszContainerName = (LPWSTR)data;
00364     containerLen = (lstrlenW(info->pwszContainerName) + 1) * sizeof(WCHAR);
00365     data += containerLen;
00366 
00367     info->pwszProvName = (LPWSTR)data;
00368     provNameLen = (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR);
00369     data += provNameLen;
00370 
00371     info->rgProvParam = (PCRYPT_KEY_PROV_PARAM)data;
00372     data += info->cProvParam * sizeof(CRYPT_KEY_PROV_PARAM);
00373 
00374     for (i = 0; i < info->cProvParam; i++)
00375     {
00376         info->rgProvParam[i].pbData = data;
00377         data += info->rgProvParam[i].cbData;
00378     }
00379 }
00380 
00381 BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
00382  DWORD dwPropId, void *pvData, DWORD *pcbData)
00383 {
00384     BOOL ret;
00385 
00386     TRACE("(%p, %d, %p, %p)\n", pCertContext, dwPropId, pvData, pcbData);
00387 
00388     switch (dwPropId)
00389     {
00390     case 0:
00391     case CERT_CERT_PROP_ID:
00392     case CERT_CRL_PROP_ID:
00393     case CERT_CTL_PROP_ID:
00394         SetLastError(E_INVALIDARG);
00395         ret = FALSE;
00396         break;
00397     case CERT_ACCESS_STATE_PROP_ID:
00398         if (pCertContext->hCertStore)
00399             ret = CertGetStoreProperty(pCertContext->hCertStore, dwPropId,
00400              pvData, pcbData);
00401         else
00402         {
00403             DWORD state = 0;
00404 
00405             ret = CertContext_CopyParam(pvData, pcbData, &state, sizeof(state));
00406         }
00407         break;
00408     case CERT_KEY_PROV_HANDLE_PROP_ID:
00409     {
00410         CERT_KEY_CONTEXT keyContext;
00411         DWORD size = sizeof(keyContext);
00412 
00413         ret = CertContext_GetProperty((void *)pCertContext,
00414          CERT_KEY_CONTEXT_PROP_ID, &keyContext, &size);
00415         if (ret)
00416             ret = CertContext_CopyParam(pvData, pcbData, &keyContext.hCryptProv,
00417              sizeof(keyContext.hCryptProv));
00418         break;
00419     }
00420     case CERT_KEY_PROV_INFO_PROP_ID:
00421         ret = CertContext_GetProperty((void *)pCertContext, dwPropId, pvData,
00422          pcbData);
00423         if (ret && pvData)
00424             CRYPT_FixKeyProvInfoPointers(pvData);
00425         break;
00426     default:
00427         ret = CertContext_GetProperty((void *)pCertContext, dwPropId, pvData,
00428          pcbData);
00429     }
00430 
00431     TRACE("returning %d\n", ret);
00432     return ret;
00433 }
00434 
00435 /* Copies key provider info from from into to, where to is assumed to be a
00436  * contiguous buffer of memory large enough for from and all its associated
00437  * data, but whose pointers are uninitialized.
00438  * Upon return, to contains a contiguous copy of from, packed in the following
00439  * order:
00440  * - CRYPT_KEY_PROV_INFO
00441  * - pwszContainerName
00442  * - pwszProvName
00443  * - rgProvParam[0]...
00444  */
00445 static void CRYPT_CopyKeyProvInfo(PCRYPT_KEY_PROV_INFO to,
00446  const CRYPT_KEY_PROV_INFO *from)
00447 {
00448     DWORD i;
00449     LPBYTE nextData = (LPBYTE)to + sizeof(CRYPT_KEY_PROV_INFO);
00450 
00451     if (from->pwszContainerName)
00452     {
00453         to->pwszContainerName = (LPWSTR)nextData;
00454         lstrcpyW(to->pwszContainerName, from->pwszContainerName);
00455         nextData += (lstrlenW(from->pwszContainerName) + 1) * sizeof(WCHAR);
00456     }
00457     else
00458         to->pwszContainerName = NULL;
00459     if (from->pwszProvName)
00460     {
00461         to->pwszProvName = (LPWSTR)nextData;
00462         lstrcpyW(to->pwszProvName, from->pwszProvName);
00463         nextData += (lstrlenW(from->pwszProvName) + 1) * sizeof(WCHAR);
00464     }
00465     else
00466         to->pwszProvName = NULL;
00467     to->dwProvType = from->dwProvType;
00468     to->dwFlags = from->dwFlags;
00469     to->cProvParam = from->cProvParam;
00470     to->rgProvParam = (PCRYPT_KEY_PROV_PARAM)nextData;
00471     nextData += to->cProvParam * sizeof(CRYPT_KEY_PROV_PARAM);
00472     to->dwKeySpec = from->dwKeySpec;
00473     for (i = 0; i < to->cProvParam; i++)
00474     {
00475         memcpy(&to->rgProvParam[i], &from->rgProvParam[i],
00476          sizeof(CRYPT_KEY_PROV_PARAM));
00477         to->rgProvParam[i].pbData = nextData;
00478         memcpy(to->rgProvParam[i].pbData, from->rgProvParam[i].pbData,
00479          from->rgProvParam[i].cbData);
00480         nextData += from->rgProvParam[i].cbData;
00481     }
00482 }
00483 
00484 static BOOL CertContext_SetKeyProvInfoProperty(PCONTEXT_PROPERTY_LIST properties,
00485  const CRYPT_KEY_PROV_INFO *info)
00486 {
00487     BOOL ret;
00488     LPBYTE buf = NULL;
00489     DWORD size = sizeof(CRYPT_KEY_PROV_INFO), i, containerSize, provNameSize;
00490 
00491     if (info->pwszContainerName)
00492         containerSize = (lstrlenW(info->pwszContainerName) + 1) * sizeof(WCHAR);
00493     else
00494         containerSize = 0;
00495     if (info->pwszProvName)
00496         provNameSize = (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR);
00497     else
00498         provNameSize = 0;
00499     size += containerSize + provNameSize;
00500     for (i = 0; i < info->cProvParam; i++)
00501         size += sizeof(CRYPT_KEY_PROV_PARAM) + info->rgProvParam[i].cbData;
00502     buf = CryptMemAlloc(size);
00503     if (buf)
00504     {
00505         CRYPT_CopyKeyProvInfo((PCRYPT_KEY_PROV_INFO)buf, info);
00506         ret = ContextPropertyList_SetProperty(properties,
00507          CERT_KEY_PROV_INFO_PROP_ID, buf, size);
00508         CryptMemFree(buf);
00509     }
00510     else
00511         ret = FALSE;
00512     return ret;
00513 }
00514 
00515 static BOOL CertContext_SetProperty(void *context, DWORD dwPropId,
00516  DWORD dwFlags, const void *pvData)
00517 {
00518     PCONTEXT_PROPERTY_LIST properties =
00519      Context_GetProperties(context, sizeof(CERT_CONTEXT));
00520     BOOL ret;
00521 
00522     TRACE("(%p, %d, %08x, %p)\n", context, dwPropId, dwFlags, pvData);
00523 
00524     if (!properties)
00525         ret = FALSE;
00526     else
00527     {
00528         switch (dwPropId)
00529         {
00530         case CERT_AUTO_ENROLL_PROP_ID:
00531         case CERT_CTL_USAGE_PROP_ID: /* same as CERT_ENHKEY_USAGE_PROP_ID */
00532         case CERT_DESCRIPTION_PROP_ID:
00533         case CERT_FRIENDLY_NAME_PROP_ID:
00534         case CERT_HASH_PROP_ID:
00535         case CERT_KEY_IDENTIFIER_PROP_ID:
00536         case CERT_MD5_HASH_PROP_ID:
00537         case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
00538         case CERT_PUBKEY_ALG_PARA_PROP_ID:
00539         case CERT_PVK_FILE_PROP_ID:
00540         case CERT_SIGNATURE_HASH_PROP_ID:
00541         case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
00542         case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
00543         case CERT_EXTENDED_ERROR_INFO_PROP_ID:
00544         case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
00545         case CERT_ENROLLMENT_PROP_ID:
00546         case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
00547         case CERT_RENEWAL_PROP_ID:
00548         {
00549             if (pvData)
00550             {
00551                 const CRYPT_DATA_BLOB *blob = pvData;
00552 
00553                 ret = ContextPropertyList_SetProperty(properties, dwPropId,
00554                  blob->pbData, blob->cbData);
00555             }
00556             else
00557             {
00558                 ContextPropertyList_RemoveProperty(properties, dwPropId);
00559                 ret = TRUE;
00560             }
00561             break;
00562         }
00563         case CERT_DATE_STAMP_PROP_ID:
00564             if (pvData)
00565                 ret = ContextPropertyList_SetProperty(properties, dwPropId,
00566                  pvData, sizeof(FILETIME));
00567             else
00568             {
00569                 ContextPropertyList_RemoveProperty(properties, dwPropId);
00570                 ret = TRUE;
00571             }
00572             break;
00573         case CERT_KEY_CONTEXT_PROP_ID:
00574         {
00575             if (pvData)
00576             {
00577                 const CERT_KEY_CONTEXT *keyContext = pvData;
00578 
00579                 if (keyContext->cbSize != sizeof(CERT_KEY_CONTEXT))
00580                 {
00581                     SetLastError(E_INVALIDARG);
00582                     ret = FALSE;
00583                 }
00584                 else
00585                     ret = ContextPropertyList_SetProperty(properties, dwPropId,
00586                      (const BYTE *)keyContext, keyContext->cbSize);
00587             }
00588             else
00589             {
00590                 ContextPropertyList_RemoveProperty(properties, dwPropId);
00591                 ret = TRUE;
00592             }
00593             break;
00594         }
00595         case CERT_KEY_PROV_INFO_PROP_ID:
00596             if (pvData)
00597                 ret = CertContext_SetKeyProvInfoProperty(properties, pvData);
00598             else
00599             {
00600                 ContextPropertyList_RemoveProperty(properties, dwPropId);
00601                 ret = TRUE;
00602             }
00603             break;
00604         case CERT_KEY_PROV_HANDLE_PROP_ID:
00605         {
00606             CERT_KEY_CONTEXT keyContext;
00607             DWORD size = sizeof(keyContext);
00608 
00609             ret = CertContext_GetProperty(context, CERT_KEY_CONTEXT_PROP_ID,
00610              &keyContext, &size);
00611             if (ret)
00612             {
00613                 if (!(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
00614                     CryptReleaseContext(keyContext.hCryptProv, 0);
00615             }
00616             keyContext.cbSize = sizeof(keyContext);
00617             if (pvData)
00618                 keyContext.hCryptProv = *(const HCRYPTPROV *)pvData;
00619             else
00620             {
00621                 keyContext.hCryptProv = 0;
00622                 keyContext.dwKeySpec = AT_SIGNATURE;
00623             }
00624             ret = CertContext_SetProperty(context, CERT_KEY_CONTEXT_PROP_ID,
00625              0, &keyContext);
00626             break;
00627         }
00628         default:
00629             FIXME("%d: stub\n", dwPropId);
00630             ret = FALSE;
00631         }
00632     }
00633     TRACE("returning %d\n", ret);
00634     return ret;
00635 }
00636 
00637 BOOL WINAPI CertSetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
00638  DWORD dwPropId, DWORD dwFlags, const void *pvData)
00639 {
00640     BOOL ret;
00641 
00642     TRACE("(%p, %d, %08x, %p)\n", pCertContext, dwPropId, dwFlags, pvData);
00643 
00644     /* Handle special cases for "read-only"/invalid prop IDs.  Windows just
00645      * crashes on most of these, I'll be safer.
00646      */
00647     switch (dwPropId)
00648     {
00649     case 0:
00650     case CERT_ACCESS_STATE_PROP_ID:
00651     case CERT_CERT_PROP_ID:
00652     case CERT_CRL_PROP_ID:
00653     case CERT_CTL_PROP_ID:
00654         SetLastError(E_INVALIDARG);
00655         return FALSE;
00656     }
00657     ret = CertContext_SetProperty((void *)pCertContext, dwPropId, dwFlags,
00658      pvData);
00659     TRACE("returning %d\n", ret);
00660     return ret;
00661 }
00662 
00663 /* Acquires the private key using the key provider info, retrieving info from
00664  * the certificate if info is NULL.  The acquired provider is returned in
00665  * *phCryptProv, and the key spec for the provider is returned in *pdwKeySpec.
00666  */
00667 static BOOL CRYPT_AcquirePrivateKeyFromProvInfo(PCCERT_CONTEXT pCert,
00668  PCRYPT_KEY_PROV_INFO info, HCRYPTPROV *phCryptProv, DWORD *pdwKeySpec)
00669 {
00670     DWORD size = 0;
00671     BOOL allocated = FALSE, ret = TRUE;
00672 
00673     if (!info)
00674     {
00675         ret = CertGetCertificateContextProperty(pCert,
00676          CERT_KEY_PROV_INFO_PROP_ID, 0, &size);
00677         if (ret)
00678         {
00679             info = HeapAlloc(GetProcessHeap(), 0, size);
00680             if (info)
00681             {
00682                 ret = CertGetCertificateContextProperty(pCert,
00683                  CERT_KEY_PROV_INFO_PROP_ID, info, &size);
00684                 allocated = TRUE;
00685             }
00686             else
00687             {
00688                 SetLastError(ERROR_OUTOFMEMORY);
00689                 ret = FALSE;
00690             }
00691         }
00692         else
00693             SetLastError(CRYPT_E_NO_KEY_PROPERTY);
00694     }
00695     if (ret)
00696     {
00697         ret = CryptAcquireContextW(phCryptProv, info->pwszContainerName,
00698          info->pwszProvName, info->dwProvType, 0);
00699         if (ret)
00700         {
00701             DWORD i;
00702 
00703             for (i = 0; i < info->cProvParam; i++)
00704             {
00705                 CryptSetProvParam(*phCryptProv,
00706                  info->rgProvParam[i].dwParam, info->rgProvParam[i].pbData,
00707                  info->rgProvParam[i].dwFlags);
00708             }
00709             *pdwKeySpec = info->dwKeySpec;
00710         }
00711         else
00712             SetLastError(CRYPT_E_NO_KEY_PROPERTY);
00713     }
00714     if (allocated)
00715         HeapFree(GetProcessHeap(), 0, info);
00716     return ret;
00717 }
00718 
00719 BOOL WINAPI CryptAcquireCertificatePrivateKey(PCCERT_CONTEXT pCert,
00720  DWORD dwFlags, void *pvReserved, HCRYPTPROV_OR_NCRYPT_KEY_HANDLE *phCryptProv,
00721  DWORD *pdwKeySpec, BOOL *pfCallerFreeProv)
00722 {
00723     BOOL ret = FALSE, cache = FALSE;
00724     PCRYPT_KEY_PROV_INFO info = NULL;
00725     CERT_KEY_CONTEXT keyContext;
00726     DWORD size;
00727 
00728     TRACE("(%p, %08x, %p, %p, %p, %p)\n", pCert, dwFlags, pvReserved,
00729      phCryptProv, pdwKeySpec, pfCallerFreeProv);
00730 
00731     if (dwFlags & CRYPT_ACQUIRE_USE_PROV_INFO_FLAG)
00732     {
00733         DWORD size = 0;
00734 
00735         ret = CertGetCertificateContextProperty(pCert,
00736          CERT_KEY_PROV_INFO_PROP_ID, 0, &size);
00737         if (ret)
00738         {
00739             info = HeapAlloc(GetProcessHeap(), 0, size);
00740             ret = CertGetCertificateContextProperty(pCert,
00741              CERT_KEY_PROV_INFO_PROP_ID, info, &size);
00742             if (ret)
00743                 cache = info->dwFlags & CERT_SET_KEY_CONTEXT_PROP_ID;
00744         }
00745     }
00746     else if (dwFlags & CRYPT_ACQUIRE_CACHE_FLAG)
00747         cache = TRUE;
00748     *phCryptProv = 0;
00749     if (cache)
00750     {
00751         size = sizeof(keyContext);
00752         ret = CertGetCertificateContextProperty(pCert, CERT_KEY_CONTEXT_PROP_ID,
00753          &keyContext, &size);
00754         if (ret)
00755         {
00756             *phCryptProv = keyContext.hCryptProv;
00757             if (pdwKeySpec)
00758                 *pdwKeySpec = keyContext.dwKeySpec;
00759             if (pfCallerFreeProv)
00760                 *pfCallerFreeProv = !cache;
00761         }
00762     }
00763     if (!*phCryptProv)
00764     {
00765         ret = CRYPT_AcquirePrivateKeyFromProvInfo(pCert, info,
00766          &keyContext.hCryptProv, &keyContext.dwKeySpec);
00767         if (ret)
00768         {
00769             *phCryptProv = keyContext.hCryptProv;
00770             if (pdwKeySpec)
00771                 *pdwKeySpec = keyContext.dwKeySpec;
00772             if (cache)
00773             {
00774                 keyContext.cbSize = sizeof(keyContext);
00775                 if (CertSetCertificateContextProperty(pCert,
00776                  CERT_KEY_CONTEXT_PROP_ID, 0, &keyContext))
00777                 {
00778                     if (pfCallerFreeProv)
00779                         *pfCallerFreeProv = FALSE;
00780                 }
00781             }
00782             else
00783             {
00784                 if (pfCallerFreeProv)
00785                     *pfCallerFreeProv = TRUE;
00786             }
00787         }
00788     }
00789     HeapFree(GetProcessHeap(), 0, info);
00790     return ret;
00791 }
00792 
00793 static BOOL key_prov_info_matches_cert(PCCERT_CONTEXT pCert,
00794  const CRYPT_KEY_PROV_INFO *keyProvInfo)
00795 {
00796     HCRYPTPROV csp;
00797     BOOL matches = FALSE;
00798 
00799     if (CryptAcquireContextW(&csp, keyProvInfo->pwszContainerName,
00800      keyProvInfo->pwszProvName, keyProvInfo->dwProvType, keyProvInfo->dwFlags))
00801     {
00802         DWORD size;
00803 
00804         /* Need to sign something to verify the sig.  What to sign?  Why not
00805          * the certificate itself?
00806          */
00807         if (CryptSignAndEncodeCertificate(csp, AT_SIGNATURE,
00808          pCert->dwCertEncodingType, X509_CERT_TO_BE_SIGNED, pCert->pCertInfo,
00809          &pCert->pCertInfo->SignatureAlgorithm, NULL, NULL, &size))
00810         {
00811             BYTE *certEncoded = CryptMemAlloc(size);
00812 
00813             if (certEncoded)
00814             {
00815                 if (CryptSignAndEncodeCertificate(csp, AT_SIGNATURE,
00816                  pCert->dwCertEncodingType, X509_CERT_TO_BE_SIGNED,
00817                  pCert->pCertInfo, &pCert->pCertInfo->SignatureAlgorithm,
00818                  NULL, certEncoded, &size))
00819                 {
00820                     if (size == pCert->cbCertEncoded &&
00821                      !memcmp(certEncoded, pCert->pbCertEncoded, size))
00822                         matches = TRUE;
00823                 }
00824                 CryptMemFree(certEncoded);
00825             }
00826         }
00827         CryptReleaseContext(csp, 0);
00828     }
00829     return matches;
00830 }
00831 
00832 static BOOL container_matches_cert(PCCERT_CONTEXT pCert, LPCSTR container,
00833  CRYPT_KEY_PROV_INFO *keyProvInfo)
00834 {
00835     CRYPT_KEY_PROV_INFO copy;
00836     WCHAR containerW[MAX_PATH];
00837     BOOL matches = FALSE;
00838 
00839     MultiByteToWideChar(CP_ACP, 0, container, -1,
00840      containerW, sizeof(containerW) / sizeof(containerW[0]));
00841     /* We make a copy of the CRYPT_KEY_PROV_INFO because the caller expects
00842      * keyProvInfo->pwszContainerName to be NULL or a heap-allocated container
00843      * name.
00844      */
00845     memcpy(&copy, keyProvInfo, sizeof(copy));
00846     copy.pwszContainerName = containerW;
00847     matches = key_prov_info_matches_cert(pCert, &copy);
00848     if (matches)
00849     {
00850         keyProvInfo->pwszContainerName =
00851          CryptMemAlloc((strlenW(containerW) + 1) * sizeof(WCHAR));
00852         if (keyProvInfo->pwszContainerName)
00853         {
00854             strcpyW(keyProvInfo->pwszContainerName, containerW);
00855             keyProvInfo->dwKeySpec = AT_SIGNATURE;
00856         }
00857         else
00858             matches = FALSE;
00859     }
00860     return matches;
00861 }
00862 
00863 /* Searches the provider named keyProvInfo.pwszProvName for a container whose
00864  * private key matches pCert's public key.  Upon success, updates keyProvInfo
00865  * with the matching container's info (free keyProvInfo.pwszContainerName upon
00866  * success.)
00867  * Returns TRUE if found, FALSE if not.
00868  */
00869 static BOOL find_key_prov_info_in_provider(PCCERT_CONTEXT pCert,
00870  CRYPT_KEY_PROV_INFO *keyProvInfo)
00871 {
00872     HCRYPTPROV defProvider;
00873     BOOL ret, found = FALSE;
00874     char containerA[MAX_PATH];
00875 
00876     assert(keyProvInfo->pwszContainerName == NULL);
00877     if ((ret = CryptAcquireContextW(&defProvider, NULL,
00878      keyProvInfo->pwszProvName, keyProvInfo->dwProvType,
00879      keyProvInfo->dwFlags | CRYPT_VERIFYCONTEXT)))
00880     {
00881         DWORD enumFlags = keyProvInfo->dwFlags | CRYPT_FIRST;
00882 
00883         while (ret && !found)
00884         {
00885             DWORD size = sizeof(containerA);
00886 
00887             ret = CryptGetProvParam(defProvider, PP_ENUMCONTAINERS,
00888              (BYTE *)containerA, &size, enumFlags);
00889             if (ret)
00890                 found = container_matches_cert(pCert, containerA, keyProvInfo);
00891             if (enumFlags & CRYPT_FIRST)
00892             {
00893                 enumFlags &= ~CRYPT_FIRST;
00894                 enumFlags |= CRYPT_NEXT;
00895             }
00896         }
00897         CryptReleaseContext(defProvider, 0);
00898     }
00899     return found;
00900 }
00901 
00902 static BOOL find_matching_provider(PCCERT_CONTEXT pCert, DWORD dwFlags)
00903 {
00904     BOOL found = FALSE, ret = TRUE;
00905     DWORD index = 0, cbProvName = 0;
00906     CRYPT_KEY_PROV_INFO keyProvInfo;
00907 
00908     TRACE("(%p, %08x)\n", pCert, dwFlags);
00909 
00910     memset(&keyProvInfo, 0, sizeof(keyProvInfo));
00911     while (ret && !found)
00912     {
00913         DWORD size = 0;
00914 
00915         ret = CryptEnumProvidersW(index, NULL, 0, &keyProvInfo.dwProvType,
00916          NULL, &size);
00917         if (ret)
00918         {
00919             if (size <= cbProvName)
00920                 ret = CryptEnumProvidersW(index, NULL, 0,
00921                  &keyProvInfo.dwProvType, keyProvInfo.pwszProvName, &size);
00922             else
00923             {
00924                 CryptMemFree(keyProvInfo.pwszProvName);
00925                 keyProvInfo.pwszProvName = CryptMemAlloc(size);
00926                 if (keyProvInfo.pwszProvName)
00927                 {
00928                     cbProvName = size;
00929                     ret = CryptEnumProvidersW(index, NULL, 0,
00930                      &keyProvInfo.dwProvType, keyProvInfo.pwszProvName, &size);
00931                     if (ret)
00932                     {
00933                         if (dwFlags & CRYPT_FIND_SILENT_KEYSET_FLAG)
00934                             keyProvInfo.dwFlags |= CRYPT_SILENT;
00935                         if (dwFlags & CRYPT_FIND_USER_KEYSET_FLAG ||
00936                          !(dwFlags & (CRYPT_FIND_USER_KEYSET_FLAG |
00937                          CRYPT_FIND_MACHINE_KEYSET_FLAG)))
00938                         {
00939                             keyProvInfo.dwFlags |= CRYPT_USER_KEYSET;
00940                             found = find_key_prov_info_in_provider(pCert,
00941                              &keyProvInfo);
00942                         }
00943                         if (!found)
00944                         {
00945                             if (dwFlags & CRYPT_FIND_MACHINE_KEYSET_FLAG ||
00946                              !(dwFlags & (CRYPT_FIND_USER_KEYSET_FLAG |
00947                              CRYPT_FIND_MACHINE_KEYSET_FLAG)))
00948                             {
00949                                 keyProvInfo.dwFlags &= ~CRYPT_USER_KEYSET;
00950                                 keyProvInfo.dwFlags |= CRYPT_MACHINE_KEYSET;
00951                                 found = find_key_prov_info_in_provider(pCert,
00952                                  &keyProvInfo);
00953                             }
00954                         }
00955                     }
00956                 }
00957                 else
00958                     ret = FALSE;
00959             }
00960             index++;
00961         }
00962     }
00963     if (found)
00964         CertSetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID,
00965          0, &keyProvInfo);
00966     CryptMemFree(keyProvInfo.pwszProvName);
00967     CryptMemFree(keyProvInfo.pwszContainerName);
00968     return found;
00969 }
00970 
00971 static BOOL cert_prov_info_matches_cert(PCCERT_CONTEXT pCert)
00972 {
00973     BOOL matches = FALSE;
00974     DWORD size;
00975 
00976     if (CertGetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID,
00977      NULL, &size))
00978     {
00979         CRYPT_KEY_PROV_INFO *keyProvInfo = CryptMemAlloc(size);
00980 
00981         if (keyProvInfo)
00982         {
00983             if (CertGetCertificateContextProperty(pCert,
00984              CERT_KEY_PROV_INFO_PROP_ID, keyProvInfo, &size))
00985                 matches = key_prov_info_matches_cert(pCert, keyProvInfo);
00986             CryptMemFree(keyProvInfo);
00987         }
00988     }
00989     return matches;
00990 }
00991 
00992 BOOL WINAPI CryptFindCertificateKeyProvInfo(PCCERT_CONTEXT pCert,
00993  DWORD dwFlags, void *pvReserved)
00994 {
00995     BOOL matches = FALSE;
00996 
00997     TRACE("(%p, %08x, %p)\n", pCert, dwFlags, pvReserved);
00998 
00999     matches = cert_prov_info_matches_cert(pCert);
01000     if (!matches)
01001         matches = find_matching_provider(pCert, dwFlags);
01002     return matches;
01003 }
01004 
01005 BOOL WINAPI CertCompareCertificate(DWORD dwCertEncodingType,
01006  PCERT_INFO pCertId1, PCERT_INFO pCertId2)
01007 {
01008     BOOL ret;
01009 
01010     TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pCertId1, pCertId2);
01011 
01012     ret = CertCompareCertificateName(dwCertEncodingType, &pCertId1->Issuer,
01013      &pCertId2->Issuer) && CertCompareIntegerBlob(&pCertId1->SerialNumber,
01014      &pCertId2->SerialNumber);
01015     TRACE("returning %d\n", ret);
01016     return ret;
01017 }
01018 
01019 BOOL WINAPI CertCompareCertificateName(DWORD dwCertEncodingType,
01020  PCERT_NAME_BLOB pCertName1, PCERT_NAME_BLOB pCertName2)
01021 {
01022     BOOL ret;
01023 
01024     TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pCertName1, pCertName2);
01025 
01026     if (pCertName1->cbData == pCertName2->cbData)
01027     {
01028         if (pCertName1->cbData)
01029             ret = !memcmp(pCertName1->pbData, pCertName2->pbData,
01030              pCertName1->cbData);
01031         else
01032             ret = TRUE;
01033     }
01034     else
01035         ret = FALSE;
01036     TRACE("returning %d\n", ret);
01037     return ret;
01038 }
01039 
01040 /* Returns the number of significant bytes in pInt, where a byte is
01041  * insignificant if it's a leading 0 for positive numbers or a leading 0xff
01042  * for negative numbers.  pInt is assumed to be little-endian.
01043  */
01044 static DWORD CRYPT_significantBytes(const CRYPT_INTEGER_BLOB *pInt)
01045 {
01046     DWORD ret = pInt->cbData;
01047 
01048     while (ret > 1)
01049     {
01050         if (pInt->pbData[ret - 2] <= 0x7f && pInt->pbData[ret - 1] == 0)
01051             ret--;
01052         else if (pInt->pbData[ret - 2] >= 0x80 && pInt->pbData[ret - 1] == 0xff)
01053             ret--;
01054         else
01055             break;
01056     }
01057     return ret;
01058 }
01059 
01060 BOOL WINAPI CertCompareIntegerBlob(PCRYPT_INTEGER_BLOB pInt1,
01061  PCRYPT_INTEGER_BLOB pInt2)
01062 {
01063     BOOL ret;
01064     DWORD cb1, cb2;
01065 
01066     TRACE("(%p, %p)\n", pInt1, pInt2);
01067 
01068     cb1 = CRYPT_significantBytes(pInt1);
01069     cb2 = CRYPT_significantBytes(pInt2);
01070     if (cb1 == cb2)
01071     {
01072         if (cb1)
01073             ret = !memcmp(pInt1->pbData, pInt2->pbData, cb1);
01074         else
01075             ret = TRUE;
01076     }
01077     else
01078         ret = FALSE;
01079     TRACE("returning %d\n", ret);
01080     return ret;
01081 }
01082 
01083 BOOL WINAPI CertComparePublicKeyInfo(DWORD dwCertEncodingType,
01084  PCERT_PUBLIC_KEY_INFO pPublicKey1, PCERT_PUBLIC_KEY_INFO pPublicKey2)
01085 {
01086     BOOL ret;
01087 
01088     TRACE("(%08x, %p, %p)\n", dwCertEncodingType, pPublicKey1, pPublicKey2);
01089 
01090     switch (GET_CERT_ENCODING_TYPE(dwCertEncodingType))
01091     {
01092     case 0: /* Seems to mean "raw binary bits" */
01093         if (pPublicKey1->PublicKey.cbData == pPublicKey2->PublicKey.cbData &&
01094          pPublicKey1->PublicKey.cUnusedBits == pPublicKey2->PublicKey.cUnusedBits)
01095         {
01096           if (pPublicKey2->PublicKey.cbData)
01097               ret = !memcmp(pPublicKey1->PublicKey.pbData,
01098                pPublicKey2->PublicKey.pbData, pPublicKey1->PublicKey.cbData);
01099           else
01100               ret = TRUE;
01101         }
01102         else
01103             ret = FALSE;
01104         break;
01105     default:
01106         WARN("Unknown encoding type %08x\n", dwCertEncodingType);
01107         /* FALLTHROUGH */
01108     case X509_ASN_ENCODING:
01109     {
01110         BLOBHEADER *pblob1, *pblob2;
01111         DWORD length;
01112         ret = FALSE;
01113         if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
01114                     pPublicKey1->PublicKey.pbData, pPublicKey1->PublicKey.cbData,
01115                     0, NULL, &length))
01116         {
01117             pblob1 = CryptMemAlloc(length);
01118             if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
01119                     pPublicKey1->PublicKey.pbData, pPublicKey1->PublicKey.cbData,
01120                     0, pblob1, &length))
01121             {
01122                 if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
01123                             pPublicKey2->PublicKey.pbData, pPublicKey2->PublicKey.cbData,
01124                             0, NULL, &length))
01125                 {
01126                     pblob2 = CryptMemAlloc(length);
01127                     if (CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
01128                             pPublicKey2->PublicKey.pbData, pPublicKey2->PublicKey.cbData,
01129                             0, pblob2, &length))
01130                     {
01131                         /* The RSAPUBKEY structure directly follows the BLOBHEADER */
01132                         RSAPUBKEY *pk1 = (LPVOID)(pblob1 + 1),
01133                                   *pk2 = (LPVOID)(pblob2 + 1);
01134                         ret = (pk1->bitlen == pk2->bitlen) && (pk1->pubexp == pk2->pubexp)
01135                                  && !memcmp(pk1 + 1, pk2 + 1, pk1->bitlen/8);
01136                     }
01137                     CryptMemFree(pblob2);
01138                 }
01139             }
01140             CryptMemFree(pblob1);
01141         }
01142 
01143         break;
01144     }
01145     }
01146     return ret;
01147 }
01148 
01149 DWORD WINAPI CertGetPublicKeyLength(DWORD dwCertEncodingType,
01150  PCERT_PUBLIC_KEY_INFO pPublicKey)
01151 {
01152     DWORD len = 0;
01153 
01154     TRACE("(%08x, %p)\n", dwCertEncodingType, pPublicKey);
01155 
01156     if (GET_CERT_ENCODING_TYPE(dwCertEncodingType) != X509_ASN_ENCODING)
01157     {
01158         SetLastError(ERROR_FILE_NOT_FOUND);
01159         return 0;
01160     }
01161     if (pPublicKey->Algorithm.pszObjId &&
01162      !strcmp(pPublicKey->Algorithm.pszObjId, szOID_RSA_DH))
01163     {
01164         FIXME("unimplemented for DH public keys\n");
01165         SetLastError(CRYPT_E_ASN1_BADTAG);
01166     }
01167     else
01168     {
01169         DWORD size;
01170         PBYTE buf;
01171         BOOL ret = CryptDecodeObjectEx(dwCertEncodingType,
01172          RSA_CSP_PUBLICKEYBLOB, pPublicKey->PublicKey.pbData,
01173          pPublicKey->PublicKey.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &buf,
01174          &size);
01175 
01176         if (ret)
01177         {
01178             RSAPUBKEY *rsaPubKey = (RSAPUBKEY *)(buf + sizeof(BLOBHEADER));
01179 
01180             len = rsaPubKey->bitlen;
01181             LocalFree(buf);
01182         }
01183     }
01184     return len;
01185 }
01186 
01187 typedef BOOL (*CertCompareFunc)(PCCERT_CONTEXT pCertContext, DWORD dwType,
01188  DWORD dwFlags, const void *pvPara);
01189 
01190 static BOOL compare_cert_by_md5_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
01191  DWORD dwFlags, const void *pvPara)
01192 {
01193     BOOL ret;
01194     BYTE hash[16];
01195     DWORD size = sizeof(hash);
01196 
01197     ret = CertGetCertificateContextProperty(pCertContext,
01198      CERT_MD5_HASH_PROP_ID, hash, &size);
01199     if (ret)
01200     {
01201         const CRYPT_HASH_BLOB *pHash = pvPara;
01202 
01203         if (size == pHash->cbData)
01204             ret = !memcmp(pHash->pbData, hash, size);
01205         else
01206             ret = FALSE;
01207     }
01208     return ret;
01209 }
01210 
01211 static BOOL compare_cert_by_sha1_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
01212  DWORD dwFlags, const void *pvPara)
01213 {
01214     BOOL ret;
01215     BYTE hash[20];
01216     DWORD size = sizeof(hash);
01217 
01218     ret = CertGetCertificateContextProperty(pCertContext,
01219      CERT_SHA1_HASH_PROP_ID, hash, &size);
01220     if (ret)
01221     {
01222         const CRYPT_HASH_BLOB *pHash = pvPara;
01223 
01224         if (size == pHash->cbData)
01225             ret = !memcmp(pHash->pbData, hash, size);
01226         else
01227             ret = FALSE;
01228     }
01229     return ret;
01230 }
01231 
01232 static BOOL compare_cert_by_name(PCCERT_CONTEXT pCertContext, DWORD dwType,
01233  DWORD dwFlags, const void *pvPara)
01234 {
01235     CERT_NAME_BLOB *blob = (CERT_NAME_BLOB *)pvPara, *toCompare;
01236     BOOL ret;
01237 
01238     if (dwType & CERT_INFO_SUBJECT_FLAG)
01239         toCompare = &pCertContext->pCertInfo->Subject;
01240     else
01241         toCompare = &pCertContext->pCertInfo->Issuer;
01242     ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
01243      toCompare, blob);
01244     return ret;
01245 }
01246 
01247 static BOOL compare_cert_by_public_key(PCCERT_CONTEXT pCertContext,
01248  DWORD dwType, DWORD dwFlags, const void *pvPara)
01249 {
01250     CERT_PUBLIC_KEY_INFO *publicKey = (CERT_PUBLIC_KEY_INFO *)pvPara;
01251     BOOL ret;
01252 
01253     ret = CertComparePublicKeyInfo(pCertContext->dwCertEncodingType,
01254      &pCertContext->pCertInfo->SubjectPublicKeyInfo, publicKey);
01255     return ret;
01256 }
01257 
01258 static BOOL compare_cert_by_subject_cert(PCCERT_CONTEXT pCertContext,
01259  DWORD dwType, DWORD dwFlags, const void *pvPara)
01260 {
01261     CERT_INFO *pCertInfo = (CERT_INFO *)pvPara;
01262     BOOL ret;
01263 
01264     /* Matching serial number and subject match.. */
01265     ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
01266      &pCertContext->pCertInfo->Subject, &pCertInfo->Issuer);
01267     if (ret)
01268         ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber,
01269          &pCertInfo->SerialNumber);
01270     else
01271     {
01272         /* failing that, if the serial number and issuer match, we match */
01273         ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber,
01274          &pCertInfo->SerialNumber);
01275         if (ret)
01276             ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
01277              &pCertContext->pCertInfo->Issuer, &pCertInfo->Issuer);
01278     }
01279     TRACE("returning %d\n", ret);
01280     return ret;
01281 }
01282 
01283 static BOOL compare_cert_by_cert_id(PCCERT_CONTEXT pCertContext, DWORD dwType,
01284  DWORD dwFlags, const void *pvPara)
01285 {
01286     CERT_ID *id = (CERT_ID *)pvPara;
01287     BOOL ret;
01288 
01289     switch (id->dwIdChoice)
01290     {
01291     case CERT_ID_ISSUER_SERIAL_NUMBER:
01292         ret = CertCompareCertificateName(pCertContext->dwCertEncodingType,
01293          &pCertContext->pCertInfo->Issuer, &id->u.IssuerSerialNumber.Issuer);
01294         if (ret)
01295             ret = CertCompareIntegerBlob(&pCertContext->pCertInfo->SerialNumber,
01296              &id->u.IssuerSerialNumber.SerialNumber);
01297         break;
01298     case CERT_ID_SHA1_HASH:
01299         ret = compare_cert_by_sha1_hash(pCertContext, dwType, dwFlags,
01300          &id->u.HashId);
01301         break;
01302     case CERT_ID_KEY_IDENTIFIER:
01303     {
01304         DWORD size = 0;
01305 
01306         ret = CertGetCertificateContextProperty(pCertContext,
01307          CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size);
01308         if (ret && size == id->u.KeyId.cbData)
01309         {
01310             LPBYTE buf = CryptMemAlloc(size);
01311 
01312             if (buf)
01313             {
01314                 CertGetCertificateContextProperty(pCertContext,
01315                  CERT_KEY_IDENTIFIER_PROP_ID, buf, &size);
01316                 ret = !memcmp(buf, id->u.KeyId.pbData, size);
01317                 CryptMemFree(buf);
01318             }
01319         }
01320         else
01321             ret = FALSE;
01322         break;
01323     }
01324     default:
01325         ret = FALSE;
01326         break;
01327     }
01328     return ret;
01329 }
01330 
01331 static BOOL compare_existing_cert(PCCERT_CONTEXT pCertContext, DWORD dwType,
01332  DWORD dwFlags, const void *pvPara)
01333 {
01334     PCCERT_CONTEXT toCompare = pvPara;
01335     return CertCompareCertificate(pCertContext->dwCertEncodingType,
01336      pCertContext->pCertInfo, toCompare->pCertInfo);
01337 }
01338 
01339 static BOOL compare_cert_by_signature_hash(PCCERT_CONTEXT pCertContext, DWORD dwType,
01340  DWORD dwFlags, const void *pvPara)
01341 {
01342     const CRYPT_HASH_BLOB *hash = pvPara;
01343     DWORD size = 0;
01344     BOOL ret;
01345 
01346     ret = CertGetCertificateContextProperty(pCertContext,
01347      CERT_SIGNATURE_HASH_PROP_ID, NULL, &size);
01348     if (ret && size == hash->cbData)
01349     {
01350         LPBYTE buf = CryptMemAlloc(size);
01351 
01352         if (buf)
01353         {
01354             CertGetCertificateContextProperty(pCertContext,
01355              CERT_SIGNATURE_HASH_PROP_ID, buf, &size);
01356             ret = !memcmp(buf, hash->pbData, size);
01357             CryptMemFree(buf);
01358         }
01359     }
01360     else
01361         ret = FALSE;
01362     return ret;
01363 }
01364 
01365 static inline PCCERT_CONTEXT cert_compare_certs_in_store(HCERTSTORE store,
01366  PCCERT_CONTEXT prev, CertCompareFunc compare, DWORD dwType, DWORD dwFlags,
01367  const void *pvPara)
01368 {
01369     BOOL matches = FALSE;
01370     PCCERT_CONTEXT ret;
01371 
01372     ret = prev;
01373     do {
01374         ret = CertEnumCertificatesInStore(store, ret);
01375         if (ret)
01376             matches = compare(ret, dwType, dwFlags, pvPara);
01377     } while (ret != NULL && !matches);
01378     return ret;
01379 }
01380 
01381 typedef PCCERT_CONTEXT (*CertFindFunc)(HCERTSTORE store, DWORD dwType,
01382  DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev);
01383 
01384 static PCCERT_CONTEXT find_cert_any(HCERTSTORE store, DWORD dwType,
01385  DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev)
01386 {
01387     return CertEnumCertificatesInStore(store, prev);
01388 }
01389 
01390 static PCCERT_CONTEXT find_cert_by_issuer(HCERTSTORE store, DWORD dwType,
01391  DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev)
01392 {
01393     BOOL ret;
01394     PCCERT_CONTEXT found = NULL, subject = pvPara;
01395     PCERT_EXTENSION ext;
01396     DWORD size;
01397 
01398     if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER,
01399      subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension)))
01400     {
01401         CERT_AUTHORITY_KEY_ID_INFO *info;
01402 
01403         ret = CryptDecodeObjectEx(subject->dwCertEncodingType,
01404          X509_AUTHORITY_KEY_ID, ext->Value.pbData, ext->Value.cbData,
01405          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
01406          &info, &size);
01407         if (ret)
01408         {
01409             CERT_ID id;
01410 
01411             if (info->CertIssuer.cbData && info->CertSerialNumber.cbData)
01412             {
01413                 id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
01414                 memcpy(&id.u.IssuerSerialNumber.Issuer, &info->CertIssuer,
01415                  sizeof(CERT_NAME_BLOB));
01416                 memcpy(&id.u.IssuerSerialNumber.SerialNumber,
01417                  &info->CertSerialNumber, sizeof(CRYPT_INTEGER_BLOB));
01418             }
01419             else if (info->KeyId.cbData)
01420             {
01421                 id.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
01422                 memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB));
01423             }
01424             else
01425                 ret = FALSE;
01426             if (ret)
01427                 found = cert_compare_certs_in_store(store, prev,
01428                  compare_cert_by_cert_id, dwType, dwFlags, &id);
01429             LocalFree(info);
01430         }
01431     }
01432     else if ((ext = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER2,
01433      subject->pCertInfo->cExtension, subject->pCertInfo->rgExtension)))
01434     {
01435         CERT_AUTHORITY_KEY_ID2_INFO *info;
01436 
01437         ret = CryptDecodeObjectEx(subject->dwCertEncodingType,
01438          X509_AUTHORITY_KEY_ID2, ext->Value.pbData, ext->Value.cbData,
01439          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
01440          &info, &size);
01441         if (ret)
01442         {
01443             CERT_ID id;
01444 
01445             if (info->AuthorityCertIssuer.cAltEntry &&
01446              info->AuthorityCertSerialNumber.cbData)
01447             {
01448                 PCERT_ALT_NAME_ENTRY directoryName = NULL;
01449                 DWORD i;
01450 
01451                 for (i = 0; !directoryName &&
01452                  i < info->AuthorityCertIssuer.cAltEntry; i++)
01453                     if (info->AuthorityCertIssuer.rgAltEntry[i].dwAltNameChoice
01454                      == CERT_ALT_NAME_DIRECTORY_NAME)
01455                         directoryName =
01456                          &info->AuthorityCertIssuer.rgAltEntry[i];
01457                 if (directoryName)
01458                 {
01459                     id.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
01460                     memcpy(&id.u.IssuerSerialNumber.Issuer,
01461                      &directoryName->u.DirectoryName, sizeof(CERT_NAME_BLOB));
01462                     memcpy(&id.u.IssuerSerialNumber.SerialNumber,
01463                      &info->AuthorityCertSerialNumber,
01464                      sizeof(CRYPT_INTEGER_BLOB));
01465                 }
01466                 else
01467                 {
01468                     FIXME("no supported name type in authority key id2\n");
01469                     ret = FALSE;
01470                 }
01471             }
01472             else if (info->KeyId.cbData)
01473             {
01474                 id.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
01475                 memcpy(&id.u.KeyId, &info->KeyId, sizeof(CRYPT_HASH_BLOB));
01476             }
01477             else
01478                 ret = FALSE;
01479             if (ret)
01480                 found = cert_compare_certs_in_store(store, prev,
01481                  compare_cert_by_cert_id, dwType, dwFlags, &id);
01482             LocalFree(info);
01483         }
01484     }
01485     else
01486        found = cert_compare_certs_in_store(store, prev,
01487         compare_cert_by_name, CERT_COMPARE_NAME | CERT_COMPARE_SUBJECT_CERT,
01488         dwFlags, &subject->pCertInfo->Issuer);
01489     return found;
01490 }
01491 
01492 static BOOL compare_cert_by_name_str(PCCERT_CONTEXT pCertContext,
01493  DWORD dwType, DWORD dwFlags, const void *pvPara)
01494 {
01495     PCERT_NAME_BLOB name;
01496     DWORD len;
01497     BOOL ret = FALSE;
01498 
01499     if (dwType & CERT_INFO_SUBJECT_FLAG)
01500         name = &pCertContext->pCertInfo->Subject;
01501     else
01502         name = &pCertContext->pCertInfo->Issuer;
01503     len = CertNameToStrW(pCertContext->dwCertEncodingType, name,
01504      CERT_SIMPLE_NAME_STR, NULL, 0);
01505     if (len)
01506     {
01507         LPWSTR str = CryptMemAlloc(len * sizeof(WCHAR));
01508 
01509         if (str)
01510         {
01511             LPWSTR ptr;
01512 
01513             CertNameToStrW(pCertContext->dwCertEncodingType, name,
01514              CERT_SIMPLE_NAME_STR, str, len);
01515             for (ptr = str; *ptr; ptr++)
01516                 *ptr = tolowerW(*ptr);
01517             if (strstrW(str, pvPara))
01518                 ret = TRUE;
01519             CryptMemFree(str);
01520         }
01521     }
01522     return ret;
01523 }
01524 
01525 static PCCERT_CONTEXT find_cert_by_name_str_a(HCERTSTORE store, DWORD dwType,
01526  DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev)
01527 {
01528     PCCERT_CONTEXT found = NULL;
01529 
01530     TRACE("%s\n", debugstr_a(pvPara));
01531 
01532     if (pvPara)
01533     {
01534         int len = MultiByteToWideChar(CP_ACP, 0, pvPara, -1, NULL, 0);
01535         LPWSTR str = CryptMemAlloc(len * sizeof(WCHAR));
01536 
01537         if (str)
01538         {
01539             LPWSTR ptr;
01540 
01541             MultiByteToWideChar(CP_ACP, 0, pvPara, -1, str, len);
01542             for (ptr = str; *ptr; ptr++)
01543                 *ptr = tolowerW(*ptr);
01544             found = cert_compare_certs_in_store(store, prev,
01545              compare_cert_by_name_str, dwType, dwFlags, str);
01546             CryptMemFree(str);
01547         }
01548     }
01549     else
01550         found = find_cert_any(store, dwType, dwFlags, NULL, prev);
01551     return found;
01552 }
01553 
01554 static PCCERT_CONTEXT find_cert_by_name_str_w(HCERTSTORE store, DWORD dwType,
01555  DWORD dwFlags, const void *pvPara, PCCERT_CONTEXT prev)
01556 {
01557     PCCERT_CONTEXT found = NULL;
01558 
01559     TRACE("%s\n", debugstr_w(pvPara));
01560 
01561     if (pvPara)
01562     {
01563         DWORD len = strlenW(pvPara);
01564         LPWSTR str = CryptMemAlloc((len + 1) * sizeof(WCHAR));
01565 
01566         if (str)
01567         {
01568             LPCWSTR src;
01569             LPWSTR dst;
01570 
01571             for (src = pvPara, dst = str; *src; src++, dst++)
01572                 *dst = tolowerW(*src);
01573             *dst = 0;
01574            found = cert_compare_certs_in_store(store, prev,
01575             compare_cert_by_name_str, dwType, dwFlags, str);
01576            CryptMemFree(str);
01577         }
01578     }
01579     else
01580         found = find_cert_any(store, dwType, dwFlags, NULL, prev);
01581     return found;
01582 }
01583 
01584 PCCERT_CONTEXT WINAPI CertFindCertificateInStore(HCERTSTORE hCertStore,
01585  DWORD dwCertEncodingType, DWORD dwFlags, DWORD dwType, const void *pvPara,
01586  PCCERT_CONTEXT pPrevCertContext)
01587 {
01588     PCCERT_CONTEXT ret;
01589     CertFindFunc find = NULL;
01590     CertCompareFunc compare = NULL;
01591 
01592     TRACE("(%p, %08x, %08x, %08x, %p, %p)\n", hCertStore, dwCertEncodingType,
01593      dwFlags, dwType, pvPara, pPrevCertContext);
01594 
01595     switch (dwType >> CERT_COMPARE_SHIFT)
01596     {
01597     case CERT_COMPARE_ANY:
01598         find = find_cert_any;
01599         break;
01600     case CERT_COMPARE_MD5_HASH:
01601         compare = compare_cert_by_md5_hash;
01602         break;
01603     case CERT_COMPARE_SHA1_HASH:
01604         compare = compare_cert_by_sha1_hash;
01605         break;
01606     case CERT_COMPARE_NAME:
01607         compare = compare_cert_by_name;
01608         break;
01609     case CERT_COMPARE_PUBLIC_KEY:
01610         compare = compare_cert_by_public_key;
01611         break;
01612     case CERT_COMPARE_NAME_STR_A:
01613         find = find_cert_by_name_str_a;
01614         break;
01615     case CERT_COMPARE_NAME_STR_W:
01616         find = find_cert_by_name_str_w;
01617         break;
01618     case CERT_COMPARE_SUBJECT_CERT:
01619         compare = compare_cert_by_subject_cert;
01620         break;
01621     case CERT_COMPARE_CERT_ID:
01622         compare = compare_cert_by_cert_id;
01623         break;
01624     case CERT_COMPARE_ISSUER_OF:
01625         find = find_cert_by_issuer;
01626         break;
01627     case CERT_COMPARE_EXISTING:
01628         compare = compare_existing_cert;
01629         break;
01630     case CERT_COMPARE_SIGNATURE_HASH:
01631         compare = compare_cert_by_signature_hash;
01632         break;
01633     default:
01634         FIXME("find type %08x unimplemented\n", dwType);
01635     }
01636 
01637     if (find)
01638         ret = find(hCertStore, dwFlags, dwType, pvPara, pPrevCertContext);
01639     else if (compare)
01640         ret = cert_compare_certs_in_store(hCertStore, pPrevCertContext,
01641          compare, dwType, dwFlags, pvPara);
01642     else
01643         ret = NULL;
01644     if (!ret)
01645         SetLastError(CRYPT_E_NOT_FOUND);
01646     TRACE("returning %p\n", ret);
01647     return ret;
01648 }
01649 
01650 PCCERT_CONTEXT WINAPI CertGetSubjectCertificateFromStore(HCERTSTORE hCertStore,
01651  DWORD dwCertEncodingType, PCERT_INFO pCertId)
01652 {
01653     TRACE("(%p, %08x, %p)\n", hCertStore, dwCertEncodingType, pCertId);
01654 
01655     if (!pCertId)
01656     {
01657         SetLastError(E_INVALIDARG);
01658         return NULL;
01659     }
01660     return CertFindCertificateInStore(hCertStore, dwCertEncodingType, 0,
01661      CERT_FIND_SUBJECT_CERT, pCertId, NULL);
01662 }
01663 
01664 BOOL WINAPI CertVerifySubjectCertificateContext(PCCERT_CONTEXT pSubject,
01665  PCCERT_CONTEXT pIssuer, DWORD *pdwFlags)
01666 {
01667     static const DWORD supportedFlags = CERT_STORE_REVOCATION_FLAG |
01668      CERT_STORE_SIGNATURE_FLAG | CERT_STORE_TIME_VALIDITY_FLAG;
01669 
01670     if (*pdwFlags & ~supportedFlags)
01671     {
01672         SetLastError(E_INVALIDARG);
01673         return FALSE;
01674     }
01675     if (*pdwFlags & CERT_STORE_REVOCATION_FLAG)
01676     {
01677         DWORD flags = 0;
01678         PCCRL_CONTEXT crl = CertGetCRLFromStore(pSubject->hCertStore, pSubject,
01679          NULL, &flags);
01680 
01681         /* FIXME: what if the CRL has expired? */
01682         if (crl)
01683         {
01684             if (CertVerifyCRLRevocation(pSubject->dwCertEncodingType,
01685              pSubject->pCertInfo, 1, (PCRL_INFO *)&crl->pCrlInfo))
01686                 *pdwFlags &= CERT_STORE_REVOCATION_FLAG;
01687         }
01688         else
01689             *pdwFlags |= CERT_STORE_NO_CRL_FLAG;
01690     }
01691     if (*pdwFlags & CERT_STORE_TIME_VALIDITY_FLAG)
01692     {
01693         if (0 == CertVerifyTimeValidity(NULL, pSubject->pCertInfo))
01694             *pdwFlags &= ~CERT_STORE_TIME_VALIDITY_FLAG;
01695     }
01696     if (*pdwFlags & CERT_STORE_SIGNATURE_FLAG)
01697     {
01698         if (CryptVerifyCertificateSignatureEx(0, pSubject->dwCertEncodingType,
01699          CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT, (void *)pSubject,
01700          CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT, (void *)pIssuer, 0, NULL))
01701             *pdwFlags &= ~CERT_STORE_SIGNATURE_FLAG;
01702     }
01703     return TRUE;
01704 }
01705 
01706 PCCERT_CONTEXT WINAPI CertGetIssuerCertificateFromStore(HCERTSTORE hCertStore,
01707  PCCERT_CONTEXT pSubjectContext, PCCERT_CONTEXT pPrevIssuerContext,
01708  DWORD *pdwFlags)
01709 {
01710     PCCERT_CONTEXT ret;
01711 
01712     TRACE("(%p, %p, %p, %08x)\n", hCertStore, pSubjectContext,
01713      pPrevIssuerContext, *pdwFlags);
01714 
01715     if (!pSubjectContext)
01716     {
01717         SetLastError(E_INVALIDARG);
01718         return NULL;
01719     }
01720 
01721     ret = CertFindCertificateInStore(hCertStore,
01722      pSubjectContext->dwCertEncodingType, 0, CERT_FIND_ISSUER_OF,
01723      pSubjectContext, pPrevIssuerContext);
01724     if (ret)
01725     {
01726         if (!CertVerifySubjectCertificateContext(pSubjectContext, ret,
01727          pdwFlags))
01728         {
01729             CertFreeCertificateContext(ret);
01730             ret = NULL;
01731         }
01732     }
01733     TRACE("returning %p\n", ret);
01734     return ret;
01735 }
01736 
01737 typedef struct _OLD_CERT_REVOCATION_STATUS {
01738     DWORD cbSize;
01739     DWORD dwIndex;
01740     DWORD dwError;
01741     DWORD dwReason;
01742 } OLD_CERT_REVOCATION_STATUS, *POLD_CERT_REVOCATION_STATUS;
01743 
01744 typedef BOOL (WINAPI *CertVerifyRevocationFunc)(DWORD, DWORD, DWORD,
01745  void **, DWORD, PCERT_REVOCATION_PARA, PCERT_REVOCATION_STATUS);
01746 
01747 BOOL WINAPI CertVerifyRevocation(DWORD dwEncodingType, DWORD dwRevType,
01748  DWORD cContext, PVOID rgpvContext[], DWORD dwFlags,
01749  PCERT_REVOCATION_PARA pRevPara, PCERT_REVOCATION_STATUS pRevStatus)
01750 {
01751     BOOL ret;
01752 
01753     TRACE("(%08x, %d, %d, %p, %08x, %p, %p)\n", dwEncodingType, dwRevType,
01754      cContext, rgpvContext, dwFlags, pRevPara, pRevStatus);
01755 
01756     if (pRevStatus->cbSize != sizeof(OLD_CERT_REVOCATION_STATUS) &&
01757      pRevStatus->cbSize != sizeof(CERT_REVOCATION_STATUS))
01758     {
01759         SetLastError(E_INVALIDARG);
01760         return FALSE;
01761     }
01762     if (cContext)
01763     {
01764         static HCRYPTOIDFUNCSET set = NULL;
01765         DWORD size;
01766 
01767         if (!set)
01768             set = CryptInitOIDFunctionSet(CRYPT_OID_VERIFY_REVOCATION_FUNC, 0);
01769         ret = CryptGetDefaultOIDDllList(set, dwEncodingType, NULL, &size);
01770         if (ret)
01771         {
01772             if (size == 1)
01773             {
01774                 /* empty list */
01775                 SetLastError(CRYPT_E_NO_REVOCATION_DLL);
01776                 ret = FALSE;
01777             }
01778             else
01779             {
01780                 LPWSTR dllList = CryptMemAlloc(size * sizeof(WCHAR)), ptr;
01781 
01782                 if (dllList)
01783                 {
01784                     ret = CryptGetDefaultOIDDllList(set, dwEncodingType,
01785                      dllList, &size);
01786                     if (ret)
01787                     {
01788                         for (ptr = dllList; ret && *ptr;
01789                          ptr += lstrlenW(ptr) + 1)
01790                         {
01791                             CertVerifyRevocationFunc func;
01792                             HCRYPTOIDFUNCADDR hFunc;
01793 
01794                             ret = CryptGetDefaultOIDFunctionAddress(set,
01795                              dwEncodingType, ptr, 0, (void **)&func, &hFunc);
01796                             if (ret)
01797                             {
01798                                 ret = func(dwEncodingType, dwRevType, cContext,
01799                                  rgpvContext, dwFlags, pRevPara, pRevStatus);
01800                                 CryptFreeOIDFunctionAddress(hFunc, 0);
01801                             }
01802                         }
01803                     }
01804                     CryptMemFree(dllList);
01805                 }
01806                 else
01807                 {
01808                     SetLastError(ERROR_OUTOFMEMORY);
01809                     ret = FALSE;
01810                 }
01811             }
01812         }
01813     }
01814     else
01815         ret = TRUE;
01816     return ret;
01817 }
01818 
01819 PCRYPT_ATTRIBUTE WINAPI CertFindAttribute(LPCSTR pszObjId, DWORD cAttr,
01820  CRYPT_ATTRIBUTE rgAttr[])
01821 {
01822     PCRYPT_ATTRIBUTE ret = NULL;
01823     DWORD i;
01824 
01825     TRACE("%s %d %p\n", debugstr_a(pszObjId), cAttr, rgAttr);
01826 
01827     if (!cAttr)
01828         return NULL;
01829     if (!pszObjId)
01830     {
01831         SetLastError(ERROR_INVALID_PARAMETER);
01832         return NULL;
01833     }
01834 
01835     for (i = 0; !ret && i < cAttr; i++)
01836         if (rgAttr[i].pszObjId && !strcmp(pszObjId, rgAttr[i].pszObjId))
01837             ret = &rgAttr[i];
01838     return ret;
01839 }
01840 
01841 PCERT_EXTENSION WINAPI CertFindExtension(LPCSTR pszObjId, DWORD cExtensions,
01842  CERT_EXTENSION rgExtensions[])
01843 {
01844     PCERT_EXTENSION ret = NULL;
01845     DWORD i;
01846 
01847     TRACE("%s %d %p\n", debugstr_a(pszObjId), cExtensions, rgExtensions);
01848 
01849     if (!cExtensions)
01850         return NULL;
01851     if (!pszObjId)
01852     {
01853         SetLastError(ERROR_INVALID_PARAMETER);
01854         return NULL;
01855     }
01856 
01857     for (i = 0; !ret && i < cExtensions; i++)
01858         if (rgExtensions[i].pszObjId && !strcmp(pszObjId,
01859          rgExtensions[i].pszObjId))
01860             ret = &rgExtensions[i];
01861     return ret;
01862 }
01863 
01864 PCERT_RDN_ATTR WINAPI CertFindRDNAttr(LPCSTR pszObjId, PCERT_NAME_INFO pName)
01865 {
01866     PCERT_RDN_ATTR ret = NULL;
01867     DWORD i, j;
01868 
01869     TRACE("%s %p\n", debugstr_a(pszObjId), pName);
01870 
01871     if (!pszObjId)
01872     {
01873         SetLastError(ERROR_INVALID_PARAMETER);
01874         return NULL;
01875     }
01876 
01877     for (i = 0; !ret && i < pName->cRDN; i++)
01878         for (j = 0; !ret && j < pName->rgRDN[i].cRDNAttr; j++)
01879             if (pName->rgRDN[i].rgRDNAttr[j].pszObjId && !strcmp(pszObjId,
01880              pName->rgRDN[i].rgRDNAttr[j].pszObjId))
01881                 ret = &pName->rgRDN[i].rgRDNAttr[j];
01882     return ret;
01883 }
01884 
01885 static BOOL find_matching_rdn_attr(DWORD dwFlags, const CERT_NAME_INFO *name,
01886  const CERT_RDN_ATTR *attr)
01887 {
01888     DWORD i, j;
01889     BOOL match = FALSE;
01890 
01891     for (i = 0; !match && i < name->cRDN; i++)
01892     {
01893         for (j = 0; j < name->rgRDN[i].cRDNAttr; j++)
01894         {
01895             if (!strcmp(name->rgRDN[i].rgRDNAttr[j].pszObjId,
01896              attr->pszObjId) &&
01897              name->rgRDN[i].rgRDNAttr[j].dwValueType ==
01898              attr->dwValueType)
01899             {
01900                 if (dwFlags & CERT_UNICODE_IS_RDN_ATTRS_FLAG)
01901                 {
01902                     LPCWSTR nameStr =
01903                      (LPCWSTR)name->rgRDN[i].rgRDNAttr[j].Value.pbData;
01904                     LPCWSTR attrStr = (LPCWSTR)attr->Value.pbData;
01905 
01906                     if (attr->Value.cbData !=
01907                      name->rgRDN[i].rgRDNAttr[j].Value.cbData)
01908                         match = FALSE;
01909                     else if (dwFlags & CERT_CASE_INSENSITIVE_IS_RDN_ATTRS_FLAG)
01910                         match = !strncmpiW(nameStr, attrStr,
01911                          attr->Value.cbData / sizeof(WCHAR));
01912                     else
01913                         match = !strncmpW(nameStr, attrStr,
01914                          attr->Value.cbData / sizeof(WCHAR));
01915                     TRACE("%s : %s => %d\n",
01916                      debugstr_wn(nameStr, attr->Value.cbData / sizeof(WCHAR)),
01917                      debugstr_wn(attrStr, attr->Value.cbData / sizeof(WCHAR)),
01918                      match);
01919                 }
01920                 else
01921                 {
01922                     LPCSTR nameStr =
01923                      (LPCSTR)name->rgRDN[i].rgRDNAttr[j].Value.pbData;
01924                     LPCSTR attrStr = (LPCSTR)attr->Value.pbData;
01925 
01926                     if (attr->Value.cbData !=
01927                      name->rgRDN[i].rgRDNAttr[j].Value.cbData)
01928                         match = FALSE;
01929                     else if (dwFlags & CERT_CASE_INSENSITIVE_IS_RDN_ATTRS_FLAG)
01930                         match = !strncasecmp(nameStr, attrStr,
01931                          attr->Value.cbData);
01932                     else
01933                         match = !strncmp(nameStr, attrStr, attr->Value.cbData);
01934                     TRACE("%s : %s => %d\n",
01935                      debugstr_an(nameStr, attr->Value.cbData),
01936                      debugstr_an(attrStr, attr->Value.cbData), match);
01937                 }
01938             }
01939         }
01940     }
01941     return match;
01942 }
01943 
01944 BOOL WINAPI CertIsRDNAttrsInCertificateName(DWORD dwCertEncodingType,
01945  DWORD dwFlags, PCERT_NAME_BLOB pCertName, PCERT_RDN pRDN)
01946 {
01947     CERT_NAME_INFO *name;
01948     LPCSTR type;
01949     DWORD size;
01950     BOOL ret;
01951 
01952     TRACE("(%08x, %08x, %p, %p)\n", dwCertEncodingType, dwFlags, pCertName,
01953      pRDN);
01954 
01955     type = dwFlags & CERT_UNICODE_IS_RDN_ATTRS_FLAG ? X509_UNICODE_NAME :
01956      X509_NAME;
01957     if ((ret = CryptDecodeObjectEx(dwCertEncodingType, type, pCertName->pbData,
01958      pCertName->cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, &name, &size)))
01959     {
01960         DWORD i;
01961 
01962         for (i = 0; ret && i < pRDN->cRDNAttr; i++)
01963             ret = find_matching_rdn_attr(dwFlags, name, &pRDN->rgRDNAttr[i]);
01964         if (!ret)
01965             SetLastError(CRYPT_E_NO_MATCH);
01966         LocalFree(name);
01967     }
01968     return ret;
01969 }
01970 
01971 LONG WINAPI CertVerifyTimeValidity(LPFILETIME pTimeToVerify,
01972  PCERT_INFO pCertInfo)
01973 {
01974     FILETIME fileTime;
01975     LONG ret;
01976 
01977     if (!pTimeToVerify)
01978     {
01979         GetSystemTimeAsFileTime(&fileTime);
01980         pTimeToVerify = &fileTime;
01981     }
01982     if ((ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotBefore)) >= 0)
01983     {
01984         ret = CompareFileTime(pTimeToVerify, &pCertInfo->NotAfter);
01985         if (ret < 0)
01986             ret = 0;
01987     }
01988     return ret;
01989 }
01990 
01991 BOOL WINAPI CertVerifyValidityNesting(PCERT_INFO pSubjectInfo,
01992  PCERT_INFO pIssuerInfo)
01993 {
01994     TRACE("(%p, %p)\n", pSubjectInfo, pIssuerInfo);
01995 
01996     return CertVerifyTimeValidity(&pSubjectInfo->NotBefore, pIssuerInfo) == 0
01997      && CertVerifyTimeValidity(&pSubjectInfo->NotAfter, pIssuerInfo) == 0;
01998 }
01999 
02000 BOOL WINAPI CryptHashCertificate(HCRYPTPROV_LEGACY hCryptProv, ALG_ID Algid,
02001  DWORD dwFlags, const BYTE *pbEncoded, DWORD cbEncoded, BYTE *pbComputedHash,
02002  DWORD *pcbComputedHash)
02003 {
02004     BOOL ret = TRUE;
02005     HCRYPTHASH hHash = 0;
02006 
02007     TRACE("(%08lx, %d, %08x, %p, %d, %p, %p)\n", hCryptProv, Algid, dwFlags,
02008      pbEncoded, cbEncoded, pbComputedHash, pcbComputedHash);
02009 
02010     if (!hCryptProv)
02011         hCryptProv = CRYPT_GetDefaultProvider();
02012     if (!Algid)
02013         Algid = CALG_SHA1;
02014     if (ret)
02015     {
02016         ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
02017         if (ret)
02018         {
02019             ret = CryptHashData(hHash, pbEncoded, cbEncoded, 0);
02020             if (ret)
02021                 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
02022                  pcbComputedHash, 0);
02023             CryptDestroyHash(hHash);
02024         }
02025     }
02026     return ret;
02027 }
02028 
02029 BOOL WINAPI CryptHashPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv, ALG_ID Algid,
02030  DWORD dwFlags, DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo,
02031  BYTE *pbComputedHash, DWORD *pcbComputedHash)
02032 {
02033     BOOL ret = TRUE;
02034     HCRYPTHASH hHash = 0;
02035 
02036     TRACE("(%08lx, %d, %08x, %d, %p, %p, %p)\n", hCryptProv, Algid, dwFlags,
02037      dwCertEncodingType, pInfo, pbComputedHash, pcbComputedHash);
02038 
02039     if (!hCryptProv)
02040         hCryptProv = CRYPT_GetDefaultProvider();
02041     if (!Algid)
02042         Algid = CALG_MD5;
02043     if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING)
02044     {
02045         SetLastError(ERROR_FILE_NOT_FOUND);
02046         return FALSE;
02047     }
02048     if (ret)
02049     {
02050         BYTE *buf;
02051         DWORD size = 0;
02052 
02053         ret = CRYPT_AsnEncodePubKeyInfoNoNull(dwCertEncodingType,
02054          X509_PUBLIC_KEY_INFO, pInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL,
02055          (LPBYTE)&buf, &size);
02056         if (ret)
02057         {
02058             ret = CryptCreateHash(hCryptProv, Algid, 0, 0, &hHash);
02059             if (ret)
02060             {
02061                 ret = CryptHashData(hHash, buf, size, 0);
02062                 if (ret)
02063                     ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
02064                      pcbComputedHash, 0);
02065                 CryptDestroyHash(hHash);
02066             }
02067             LocalFree(buf);
02068         }
02069     }
02070     return ret;
02071 }
02072 
02073 BOOL WINAPI CryptHashToBeSigned(HCRYPTPROV_LEGACY hCryptProv,
02074  DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
02075  BYTE *pbComputedHash, DWORD *pcbComputedHash)
02076 {
02077     BOOL ret;
02078     CERT_SIGNED_CONTENT_INFO *info;
02079     DWORD size;
02080 
02081     TRACE("(%08lx, %08x, %p, %d, %p, %d)\n", hCryptProv, dwCertEncodingType,
02082      pbEncoded, cbEncoded, pbComputedHash, *pcbComputedHash);
02083 
02084     ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT,
02085      pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size);
02086     if (ret)
02087     {
02088         PCCRYPT_OID_INFO oidInfo;
02089         HCRYPTHASH hHash;
02090 
02091         if (!hCryptProv)
02092             hCryptProv = CRYPT_GetDefaultProvider();
02093         oidInfo = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
02094          info->SignatureAlgorithm.pszObjId, 0);
02095         if (!oidInfo)
02096         {
02097             SetLastError(NTE_BAD_ALGID);
02098             ret = FALSE;
02099         }
02100         else
02101         {
02102             ret = CryptCreateHash(hCryptProv, oidInfo->u.Algid, 0, 0, &hHash);
02103             if (ret)
02104             {
02105                 ret = CryptHashData(hHash, info->ToBeSigned.pbData,
02106                  info->ToBeSigned.cbData, 0);
02107                 if (ret)
02108                     ret = CryptGetHashParam(hHash, HP_HASHVAL, pbComputedHash,
02109                      pcbComputedHash, 0);
02110                 CryptDestroyHash(hHash);
02111             }
02112         }
02113         LocalFree(info);
02114     }
02115     return ret;
02116 }
02117 
02118 BOOL WINAPI CryptSignCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv,
02119  DWORD dwKeySpec, DWORD dwCertEncodingType, const BYTE *pbEncodedToBeSigned,
02120  DWORD cbEncodedToBeSigned, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
02121  const void *pvHashAuxInfo, BYTE *pbSignature, DWORD *pcbSignature)
02122 {
02123     BOOL ret;
02124     PCCRYPT_OID_INFO info;
02125     HCRYPTHASH hHash;
02126 
02127     TRACE("(%08lx, %d, %d, %p, %d, %p, %p, %p, %p)\n", hCryptProv,
02128      dwKeySpec, dwCertEncodingType, pbEncodedToBeSigned, cbEncodedToBeSigned,
02129      pSignatureAlgorithm, pvHashAuxInfo, pbSignature, pcbSignature);
02130 
02131     info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
02132      pSignatureAlgorithm->pszObjId, 0);
02133     if (!info)
02134     {
02135         SetLastError(NTE_BAD_ALGID);
02136         return FALSE;
02137     }
02138     if (info->dwGroupId == CRYPT_HASH_ALG_OID_GROUP_ID)
02139     {
02140         if (!hCryptProv)
02141             hCryptProv = CRYPT_GetDefaultProvider();
02142         ret = CryptCreateHash(hCryptProv, info->u.Algid, 0, 0, &hHash);
02143         if (ret)
02144         {
02145             ret = CryptHashData(hHash, pbEncodedToBeSigned,
02146              cbEncodedToBeSigned, 0);
02147             if (ret)
02148                 ret = CryptGetHashParam(hHash, HP_HASHVAL, pbSignature,
02149                  pcbSignature, 0);
02150             CryptDestroyHash(hHash);
02151         }
02152     }
02153     else
02154     {
02155         if (!hCryptProv)
02156         {
02157             SetLastError(ERROR_INVALID_PARAMETER);
02158             ret = FALSE;
02159         }
02160         else
02161         {
02162             ret = CryptCreateHash(hCryptProv, info->u.Algid, 0, 0, &hHash);
02163             if (ret)
02164             {
02165                 ret = CryptHashData(hHash, pbEncodedToBeSigned,
02166                  cbEncodedToBeSigned, 0);
02167                 if (ret)
02168                     ret = CryptSignHashW(hHash, dwKeySpec, NULL, 0, pbSignature,
02169                      pcbSignature);
02170                 CryptDestroyHash(hHash);
02171             }
02172         }
02173     }
02174     return ret;
02175 }
02176 
02177 BOOL WINAPI CryptSignAndEncodeCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv,
02178  DWORD dwKeySpec, DWORD dwCertEncodingType, LPCSTR lpszStructType,
02179  const void *pvStructInfo, PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
02180  const void *pvHashAuxInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
02181 {
02182     BOOL ret;
02183     DWORD encodedSize, hashSize;
02184 
02185     TRACE("(%08lx, %d, %d, %s, %p, %p, %p, %p, %p)\n", hCryptProv, dwKeySpec,
02186      dwCertEncodingType, debugstr_a(lpszStructType), pvStructInfo,
02187      pSignatureAlgorithm, pvHashAuxInfo, pbEncoded, pcbEncoded);
02188 
02189     ret = CryptEncodeObject(dwCertEncodingType, lpszStructType, pvStructInfo,
02190      NULL, &encodedSize);
02191     if (ret)
02192     {
02193         PBYTE encoded = CryptMemAlloc(encodedSize);
02194 
02195         if (encoded)
02196         {
02197             ret = CryptEncodeObject(dwCertEncodingType, lpszStructType,
02198              pvStructInfo, encoded, &encodedSize);
02199             if (ret)
02200             {
02201                 ret = CryptSignCertificate(hCryptProv, dwKeySpec,
02202                  dwCertEncodingType, encoded, encodedSize, pSignatureAlgorithm,
02203                  pvHashAuxInfo, NULL, &hashSize);
02204                 if (ret)
02205                 {
02206                     PBYTE hash = CryptMemAlloc(hashSize);
02207 
02208                     if (hash)
02209                     {
02210                         ret = CryptSignCertificate(hCryptProv, dwKeySpec,
02211                          dwCertEncodingType, encoded, encodedSize,
02212                          pSignatureAlgorithm, pvHashAuxInfo, hash, &hashSize);
02213                         if (ret)
02214                         {
02215                             CERT_SIGNED_CONTENT_INFO info = { { 0 } };
02216 
02217                             info.ToBeSigned.cbData = encodedSize;
02218                             info.ToBeSigned.pbData = encoded;
02219                             memcpy(&info.SignatureAlgorithm,
02220                              pSignatureAlgorithm,
02221                              sizeof(info.SignatureAlgorithm));
02222                             info.Signature.cbData = hashSize;
02223                             info.Signature.pbData = hash;
02224                             info.Signature.cUnusedBits = 0;
02225                             ret = CryptEncodeObject(dwCertEncodingType,
02226                              X509_CERT, &info, pbEncoded, pcbEncoded);
02227                         }
02228                         CryptMemFree(hash);
02229                     }
02230                 }
02231             }
02232             CryptMemFree(encoded);
02233         }
02234     }
02235     return ret;
02236 }
02237 
02238 BOOL WINAPI CryptVerifyCertificateSignature(HCRYPTPROV_LEGACY hCryptProv,
02239  DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
02240  PCERT_PUBLIC_KEY_INFO pPublicKey)
02241 {
02242     return CryptVerifyCertificateSignatureEx(hCryptProv, dwCertEncodingType,
02243      CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB, (void *)pbEncoded,
02244      CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY, pPublicKey, 0, NULL);
02245 }
02246 
02247 static BOOL CRYPT_VerifyCertSignatureFromPublicKeyInfo(HCRYPTPROV_LEGACY hCryptProv,
02248  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pubKeyInfo,
02249  const CERT_SIGNED_CONTENT_INFO *signedCert)
02250 {
02251     BOOL ret;
02252     HCRYPTKEY key;
02253     PCCRYPT_OID_INFO info;
02254     ALG_ID pubKeyID, hashID;
02255 
02256     info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
02257      signedCert->SignatureAlgorithm.pszObjId, 0);
02258     if (!info || info->dwGroupId != CRYPT_SIGN_ALG_OID_GROUP_ID)
02259     {
02260         SetLastError(NTE_BAD_ALGID);
02261         return FALSE;
02262     }
02263     hashID = info->u.Algid;
02264     if (info->ExtraInfo.cbData >= sizeof(ALG_ID))
02265         pubKeyID = *(ALG_ID *)info->ExtraInfo.pbData;
02266     else
02267         pubKeyID = hashID;
02268     /* Load the default provider if necessary */
02269     if (!hCryptProv)
02270         hCryptProv = CRYPT_GetDefaultProvider();
02271     ret = CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType,
02272      pubKeyInfo, pubKeyID, 0, NULL, &key);
02273     if (ret)
02274     {
02275         HCRYPTHASH hash;
02276 
02277         ret = CryptCreateHash(hCryptProv, hashID, 0, 0, &hash);
02278         if (ret)
02279         {
02280             ret = CryptHashData(hash, signedCert->ToBeSigned.pbData,
02281              signedCert->ToBeSigned.cbData, 0);
02282             if (ret)
02283                 ret = CryptVerifySignatureW(hash, signedCert->Signature.pbData,
02284                  signedCert->Signature.cbData, key, NULL, 0);
02285             CryptDestroyHash(hash);
02286         }
02287         CryptDestroyKey(key);
02288     }
02289     return ret;
02290 }
02291 
02292 BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV_LEGACY hCryptProv,
02293  DWORD dwCertEncodingType, DWORD dwSubjectType, void *pvSubject,
02294  DWORD dwIssuerType, void *pvIssuer, DWORD dwFlags, void *pvReserved)
02295 {
02296     BOOL ret = TRUE;
02297     CRYPT_DATA_BLOB subjectBlob;
02298 
02299     TRACE("(%08lx, %d, %d, %p, %d, %p, %08x, %p)\n", hCryptProv,
02300      dwCertEncodingType, dwSubjectType, pvSubject, dwIssuerType, pvIssuer,
02301      dwFlags, pvReserved);
02302 
02303     switch (dwSubjectType)
02304     {
02305     case CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB:
02306     {
02307         PCRYPT_DATA_BLOB blob = pvSubject;
02308 
02309         subjectBlob.pbData = blob->pbData;
02310         subjectBlob.cbData = blob->cbData;
02311         break;
02312     }
02313     case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT:
02314     {
02315         PCERT_CONTEXT context = pvSubject;
02316 
02317         subjectBlob.pbData = context->pbCertEncoded;
02318         subjectBlob.cbData = context->cbCertEncoded;
02319         break;
02320     }
02321     case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL:
02322     {
02323         PCRL_CONTEXT context = pvSubject;
02324 
02325         subjectBlob.pbData = context->pbCrlEncoded;
02326         subjectBlob.cbData = context->cbCrlEncoded;
02327         break;
02328     }
02329     default:
02330         SetLastError(E_INVALIDARG);
02331         ret = FALSE;
02332     }
02333 
02334     if (ret)
02335     {
02336         PCERT_SIGNED_CONTENT_INFO signedCert = NULL;
02337         DWORD size = 0;
02338 
02339         ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT,
02340          subjectBlob.pbData, subjectBlob.cbData,
02341          CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
02342          &signedCert, &size);
02343         if (ret)
02344         {
02345             switch (dwIssuerType)
02346             {
02347             case CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY:
02348                 ret = CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv,
02349                  dwCertEncodingType, pvIssuer,
02350                  signedCert);
02351                 break;
02352             case CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT:
02353                 ret = CRYPT_VerifyCertSignatureFromPublicKeyInfo(hCryptProv,
02354                  dwCertEncodingType,
02355                  &((PCCERT_CONTEXT)pvIssuer)->pCertInfo->SubjectPublicKeyInfo,
02356                  signedCert);
02357                 break;
02358             case CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN:
02359                 FIXME("CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN: stub\n");
02360                 ret = FALSE;
02361                 break;
02362             case CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL:
02363                 if (pvIssuer)
02364                 {
02365                     SetLastError(E_INVALIDARG);
02366                     ret = FALSE;
02367                 }
02368                 else
02369                 {
02370                     FIXME("unimplemented for NULL signer\n");
02371                     SetLastError(E_INVALIDARG);
02372                     ret = FALSE;
02373                 }
02374                 break;
02375             default:
02376                 SetLastError(E_INVALIDARG);
02377                 ret = FALSE;
02378             }
02379             LocalFree(signedCert);
02380         }
02381     }
02382     return ret;
02383 }
02384 
02385 BOOL WINAPI CertGetIntendedKeyUsage(DWORD dwCertEncodingType,
02386  PCERT_INFO pCertInfo, BYTE *pbKeyUsage, DWORD cbKeyUsage)
02387 {
02388     PCERT_EXTENSION ext;
02389     BOOL ret = FALSE;
02390 
02391     TRACE("(%08x, %p, %p, %d)\n", dwCertEncodingType, pCertInfo, pbKeyUsage,
02392      cbKeyUsage);
02393 
02394     ext = CertFindExtension(szOID_KEY_USAGE, pCertInfo->cExtension,
02395      pCertInfo->rgExtension);
02396     if (ext)
02397     {
02398         CRYPT_BIT_BLOB usage;
02399         DWORD size = sizeof(usage);
02400 
02401         ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BITS,
02402          ext->Value.pbData, ext->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, NULL,
02403          &usage, &size);
02404         if (ret)
02405         {
02406             if (cbKeyUsage < usage.cbData)
02407                 ret = FALSE;
02408             else
02409             {
02410                 memcpy(pbKeyUsage, usage.pbData, usage.cbData);
02411                 if (cbKeyUsage > usage.cbData)
02412                     memset(pbKeyUsage + usage.cbData, 0,
02413                      cbKeyUsage - usage.cbData);
02414             }
02415         }
02416     }
02417     else
02418         SetLastError(0);
02419     return ret;
02420 }
02421 
02422 BOOL WINAPI CertGetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext, DWORD dwFlags,
02423  PCERT_ENHKEY_USAGE pUsage, DWORD *pcbUsage)
02424 {
02425     PCERT_ENHKEY_USAGE usage = NULL;
02426     DWORD bytesNeeded;
02427     BOOL ret = TRUE;
02428 
02429     if (!pCertContext || !pcbUsage)
02430     {
02431         SetLastError(ERROR_INVALID_PARAMETER);
02432         return FALSE;
02433     }
02434 
02435     TRACE("(%p, %08x, %p, %d)\n", pCertContext, dwFlags, pUsage, *pcbUsage);
02436 
02437     if (!(dwFlags & CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG))
02438     {
02439         DWORD propSize = 0;
02440 
02441         if (CertGetCertificateContextProperty(pCertContext,
02442          CERT_ENHKEY_USAGE_PROP_ID, NULL, &propSize))
02443         {
02444             LPBYTE buf = CryptMemAlloc(propSize);
02445 
02446             if (buf)
02447             {
02448                 if (CertGetCertificateContextProperty(pCertContext,
02449                  CERT_ENHKEY_USAGE_PROP_ID, buf, &propSize))
02450                 {
02451                     ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
02452                      X509_ENHANCED_KEY_USAGE, buf, propSize,
02453                      CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
02454                 }
02455                 CryptMemFree(buf);
02456             }
02457         }
02458     }
02459     if (!usage && !(dwFlags & CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG))
02460     {
02461         PCERT_EXTENSION ext = CertFindExtension(szOID_ENHANCED_KEY_USAGE,
02462          pCertContext->pCertInfo->cExtension,
02463          pCertContext->pCertInfo->rgExtension);
02464 
02465         if (ext)
02466         {
02467             ret = CryptDecodeObjectEx(pCertContext->dwCertEncodingType,
02468              X509_ENHANCED_KEY_USAGE, ext->Value.pbData, ext->Value.cbData,
02469              CRYPT_ENCODE_ALLOC_FLAG, NULL, &usage, &bytesNeeded);
02470         }
02471     }
02472     if (!usage)
02473     {
02474         /* If a particular location is specified, this should fail.  Otherwise
02475          * it should succeed with an empty usage.  (This is true on Win2k and
02476          * later, which we emulate.)
02477          */
02478         if (dwFlags)
02479         {
02480             SetLastError(CRYPT_E_NOT_FOUND);
02481             ret = FALSE;
02482         }
02483         else
02484             bytesNeeded = sizeof(CERT_ENHKEY_USAGE);
02485     }
02486 
02487     if (ret)
02488     {
02489         if (!pUsage)
02490             *pcbUsage = bytesNeeded;
02491         else if (*pcbUsage < bytesNeeded)
02492         {
02493             SetLastError(ERROR_MORE_DATA);
02494             *pcbUsage = bytesNeeded;
02495             ret = FALSE;
02496         }
02497         else
02498         {
02499             *pcbUsage = bytesNeeded;
02500             if (usage)
02501             {
02502                 DWORD i;
02503                 LPSTR nextOID = (LPSTR)((LPBYTE)pUsage +
02504                  sizeof(CERT_ENHKEY_USAGE) +
02505                  usage->cUsageIdentifier * sizeof(LPSTR));
02506 
02507                 pUsage->cUsageIdentifier = usage->cUsageIdentifier;
02508                 pUsage->rgpszUsageIdentifier = (LPSTR *)((LPBYTE)pUsage +
02509                  sizeof(CERT_ENHKEY_USAGE));
02510                 for (i = 0; i < usage->cUsageIdentifier; i++)
02511                 {
02512                     pUsage->rgpszUsageIdentifier[i] = nextOID;
02513                     strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
02514                     nextOID += strlen(nextOID) + 1;
02515                 }
02516             }
02517             else
02518                 pUsage->cUsageIdentifier = 0;
02519         }
02520     }
02521     if (usage)
02522         LocalFree(usage);
02523     TRACE("returning %d\n", ret);
02524     return ret;
02525 }
02526 
02527 BOOL WINAPI CertSetEnhancedKeyUsage(PCCERT_CONTEXT pCertContext,
02528  PCERT_ENHKEY_USAGE pUsage)
02529 {
02530     BOOL ret;
02531 
02532     TRACE("(%p, %p)\n", pCertContext, pUsage);
02533 
02534     if (pUsage)
02535     {
02536         CRYPT_DATA_BLOB blob = { 0, NULL };
02537 
02538         ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE,
02539          pUsage, CRYPT_ENCODE_ALLOC_FLAG, NULL, &blob.pbData, &blob.cbData);
02540         if (ret)
02541         {
02542             ret = CertSetCertificateContextProperty(pCertContext,
02543              CERT_ENHKEY_USAGE_PROP_ID, 0, &blob);
02544             LocalFree(blob.pbData);
02545         }
02546     }
02547     else
02548         ret = CertSetCertificateContextProperty(pCertContext,
02549          CERT_ENHKEY_USAGE_PROP_ID, 0, NULL);
02550     return ret;
02551 }
02552 
02553 BOOL WINAPI CertAddEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
02554  LPCSTR pszUsageIdentifier)
02555 {
02556     BOOL ret;
02557     DWORD size;
02558 
02559     TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
02560 
02561     if (CertGetEnhancedKeyUsage(pCertContext,
02562      CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, NULL, &size))
02563     {
02564         PCERT_ENHKEY_USAGE usage = CryptMemAlloc(size);
02565 
02566         if (usage)
02567         {
02568             ret = CertGetEnhancedKeyUsage(pCertContext,
02569              CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, usage, &size);
02570             if (ret)
02571             {
02572                 DWORD i;
02573                 BOOL exists = FALSE;
02574 
02575                 /* Make sure usage doesn't already exist */
02576                 for (i = 0; !exists && i < usage->cUsageIdentifier; i++)
02577                 {
02578                     if (!strcmp(usage->rgpszUsageIdentifier[i],
02579                      pszUsageIdentifier))
02580                         exists = TRUE;
02581                 }
02582                 if (!exists)
02583                 {
02584                     PCERT_ENHKEY_USAGE newUsage = CryptMemAlloc(size +
02585                      sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
02586 
02587                     if (newUsage)
02588                     {
02589                         LPSTR nextOID;
02590 
02591                         newUsage->rgpszUsageIdentifier = (LPSTR *)
02592                          ((LPBYTE)newUsage + sizeof(CERT_ENHKEY_USAGE));
02593                         nextOID = (LPSTR)((LPBYTE)newUsage->rgpszUsageIdentifier
02594                           + (usage->cUsageIdentifier + 1) * sizeof(LPSTR));
02595                         for (i = 0; i < usage->cUsageIdentifier; i++)
02596                         {
02597                             newUsage->rgpszUsageIdentifier[i] = nextOID;
02598                             strcpy(nextOID, usage->rgpszUsageIdentifier[i]);
02599                             nextOID += strlen(nextOID) + 1;
02600                         }
02601                         newUsage->rgpszUsageIdentifier[i] = nextOID;
02602                         strcpy(nextOID, pszUsageIdentifier);
02603                         newUsage->cUsageIdentifier = i + 1;
02604                         ret = CertSetEnhancedKeyUsage(pCertContext, newUsage);
02605                         CryptMemFree(newUsage);
02606                     }
02607                     else
02608                         ret = FALSE;
02609                 }
02610             }
02611             CryptMemFree(usage);
02612         }
02613         else
02614             ret = FALSE;
02615     }
02616     else
02617     {
02618         PCERT_ENHKEY_USAGE usage = CryptMemAlloc(sizeof(CERT_ENHKEY_USAGE) +
02619          sizeof(LPSTR) + strlen(pszUsageIdentifier) + 1);
02620 
02621         if (usage)
02622         {
02623             usage->rgpszUsageIdentifier =
02624              (LPSTR *)((LPBYTE)usage + sizeof(CERT_ENHKEY_USAGE));
02625             usage->rgpszUsageIdentifier[0] = (LPSTR)((LPBYTE)usage +
02626              sizeof(CERT_ENHKEY_USAGE) + sizeof(LPSTR));
02627             strcpy(usage->rgpszUsageIdentifier[0], pszUsageIdentifier);
02628             usage->cUsageIdentifier = 1;
02629             ret = CertSetEnhancedKeyUsage(pCertContext, usage);
02630             CryptMemFree(usage);
02631         }
02632         else
02633             ret = FALSE;
02634     }
02635     return ret;
02636 }
02637 
02638 BOOL WINAPI CertRemoveEnhancedKeyUsageIdentifier(PCCERT_CONTEXT pCertContext,
02639  LPCSTR pszUsageIdentifier)
02640 {
02641     BOOL ret;
02642     DWORD size;
02643     CERT_ENHKEY_USAGE usage;
02644 
02645     TRACE("(%p, %s)\n", pCertContext, debugstr_a(pszUsageIdentifier));
02646 
02647     size = sizeof(usage);
02648     ret = CertGetEnhancedKeyUsage(pCertContext,
02649      CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, &usage, &size);
02650     if (!ret && GetLastError() == ERROR_MORE_DATA)
02651     {
02652         PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size);
02653 
02654         if (pUsage)
02655         {
02656             ret = CertGetEnhancedKeyUsage(pCertContext,
02657              CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG, pUsage, &size);
02658             if (ret)
02659             {
02660                 if (pUsage->cUsageIdentifier)
02661                 {
02662                     DWORD i;
02663                     BOOL found = FALSE;
02664 
02665                     for (i = 0; i < pUsage->cUsageIdentifier; i++)
02666                     {
02667                         if (!strcmp(pUsage->rgpszUsageIdentifier[i],
02668                          pszUsageIdentifier))
02669                             found = TRUE;
02670                         if (found && i < pUsage->cUsageIdentifier - 1)
02671                             pUsage->rgpszUsageIdentifier[i] =
02672                              pUsage->rgpszUsageIdentifier[i + 1];
02673                     }
02674                     pUsage->cUsageIdentifier--;
02675                     /* Remove the usage if it's empty */
02676                     if (pUsage->cUsageIdentifier)
02677                         ret = CertSetEnhancedKeyUsage(pCertContext, pUsage);
02678                     else
02679                         ret = CertSetEnhancedKeyUsage(pCertContext, NULL);
02680                 }
02681             }
02682             CryptMemFree(pUsage);
02683         }
02684         else
02685             ret = FALSE;
02686     }
02687     else
02688     {
02689         /* it fit in an empty usage, therefore there's nothing to remove */
02690         ret = TRUE;
02691     }
02692     return ret;
02693 }
02694 
02695 struct BitField
02696 {
02697     DWORD  cIndexes;
02698     DWORD *indexes;
02699 };
02700 
02701 #define BITS_PER_DWORD (sizeof(DWORD) * 8)
02702 
02703 static void CRYPT_SetBitInField(struct BitField *field, DWORD bit)
02704 {
02705     DWORD indexIndex = bit / BITS_PER_DWORD;
02706 
02707     if (indexIndex + 1 > field->cIndexes)
02708     {
02709         if (field->cIndexes)
02710             field->indexes = CryptMemRealloc(field->indexes,
02711              (indexIndex + 1) * sizeof(DWORD));
02712         else
02713             field->indexes = CryptMemAlloc(sizeof(DWORD));
02714         if (field->indexes)
02715         {
02716             field->indexes[indexIndex] = 0;
02717             field->cIndexes = indexIndex + 1;
02718         }
02719     }
02720     if (field->indexes)
02721         field->indexes[indexIndex] |= 1 << (bit % BITS_PER_DWORD);
02722 }
02723 
02724 static BOOL CRYPT_IsBitInFieldSet(const struct BitField *field, DWORD bit)
02725 {
02726     BOOL set = FALSE;
02727     DWORD indexIndex = bit / BITS_PER_DWORD;
02728 
02729     assert(field->cIndexes);
02730     set = field->indexes[indexIndex] & (1 << (bit % BITS_PER_DWORD));
02731     return set;
02732 }
02733 
02734 BOOL WINAPI CertGetValidUsages(DWORD cCerts, PCCERT_CONTEXT *rghCerts,
02735  int *cNumOIDs, LPSTR *rghOIDs, DWORD *pcbOIDs)
02736 {
02737     BOOL ret = TRUE;
02738     DWORD i, cbOIDs = 0;
02739     BOOL allUsagesValid = TRUE;
02740     CERT_ENHKEY_USAGE validUsages = { 0, NULL };
02741 
02742     TRACE("(%d, %p, %d, %p, %d)\n", cCerts, rghCerts, *cNumOIDs,
02743      rghOIDs, *pcbOIDs);
02744 
02745     for (i = 0; i < cCerts; i++)
02746     {
02747         CERT_ENHKEY_USAGE usage;
02748         DWORD size = sizeof(usage);
02749 
02750         ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, &usage, &size);
02751         /* Success is deliberately ignored: it implies all usages are valid */
02752         if (!ret && GetLastError() == ERROR_MORE_DATA)
02753         {
02754             PCERT_ENHKEY_USAGE pUsage = CryptMemAlloc(size);
02755 
02756             allUsagesValid = FALSE;
02757             if (pUsage)
02758             {
02759                 ret = CertGetEnhancedKeyUsage(rghCerts[i], 0, pUsage, &size);
02760                 if (ret)
02761                 {
02762                     if (!validUsages.cUsageIdentifier)
02763                     {
02764                         DWORD j;
02765 
02766                         cbOIDs = pUsage->cUsageIdentifier * sizeof(LPSTR);
02767                         validUsages.cUsageIdentifier = pUsage->cUsageIdentifier;
02768                         for (j = 0; j < validUsages.cUsageIdentifier; j++)
02769                             cbOIDs += lstrlenA(pUsage->rgpszUsageIdentifier[j])
02770                              + 1;
02771                         validUsages.rgpszUsageIdentifier =
02772                          CryptMemAlloc(cbOIDs);
02773                         if (validUsages.rgpszUsageIdentifier)
02774                         {
02775                             LPSTR nextOID = (LPSTR)
02776                              ((LPBYTE)validUsages.rgpszUsageIdentifier +
02777                              validUsages.cUsageIdentifier * sizeof(LPSTR));
02778 
02779                             for (j = 0; j < validUsages.cUsageIdentifier; j++)
02780                             {
02781                                 validUsages.rgpszUsageIdentifier[j] = nextOID;
02782                                 lstrcpyA(validUsages.rgpszUsageIdentifier[j],
02783                                  pUsage->rgpszUsageIdentifier[j]);
02784                                 nextOID += lstrlenA(nextOID) + 1;
02785                             }
02786                         }
02787                     }
02788                     else
02789                     {
02790                         struct BitField validIndexes = { 0, NULL };
02791                         DWORD j, k, numRemoved = 0;
02792 
02793                         /* Merge: build a bitmap of all the indexes of
02794                          * validUsages.rgpszUsageIdentifier that are in pUsage.
02795                          */
02796                         for (j = 0; j < pUsage->cUsageIdentifier; j++)
02797                         {
02798                             for (k = 0; k < validUsages.cUsageIdentifier; k++)
02799                             {
02800                                 if (!strcmp(pUsage->rgpszUsageIdentifier[j],
02801                                  validUsages.rgpszUsageIdentifier[k]))
02802                                 {
02803                                     CRYPT_SetBitInField(&validIndexes, k);
02804                                     break;
02805                                 }
02806                             }
02807                         }
02808                         /* Merge by removing from validUsages those that are
02809                          * not in the bitmap.
02810                          */
02811                         for (j = 0; j < validUsages.cUsageIdentifier; j++)
02812                         {
02813                             if (!CRYPT_IsBitInFieldSet(&validIndexes, j))
02814                             {
02815                                 if (j < validUsages.cUsageIdentifier - 1)
02816                                 {
02817                                     memmove(&validUsages.rgpszUsageIdentifier[j],
02818                                      &validUsages.rgpszUsageIdentifier[j +
02819                                      numRemoved + 1],
02820                                      (validUsages.cUsageIdentifier - numRemoved
02821                                      - j - 1) * sizeof(LPSTR));
02822                                     cbOIDs -= lstrlenA(
02823                                      validUsages.rgpszUsageIdentifier[j]) + 1 +
02824                                      sizeof(LPSTR);
02825                                     validUsages.cUsageIdentifier--;
02826                                     numRemoved++;
02827                                 }
02828                                 else
02829                                     validUsages.cUsageIdentifier--;
02830                             }
02831                         }
02832                         CryptMemFree(validIndexes.indexes);
02833                     }
02834                 }
02835                 CryptMemFree(pUsage);
02836             }
02837         }
02838     }
02839     ret = TRUE;
02840     if (allUsagesValid)
02841     {
02842         *cNumOIDs = -1;
02843         *pcbOIDs = 0;
02844     }
02845     else
02846     {
02847         *cNumOIDs = validUsages.cUsageIdentifier;
02848         if (!rghOIDs)
02849             *pcbOIDs = cbOIDs;
02850         else if (*pcbOIDs < cbOIDs)
02851         {
02852             *pcbOIDs = cbOIDs;
02853             SetLastError(ERROR_MORE_DATA);
02854             ret = FALSE;
02855         }
02856         else
02857         {
02858             LPSTR nextOID = (LPSTR)((LPBYTE)rghOIDs +
02859              validUsages.cUsageIdentifier * sizeof(LPSTR));
02860 
02861             *pcbOIDs = cbOIDs;
02862             for (i = 0; i < validUsages.cUsageIdentifier; i++)
02863             {
02864                 rghOIDs[i] = nextOID;
02865                 lstrcpyA(nextOID, validUsages.rgpszUsageIdentifier[i]);
02866                 nextOID += lstrlenA(nextOID) + 1;
02867             }
02868         }
02869     }
02870     CryptMemFree(validUsages.rgpszUsageIdentifier);
02871     TRACE("cNumOIDs: %d\n", *cNumOIDs);
02872     TRACE("returning %d\n", ret);
02873     return ret;
02874 }
02875 
02876 /* Sets the CERT_KEY_PROV_INFO_PROP_ID property of context from pInfo, or, if
02877  * pInfo is NULL, from the attributes of hProv.
02878  */
02879 static void CertContext_SetKeyProvInfo(PCCERT_CONTEXT context,
02880  const CRYPT_KEY_PROV_INFO *pInfo, HCRYPTPROV hProv)
02881 {
02882     CRYPT_KEY_PROV_INFO info = { 0 };
02883     BOOL ret;
02884 
02885     if (!pInfo)
02886     {
02887         DWORD size;
02888         int len;
02889 
02890         ret = CryptGetProvParam(hProv, PP_CONTAINER, NULL, &size, 0);
02891         if (ret)
02892         {
02893             LPSTR szContainer = CryptMemAlloc(size);
02894 
02895             if (szContainer)
02896             {
02897                 ret = CryptGetProvParam(hProv, PP_CONTAINER,
02898                  (BYTE *)szContainer, &size, 0);
02899                 if (ret)
02900                 {
02901                     len = MultiByteToWideChar(CP_ACP, 0, szContainer, -1,
02902                      NULL, 0);
02903                     if (len)
02904                     {
02905                         info.pwszContainerName = CryptMemAlloc(len *
02906                          sizeof(WCHAR));
02907                         MultiByteToWideChar(CP_ACP, 0, szContainer, -1,
02908                          info.pwszContainerName, len);
02909                     }
02910                 }
02911                 CryptMemFree(szContainer);
02912             }
02913         }
02914         ret = CryptGetProvParam(hProv, PP_NAME, NULL, &size, 0);
02915         if (ret)
02916         {
02917             LPSTR szProvider = CryptMemAlloc(size);
02918 
02919             if (szProvider)
02920             {
02921                 ret = CryptGetProvParam(hProv, PP_NAME, (BYTE *)szProvider,
02922                  &size, 0);
02923                 if (ret)
02924                 {
02925                     len = MultiByteToWideChar(CP_ACP, 0, szProvider, -1,
02926                      NULL, 0);
02927                     if (len)
02928                     {
02929                         info.pwszProvName = CryptMemAlloc(len *
02930                          sizeof(WCHAR));
02931                         MultiByteToWideChar(CP_ACP, 0, szProvider, -1,
02932                          info.pwszProvName, len);
02933                     }
02934                 }
02935                 CryptMemFree(szProvider);
02936             }
02937         }
02938         size = sizeof(info.dwKeySpec);
02939         /* in case no CRYPT_KEY_PROV_INFO given,
02940          *  we always use AT_SIGNATURE key spec
02941          */
02942         info.dwKeySpec = AT_SIGNATURE;
02943         size = sizeof(info.dwProvType);
02944         ret = CryptGetProvParam(hProv, PP_PROVTYPE, (LPBYTE)&info.dwProvType,
02945          &size, 0);
02946         if (!ret)
02947             info.dwProvType = PROV_RSA_FULL;
02948         pInfo = &info;
02949     }
02950 
02951     CertSetCertificateContextProperty(context, CERT_KEY_PROV_INFO_PROP_ID,
02952      0, pInfo);
02953 
02954     if (pInfo == &info)
02955     {
02956         CryptMemFree(info.pwszContainerName);
02957         CryptMemFree(info.pwszProvName);
02958     }
02959 }
02960 
02961 /* Creates a signed certificate context from the unsigned, encoded certificate
02962  * in blob, using the crypto provider hProv and the signature algorithm sigAlgo.
02963  */
02964 static PCCERT_CONTEXT CRYPT_CreateSignedCert(const CRYPT_DER_BLOB *blob,
02965  HCRYPTPROV hProv, DWORD dwKeySpec, PCRYPT_ALGORITHM_IDENTIFIER sigAlgo)
02966 {
02967     PCCERT_CONTEXT context = NULL;
02968     BOOL ret;
02969     DWORD sigSize = 0;
02970 
02971     ret = CryptSignCertificate(hProv, dwKeySpec, X509_ASN_ENCODING,
02972      blob->pbData, blob->cbData, sigAlgo, NULL, NULL, &sigSize);
02973     if (ret)
02974     {
02975         LPBYTE sig = CryptMemAlloc(sigSize);
02976 
02977         ret = CryptSignCertificate(hProv, dwKeySpec, X509_ASN_ENCODING,
02978          blob->pbData, blob->cbData, sigAlgo, NULL, sig, &sigSize);
02979         if (ret)
02980         {
02981             CERT_SIGNED_CONTENT_INFO signedInfo;
02982             BYTE *encodedSignedCert = NULL;
02983             DWORD encodedSignedCertSize = 0;
02984 
02985             signedInfo.ToBeSigned.cbData = blob->cbData;
02986             signedInfo.ToBeSigned.pbData = blob->pbData;
02987             memcpy(&signedInfo.SignatureAlgorithm, sigAlgo,
02988              sizeof(signedInfo.SignatureAlgorithm));
02989             signedInfo.Signature.cbData = sigSize;
02990             signedInfo.Signature.pbData = sig;
02991             signedInfo.Signature.cUnusedBits = 0;
02992             ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT,
02993              &signedInfo, CRYPT_ENCODE_ALLOC_FLAG, NULL,
02994              &encodedSignedCert, &encodedSignedCertSize);
02995             if (ret)
02996             {
02997                 context = CertCreateCertificateContext(X509_ASN_ENCODING,
02998                  encodedSignedCert, encodedSignedCertSize);
02999                 LocalFree(encodedSignedCert);
03000             }
03001         }
03002         CryptMemFree(sig);
03003     }
03004     return context;
03005 }
03006 
03007 /* Copies data from the parameters into info, where:
03008  * pSerialNumber: The serial number.  Must not be NULL.
03009  * pSubjectIssuerBlob: Specifies both the subject and issuer for info.
03010  *                     Must not be NULL
03011  * pSignatureAlgorithm: Optional.
03012  * pStartTime: The starting time of the certificate.  If NULL, the current
03013  *             system time is used.
03014  * pEndTime: The ending time of the certificate.  If NULL, one year past the
03015  *           starting time is used.
03016  * pubKey: The public key of the certificate.  Must not be NULL.
03017  * pExtensions: Extensions to be included with the certificate.  Optional.
03018  */
03019 static void CRYPT_MakeCertInfo(PCERT_INFO info, const CRYPT_DATA_BLOB *pSerialNumber,
03020  const CERT_NAME_BLOB *pSubjectIssuerBlob,
03021  const CRYPT_ALGORITHM_IDENTIFIER *pSignatureAlgorithm, const SYSTEMTIME *pStartTime,
03022  const SYSTEMTIME *pEndTime, const CERT_PUBLIC_KEY_INFO *pubKey,
03023  const CERT_EXTENSIONS *pExtensions)
03024 {
03025     static CHAR oid[] = szOID_RSA_SHA1RSA;
03026 
03027     assert(info);
03028     assert(pSerialNumber);
03029     assert(pSubjectIssuerBlob);
03030     assert(pubKey);
03031 
03032     if (pExtensions && pExtensions->cExtension)
03033         info->dwVersion = CERT_V3;
03034     else
03035         info->dwVersion = CERT_V1;
03036     info->SerialNumber.cbData = pSerialNumber->cbData;
03037     info->SerialNumber.pbData = pSerialNumber->pbData;
03038     if (pSignatureAlgorithm)
03039         memcpy(&info->SignatureAlgorithm, pSignatureAlgorithm,
03040          sizeof(info->SignatureAlgorithm));
03041     else
03042     {
03043         info->SignatureAlgorithm.pszObjId = oid;
03044         info->SignatureAlgorithm.Parameters.cbData = 0;
03045         info->SignatureAlgorithm.Parameters.pbData = NULL;
03046     }
03047     info->Issuer.cbData = pSubjectIssuerBlob->cbData;
03048     info->Issuer.pbData = pSubjectIssuerBlob->pbData;
03049     if (pStartTime)
03050         SystemTimeToFileTime(pStartTime, &info->NotBefore);
03051     else
03052         GetSystemTimeAsFileTime(&info->NotBefore);
03053     if (pEndTime)
03054         SystemTimeToFileTime(pEndTime, &info->NotAfter);
03055     else
03056     {
03057         SYSTEMTIME endTime;
03058 
03059         if (FileTimeToSystemTime(&info->NotBefore, &endTime))
03060         {
03061             endTime.wYear++;
03062             SystemTimeToFileTime(&endTime, &info->NotAfter);
03063         }
03064     }
03065     info->Subject.cbData = pSubjectIssuerBlob->cbData;
03066     info->Subject.pbData = pSubjectIssuerBlob->pbData;
03067     memcpy(&info->SubjectPublicKeyInfo, pubKey,
03068      sizeof(info->SubjectPublicKeyInfo));
03069     if (pExtensions)
03070     {
03071         info->cExtension = pExtensions->cExtension;
03072         info->rgExtension = pExtensions->rgExtension;
03073     }
03074     else
03075     {
03076         info->cExtension = 0;
03077         info->rgExtension = NULL;
03078     }
03079 }
03080  
03081 typedef RPC_STATUS (RPC_ENTRY *UuidCreateFunc)(UUID *);
03082 typedef RPC_STATUS (RPC_ENTRY *UuidToStringFunc)(UUID *, unsigned char **);
03083 typedef RPC_STATUS (RPC_ENTRY *RpcStringFreeFunc)(unsigned char **);
03084 
03085 static HCRYPTPROV CRYPT_CreateKeyProv(void)
03086 {
03087     HCRYPTPROV hProv = 0;
03088     HMODULE rpcrt = LoadLibraryA("rpcrt4");
03089 
03090     if (rpcrt)
03091     {
03092         UuidCreateFunc uuidCreate = (UuidCreateFunc)GetProcAddress(rpcrt,
03093          "UuidCreate");
03094         UuidToStringFunc uuidToString = (UuidToStringFunc)GetProcAddress(rpcrt,
03095          "UuidToStringA");
03096         RpcStringFreeFunc rpcStringFree = (RpcStringFreeFunc)GetProcAddress(
03097          rpcrt, "RpcStringFreeA");
03098 
03099         if (uuidCreate && uuidToString && rpcStringFree)
03100         {
03101             UUID uuid;
03102             RPC_STATUS status = uuidCreate(&uuid);
03103 
03104             if (status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY)
03105             {
03106                 unsigned char *uuidStr;
03107 
03108                 status = uuidToString(&uuid, &uuidStr);
03109                 if (status == RPC_S_OK)
03110                 {
03111                     BOOL ret = CryptAcquireContextA(&hProv, (LPCSTR)uuidStr,
03112                      MS_DEF_PROV_A, PROV_RSA_FULL, CRYPT_NEWKEYSET);
03113 
03114                     if (ret)
03115                     {
03116                         HCRYPTKEY key;
03117 
03118                         ret = CryptGenKey(hProv, AT_SIGNATURE, 0, &key);
03119                         if (ret)
03120                             CryptDestroyKey(key);
03121                     }
03122                     rpcStringFree(&uuidStr);
03123                 }
03124             }
03125         }
03126         FreeLibrary(rpcrt);
03127     }
03128     return hProv;
03129 }
03130 
03131 PCCERT_CONTEXT WINAPI CertCreateSelfSignCertificate(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hProv,
03132  PCERT_NAME_BLOB pSubjectIssuerBlob, DWORD dwFlags,
03133  PCRYPT_KEY_PROV_INFO pKeyProvInfo,
03134  PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm, PSYSTEMTIME pStartTime,
03135  PSYSTEMTIME pEndTime, PCERT_EXTENSIONS pExtensions)
03136 {
03137     PCCERT_CONTEXT context = NULL;
03138     BOOL ret, releaseContext = FALSE;
03139     PCERT_PUBLIC_KEY_INFO pubKey = NULL;
03140     DWORD pubKeySize = 0,dwKeySpec = AT_SIGNATURE;
03141 
03142     TRACE("(%08lx, %p, %08x, %p, %p, %p, %p, %p)\n", hProv,
03143      pSubjectIssuerBlob, dwFlags, pKeyProvInfo, pSignatureAlgorithm, pStartTime,
03144      pExtensions, pExtensions);
03145 
03146     if(!pSubjectIssuerBlob)
03147     {
03148         SetLastError(ERROR_INVALID_PARAMETER);
03149         return NULL;
03150     }
03151 
03152     if (!hProv)
03153     {
03154         if (!pKeyProvInfo)
03155         {
03156             hProv = CRYPT_CreateKeyProv();
03157             releaseContext = TRUE;
03158         }
03159         else if (pKeyProvInfo->dwFlags & CERT_SET_KEY_PROV_HANDLE_PROP_ID)
03160         {
03161             SetLastError(NTE_BAD_FLAGS);
03162             return NULL;
03163         }
03164         else
03165         {
03166             HCRYPTKEY hKey = 0;
03167             /* acquire the context using the given information*/
03168             ret = CryptAcquireContextW(&hProv,pKeyProvInfo->pwszContainerName,
03169                     pKeyProvInfo->pwszProvName,pKeyProvInfo->dwProvType,
03170                     pKeyProvInfo->dwFlags);
03171             if (!ret)
03172             {
03173             if(GetLastError() != NTE_BAD_KEYSET)
03174                     return NULL;
03175                 /* create the key set */
03176                 ret = CryptAcquireContextW(&hProv,pKeyProvInfo->pwszContainerName,
03177                     pKeyProvInfo->pwszProvName,pKeyProvInfo->dwProvType,
03178                     pKeyProvInfo->dwFlags|CRYPT_NEWKEYSET);
03179                 if (!ret)
03180                     return NULL;
03181         }
03182             dwKeySpec = pKeyProvInfo->dwKeySpec;
03183             /* check if the key is here */
03184             ret = CryptGetUserKey(hProv,dwKeySpec,&hKey);
03185             if(!ret)
03186             {
03187                 if (NTE_NO_KEY == GetLastError())
03188                 { /* generate the key */
03189                     ret = CryptGenKey(hProv,dwKeySpec,0,&hKey);
03190                 }
03191                 if (!ret)
03192                 {
03193                     CryptReleaseContext(hProv,0);
03194                     SetLastError(NTE_BAD_KEYSET);
03195                     return NULL;
03196                 }
03197             }
03198             CryptDestroyKey(hKey);
03199             releaseContext = TRUE;
03200         }
03201     }
03202     else if (pKeyProvInfo)
03203     {
03204         SetLastError(ERROR_INVALID_PARAMETER);
03205         return NULL;
03206     }
03207 
03208     CryptExportPublicKeyInfo(hProv, dwKeySpec, X509_ASN_ENCODING, NULL,
03209      &pubKeySize);
03210     pubKey = CryptMemAlloc(pubKeySize);
03211     if (pubKey)
03212     {
03213         ret = CryptExportPublicKeyInfo(hProv, dwKeySpec, X509_ASN_ENCODING,
03214          pubKey, &pubKeySize);
03215         if (ret)
03216         {
03217             CERT_INFO info = { 0 };
03218             CRYPT_DER_BLOB blob = { 0, NULL };
03219             BYTE serial[16];
03220             CRYPT_DATA_BLOB serialBlob = { sizeof(serial), serial };
03221 
03222             CryptGenRandom(hProv, sizeof(serial), serial);
03223             CRYPT_MakeCertInfo(&info, &serialBlob, pSubjectIssuerBlob,
03224              pSignatureAlgorithm, pStartTime, pEndTime, pubKey, pExtensions);
03225             ret = CryptEncodeObjectEx(X509_ASN_ENCODING, X509_CERT_TO_BE_SIGNED,
03226              &info, CRYPT_ENCODE_ALLOC_FLAG, NULL, &blob.pbData,
03227              &blob.cbData);
03228             if (ret)
03229             {
03230                 if (!(dwFlags & CERT_CREATE_SELFSIGN_NO_SIGN))
03231                     context = CRYPT_CreateSignedCert(&blob, hProv,dwKeySpec,
03232                      &info.SignatureAlgorithm);
03233                 else
03234                     context = CertCreateCertificateContext(X509_ASN_ENCODING,
03235                      blob.pbData, blob.cbData);
03236                 if (context && !(dwFlags & CERT_CREATE_SELFSIGN_NO_KEY_INFO))
03237                     CertContext_SetKeyProvInfo(context, pKeyProvInfo, hProv);
03238                 LocalFree(blob.pbData);
03239             }
03240         }
03241         CryptMemFree(pubKey);
03242     }
03243     if (releaseContext)
03244         CryptReleaseContext(hProv, 0);
03245     return context;
03246 }
03247 
03248 BOOL WINAPI CertVerifyCTLUsage(DWORD dwEncodingType, DWORD dwSubjectType,
03249                                void *pvSubject, PCTL_USAGE pSubjectUsage, DWORD dwFlags,
03250                                PCTL_VERIFY_USAGE_PARA pVerifyUsagePara,
03251                                PCTL_VERIFY_USAGE_STATUS pVerifyUsageStatus)
03252 {
03253     FIXME("(0x%x, %d, %p, %p, 0x%x, %p, %p): stub\n", dwEncodingType,
03254           dwSubjectType, pvSubject, pSubjectUsage, dwFlags, pVerifyUsagePara,
03255           pVerifyUsageStatus);
03256     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
03257     return FALSE;
03258 }
03259 
03260 const void * WINAPI CertCreateContext(DWORD dwContextType, DWORD dwEncodingType,
03261                                       const BYTE *pbEncoded, DWORD cbEncoded,
03262                                       DWORD dwFlags, PCERT_CREATE_CONTEXT_PARA pCreatePara)
03263 {
03264     TRACE("(0x%x, 0x%x, %p, %d, 0x%08x, %p)\n", dwContextType, dwEncodingType,
03265           pbEncoded, cbEncoded, dwFlags, pCreatePara);
03266 
03267     if (dwFlags)
03268     {
03269         FIXME("dwFlags 0x%08x not handled\n", dwFlags);
03270         return NULL;
03271     }
03272     if (pCreatePara)
03273     {
03274         FIXME("pCreatePara not handled\n");
03275         return NULL;
03276     }
03277 
03278     switch (dwContextType)
03279     {
03280     case CERT_STORE_CERTIFICATE_CONTEXT:
03281         return CertCreateCertificateContext(dwEncodingType, pbEncoded, cbEncoded);
03282     case CERT_STORE_CRL_CONTEXT:
03283         return CertCreateCRLContext(dwEncodingType, pbEncoded, cbEncoded);
03284     case CERT_STORE_CTL_CONTEXT:
03285         return CertCreateCTLContext(dwEncodingType, pbEncoded, cbEncoded);
03286     default:
03287         WARN("unknown context type: 0x%x\n", dwContextType);
03288         return NULL;
03289     }
03290 }

Generated on Sun May 27 2012 04:23:11 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.