Add a comment noting the padding oracle.
[openssl.git] / crypto / rand / rand_win.c
index aaea92c8fd00d34e06e166e1145c8646eab6a565..e7cbd052121737bbc6ab8b782cb24ff7e51b6751 100644 (file)
  *
  */
 
+
+
 #include "cryptlib.h"
 #include <openssl/rand.h>
 #include "rand_lcl.h"
 #include <wincrypt.h>
 #include <tlhelp32.h>
 
+/* Limit the time spent walking through the heap, processes, threads and modules to
+   a maximum of 1000 miliseconds each, unless CryptoGenRandom failed */
+#define MAXDELAY 1000
+
 /* Intel hardware RNG CSP -- available from
  * http://developer.intel.com/design/security/rng/redist_license.htm
  */
@@ -152,6 +158,7 @@ typedef struct tagCURSORINFO
 #define CURSOR_SHOWING     0x00000001
 #endif /* CURSOR_SHOWING */
 
+#if !defined(OPENSSL_SYS_WINCE)
 typedef BOOL (WINAPI *CRYPTACQUIRECONTEXTW)(HCRYPTPROV *, LPCWSTR, LPCWSTR,
                                    DWORD, DWORD);
 typedef BOOL (WINAPI *CRYPTGENRANDOM)(HCRYPTPROV, DWORD, BYTE *);
@@ -163,7 +170,7 @@ typedef DWORD (WINAPI *GETQUEUESTATUS)(UINT);
 
 typedef HANDLE (WINAPI *CREATETOOLHELP32SNAPSHOT)(DWORD, DWORD);
 typedef BOOL (WINAPI *CLOSETOOLHELP32SNAPSHOT)(HANDLE);
-typedef BOOL (WINAPI *HEAP32FIRST)(LPHEAPENTRY32, DWORD, DWORD);
+typedef BOOL (WINAPI *HEAP32FIRST)(LPHEAPENTRY32, DWORD, size_t);
 typedef BOOL (WINAPI *HEAP32NEXT)(LPHEAPENTRY32);
 typedef BOOL (WINAPI *HEAP32LIST)(HANDLE, LPHEAPLIST32);
 typedef BOOL (WINAPI *PROCESS32)(HANDLE, LPPROCESSENTRY32);
@@ -171,9 +178,7 @@ typedef BOOL (WINAPI *THREAD32)(HANDLE, LPTHREADENTRY32);
 typedef BOOL (WINAPI *MODULE32)(HANDLE, LPMODULEENTRY32);
 
 #include <lmcons.h>
-#ifndef OPENSSL_SYS_WINCE
 #include <lmstats.h>
-#endif
 #if 1 /* The NET API is Unicode only.  It requires the use of the UNICODE
        * macro.  When UNICODE is defined LPTSTR becomes LPWSTR.  LMSTR was
        * was added to the Platform SDK to allow the NET API to be used in
@@ -184,26 +189,14 @@ typedef NET_API_STATUS (NET_API_FUNCTION * NETSTATGET)
         (LPWSTR, LPWSTR, DWORD, DWORD, LPBYTE*);
 typedef NET_API_STATUS (NET_API_FUNCTION * NETFREE)(LPBYTE);
 #endif /* 1 */
