Sync to Wine-0_9_4:
[reactos.git] / reactos / lib / crypt32 / cert.c
index 744f9c3..4f822d1 100644 (file)
@@ -1,6 +1,5 @@
 /*
- * Copyright 2002
- Mike McCormack for CodeWeavers
+ * Copyright 2002 Mike McCormack for CodeWeavers
  * Copyright 2004,2005 Juan Lang
  *
  * This library is free software; you can redistribute it and/or
  *   registering and enumerating physical stores and locations.)
  * - Many flags, options and whatnot are unimplemented.
  */
-
-#include "precomp.h"
+#include <assert.h>
+#include <stdarg.h>
+#include "windef.h"
+#include "winbase.h"
+#include "winnls.h"
+#include "winreg.h"
+#include "winuser.h"
+#include "wincrypt.h"
+#include "wine/debug.h"
+#include "wine/list.h"
+#include "excpt.h"
+#include "wine/exception.h"
+#include "crypt32_private.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
 
@@ -303,14 +313,6 @@ static BOOL WINAPI CRYPT_SetCertificateContextProperty(
 static const void * WINAPI CRYPT_ReadSerializedElement(const BYTE *pbElement,
  DWORD cbElement, DWORD dwContextTypeFlags, DWORD *pdwContentType);
 
-/* filter for page-fault exceptions */
-static WINE_EXCEPTION_FILTER(page_fault)
-{
-    if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
-        return EXCEPTION_EXECUTE_HANDLER;
-    return EXCEPTION_CONTINUE_SEARCH;
-}
-
 static void CRYPT_InitStore(WINECRYPT_CERTSTORE *store, HCRYPTPROV hCryptProv,
  DWORD dwFlags, CertStoreType type)
 {
@@ -337,6 +339,7 @@ static void CRYPT_InitCertRef(PWINE_CERT_CONTEXT_REF ref,
     memcpy(&ref->cert, context, sizeof(ref->cert));
     ref->context = context;
     InterlockedIncrement(&context->ref);
+    TRACE("%p's ref count is %ld\n", context, context->ref);
     ref->cert.hCertStore = store;
 }
 
@@ -346,6 +349,7 @@ static PWINE_CERT_CONTEXT_REF CRYPT_CreateCertRef(PWINE_CERT_CONTEXT context,
     PWINE_CERT_CONTEXT_REF pCertRef = CryptMemAlloc(
      sizeof(WINE_CERT_CONTEXT_REF));
 
+    TRACE("(%p, %p)\n", context, store);
     if (pCertRef)
         CRYPT_InitCertRef(pCertRef, context, store);
     return pCertRef;
@@ -451,6 +455,7 @@ static BOOL WINAPI CRYPT_MemAddCert(HCERTSTORE store, PCCERT_CONTEXT pCert,
     }
     else
         ret = FALSE;
+    TRACE("returning %d\n", ret);
     return ret;
 }
 
@@ -473,9 +478,12 @@ static PWINE_CERT_CONTEXT_REF CRYPT_MemEnumCert(PWINECRYPT_CERTSTORE store,
     if (listNext)
     {
         ret = CryptMemAlloc(sizeof(WINE_CERT_LIST_ENTRY));
-        memcpy(ret, LIST_ENTRY(listNext, WINE_CERT_LIST_ENTRY, entry),
-         sizeof(WINE_CERT_LIST_ENTRY));
-        InterlockedIncrement(&ret->cert.context->ref);
+        if (ret)
+        {
+            memcpy(ret, LIST_ENTRY(listNext, WINE_CERT_LIST_ENTRY, entry),
+             sizeof(WINE_CERT_LIST_ENTRY));
+            InterlockedIncrement(&ret->cert.context->ref);
+        }
     }
     else
     {
@@ -488,13 +496,15 @@ static PWINE_CERT_CONTEXT_REF CRYPT_MemEnumCert(PWINECRYPT_CERTSTORE store,
     return (PWINE_CERT_CONTEXT_REF)ret;
 }
 
+static void CRYPT_UnrefCertificateContext(PWINE_CERT_CONTEXT_REF ref);
+
 static BOOL WINAPI CRYPT_MemDeleteCert(HCERTSTORE hCertStore,
  PCCERT_CONTEXT pCertContext, DWORD dwFlags)
 {
     WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore;
     WINE_CERT_CONTEXT_REF *ref = (WINE_CERT_CONTEXT_REF *)pCertContext;
     PWINE_CERT_LIST_ENTRY cert, next;
-    BOOL ret;
+    BOOL ret = TRUE;
 
     /* Find the entry associated with the passed-in context, since the
      * passed-in context may not be a list entry itself (e.g. if it came from
@@ -512,11 +522,16 @@ static BOOL WINAPI CRYPT_MemDeleteCert(HCERTSTORE hCertStore,
              * protected.
              */
             list_remove(&cert->entry);
+            /* FIXME: generally I should do the following, otherwise there is
+             * a memory leak.  But doing so when called by
+             * CertDeleteCertificateFromStore results in a double free, so
+             * leaving commented for now.
+            ret = CertFreeCertificateContext((PCCERT_CONTEXT)cert);
+             */
             cert->entry.prev = cert->entry.next = &store->certs;
             break;
         }
     }
-    ret = TRUE;
     LeaveCriticalSection(&store->cs);
     return ret;
 }
@@ -652,73 +667,41 @@ static PWINE_COLLECTION_CERT_CONTEXT CRYPT_CollectionAdvanceEnum(
 {
     PWINE_COLLECTION_CERT_CONTEXT ret;
     PWINE_CERT_CONTEXT_REF child;
+    struct list *storeNext = list_next(&store->stores, &storeEntry->entry);
 
     TRACE("(%p, %p, %p)\n", store, storeEntry, pPrev);
 
+    child = storeEntry->store->enumCert((HCERTSTORE)storeEntry->store,
+     pPrev ? pPrev->childContext : NULL);
     if (pPrev)
     {
-        child = storeEntry->store->enumCert((HCERTSTORE)storeEntry->store,
-         pPrev->childContext);
-        if (child)
+        pPrev->childContext = NULL;
+        CertFreeCertificateContext((PCCERT_CONTEXT)pPrev);
+        pPrev = NULL;
+    }
+    if (child)
+    {
+        ret = (PWINE_COLLECTION_CERT_CONTEXT)CRYPT_CollectionCreateCertRef(
+         child->context, store);
+        if (ret)
         {
-            ret = pPrev;
-            memcpy(&ret->cert, child, sizeof(WINE_CERT_CONTEXT_REF));
-            ret->cert.cert.hCertStore = (HCERTSTORE)store;
-            InterlockedIncrement(&ret->cert.context->ref);
+            ret->entry = storeEntry;
             ret->childContext = child;
         }
         else
-        {
-            struct list *storeNext = list_next(&store->stores,
-             &storeEntry->entry);
-
-            pPrev->childContext = NULL;
-            CertFreeCertificateContext((PCCERT_CONTEXT)pPrev);
-            if (storeNext)
-            {
-                storeEntry = LIST_ENTRY(storeNext, WINE_STORE_LIST_ENTRY,
-                 entry);
-                ret = CRYPT_CollectionAdvanceEnum(store, storeEntry, NULL);
-            }
-            else
-            {
-                SetLastError(CRYPT_E_NOT_FOUND);
-                ret = NULL;
-            }
-        }
+            CertFreeCertificateContext((PCCERT_CONTEXT)child);
     }
     else
     {
-        child = storeEntry->store->enumCert((HCERTSTORE)storeEntry->store,
-         NULL);
-        if (child)
+        if (storeNext)
         {
-            ret = (PWINE_COLLECTION_CERT_CONTEXT)CRYPT_CollectionCreateCertRef(
-             child->context, store);
-            if (ret)
-            {
-                ret->entry = storeEntry;
-                ret->childContext = child;
-            }
-            else
-                CertFreeCertificateContext((PCCERT_CONTEXT)child);
+            storeEntry = LIST_ENTRY(storeNext, WINE_STORE_LIST_ENTRY, entry);
+            ret = CRYPT_CollectionAdvanceEnum(store, storeEntry, NULL);
         }
         else
         {
-            struct list *storeNext = list_next(&store->stores,
-             &storeEntry->entry);
-
-            if (storeNext)
-            {
-                storeEntry = LIST_ENTRY(storeNext, WINE_STORE_LIST_ENTRY,
-                 entry);
-                ret = CRYPT_CollectionAdvanceEnum(store, storeEntry, NULL);
-            }
-            else
-            {
-                SetLastError(CRYPT_E_NOT_FOUND);
-                ret = NULL;
-            }
+            SetLastError(CRYPT_E_NOT_FOUND);
+            ret = NULL;
         }
     }
     TRACE("returning %p\n", ret);
@@ -913,11 +896,9 @@ static void CRYPT_RegReadSerializedFromReg(PWINE_REGSTORE store, HKEY key,
                                          CERT_STORE_ADD_REPLACE_EXISTING, NULL);
                                     }
                                     else
-                                    {
                                         TRACE("hash doesn't match, ignoring\n");
-                                        contextInterface->free(context);
-                                    }
                                 }
+                                contextInterface->free(context);
                             }
                         }
                     }
