|
reSIProcate/rutil
9694
|
00001 #if defined(HAVE_CONFIG_H) 00002 #include "config.h" 00003 #endif 00004 00005 #include <cassert> 00006 #include <stdlib.h> 00007 00008 #ifdef WIN32 00009 #include "rutil/Socket.hxx" 00010 #include "rutil/DataStream.hxx" 00011 #include "rutil/Data.hxx" 00012 #else 00013 #include <unistd.h> 00014 #include <sys/types.h> 00015 #include <sys/stat.h> 00016 #include <fcntl.h> 00017 #endif 00018 00019 #include "rutil/Random.hxx" 00020 #include "rutil/Timer.hxx" 00021 #include "rutil/Mutex.hxx" 00022 #include "rutil/Lock.hxx" 00023 #include "rutil/Logger.hxx" 00024 00025 00026 #ifdef USE_SSL 00027 #ifdef WIN32 00028 //hack for name collision of OCSP_RESPONSE and wincrypt.h in latest openssl release 0.9.8h 00029 //http://www.google.com/search?q=OCSP%5fRESPONSE+wincrypt%2eh 00030 //continue to watch this issue for a real fix. 00031 #undef OCSP_RESPONSE 00032 #endif 00033 #include "rutil/ssl/OpenSSLInit.hxx" 00034 # define USE_OPENSSL 1 00035 #else 00036 # define USE_OPENSSL 0 00037 #endif 00038 00039 #if ( USE_OPENSSL == 1 ) 00040 # include <openssl/e_os2.h> 00041 # include <openssl/rand.h> 00042 # include <openssl/err.h> 00043 #endif 00044 00045 using namespace resip; 00046 #define RESIPROCATE_SUBSYSTEM Subsystem::SIP 00047 00048 Mutex Random::mMutex; 00049 bool Random::mIsInitialized = false; 00050 00051 #ifdef WIN32 00052 Random::Initializer Random::mInitializer; 00053 #ifdef RESIP_RANDOM_WIN32_RTL 00054 BOOLEAN (APIENTRY *Random::RtlGenRandom)(void*, ULONG) = 0; 00055 #endif 00056 #endif //WIN32 00057 00058 #ifdef RESIP_RANDOM_THREAD_MUTEX 00059 struct random_data* Random::sRandomState = 0; 00060 #endif 00061 00062 #ifdef RESIP_RANDOM_THREAD_LOCAL 00063 ThreadIf::TlsKey Random::sRandomStateKey = 0; 00064 #endif 00065 00066 #define RANDOM_STATE_SIZE 128 00067 00068 const char* 00069 Random::getImplName() 00070 { 00071 #ifdef WIN32 00072 #if defined(RESIP_RANDOM_WIN32_RTL) 00073 return "win32_rtl"; 00074 #else 00075 return "win32_rand"; 00076 #endif 00077 #else // WIN32 00078 #if defined(RESIP_RANDOM_THREAD_LOCAL) 00079 return "posix_thread_local"; 00080 #elif defined(RESIP_RANDOM_THREAD_MUTEX) 00081 return "posix_thread_mutex"; 00082 #else 00083 return "posix_random"; 00084 #endif 00085 #endif // not WIN32 00086 } 00087 00091 unsigned 00092 Random::getSimpleSeed() 00093 { 00094 // !cj! need to find a better way - use pentium random commands? 00095 Data buffer; 00096 { 00097 DataStream strm(buffer); 00098 #ifdef WIN32 00099 strm << GetTickCount() << ":"; 00100 strm << GetCurrentProcessId() << ":"; 00101 strm << GetCurrentThreadId(); 00102 #else 00103 // .kw. previously just used the lower 32bits of getTimeMs() 00104 strm << ResipClock::getTimeMicroSec() << ":"; 00105 strm << getpid(); 00106 #if defined(RESIP_RANDOM_THREAD_LOCAL) 00107 strm << ":" << ThreadIf::selfId(); 00108 #endif 00109 #endif 00110 } 00111 return (unsigned int)buffer.hash(); 00112 } 00113 00114 void 00115 Random::initialize() 00116 { 00117 #ifdef WIN32 00118 //#if defined(USE_SSL) 00119 #if 0 //!dcm! - this shouldn't be per thread for win32, and this is slow. Going 00120 //to re-work openssl initialization 00121 if ( !Random::mIsInitialized) 00122 { 00123 Lock lock(mMutex); 00124 if (!Random::mIsInitialized) 00125 { 00126 mIsInitialized = true; 00127 RAND_screen (); 00128 } 00129 } 00130 #else 00131 if (!Random::mInitializer.isInitialized()) 00132 { 00133 Lock lock(mMutex); 00134 if (!Random::mInitializer.isInitialized()) 00135 { 00136 Random::mInitializer.setInitialized(); 00137 00138 unsigned seed = getSimpleSeed(); 00139 srand(seed); 00140 00141 #ifdef RESIP_RANDOM_WIN32_RTL 00142 // .jjg. from http://blogs.msdn.com/michael_howard/archive/2005/01/14/353379.aspx 00143 // srand(..) and rand() have proven to be insufficient sources of randomness, 00144 // leading to transaction id collisions in resip. 00145 // SystemFunction036 maps to RtlGenRandom, which is used by rand_s() (which is available 00146 // only with the VC 8.0 runtime or later) and is the Microsoft-recommended way of getting 00147 // a random number. This code allows that functionality to be accessed even from VC 7.1. 00148 // However, SystemFunction036 only exists in Windows XP and later, so we may need to fallback 00149 // to the old method using rand(). 00150 HMODULE hLib = LoadLibrary("ADVAPI32.DLL"); 00151 if (hLib) 00152 { 00153 Random::RtlGenRandom = 00154 (BOOLEAN (APIENTRY *)(void*,ULONG))GetProcAddress(hLib,"SystemFunction036"); 00155 00156 if (!Random::RtlGenRandom) 00157 { 00158 WarningLog(<< "Using srand(..) and rand() for random numbers"); 00159 } 00160 } 00161 #endif // RESIP_RANDOM_WIN32_RTL 00162 00163 mIsInitialized = true; 00164 00165 } 00166 } 00167 #endif // not dead code 00168 00169 #else // WIN32 00170 // ?dcm? -- OpenSSL will transparently initialize PRNG if /dev/urandom is 00171 // present. In any case, will move into OpenSSLInit 00172 if ( !Random::mIsInitialized) 00173 { 00174 Lock lock(mMutex); 00175 if (!Random::mIsInitialized) 00176 { 00177 mIsInitialized = true; 00178 Timer::setupTimeOffsets(); 00179 00180 unsigned seed = getSimpleSeed(); 00181 00182 #if defined(RESIP_RANDOM_THREAD_LOCAL) 00183 ThreadIf::tlsKeyCreate(sRandomStateKey, ::free); 00184 #elif defined(RESIP_RANDOM_THREAD_MUTEX) 00185 struct random_data *buf; 00186 size_t sz = sizeof(*buf)+RANDOM_STATE_SIZE; 00187 buf = (struct random_data*) ::malloc(sz); 00188 memset( buf, 0, sz); // .kw. strange segfaults without this 00189 initstate_r(seed, ((char*)buf)+sizeof(*buf), RANDOM_STATE_SIZE, buf); 00190 sRandomState = buf; 00191 #else 00192 srandom(seed); 00193 #endif 00194 00195 00196 int fd = open("/dev/urandom", O_RDONLY); 00197 // !ah! blocks on embedded devices -- not enough entropy. 00198 if ( fd != -1 ) 00199 { 00200 int s = read( fd,&seed,sizeof(seed) ); 00201 00202 if ( s != sizeof(seed) ) 00203 { 00204 ErrLog( << "System is short of randomness" ); // !ah! never prints 00205 } 00206 } 00207 else 00208 { 00209 ErrLog( << "Could not open /dev/urandom" ); 00210 } 00211 00212 #if defined(USE_SSL) 00213 if (fd == -1 ) 00214 { 00215 // really bad sign - /dev/random does not exist so need to intialize 00216 // OpenSSL some other way 00217 00218 // !cj! need to fix assert(0); 00219 } 00220 else 00221 { 00222 char buf[1024/8]; // size is number byes used for OpenSSL init 00223 00224 int s = read( fd,&buf,sizeof(buf) ); 00225 00226 if ( s != sizeof(buf) ) 00227 { 00228 ErrLog( << "System is short of randomness" ); 00229 } 00230 00231 RAND_add(buf,sizeof(buf),double(s*8)); 00232 } 00233 #endif // SSL 00234 if (fd != -1 ) 00235 { 00236 ::close(fd); 00237 } 00238 } 00239 } 00240 #endif // not WIN32 00241 } 00242 00243 int 00244 Random::getRandom() 00245 { 00246 initialize(); 00247 00248 #ifdef WIN32 00249 00250 int ret = 0; 00251 00252 #ifdef RESIP_RANDOM_WIN32_RTL 00253 // see comment in initialize() 00254 if (Random::RtlGenRandom) 00255 { 00256 unsigned long buff[1]; 00257 ULONG ulCbBuff = sizeof(buff); 00258 if (Random::RtlGenRandom(buff,ulCbBuff)) 00259 { 00260 // .kw. all other impls here return positive number, so do the same... 00261 ret = buff[0] & (~(1<<31)); 00262 return ret; 00263 } 00264 } 00265 // fallback to using rand() if this is a Windows version previous to XP 00266 #endif // RESIP_RANDOM_WIN32_RTL 00267 { 00268 // rand() returns [0,RAND_MAX], which on Windows is 15 bits and positive 00269 // code below gets 30bits of randomness; with bit31 and bit15 00270 // always zero; result is always positive 00271 assert( RAND_MAX == 0x7fff ); 00272 // WATCHOUT: on Linux, rand() returns 31bits, and assert above will fail 00273 int r1 = rand(); 00274 int r2 = rand(); 00275 ret = (r1<<16) + r2; 00276 } 00277 00278 return ret; 00279 #else // WIN32 00280 00281 #if defined(RESIP_RANDOM_THREAD_LOCAL) 00282 struct random_data *buf = (struct random_data*) ThreadIf::tlsGetValue(sRandomStateKey); 00283 if ( buf==NULL ) { 00284 size_t sz = sizeof(*buf)+RANDOM_STATE_SIZE; 00285 buf = (struct random_data*) ::malloc(sz); 00286 memset( buf, 0, sz); // .kw. strange segfaults without this 00287 unsigned seed = getSimpleSeed(); 00288 initstate_r(seed, ((char*)buf)+sizeof(*buf), RANDOM_STATE_SIZE, buf); 00289 ThreadIf::tlsSetValue(sRandomStateKey, buf); 00290 } 00291 int32_t ret; 00292 random_r(buf, &ret); 00293 return ret; 00294 #elif defined(RESIP_RANDOM_THREAD_MUTEX) 00295 int32_t ret; 00296 { 00297 Lock statelock(mMutex); 00298 random_r(sRandomState, &ret); 00299 } 00300 return ret; 00301 #else 00302 // random returns [0,RAN_MAX]. On Linux, this is 31 bits and positive. 00303 // On some platforms it might be on 15 bits, and will need to do something. 00304 // assert( RAND_MAX == ((1<<31)-1) ); // ?slg? commented out assert since, RAND_MAX is not used in random(), it applies to rand() only 00305 return random(); 00306 #endif // THREAD_LOCAL 00307 #endif // WIN32 00308 } 00309 00310 int 00311 Random::getCryptoRandom() 00312 { 00313 initialize(); 00314 00315 #if USE_OPENSSL 00316 int ret; 00317 int e = RAND_bytes( (unsigned char*)&ret , sizeof(ret) ); 00318 if ( e < 0 ) 00319 { 00320 // error of some type - likely not enough rendomness to dod this 00321 long err = ERR_get_error(); 00322 00323 char buf[1024]; 00324 ERR_error_string_n(err,buf,sizeof(buf)); 00325 00326 ErrLog( << buf ); 00327 assert(0); 00328 } 00329 return ret; 00330 #else 00331 return getRandom(); 00332 #endif 00333 } 00334 00335 Data 00336 Random::getRandom(unsigned int len) 00337 { 00338 initialize(); 00339 assert(len < Random::maxLength+1); 00340 00341 union 00342 { 00343 char cbuf[Random::maxLength+1]; 00344 unsigned int ibuf[(Random::maxLength+1)/sizeof(int)]; 00345 }; 00346 00347 for (unsigned int count=0; count<(len+sizeof(int)-1)/sizeof(int); ++count) 00348 { 00349 ibuf[count] = Random::getRandom(); 00350 } 00351 return Data(cbuf, len); 00352 } 00353 00354 Data 00355 Random::getCryptoRandom(unsigned int len) 00356 { 00357 unsigned char* buf = new unsigned char[len]; 00358 getCryptoRandom(buf, len); // USE_SSL check is in here 00359 return Data(Data::Take, (char*)buf, len); 00360 } 00361 00362 Data 00363 Random::getRandomHex(unsigned int numBytes) 00364 { 00365 return Random::getRandom(numBytes).hex(); 00366 } 00367 00368 Data 00369 Random::getRandomBase64(unsigned int numBytes) 00370 { 00371 return Random::getRandom(numBytes).base64encode(); 00372 } 00373 00374 Data 00375 Random::getCryptoRandomHex(unsigned int numBytes) 00376 { 00377 return Random::getCryptoRandom(numBytes).hex(); 00378 } 00379 00380 Data 00381 Random::getCryptoRandomBase64(unsigned int numBytes) 00382 { 00383 return Random::getCryptoRandom(numBytes).base64encode(); 00384 } 00385 00386 /* 00387 [From RFC 4122] 00388 00389 The version 4 UUID is meant for generating UUIDs from truly-random or 00390 pseudo-random numbers. 00391 00392 The algorithm is as follows: 00393 00394 o Set the two most significant bits (bits 6 and 7) of the 00395 clock_seq_hi_and_reserved to zero and one, respectively. 00396 00397 o Set the four most significant bits (bits 12 through 15) of the 00398 time_hi_and_version field to the 4-bit version number from 00399 Section 4.1.3. (0 1 0 0) 00400 00401 o Set all the other bits to randomly (or pseudo-randomly) chosen 00402 values. 00403 00404 UUID = time-low "-" time-mid "-" 00405 time-high-and-version "-" 00406 clock-seq-and-reserved 00407 clock-seq-low "-" node 00408 time-low = 4hexOctet 00409 time-mid = 2hexOctet 00410 time-high-and-version = 2hexOctet 00411 clock-seq-and-reserved = hexOctet 00412 clock-seq-low = hexOctet 00413 node = 6hexOctet 00414 hexOctet = hexDigit hexDigit 00415 */ 00416 Data 00417 Random::getVersion4UuidUrn() 00418 { 00419 Data urn ("urn:uuid:"); 00420 urn += getCryptoRandomHex(4); // time-low 00421 urn += "-"; 00422 urn += getCryptoRandomHex(2); // time-mid 00423 urn += "-"; 00424 00425 Data time_hi_and_version = Random::getCryptoRandom(2); 00426 time_hi_and_version[0] &= 0x0f; 00427 time_hi_and_version[0] |= 0x40; 00428 urn += time_hi_and_version.hex(); 00429 00430 urn += "-"; 00431 00432 Data clock_seq_hi_and_reserved = Random::getCryptoRandom(1); 00433 clock_seq_hi_and_reserved[0] &= 0x3f; 00434 clock_seq_hi_and_reserved[0] |= 0x40; 00435 urn += clock_seq_hi_and_reserved.hex(); 00436 00437 urn += getCryptoRandomHex(1); // clock-seq-low 00438 urn += "-"; 00439 urn += getCryptoRandomHex(6); // node 00440 return urn; 00441 } 00442 00443 void 00444 Random::getCryptoRandom(unsigned char* buf, unsigned int numBytes) 00445 { 00446 assert(numBytes < Random::maxLength+1); 00447 00448 #if USE_OPENSSL 00449 initialize(); 00450 int e = RAND_bytes( (unsigned char*)buf , numBytes ); 00451 if ( e < 0 ) 00452 { 00453 // error of some type - likely not enough rendomness to dod this 00454 long err = ERR_get_error(); 00455 00456 char buf[1024]; 00457 ERR_error_string_n(err,buf,sizeof(buf)); 00458 00459 ErrLog( << buf ); 00460 assert(0); 00461 } 00462 #else 00463 // !bwc! Should optimize this. 00464 Data temp=Random::getRandom(numBytes); 00465 memcpy(buf, temp.data(), numBytes); 00466 #endif 00467 } 00468 00469 #ifdef WIN32 00470 Random::Initializer::Initializer() : mThreadStorage(::TlsAlloc()) 00471 { 00472 assert(mThreadStorage != TLS_OUT_OF_INDEXES); 00473 } 00474 00475 Random::Initializer::~Initializer() 00476 { 00477 ::TlsFree(mThreadStorage); 00478 } 00479 00480 void 00481 Random::Initializer::setInitialized() 00482 { 00483 ::TlsSetValue(mThreadStorage, (LPVOID) TRUE); 00484 } 00485 00486 bool 00487 Random::Initializer::isInitialized() 00488 { 00489 // Note: if value is not set yet then 0 (false) is returned 00490 return (BOOL) ::TlsGetValue(mThreadStorage) == TRUE; 00491 } 00492 #endif 00493 00494 00495 /* ==================================================================== 00496 * The Vovida Software License, Version 1.0 00497 * 00498 * Copyright (c) 2005. All rights reserved. 00499 * 00500 * Redistribution and use in source and binary forms, with or without 00501 * modification, are permitted provided that the following conditions 00502 * are met: 00503 * 00504 * 1. Redistributions of source code must retain the above copyright 00505 * notice, this list of conditions and the following disclaimer. 00506 * 00507 * 2. Redistributions in binary form must reproduce the above copyright 00508 * notice, this list of conditions and the following disclaimer in 00509 * the documentation and/or other materials provided with the 00510 * distribution. 00511 * 00512 * 3. The names "VOCAL", "Vovida Open Communication Application Library", 00513 * and "Vovida Open Communication Application Library (VOCAL)" must 00514 * not be used to endorse or promote products derived from this 00515 * software without prior written permission. For written 00516 * permission, please contact vocal@vovida.org. 00517 * 00518 * 4. Products derived from this software may not be called "VOCAL", nor 00519 * may "VOCAL" appear in their name, without prior written 00520 * permission of Vovida Networks, Inc. 00521 * 00522 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED 00523 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00524 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND 00525 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA 00526 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES 00527 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, 00528 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00529 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00530 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 00531 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00532 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 00533 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 00534 * DAMAGE. 00535 * 00536 * ==================================================================== 00537 * 00538 * This software consists of voluntary contributions made by Vovida 00539 * Networks, Inc. and many individuals on behalf of Vovida Networks, 00540 * Inc. For more information on Vovida Networks, Inc., please see 00541 * <http://www.vovida.org/>. 00542 * 00543 * vi: set shiftwidth=3 expandtab: 00544 */
1.7.5.1