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

object.c
Go to the documentation of this file.
00001 /*
00002  * crypt32 Crypt*Object functions
00003  *
00004  * Copyright 2007 Juan Lang
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00019  */
00020 #include <stdarg.h>
00021 #define NONAMELESSUNION
00022 #include "windef.h"
00023 #include "winbase.h"
00024 #include "wincrypt.h"
00025 #include "mssip.h"
00026 #include "winuser.h"
00027 #include "wintrust.h"
00028 #include "crypt32_private.h"
00029 #include "cryptres.h"
00030 #include "wine/unicode.h"
00031 #include "wine/debug.h"
00032 
00033 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
00034 
00035 static BOOL CRYPT_ReadBlobFromFile(LPCWSTR fileName, PCERT_BLOB blob)
00036 {
00037     BOOL ret = FALSE;
00038     HANDLE file;
00039 
00040     TRACE("%s\n", debugstr_w(fileName));
00041 
00042     file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
00043      OPEN_EXISTING, 0, NULL);
00044     if (file != INVALID_HANDLE_VALUE)
00045     {
00046         ret = TRUE;
00047         blob->cbData = GetFileSize(file, NULL);
00048         if (blob->cbData)
00049         {
00050             blob->pbData = CryptMemAlloc(blob->cbData);
00051             if (blob->pbData)
00052             {
00053                 DWORD read;
00054 
00055                 ret = ReadFile(file, blob->pbData, blob->cbData, &read, NULL);
00056             }
00057         }
00058         CloseHandle(file);
00059     }
00060     TRACE("returning %d\n", ret);
00061     return ret;
00062 }
00063 
00064 static BOOL CRYPT_QueryContextBlob(const CERT_BLOB *blob,
00065  DWORD dwExpectedContentTypeFlags, HCERTSTORE store,
00066  DWORD *contentType, const void **ppvContext)
00067 {
00068     BOOL ret = FALSE;
00069 
00070     if (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CERT)
00071     {
00072         ret = pCertInterface->addEncodedToStore(store, X509_ASN_ENCODING,
00073          blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext);
00074         if (ret && contentType)
00075             *contentType = CERT_QUERY_CONTENT_CERT;
00076     }
00077     if (!ret && (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CRL))
00078     {
00079         ret = pCRLInterface->addEncodedToStore(store, X509_ASN_ENCODING,
00080          blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext);
00081         if (ret && contentType)
00082             *contentType = CERT_QUERY_CONTENT_CRL;
00083     }
00084     if (!ret && (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CTL))
00085     {
00086         ret = pCTLInterface->addEncodedToStore(store, X509_ASN_ENCODING,
00087          blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext);
00088         if (ret && contentType)
00089             *contentType = CERT_QUERY_CONTENT_CTL;
00090     }
00091     return ret;
00092 }
00093 
00094 static BOOL CRYPT_QueryContextObject(DWORD dwObjectType, const void *pvObject,
00095  DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags,
00096  DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, DWORD *pdwFormatType,
00097  HCERTSTORE *phCertStore, const void **ppvContext)
00098 {
00099     CERT_BLOB fileBlob;
00100     const CERT_BLOB *blob;
00101     HCERTSTORE store;
00102     BOOL ret;
00103     DWORD formatType = 0;
00104 
00105     switch (dwObjectType)
00106     {
00107     case CERT_QUERY_OBJECT_FILE:
00108         /* Cert, CRL, and CTL contexts can't be "embedded" in a file, so
00109          * just read the file directly
00110          */
00111         ret = CRYPT_ReadBlobFromFile(pvObject, &fileBlob);
00112         blob = &fileBlob;
00113         break;
00114     case CERT_QUERY_OBJECT_BLOB:
00115         blob = pvObject;
00116         ret = TRUE;
00117         break;
00118     default:
00119         SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
00120         ret = FALSE;
00121     }
00122     if (!ret)
00123         return FALSE;
00124 
00125     ret = FALSE;
00126     store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
00127      CERT_STORE_CREATE_NEW_FLAG, NULL);
00128     if (dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BINARY)
00129     {
00130         ret = CRYPT_QueryContextBlob(blob, dwExpectedContentTypeFlags, store,
00131          pdwContentType, ppvContext);
00132         if (ret)
00133             formatType = CERT_QUERY_FORMAT_BINARY;
00134     }
00135     if (!ret &&
00136      (dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED))
00137     {
00138         CRYPT_DATA_BLOB trimmed = { blob->cbData, blob->pbData };
00139         CRYPT_DATA_BLOB decoded;
00140 
00141         while (trimmed.cbData && !trimmed.pbData[trimmed.cbData - 1])
00142             trimmed.cbData--;
00143         ret = CryptStringToBinaryA((LPSTR)trimmed.pbData, trimmed.cbData,
00144          CRYPT_STRING_BASE64_ANY, NULL, &decoded.cbData, NULL, NULL);
00145         if (ret)
00146         {
00147             decoded.pbData = CryptMemAlloc(decoded.cbData);
00148             if (decoded.pbData)
00149             {
00150                 ret = CryptStringToBinaryA((LPSTR)trimmed.pbData,
00151                  trimmed.cbData, CRYPT_STRING_BASE64_ANY, decoded.pbData,
00152                  &decoded.cbData, NULL, NULL);
00153                 if (ret)
00154                 {
00155                     ret = CRYPT_QueryContextBlob(&decoded,
00156                      dwExpectedContentTypeFlags, store, pdwContentType,
00157                      ppvContext);
00158                     if (ret)
00159                         formatType = CERT_QUERY_FORMAT_BASE64_ENCODED;
00160                 }
00161                 CryptMemFree(decoded.pbData);
00162             }
00163             else
00164                 ret = FALSE;
00165         }
00166     }
00167     if (ret)
00168     {
00169         if (pdwMsgAndCertEncodingType)
00170             *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
00171         if (pdwFormatType)
00172             *pdwFormatType = formatType;
00173         if (phCertStore)
00174             *phCertStore = CertDuplicateStore(store);
00175     }
00176     CertCloseStore(store, 0);
00177     if (blob == &fileBlob)
00178         CryptMemFree(blob->pbData);
00179     TRACE("returning %d\n", ret);
00180     return ret;
00181 }
00182 
00183 static BOOL CRYPT_QuerySerializedContextObject(DWORD dwObjectType,
00184  const void *pvObject, DWORD dwExpectedContentTypeFlags,
00185  DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
00186  HCERTSTORE *phCertStore, const void **ppvContext)
00187 {
00188     CERT_BLOB fileBlob;
00189     const CERT_BLOB *blob;
00190     const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
00191     const void *context;
00192     DWORD contextType;
00193     BOOL ret;
00194 
00195     switch (dwObjectType)
00196     {
00197     case CERT_QUERY_OBJECT_FILE:
00198         /* Cert, CRL, and CTL contexts can't be "embedded" in a file, so
00199          * just read the file directly
00200          */
00201         ret = CRYPT_ReadBlobFromFile(pvObject, &fileBlob);
00202         blob = &fileBlob;
00203         break;
00204     case CERT_QUERY_OBJECT_BLOB:
00205         blob = pvObject;
00206         ret = TRUE;
00207         break;
00208     default:
00209         SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
00210         ret = FALSE;
00211     }
00212     if (!ret)
00213         return FALSE;
00214 
00215     ret = FALSE;
00216     context = CRYPT_ReadSerializedElement(blob->pbData, blob->cbData,
00217      CERT_STORE_ALL_CONTEXT_FLAG, &contextType);
00218     if (context)
00219     {
00220         DWORD contentType, certStoreOffset;
00221 
00222         ret = TRUE;
00223         switch (contextType)
00224         {
00225         case CERT_STORE_CERTIFICATE_CONTEXT:
00226             contextInterface = pCertInterface;
00227             contentType = CERT_QUERY_CONTENT_SERIALIZED_CERT;
00228             certStoreOffset = offsetof(CERT_CONTEXT, hCertStore);
00229             if (!(dwExpectedContentTypeFlags &
00230              CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT))
00231             {
00232                 SetLastError(ERROR_INVALID_DATA);
00233                 ret = FALSE;
00234                 goto end;
00235             }
00236             break;
00237         case CERT_STORE_CRL_CONTEXT:
00238             contextInterface = pCRLInterface;
00239             contentType = CERT_QUERY_CONTENT_SERIALIZED_CRL;
00240             certStoreOffset = offsetof(CRL_CONTEXT, hCertStore);
00241             if (!(dwExpectedContentTypeFlags &
00242              CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL))
00243             {
00244                 SetLastError(ERROR_INVALID_DATA);
00245                 ret = FALSE;
00246                 goto end;
00247             }
00248             break;
00249         case CERT_STORE_CTL_CONTEXT:
00250             contextInterface = pCTLInterface;
00251             contentType = CERT_QUERY_CONTENT_SERIALIZED_CTL;
00252             certStoreOffset = offsetof(CTL_CONTEXT, hCertStore);
00253             if (!(dwExpectedContentTypeFlags &
00254              CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL))
00255             {
00256                 SetLastError(ERROR_INVALID_DATA);
00257                 ret = FALSE;
00258                 goto end;
00259             }
00260             break;
00261         default:
00262             SetLastError(ERROR_INVALID_DATA);
00263             ret = FALSE;
00264             goto end;
00265         }
00266         if (pdwMsgAndCertEncodingType)
00267             *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
00268         if (pdwContentType)
00269             *pdwContentType = contentType;
00270         if (phCertStore)
00271             *phCertStore = CertDuplicateStore(
00272              *(HCERTSTORE *)((const BYTE *)context + certStoreOffset));
00273         if (ppvContext)
00274             *ppvContext = contextInterface->duplicate(context);
00275     }
00276 
00277 end:
00278     if (contextInterface && context)
00279         contextInterface->free(context);
00280     if (blob == &fileBlob)
00281         CryptMemFree(blob->pbData);
00282     TRACE("returning %d\n", ret);
00283     return ret;
00284 }
00285 
00286 static BOOL CRYPT_QuerySerializedStoreFromFile(LPCWSTR fileName,
00287  DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
00288  HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
00289 {
00290     HANDLE file;
00291     BOOL ret = FALSE;
00292 
00293     TRACE("%s\n", debugstr_w(fileName));
00294     file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
00295      OPEN_EXISTING, 0, NULL);
00296     if (file != INVALID_HANDLE_VALUE)
00297     {
00298         HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
00299          CERT_STORE_CREATE_NEW_FLAG, NULL);
00300 
00301         ret = CRYPT_ReadSerializedStoreFromFile(file, store);
00302         if (ret)
00303         {
00304             if (pdwMsgAndCertEncodingType)
00305                 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
00306             if (pdwContentType)
00307                 *pdwContentType = CERT_QUERY_CONTENT_SERIALIZED_STORE;
00308             if (phCertStore)
00309                 *phCertStore = CertDuplicateStore(store);
00310         }
00311         CertCloseStore(store, 0);
00312         CloseHandle(file);
00313     }
00314     TRACE("returning %d\n", ret);
00315     return ret;
00316 }
00317 
00318 static BOOL CRYPT_QuerySerializedStoreFromBlob(const CRYPT_DATA_BLOB *blob,
00319  DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
00320  HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
00321 {
00322     HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
00323      CERT_STORE_CREATE_NEW_FLAG, NULL);
00324     BOOL ret;
00325 
00326     TRACE("(%d, %p)\n", blob->cbData, blob->pbData);
00327 
00328     ret = CRYPT_ReadSerializedStoreFromBlob(blob, store);
00329     if (ret)
00330     {
00331         if (pdwMsgAndCertEncodingType)
00332             *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
00333         if (pdwContentType)
00334             *pdwContentType = CERT_QUERY_CONTENT_SERIALIZED_STORE;
00335         if (phCertStore)
00336             *phCertStore = CertDuplicateStore(store);
00337     }
00338     CertCloseStore(store, 0);
00339     TRACE("returning %d\n", ret);
00340     return ret;
00341 }
00342 
00343 static BOOL CRYPT_QuerySerializedStoreObject(DWORD dwObjectType,
00344  const void *pvObject, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
00345  HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
00346 {
00347     switch (dwObjectType)
00348     {
00349     case CERT_QUERY_OBJECT_FILE:
00350         return CRYPT_QuerySerializedStoreFromFile(pvObject,
00351          pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
00352     case CERT_QUERY_OBJECT_BLOB:
00353         return CRYPT_QuerySerializedStoreFromBlob(pvObject,
00354          pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
00355     default:
00356         FIXME("unimplemented for type %d\n", dwObjectType);
00357         SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
00358         return FALSE;
00359     }
00360 }
00361 
00362 static BOOL CRYPT_QuerySignedMessage(const CRYPT_DATA_BLOB *blob,
00363  DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, HCRYPTMSG *phMsg)
00364 {
00365     DWORD encodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
00366     BOOL ret = FALSE;
00367     HCRYPTMSG msg;
00368 
00369     if ((msg = CryptMsgOpenToDecode(encodingType, 0, 0, 0, NULL, NULL)))
00370     {
00371         ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
00372         if (ret)
00373         {
00374             DWORD type, len = sizeof(type);
00375 
00376             ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &type, &len);
00377             if (ret)
00378             {
00379                 if (type != CMSG_SIGNED)
00380                 {
00381                     SetLastError(ERROR_INVALID_DATA);
00382                     ret = FALSE;
00383                 }
00384             }
00385         }
00386         if (!ret)
00387         {
00388             CryptMsgClose(msg);
00389             msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_SIGNED, 0, NULL,
00390              NULL);
00391             if (msg)
00392             {
00393                 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
00394                 if (!ret)
00395                 {
00396                     CryptMsgClose(msg);
00397                     msg = NULL;
00398                 }
00399             }
00400         }
00401     }
00402     if (ret)
00403     {
00404         if (pdwMsgAndCertEncodingType)
00405             *pdwMsgAndCertEncodingType = encodingType;
00406         if (pdwContentType)
00407             *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED;
00408         if (phMsg)
00409             *phMsg = msg;
00410     }
00411     return ret;
00412 }
00413 
00414 static BOOL CRYPT_QueryUnsignedMessage(const CRYPT_DATA_BLOB *blob,
00415  DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, HCRYPTMSG *phMsg)
00416 {
00417     DWORD encodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
00418     BOOL ret = FALSE;
00419     HCRYPTMSG msg;
00420 
00421     if ((msg = CryptMsgOpenToDecode(encodingType, 0, 0, 0, NULL, NULL)))
00422     {
00423         ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
00424         if (ret)
00425         {
00426             DWORD type, len = sizeof(type);
00427 
00428             ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &type, &len);
00429             if (ret)
00430             {
00431                 if (type != CMSG_DATA)
00432                 {
00433                     SetLastError(ERROR_INVALID_DATA);
00434                     ret = FALSE;
00435                 }
00436             }
00437         }
00438         if (!ret)
00439         {
00440             CryptMsgClose(msg);
00441             msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_DATA, 0,
00442              NULL, NULL);
00443             if (msg)
00444             {
00445                 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
00446                 if (!ret)
00447                 {
00448                     CryptMsgClose(msg);
00449                     msg = NULL;
00450                 }
00451             }
00452         }
00453     }
00454     if (ret)
00455     {
00456         if (pdwMsgAndCertEncodingType)
00457             *pdwMsgAndCertEncodingType = encodingType;
00458         if (pdwContentType)
00459             *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED;
00460         if (phMsg)
00461             *phMsg = msg;
00462     }
00463     return ret;
00464 }
00465 
00466 /* Used to decode non-embedded messages */
00467 static BOOL CRYPT_QueryMessageObject(DWORD dwObjectType, const void *pvObject,
00468  DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags,
00469  DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, DWORD *pdwFormatType,
00470  HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
00471 {
00472     CERT_BLOB fileBlob;
00473     const CERT_BLOB *blob;
00474     BOOL ret;
00475     HCRYPTMSG msg = NULL;
00476     DWORD encodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
00477     DWORD formatType = 0;
00478 
00479     TRACE("(%d, %p, %08x, %08x, %p, %p, %p, %p, %p)\n", dwObjectType, pvObject,
00480      dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags,
00481      pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType, phCertStore,
00482      phMsg);
00483 
00484     switch (dwObjectType)
00485     {
00486     case CERT_QUERY_OBJECT_FILE:
00487         /* This isn't an embedded PKCS7 message, so just read the file
00488          * directly
00489          */
00490         ret = CRYPT_ReadBlobFromFile(pvObject, &fileBlob);
00491         blob = &fileBlob;
00492         break;
00493     case CERT_QUERY_OBJECT_BLOB:
00494         blob = pvObject;
00495         ret = TRUE;
00496         break;
00497     default:
00498         SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
00499         ret = FALSE;
00500     }
00501     if (!ret)
00502         return FALSE;
00503 
00504     ret = FALSE;
00505     if (dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BINARY)
00506     {
00507         /* Try it first as a signed message */
00508         if (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED)
00509             ret = CRYPT_QuerySignedMessage(blob, pdwMsgAndCertEncodingType,
00510              pdwContentType, &msg);
00511         /* Failing that, try as an unsigned message */
00512         if (!ret &&
00513          (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
00514             ret = CRYPT_QueryUnsignedMessage(blob, pdwMsgAndCertEncodingType,
00515              pdwContentType, &msg);
00516         if (ret)
00517             formatType = CERT_QUERY_FORMAT_BINARY;
00518     }
00519     if (!ret &&
00520      (dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED))
00521     {
00522         CRYPT_DATA_BLOB trimmed = { blob->cbData, blob->pbData };
00523         CRYPT_DATA_BLOB decoded;
00524 
00525         while (trimmed.cbData && !trimmed.pbData[trimmed.cbData - 1])
00526             trimmed.cbData--;
00527         ret = CryptStringToBinaryA((LPSTR)trimmed.pbData, trimmed.cbData,
00528          CRYPT_STRING_BASE64_ANY, NULL, &decoded.cbData, NULL, NULL);
00529         if (ret)
00530         {
00531             decoded.pbData = CryptMemAlloc(decoded.cbData);
00532             if (decoded.pbData)
00533             {
00534                 ret = CryptStringToBinaryA((LPSTR)trimmed.pbData,
00535                  trimmed.cbData, CRYPT_STRING_BASE64_ANY, decoded.pbData,
00536                  &decoded.cbData, NULL, NULL);
00537                 if (ret)
00538                 {
00539                     /* Try it first as a signed message */
00540                     if (dwExpectedContentTypeFlags &
00541                      CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED)
00542                         ret = CRYPT_QuerySignedMessage(&decoded,
00543                          pdwMsgAndCertEncodingType, pdwContentType, &msg);
00544                     /* Failing that, try as an unsigned message */
00545                     if (!ret && (dwExpectedContentTypeFlags &
00546                      CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
00547                         ret = CRYPT_QueryUnsignedMessage(&decoded,
00548                          pdwMsgAndCertEncodingType, pdwContentType, &msg);
00549                     if (ret)
00550                         formatType = CERT_QUERY_FORMAT_BASE64_ENCODED;
00551                 }
00552                 CryptMemFree(decoded.pbData);
00553             }
00554             else
00555                 ret = FALSE;
00556         }
00557         if (!ret && !(blob->cbData % sizeof(WCHAR)))
00558         {
00559             CRYPT_DATA_BLOB decoded;
00560             LPWSTR str = (LPWSTR)blob->pbData;
00561             DWORD strLen = blob->cbData / sizeof(WCHAR);
00562 
00563             /* Try again, assuming the input string is UTF-16 base64 */
00564             while (strLen && !str[strLen - 1])
00565                 strLen--;
00566             ret = CryptStringToBinaryW(str, strLen, CRYPT_STRING_BASE64_ANY,
00567              NULL, &decoded.cbData, NULL, NULL);
00568             if (ret)
00569             {
00570                 decoded.pbData = CryptMemAlloc(decoded.cbData);
00571                 if (decoded.pbData)
00572                 {
00573                     ret = CryptStringToBinaryW(str, strLen,
00574                      CRYPT_STRING_BASE64_ANY, decoded.pbData, &decoded.cbData,
00575                      NULL, NULL);
00576                     if (ret)
00577                     {
00578                         /* Try it first as a signed message */
00579                         if (dwExpectedContentTypeFlags &
00580                          CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED)
00581                             ret = CRYPT_QuerySignedMessage(&decoded,
00582                              pdwMsgAndCertEncodingType, pdwContentType, &msg);
00583                         /* Failing that, try as an unsigned message */
00584                         if (!ret && (dwExpectedContentTypeFlags &
00585                          CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
00586                             ret = CRYPT_QueryUnsignedMessage(&decoded,
00587                              pdwMsgAndCertEncodingType, pdwContentType, &msg);
00588                         if (ret)
00589                             formatType = CERT_QUERY_FORMAT_BASE64_ENCODED;
00590                     }
00591                     CryptMemFree(decoded.pbData);
00592                 }
00593                 else
00594                     ret = FALSE;
00595             }
00596         }
00597     }
00598     if (ret)
00599     {
00600         if (pdwFormatType)
00601             *pdwFormatType = formatType;
00602         if (phCertStore)
00603             *phCertStore = CertOpenStore(CERT_STORE_PROV_MSG, encodingType, 0,
00604              0, msg);
00605         if (phMsg)
00606             *phMsg = msg;
00607         else
00608             CryptMsgClose(msg);
00609     }
00610     if (blob == &fileBlob)
00611         CryptMemFree(blob->pbData);
00612     TRACE("returning %d\n", ret);
00613     return ret;
00614 }
00615 
00616 static BOOL CRYPT_QueryEmbeddedMessageObject(DWORD dwObjectType,
00617  const void *pvObject, DWORD dwExpectedContentTypeFlags,
00618  DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
00619  HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
00620 {
00621     HANDLE file;
00622     GUID subject;
00623     BOOL ret = FALSE;
00624 
00625     TRACE("%s\n", debugstr_w(pvObject));
00626 
00627     if (dwObjectType != CERT_QUERY_OBJECT_FILE)
00628     {
00629         WARN("don't know what to do for type %d embedded signed messages\n",
00630          dwObjectType);
00631         SetLastError(E_INVALIDARG);
00632         return FALSE;
00633     }
00634     file = CreateFileW(pvObject, GENERIC_READ, FILE_SHARE_READ,
00635      NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
00636     if (file != INVALID_HANDLE_VALUE)
00637     {
00638         ret = CryptSIPRetrieveSubjectGuid(pvObject, file, &subject);
00639         if (ret)
00640         {
00641             SIP_DISPATCH_INFO sip;
00642 
00643             memset(&sip, 0, sizeof(sip));
00644             sip.cbSize = sizeof(sip);
00645             ret = CryptSIPLoad(&subject, 0, &sip);
00646             if (ret)
00647             {
00648                 SIP_SUBJECTINFO subjectInfo;
00649                 CERT_BLOB blob;
00650                 DWORD encodingType;
00651 
00652                 memset(&subjectInfo, 0, sizeof(subjectInfo));
00653                 subjectInfo.cbSize = sizeof(subjectInfo);
00654                 subjectInfo.pgSubjectType = &subject;
00655                 subjectInfo.hFile = file;
00656                 subjectInfo.pwsFileName = pvObject;
00657                 ret = sip.pfGet(&subjectInfo, &encodingType, 0, &blob.cbData,
00658                  NULL);
00659                 if (ret)
00660                 {
00661                     blob.pbData = CryptMemAlloc(blob.cbData);
00662                     if (blob.pbData)
00663                     {
00664                         ret = sip.pfGet(&subjectInfo, &encodingType, 0,
00665                          &blob.cbData, blob.pbData);
00666                         if (ret)
00667                         {
00668                             ret = CRYPT_QueryMessageObject(
00669                              CERT_QUERY_OBJECT_BLOB, &blob,
00670                              CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED,
00671                              CERT_QUERY_FORMAT_FLAG_BINARY,
00672                              pdwMsgAndCertEncodingType, NULL, NULL,
00673                              phCertStore, phMsg);
00674                             if (ret && pdwContentType)
00675                                 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED;
00676                         }
00677                         CryptMemFree(blob.pbData);
00678                     }
00679                     else
00680                     {
00681                         SetLastError(ERROR_OUTOFMEMORY);
00682                         ret = FALSE;
00683                     }
00684                 }
00685             }
00686         }
00687         CloseHandle(file);
00688     }
00689     TRACE("returning %d\n", ret);
00690     return ret;
00691 }
00692 
00693 BOOL WINAPI CryptQueryObject(DWORD dwObjectType, const void *pvObject,
00694  DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags,
00695  DWORD dwFlags, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
00696  DWORD *pdwFormatType, HCERTSTORE *phCertStore, HCRYPTMSG *phMsg,
00697  const void **ppvContext)
00698 {
00699     static const DWORD unimplementedTypes =
00700      CERT_QUERY_CONTENT_FLAG_PKCS10 | CERT_QUERY_CONTENT_FLAG_PFX |
00701      CERT_QUERY_CONTENT_FLAG_CERT_PAIR;
00702     BOOL ret = TRUE;
00703 
00704     TRACE("(%08x, %p, %08x, %08x, %08x, %p, %p, %p, %p, %p, %p)\n",
00705      dwObjectType, pvObject, dwExpectedContentTypeFlags,
00706      dwExpectedFormatTypeFlags, dwFlags, pdwMsgAndCertEncodingType,
00707      pdwContentType, pdwFormatType, phCertStore, phMsg, ppvContext);
00708 
00709     if (dwObjectType != CERT_QUERY_OBJECT_BLOB &&
00710      dwObjectType != CERT_QUERY_OBJECT_FILE)
00711     {
00712         WARN("unsupported type %d\n", dwObjectType);
00713         SetLastError(E_INVALIDARG);
00714         return FALSE;
00715     }
00716     if (!pvObject)
00717     {
00718         WARN("missing required argument\n");
00719         SetLastError(E_INVALIDARG);
00720         return FALSE;
00721     }
00722     if (dwExpectedContentTypeFlags & unimplementedTypes)
00723         WARN("unimplemented for types %08x\n",
00724          dwExpectedContentTypeFlags & unimplementedTypes);
00725 
00726     if (pdwFormatType)
00727         *pdwFormatType = CERT_QUERY_FORMAT_BINARY;
00728     if (phCertStore)
00729         *phCertStore = NULL;
00730     if (phMsg)
00731         *phMsg = NULL;
00732     if (ppvContext)
00733         *ppvContext = NULL;
00734 
00735     ret = FALSE;
00736     if ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CERT) ||
00737      (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CRL) ||
00738      (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CTL))
00739     {
00740         ret = CRYPT_QueryContextObject(dwObjectType, pvObject,
00741          dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags,
00742          pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType, phCertStore,
00743          ppvContext);
00744     }
00745     if (!ret &&
00746      (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE))
00747     {
00748         ret = CRYPT_QuerySerializedStoreObject(dwObjectType, pvObject,
00749          pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
00750     }
00751     if (!ret &&
00752      ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT) ||
00753      (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL) ||
00754      (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL)))
00755     {
00756         ret = CRYPT_QuerySerializedContextObject(dwObjectType, pvObject,
00757          dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
00758          phCertStore, ppvContext);
00759     }
00760     if (!ret &&
00761      ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED) ||
00762      (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED)))
00763     {
00764         ret = CRYPT_QueryMessageObject(dwObjectType, pvObject,
00765          dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags,
00766          pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType,
00767          phCertStore, phMsg);
00768     }
00769     if (!ret &&
00770      (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED))
00771     {
00772         ret = CRYPT_QueryEmbeddedMessageObject(dwObjectType, pvObject,
00773          dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
00774          phCertStore, phMsg);
00775     }
00776     if (!ret)
00777         SetLastError(CRYPT_E_NO_MATCH);
00778     TRACE("returning %d\n", ret);
00779     return ret;
00780 }
00781 
00782 static BOOL WINAPI CRYPT_FormatHexString(DWORD dwCertEncodingType,
00783  DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
00784  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
00785  DWORD *pcbFormat)
00786 {
00787     BOOL ret;
00788     DWORD bytesNeeded;
00789 
00790     if (cbEncoded)
00791         bytesNeeded = (cbEncoded * 3) * sizeof(WCHAR);
00792     else
00793         bytesNeeded = sizeof(WCHAR);
00794     if (!pbFormat)
00795     {
00796         *pcbFormat = bytesNeeded;
00797         ret = TRUE;
00798     }
00799     else if (*pcbFormat < bytesNeeded)
00800     {
00801         *pcbFormat = bytesNeeded;
00802         SetLastError(ERROR_MORE_DATA);
00803         ret = FALSE;
00804     }
00805     else
00806     {
00807         static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
00808         static const WCHAR endFmt[] = { '%','0','2','x',0 };
00809         DWORD i;
00810         LPWSTR ptr = pbFormat;
00811 
00812         *pcbFormat = bytesNeeded;
00813         if (cbEncoded)
00814         {
00815             for (i = 0; i < cbEncoded; i++)
00816             {
00817                 if (i < cbEncoded - 1)
00818                     ptr += sprintfW(ptr, fmt, pbEncoded[i]);
00819                 else
00820                     ptr += sprintfW(ptr, endFmt, pbEncoded[i]);
00821             }
00822         }
00823         else
00824             *ptr = 0;
00825         ret = TRUE;
00826     }
00827     return ret;
00828 }
00829 
00830 #define MAX_STRING_RESOURCE_LEN 128
00831 
00832 static const WCHAR commaSpace[] = { ',',' ',0 };
00833 
00834 struct BitToString
00835 {
00836     BYTE bit;
00837     int id;
00838     WCHAR str[MAX_STRING_RESOURCE_LEN];
00839 };
00840 
00841 static BOOL CRYPT_FormatBits(BYTE bits, const struct BitToString *map,
00842  DWORD mapEntries, void *pbFormat, DWORD *pcbFormat, BOOL *first)
00843 {
00844     DWORD bytesNeeded = sizeof(WCHAR);
00845     int i;
00846     BOOL ret = TRUE, localFirst = *first;
00847 
00848     for (i = 0; i < mapEntries; i++)
00849         if (bits & map[i].bit)
00850         {
00851             if (!localFirst)
00852                 bytesNeeded += strlenW(commaSpace) * sizeof(WCHAR);
00853             localFirst = FALSE;
00854             bytesNeeded += strlenW(map[i].str) * sizeof(WCHAR);
00855         }
00856     if (!pbFormat)
00857     {
00858         *first = localFirst;
00859         *pcbFormat = bytesNeeded;
00860     }
00861     else if (*pcbFormat < bytesNeeded)
00862     {
00863         *first = localFirst;
00864         *pcbFormat = bytesNeeded;
00865         SetLastError(ERROR_MORE_DATA);
00866         ret = FALSE;
00867     }
00868     else
00869     {
00870         LPWSTR str = pbFormat;
00871 
00872         localFirst = *first;
00873         *pcbFormat = bytesNeeded;
00874         for (i = 0; i < mapEntries; i++)
00875             if (bits & map[i].bit)
00876             {
00877                 if (!localFirst)
00878                 {
00879                     strcpyW(str, commaSpace);
00880                     str += strlenW(commaSpace);
00881                 }
00882                 localFirst = FALSE;
00883                 strcpyW(str, map[i].str);
00884                 str += strlenW(map[i].str);
00885             }
00886         *first = localFirst;
00887     }
00888     return ret;
00889 }
00890 
00891 static struct BitToString keyUsageByte0Map[] = {
00892  { CERT_DIGITAL_SIGNATURE_KEY_USAGE, IDS_DIGITAL_SIGNATURE, { 0 } },
00893  { CERT_NON_REPUDIATION_KEY_USAGE, IDS_NON_REPUDIATION, { 0 } },
00894  { CERT_KEY_ENCIPHERMENT_KEY_USAGE, IDS_KEY_ENCIPHERMENT, { 0 } },
00895  { CERT_DATA_ENCIPHERMENT_KEY_USAGE, IDS_DATA_ENCIPHERMENT, { 0 } },
00896  { CERT_KEY_AGREEMENT_KEY_USAGE, IDS_KEY_AGREEMENT, { 0 } },
00897  { CERT_KEY_CERT_SIGN_KEY_USAGE, IDS_CERT_SIGN, { 0 } },
00898  { CERT_OFFLINE_CRL_SIGN_KEY_USAGE, IDS_OFFLINE_CRL_SIGN, { 0 } },
00899  { CERT_CRL_SIGN_KEY_USAGE, IDS_CRL_SIGN, { 0 } },
00900  { CERT_ENCIPHER_ONLY_KEY_USAGE, IDS_ENCIPHER_ONLY, { 0 } },
00901 };
00902 static struct BitToString keyUsageByte1Map[] = {
00903  { CERT_DECIPHER_ONLY_KEY_USAGE, IDS_DECIPHER_ONLY, { 0 } },
00904 };
00905 
00906 static BOOL WINAPI CRYPT_FormatKeyUsage(DWORD dwCertEncodingType,
00907  DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
00908  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
00909  DWORD *pcbFormat)
00910 {
00911     DWORD size;
00912     CRYPT_BIT_BLOB *bits;
00913     BOOL ret;
00914 
00915     if (!cbEncoded)
00916     {
00917         SetLastError(E_INVALIDARG);
00918         return FALSE;
00919     }
00920     if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_KEY_USAGE,
00921      pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &bits, &size)))
00922     {
00923         WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
00924         DWORD bytesNeeded = sizeof(WCHAR);
00925 
00926         LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
00927          sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
00928         if (!bits->cbData || bits->cbData > 2)
00929         {
00930             bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
00931             if (!pbFormat)
00932                 *pcbFormat = bytesNeeded;
00933             else if (*pcbFormat < bytesNeeded)
00934             {
00935                 *pcbFormat = bytesNeeded;
00936                 SetLastError(ERROR_MORE_DATA);
00937                 ret = FALSE;
00938             }
00939             else
00940             {
00941                 LPWSTR str = pbFormat;
00942 
00943                 *pcbFormat = bytesNeeded;
00944                 strcpyW(str, infoNotAvailable);
00945             }
00946         }
00947         else
00948         {
00949             static BOOL stringsLoaded = FALSE;
00950             int i;
00951             DWORD bitStringLen;
00952             BOOL first = TRUE;
00953 
00954             if (!stringsLoaded)
00955             {
00956                 for (i = 0;
00957                  i < sizeof(keyUsageByte0Map) / sizeof(keyUsageByte0Map[0]);
00958                  i++)
00959                     LoadStringW(hInstance, keyUsageByte0Map[i].id,
00960                      keyUsageByte0Map[i].str, MAX_STRING_RESOURCE_LEN);
00961                 for (i = 0;
00962                  i < sizeof(keyUsageByte1Map) / sizeof(keyUsageByte1Map[0]);
00963                  i++)
00964                     LoadStringW(hInstance, keyUsageByte1Map[i].id,
00965                      keyUsageByte1Map[i].str, MAX_STRING_RESOURCE_LEN);
00966                 stringsLoaded = TRUE;
00967             }
00968             CRYPT_FormatBits(bits->pbData[0], keyUsageByte0Map,
00969              sizeof(keyUsageByte0Map) / sizeof(keyUsageByte0Map[0]),
00970              NULL, &bitStringLen, &first);
00971             bytesNeeded += bitStringLen;
00972             if (bits->cbData == 2)
00973             {
00974                 CRYPT_FormatBits(bits->pbData[1], keyUsageByte1Map,
00975                  sizeof(keyUsageByte1Map) / sizeof(keyUsageByte1Map[0]),
00976                  NULL, &bitStringLen, &first);
00977                 bytesNeeded += bitStringLen;
00978             }
00979             bytesNeeded += 3 * sizeof(WCHAR); /* " (" + ")" */
00980             CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
00981              bits->cbData, NULL, &size);
00982             bytesNeeded += size;
00983             if (!pbFormat)
00984                 *pcbFormat = bytesNeeded;
00985             else if (*pcbFormat < bytesNeeded)
00986             {
00987                 *pcbFormat = bytesNeeded;
00988                 SetLastError(ERROR_MORE_DATA);
00989                 ret = FALSE;
00990             }
00991             else
00992             {
00993                 LPWSTR str = pbFormat;
00994 
00995                 bitStringLen = bytesNeeded;
00996                 first = TRUE;
00997                 CRYPT_FormatBits(bits->pbData[0], keyUsageByte0Map,
00998                  sizeof(keyUsageByte0Map) / sizeof(keyUsageByte0Map[0]),
00999                  str, &bitStringLen, &first);
01000                 str += bitStringLen / sizeof(WCHAR) - 1;
01001                 if (bits->cbData == 2)
01002                 {
01003                     bitStringLen = bytesNeeded;
01004                     CRYPT_FormatBits(bits->pbData[1], keyUsageByte1Map,
01005                      sizeof(keyUsageByte1Map) / sizeof(keyUsageByte1Map[0]),
01006                      str, &bitStringLen, &first);
01007                     str += bitStringLen / sizeof(WCHAR) - 1;
01008                 }
01009                 *str++ = ' ';
01010                 *str++ = '(';
01011                 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
01012                  bits->cbData, str, &size);
01013                 str += size / sizeof(WCHAR) - 1;
01014                 *str++ = ')';
01015                 *str = 0;
01016             }
01017         }
01018         LocalFree(bits);
01019     }
01020     return ret;
01021 }
01022 
01023 static const WCHAR crlf[] = { '\r','\n',0 };
01024 
01025 static WCHAR subjectTypeHeader[MAX_STRING_RESOURCE_LEN];
01026 static WCHAR subjectTypeCA[MAX_STRING_RESOURCE_LEN];
01027 static WCHAR subjectTypeEndCert[MAX_STRING_RESOURCE_LEN];
01028 static WCHAR pathLengthHeader[MAX_STRING_RESOURCE_LEN];
01029 
01030 static BOOL WINAPI CRYPT_FormatBasicConstraints2(DWORD dwCertEncodingType,
01031  DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
01032  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
01033  DWORD *pcbFormat)
01034 {
01035     DWORD size;
01036     CERT_BASIC_CONSTRAINTS2_INFO *info;
01037     BOOL ret;
01038 
01039     if (!cbEncoded)
01040     {
01041         SetLastError(E_INVALIDARG);
01042         return FALSE;
01043     }
01044     if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BASIC_CONSTRAINTS2,
01045      pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
01046     {
01047         static const WCHAR pathFmt[] = { '%','d',0 };
01048         static BOOL stringsLoaded = FALSE;
01049         DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
01050         WCHAR pathLength[MAX_STRING_RESOURCE_LEN];
01051         LPCWSTR sep, subjectType;
01052         DWORD sepLen;
01053 
01054         if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
01055         {
01056             sep = crlf;
01057             sepLen = strlenW(crlf) * sizeof(WCHAR);
01058         }
01059         else
01060         {
01061             sep = commaSpace;
01062             sepLen = strlenW(commaSpace) * sizeof(WCHAR);
01063         }
01064 
01065         if (!stringsLoaded)
01066         {
01067             LoadStringW(hInstance, IDS_SUBJECT_TYPE, subjectTypeHeader,
01068              sizeof(subjectTypeHeader) / sizeof(subjectTypeHeader[0]));
01069             LoadStringW(hInstance, IDS_SUBJECT_TYPE_CA, subjectTypeCA,
01070              sizeof(subjectTypeCA) / sizeof(subjectTypeCA[0]));
01071             LoadStringW(hInstance, IDS_SUBJECT_TYPE_END_CERT,
01072              subjectTypeEndCert,
01073              sizeof(subjectTypeEndCert) / sizeof(subjectTypeEndCert[0]));
01074             LoadStringW(hInstance, IDS_PATH_LENGTH, pathLengthHeader,
01075              sizeof(pathLengthHeader) / sizeof(pathLengthHeader[0]));
01076             stringsLoaded = TRUE;
01077         }
01078         bytesNeeded += strlenW(subjectTypeHeader) * sizeof(WCHAR);
01079         if (info->fCA)
01080             subjectType = subjectTypeCA;
01081         else
01082             subjectType = subjectTypeEndCert;
01083         bytesNeeded += strlenW(subjectType) * sizeof(WCHAR);
01084         bytesNeeded += sepLen;
01085         bytesNeeded += strlenW(pathLengthHeader) * sizeof(WCHAR);
01086         if (info->fPathLenConstraint)
01087             sprintfW(pathLength, pathFmt, info->dwPathLenConstraint);
01088         else
01089             LoadStringW(hInstance, IDS_PATH_LENGTH_NONE, pathLength,
01090              sizeof(pathLength) / sizeof(pathLength[0]));
01091         bytesNeeded += strlenW(pathLength) * sizeof(WCHAR);
01092         if (!pbFormat)
01093             *pcbFormat = bytesNeeded;
01094         else if (*pcbFormat < bytesNeeded)
01095         {
01096             *pcbFormat = bytesNeeded;
01097             SetLastError(ERROR_MORE_DATA);
01098             ret = FALSE;
01099         }
01100         else
01101         {
01102             LPWSTR str = pbFormat;
01103 
01104             *pcbFormat = bytesNeeded;
01105             strcpyW(str, subjectTypeHeader);
01106             str += strlenW(subjectTypeHeader);
01107             strcpyW(str, subjectType);
01108             str += strlenW(subjectType);
01109             strcpyW(str, sep);
01110             str += sepLen / sizeof(WCHAR);
01111             strcpyW(str, pathLengthHeader);
01112             str += strlenW(pathLengthHeader);
01113             strcpyW(str, pathLength);
01114         }
01115         LocalFree(info);
01116     }
01117     return ret;
01118 }
01119 
01120 static BOOL CRYPT_FormatHexStringWithPrefix(const CRYPT_DATA_BLOB *blob, int id,
01121  LPWSTR str, DWORD *pcbStr)
01122 {
01123     WCHAR buf[MAX_STRING_RESOURCE_LEN];
01124     DWORD bytesNeeded;
01125     BOOL ret;
01126 
01127     LoadStringW(hInstance, id, buf, sizeof(buf) / sizeof(buf[0]));
01128     CRYPT_FormatHexString(X509_ASN_ENCODING, 0, 0, NULL, NULL,
01129      blob->pbData, blob->cbData, NULL, &bytesNeeded);
01130     bytesNeeded += strlenW(buf) * sizeof(WCHAR);
01131     if (!str)
01132     {
01133         *pcbStr = bytesNeeded;
01134         ret = TRUE;
01135     }
01136     else if (*pcbStr < bytesNeeded)
01137     {
01138         *pcbStr = bytesNeeded;
01139         SetLastError(ERROR_MORE_DATA);
01140         ret = FALSE;
01141     }
01142     else
01143     {
01144         *pcbStr = bytesNeeded;
01145         strcpyW(str, buf);
01146         str += strlenW(str);
01147         bytesNeeded -= strlenW(str) * sizeof(WCHAR);
01148         ret = CRYPT_FormatHexString(X509_ASN_ENCODING, 0, 0, NULL, NULL,
01149          blob->pbData, blob->cbData, str, &bytesNeeded);
01150     }
01151     return ret;
01152 }
01153 
01154 static BOOL CRYPT_FormatKeyId(const CRYPT_DATA_BLOB *keyId, LPWSTR str,
01155  DWORD *pcbStr)
01156 {
01157     return CRYPT_FormatHexStringWithPrefix(keyId, IDS_KEY_ID, str, pcbStr);
01158 }
01159 
01160 static BOOL CRYPT_FormatCertSerialNumber(const CRYPT_DATA_BLOB *serialNum, LPWSTR str,
01161  DWORD *pcbStr)
01162 {
01163     return CRYPT_FormatHexStringWithPrefix(serialNum, IDS_CERT_SERIAL_NUMBER,
01164      str, pcbStr);
01165 }
01166 
01167 static const WCHAR indent[] = { ' ',' ',' ',' ',' ',0 };
01168 static const WCHAR colonCrlf[] = { ':','\r','\n',0 };
01169 
01170 static BOOL CRYPT_FormatAltNameEntry(DWORD dwFormatStrType, DWORD indentLevel,
01171  const CERT_ALT_NAME_ENTRY *entry, LPWSTR str, DWORD *pcbStr)
01172 {
01173     BOOL ret;
01174     WCHAR buf[MAX_STRING_RESOURCE_LEN];
01175     WCHAR mask[MAX_STRING_RESOURCE_LEN];
01176     WCHAR ipAddrBuf[32];
01177     WCHAR maskBuf[16];
01178     DWORD bytesNeeded = sizeof(WCHAR);
01179     DWORD strType = CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG;
01180 
01181     if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
01182         bytesNeeded += indentLevel * strlenW(indent) * sizeof(WCHAR);
01183     switch (entry->dwAltNameChoice)
01184     {
01185     case CERT_ALT_NAME_RFC822_NAME:
01186         LoadStringW(hInstance, IDS_ALT_NAME_RFC822_NAME, buf,
01187          sizeof(buf) / sizeof(buf[0]));
01188         bytesNeeded += strlenW(entry->u.pwszRfc822Name) * sizeof(WCHAR);
01189         ret = TRUE;
01190         break;
01191     case CERT_ALT_NAME_DNS_NAME:
01192         LoadStringW(hInstance, IDS_ALT_NAME_DNS_NAME, buf,
01193          sizeof(buf) / sizeof(buf[0]));
01194         bytesNeeded += strlenW(entry->u.pwszDNSName) * sizeof(WCHAR);
01195         ret = TRUE;
01196         break;
01197     case CERT_ALT_NAME_DIRECTORY_NAME:
01198     {
01199         DWORD directoryNameLen;
01200 
01201         if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
01202             strType |= CERT_NAME_STR_CRLF_FLAG;
01203         directoryNameLen = cert_name_to_str_with_indent(X509_ASN_ENCODING,
01204          indentLevel + 1, &entry->u.DirectoryName, strType, NULL, 0);
01205         LoadStringW(hInstance, IDS_ALT_NAME_DIRECTORY_NAME, buf,
01206          sizeof(buf) / sizeof(buf[0]));
01207         bytesNeeded += (directoryNameLen - 1) * sizeof(WCHAR);
01208         if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
01209             bytesNeeded += strlenW(colonCrlf) * sizeof(WCHAR);
01210         else
01211             bytesNeeded += sizeof(WCHAR); /* '=' */
01212         ret = TRUE;
01213         break;
01214     }
01215     case CERT_ALT_NAME_URL:
01216         LoadStringW(hInstance, IDS_ALT_NAME_URL, buf,
01217          sizeof(buf) / sizeof(buf[0]));
01218         bytesNeeded += strlenW(entry->u.pwszURL) * sizeof(WCHAR);
01219         ret = TRUE;
01220         break;
01221     case CERT_ALT_NAME_IP_ADDRESS:
01222     {
01223         static const WCHAR ipAddrWithMaskFmt[] = { '%','d','.','%','d','.',
01224          '%','d','.','%','d','/','%','d','.','%','d','.','%','d','.','%','d',0
01225         };
01226         static const WCHAR ipAddrFmt[] = { '%','d','.','%','d','.','%','d',
01227          '.','%','d',0 };
01228 
01229         LoadStringW(hInstance, IDS_ALT_NAME_IP_ADDRESS, buf,
01230          sizeof(buf) / sizeof(buf[0]));
01231         if (entry->u.IPAddress.cbData == 8)
01232         {
01233             if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
01234             {
01235                 LoadStringW(hInstance, IDS_ALT_NAME_MASK, mask,
01236                  sizeof(mask) / sizeof(mask[0]));
01237                 bytesNeeded += strlenW(mask) * sizeof(WCHAR);
01238                 sprintfW(ipAddrBuf, ipAddrFmt,
01239                  entry->u.IPAddress.pbData[0],
01240                  entry->u.IPAddress.pbData[1],
01241                  entry->u.IPAddress.pbData[2],
01242                  entry->u.IPAddress.pbData[3]);
01243                 bytesNeeded += strlenW(ipAddrBuf) * sizeof(WCHAR);
01244                 /* indent again, for the mask line */
01245                 bytesNeeded += indentLevel * strlenW(indent) * sizeof(WCHAR);
01246                 sprintfW(maskBuf, ipAddrFmt,
01247                  entry->u.IPAddress.pbData[4],
01248                  entry->u.IPAddress.pbData[5],
01249                  entry->u.IPAddress.pbData[6],
01250                  entry->u.IPAddress.pbData[7]);
01251                 bytesNeeded += strlenW(maskBuf) * sizeof(WCHAR);
01252                 bytesNeeded += strlenW(crlf) * sizeof(WCHAR);
01253             }
01254             else
01255             {
01256                 sprintfW(ipAddrBuf, ipAddrWithMaskFmt,
01257                  entry->u.IPAddress.pbData[0],
01258                  entry->u.IPAddress.pbData[1],
01259                  entry->u.IPAddress.pbData[2],
01260                  entry->u.IPAddress.pbData[3],
01261                  entry->u.IPAddress.pbData[4],
01262                  entry->u.IPAddress.pbData[5],
01263                  entry->u.IPAddress.pbData[6],
01264                  entry->u.IPAddress.pbData[7]);
01265                 bytesNeeded += (strlenW(ipAddrBuf) + 1) * sizeof(WCHAR);
01266             }
01267             ret = TRUE;
01268         }
01269         else
01270         {
01271             FIXME("unknown IP address format (%d bytes)\n",
01272              entry->u.IPAddress.cbData);
01273             ret = FALSE;
01274         }
01275         break;
01276     }
01277     default:
01278         FIXME("unimplemented for %d\n", entry->dwAltNameChoice);
01279         ret = FALSE;
01280     }
01281     if (ret)
01282     {
01283         bytesNeeded += strlenW(buf) * sizeof(WCHAR);
01284         if (!str)
01285             *pcbStr = bytesNeeded;
01286         else if (*pcbStr < bytesNeeded)
01287         {
01288             *pcbStr = bytesNeeded;
01289             SetLastError(ERROR_MORE_DATA);
01290             ret = FALSE;
01291         }
01292         else
01293         {
01294             DWORD i;
01295 
01296             *pcbStr = bytesNeeded;
01297             if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
01298             {
01299                 for (i = 0; i < indentLevel; i++)
01300                 {
01301                     strcpyW(str, indent);
01302                     str += strlenW(indent);
01303                 }
01304             }
01305             strcpyW(str, buf);
01306             str += strlenW(str);
01307             switch (entry->dwAltNameChoice)
01308             {
01309             case CERT_ALT_NAME_RFC822_NAME:
01310             case CERT_ALT_NAME_DNS_NAME:
01311             case CERT_ALT_NAME_URL:
01312                 strcpyW(str, entry->u.pwszURL);
01313                 break;
01314             case CERT_ALT_NAME_DIRECTORY_NAME:
01315                 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
01316                 {
01317                     strcpyW(str, colonCrlf);
01318                     str += strlenW(colonCrlf);
01319                 }
01320                 else
01321                     *str++ = '=';
01322                 cert_name_to_str_with_indent(X509_ASN_ENCODING,
01323                  indentLevel + 1, &entry->u.DirectoryName, strType, str,
01324                  bytesNeeded / sizeof(WCHAR));
01325                 break;
01326             case CERT_ALT_NAME_IP_ADDRESS:
01327                 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
01328                 {
01329                     strcpyW(str, ipAddrBuf);
01330                     str += strlenW(ipAddrBuf);
01331                     strcpyW(str, crlf);
01332                     str += strlenW(crlf);
01333                     if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
01334                     {
01335                         for (i = 0; i < indentLevel; i++)
01336                         {
01337                             strcpyW(str, indent);
01338                             str += strlenW(indent);
01339                         }
01340                     }
01341                     strcpyW(str, mask);
01342                     str += strlenW(mask);
01343                     strcpyW(str, maskBuf);
01344                 }
01345                 else
01346                     strcpyW(str, ipAddrBuf);
01347                 break;
01348             }
01349         }
01350     }
01351     return ret;
01352 }
01353 
01354 static BOOL CRYPT_FormatAltNameInfo(DWORD dwFormatStrType, DWORD indentLevel,
01355  const CERT_ALT_NAME_INFO *name, LPWSTR str, DWORD *pcbStr)
01356 {
01357     DWORD i, size, bytesNeeded = 0;
01358     BOOL ret = TRUE;
01359     LPCWSTR sep;
01360     DWORD sepLen;
01361 
01362     if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
01363     {
01364         sep = crlf;
01365         sepLen = strlenW(crlf) * sizeof(WCHAR);
01366     }
01367     else
01368     {
01369         sep = commaSpace;
01370         sepLen = strlenW(commaSpace) * sizeof(WCHAR);
01371     }
01372 
01373     for (i = 0; ret && i < name->cAltEntry; i++)
01374     {
01375         ret = CRYPT_FormatAltNameEntry(dwFormatStrType, indentLevel,
01376          &name->rgAltEntry[i], NULL, &size);
01377         if (ret)
01378         {
01379             bytesNeeded += size - sizeof(WCHAR);
01380             if (i < name->cAltEntry - 1)
01381                 bytesNeeded += sepLen;
01382         }
01383     }
01384     if (ret)
01385     {
01386         bytesNeeded += sizeof(WCHAR);
01387         if (!str)
01388             *pcbStr = bytesNeeded;
01389         else if (*pcbStr < bytesNeeded)
01390         {
01391             *pcbStr = bytesNeeded;
01392             SetLastError(ERROR_MORE_DATA);
01393             ret = FALSE;
01394         }
01395         else
01396         {
01397             *pcbStr = bytesNeeded;
01398             for (i = 0; ret && i < name->cAltEntry; i++)
01399             {
01400                 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, indentLevel,
01401                  &name->rgAltEntry[i], str, &size);
01402                 if (ret)
01403                 {
01404                     str += size / sizeof(WCHAR) - 1;
01405                     if (i < name->cAltEntry - 1)
01406                     {
01407                         strcpyW(str, sep);
01408                         str += sepLen / sizeof(WCHAR);
01409                     }
01410                 }
01411             }
01412         }
01413     }
01414     return ret;
01415 }
01416 
01417 static const WCHAR colonSep[] = { ':',' ',0 };
01418 
01419 static BOOL WINAPI CRYPT_FormatAltName(DWORD dwCertEncodingType,
01420  DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
01421  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
01422  DWORD *pcbFormat)
01423 {
01424     BOOL ret;
01425     CERT_ALT_NAME_INFO *info;
01426     DWORD size;
01427 
01428     if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_ALTERNATE_NAME,
01429      pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
01430     {
01431         ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 0, info, pbFormat, pcbFormat);
01432         LocalFree(info);
01433     }
01434     return ret;
01435 }
01436 
01437 static BOOL CRYPT_FormatCertIssuer(DWORD dwFormatStrType,
01438  const CERT_ALT_NAME_INFO *issuer, LPWSTR str, DWORD *pcbStr)
01439 {
01440     WCHAR buf[MAX_STRING_RESOURCE_LEN];
01441     DWORD bytesNeeded, sepLen;
01442     LPCWSTR sep;
01443     BOOL ret;
01444 
01445     LoadStringW(hInstance, IDS_CERT_ISSUER, buf, sizeof(buf) / sizeof(buf[0]));
01446     ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 1, issuer, NULL,
01447      &bytesNeeded);
01448     bytesNeeded += strlenW(buf) * sizeof(WCHAR);
01449     if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
01450     {
01451         sep = colonCrlf;
01452         sepLen = strlenW(colonCrlf) * sizeof(WCHAR);
01453     }
01454     else
01455     {
01456         sep = colonSep;
01457         sepLen = strlenW(colonSep) * sizeof(WCHAR);
01458     }
01459     bytesNeeded += sepLen;
01460     if (ret)
01461     {
01462         if (!str)
01463             *pcbStr = bytesNeeded;
01464         else if (*pcbStr < bytesNeeded)
01465         {
01466             *pcbStr = bytesNeeded;
01467             SetLastError(ERROR_MORE_DATA);
01468             ret = FALSE;
01469         }
01470         else
01471         {
01472             *pcbStr = bytesNeeded;
01473             strcpyW(str, buf);
01474             bytesNeeded -= strlenW(str) * sizeof(WCHAR);
01475             str += strlenW(str);
01476             strcpyW(str, sep);
01477             str += sepLen / sizeof(WCHAR);
01478             ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 1, issuer, str,
01479              &bytesNeeded);
01480         }
01481     }
01482     return ret;
01483 }
01484 
01485 static BOOL WINAPI CRYPT_FormatAuthorityKeyId2(DWORD dwCertEncodingType,
01486  DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
01487  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
01488  DWORD *pcbFormat)
01489 {
01490     CERT_AUTHORITY_KEY_ID2_INFO *info;
01491     DWORD size;
01492     BOOL ret = FALSE;
01493 
01494     if (!cbEncoded)
01495     {
01496         SetLastError(E_INVALIDARG);
01497         return FALSE;
01498     }
01499     if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_AUTHORITY_KEY_ID2,
01500      pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
01501     {
01502         DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
01503         LPCWSTR sep;
01504         DWORD sepLen;
01505         BOOL needSeparator = FALSE;
01506 
01507         if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
01508         {
01509             sep = crlf;
01510             sepLen = strlenW(crlf) * sizeof(WCHAR);
01511         }
01512         else
01513         {
01514             sep = commaSpace;
01515             sepLen = strlenW(commaSpace) * sizeof(WCHAR);
01516         }
01517 
01518         if (info->KeyId.cbData)
01519         {
01520             needSeparator = TRUE;
01521             ret = CRYPT_FormatKeyId(&info->KeyId, NULL, &size);
01522             if (ret)
01523             {
01524                 /* don't include NULL-terminator more than once */
01525                 bytesNeeded += size - sizeof(WCHAR);
01526             }
01527         }
01528         if (info->AuthorityCertIssuer.cAltEntry)
01529         {
01530             if (needSeparator)
01531                 bytesNeeded += sepLen;
01532             needSeparator = TRUE;
01533             ret = CRYPT_FormatCertIssuer(dwFormatStrType,
01534              &info->AuthorityCertIssuer, NULL, &size);
01535             if (ret)
01536             {
01537                 /* don't include NULL-terminator more than once */
01538                 bytesNeeded += size - sizeof(WCHAR);
01539             }
01540         }
01541         if (info->AuthorityCertSerialNumber.cbData)
01542         {
01543             if (needSeparator)
01544                 bytesNeeded += sepLen;
01545             ret = CRYPT_FormatCertSerialNumber(
01546              &info->AuthorityCertSerialNumber, NULL, &size);
01547             if (ret)
01548             {
01549                 /* don't include NULL-terminator more than once */
01550                 bytesNeeded += size - sizeof(WCHAR);
01551             }
01552         }
01553         if (ret)
01554         {
01555             if (!pbFormat)
01556                 *pcbFormat = bytesNeeded;
01557             else if (*pcbFormat < bytesNeeded)
01558             {
01559                 *pcbFormat = bytesNeeded;
01560                 SetLastError(ERROR_MORE_DATA);
01561                 ret = FALSE;
01562             }
01563             else
01564             {
01565                 LPWSTR str = pbFormat;
01566 
01567                 *pcbFormat = bytesNeeded;
01568                 needSeparator = FALSE;
01569                 if (info->KeyId.cbData)
01570                 {
01571                     needSeparator = TRUE;
01572                     /* Overestimate size available, it's already been checked
01573                      * above.
01574                      */
01575                     size = bytesNeeded;
01576                     ret = CRYPT_FormatKeyId(&info->KeyId, str, &size);
01577                     if (ret)
01578                         str += size / sizeof(WCHAR) - 1;
01579                 }
01580                 if (info->AuthorityCertIssuer.cAltEntry)
01581                 {
01582                     if (needSeparator)
01583                     {
01584                         strcpyW(str, sep);
01585                         str += sepLen / sizeof(WCHAR);
01586                     }
01587                     needSeparator = TRUE;
01588                     /* Overestimate size available, it's already been checked
01589                      * above.
01590                      */
01591                     size = bytesNeeded;
01592                     ret = CRYPT_FormatCertIssuer(dwFormatStrType,
01593                      &info->AuthorityCertIssuer, str, &size);
01594                     if (ret)
01595                         str += size / sizeof(WCHAR) - 1;
01596                 }
01597                 if (info->AuthorityCertSerialNumber.cbData)
01598                 {
01599                     if (needSeparator)
01600                     {
01601                         strcpyW(str, sep);
01602                         str += sepLen / sizeof(WCHAR);
01603                     }
01604                     /* Overestimate size available, it's already been checked
01605                      * above.
01606                      */
01607                     size = bytesNeeded;
01608                     ret = CRYPT_FormatCertSerialNumber(
01609                      &info->AuthorityCertSerialNumber, str, &size);
01610                 }
01611             }
01612         }
01613         LocalFree(info);
01614     }
01615     return ret;
01616 }
01617 
01618 static WCHAR aia[MAX_STRING_RESOURCE_LEN];
01619 static WCHAR accessMethod[MAX_STRING_RESOURCE_LEN];
01620 static WCHAR ocsp[MAX_STRING_RESOURCE_LEN];
01621 static WCHAR caIssuers[MAX_STRING_RESOURCE_LEN];
01622 static WCHAR unknown[MAX_STRING_RESOURCE_LEN];
01623 static WCHAR accessLocation[MAX_STRING_RESOURCE_LEN];
01624 
01625 static BOOL WINAPI CRYPT_FormatAuthorityInfoAccess(DWORD dwCertEncodingType,
01626  DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
01627  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
01628  DWORD *pcbFormat)
01629 {
01630     CERT_AUTHORITY_INFO_ACCESS *info;
01631     DWORD size;
01632     BOOL ret = FALSE;
01633 
01634     if (!cbEncoded)
01635     {
01636         SetLastError(E_INVALIDARG);
01637         return FALSE;
01638     }
01639     if ((ret = CryptDecodeObjectEx(dwCertEncodingType,
01640      X509_AUTHORITY_INFO_ACCESS, pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG,
01641      NULL, &info, &size)))
01642     {
01643         DWORD bytesNeeded = sizeof(WCHAR);
01644 
01645         if (!info->cAccDescr)
01646         {
01647             WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
01648 
01649             LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
01650              sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
01651             bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
01652             if (!pbFormat)
01653                 *pcbFormat = bytesNeeded;
01654             else if (*pcbFormat < bytesNeeded)
01655             {
01656                 *pcbFormat = bytesNeeded;
01657                 SetLastError(ERROR_MORE_DATA);
01658                 ret = FALSE;
01659             }
01660             else
01661             {
01662                 *pcbFormat = bytesNeeded;
01663                 strcpyW(pbFormat, infoNotAvailable);
01664             }
01665         }
01666         else
01667         {
01668             static const WCHAR numFmt[] = { '%','d',0 };
01669             static const WCHAR equal[] = { '=',0 };
01670             static BOOL stringsLoaded = FALSE;
01671             DWORD i;
01672             LPCWSTR headingSep, accessMethodSep, locationSep;
01673             WCHAR accessDescrNum[11];
01674 
01675             if (!stringsLoaded)
01676             {
01677                 LoadStringW(hInstance, IDS_AIA, aia,
01678                  sizeof(aia) / sizeof(aia[0]));
01679                 LoadStringW(hInstance, IDS_ACCESS_METHOD, accessMethod,
01680                  sizeof(accessMethod) / sizeof(accessMethod[0]));
01681                 LoadStringW(hInstance, IDS_ACCESS_METHOD_OCSP, ocsp,
01682                  sizeof(ocsp) / sizeof(ocsp[0]));
01683                 LoadStringW(hInstance, IDS_ACCESS_METHOD_CA_ISSUERS, caIssuers,
01684                  sizeof(caIssuers) / sizeof(caIssuers[0]));
01685                 LoadStringW(hInstance, IDS_ACCESS_METHOD_UNKNOWN, unknown,
01686                  sizeof(unknown) / sizeof(unknown[0]));
01687                 LoadStringW(hInstance, IDS_ACCESS_LOCATION, accessLocation,
01688                  sizeof(accessLocation) / sizeof(accessLocation[0]));
01689                 stringsLoaded = TRUE;
01690             }
01691             if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
01692             {
01693                 headingSep = crlf;
01694                 accessMethodSep = crlf;
01695                 locationSep = colonCrlf;
01696             }
01697             else
01698             {
01699                 headingSep = colonSep;
01700                 accessMethodSep = commaSpace;
01701                 locationSep = equal;
01702             }
01703 
01704             for (i = 0; ret && i < info->cAccDescr; i++)
01705             {
01706                 /* Heading */
01707                 bytesNeeded += sizeof(WCHAR); /* left bracket */
01708                 sprintfW(accessDescrNum, numFmt, i + 1);
01709                 bytesNeeded += strlenW(accessDescrNum) * sizeof(WCHAR);
01710                 bytesNeeded += sizeof(WCHAR); /* right bracket */
01711                 bytesNeeded += strlenW(aia) * sizeof(WCHAR);
01712                 bytesNeeded += strlenW(headingSep) * sizeof(WCHAR);
01713                 /* Access method */
01714                 bytesNeeded += strlenW(accessMethod) * sizeof(WCHAR);
01715                 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
01716                     bytesNeeded += strlenW(indent) * sizeof(WCHAR);
01717                 if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
01718                  szOID_PKIX_OCSP))
01719                     bytesNeeded += strlenW(ocsp) * sizeof(WCHAR);
01720                 else if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
01721                  szOID_PKIX_CA_ISSUERS))
01722                     bytesNeeded += strlenW(caIssuers) * sizeof(caIssuers);
01723                 else
01724                     bytesNeeded += strlenW(unknown) * sizeof(WCHAR);
01725                 bytesNeeded += sizeof(WCHAR); /* space */
01726                 bytesNeeded += sizeof(WCHAR); /* left paren */
01727                 bytesNeeded += strlen(info->rgAccDescr[i].pszAccessMethod)
01728                  * sizeof(WCHAR);
01729                 bytesNeeded += sizeof(WCHAR); /* right paren */
01730                 /* Delimiter between access method and location */
01731                 bytesNeeded += strlenW(accessMethodSep) * sizeof(WCHAR);
01732                 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
01733                     bytesNeeded += strlenW(indent) * sizeof(WCHAR);
01734                 bytesNeeded += strlenW(accessLocation) * sizeof(WCHAR);
01735                 bytesNeeded += strlenW(locationSep) * sizeof(WCHAR);
01736                 ret = CRYPT_FormatAltNameEntry(dwFormatStrType, 2,
01737                  &info->rgAccDescr[i].AccessLocation, NULL, &size);
01738                 if (ret)
01739                     bytesNeeded += size - sizeof(WCHAR);
01740                 /* Need extra delimiter between access method entries */
01741                 if (i < info->cAccDescr - 1)
01742                     bytesNeeded += strlenW(accessMethodSep) * sizeof(WCHAR);
01743             }
01744             if (ret)
01745             {
01746                 if (!pbFormat)
01747                     *pcbFormat = bytesNeeded;
01748                 else if (*pcbFormat < bytesNeeded)
01749                 {
01750                     *pcbFormat = bytesNeeded;
01751                     SetLastError(ERROR_MORE_DATA);
01752                     ret = FALSE;
01753                 }
01754                 else
01755                 {
01756                     LPWSTR str = pbFormat;
01757                     DWORD altNameEntrySize;
01758 
01759                     *pcbFormat = bytesNeeded;
01760                     for (i = 0; ret && i < info->cAccDescr; i++)
01761                     {
01762                         LPCSTR oidPtr;
01763 
01764                         *str++ = '[';
01765                         sprintfW(accessDescrNum, numFmt, i + 1);
01766                         strcpyW(str, accessDescrNum);
01767                         str += strlenW(accessDescrNum);
01768                         *str++ = ']';
01769                         strcpyW(str, aia);
01770                         str += strlenW(aia);
01771                         strcpyW(str, headingSep);
01772                         str += strlenW(headingSep);
01773                         if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
01774                         {
01775                             strcpyW(str, indent);
01776                             str += strlenW(indent);
01777                         }
01778                         strcpyW(str, accessMethod);
01779                         str += strlenW(accessMethod);
01780                         if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
01781                          szOID_PKIX_OCSP))
01782                         {
01783                             strcpyW(str, ocsp);
01784                             str += strlenW(ocsp);
01785                         }
01786                         else if (!strcmp(info->rgAccDescr[i].pszAccessMethod,
01787                          szOID_PKIX_CA_ISSUERS))
01788                         {
01789                             strcpyW(str, caIssuers);
01790                             str += strlenW(caIssuers);
01791                         }
01792                         else
01793                         {
01794                             strcpyW(str, unknown);
01795                             str += strlenW(unknown);
01796                         }
01797                         *str++ = ' ';
01798                         *str++ = '(';
01799                         for (oidPtr = info->rgAccDescr[i].pszAccessMethod;
01800                          *oidPtr; oidPtr++, str++)
01801                             *str = *oidPtr;
01802                         *str++ = ')';
01803                         strcpyW(str, accessMethodSep);
01804                         str += strlenW(accessMethodSep);
01805                         if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
01806                         {
01807                             strcpyW(str, indent);
01808                             str += strlenW(indent);
01809                         }
01810                         strcpyW(str, accessLocation);
01811                         str += strlenW(accessLocation);
01812                         strcpyW(str, locationSep);
01813                         str += strlenW(locationSep);
01814                         /* This overestimates the size available, but that
01815                          * won't matter since we checked earlier whether enough
01816                          * space for the entire string was available.
01817                          */
01818                         altNameEntrySize = bytesNeeded;
01819                         ret = CRYPT_FormatAltNameEntry(dwFormatStrType, 2,
01820                          &info->rgAccDescr[i].AccessLocation, str,
01821                          &altNameEntrySize);
01822                         if (ret)
01823                             str += altNameEntrySize / sizeof(WCHAR) - 1;
01824                         if (i < info->cAccDescr - 1)
01825                         {
01826                             strcpyW(str, accessMethodSep);
01827                             str += strlenW(accessMethodSep);
01828                         }
01829                     }
01830                 }
01831             }
01832         }
01833         LocalFree(info);
01834     }
01835     return ret;
01836 }
01837 
01838 static WCHAR keyCompromise[MAX_STRING_RESOURCE_LEN];
01839 static WCHAR caCompromise[MAX_STRING_RESOURCE_LEN];
01840 static WCHAR affiliationChanged[MAX_STRING_RESOURCE_LEN];
01841 static WCHAR superseded[MAX_STRING_RESOURCE_LEN];
01842 static WCHAR operationCeased[MAX_STRING_RESOURCE_LEN];
01843 static WCHAR certificateHold[MAX_STRING_RESOURCE_LEN];
01844 
01845 struct reason_map_entry
01846 {
01847     BYTE   reasonBit;
01848     LPWSTR reason;
01849     int    id;
01850 };
01851 static struct reason_map_entry reason_map[] = {
01852  { CRL_REASON_KEY_COMPROMISE_FLAG, keyCompromise, IDS_REASON_KEY_COMPROMISE },
01853  { CRL_REASON_CA_COMPROMISE_FLAG, caCompromise, IDS_REASON_CA_COMPROMISE },
01854  { CRL_REASON_AFFILIATION_CHANGED_FLAG, affiliationChanged,
01855    IDS_REASON_AFFILIATION_CHANGED },
01856  { CRL_REASON_SUPERSEDED_FLAG, superseded, IDS_REASON_SUPERSEDED },
01857  { CRL_REASON_CESSATION_OF_OPERATION_FLAG, operationCeased,
01858    IDS_REASON_CESSATION_OF_OPERATION },
01859  { CRL_REASON_CERTIFICATE_HOLD_FLAG, certificateHold,
01860    IDS_REASON_CERTIFICATE_HOLD },
01861 };
01862 
01863 static BOOL CRYPT_FormatReason(DWORD dwFormatStrType,
01864  const CRYPT_BIT_BLOB *reasonFlags, LPWSTR str, DWORD *pcbStr)
01865 {
01866     static const WCHAR sep[] = { ',',' ',0 };
01867     static const WCHAR bitsFmt[] = { ' ','(','%','0','2','x',')',0 };
01868     static BOOL stringsLoaded = FALSE;
01869     int i, numReasons = 0;
01870     BOOL ret = TRUE;
01871     DWORD bytesNeeded = sizeof(WCHAR);
01872     WCHAR bits[6];
01873 
01874     if (!stringsLoaded)
01875     {
01876         for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++)
01877             LoadStringW(hInstance, reason_map[i].id, reason_map[i].reason,
01878              MAX_STRING_RESOURCE_LEN);
01879         stringsLoaded = TRUE;
01880     }
01881     /* No need to check reasonFlags->cbData, we already know it's positive.
01882      * Ignore any other bytes, as they're for undefined bits.
01883      */
01884     for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++)
01885     {
01886         if (reasonFlags->pbData[0] & reason_map[i].reasonBit)
01887         {
01888             bytesNeeded += strlenW(reason_map[i].reason) * sizeof(WCHAR);
01889             if (numReasons++)
01890                 bytesNeeded += strlenW(sep) * sizeof(WCHAR);
01891         }
01892     }
01893     sprintfW(bits, bitsFmt, reasonFlags->pbData[0]);
01894     bytesNeeded += strlenW(bits);
01895     if (!str)
01896         *pcbStr = bytesNeeded;
01897     else if (*pcbStr < bytesNeeded)
01898     {
01899         *pcbStr = bytesNeeded;
01900         SetLastError(ERROR_MORE_DATA);
01901         ret = FALSE;
01902     }
01903     else
01904     {
01905         *pcbStr = bytesNeeded;
01906         for (i = 0; i < sizeof(reason_map) / sizeof(reason_map[0]); i++)
01907         {
01908             if (reasonFlags->pbData[0] & reason_map[i].reasonBit)
01909             {
01910                 strcpyW(str, reason_map[i].reason);
01911                 str += strlenW(reason_map[i].reason);
01912                 if (i < sizeof(reason_map) / sizeof(reason_map[0]) - 1 &&
01913                  numReasons)
01914                 {
01915                     strcpyW(str, sep);
01916                     str += strlenW(sep);
01917                 }
01918             }
01919         }
01920         strcpyW(str, bits);
01921     }
01922     return ret;
01923 }
01924 
01925 static WCHAR crlDistPoint[MAX_STRING_RESOURCE_LEN];
01926 static WCHAR distPointName[MAX_STRING_RESOURCE_LEN];
01927 static WCHAR fullName[MAX_STRING_RESOURCE_LEN];
01928 static WCHAR rdnName[MAX_STRING_RESOURCE_LEN];
01929 static WCHAR reason[MAX_STRING_RESOURCE_LEN];
01930 static WCHAR issuer[MAX_STRING_RESOURCE_LEN];
01931 
01932 static BOOL WINAPI CRYPT_FormatCRLDistPoints(DWORD dwCertEncodingType,
01933  DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
01934  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
01935  DWORD *pcbFormat)
01936 {
01937     CRL_DIST_POINTS_INFO *info;
01938     DWORD size;
01939     BOOL ret = FALSE;
01940 
01941     if (!cbEncoded)
01942     {
01943         SetLastError(E_INVALIDARG);
01944         return FALSE;
01945     }
01946     if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CRL_DIST_POINTS,
01947      pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size)))
01948     {
01949         static const WCHAR numFmt[] = { '%','d',0 };
01950         static const WCHAR colon[] = { ':',0 };
01951         static BOOL stringsLoaded = FALSE;
01952         DWORD bytesNeeded = sizeof(WCHAR); /* space for NULL terminator */
01953         BOOL haveAnEntry = FALSE;
01954         LPCWSTR headingSep, nameSep;
01955         WCHAR distPointNum[11];
01956         DWORD i;
01957 
01958         if (!stringsLoaded)
01959         {
01960             LoadStringW(hInstance, IDS_CRL_DIST_POINT, crlDistPoint,
01961              sizeof(crlDistPoint) / sizeof(crlDistPoint[0]));
01962             LoadStringW(hInstance, IDS_CRL_DIST_POINT_NAME, distPointName,
01963              sizeof(distPointName) / sizeof(distPointName[0]));
01964             LoadStringW(hInstance, IDS_CRL_DIST_POINT_FULL_NAME, fullName,
01965              sizeof(fullName) / sizeof(fullName[0]));
01966             LoadStringW(hInstance, IDS_CRL_DIST_POINT_RDN_NAME, rdnName,
01967              sizeof(rdnName) / sizeof(rdnName[0]));
01968             LoadStringW(hInstance, IDS_CRL_DIST_POINT_REASON, reason,
01969              sizeof(reason) / sizeof(reason[0]));
01970             LoadStringW(hInstance, IDS_CRL_DIST_POINT_ISSUER, issuer,
01971              sizeof(issuer) / sizeof(issuer[0]));
01972             stringsLoaded = TRUE;
01973         }
01974         if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
01975         {
01976             headingSep = crlf;
01977             nameSep = colonCrlf;
01978         }
01979         else
01980         {
01981             headingSep = colonSep;
01982             nameSep = colon;
01983         }
01984 
01985         for (i = 0; ret && i < info->cDistPoint; i++)
01986         {
01987             CRL_DIST_POINT *distPoint = &info->rgDistPoint[i];
01988 
01989             if (distPoint->DistPointName.dwDistPointNameChoice !=
01990              CRL_DIST_POINT_NO_NAME)
01991             {
01992                 bytesNeeded += strlenW(distPointName) * sizeof(WCHAR);
01993                 bytesNeeded += strlenW(nameSep) * sizeof(WCHAR);
01994                 if (distPoint->DistPointName.dwDistPointNameChoice ==
01995                  CRL_DIST_POINT_FULL_NAME)
01996                     bytesNeeded += strlenW(fullName) * sizeof(WCHAR);
01997                 else
01998                     bytesNeeded += strlenW(rdnName) * sizeof(WCHAR);
01999                 bytesNeeded += strlenW(nameSep) * sizeof(WCHAR);
02000                 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
02001                     bytesNeeded += 2 * strlenW(indent) * sizeof(WCHAR);
02002                 /* The indent level (3) is higher than when used as the issuer,
02003                  * because the name is subordinate to the name type (full vs.
02004                  * RDN.)
02005                  */
02006                 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 3,
02007                  &distPoint->DistPointName.u.FullName, NULL, &size);
02008                 if (ret)
02009                     bytesNeeded += size - sizeof(WCHAR);
02010                 haveAnEntry = TRUE;
02011             }
02012             else if (distPoint->ReasonFlags.cbData)
02013             {
02014                 bytesNeeded += strlenW(reason) * sizeof(WCHAR);
02015                 ret = CRYPT_FormatReason(dwFormatStrType,
02016                  &distPoint->ReasonFlags, NULL, &size);
02017                 if (ret)
02018                     bytesNeeded += size - sizeof(WCHAR);
02019                 haveAnEntry = TRUE;
02020             }
02021             else if (distPoint->CRLIssuer.cAltEntry)
02022             {
02023                 bytesNeeded += strlenW(issuer) * sizeof(WCHAR);
02024                 bytesNeeded += strlenW(nameSep) * sizeof(WCHAR);
02025                 ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 2,
02026                  &distPoint->CRLIssuer, NULL, &size);
02027                 if (ret)
02028                     bytesNeeded += size - sizeof(WCHAR);
02029                 haveAnEntry = TRUE;
02030             }
02031             if (haveAnEntry)
02032             {
02033                 bytesNeeded += sizeof(WCHAR); /* left bracket */
02034                 sprintfW(distPointNum, numFmt, i + 1);
02035                 bytesNeeded += strlenW(distPointNum) * sizeof(WCHAR);
02036                 bytesNeeded += sizeof(WCHAR); /* right bracket */
02037                 bytesNeeded += strlenW(crlDistPoint) * sizeof(WCHAR);
02038                 bytesNeeded += strlenW(headingSep) * sizeof(WCHAR);
02039                 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
02040                     bytesNeeded += strlenW(indent) * sizeof(WCHAR);
02041             }
02042         }
02043         if (!haveAnEntry)
02044         {
02045             WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
02046 
02047             LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
02048              sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
02049             bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
02050             if (!pbFormat)
02051                 *pcbFormat = bytesNeeded;
02052             else if (*pcbFormat < bytesNeeded)
02053             {
02054                 *pcbFormat = bytesNeeded;
02055                 SetLastError(ERROR_MORE_DATA);
02056                 ret = FALSE;
02057             }
02058             else
02059             {
02060                 *pcbFormat = bytesNeeded;
02061                 strcpyW(pbFormat, infoNotAvailable);
02062             }
02063         }
02064         else
02065         {
02066             if (!pbFormat)
02067                 *pcbFormat = bytesNeeded;
02068             else if (*pcbFormat < bytesNeeded)
02069             {
02070                 *pcbFormat = bytesNeeded;
02071                 SetLastError(ERROR_MORE_DATA);
02072                 ret = FALSE;
02073             }
02074             else
02075             {
02076                 LPWSTR str = pbFormat;
02077 
02078                 *pcbFormat = bytesNeeded;
02079                 for (i = 0; ret && i < info->cDistPoint; i++)
02080                 {
02081                     CRL_DIST_POINT *distPoint = &info->rgDistPoint[i];
02082 
02083                     *str++ = '[';
02084                     sprintfW(distPointNum, numFmt, i + 1);
02085                     strcpyW(str, distPointNum);
02086                     str += strlenW(distPointNum);
02087                     *str++ = ']';
02088                     strcpyW(str, crlDistPoint);
02089                     str += strlenW(crlDistPoint);
02090                     strcpyW(str, headingSep);
02091                     str += strlenW(headingSep);
02092                     if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
02093                     {
02094                         strcpyW(str, indent);
02095                         str += strlenW(indent);
02096                     }
02097                     if (distPoint->DistPointName.dwDistPointNameChoice !=
02098                      CRL_DIST_POINT_NO_NAME)
02099                     {
02100                         DWORD altNameSize = bytesNeeded;
02101 
02102                         strcpyW(str, distPointName);
02103                         str += strlenW(distPointName);
02104                         strcpyW(str, nameSep);
02105                         str += strlenW(nameSep);
02106                         if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
02107                         {
02108                             strcpyW(str, indent);
02109                             str += strlenW(indent);
02110                             strcpyW(str, indent);
02111                             str += strlenW(indent);
02112                         }
02113                         if (distPoint->DistPointName.dwDistPointNameChoice ==
02114                          CRL_DIST_POINT_FULL_NAME)
02115                         {
02116                             strcpyW(str, fullName);
02117                             str += strlenW(fullName);
02118                         }
02119                         else
02120                         {
02121                             strcpyW(str, rdnName);
02122                             str += strlenW(rdnName);
02123                         }
02124                         strcpyW(str, nameSep);
02125                         str += strlenW(nameSep);
02126                         ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 3,
02127                          &distPoint->DistPointName.u.FullName, str,
02128                          &altNameSize);
02129                         if (ret)
02130                             str += altNameSize / sizeof(WCHAR) - 1;
02131                     }
02132                     else if (distPoint->ReasonFlags.cbData)
02133                     {
02134                         DWORD reasonSize = bytesNeeded;
02135 
02136                         strcpyW(str, reason);
02137                         str += strlenW(reason);
02138                         ret = CRYPT_FormatReason(dwFormatStrType,
02139                          &distPoint->ReasonFlags, str, &reasonSize);
02140                         if (ret)
02141                             str += reasonSize / sizeof(WCHAR) - 1;
02142                     }
02143                     else if (distPoint->CRLIssuer.cAltEntry)
02144                     {
02145                         DWORD crlIssuerSize = bytesNeeded;
02146 
02147                         strcpyW(str, issuer);
02148                         str += strlenW(issuer);
02149                         strcpyW(str, nameSep);
02150                         str += strlenW(nameSep);
02151                         ret = CRYPT_FormatAltNameInfo(dwFormatStrType, 2,
02152                          &distPoint->CRLIssuer, str,
02153                          &crlIssuerSize);
02154                         if (ret)
02155                             str += crlIssuerSize / sizeof(WCHAR) - 1;
02156                     }
02157                 }
02158             }
02159         }
02160         LocalFree(info);
02161     }
02162     return ret;
02163 }
02164 
02165 static BOOL WINAPI CRYPT_FormatEnhancedKeyUsage(DWORD dwCertEncodingType,
02166  DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
02167  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
02168  DWORD *pcbFormat)
02169 {
02170     CERT_ENHKEY_USAGE *usage;
02171     DWORD size;
02172     BOOL ret = FALSE;
02173 
02174     if (!cbEncoded)
02175     {
02176         SetLastError(E_INVALIDARG);
02177         return FALSE;
02178     }
02179     if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_ENHANCED_KEY_USAGE,
02180      pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &usage, &size)))
02181     {
02182         WCHAR unknown[MAX_STRING_RESOURCE_LEN];
02183         DWORD i;
02184         DWORD bytesNeeded = sizeof(WCHAR); /* space for the NULL terminator */
02185         LPCWSTR sep;
02186         DWORD sepLen;
02187 
02188         if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
02189         {
02190             sep = crlf;
02191             sepLen = strlenW(crlf) * sizeof(WCHAR);
02192         }
02193         else
02194         {
02195             sep = commaSpace;
02196             sepLen = strlenW(commaSpace) * sizeof(WCHAR);
02197         }
02198 
02199         LoadStringW(hInstance, IDS_USAGE_UNKNOWN, unknown,
02200          sizeof(unknown) / sizeof(unknown[0]));
02201         for (i = 0; i < usage->cUsageIdentifier; i++)
02202         {
02203             PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
02204              usage->rgpszUsageIdentifier[i], CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
02205 
02206             if (info)
02207                 bytesNeeded += strlenW(info->pwszName) * sizeof(WCHAR);
02208             else
02209                 bytesNeeded += strlenW(unknown) * sizeof(WCHAR);
02210             bytesNeeded += sizeof(WCHAR); /* space */
02211             bytesNeeded += sizeof(WCHAR); /* left paren */
02212             bytesNeeded += strlen(usage->rgpszUsageIdentifier[i]) *
02213              sizeof(WCHAR);
02214             bytesNeeded += sizeof(WCHAR); /* right paren */
02215             if (i < usage->cUsageIdentifier - 1)
02216                 bytesNeeded += sepLen;
02217         }
02218         if (!pbFormat)
02219             *pcbFormat = bytesNeeded;
02220         else if (*pcbFormat < bytesNeeded)
02221         {
02222             *pcbFormat = bytesNeeded;
02223             SetLastError(ERROR_MORE_DATA);
02224             ret = FALSE;
02225         }
02226         else
02227         {
02228             LPWSTR str = pbFormat;
02229 
02230             *pcbFormat = bytesNeeded;
02231             for (i = 0; i < usage->cUsageIdentifier; i++)
02232             {
02233                 PCCRYPT_OID_INFO info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY,
02234                  usage->rgpszUsageIdentifier[i],
02235                  CRYPT_ENHKEY_USAGE_OID_GROUP_ID);
02236                 LPCSTR oidPtr;
02237 
02238                 if (info)
02239                 {
02240                     strcpyW(str, info->pwszName);
02241                     str += strlenW(info->pwszName);
02242                 }
02243                 else
02244                 {
02245                     strcpyW(str, unknown);
02246                     str += strlenW(unknown);
02247                 }
02248                 *str++ = ' ';
02249                 *str++ = '(';
02250                 for (oidPtr = usage->rgpszUsageIdentifier[i]; *oidPtr; oidPtr++)
02251                     *str++ = *oidPtr;
02252                 *str++ = ')';
02253                 *str = 0;
02254                 if (i < usage->cUsageIdentifier - 1)
02255                 {
02256                     strcpyW(str, sep);
02257                     str += sepLen / sizeof(WCHAR);
02258                 }
02259             }
02260         }
02261         LocalFree(usage);
02262     }
02263     return ret;
02264 }
02265 
02266 static struct BitToString netscapeCertTypeMap[] = {
02267  { NETSCAPE_SSL_CLIENT_AUTH_CERT_TYPE, IDS_NETSCAPE_SSL_CLIENT, { 0 } },
02268  { NETSCAPE_SSL_SERVER_AUTH_CERT_TYPE, IDS_NETSCAPE_SSL_SERVER, { 0 } },
02269  { NETSCAPE_SMIME_CERT_TYPE, IDS_NETSCAPE_SMIME, { 0 } },
02270  { NETSCAPE_SIGN_CERT_TYPE, IDS_NETSCAPE_SIGN, { 0 } },
02271  { NETSCAPE_SSL_CA_CERT_TYPE, IDS_NETSCAPE_SSL_CA, { 0 } },
02272  { NETSCAPE_SMIME_CA_CERT_TYPE, IDS_NETSCAPE_SMIME_CA, { 0 } },
02273  { NETSCAPE_SIGN_CA_CERT_TYPE, IDS_NETSCAPE_SIGN_CA, { 0 } },
02274 };
02275 
02276 static BOOL WINAPI CRYPT_FormatNetscapeCertType(DWORD dwCertEncodingType,
02277  DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
02278  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
02279  DWORD *pcbFormat)
02280 {
02281     DWORD size;
02282     CRYPT_BIT_BLOB *bits;
02283     BOOL ret;
02284 
02285     if (!cbEncoded)
02286     {
02287         SetLastError(E_INVALIDARG);
02288         return FALSE;
02289     }
02290     if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_BITS,
02291      pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &bits, &size)))
02292     {
02293         WCHAR infoNotAvailable[MAX_STRING_RESOURCE_LEN];
02294         DWORD bytesNeeded = sizeof(WCHAR);
02295 
02296         LoadStringW(hInstance, IDS_INFO_NOT_AVAILABLE, infoNotAvailable,
02297          sizeof(infoNotAvailable) / sizeof(infoNotAvailable[0]));
02298         if (!bits->cbData || bits->cbData > 1)
02299         {
02300             bytesNeeded += strlenW(infoNotAvailable) * sizeof(WCHAR);
02301             if (!pbFormat)
02302                 *pcbFormat = bytesNeeded;
02303             else if (*pcbFormat < bytesNeeded)
02304             {
02305                 *pcbFormat = bytesNeeded;
02306                 SetLastError(ERROR_MORE_DATA);
02307                 ret = FALSE;
02308             }
02309             else
02310             {
02311                 LPWSTR str = pbFormat;
02312 
02313                 *pcbFormat = bytesNeeded;
02314                 strcpyW(str, infoNotAvailable);
02315             }
02316         }
02317         else
02318         {
02319             static BOOL stringsLoaded = FALSE;
02320             int i;
02321             DWORD bitStringLen;
02322             BOOL first = TRUE;
02323 
02324             if (!stringsLoaded)
02325             {
02326                 for (i = 0; i < sizeof(netscapeCertTypeMap) /
02327                  sizeof(netscapeCertTypeMap[0]); i++)
02328                     LoadStringW(hInstance, netscapeCertTypeMap[i].id,
02329                      netscapeCertTypeMap[i].str, MAX_STRING_RESOURCE_LEN);
02330                 stringsLoaded = TRUE;
02331             }
02332             CRYPT_FormatBits(bits->pbData[0], netscapeCertTypeMap,
02333              sizeof(netscapeCertTypeMap) / sizeof(netscapeCertTypeMap[0]),
02334              NULL, &bitStringLen, &first);
02335             bytesNeeded += bitStringLen;
02336             bytesNeeded += 3 * sizeof(WCHAR); /* " (" + ")" */
02337             CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
02338              bits->cbData, NULL, &size);
02339             bytesNeeded += size;
02340             if (!pbFormat)
02341                 *pcbFormat = bytesNeeded;
02342             else if (*pcbFormat < bytesNeeded)
02343             {
02344                 *pcbFormat = bytesNeeded;
02345                 SetLastError(ERROR_MORE_DATA);
02346                 ret = FALSE;
02347             }
02348             else
02349             {
02350                 LPWSTR str = pbFormat;
02351 
02352                 bitStringLen = bytesNeeded;
02353                 first = TRUE;
02354                 CRYPT_FormatBits(bits->pbData[0], netscapeCertTypeMap,
02355                  sizeof(netscapeCertTypeMap) / sizeof(netscapeCertTypeMap[0]),
02356                  str, &bitStringLen, &first);
02357                 str += bitStringLen / sizeof(WCHAR) - 1;
02358                 *str++ = ' ';
02359                 *str++ = '(';
02360                 CRYPT_FormatHexString(0, 0, 0, NULL, NULL, bits->pbData,
02361                  bits->cbData, str, &size);
02362                 str += size / sizeof(WCHAR) - 1;
02363                 *str++ = ')';
02364                 *str = 0;
02365             }
02366         }
02367         LocalFree(bits);
02368     }
02369     return ret;
02370 }
02371 
02372 static WCHAR financialCriteria[MAX_STRING_RESOURCE_LEN];
02373 static WCHAR available[MAX_STRING_RESOURCE_LEN];
02374 static WCHAR notAvailable[MAX_STRING_RESOURCE_LEN];
02375 static WCHAR meetsCriteria[MAX_STRING_RESOURCE_LEN];
02376 static WCHAR yes[MAX_STRING_RESOURCE_LEN];
02377 static WCHAR no[MAX_STRING_RESOURCE_LEN];
02378 
02379 static BOOL WINAPI CRYPT_FormatSpcFinancialCriteria(DWORD dwCertEncodingType,
02380  DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
02381  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
02382  DWORD *pcbFormat)
02383 {
02384     SPC_FINANCIAL_CRITERIA criteria;
02385     DWORD size = sizeof(criteria);
02386     BOOL ret = FALSE;
02387 
02388     if (!cbEncoded)
02389     {
02390         SetLastError(E_INVALIDARG);
02391         return FALSE;
02392     }
02393     if ((ret = CryptDecodeObjectEx(dwCertEncodingType,
02394      SPC_FINANCIAL_CRITERIA_STRUCT, pbEncoded, cbEncoded, 0, NULL, &criteria,
02395      &size)))
02396     {
02397         static BOOL stringsLoaded = FALSE;
02398         DWORD bytesNeeded = sizeof(WCHAR);
02399         LPCWSTR sep;
02400         DWORD sepLen;
02401 
02402         if (!stringsLoaded)
02403         {
02404             LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA, financialCriteria,
02405              sizeof(financialCriteria) / sizeof(financialCriteria[0]));
02406             LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_AVAILABLE, available,
02407              sizeof(available) / sizeof(available[0]));
02408             LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_NOT_AVAILABLE,
02409              notAvailable, sizeof(notAvailable) / sizeof(notAvailable[0]));
02410             LoadStringW(hInstance, IDS_FINANCIAL_CRITERIA_MEETS_CRITERIA,
02411              meetsCriteria, sizeof(meetsCriteria) / sizeof(meetsCriteria[0]));
02412             LoadStringW(hInstance, IDS_YES, yes, sizeof(yes) / sizeof(yes[0]));
02413             LoadStringW(hInstance, IDS_NO, no, sizeof(no) / sizeof(no[0]));
02414             stringsLoaded = TRUE;
02415         }
02416         if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
02417         {
02418             sep = crlf;
02419             sepLen = strlenW(crlf) * sizeof(WCHAR);
02420         }
02421         else
02422         {
02423             sep = commaSpace;
02424             sepLen = strlenW(commaSpace) * sizeof(WCHAR);
02425         }
02426         bytesNeeded += strlenW(financialCriteria) * sizeof(WCHAR);
02427         if (criteria.fFinancialInfoAvailable)
02428         {
02429             bytesNeeded += strlenW(available) * sizeof(WCHAR);
02430             bytesNeeded += sepLen;
02431             bytesNeeded += strlenW(meetsCriteria) * sizeof(WCHAR);
02432             if (criteria.fMeetsCriteria)
02433                 bytesNeeded += strlenW(yes) * sizeof(WCHAR);
02434             else
02435                 bytesNeeded += strlenW(no) * sizeof(WCHAR);
02436         }
02437         else
02438             bytesNeeded += strlenW(notAvailable) * sizeof(WCHAR);
02439         if (!pbFormat)
02440             *pcbFormat = bytesNeeded;
02441         else if (*pcbFormat < bytesNeeded)
02442         {
02443             *pcbFormat = bytesNeeded;
02444             SetLastError(ERROR_MORE_DATA);
02445             ret = FALSE;
02446         }
02447         else
02448         {
02449             LPWSTR str = pbFormat;
02450 
02451             *pcbFormat = bytesNeeded;
02452             strcpyW(str, financialCriteria);
02453             str += strlenW(financialCriteria);
02454             if (criteria.fFinancialInfoAvailable)
02455             {
02456                 strcpyW(str, available);
02457                 str += strlenW(available);
02458                 strcpyW(str, sep);
02459                 str += sepLen / sizeof(WCHAR);
02460                 strcpyW(str, meetsCriteria);
02461                 str += strlenW(meetsCriteria);
02462                 if (criteria.fMeetsCriteria)
02463                     strcpyW(str, yes);
02464                 else
02465                     strcpyW(str, no);
02466             }
02467             else
02468             {
02469                 strcpyW(str, notAvailable);
02470             }
02471         }
02472     }
02473     return ret;
02474 }
02475 
02476 static BOOL WINAPI CRYPT_FormatUnicodeString(DWORD dwCertEncodingType,
02477  DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
02478  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
02479  DWORD *pcbFormat)
02480 {
02481     CERT_NAME_VALUE *value;
02482     DWORD size;
02483     BOOL ret;
02484 
02485     if (!cbEncoded)
02486     {
02487         SetLastError(E_INVALIDARG);
02488         return FALSE;
02489     }
02490     if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_UNICODE_ANY_STRING,
02491      pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &value, &size)))
02492     {
02493         if (!pbFormat)
02494             *pcbFormat = value->Value.cbData;
02495         else if (*pcbFormat < value->Value.cbData)
02496         {
02497             *pcbFormat = value->Value.cbData;
02498             SetLastError(ERROR_MORE_DATA);
02499             ret = FALSE;
02500         }
02501         else
02502         {
02503             LPWSTR str = pbFormat;
02504 
02505             *pcbFormat = value->Value.cbData;
02506             strcpyW(str, (LPWSTR)value->Value.pbData);
02507         }
02508     }
02509     return ret;
02510 }
02511 
02512 typedef BOOL (WINAPI *CryptFormatObjectFunc)(DWORD, DWORD, DWORD, void *,
02513  LPCSTR, const BYTE *, DWORD, void *, DWORD *);
02514 
02515 static CryptFormatObjectFunc CRYPT_GetBuiltinFormatFunction(DWORD encodingType,
02516  DWORD formatStrType, LPCSTR lpszStructType)
02517 {
02518     CryptFormatObjectFunc format = NULL;
02519 
02520     if ((encodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING)
02521     {
02522         SetLastError(ERROR_FILE_NOT_FOUND);
02523         return NULL;
02524     }
02525     if (IS_INTOID(lpszStructType))
02526     {
02527         switch (LOWORD(lpszStructType))
02528         {
02529         case LOWORD(X509_KEY_USAGE):
02530             format = CRYPT_FormatKeyUsage;
02531             break;
02532         case LOWORD(X509_ALTERNATE_NAME):
02533             format = CRYPT_FormatAltName;
02534             break;
02535         case LOWORD(X509_BASIC_CONSTRAINTS2):
02536             format = CRYPT_FormatBasicConstraints2;
02537             break;
02538         case LOWORD(X509_AUTHORITY_KEY_ID2):
02539             format = CRYPT_FormatAuthorityKeyId2;
02540             break;
02541         case LOWORD(X509_AUTHORITY_INFO_ACCESS):
02542             format = CRYPT_FormatAuthorityInfoAccess;
02543             break;
02544         case LOWORD(X509_CRL_DIST_POINTS):
02545             format = CRYPT_FormatCRLDistPoints;
02546             break;
02547         case LOWORD(X509_ENHANCED_KEY_USAGE):
02548             format = CRYPT_FormatEnhancedKeyUsage;
02549             break;
02550         case LOWORD(SPC_FINANCIAL_CRITERIA_STRUCT):
02551             format = CRYPT_FormatSpcFinancialCriteria;
02552             break;
02553         }
02554     }
02555     else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
02556         format = CRYPT_FormatAltName;
02557     else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
02558         format = CRYPT_FormatAltName;
02559     else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
02560         format = CRYPT_FormatKeyUsage;
02561     else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
02562         format = CRYPT_FormatAltName;
02563     else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
02564         format = CRYPT_FormatAltName;
02565     else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
02566         format = CRYPT_FormatBasicConstraints2;
02567     else if (!strcmp(lpszStructType, szOID_AUTHORITY_INFO_ACCESS))
02568         format = CRYPT_FormatAuthorityInfoAccess;
02569     else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER2))
02570         format = CRYPT_FormatAuthorityKeyId2;
02571     else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS))
02572         format = CRYPT_FormatCRLDistPoints;
02573     else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE))
02574         format = CRYPT_FormatEnhancedKeyUsage;
02575     else if (!strcmp(lpszStructType, szOID_NETSCAPE_CERT_TYPE))
02576         format = CRYPT_FormatNetscapeCertType;
02577     else if (!strcmp(lpszStructType, szOID_NETSCAPE_BASE_URL) ||
02578      !strcmp(lpszStructType, szOID_NETSCAPE_REVOCATION_URL) ||
02579      !strcmp(lpszStructType, szOID_NETSCAPE_CA_REVOCATION_URL) ||
02580      !strcmp(lpszStructType, szOID_NETSCAPE_CERT_RENEWAL_URL) ||
02581      !strcmp(lpszStructType, szOID_NETSCAPE_CA_POLICY_URL) ||
02582      !strcmp(lpszStructType, szOID_NETSCAPE_SSL_SERVER_NAME) ||
02583      !strcmp(lpszStructType, szOID_NETSCAPE_COMMENT))
02584         format = CRYPT_FormatUnicodeString;
02585     else if (!strcmp(lpszStructType, SPC_FINANCIAL_CRITERIA_OBJID))
02586         format = CRYPT_FormatSpcFinancialCriteria;
02587     return format;
02588 }
02589 
02590 BOOL WINAPI CryptFormatObject(DWORD dwCertEncodingType, DWORD dwFormatType,
02591  DWORD dwFormatStrType, void *pFormatStruct, LPCSTR lpszStructType,
02592  const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, DWORD *pcbFormat)
02593 {
02594     CryptFormatObjectFunc format = NULL;
02595     HCRYPTOIDFUNCADDR hFunc = NULL;
02596     BOOL ret = FALSE;
02597 
02598     TRACE("(%08x, %d, %08x, %p, %s, %p, %d, %p, %p)\n", dwCertEncodingType,
02599      dwFormatType, dwFormatStrType, pFormatStruct, debugstr_a(lpszStructType),
02600      pbEncoded, cbEncoded, pbFormat, pcbFormat);
02601 
02602     if (!(format = CRYPT_GetBuiltinFormatFunction(dwCertEncodingType,
02603      dwFormatStrType, lpszStructType)))
02604     {
02605         static HCRYPTOIDFUNCSET set = NULL;
02606 
02607         if (!set)
02608             set = CryptInitOIDFunctionSet(CRYPT_OID_FORMAT_OBJECT_FUNC, 0);
02609         CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
02610          (void **)&format, &hFunc);
02611     }
02612     if (!format && (dwCertEncodingType & CERT_ENCODING_TYPE_MASK) ==
02613      X509_ASN_ENCODING && !(dwFormatStrType & CRYPT_FORMAT_STR_NO_HEX))
02614         format = CRYPT_FormatHexString;
02615     if (format)
02616         ret = format(dwCertEncodingType, dwFormatType, dwFormatStrType,
02617          pFormatStruct, lpszStructType, pbEncoded, cbEncoded, pbFormat,
02618          pcbFormat);
02619     if (hFunc)
02620         CryptFreeOIDFunctionAddress(hFunc, 0);
02621     return ret;
02622 }

Generated on Mon May 28 2012 04:22:56 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.