@@ -1129,8 +1110,7 @@ static BOOL WINAPI CRYPT_RegAddCert(HCERTSTORE hCertStore, PCCERT_CONTEXT cert,
 static PWINE_CERT_CONTEXT_REF CRYPT_RegCreateCertRef(
  PWINE_CERT_CONTEXT context, HCERTSTORE store)
 {
-    PWINE_REG_CERT_CONTEXT ret = CryptMemAlloc(
-     sizeof(WINE_REG_CERT_CONTEXT));
+    PWINE_REG_CERT_CONTEXT ret = CryptMemAlloc(sizeof(WINE_REG_CERT_CONTEXT));
 
     if (ret)
     {
@@ -1149,33 +1129,22 @@ static PWINE_CERT_CONTEXT_REF CRYPT_RegEnumCert(PWINECRYPT_CERTSTORE store,
 
     TRACE("(%p, %p)\n", store, pPrev);
 
-    if (pPrev)
+    child = rs->memStore->enumCert(rs->memStore, prev ? prev->childContext
+     : NULL);
+    if (prev)
     {
-        child = rs->memStore->enumCert(rs->memStore, prev->childContext);
-        if (child)
-        {
-            ret = (PWINE_REG_CERT_CONTEXT)pPrev;
-            memcpy(&ret->cert, child, sizeof(WINE_CERT_CONTEXT_REF));
-            ret->cert.cert.hCertStore = (HCERTSTORE)store;
-            ret->childContext = child;
-        }
+        prev->childContext = NULL;
+        CertFreeCertificateContext((PCCERT_CONTEXT)prev);
+        prev = NULL;
     }
-    else
+    if (child)
     {
-        child = rs->memStore->enumCert(rs->memStore, NULL);
-        if (child)
-        {
-            ret = CryptMemAlloc(sizeof(WINE_REG_CERT_CONTEXT));
-
-            if (ret)
-            {
-                memcpy(&ret->cert, child, sizeof(WINE_CERT_CONTEXT_REF));
-                ret->cert.cert.hCertStore = (HCERTSTORE)store;
-                ret->childContext = child;
-            }
-            else
-                CertFreeCertificateContext((PCCERT_CONTEXT)child);
-        }
+        ret = (PWINE_REG_CERT_CONTEXT)CRYPT_RegCreateCertRef(child->context,
+         store);
+        if (ret)
+            ret->childContext = child;
+        else
+            CertFreeCertificateContext((PCCERT_CONTEXT)child);
     }
     return (PWINE_CERT_CONTEXT_REF)ret;
 }
@@ -1908,6 +1877,22 @@ DWORD WINAPI CertEnumCertificateContextProperties(PCCERT_CONTEXT pCertContext,
     return ret;
 }
 
+static BOOL CRYPT_GetCertHashProp(PWINE_CERT_CONTEXT context, DWORD dwPropId,
+ ALG_ID algID, const BYTE *toHash, DWORD toHashLen, void *pvData,
+ DWORD *pcbData)
+{
+    BOOL ret = CryptHashCertificate(0, algID, 0, toHash, toHashLen, pvData,
+     pcbData);
+    if (ret)
+    {
+        CRYPT_DATA_BLOB blob = { *pcbData, pvData };
+
+        ret = CRYPT_SetCertificateContextProperty(context, dwPropId,
+         0, &blob);
+    }
+    return ret;
+}
+
 static BOOL WINAPI CRYPT_GetCertificateContextProperty(
  PWINE_CERT_CONTEXT context, DWORD dwPropId, void *pvData, DWORD *pcbData)
 {
@@ -1950,26 +1935,34 @@ static BOOL WINAPI CRYPT_GetCertificateContextProperty(
         switch (dwPropId)
         {
         case CERT_SHA1_HASH_PROP_ID:
-            ret = CryptHashCertificate(0, CALG_SHA1, 0,
+            ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_SHA1,
              context->cert.pbCertEncoded, context->cert.cbCertEncoded, pvData,
              pcbData);
-            if (ret)
-            {
-                CRYPT_DATA_BLOB blob = { *pcbData, pvData };
-
-                ret = CRYPT_SetCertificateContextProperty(context, dwPropId,
-                 0, &blob);
-            }
             break;
-        case CERT_KEY_PROV_INFO_PROP_ID:
         case CERT_MD5_HASH_PROP_ID:
-        case CERT_SIGNATURE_HASH_PROP_ID:
-        case CERT_KEY_IDENTIFIER_PROP_ID:
+            ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_MD5,
+             context->cert.pbCertEncoded, context->cert.cbCertEncoded, pvData,
+             pcbData);
+            break;
+        case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
+            ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_MD5,
+             context->cert.pCertInfo->Subject.pbData,
+             context->cert.pCertInfo->Subject.cbData,
+             pvData, pcbData);
+            break;
         case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
+            ret = CRYPT_GetCertHashProp(context, dwPropId, CALG_MD5,
+             context->cert.pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
+             context->cert.pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData,
+             pvData, pcbData);
+            break;
+        case CERT_SIGNATURE_HASH_PROP_ID:
         case CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID:
-        case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
             FIXME("implicit property %ld\n", dwPropId);
+            SetLastError(CRYPT_E_NOT_FOUND);
             break;
+        default:
+            SetLastError(CRYPT_E_NOT_FOUND);
         }
     }
     LeaveCriticalSection(&context->cs);
@@ -2131,6 +2124,7 @@ static BOOL WINAPI CRYPT_SetCertificateContextProperty(
         case CERT_PVK_FILE_PROP_ID:
         case CERT_SIGNATURE_HASH_PROP_ID:
         case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
+        case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
         case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
         case CERT_ENROLLMENT_PROP_ID:
         case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
@@ -2339,7 +2333,8 @@ BOOL WINAPI CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext)
         else
         {
             ret = hcs->deleteCert(hcs, pCertContext, 0);
-            CertFreeCertificateContext(pCertContext);
+            if (ret)
+                CertFreeCertificateContext(pCertContext);
         }
     }
     return ret;
@@ -2809,7 +2804,7 @@ static const void * WINAPI CRYPT_ReadSerializedElement(const BYTE *pbElement,
             }
         }
     }
