X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Frand.c;h=1060e6519f0a23861db4e5f9d151ddb21835358e;hb=64e2556130a5220a09a770b85b442d0ff34bcbda;hp=c51c51c3e1861bb5f33617b79395b1169b5aa40b;hpb=9ac72b51b6e74e40f1b91c11fd702c1f56c41b3b;p=mono.git diff --git a/mono/metadata/rand.c b/mono/metadata/rand.c index c51c51c3e18..1060e6519f0 100644 --- a/mono/metadata/rand.c +++ b/mono/metadata/rand.c @@ -1,12 +1,13 @@ /* * rand.c: System.Security.Cryptography.RNGCryptoServiceProvider support * - * Author: + * Authors: * Mark Crichton (crichton@gimp.org) * Patrik Torstensson (p@rxc.se) + * Sebastien Pouliot (sebastien@ximian.com) * - * (C) 2001 Ximian, Inc. - * + * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com) + * Copyright 2004-2009 Novell, Inc (http://www.novell.com) */ #include @@ -14,7 +15,12 @@ #include #include #include +#ifdef HAVE_UNISTD_H #include +#endif +#ifdef HAVE_STRING_H +#include +#endif #include #include @@ -93,41 +99,85 @@ get_entropy_from_server (const char *path, guchar *buf, int len) #if defined (PLATFORM_WIN32) -#include - -static int s_providerInitialized = 0; -static HCRYPTPROV s_provider; - -static HCRYPTPROV GetProvider() -{ - if (s_providerInitialized == 1) - return s_provider; - - if (!CryptAcquireContext (&s_provider, NULL, NULL, PROV_RSA_FULL, 0)) - { - if (GetLastError() != NTE_BAD_KEYSET) - mono_raise_exception (mono_get_exception_execution_engine ("Failed to acquire crypt context")); - - // Generate a new keyset if needed - if (!CryptAcquireContext (&s_provider, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) - mono_raise_exception (mono_get_exception_execution_engine ("Failed to acquire crypt context (new keyset)")); - } - - s_providerInitialized = 1; - - return s_provider; -} - -void ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_InternalGetBytes(MonoObject *self, MonoArray *arry) +#include +#include + +#ifndef PROV_INTEL_SEC +#define PROV_INTEL_SEC 22 +#endif +#ifndef CRYPT_VERIFY_CONTEXT +#define CRYPT_VERIFY_CONTEXT 0xF0000000 +#endif + +MonoBoolean +ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_RngOpen (void) +{ + /* FALSE == Local (instance) handle for randomness */ + return FALSE; +} + +gpointer +ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_RngInitialize (MonoArray *seed) { - guint32 len; - guchar *buf; + HCRYPTPROV provider = 0; + + /* There is no need to create a container for just random data, + so we can use CRYPT_VERIFY_CONTEXT (one call) see: + http://blogs.msdn.com/dangriff/archive/2003/11/19/51709.aspx */ + + /* We first try to use the Intel PIII RNG if drivers are present */ + if (!CryptAcquireContext (&provider, NULL, NULL, PROV_INTEL_SEC, CRYPT_VERIFY_CONTEXT)) { + /* not a PIII or no drivers available, use default RSA CSP */ + if (!CryptAcquireContext (&provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFY_CONTEXT)) { + provider = 0; + /* exception will be thrown in managed code */ + } + } - len = mono_array_length (arry); - buf = mono_array_addr (arry, guchar, 0); + /* seed the CSP with the supplied buffer (if present) */ + if ((provider != 0) && (seed)) { + guint32 len = mono_array_length (seed); + guchar *buf = mono_array_addr (seed, guchar, 0); + /* the call we replace the seed with random - this isn't what is + expected from the class library user */ + guchar *data = g_malloc (len); + if (data) { + memcpy (data, buf, len); + /* add seeding material to the RNG */ + CryptGenRandom (provider, len, data); + /* zeroize and free */ + memset (data, 0, len); + g_free (data); + } + } + + return (gpointer) provider; +} + +gpointer +ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_RngGetBytes (gpointer handle, MonoArray *arry) +{ + HCRYPTPROV provider = (HCRYPTPROV) handle; + guint32 len = mono_array_length (arry); + guchar *buf = mono_array_addr (arry, guchar, 0); + + if (!CryptGenRandom (provider, len, buf)) { + CryptReleaseContext (provider, 0); + /* we may have lost our context with CryptoAPI, but all hope isn't lost yet! */ + provider = (HCRYPTPROV) ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_RngInitialize (NULL); + if (!CryptGenRandom (provider, len, buf)) { + CryptReleaseContext (provider, 0); + provider = 0; + /* exception will be thrown in managed code */ + } + } + return (gpointer) provider; +} - if (0 == CryptGenRandom (GetProvider(), len, buf)) - mono_raise_exception (mono_get_exception_execution_engine ("Failed to generate random bytes from CryptoAPI")); +void +ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_RngClose (gpointer handle) +{ + CryptReleaseContext ((HCRYPTPROV) handle, 0); } #else @@ -136,59 +186,84 @@ void ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_InternalGet #define NAME_DEV_URANDOM "/dev/urandom" #endif -void -ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_InternalGetBytes (MonoObject *self, MonoArray *arry) -{ - guint32 len; - gint file = -1; - gint err; - gint count; - guchar *buf; +static gboolean egd = FALSE; +static gint file = -1; - len = mono_array_length(arry); - buf = mono_array_addr(arry, guchar, 0); +MonoBoolean +ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_RngOpen (void) +{ + if (egd || (file >= 0)) + return TRUE; #if defined (NAME_DEV_URANDOM) - file = open (NAME_DEV_URANDOM, O_RDONLY); + file = open (NAME_DEV_URANDOM, O_RDONLY); #endif #if defined (NAME_DEV_RANDOM) - if (file < 0) - file = open (NAME_DEV_RANDOM, O_RDONLY); + if (file < 0) + file = open (NAME_DEV_RANDOM, O_RDONLY); #endif - if (file < 0) { - const char *socket_path = getenv("MONO_EGD_SOCKET"); + if (file < 0) { + const char *socket_path = g_getenv("MONO_EGD_SOCKET"); + egd = (socket_path != NULL); + } - if (socket_path == NULL) - mono_raise_exception (mono_get_exception_execution_engine ("Failed to open /dev/urandom or /dev/random device, or find egd socket")); + /* TRUE == Global handle for randomness */ + return TRUE; +} - get_entropy_from_server (socket_path, mono_array_addr(arry, guchar, 0), mono_array_length(arry)); - return; - } +gpointer +ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_RngInitialize (MonoArray *seed) +{ + /* if required exception will be thrown in managed code */ + return ((!egd && (file < 0)) ? NULL : GINT_TO_POINTER (file)); +} - /* Read until the buffer is filled. This may block if using NAME_DEV_RANDOM. */ - count = 0; - do { - err = read(file, buf + count, len - count); - count += err; - } while (err >= 0 && count < len); - close(file); - - if (err < 0) { - g_warning("Entropy error! Error in read (%s).", strerror (errno)); - mono_raise_exception (mono_get_exception_execution_engine ("Failed to read a random byte from /dev/urandom or /dev/random device")); - } +gpointer +ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_RngGetBytes (gpointer handle, MonoArray *arry) +{ + gint file = GPOINTER_TO_INT (handle); + guint32 len = mono_array_length (arry); + guchar *buf = mono_array_addr (arry, guchar, 0); -} + if (egd) { + const char *socket_path = g_getenv ("MONO_EGD_SOCKET"); + /* exception will be thrown in managed code */ + if (socket_path == NULL) + return NULL; + get_entropy_from_server (socket_path, mono_array_addr (arry, guchar, 0), mono_array_length (arry)); + return (gpointer) -1; + } else { + /* Read until the buffer is filled. This may block if using NAME_DEV_RANDOM. */ + gint count = 0; + gint err; -#endif /* OS definition */ + do { + err = read (file, buf + count, len - count); + if (err < 0) { + if (errno == EINTR) + continue; + break; + } + count += err; + } while (count < len); + + if (err < 0) { + g_warning("Entropy error! Error in read (%s).", strerror (errno)); + /* exception will be thrown in managed code */ + return NULL; + } + } + + /* We do not support PRNG seeding right now but the class library is this */ + + return handle; +} void -ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_Seed (MonoArray *seed) +ves_icall_System_Security_Cryptography_RNGCryptoServiceProvider_RngClose (gpointer handle) { - /* actually we do not support any PRNG requiring seeding right now but - the class library is ready for such possibility - so this empty - function is needed (e.g. a new or modified runtime) */ } +#endif /* OS definition */