]> git.sur5r.net Git - openldap/blobdiff - libraries/liblutil/entropy.c
Fix ldaps / TLS processing...
[openldap] / libraries / liblutil / entropy.c
index dc33f7cfc4344ae30fd7e24623e40c3ff124e18c..6b7c6c9552f50c036185ed62607fd551672a0f60 100644 (file)
@@ -6,17 +6,35 @@
 
 #include "portable.h"
 
+#include <ac/string.h>
+#include <ac/time.h>
+
+#ifdef HAVE_WINCRYPT_H
+#include <wincrypt.h>
+#endif
+#ifdef HAVE_PROCESS_H
+#include <process.h>
+#endif
+
 #include <fcntl.h>
 
 #include <lutil.h>
+#include <lutil_md5.h>
 
 /*
  * lutil_entropy() provides nbytes of entropy in buf.
  * Quality offerred is suitable for one-time uses, such as "once" keys.
+ * Values may not be suitable for multi-time uses.
+ *
+ * Note:  Callers are encouraged to provide additional bytes of
+ * of entropy in the buf argument.  This information is used in
+ * fallback mode to improve the quality of bytes returned.
+ *
+ * This routinue should be extended to support additional sources
+ * of entropy.
  */
-int lutil_entropy( char *buf, int nbytes )
+int lutil_entropy( char *buf, ber_len_t nbytes )
 {
-       if( nbytes < 0 ) return -1;
        if( nbytes == 0 ) return 0;
 
 #ifdef URANDOM_DEVICE
@@ -34,6 +52,98 @@ int lutil_entropy( char *buf, int nbytes )
                /* should return nbytes */
                if( rc < nbytes ) return -1;
 
+               return 0;
+       }
+#elif PROV_RSA_FULL
+       {
+               /* Not used since _WIN32_WINNT not set... */
+               HCRYPTPROV hProv = 0;
+
+               /* Get handle to user default provider */
+               if(!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0)) {
+                  return -1;
+               }
+
+               /* Generate random initialization vector */
+               if(!CryptGenRandom(hProv, (DWORD) nbytes, (BYTE *) buf)) {
+                  return -1;
+               }
+
+               /* Release provider handle */
+               if(hProv != 0) CryptReleaseContext(hProv, 0);
+
+               return 0;
+       }
+#else
+       {
+               /* based upon Phil Karn's "practical randomness" idea
+                * but implementation 100% OpenLDAP.  So don't blame Phil.
+                *
+                * Worse case is that this is a MD5 hash of a counter, if
+                * MD5 is a strong cryptographic hash, this should be fairly
+                * resistant to attack
+                */
+
+               /*
+                * the caller may need to provide external synchronization OR
+                * provide entropy (in buf) to ensure quality results as
+                * access to this counter may not be atomic.
+                */
+               static int counter = 0;
+               ber_len_t n;
+
+               struct rdata_s {
+                       int counter;
+
+                       char *buf;
+                       struct rdata_s *stack;
+
+                       pid_t   pid;
+
+#ifdef HAVE_GETTIMEOFDAY
+                       struct timeval tv;
+#else
+                       time_t  time;
+#endif
+
+                       unsigned long   junk;   /* purposely not initialized */
+               } rdata;
+
+               /* make sure rdata differs for each process */
+               rdata.pid = getpid();
+
+               /* make sure rdata differs for each program */
+               rdata.buf = buf;
+               rdata.stack = &rdata;
+
+               for( n = 0; n < nbytes; n += 16 ) {
+                       struct lutil_MD5Context ctx;
+                       char digest[16];
+
+                       /* poor resolution */
+#ifdef HAVE_GETTIMEOFDAY
+                       (void) gettimeofday( &rdata.tv, NULL );
+#else
+                       (void) time( &rdata.time );
+#endif
+
+                       /* make sure rdata differs */
+                       rdata.counter = ++counter;
+                       rdata.pid++;
+                       rdata.junk++;
+
+                       lutil_MD5Init( &ctx );
+                       lutil_MD5Update( &ctx, (char *) &rdata, sizeof( rdata ) );
+
+                       /* allow caller to provided additional entropy */
+                       lutil_MD5Update( &ctx, (char *) &buf, nbytes );
+
+                       lutil_MD5Final( digest, &ctx );
+
+                       memcpy( &buf[n], digest,
+                               nbytes - n >= 16 ? 16 : nbytes - n );
+               }
+
                return 0;
        }
 #endif