-    _SEH_EXCEPT(page_fault)
+    __EXCEPT_PAGE_FAULT
     {
         SetLastError(STATUS_ACCESS_VIOLATION);
         context = NULL;
@@ -2874,6 +2869,17 @@ BOOL WINAPI CertAddSerializedElementToStore(HCERTSTORE hCertStore,
     return ret;
 }
 
+static void CRYPT_UnrefCertificateContext(PWINE_CERT_CONTEXT_REF ref)
+{
+    if (InterlockedDecrement(&ref->context->ref) == 0)
+    {
+        TRACE("%p's ref count is 0, freeing\n", ref->context);
+        CRYPT_FreeCert(ref->context);
+    }
+    else
+        TRACE("%p's ref count is %ld\n", ref->context, ref->context->ref);
+}
+
 BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext)
 {
     TRACE("(%p)\n", pCertContext);
@@ -2883,16 +2889,11 @@ BOOL WINAPI CertFreeCertificateContext(PCCERT_CONTEXT pCertContext)
         PWINE_CERT_CONTEXT_REF ref = (PWINE_CERT_CONTEXT_REF)pCertContext;
         PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)ref->cert.hCertStore;
 
-        if (InterlockedDecrement(&ref->context->ref) == 0)
-        {
-            TRACE("%p's ref count is 0, freeing\n", ref->context);
-            CRYPT_FreeCert(ref->context);
-        }
-        else
-            TRACE("%p's ref count is %ld\n", ref->context, ref->context->ref);
+        CRYPT_UnrefCertificateContext(ref);
         if (store && store->dwMagic == WINE_CRYPTCERTSTORE_MAGIC &&
          store->freeCert)
             store->freeCert(ref);