+#endif /* !OPENSSL_SYS_WINCE */
 
 int RAND_poll(void)
 {
        MEMORYSTATUS m;
        HCRYPTPROV hProvider = 0;
-       BYTE buf[64];
        DWORD w;
-       HWND h;
-
-       HMODULE advapi, kernel, user, netapi;
-       CRYPTACQUIRECONTEXTW acquire = 0;
-       CRYPTGENRANDOM gen = 0;
-       CRYPTRELEASECONTEXT release = 0;
-#if 1 /* There was previously a problem with NETSTATGET.  Currently, this
-       * section is still experimental, but if all goes well, this conditional
-       * will be removed
-       */
-       NETSTATGET netstatget = 0;
-       NETFREE netfree = 0;
-#endif /* 1 */
+       int good = 0;
 
        /* Determine the OS version we are on so we can turn off things 
         * that do not work properly.
@@ -212,21 +205,24 @@ int RAND_poll(void)
         osverinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO) ;
         GetVersionEx( &osverinfo ) ;
 
-#if defined(OPENSSL_SYS_WINCE) && WCEPLATFORM!=MS_HPC_PRO
-#ifndef CryptAcquireContext
-#define CryptAcquireContext CryptAcquireContextW
-#endif
+#if defined(OPENSSL_SYS_WINCE)
+# if defined(_WIN32_WCE) && _WIN32_WCE>=300
+/* Even though MSDN says _WIN32_WCE>=210, it doesn't seem to be available
+ * in commonly available implementations prior 300... */
+       {
+       BYTE buf[64];
        /* poll the CryptoAPI PRNG */
        /* The CryptoAPI returns sizeof(buf) bytes of randomness */
-       if (CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
+       if (CryptAcquireContextW(&hProvider, NULL, NULL, PROV_RSA_FULL,
+                               CRYPT_VERIFYCONTEXT))
                {
                if (CryptGenRandom(hProvider, sizeof(buf), buf))
                        RAND_add(buf, sizeof(buf), sizeof(buf));
                CryptReleaseContext(hProvider, 0); 
                }
-#endif
-
-#ifndef OPENSSL_SYS_WINCE
+       }
+# endif
+#else  /* OPENSSL_SYS_WINCE */
        /*
         * None of below libraries are present on Windows CE, which is
         * why we #ifndef the whole section. This also excuses us from
@@ -240,17 +236,19 @@ int RAND_poll(void)
         * implement own shim routine, which would accept ANSI argument
         * and expand it to Unicode.
         */
-
+       {
        /* load functions dynamically - not available on all systems */
-       advapi = LoadLibrary(TEXT("ADVAPI32.DLL"));
-       kernel = LoadLibrary(TEXT("KERNEL32.DLL"));
-       user = LoadLibrary(TEXT("USER32.DLL"));
-       netapi = LoadLibrary(TEXT("NETAPI32.DLL"));
-
-#if 1 /* There was previously a problem with NETSTATGET.  Currently, this
-       * section is still experimental, but if all goes well, this conditional
-       * will be removed
-       */
+       HMODULE advapi = LoadLibrary(TEXT("ADVAPI32.DLL"));
+       HMODULE kernel = LoadLibrary(TEXT("KERNEL32.DLL"));
+       HMODULE user = NULL;
+       HMODULE netapi = LoadLibrary(TEXT("NETAPI32.DLL"));
+       CRYPTACQUIRECONTEXTW acquire = NULL;
+       CRYPTGENRANDOM gen = NULL;
+       CRYPTRELEASECONTEXT release = NULL;
+       NETSTATGET netstatget = NULL;
+       NETFREE netfree = NULL;
+       BYTE buf[64];
+
        if (netapi)
                {
                netstatget = (NETSTATGET) GetProcAddress(netapi,"NetStatisticsGet");
@@ -280,7 +278,6 @@ int RAND_poll(void)
 
        if (netapi)
                FreeLibrary(netapi);
-#endif /* 1 */
 
         /* It appears like this can cause an exception deep within ADVAPI32.DLL
          * at random times on Windows 2000.  Reported by Jeffrey Altman.  
@@ -356,12 +353,13 @@ int RAND_poll(void)
                {
                /* poll the CryptoAPI PRNG */
                 /* The CryptoAPI returns sizeof(buf) bytes of randomness */
-               if (acquire(&hProvider, 0, 0, PROV_RSA_FULL,
+               if (acquire(&hProvider, NULL, NULL, PROV_RSA_FULL,
                        CRYPT_VERIFYCONTEXT))
                        {
                        if (gen(hProvider, sizeof(buf), buf) != 0)
                                {
                                RAND_add(buf, sizeof(buf), 0);
+                               good = 1;
 #if 0
                                printf("randomness from PROV_RSA_FULL\n");
 #endif
@@ -375,6 +373,7 @@ int RAND_poll(void)
                        if (gen(hProvider, sizeof(buf), buf) != 0)
                                {
                                RAND_add(buf, sizeof(buf), sizeof(buf));
+                               good = 1;
 #if 0
                                printf("randomness from PROV_INTEL_SEC\n");
 #endif
@@ -386,7 +385,9 @@ int RAND_poll(void)
         if (advapi)
                FreeLibrary(advapi);
 
-       if (user)
+       if ((osverinfo.dwPlatformId != VER_PLATFORM_WIN32_NT ||
+            !OPENSSL_isservice()) &&
+           (user = LoadLibrary(TEXT("USER32.DLL"))))
                {
                GETCURSORINFO cursor;
                GETFOREGROUNDWINDOW win;
@@ -399,7 +400,7 @@ int RAND_poll(void)
                if (win)
                        {
                        /* window handle */
-                       h = win();
+                       HWND h = win();
                        RAND_add(&h, sizeof(h), 0);
                        }
                if (cursor)
@@ -464,6 +465,7 @@ int RAND_poll(void)
                PROCESSENTRY32 p;
                THREADENTRY32 t;
                MODULEENTRY32 m;
+               DWORD starttime = 0;
 
                snap = (CREATETOOLHELP32SNAPSHOT)
                        GetProcAddress(kernel, "CreateToolhelp32Snapshot");
@@ -494,8 +496,56 @@ int RAND_poll(void)
                          * each entry.  Consider each field a source of 1 byte
                          * of entropy.
                          */
+                       ZeroMemory(&hlist, sizeof(HEAPLIST32));
                        hlist.dwSize = sizeof(HEAPLIST32);              
+                       if (good) starttime = GetTickCount();
+#ifdef _MSC_VER
+                       if (heaplist_first(handle, &hlist))
+                               {
+                               /*
+                                  following discussion on dev ML, exception on WinCE (or other Win
+                                  platform) is theoretically of unknown origin; prevent infinite
+                                  loop here when this theoretical case occurs; otherwise cope with
+                                  the expected (MSDN documented) exception-throwing behaviour of
+                                  Heap32Next() on WinCE.
+
+                                  based on patch in original message by Tanguy Fautré (2009/03/02)
+                                  Subject: RAND_poll() and CreateToolhelp32Snapshot() stability
+                            */
+                               int ex_cnt_limit = 42; 
+                               do
+                                       {
+                                       RAND_add(&hlist, hlist.dwSize, 3);
+                                       __try
+                                               {
+                                               ZeroMemory(&hentry, sizeof(HEAPENTRY32));
+                                       hentry.dwSize = sizeof(HEAPENTRY32);
+                                       if (heap_first(&hentry,
+                                               hlist.th32ProcessID,
+                                               hlist.th32HeapID))
+                                               {
+                                               int entrycnt = 80;
+                                               do
+                                                       RAND_add(&hentry,
+                                                               hentry.dwSize, 5);
+                                               while (heap_next(&hentry)
+                                               && (!good || (GetTickCount()-starttime)<MAXDELAY)
+                                                       && --entrycnt > 0);
+                                               }
+                                               }
+                                       __except (EXCEPTION_EXECUTE_HANDLER)
+                                               {
+                                                       /* ignore access violations when walking the heap list */
+                                                       ex_cnt_limit--;
+                                               }
+                                       } while (heaplist_next(handle, &hlist) 
+                                               && (!good || (GetTickCount()-starttime)<MAXDELAY)
+                                               && ex_cnt_limit > 0);
+                               }
+
+#else
                        if (heaplist_first(handle, &hlist))
+                               {
                                do
                                        {
                                        RAND_add(&hlist, hlist.dwSize, 3);
@@ -511,19 +561,23 @@ int RAND_poll(void)
                                                while (heap_next(&hentry)
                                                        && --entrycnt > 0);
                                                }
-                                       } while (heaplist_next(handle,
-                                               &hlist));
-                       
+                                       } while (heaplist_next(handle, &hlist) 
+                                               && (!good || (GetTickCount()-starttime)<MAXDELAY));
+                               }
+#endif
+
                        /* process walking */
                         /* PROCESSENTRY32 contains 9 fields that will change
                          * with each entry.  Consider each field a source of
                          * 1 byte of entropy.
                          */
                        p.dwSize = sizeof(PROCESSENTRY32);
+               
+                       if (good) starttime = GetTickCount();
                        if (process_first(handle, &p))
                                do
                                        RAND_add(&p, p.dwSize, 9);
-                               while (process_next(handle, &p));
+                               while (process_next(handle, &p) && (!good || (GetTickCount()-starttime)<MAXDELAY));
 
                        /* thread walking */
                         /* THREADENTRY32 contains 6 fields that will change
@@ -531,10 +585,11 @@ int RAND_poll(void)
                          * 1 byte of entropy.
                          */
                        t.dwSize = sizeof(THREADENTRY32);
+                       if (good) starttime = GetTickCount();
                        if (thread_first(handle, &t))
                                do
                                        RAND_add(&t, t.dwSize, 6);
-                               while (thread_next(handle, &t));
+                               while (thread_next(handle, &t) && (!good || (GetTickCount()-starttime)<MAXDELAY));
 
                        /* module walking */
                         /* MODULEENTRY32 contains 9 fields that will change
@@ -542,18 +597,22 @@ int RAND_poll(void)
                          * 1 byte of entropy.
                          */
                        m.dwSize = sizeof(MODULEENTRY32);
+                       if (good) starttime = GetTickCount();
                        if (module_first(handle, &m))
                                do
                                        RAND_add(&m, m.dwSize, 9);
-                               while (module_next(handle, &m));
+                               while (module_next(handle, &m)
+                                               && (!good || (GetTickCount()-starttime)<MAXDELAY));
                        if (close_snap)
                                close_snap(handle);
                        else
                                CloseHandle(handle);
+
                        }
 
                FreeLibrary(kernel);
                }
+       }
 #endif /* !OPENSSL_SYS_WINCE */
 
        /* timer data */
@@ -680,11 +739,9 @@ static void readtimer(void)
 
 static void readscreen(void)
 {
-#ifndef OPENSSL_SYS_WINCE
+#if !defined(OPENSSL_SYS_WINCE) && !defined(OPENSSL_SYS_WIN32_CYGWIN)
   HDC          hScrDC;         /* screen DC */
-  HDC          hMemDC;         /* memory DC */
   HBITMAP      hBitmap;        /* handle for our bitmap */
-  HBITMAP      hOldBitmap;     /* handle for previous bitmap */
   BITMAP       bm;             /* bitmap properties */
   unsigned int size;           /* size of bitmap */
   char         *bmbits;        /* contents of bitmap */
@@ -692,10 +749,13 @@ static void readscreen(void)
   int          h;              /* screen height */
   int          y;              /* y-coordinate of screen lines to grab */
   int          n = 16;         /* number of screen lines to grab at a time */
+  BITMAPINFOHEADER bi;         /* info about the bitmap */
+
+  if (check_winnt() && OPENSSL_isservice()>0)
+    return;
 
-  /* Create a screen DC and a memory DC compatible to screen DC */
-  hScrDC = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
-  hMemDC = CreateCompatibleDC(hScrDC);
+  /* Get a reference to the screen DC */
+  hScrDC = GetDC(NULL);
 
   /* Get screen resolution */
   w = GetDeviceCaps(hScrDC, HORZRES);
@@ -704,13 +764,22 @@ static void readscreen(void)
   /* Create a bitmap compatible with the screen DC */
   hBitmap = CreateCompatibleBitmap(hScrDC, w, n);
 
-  /* Select new bitmap into memory DC */
-  hOldBitmap = SelectObject(hMemDC, hBitmap);
-
   /* Get bitmap properties */
   GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&bm);
   size = (unsigned int)bm.bmWidthBytes * bm.bmHeight * bm.bmPlanes;
 
+  bi.biSize = sizeof(BITMAPINFOHEADER);
+  bi.biWidth = bm.bmWidth;
+  bi.biHeight = bm.bmHeight;
+  bi.biPlanes = bm.bmPlanes;
+  bi.biBitCount = bm.bmBitsPixel;
+  bi.biCompression = BI_RGB;
+  bi.biSizeImage = 0;
+  bi.biXPelsPerMeter = 0;
+  bi.biYPelsPerMeter = 0;
+  bi.biClrUsed = 0;
+  bi.biClrImportant = 0;
+
   bmbits = OPENSSL_malloc(size);
   if (bmbits) {
     /* Now go through the whole screen, repeatedly grabbing n lines */
@@ -718,11 +787,9 @@ static void readscreen(void)
        {
        unsigned char md[MD_DIGEST_LENGTH];
 
-       /* Bitblt screen DC to memory DC */
-       BitBlt(hMemDC, 0, 0, w, n, hScrDC, 0, y, SRCCOPY);
-
-       /* Copy bitmap bits from memory DC to bmbits */
-       GetBitmapBits(hBitmap, size, bmbits);
+       /* Copy the bits of the current line range into the buffer */
+       GetDIBits(hScrDC, hBitmap, y, n,
+                 bmbits, (BITMAPINFO *)&bi, DIB_RGB_COLORS);
 
        /* Get the hash of the bitmap */
        MD(bmbits,size,md);
@@ -734,13 +801,9 @@ static void readscreen(void)
     OPENSSL_free(bmbits);
   }
 
-  /* Select old bitmap back into memory DC */
-  hBitmap = SelectObject(hMemDC, hOldBitmap);
-
   /* Clean up */
   DeleteObject(hBitmap);
-  DeleteDC(hMemDC);
-  DeleteDC(hScrDC);
+  ReleaseDC(NULL, hScrDC);
 #endif /* !OPENSSL_SYS_WINCE */
 }