Hello,
I am sorry for the long post, there is a question at the very end :-)
(I sent it to the the openssl-users group at first, maybe you the
developers are interested rather than users.)
We integrate OpenSSL 0.9.6l compiled with standard settings and linked statically on Win32 and used on Windows XP, 2000 and 2003.
The initialization of OpenSSL used within an extension module for Microsoft Sharepoint 2003 caused very long delays (15 - 30 seconds) during the first call. The method RAND_poll() called from RAND_status() was identified to cause this.
There were more tests performed to ensure the validity of results, here we are typical perfomances of RAND_poll().
Here we are a test result of an unmanaged Win32 executable, of a managed .NET executable and of an extension module for Sharepoint 2003, with the unmodified OpenSSL, only the extended performance logging added (there is number of kernel objects in parentheses and time in milliseconds next to them):
----------+-----------+-------------+----------------------------------
Win32 EXE .NET EXE SPS DLL Source of entropy WITH HEAPS
----------+-----------+-------------+----------------------------------
(N/A) 15 (N/A) 16 (N/A) 0 netapi32.dll (NetStatisticsGet)
(N/A) 63 (N/A) 15 (N/A) 0 advapi32.dll (CryptoAPI)
(256) 16 (471) 297 (1200) 17391 kernel32.dll (Heaps)
(51) 0 (45) 0 (44) 15 kernel32.dll (Processes)
(509) 15 (506) 16 (676) 203 kernel32.dll (Threads)
(13) 0 (45) 0 (169) 47 kernel32.dll (Modules)
----------+-----------+-------------+----------------------------------
140 344 17672 The whole RAND_poll().
----------+-----------+-------------+----------------------------------
The Sharepoint extension can be unloaded if idle, and server reloads it again if needed. Then happens the reinitialization again, which is painful when it is used in a search engine. The first hit is unacceptably slow then.
What happens, when we abandon the heap inspection? What improves in the performance and what we loose in entropy?
Here we are a test result of an unmanaged Win32 executable, of a managed .NET executable and of an extension module for Sharepoint 2003, with a modified OpenSSL, where only the heap walking was removed and the extended performance logging added (there is number of kernel objects in parentheses and time in milliseconds next to them):
----------+-----------+-------------+----------------------------------
Win32 EXE .NET EXE SPS DLL Source of entropy WITHOUT HEAPS
----------+-----------+-------------+----------------------------------
(N/A) 0 (N/A) 0 (N/A) 0 netapi32.dll (NetStatisticsGet)
(N/A) 15 (N/A) 15 (N/A) 31 advapi32.dll (CryptoAPI)
(50) 0 (46) 0 (51) 15 kernel32.dll (Processes)
(504) 16 (510) 16 (722) 203 kernel32.dll (Threads)
(13) 0 (45) 0 (172) 63 kernel32.dll (Modules)
----------+-----------+-------------+----------------------------------
31 31 344 The whole RAND_poll().
----------+-----------+-------------+----------------------------------
The achieved times are acceptable also on a server, where there are many kernel objects in use.
Here we are a comparison, what entropy we achive with the current
RAND_poll() without the heap walking:
----------------------+--------------------+---------------------------
Bytes in buffer Bytes of entropy Source of entropy INCLUDED
----------------------+--------------------+---------------------------
(120 + 68) (45 + 17) netapi32 (NetStatisticsGet
+ NetApiBufferFree,
LanmanWorkstation
+ LanmanServer)
(64 + 64) (64 + 64) advapi32.dll (
+ CryptAcquireContextA
+ CryptGenRandom
+ CryptReleaseContext,
RSA_FULL + INTEL_P5_PRG)
32 1 GlobalMemoryStatus
4 1 GetCurrentProcessId
(4 + 20 + 4) (1 + 2 + 1) user32.dll (
+ GetForegroundWindow
+ GetCursorInfo
+ GetQueueStatus) processes.count * 296 processes.count * 9 kernel32.dll (Processes
+ threads.count * 28 + threads.count * 6 + Threads
+ modules.count * 547 + modules.count * 9 + Modules)
----------------------+--------------------+---------------------------
An example of an achieved entropy in a process in a Windows XP/2003
session: 10 processes, 500 threads, 10 modules:
196 + 40 * 9 + 500 * 6 + 10 * 9 = 3376
-----------------------------------------------------------------------
These bytes of entropy are still bigger than 1024 bytes, which can be considered an adequately secure random seed.
Here we are the entropy, which had added the heap walking:
----------------------+---------------------+--------------------------
Bytes in buffer Bytes of entropy Source of entropy REMOVED
----------------------+---------------------+--------------------------
heaps.count * (16 heaps.count * (3 kernel32.dll (Heaps,
+ entries.count * 36) + entries.count * 5) entries can reach max. 80)
----------------------+---------------------+--------------------------
An example of a lost entropy in a process in a Windows XP/2003 session:
5 heaps, every 100 entries: 5 * (3 + 80 * 5) = 2015
-----------------------------------------------------------------------
The heap walking brings substantial number of bytes of entropy, however in some environments it takes surprisingly more time than the threads walking.
Here we are links into some discussions about this theme:
http://curl.haxx.se/mail/lib-2004-06/0133.html
The change I made removes the heap walking and constraints number of processes/threads/modules to walk through to 256/512/256. It makes a fixed limit for the count of bytes of entropy, namely 7876 bytes (for
256 processes, 512 threads and 256 modules), with a usual value around 3000 instead of 5000, which was achieved with the heap.
Another solution to improve the performance of RAND_poll() would be to count the bytes of entropy after every call to RAND_add() and leave the method when a sufficient amount is acquired (for example 1024 or 2048).
And move the heap walking to the end, of course.
Yet another solution would be to provide a public interface to let the client to setup the limits for different sources of entropy as he finds satisfactory. I found an unnecessary increase of the complexity of the public interface, though.
Do you think that some of the suggested solutions can make its way into the official OpenSSL sources? If you are interested in the change I did I would post it here gladly.
Ferda Prantl