+        TRACE("freeing %p\n", ref);
         CryptMemFree(ref);
     }
     return TRUE;
@@ -3301,15 +3302,12 @@ BOOL WINAPI CryptVerifyCertificateSignatureEx(HCRYPTPROV hCryptProv,
     return ret;
 }
 
-HCRYPTOIDFUNCSET WINAPI CryptInitOIDFunctionSet(LPCSTR pszFuncName, DWORD dwFlags)
-{
-    FIXME("stub: %s %lx\n", debugstr_a(pszFuncName), dwFlags);
-    return NULL;
-}
-
-BOOL WINAPI CryptUnregisterDefaultOIDFunction(DWORD dwEncodingType,
-                                              LPCSTR pszFuncName, LPCWSTR pwszDll)
+BOOL WINAPI CryptVerifyMessageSignature(/*PCRYPT_VERIFY_MESSAGE_PARA*/ void* pVerifyPara,
+          DWORD dwSignerIndex, const BYTE* pbSignedBlob, DWORD cbSignedBlob,
+          BYTE* pbDecoded, DWORD* pcbDecoded, PCCERT_CONTEXT* ppSignerCert)
 {
-    FIXME("stub: %lx %s %s\n", dwEncodingType, debugstr_a(pszFuncName), debugstr_w(pwszDll));
+    FIXME("stub: %p, %ld, %p, %ld, %p, %p, %p\n",
+        pVerifyPara, dwSignerIndex, pbSignedBlob, cbSignedBlob,
+        pbDecoded, pcbDecoded, ppSignerCert);
     return FALSE;
 }