|
reSIProcate/stack
9694
|
00001 #if defined(HAVE_CONFIG_H) 00002 #include "config.h" 00003 #endif 00004 00005 #ifdef USE_SSL 00006 00007 #include "resip/stack/ssl/Security.hxx" 00008 00009 #include <ostream> 00010 #include <fstream> 00011 00012 #include "resip/stack/Contents.hxx" 00013 #include "resip/stack/MultipartSignedContents.hxx" 00014 #include "resip/stack/Pkcs7Contents.hxx" 00015 #include "resip/stack/PlainContents.hxx" 00016 #include "resip/stack/SecurityAttributes.hxx" 00017 #include "resip/stack/Transport.hxx" 00018 #include "resip/stack/SipMessage.hxx" 00019 #include "rutil/BaseException.hxx" 00020 #include "rutil/DataStream.hxx" 00021 #include "rutil/Logger.hxx" 00022 #include "rutil/Random.hxx" 00023 #include "rutil/Socket.hxx" 00024 #include "rutil/Timer.hxx" 00025 #include "rutil/ParseBuffer.hxx" 00026 #include "rutil/FileSystem.hxx" 00027 #include "rutil/WinLeakCheck.hxx" 00028 00029 #include "rutil/ssl/SHA1Stream.hxx" 00030 00031 #if !defined(WIN32) 00032 #include <sys/types.h> 00033 #include <sys/uio.h> 00034 #include <sys/fcntl.h> 00035 #include <unistd.h> 00036 #include <dirent.h> 00037 #endif 00038 00039 #include <sys/types.h> 00040 #include <openssl/e_os2.h> 00041 #include <openssl/evp.h> 00042 #include <openssl/crypto.h> 00043 #include <openssl/err.h> 00044 #include <openssl/pem.h> 00045 #include <openssl/pkcs7.h> 00046 #include <openssl/ossl_typ.h> 00047 #include <openssl/x509.h> 00048 #include <openssl/x509v3.h> 00049 #include <openssl/ssl.h> 00050 00051 using namespace resip; 00052 using namespace std; 00053 00054 #define RESIPROCATE_SUBSYSTEM Subsystem::SIP 00055 00056 static const Data PEM(".pem"); 00057 00058 static const Data rootCert("root_cert_"); 00059 static const Data domainCert("domain_cert_"); 00060 static const Data domainKey("domain_key_"); 00061 static const Data userCert("user_cert_"); 00062 static const Data userKey("user_key_"); 00063 static const Data unknownKey("user_key_"); 00064 00065 static const Data 00066 pemTypePrefixes( Security::PEMType pType ) 00067 { 00068 switch (pType) 00069 { 00070 case Security::RootCert: return rootCert; 00071 case Security::DomainCert: return domainCert; 00072 case Security::DomainPrivateKey: return domainKey; 00073 case Security::UserCert: return userCert; 00074 case Security::UserPrivateKey: return userKey; 00075 default: 00076 { 00077 ErrLog( << "Some unkonw pem type prefix requested" << (int)(pType) ); 00078 assert(0); 00079 } 00080 } 00081 return unknownKey; 00082 } 00083 00084 static Data 00085 readIntoData(const Data& filename) 00086 { 00087 DebugLog( << "Trying to read file " << filename ); 00088 00089 ifstream is; 00090 is.open(filename.c_str(), ios::binary ); 00091 if ( !is.is_open() ) 00092 { 00093 ErrLog( << "Could not open file " << filename << " for read"); 00094 throw BaseSecurity::Exception("Could not read file ", 00095 __FILE__,__LINE__); 00096 } 00097 00098 assert(is.is_open()); 00099 00100 int length = 0; 00101 00102 // get length of file: 00103 #if !defined(__MSL_CPP__) || (__MSL_CPP_ >= 0x00012000) 00104 is.seekg (0, ios::end); 00105 length = (int)is.tellg(); 00106 is.seekg (0, ios::beg); 00107 #else 00108 // this is a work around for a bug in CodeWarrior 9's implementation of seekg. 00109 // http://groups.google.ca/group/comp.sys.mac.programmer.codewarrior/browse_frm/thread/a4279eb75f3bd55a 00110 FILE * tmpFile = fopen(filename.c_str(), "r+b"); 00111 assert(tmpFile != NULL); 00112 fseek(tmpFile, 0, SEEK_END); 00113 length = ftell(tmpFile); 00114 fseek(tmpFile, 0, SEEK_SET); 00115 #endif // __MWERKS__ 00116 00117 // tellg/tell will return -1 if the stream is bad 00118 if (length == -1) 00119 { 00120 ErrLog( << "Could not seek into file " << filename); 00121 throw BaseSecurity::Exception("Could not seek into file ", 00122 __FILE__,__LINE__); 00123 } 00124 00125 // !jf! +1 is a workaround for a bug in Data::c_str() that adds the 0 without 00126 // resizing. 00127 char* buffer = new char [length+1]; 00128 00129 // read data as a block: 00130 is.read (buffer,length); 00131 00132 Data target(Data::Take, buffer, length); 00133 00134 is.close(); 00135 00136 return target; 00137 } 00138 00139 00140 static Data 00141 getAor(const Data& filename, const Security::PEMType &pemType ) 00142 { 00143 const Data& prefix = pemTypePrefixes( pemType ); 00144 return filename.substr(prefix.size(), filename.size() - prefix.size() - PEM.size()); 00145 } 00146 00147 extern "C" 00148 { 00149 00150 static int 00151 verifyCallback(int iInCode, X509_STORE_CTX *pInStore) 00152 { 00153 char cBuf1[500]; 00154 char cBuf2[500]; 00155 X509 *pErrCert; 00156 int iErr = 0; 00157 int iDepth = 0; 00158 pErrCert = X509_STORE_CTX_get_current_cert(pInStore); 00159 iErr = X509_STORE_CTX_get_error(pInStore); 00160 iDepth = X509_STORE_CTX_get_error_depth(pInStore); 00161 00162 if (NULL != pErrCert) 00163 X509_NAME_oneline(X509_get_subject_name(pErrCert),cBuf1,256); 00164 00165 sprintf(cBuf2,", depth=%d %s\n",iDepth,cBuf1); 00166 if(!iInCode) 00167 ErrLog(<< "Error when verifying server's chain of certificates: " << X509_verify_cert_error_string(pInStore->error) << cBuf2 ); 00168 00169 return iInCode; 00170 } 00171 00172 } 00173 00174 // .amr. RFC 5922 mandates exact match only on certificates, so this is the default, but RFC 2459 and RFC 3261 don't prevent wildcards, so enable if you want that mode. 00175 bool BaseSecurity::mAllowWildcardCertificates = false; 00176 BaseSecurity::CipherList BaseSecurity::ExportableSuite("!SSLv2:aRSA+AES:aDSS+AES:@STRENGTH:aRSA+3DES:aDSS+3DES:aRSA+RC4+MEDIUM:aDSS+RC4+MEDIUM:aRSA+DES:aDSS+DES:aRSA+RC4:aDSS+RC4"); 00177 BaseSecurity::CipherList BaseSecurity::StrongestSuite("!SSLv2:aRSA+AES:aDSS+AES:@STRENGTH:aRSA+3DES:aDSS+3DES"); 00178 00179 Security::Security(const CipherList& cipherSuite) : BaseSecurity(cipherSuite) 00180 { 00181 #ifdef WIN32 00182 mPath = "C:\\sipCerts\\"; 00183 #else 00184 const char* env=getenv("HOME"); 00185 if(env) 00186 { 00187 mPath = env; 00188 } 00189 mPath += "/.sipCerts/"; 00190 #endif 00191 } 00192 00193 Security::Security(const Data& directory, const CipherList& cipherSuite) : 00194 BaseSecurity(cipherSuite), 00195 mPath(directory) 00196 { 00197 // since the preloader won't work otherwise and VERY difficult to figure 00198 // out. 00199 if ( !mPath.postfix(Symbols::SLASH)) 00200 { 00201 mPath += Symbols::SLASH; 00202 } 00203 } 00204 00205 void 00206 Security::addCADirectory(const Data& caDirectory) 00207 { 00208 mCADirectories.push_back(caDirectory); 00209 Data &_dir = mCADirectories.back(); 00210 if ( !_dir.postfix(Symbols::SLASH)) 00211 { 00212 _dir += Symbols::SLASH; 00213 } 00214 } 00215 00216 void 00217 Security::addCAFile(const Data& caFile) 00218 { 00219 mCAFiles.push_back(caFile); 00220 } 00221 00222 void 00223 Security::preload() 00224 { 00225 FileSystem::Directory dir(mPath); 00226 FileSystem::Directory::iterator it(dir); 00227 for (; it != dir.end(); ++it) 00228 { 00229 Data name = *it; 00230 00231 if (name.postfix(PEM)) 00232 { 00233 Data fileName = mPath + name; 00234 bool attemptedToLoad = true; 00235 00236 DebugLog(<< "Checking to load file " << name ); 00237 try 00238 { 00239 if (name.prefix(pemTypePrefixes(UserCert))) 00240 { 00241 addCertPEM( UserCert, getAor(name, UserCert), readIntoData(fileName), false ); 00242 } 00243 else if (name.prefix(pemTypePrefixes(UserPrivateKey))) 00244 { 00245 addPrivateKeyPEM( UserPrivateKey, getAor(name, UserPrivateKey), readIntoData(fileName), false); 00246 } 00247 else if (name.prefix(pemTypePrefixes(DomainCert))) 00248 { 00249 addCertPEM( DomainCert, getAor(name, DomainCert), readIntoData(fileName), false); 00250 } 00251 else if (name.prefix(pemTypePrefixes(DomainPrivateKey))) 00252 { 00253 addPrivateKeyPEM( DomainPrivateKey, getAor(name, DomainPrivateKey), readIntoData(fileName), false); 00254 } 00255 else if (name.prefix(pemTypePrefixes(RootCert))) 00256 { 00257 addRootCertPEM(readIntoData(fileName)); 00258 } 00259 else 00260 { 00261 DebugLog(<< "PEM file " << name << " does not have appropriate resip prefix, skipping..."); 00262 attemptedToLoad = false; 00263 } 00264 } 00265 catch (Exception& e) 00266 { 00267 ErrLog(<< "Some problem reading " << fileName << ": " << e); 00268 } 00269 catch (...) 00270 { 00271 ErrLog(<< "Some problem reading " << fileName ); 00272 } 00273 00274 if(attemptedToLoad) 00275 { 00276 InfoLog(<<"Successfully loaded " << fileName ); 00277 } 00278 } 00279 } 00280 std::list<Data>::iterator it_d = mCADirectories.begin(); 00281 for (; it_d != mCADirectories.end(); ++it_d) 00282 { 00283 const Data _dir = *it_d; 00284 FileSystem::Directory dir(_dir); 00285 FileSystem::Directory::iterator it(dir); 00286 for (; it != dir.end(); ++it) 00287 { 00288 Data name = *it; 00289 Data fileName = _dir + name; 00290 addCAFile(fileName); 00291 } 00292 } 00293 std::list<Data>::iterator it_f = mCAFiles.begin(); 00294 for (; it_f != mCAFiles.end(); ++it_f) 00295 { 00296 const Data _file = *it_f; 00297 try 00298 { 00299 addRootCertPEM(readIntoData(_file)); 00300 } 00301 catch (Exception& e) 00302 { 00303 ErrLog(<< "Some problem reading " << _file << ": " << e); 00304 } 00305 catch (...) 00306 { 00307 ErrLog(<< "Some problem reading " << _file); 00308 } 00309 } 00310 } 00311 00312 SSL_CTX* 00313 Security::createDomainCtx(const SSL_METHOD* method, const Data& domain) 00314 { 00315 #if (OPENSSL_VERSION_NUMBER >= 0x1000000fL ) 00316 SSL_CTX* ctx = SSL_CTX_new(method); 00317 #else 00318 SSL_CTX* ctx = SSL_CTX_new((SSL_METHOD*)method); 00319 #endif 00320 assert(ctx); 00321 00322 X509_STORE* x509Store = X509_STORE_new(); 00323 assert(x509Store); 00324 00325 // Load root certs into store 00326 X509List::iterator it; 00327 for(it = mRootCerts.begin(); it != mRootCerts.end(); it++) 00328 { 00329 X509_STORE_add_cert(x509Store,*it); 00330 } 00331 SSL_CTX_set_cert_store(ctx, x509Store); 00332 00333 // Load domain cert chain and private key 00334 if(!domain.empty()) 00335 { 00336 Data certFilename(mPath + pemTypePrefixes(DomainCert) + domain + PEM); 00337 if(SSL_CTX_use_certificate_chain_file(ctx, certFilename.c_str()) != 1) 00338 { 00339 ErrLog (<< "Error reading domain chain file " << certFilename); 00340 SSL_CTX_free(ctx); 00341 throw BaseSecurity::Exception("Failed opening PEM chain file", __FILE__,__LINE__); 00342 } 00343 Data keyFilename(mPath + pemTypePrefixes(DomainPrivateKey) + domain + PEM); 00344 if(SSL_CTX_use_PrivateKey_file(ctx, keyFilename.c_str(), SSL_FILETYPE_PEM) != 1) 00345 { 00346 ErrLog (<< "Error reading domain private key file " << keyFilename); 00347 SSL_CTX_free(ctx); 00348 throw BaseSecurity::Exception("Failed opening PEM private key file", __FILE__,__LINE__); 00349 } 00350 if (!SSL_CTX_check_private_key(ctx)) 00351 { 00352 ErrLog (<< "Invalid domain private key from file: " << keyFilename); 00353 SSL_CTX_free(ctx); 00354 throw BaseSecurity::Exception("Invalid domain private key", __FILE__,__LINE__); 00355 } 00356 } 00357 00358 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, verifyCallback); 00359 SSL_CTX_set_cipher_list(ctx, mCipherList.cipherList().c_str()); 00360 00361 return ctx; 00362 } 00363 00364 void 00365 Security::onReadPEM(const Data& name, PEMType type, Data& buffer) const 00366 { 00367 Data filename = mPath + pemTypePrefixes(type) + name + PEM; 00368 00369 InfoLog (<< "Reading PEM file " << filename << " into " << name); 00370 // .dlb. extra copy 00371 buffer = readIntoData(filename); 00372 } 00373 00374 00375 void 00376 Security::onWritePEM(const Data& name, PEMType type, const Data& buffer) const 00377 { 00378 Data filename = mPath + pemTypePrefixes(type) + name + PEM; 00379 InfoLog (<< "Writing PEM file " << filename << " for " << name); 00380 ofstream str(filename.c_str(), ios::binary); 00381 if (!str) 00382 { 00383 ErrLog (<< "Can't write to " << filename); 00384 throw BaseSecurity::Exception("Failed opening PEM file", __FILE__,__LINE__); 00385 } 00386 else 00387 { 00388 str.write(buffer.data(), buffer.size()); 00389 if (!str) 00390 { 00391 ErrLog (<< "Failed writing to " << filename << " " << buffer.size() << " bytes"); 00392 throw BaseSecurity::Exception("Failed writing PEM file", __FILE__,__LINE__); 00393 } 00394 } 00395 } 00396 00397 00398 void 00399 Security::onRemovePEM(const Data& name, PEMType type) const 00400 { 00401 assert(0); 00402 // TODO - should delete file 00403 } 00404 00405 00406 void 00407 BaseSecurity::addCertDER (PEMType type, 00408 const Data& key, 00409 const Data& certDER, 00410 bool write) 00411 { 00412 if( certDER.empty() ) 00413 { 00414 ErrLog(<< "File is empty. Skipping."); 00415 return; 00416 } 00417 00418 X509* cert = 0; 00419 00420 #if (OPENSSL_VERSION_NUMBER < 0x0090800fL ) 00421 unsigned char* in = (unsigned char*)certDER.data(); 00422 #else 00423 unsigned const char* in = (unsigned const char*)certDER.data(); 00424 #endif 00425 00426 if (d2i_X509(&cert,&in,(long)certDER.size()) == 0) 00427 { 00428 ErrLog(<< "Could not read DER certificate from " << certDER ); 00429 throw BaseSecurity::Exception("Could not read DER certificate ", 00430 __FILE__,__LINE__); 00431 } 00432 addCertX509(type,key,cert,write); 00433 } 00434 00435 00436 void 00437 BaseSecurity::addCertPEM (PEMType type, 00438 const Data& name, 00439 const Data& certPEM, 00440 bool write) 00441 { 00442 if( certPEM.empty() ) 00443 { 00444 ErrLog(<< name << " is empty. Skipping."); 00445 return; 00446 } 00447 X509* cert=NULL; 00448 00449 BIO* in = BIO_new_mem_buf(const_cast<char*>(certPEM.c_str()), -1); 00450 if ( !in ) 00451 { 00452 ErrLog(<< "Could not create BIO buffer from '" << certPEM << "'"); 00453 throw Exception("Could not create BIO buffer", __FILE__,__LINE__); 00454 } 00455 cert = PEM_read_bio_X509(in,0,0,0); 00456 if (cert == NULL) 00457 { 00458 ErrLog( << "Could not load X509 cert from '" << certPEM << "'" ); 00459 BIO_free(in); 00460 throw Exception("Could not load X509 cert from BIO buffer", __FILE__,__LINE__); 00461 } 00462 00463 addCertX509(type,name,cert,write); 00464 00465 BIO_free(in); 00466 } 00467 00468 00469 void 00470 BaseSecurity::addCertX509(PEMType type, const Data& key, X509* cert, bool write) 00471 { 00472 switch (type) 00473 { 00474 case DomainCert: 00475 { 00476 mDomainCerts.insert(std::make_pair(key, cert)); 00477 } 00478 break; 00479 case UserCert: 00480 { 00481 mUserCerts.insert(std::make_pair(key, cert)); 00482 } 00483 break; 00484 case RootCert: 00485 { 00486 mRootCerts.push_back(cert); 00487 X509_STORE_add_cert(mRootTlsCerts,cert); 00488 X509_STORE_add_cert(mRootSslCerts,cert); 00489 } 00490 break; 00491 default: 00492 { 00493 assert(0); 00494 } 00495 } 00496 00497 if (write) 00498 { 00499 // creates a read/write BIO buffer. 00500 BIO *out = BIO_new(BIO_s_mem()); 00501 if(!out) 00502 { 00503 ErrLog(<< "Failed to create BIO: this cert will not be added."); 00504 assert(0); 00505 return; 00506 } 00507 00508 try 00509 { 00510 int ret = PEM_write_bio_X509(out, cert); 00511 if(!ret) 00512 { 00513 assert(0); 00514 throw Exception("PEM_write_bio_X509 failed: this cert will not be " 00515 "added.", __FILE__,__LINE__); 00516 } 00517 00518 (void)BIO_flush(out); 00519 // get content in BIO buffer to our buffer. 00520 char* p = 0; 00521 size_t len = BIO_get_mem_data(out,&p); 00522 if(!p || !len) 00523 { 00524 assert(0); 00525 throw Exception("BIO_get_mem_data failed: this cert will not be " 00526 "added.", __FILE__,__LINE__); 00527 } 00528 Data buf(Data::Borrow, p, len); 00529 00530 this->onWritePEM(key, type, buf); 00531 } 00532 catch(Exception& e) 00533 { 00534 ErrLog(<<"Caught exception: " << e); 00535 } 00536 catch(std::exception& e) 00537 { 00538 ErrLog(<<"Caught unknown exception, rethrowing"); 00539 BIO_free(out); 00540 throw e; 00541 } 00542 BIO_free(out); 00543 } 00544 } 00545 00546 00547 bool 00548 BaseSecurity::hasCert (PEMType type, const Data& aor) const 00549 { 00550 assert( !aor.empty() ); 00551 const X509Map& certs = (type == DomainCert ? mDomainCerts : mUserCerts); 00552 00553 X509Map::const_iterator where = certs.find(aor); 00554 if (where != certs.end()) 00555 { 00556 return true; 00557 } 00558 00559 try 00560 { 00561 Data certPEM; 00562 onReadPEM(aor, type, certPEM); 00563 if (certPEM.empty()) 00564 { 00565 return false; 00566 } 00567 BaseSecurity* mutable_this = const_cast<BaseSecurity*>(this); 00568 mutable_this->addCertPEM(type, aor, certPEM, false); 00569 } 00570 catch (Exception& e) 00571 { 00572 ErrLog(<<"Caught exception: " << e); 00573 return false; 00574 } 00575 catch (...) 00576 { 00577 ErrLog(<<"Caught exception: "); 00578 return false; 00579 } 00580 00581 assert( certs.find(aor) != certs.end() ); 00582 00583 return true; 00584 } 00585 00586 00587 void 00588 BaseSecurity::removeCert (PEMType type, const Data& aor) 00589 { 00590 assert( !aor.empty() ); 00591 X509Map& certs = (type == DomainCert ? mDomainCerts : mUserCerts); 00592 00593 X509Map::iterator iter = certs.find(aor); 00594 if (iter != certs.end()) 00595 { 00596 X509_free(iter->second); 00597 certs.erase(iter); 00598 00599 onRemovePEM(aor, type); 00600 } 00601 00602 assert( certs.find(aor) == certs.end() ); 00603 } 00604 00605 00606 Data 00607 BaseSecurity::getCertDER (PEMType type, const Data& key) const 00608 { 00609 assert( !key.empty() ); 00610 00611 if (hasCert(type, key) == false) 00612 { 00613 ErrLog(<< "Could not find certificate for '" << key << "'"); 00614 throw BaseSecurity::Exception("Could not find certificate", __FILE__,__LINE__); 00615 } 00616 00617 const X509Map& certs = (type == DomainCert ? mDomainCerts : mUserCerts); 00618 BaseSecurity::X509Map::const_iterator where = certs.find(key); 00619 if (where == certs.end()) 00620 { 00621 // not supposed to happen, 00622 // hasCert() should have inserted a value into certs 00623 // or we should have throwed. 00624 assert(0); 00625 } 00626 00627 //assert(0); // the code following this has no hope of working 00628 00629 X509* x = where->second; 00630 unsigned char* buffer=0; 00631 int len = i2d_X509(x, &buffer); 00632 00633 // !kh! 00634 // Although len == 0 is not an error, I am not sure what quite to do. 00635 // Asserting for now. 00636 assert(len != 0); 00637 if(len < 0) 00638 { 00639 ErrLog(<< "Could encode certificate of '" << key << "' to DER form"); 00640 throw BaseSecurity::Exception("Could encode certificate to DER form", __FILE__,__LINE__); 00641 } 00642 Data certDER((char*)buffer, len); 00643 OPENSSL_free(buffer); 00644 return certDER; 00645 } 00646 00647 00648 void 00649 BaseSecurity::addPrivateKeyPKEY(PEMType type, 00650 const Data& name, 00651 EVP_PKEY* pKey, 00652 bool write) 00653 { 00654 PrivateKeyMap& privateKeys = (type == DomainPrivateKey ? 00655 mDomainPrivateKeys : mUserPrivateKeys); 00656 00657 /* 00658 // make a copy of the the key 00659 assert( EVP_PKEY_type(pKey->type) == EVP_PKEY_RSA ); 00660 RSA* rsa = EVP_PKEY_get1_RSA(pKey); 00661 assert( rsa ); 00662 EVP_PKEY* nKey = EVP_PKEY_new(); 00663 assert( nKey ); 00664 EVP_PKEY_set1_RSA(nKey, rsa); 00665 */ 00666 00667 //privateKeys.insert(std::make_pair(name, nKey)); 00668 privateKeys.insert(std::make_pair(name, pKey)); 00669 00670 if (write) 00671 { 00672 // figure out a passPhrase to encrypt with 00673 char* kstr=NULL; 00674 int klen=0; 00675 if (type != DomainPrivateKey) 00676 { 00677 PassPhraseMap::const_iterator iter = mUserPassPhrases.find(name); 00678 if(iter != mUserPassPhrases.end()) 00679 { 00680 kstr = (char*)iter->second.c_str(); 00681 klen = (int)iter->second.size(); 00682 } 00683 } 00684 00685 BIO *bio = BIO_new(BIO_s_mem()); 00686 if(!bio) 00687 { 00688 ErrLog(<< "BIO_new failed: cannot add private key."); 00689 assert(0); 00690 } 00691 00692 try 00693 { 00694 assert( EVP_des_ede3_cbc() ); 00695 const EVP_CIPHER* cipher = EVP_des_ede3_cbc(); 00696 if (kstr == NULL ) 00697 { 00698 cipher = NULL; 00699 } 00700 #if 0 // TODO - need to figure out what format to write in 00701 int ret = PEM_write_bio_PrivateKey(bio, pKey, cipher, 00702 (unsigned char*)kstr, klen, 00703 NULL, NULL); 00704 #else 00705 int ret = PEM_write_bio_PKCS8PrivateKey(bio, pKey, cipher, 00706 kstr, klen, 00707 NULL, NULL); 00708 #endif 00709 if(!ret) 00710 { 00711 assert(0); 00712 throw Exception("PEM_write_bio_PKCS8PrivateKey failed: cannot add" 00713 " private key.", __FILE__, __LINE__); 00714 } 00715 00716 (void)BIO_flush(bio); 00717 char* p = 0; 00718 size_t len = BIO_get_mem_data(bio,&p); 00719 if(!p || !len) 00720 { 00721 assert(0); 00722 throw Exception("BIO_get_mem_data failed: cannot add" 00723 " private key.", __FILE__, __LINE__); 00724 } 00725 Data pem(Data::Borrow, p, len); 00726 onWritePEM(name, type, pem ); 00727 } 00728 catch(Exception& e) 00729 { 00730 ErrLog( << "Caught exception: " << e); 00731 } 00732 catch(std::exception& e) 00733 { 00734 ErrLog(<<"Caught unknown exception, rethrowing: " << e.what()); 00735 BIO_free(bio); 00736 throw e; 00737 } 00738 BIO_free(bio); 00739 } 00740 } 00741 00742 00743 void 00744 BaseSecurity::addPrivateKeyDER( PEMType type, 00745 const Data& name, 00746 const Data& privateKeyDER, 00747 bool write ) 00748 { 00749 assert( !name.empty() ); 00750 if( privateKeyDER.empty() ) 00751 { 00752 ErrLog(<< name << " is empty. Skipping."); 00753 return; 00754 } 00755 00756 char* passPhrase = 0; 00757 if (type != DomainPrivateKey) 00758 { 00759 PassPhraseMap::const_iterator iter = mUserPassPhrases.find(name); 00760 if(iter != mUserPassPhrases.end()) 00761 { 00762 passPhrase = const_cast<char*>(iter->second.c_str()); 00763 } 00764 } 00765 00766 BIO* in = BIO_new_mem_buf(const_cast<char*>(privateKeyDER.c_str()), -1); 00767 if ( !in ) 00768 { 00769 ErrLog(<< "Could create BIO buffer from '" << privateKeyDER << "'"); 00770 throw Exception("Could not create BIO buffer", __FILE__,__LINE__); 00771 } 00772 00773 try 00774 { 00775 00776 EVP_PKEY* privateKey; 00777 if (d2i_PKCS8PrivateKey_bio(in, &privateKey, 0, passPhrase) == 0) 00778 { 00779 ErrLog(<< "Could not read private key from <" << privateKeyDER << ">" ); 00780 throw Exception("Could not read private key ", __FILE__,__LINE__); 00781 } 00782 00783 addPrivateKeyPKEY(type,name,privateKey,write); 00784 } 00785 catch(std::exception& e) 00786 { 00787 ErrLog(<<"Caught exception: "); 00788 BIO_free(in); 00789 throw e; 00790 } 00791 00792 BIO_free(in); 00793 } 00794 00795 00796 void 00797 BaseSecurity::addPrivateKeyPEM( PEMType type, 00798 const Data& name, 00799 const Data& privateKeyPEM, 00800 bool write ) 00801 { 00802 assert( !name.empty() ); 00803 if( privateKeyPEM.empty() ) 00804 { 00805 ErrLog(<< name << " is empty. Skipping."); 00806 return; 00807 } 00808 00809 BIO* in = BIO_new_mem_buf(const_cast<char*>(privateKeyPEM.c_str()), -1); 00810 if ( !in ) 00811 { 00812 ErrLog(<< "Could create BIO buffer from '" << privateKeyPEM << "'"); 00813 throw Exception("Could not create BIO buffer", __FILE__,__LINE__); 00814 } 00815 00816 char* passPhrase = 0; 00817 try 00818 { 00819 if (type == UserPrivateKey) 00820 { 00821 PassPhraseMap::const_iterator iter = mUserPassPhrases.find(name); 00822 if(iter != mUserPassPhrases.end()) 00823 { 00824 passPhrase = const_cast<char*>(iter->second.c_str()); 00825 } 00826 } 00827 00828 EVP_PKEY* privateKey=0; 00829 if ( ( privateKey = PEM_read_bio_PrivateKey(in, NULL, 0, passPhrase)) == NULL) 00830 { 00831 ErrLog(<< "Could not read private key from <" << privateKeyPEM << ">" ); 00832 throw Exception("Could not read private key ", __FILE__,__LINE__); 00833 } 00834 00835 addPrivateKeyPKEY(type,name,privateKey,write); 00836 } 00837 catch(std::exception& e) 00838 { 00839 ErrLog(<<"Caught exception: "); 00840 BIO_free(in); 00841 throw e; 00842 } 00843 00844 BIO_free(in); 00845 } 00846 00847 00848 bool 00849 BaseSecurity::hasPrivateKey( PEMType type, 00850 const Data& key ) const 00851 { 00852 assert( !key.empty() ); 00853 00854 const PrivateKeyMap& privateKeys = (type == DomainPrivateKey 00855 ? mDomainPrivateKeys : mUserPrivateKeys); 00856 00857 PrivateKeyMap::const_iterator where = privateKeys.find(key); 00858 if (where != privateKeys.end()) 00859 { 00860 return true; 00861 } 00862 00863 Data privateKeyPEM; 00864 try 00865 { 00866 onReadPEM(key, type, privateKeyPEM); 00867 BaseSecurity* mutable_this = const_cast<BaseSecurity*>(this); 00868 mutable_this->addPrivateKeyPEM(type, key, privateKeyPEM, false); 00869 } 00870 catch(std::exception& e) 00871 { 00872 ErrLog(<<"Caught exception: " << e.what()); 00873 return false; 00874 } 00875 catch(...) 00876 { 00877 ErrLog(<<"Caught unknown class!"); 00878 return false; 00879 } 00880 00881 return true; 00882 } 00883 00884 00885 Data 00886 BaseSecurity::getPrivateKeyPEM( PEMType type, 00887 const Data& key) const 00888 { 00889 assert( !key.empty() ); 00890 00891 if ( !hasPrivateKey(type, key) ) 00892 { 00893 ErrLog(<< "Could find private key for '" << key << "'"); 00894 throw Exception("Could not find private key", __FILE__,__LINE__); 00895 } 00896 00897 const PrivateKeyMap& privateKeys = (type == DomainPrivateKey ? mDomainPrivateKeys : mUserPrivateKeys); 00898 00899 PrivateKeyMap::const_iterator where = privateKeys.find(key); 00900 char* p = 0; 00901 if (type != DomainPrivateKey) 00902 { 00903 PassPhraseMap::const_iterator iter = mUserPassPhrases.find(key); 00904 if (iter != mUserPassPhrases.end()) 00905 { 00906 p = const_cast<char*>(iter->second.c_str()); 00907 } 00908 } 00909 00910 assert(0); // TODO - following code has no hope of working 00911 00912 // !kh! 00913 // creates a read/write BIO buffer. 00914 BIO *out = BIO_new(BIO_s_mem()); 00915 assert(out); 00916 EVP_PKEY* pk = where->second; 00917 assert(pk); 00918 00919 // write pk to out using key phrase p, with no cipher. 00920 int ret = PEM_write_bio_PrivateKey(out, pk, 0, 0, 0, 0, p); // paraters 00921 // are in the wrong order 00922 (void)ret; 00923 assert(ret == 1); 00924 00925 // get content in BIO buffer to our buffer. 00926 // hand our buffer to a Data object. 00927 (void)BIO_flush(out); 00928 char* buf = 0; 00929 int len = BIO_get_mem_data(out, &buf); 00930 Data retVal(Data::Borrow, buf, len); 00931 00932 BIO_free(out); 00933 00934 return retVal; 00935 } 00936 00937 00938 Data 00939 BaseSecurity::getPrivateKeyDER( PEMType type, 00940 const Data& key) const 00941 { 00942 assert( !key.empty() ); 00943 00944 if ( !hasPrivateKey(type, key) ) 00945 { 00946 ErrLog(<< "Could find private key for '" << key << "'"); 00947 throw Exception("Could not find private key", __FILE__,__LINE__); 00948 } 00949 00950 const PrivateKeyMap& privateKeys = (type == DomainPrivateKey ? mDomainPrivateKeys : mUserPrivateKeys); 00951 00952 PrivateKeyMap::const_iterator where = privateKeys.find(key); 00953 char* p = 0; 00954 if (type != DomainPrivateKey) 00955 { 00956 PassPhraseMap::const_iterator iter = mUserPassPhrases.find(key); 00957 if(iter != mUserPassPhrases.end()) 00958 { 00959 p = const_cast<char*>(iter->second.c_str()); 00960 } 00961 } 00962 00963 assert(0); // TODO - following code has no hope of working 00964 00965 // !kh! 00966 // creates a read/write BIO buffer. 00967 BIO *out = BIO_new(BIO_s_mem()); 00968 assert(out); 00969 EVP_PKEY* pk = where->second; 00970 assert(pk); 00971 00972 // write pk to out using key phrase p, with no cipher. 00973 int ret = i2d_PKCS8PrivateKey_bio(out, pk, 0, 0, 0, 0, p); 00974 (void)ret; 00975 assert(ret == 1); 00976 00977 // get content in BIO buffer to our buffer. 00978 // hand our buffer to a Data object. 00979 (void)BIO_flush(out); 00980 char* buf = 0; 00981 int len = BIO_get_mem_data(out, &buf); 00982 Data retVal(Data::Borrow, buf, len); 00983 00984 BIO_free(out); 00985 00986 return retVal; 00987 } 00988 00989 00990 void 00991 BaseSecurity::removePrivateKey(PEMType type, const Data& key) 00992 { 00993 assert( !key.empty() ); 00994 00995 PrivateKeyMap& privateKeys = (type == DomainPrivateKey ? mDomainPrivateKeys : mUserPrivateKeys); 00996 00997 assert( !key.empty() ); 00998 PrivateKeyMap::iterator iter = privateKeys.find(key); 00999 if (iter != privateKeys.end()) 01000 { 01001 EVP_PKEY_free(iter->second); 01002 privateKeys.erase(iter); 01003 01004 onRemovePEM(key, type); 01005 } 01006 } 01007 01008 01009 Security::Exception::Exception(const Data& msg, const Data& file, const int line) 01010 : BaseException(msg,file,line) 01011 { 01012 } 01013 01014 01015 BaseSecurity::BaseSecurity (const CipherList& cipherSuite) : 01016 mTlsCtx(0), 01017 mSslCtx(0), 01018 mCipherList(cipherSuite), 01019 mRootTlsCerts(0), 01020 mRootSslCerts(0) 01021 { 01022 DebugLog(<< "BaseSecurity::BaseSecurity"); 01023 01024 int ret; 01025 initialize(); 01026 01027 mRootTlsCerts = X509_STORE_new(); 01028 mRootSslCerts = X509_STORE_new(); 01029 assert(mRootTlsCerts && mRootSslCerts); 01030 01031 mTlsCtx = SSL_CTX_new( TLSv1_method() ); 01032 if (!mTlsCtx) 01033 { 01034 ErrLog(<< "SSL_CTX_new failed, dumping OpenSSL error stack:"); 01035 while (ERR_peek_error()) 01036 { 01037 char errBuf[120]; 01038 ERR_error_string(ERR_get_error(), errBuf); 01039 ErrLog(<< "OpenSSL error stack: " << errBuf); 01040 } 01041 } 01042 assert(mTlsCtx); 01043 01044 SSL_CTX_set_cert_store(mTlsCtx, mRootTlsCerts); 01045 SSL_CTX_set_verify(mTlsCtx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, verifyCallback); 01046 ret = SSL_CTX_set_cipher_list(mTlsCtx, cipherSuite.cipherList().c_str()); 01047 assert(ret); 01048 01049 mSslCtx = SSL_CTX_new( SSLv23_method() ); 01050 assert(mSslCtx); 01051 SSL_CTX_set_cert_store(mSslCtx, mRootSslCerts); 01052 SSL_CTX_set_verify(mSslCtx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, verifyCallback); 01053 ret = SSL_CTX_set_cipher_list(mSslCtx,cipherSuite.cipherList().c_str()); 01054 assert(ret); 01055 } 01056 01057 01058 template<class T, class Func> 01059 void clearMap(T& m, Func& clearFunc) 01060 { 01061 for (typename T::iterator it = m.begin(); it != m.end(); it++) 01062 { 01063 clearFunc(it->second); 01064 } 01065 m.clear(); 01066 } 01067 01068 template<class T, class Func> 01069 void clearList(T& m, Func& clearFunc) 01070 { 01071 for (typename T::iterator it = m.begin(); it != m.end(); it++) 01072 { 01073 clearFunc(*it); 01074 } 01075 m.clear(); 01076 } 01077 01078 BaseSecurity::~BaseSecurity () 01079 { 01080 DebugLog(<< "BaseSecurity::~BaseSecurity"); 01081 01082 // cleanup certificates 01083 clearList(mRootCerts, X509_free); 01084 clearMap(mDomainCerts, X509_free); 01085 clearMap(mUserCerts, X509_free); 01086 01087 // cleanup private keys 01088 clearMap(mDomainPrivateKeys, EVP_PKEY_free); 01089 clearMap(mUserPrivateKeys, EVP_PKEY_free); 01090 01091 // cleanup SSL_CTXes 01092 if (mTlsCtx) 01093 { 01094 SSL_CTX_free(mTlsCtx);mTlsCtx=0; // This free's X509_STORE (mRootTlsCerts) 01095 } 01096 if (mSslCtx) 01097 { 01098 SSL_CTX_free(mSslCtx);mSslCtx=0; // This free's X509_STORE (mRootSslCerts) 01099 } 01100 01101 } 01102 01103 01104 void 01105 BaseSecurity::initialize () 01106 { 01107 Timer::getTimeMs(); // initalize time offsets 01108 } 01109 01110 01111 Security::CertificateInfoContainer 01112 BaseSecurity::getRootCertDescriptions() const 01113 { 01114 // !kh! 01115 // need to be implemented. 01116 assert(0); // TODO 01117 return CertificateInfoContainer(); 01118 } 01119 01120 01121 void 01122 BaseSecurity::addRootCertPEM(const Data& x509PEMEncodedRootCerts) 01123 { 01124 assert( mRootTlsCerts && mRootSslCerts ); 01125 #if 1 01126 addCertPEM(RootCert,Data::Empty,x509PEMEncodedRootCerts,false); 01127 #else 01128 assert( !x509PEMEncodedRootCerts.empty() ); 01129 01130 static X509_LOOKUP_METHOD x509_pemstring_lookup = 01131 { 01132 "Load cert from PEM string into cache", 01133 NULL, /* new */ 01134 NULL, /* free */ 01135 NULL, /* init */ 01136 NULL, /* shutdown */ 01137 pemstring_ctrl,/* ctrl */ 01138 NULL, /* get_by_subject */ 01139 NULL, /* get_by_issuer_serial */ 01140 NULL, /* get_by_fingerprint */ 01141 NULL, /* get_by_alias */ 01142 }; 01143 01144 if (mRootCerts == 0) 01145 { 01146 mRootCerts = X509_STORE_new(); 01147 } 01148 01149 assert( mRootCerts ); 01150 01151 X509_LOOKUP* lookup = X509_STORE_add_lookup(mRootCerts, &x509_pemstring_lookup); 01152 01153 if (lookup == NULL) 01154 throw Exception("Error in BaseSecurity::addRootCertPEM()", __FILE__,__LINE__); 01155 01156 // !kh! 01157 // bug, no error handling here. 01158 X509_LOOKUP_ctrl(lookup, X509_L_FILE_LOAD, x509PEMEncodedRootCerts.c_str(), 0, 0); 01159 #endif 01160 } 01161 01162 01163 void 01164 BaseSecurity::addDomainCertPEM(const Data& domainName, const Data& certPEM) 01165 { 01166 addCertPEM(DomainCert, domainName, certPEM, true); 01167 } 01168 01169 01170 void 01171 BaseSecurity::addDomainCertDER(const Data& domainName, const Data& certDER) 01172 { 01173 addCertDER(DomainCert, domainName, certDER, true); 01174 } 01175 01176 01177 bool 01178 BaseSecurity::hasDomainCert(const Data& domainName) const 01179 { 01180 return hasCert(DomainCert, domainName); 01181 } 01182 01183 01184 void 01185 BaseSecurity::removeDomainCert(const Data& domainName) 01186 { 01187 return removeCert(DomainCert, domainName); 01188 } 01189 01190 01191 Data 01192 BaseSecurity::getDomainCertDER(const Data& domainName) const 01193 { 01194 return getCertDER(DomainCert, domainName); 01195 } 01196 01197 01198 void 01199 BaseSecurity::addDomainPrivateKeyPEM(const Data& domainName, const Data& privateKeyPEM) 01200 { 01201 addPrivateKeyPEM(DomainPrivateKey, domainName, privateKeyPEM, true); 01202 } 01203 01204 01205 bool 01206 BaseSecurity::hasDomainPrivateKey(const Data& domainName) const 01207 { 01208 return hasPrivateKey(DomainPrivateKey, domainName); 01209 } 01210 01211 01212 void 01213 BaseSecurity::removeDomainPrivateKey(const Data& domainName) 01214 { 01215 removePrivateKey(DomainPrivateKey, domainName); 01216 } 01217 01218 01219 Data 01220 BaseSecurity::getDomainPrivateKeyPEM(const Data& domainName) const 01221 { 01222 return getPrivateKeyPEM(DomainPrivateKey, domainName); 01223 } 01224 01225 01226 void 01227 BaseSecurity::addUserCertPEM(const Data& aor, const Data& certPEM) 01228 { 01229 addCertPEM(UserCert, aor, certPEM, true); 01230 } 01231 01232 01233 void 01234 BaseSecurity::addUserCertDER(const Data& aor, const Data& certDER) 01235 { 01236 addCertDER(UserCert, aor, certDER, true); 01237 } 01238 01239 01240 bool 01241 BaseSecurity::hasUserCert(const Data& aor) const 01242 { 01243 return hasCert(UserCert, aor); 01244 } 01245 01246 01247 void 01248 BaseSecurity::removeUserCert(const Data& aor) 01249 { 01250 removeCert(UserCert, aor); 01251 } 01252 01253 01254 Data 01255 BaseSecurity::getUserCertDER(const Data& aor) const 01256 { 01257 return getCertDER(UserCert, aor); 01258 } 01259 01260 01261 void 01262 BaseSecurity::setUserPassPhrase(const Data& aor, const Data& passPhrase) 01263 { 01264 assert(!aor.empty()); 01265 01266 PassPhraseMap::iterator iter = mUserPassPhrases.find(aor); 01267 if (iter == mUserPassPhrases.end()) 01268 { 01269 mUserPassPhrases.insert(std::make_pair(aor, passPhrase)); 01270 } 01271 } 01272 01273 01274 bool 01275 BaseSecurity::hasUserPassPhrase(const Data& aor) const 01276 { 01277 assert(aor.empty()); 01278 01279 PassPhraseMap::const_iterator iter = mUserPassPhrases.find(aor); 01280 if (iter == mUserPassPhrases.end()) 01281 { 01282 return false; 01283 } 01284 else 01285 { 01286 return true; 01287 } 01288 } 01289 01290 01291 void 01292 BaseSecurity::removeUserPassPhrase(const Data& aor) 01293 { 01294 assert(aor.empty()); 01295 01296 PassPhraseMap::iterator iter = mUserPassPhrases.find(aor); 01297 if(iter != mUserPassPhrases.end()) 01298 { 01299 mUserPassPhrases.erase(iter); 01300 } 01301 } 01302 01303 01304 Data 01305 BaseSecurity::getUserPassPhrase(const Data& aor) const 01306 { 01307 assert(aor.empty()); 01308 01309 PassPhraseMap::const_iterator iter = mUserPassPhrases.find(aor); 01310 if(iter == mUserPassPhrases.end()) 01311 { 01312 return iter->second; 01313 } 01314 else 01315 { 01316 return Data::Empty; 01317 } 01318 } 01319 01320 01321 void 01322 BaseSecurity::addUserPrivateKeyPEM(const Data& aor, const Data& cert) 01323 { 01324 addPrivateKeyPEM(UserPrivateKey, aor, cert, true); 01325 } 01326 01327 01328 void 01329 BaseSecurity::addUserPrivateKeyDER(const Data& aor, const Data& cert) 01330 { 01331 addPrivateKeyDER(UserPrivateKey, aor, cert, true); 01332 } 01333 01334 01335 bool 01336 BaseSecurity::hasUserPrivateKey(const Data& aor) const 01337 { 01338 return hasPrivateKey(UserPrivateKey, aor); 01339 } 01340 01341 01342 void 01343 BaseSecurity::removeUserPrivateKey(const Data& aor) 01344 { 01345 removePrivateKey(UserPrivateKey, aor); 01346 } 01347 01348 01349 Data 01350 BaseSecurity::getUserPrivateKeyPEM(const Data& aor) const 01351 { 01352 return getPrivateKeyPEM(UserPrivateKey, aor); 01353 } 01354 01355 01356 Data 01357 BaseSecurity::getUserPrivateKeyDER(const Data& aor) const 01358 { 01359 return getPrivateKeyDER(UserPrivateKey, aor); 01360 } 01361 01362 01363 void 01364 BaseSecurity::generateUserCert (const Data& pAor, int expireDays, int keyLen ) 01365 { 01366 int ret; 01367 01368 InfoLog( <<"Generating new user cert for " << pAor ); 01369 01370 Data domain; 01371 Data aor; 01372 01373 try 01374 { 01375 Uri uri( Data("sip:")+pAor ); 01376 aor = uri.getAor(); 01377 domain = uri.host(); 01378 } 01379 catch (...) 01380 { 01381 ErrLog( <<"Invalid aor passed to generateUserCert"); 01382 throw Exception("Bad aor passed to generateUserCert", __FILE__,__LINE__); 01383 } 01384 01385 // Make sure that necessary algorithms exist: 01386 assert(EVP_sha1()); 01387 01388 RSA* rsa = RSA_generate_key(keyLen, RSA_F4, NULL, NULL); 01389 assert(rsa); // couldn't make key pair 01390 01391 EVP_PKEY* privkey = EVP_PKEY_new(); 01392 assert(privkey); 01393 ret = EVP_PKEY_set1_RSA(privkey, rsa); 01394 assert(ret); 01395 01396 X509* cert = X509_new(); 01397 assert(cert); 01398 01399 X509_NAME* subject = X509_NAME_new(); 01400 X509_EXTENSION* ext = X509_EXTENSION_new(); 01401 01402 // set version to X509v3 (starts from 0) 01403 X509_set_version(cert, 2L); 01404 01405 int serial = Random::getRandom(); // get an int worth of randomness 01406 assert(sizeof(int)==4); 01407 ASN1_INTEGER_set(X509_get_serialNumber(cert),serial); 01408 01409 ret = X509_NAME_add_entry_by_txt( subject, "O", MBSTRING_ASC, 01410 (unsigned char *) domain.data(), (int)domain.size(), 01411 -1, 0); 01412 assert(ret); 01413 ret = X509_NAME_add_entry_by_txt( subject, "CN", MBSTRING_ASC, 01414 (unsigned char *) aor.data(), (int)aor.size(), 01415 -1, 0); 01416 assert(ret); 01417 01418 ret = X509_set_issuer_name(cert, subject); 01419 assert(ret); 01420 ret = X509_set_subject_name(cert, subject); 01421 assert(ret); 01422 01423 const long duration = 60*60*24*expireDays; 01424 X509_gmtime_adj(X509_get_notBefore(cert),0); 01425 X509_gmtime_adj(X509_get_notAfter(cert), duration); 01426 01427 ret = X509_set_pubkey(cert, privkey); 01428 assert(ret); 01429 01430 Data subjectAltNameStr = Data("URI:sip:") + aor 01431 + Data(",URI:im:")+aor 01432 + Data(",URI:pres:")+aor; 01433 ext = X509V3_EXT_conf_nid( NULL , NULL , NID_subject_alt_name, 01434 (char*) subjectAltNameStr.c_str() ); 01435 X509_add_ext( cert, ext, -1); 01436 X509_EXTENSION_free(ext); 01437 01438 static char CA_FALSE[] = "CA:FALSE"; 01439 ext = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints, CA_FALSE); 01440 ret = X509_add_ext( cert, ext, -1); 01441 assert(ret); 01442 X509_EXTENSION_free(ext); 01443 01444 // TODO add extensions NID_subject_key_identifier and NID_authority_key_identifier 01445 01446 ret = X509_sign(cert, privkey, EVP_sha1()); 01447 assert(ret); 01448 01449 addCertX509( UserCert, aor, cert, true /* write */ ); 01450 addPrivateKeyPKEY( UserPrivateKey, aor, privkey, true /* write */ ); 01451 } 01452 01453 MultipartSignedContents* 01454 BaseSecurity::sign(const Data& senderAor, Contents* contents) 01455 { 01456 assert( contents ); 01457 01458 // form the multipart 01459 MultipartSignedContents* multi = new MultipartSignedContents; 01460 multi->header(h_ContentType).param( p_micalg ) = "sha1"; 01461 multi->header(h_ContentType).param( p_protocol ) = "application/pkcs7-signature"; 01462 01463 // add the main body to it 01464 Contents* body = contents->clone(); 01465 multi->parts().push_back( body ); 01466 01467 Data bodyData; 01468 DataStream strm( bodyData ); 01469 body->encodeHeaders( strm ); 01470 body->encode( strm ); 01471 strm.flush(); 01472 01473 DebugLog( << "signing data <" << bodyData.escaped() << ">" ); 01474 //Security::dumpAsn("resip-sign-out-data",bodyData); 01475 01476 const char* p = bodyData.data(); 01477 int s = (int)bodyData.size(); 01478 BIO* in=BIO_new_mem_buf( (void*)p,s); 01479 assert(in); 01480 DebugLog( << "created in BIO"); 01481 01482 BIO* out = BIO_new(BIO_s_mem()); // TODO - mem leak 01483 assert(out); 01484 DebugLog( << "created out BIO" ); 01485 01486 STACK_OF(X509)* chain = sk_X509_new_null(); 01487 assert(chain); 01488 01489 DebugLog( << "searching for cert/key for <" << senderAor << ">" ); 01490 if (mUserCerts.count(senderAor) == 0 || 01491 mUserPrivateKeys.count(senderAor) == 0) 01492 { 01493 BIO_free(in); 01494 BIO_free(out); 01495 sk_X509_free(chain); 01496 WarningLog (<< "Tried to sign with no cert or private key for " << senderAor); 01497 throw Exception("No cert or private key to sign with",__FILE__,__LINE__); 01498 } 01499 01500 X509* publicCert = mUserCerts[senderAor]; 01501 EVP_PKEY* privateKey = mUserPrivateKeys[senderAor]; 01502 01503 int rv = X509_check_private_key(publicCert, privateKey); 01504 if(!rv) 01505 { 01506 BIO_free(in); 01507 BIO_free(out); 01508 sk_X509_free(chain); 01509 ErrLog (<< "X509_check_private_key failed for " << senderAor); 01510 return 0; 01511 } 01512 01513 // compute the signature 01514 int flags = 0; 01515 flags |= PKCS7_BINARY; 01516 flags |= PKCS7_DETACHED; 01517 if ( true ) // don't do caps 01518 { 01519 flags |= PKCS7_NOSMIMECAP; 01520 flags |= PKCS7_NOATTR; 01521 } 01522 if ( true ) // don't do certs 01523 { 01524 flags |= PKCS7_NOCERTS; 01525 } 01526 01527 PKCS7* pkcs7 = PKCS7_sign( publicCert, privateKey, chain, in, flags); 01528 if ( !pkcs7 ) 01529 { 01530 BIO_free(in); 01531 BIO_free(out); 01532 sk_X509_free(chain); 01533 ErrLog( << "Error creating PKCS7 signature object" ); 01534 return 0; 01535 } 01536 DebugLog( << "created PKCS7 signature object " ); 01537 01538 i2d_PKCS7_bio(out,pkcs7); 01539 (void)BIO_flush(out); 01540 01541 char* outBuf=0; 01542 long size = BIO_get_mem_data(out,&outBuf); 01543 assert( size > 0 ); 01544 01545 Data outData(outBuf,size); 01546 static char RESIP_SIGN_OUT_SIG[] = "resip-sign-out-sig"; 01547 Security::dumpAsn(RESIP_SIGN_OUT_SIG,outData); 01548 01549 Pkcs7SignedContents* sigBody = new Pkcs7SignedContents( outData ); 01550 assert( sigBody ); 01551 01552 // add the signature to it 01553 sigBody->header(h_ContentType).param( p_name ) = "smime.p7s"; 01554 sigBody->header(h_ContentDisposition).param( p_handling ) = "required"; 01555 sigBody->header(h_ContentDisposition).param( p_filename ) = "smime.p7s"; 01556 sigBody->header(h_ContentDisposition).value() = "attachment" ; 01557 sigBody->header(h_ContentTransferEncoding).value() = "binary"; 01558 multi->parts().push_back( sigBody ); 01559 01560 assert( multi->parts().size() == 2 ); 01561 01562 BIO_free(in); 01563 BIO_free(out); 01564 sk_X509_free(chain); 01565 PKCS7_free(pkcs7); 01566 01567 return multi; 01568 } 01569 01570 01571 Pkcs7Contents* 01572 BaseSecurity::encrypt(Contents* bodyIn, const Data& recipCertName ) 01573 { 01574 assert( bodyIn ); 01575 01576 int flags = 0 ; 01577 flags |= PKCS7_BINARY; 01578 flags |= PKCS7_NOCERTS; 01579 01580 Data bodyData; 01581 DataStream strm(bodyData); 01582 bodyIn->encodeHeaders(strm); 01583 bodyIn->encode( strm ); 01584 strm.flush(); 01585 01586 InfoLog( << "body data to encrypt is <" << bodyData.escaped() << ">" ); 01587 01588 const char* p = bodyData.data(); 01589 int s = (int)bodyData.size(); 01590 01591 BIO* in = BIO_new_mem_buf( (void*)p,s); 01592 assert(in); 01593 DebugLog( << "created in BIO"); 01594 01595 BIO* out = BIO_new(BIO_s_mem()); 01596 assert(out); 01597 DebugLog( << "created out BIO" ); 01598 01599 InfoLog( << "target cert name is <" << recipCertName << ">" ); 01600 if (mUserCerts.count(recipCertName) == 0) 01601 { 01602 BIO_free(in); 01603 BIO_free(out); 01604 WarningLog (<< "Tried to encrypt with no cert or private key for " << recipCertName); 01605 throw Exception("No cert or private key to encrypt with",__FILE__,__LINE__); 01606 } 01607 01608 X509* cert = mUserCerts[recipCertName]; 01609 assert(cert); 01610 01611 STACK_OF(X509) *certs = sk_X509_new_null(); 01612 assert(certs); 01613 sk_X509_push(certs, cert); 01614 01615 // if you think you need to change the following few lines, please email fluffy 01616 // the value of OPENSSL_VERSION_NUMBER ( in opensslv.h ) and the signature of 01617 // PKCS_encrypt found ( in pkcs7.h ) and the OS you are using 01618 #if ( OPENSSL_VERSION_NUMBER > 0x009060ffL ) 01619 // const EVP_CIPHER* cipher = EVP_des_ede3_cbc(); 01620 const EVP_CIPHER* cipher = EVP_aes_128_cbc(); 01621 #else 01622 //const EVP_CIPHER* cipher = EVP_enc_null(); 01623 EVP_CIPHER* cipher = EVP_des_ede3_cbc(); 01624 #endif 01625 assert( cipher ); 01626 01627 #if (OPENSSL_VERSION_NUMBER < 0x0090705fL ) 01628 #warning PKCS7_encrypt() is broken in OpenSSL 0.9.7d 01629 #endif 01630 01631 PKCS7* pkcs7 = PKCS7_encrypt( certs, in, cipher, flags); 01632 if ( !pkcs7 ) 01633 { 01634 BIO_free(in); 01635 BIO_free(out); 01636 sk_X509_free(certs); 01637 ErrLog( << "Error creating PKCS7 encrypt object" ); 01638 //throw Exception("Can't encrypt",__FILE__,__LINE__); 01639 return 0; 01640 } 01641 DebugLog( << "created PKCS7 encrypt object " ); 01642 01643 i2d_PKCS7_bio(out,pkcs7); 01644 01645 (void)BIO_flush(out); 01646 01647 char* outBuf=0; 01648 long size = BIO_get_mem_data(out,&outBuf); 01649 assert( size > 0 ); 01650 01651 Data outData(outBuf,size); 01652 assert( (long)outData.size() == size ); 01653 01654 InfoLog( << "Encrypted body size is " << outData.size() ); 01655 InfoLog( << "Encrypted body is <" << outData.escaped() << ">" ); 01656 01657 static char RESIP_ENCRYPT_OUT[] = "resip-encrypt-out"; 01658 Security::dumpAsn(RESIP_ENCRYPT_OUT, outData); 01659 01660 Pkcs7Contents* outBody = new Pkcs7Contents( outData ); 01661 assert( outBody ); 01662 01663 outBody->header(h_ContentType).param( p_smimeType ) = "enveloped-data"; 01664 outBody->header(h_ContentType).param( p_name ) = "smime.p7m"; 01665 outBody->header(h_ContentDisposition).param( p_handling ) = "required"; 01666 outBody->header(h_ContentDisposition).param( p_filename ) = "smime.p7"; 01667 outBody->header(h_ContentDisposition).value() = "attachment" ; 01668 outBody->header(h_ContentTransferEncoding).value() = "binary"; 01669 01670 BIO_free(in); 01671 BIO_free(out); 01672 sk_X509_free(certs); 01673 PKCS7_free(pkcs7); 01674 01675 return outBody; 01676 } 01677 01678 01679 MultipartSignedContents * 01680 BaseSecurity::signAndEncrypt( const Data& senderAor, Contents* body, const Data& recipCertName ) 01681 { 01682 //assert(0); 01683 //return 0; 01684 return sign(senderAor, encrypt(body, recipCertName)); 01685 } 01686 01687 01688 Data 01689 BaseSecurity::computeIdentity( const Data& signerDomain, const Data& in ) const 01690 { 01691 DebugLog( << "Compute identity for " << in ); 01692 01693 PrivateKeyMap::const_iterator k(mDomainPrivateKeys.find(signerDomain)); 01694 if (k == mDomainPrivateKeys.end()) 01695 { 01696 InfoLog( << "No private key for " << signerDomain ); 01697 throw Exception("Missing private key when computing identity",__FILE__,__LINE__); 01698 } 01699 01700 EVP_PKEY* pKey = k->second; 01701 assert( pKey ); 01702 01703 if ( pKey->type != EVP_PKEY_RSA ) 01704 { 01705 ErrLog( << "Private key (type=" << pKey->type <<"for " 01706 << signerDomain << " is not of type RSA" ); 01707 throw Exception("No RSA private key when computing identity",__FILE__,__LINE__); 01708 } 01709 01710 assert( pKey->type == EVP_PKEY_RSA ); 01711 RSA* rsa = EVP_PKEY_get1_RSA(pKey); 01712 01713 unsigned char result[4096]; 01714 int resultSize = sizeof(result); 01715 assert( resultSize >= RSA_size(rsa) ); 01716 01717 SHA1Stream sha; 01718 sha << in; 01719 Data hashRes = sha.getBin(); 01720 DebugLog( << "hash of string is 0x" << hashRes.hex() ); 01721 01722 #if 1 01723 int r = RSA_sign(NID_sha1, (unsigned char *)hashRes.data(), (unsigned int)hashRes.size(), 01724 result, (unsigned int*)( &resultSize ), 01725 rsa); 01726 if( r != 1 ) 01727 { 01728 ErrLog(<< "RSA_sign failed with return " << r); 01729 assert(0); 01730 return Data::Empty; 01731 } 01732 #else 01733 resultSize = RSA_private_encrypt(hashResLen, hashRes, 01734 result, rsa, RSA_PKCS1_PADDING); 01735 if ( resultSize == -1 ) 01736 { 01737 DebugLog( << "Problem doing RSA encrypt for identity"); 01738 while (1) 01739 { 01740 const char* file; 01741 int line; 01742 01743 unsigned long code = ERR_get_error_line(&file,&line); 01744 if ( code == 0 ) 01745 { 01746 break; 01747 } 01748 01749 char buf[256]; 01750 ERR_error_string_n(code,buf,sizeof(buf)); 01751 ErrLog( << buf ); 01752 InfoLog( << "Error code = " << code << " file="<<file<<" line=" << line ); 01753 } 01754 01755 return Data::Empty; 01756 } 01757 #endif 01758 01759 Data res(result,resultSize); 01760 DebugLog( << "rsa encrypt of hash is 0x"<< res.hex() ); 01761 01762 Data enc = res.base64encode(); 01763 01764 static char IDENTITY_IN[] = "identity-in"; 01765 static char IDENTITY_IN_HASH[] = "identity-in-hash"; 01766 static char IDENTITY_IN_RSA[] = "identity-in-rsa"; 01767 static char IDENTITY_IN_BASE64[] = "identity-in-base64"; 01768 01769 Security::dumpAsn(IDENTITY_IN, in ); 01770 Security::dumpAsn(IDENTITY_IN_HASH, hashRes ); 01771 Security::dumpAsn(IDENTITY_IN_RSA,res); 01772 Security::dumpAsn(IDENTITY_IN_BASE64,enc); 01773 01774 return enc; 01775 } 01776 01777 01778 bool 01779 BaseSecurity::checkIdentity( const Data& signerDomain, const Data& in, const Data& sigBase64, X509* pCert ) const 01780 { 01781 X509* cert = pCert; 01782 if (!cert) 01783 { 01784 X509Map::const_iterator x=mDomainCerts.find(signerDomain); 01785 if (x == mDomainCerts.end()) 01786 { 01787 ErrLog( << "No public key for " << signerDomain ); 01788 throw Exception("Missing public key when verifying identity",__FILE__,__LINE__); 01789 } 01790 cert = x->second; 01791 } 01792 01793 DebugLog( << "Check identity for " << in ); 01794 DebugLog( << " base64 data is " << sigBase64 ); 01795 01796 Data sig = sigBase64.base64decode(); 01797 DebugLog( << "decoded sig is 0x"<< sig.hex() ); 01798 01799 SHA1Stream sha; 01800 sha << in; 01801 Data hashRes = sha.getBin(); 01802 DebugLog( << "hash of string is 0x" << hashRes.hex() ); 01803 01804 EVP_PKEY* pKey = X509_get_pubkey( cert ); 01805 assert( pKey ); 01806 01807 assert( pKey->type == EVP_PKEY_RSA ); 01808 RSA* rsa = EVP_PKEY_get1_RSA(pKey); 01809 01810 #if 1 01811 int ret = RSA_verify(NID_sha1, (unsigned char *)hashRes.data(), 01812 (unsigned int)hashRes.size(), (unsigned char*)sig.data(), (unsigned int)sig.size(), 01813 rsa); 01814 #else 01815 unsigned char result[4096]; 01816 int resultSize = sizeof(result); 01817 assert( resultSize >= RSA_size(rsa) ); 01818 01819 resultSize = RSA_public_decrypt(sig.size(),(unsigned char*)sig.data(), 01820 result, rsa, RSA_PKCS1_PADDING ); 01821 assert( resultSize != -1 ); 01822 //assert( resultSize == SHA_DIGEST_LENGTH ); 01823 Data recievedHash(result,resultSize); 01824 dumpAsn("identity-out-decrypt", recievedHash ); 01825 01826 bool ret = ( computedHash == recievedHash ); 01827 #endif 01828 01829 DebugLog( << "rsa verify result is " << ret ); 01830 01831 static char IDENTITY_OUT_MSG[] = "identity-out-msg"; 01832 static char IDENTITY_OUT_BASE64[] = "identity-out-base64"; 01833 static char IDENTITY_OUT_SIG[] = "identity-out-sig"; 01834 static char IDENTITY_OUT_HASH[] = "identity-out-hash"; 01835 01836 Security::dumpAsn(IDENTITY_OUT_MSG, in ); 01837 Security::dumpAsn(IDENTITY_OUT_BASE64,sigBase64); 01838 Security::dumpAsn(IDENTITY_OUT_SIG, sig); 01839 Security::dumpAsn(IDENTITY_OUT_HASH, hashRes ); 01840 01841 return (ret != 0); 01842 } 01843 01844 01845 void 01846 BaseSecurity::checkAndSetIdentity(SipMessage& msg, const Data& certDer) const 01847 { 01848 auto_ptr<SecurityAttributes> sec(new SecurityAttributes); 01849 X509* cert=NULL; 01850 01851 try 01852 { 01853 if ( !certDer.empty() ) 01854 { 01855 #if (OPENSSL_VERSION_NUMBER < 0x0090800fL ) 01856 unsigned char* in = (unsigned char*)certDer.data(); 01857 #else 01858 unsigned const char* in = (unsigned const char*)certDer.data(); 01859 #endif 01860 if (d2i_X509(&cert,&in,(long)certDer.size()) == 0) 01861 { 01862 DebugLog(<< "Could not read DER certificate from " << certDer ); 01863 cert = NULL; 01864 } 01865 } 01866 if ( certDer.empty() || cert ) 01867 { 01868 if ( checkIdentity(msg.const_header(h_From).uri().host(), 01869 msg.getCanonicalIdentityString(), 01870 msg.const_header(h_Identity).value(), 01871 cert ) ) 01872 { 01873 sec->setIdentity(msg.const_header(h_From).uri().getAor()); 01874 sec->setIdentityStrength(SecurityAttributes::Identity); 01875 } 01876 else 01877 { 01878 sec->setIdentity(msg.const_header(h_From).uri().getAor()); 01879 sec->setIdentityStrength(SecurityAttributes::FailedIdentity); 01880 } 01881 } 01882 else 01883 { 01884 sec->setIdentity(msg.const_header(h_From).uri().getAor()); 01885 sec->setIdentityStrength(SecurityAttributes::FailedIdentity); 01886 } 01887 } 01888 catch (BaseException& e) 01889 { 01890 ErrLog(<<"Caught exception: "<< e); 01891 sec->setIdentity(msg.const_header(h_From).uri().getAor()); 01892 sec->setIdentityStrength(SecurityAttributes::FailedIdentity); 01893 } 01894 msg.setSecurityAttributes(sec); 01895 } 01896 01897 01898 Contents* 01899 BaseSecurity::decrypt( const Data& decryptorAor, const Pkcs7Contents* contents) 01900 { 01901 01902 DebugLog( << "decryptor Aor: <" << decryptorAor << ">" ); 01903 01904 int flags=0; 01905 flags |= PKCS7_BINARY; 01906 01907 // for now, assume that this is only a singed message 01908 assert( contents ); 01909 01910 Data text = contents->getBodyData(); 01911 DebugLog( << "uncode body = <" << text.escaped() << ">" ); 01912 DebugLog( << "uncode body size = " << text.size() ); 01913 01914 static char RESIP_ASN_DECRYPT[] = "resip-asn-decrypt"; 01915 Security::dumpAsn(RESIP_ASN_DECRYPT, text ); 01916 01917 BIO* in = BIO_new_mem_buf( (void*)text.c_str(), (int)text.size()); 01918 assert(in); 01919 InfoLog( << "created in BIO"); 01920 01921 BIO* out; 01922 out = BIO_new(BIO_s_mem()); 01923 assert(out); 01924 InfoLog( << "created out BIO" ); 01925 01926 PKCS7* pkcs7 = d2i_PKCS7_bio(in, 0); 01927 if ( !pkcs7 ) 01928 { 01929 ErrLog( << "Problems doing decode of PKCS7 object" ); 01930 01931 while (1) 01932 { 01933 const char* file; 01934 int line; 01935 01936 unsigned long code = ERR_get_error_line(&file,&line); 01937 if ( code == 0 ) 01938 { 01939 break; 01940 } 01941 01942 char buf[256]; 01943 ERR_error_string_n(code,buf,sizeof(buf)); 01944 ErrLog( << buf ); 01945 InfoLog( << "Error code = " << code << " file=" << file << " line=" << line ); 01946 } 01947 01948 BIO_free(in); 01949 BIO_free(out); 01950 01951 return 0; 01952 } 01953 (void)BIO_flush(in); 01954 01955 int type=OBJ_obj2nid(pkcs7->type); 01956 switch (type) 01957 { 01958 case NID_pkcs7_signed: 01959 InfoLog( << "data is pkcs7 signed" ); 01960 break; 01961 case NID_pkcs7_signedAndEnveloped: 01962 InfoLog( << "data is pkcs7 signed and enveloped" ); 01963 break; 01964 case NID_pkcs7_enveloped: 01965 InfoLog( << "data is pkcs7 enveloped" ); 01966 break; 01967 case NID_pkcs7_data: 01968 InfoLog( << "data i pkcs7 data" ); 01969 break; 01970 case NID_pkcs7_encrypted: 01971 InfoLog( << "data is pkcs7 encrypted " ); 01972 break; 01973 case NID_pkcs7_digest: 01974 InfoLog( << "data is pkcs7 digest" ); 01975 break; 01976 default: 01977 InfoLog( << "Unknown pkcs7 type" ); 01978 break; 01979 } 01980 01981 STACK_OF(X509)* certs = sk_X509_new_null(); 01982 assert( certs ); 01983 01984 // flags |= PKCS7_NOVERIFY; 01985 01986 assert( mRootTlsCerts ); 01987 01988 switch (type) 01989 { 01990 case NID_pkcs7_signedAndEnveloped: 01991 { 01992 BIO_free(in); 01993 BIO_free(out); 01994 sk_X509_free(certs); 01995 PKCS7_free(pkcs7); 01996 throw Exception("Signed and enveloped is not supported", __FILE__, __LINE__); 01997 } 01998 break; 01999 02000 case NID_pkcs7_enveloped: 02001 { 02002 if (mUserPrivateKeys.count(decryptorAor) == 0) 02003 { 02004 BIO_free(in); 02005 BIO_free(out); 02006 sk_X509_free(certs); 02007 PKCS7_free(pkcs7); 02008 InfoLog( << "Don't have a private key for " << decryptorAor << " for PKCS7_decrypt" ); 02009 throw Exception("Missing private key", __FILE__, __LINE__); 02010 } 02011 else if (mUserCerts.count(decryptorAor) == 0) 02012 { 02013 BIO_free(in); 02014 BIO_free(out); 02015 sk_X509_free(certs); 02016 PKCS7_free(pkcs7); 02017 InfoLog( << "Don't have a public cert for " << decryptorAor << " for PKCS7_decrypt" ); 02018 throw Exception("Missing cert", __FILE__, __LINE__); 02019 } 02020 02021 EVP_PKEY* privateKey = mUserPrivateKeys[decryptorAor]; 02022 X509* publicCert = mUserCerts[decryptorAor]; 02023 02024 if ( PKCS7_decrypt(pkcs7, privateKey, publicCert, out, flags ) != 1 ) 02025 { 02026 ErrLog( << "Problems doing PKCS7_decrypt" ); 02027 while (1) 02028 { 02029 const char* file; 02030 int line; 02031 02032 unsigned long code = ERR_get_error_line(&file,&line); 02033 if ( code == 0 ) 02034 { 02035 break; 02036 } 02037 02038 char buf[256]; 02039 ERR_error_string_n(code,buf,sizeof(buf)); 02040 ErrLog( << buf ); 02041 InfoLog( << "Error code = " << code << " file=" << file << " line=" << line ); 02042 } 02043 02044 BIO_free(in); 02045 BIO_free(out); 02046 sk_X509_free(certs); 02047 PKCS7_free(pkcs7); 02048 return 0; 02049 } 02050 } 02051 break; 02052 02053 default: 02054 BIO_free(in); 02055 BIO_free(out); 02056 sk_X509_free(certs); 02057 PKCS7_free(pkcs7); 02058 ErrLog(<< "Got PKCS7 data that could not be handled type=" << type ); 02059 throw Exception("Unsupported PKCS7 data type", __FILE__, __LINE__); 02060 } 02061 02062 (void)BIO_flush(out); 02063 BUF_MEM* bufMem; 02064 BIO_get_mem_ptr(out, &bufMem); 02065 02066 int len = bufMem->length; 02067 char* buffer = new char[len]; 02068 memcpy(buffer, bufMem->data, len); 02069 02070 (void)BIO_set_close(out, BIO_CLOSE); 02071 BIO_free(in); 02072 BIO_free(out); 02073 sk_X509_free(certs); 02074 PKCS7_free(pkcs7); 02075 02076 // parse out the header information and form new body. 02077 // TODO !jf! this is a really crappy parser - shoudl do proper mime stuff 02078 ParseBuffer pb(buffer, len); 02079 02080 const char* headerStart = pb.position(); 02081 02082 // pull out contents type only 02083 pb.skipToChars("Content-Type"); 02084 pb.assertNotEof(); 02085 02086 pb.skipToChar(Symbols::COLON[0]); 02087 pb.skipChar(); 02088 pb.assertNotEof(); 02089 02090 pb.skipWhitespace(); 02091 const char* typeStart = pb.position(); 02092 pb.assertNotEof(); 02093 02094 // determine contents-type header buffer 02095 pb.skipToTermCRLF(); 02096 pb.assertNotEof(); 02097 02098 ParseBuffer subPb(typeStart, pb.position() - typeStart); 02099 Mime contentType; 02100 contentType.parse(subPb); 02101 02102 pb.assertNotEof(); 02103 02104 // determine body start 02105 pb.reset(typeStart); 02106 const char* bodyStart = pb.skipToChars(Symbols::CRLFCRLF); 02107 pb.assertNotEof(); 02108 bodyStart += 4; 02109 02110 // determine contents body buffer 02111 pb.skipToEnd(); 02112 Data tmp; 02113 pb.data(tmp, bodyStart); 02114 // create contents against body 02115 Contents* ret = Contents::createContents(contentType, tmp); 02116 ret->addBuffer(buffer); 02117 02118 // pre-parse headers 02119 ParseBuffer headersPb(headerStart, bodyStart-4-headerStart); 02120 ret->preParseHeaders(headersPb); 02121 02122 InfoLog( << "Got body data of " << ret->getBodyData() ); 02123 02124 return ret; 02125 } 02126 02127 02128 02129 02130 02131 Contents* 02132 BaseSecurity::checkSignature(MultipartSignedContents* multi, 02133 Data* signedBy, 02134 SignatureStatus* sigStat ) 02135 { 02136 if ( multi->parts().size() != 2 ) 02137 { 02138 ErrLog(<< "Trying to decode a message with wrong number of contents " << multi->parts().size()); 02139 throw Exception("Invalid contents passed to checkSignature", __FILE__, __LINE__); 02140 } 02141 02142 MultipartSignedContents::Parts::const_iterator it = multi->parts().begin(); 02143 Contents* first = *it; 02144 ++it; 02145 assert( it != multi->parts().end() ); 02146 Contents* second = *it; 02147 02148 assert( second ); 02149 assert( first ); 02150 02151 InfoLog( << "message to signature-check is " << *first ); 02152 02153 Pkcs7SignedContents* sig = dynamic_cast<Pkcs7SignedContents*>( second ); 02154 if ( !sig ) 02155 { 02156 ErrLog( << "Don't know how to deal with signature type " ); 02157 //throw Exception("Invalid contents passed to checkSignature", __FILE__, 02158 //__LINE__); 02159 return first; 02160 } 02161 Data sigData = sig->getBodyData(); 02162 02163 Data textData; 02164 DataStream strm( textData ); 02165 first->encodeHeaders( strm ); 02166 first->encode( strm ); 02167 strm.flush(); 02168 02169 InfoLog( << "text <" << textData.escaped() << ">" ); 02170 InfoLog( << "signature <" << sigData.escaped() << ">" ); 02171 02172 static char RESIP_ASN_UNCODE_SIGNED_TEXT[] = "resip-asn-uncode-signed-text"; 02173 static char RESIP_ASN_UNCODE_SIGNED_SIG[] = "resip-asn-uncode-signed-sig"; 02174 02175 Security::dumpAsn( RESIP_ASN_UNCODE_SIGNED_TEXT, textData ); 02176 Security::dumpAsn( RESIP_ASN_UNCODE_SIGNED_SIG, sigData ); 02177 02178 BIO* in = BIO_new_mem_buf( (void*)sigData.data(),(int)sigData.size()); 02179 assert(in); 02180 InfoLog( << "created in BIO"); 02181 02182 BIO* out = BIO_new(BIO_s_mem()); 02183 assert(out); 02184 InfoLog( << "created out BIO" ); 02185 02186 BIO* pkcs7Bio = BIO_new_mem_buf( (void*) textData.data(),(int)textData.size()); 02187 assert(pkcs7Bio); 02188 InfoLog( << "created pkcs7 BIO"); 02189 02190 PKCS7* pkcs7 = d2i_PKCS7_bio(in, 0); 02191 if ( !pkcs7 ) 02192 { 02193 ErrLog( << "Problems doing decode of PKCS7 object <" 02194 << sigData.escaped() << ">" ); 02195 02196 while (1) 02197 { 02198 const char* file; 02199 int line; 02200 02201 unsigned long code = ERR_get_error_line(&file,&line); 02202 if ( code == 0 ) 02203 { 02204 break; 02205 } 02206 02207 char buf[256]; 02208 ERR_error_string_n(code,buf,sizeof(buf)); 02209 ErrLog( << buf ); 02210 InfoLog( <<"Error code = "<< code <<" file=" << file << " line=" << line ); 02211 } 02212 BIO_free(in); 02213 BIO_free(out); 02214 BIO_free(pkcs7Bio); 02215 02216 return first; 02217 } 02218 (void)BIO_flush(in); 02219 02220 int type=OBJ_obj2nid(pkcs7->type); 02221 switch (type) 02222 { 02223 case NID_pkcs7_signed: 02224 InfoLog( << "data is pkcs7 signed" ); 02225 break; 02226 case NID_pkcs7_signedAndEnveloped: 02227 InfoLog( << "data is pkcs7 signed and enveloped" ); 02228 break; 02229 case NID_pkcs7_enveloped: 02230 InfoLog( << "data is pkcs7 enveloped" ); 02231 break; 02232 case NID_pkcs7_data: 02233 InfoLog( << "data is pkcs7 data" ); 02234 break; 02235 case NID_pkcs7_encrypted: 02236 InfoLog( << "data is pkcs7 encrypted " ); 02237 break; 02238 case NID_pkcs7_digest: 02239 InfoLog( << "data is pkcs7 digest" ); 02240 break; 02241 default: 02242 InfoLog( << "Unknown pkcs7 type" ); 02243 break; 02244 } 02245 02246 STACK_OF(X509)* certs = 0; 02247 certs = sk_X509_new_null(); 02248 assert( certs ); 02249 02250 if ( *signedBy == Data::Empty ) 02251 { 02252 //add all the certificates from mUserCerts stack to 'certs' stack 02253 for(X509Map::iterator it = mUserCerts.begin(); it != mUserCerts.end(); it++) 02254 { 02255 assert(it->second); 02256 sk_X509_push(certs, it->second); 02257 } 02258 } 02259 else 02260 { 02261 if (mUserCerts.count( *signedBy )) 02262 { 02263 InfoLog( <<"Adding cert from " << *signedBy << " to check sig" ); 02264 X509* cert = mUserCerts[ *signedBy ]; 02265 assert(cert); 02266 sk_X509_push(certs, cert); 02267 } 02268 } 02269 02270 int flags = 0; 02271 flags |= PKCS7_NOINTERN; 02272 02273 // matches on certificate issuer and serial number - they must be unique 02274 STACK_OF(X509)* signers = PKCS7_get0_signers(pkcs7, certs, flags); 02275 if ( signers ) 02276 { 02277 02278 DebugLog( << "Found " << sk_X509_num(signers) << " signers." ); 02279 for (int i=0; i<sk_X509_num(signers); i++) 02280 { 02281 X509* x = sk_X509_value(signers, i); 02282 InfoLog(<< "Got a signer <" << i << "> : " << getCertName(x) ); 02283 02284 GENERAL_NAMES* gens = 0; 02285 gens = (GENERAL_NAMES*)X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL); 02286 02287 for (int j = 0; j < sk_GENERAL_NAME_num(gens); j++) 02288 { 02289 GENERAL_NAME* gen = sk_GENERAL_NAME_value(gens, j); 02290 if (gen->type == GEN_URI) 02291 { 02292 ASN1_IA5STRING* uri = gen->d.uniformResourceIdentifier; 02293 Data name(uri->data, uri->length); 02294 InfoLog(<< "subjectAltName of signing cert contains <" << name << ">" ); 02295 try 02296 { 02297 Uri n(name); 02298 if ( n.scheme() == "sip" ) 02299 { 02300 *signedBy = name; 02301 InfoLog(<< "choose <" << name << "> signature" ); 02302 } 02303 } 02304 catch (ParseException& e) 02305 { 02306 ErrLog(<<"Caught exception: "<< e); 02307 } 02308 } 02309 } 02310 02311 sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); 02312 } 02313 } 02314 else 02315 { 02316 BIO_free(in); 02317 BIO_free(out); 02318 BIO_free(pkcs7Bio); 02319 sk_X509_free(certs); 02320 PKCS7_free(pkcs7); 02321 *sigStat = SignatureIsBad; 02322 InfoLog(<< "No valid signers of this messages" ); 02323 return first; 02324 } 02325 02326 #if 0 02327 // this is debugging information to get the serial number of the signed 02328 // information 02329 STACK_OF(PKCS7_SIGNER_INFO) *sinfos; 02330 PKCS7_SIGNER_INFO *si; 02331 PKCS7_ISSUER_AND_SERIAL *ias; 02332 ASN1_INTEGER* asnSerial; 02333 long longSerial; 02334 X509_NAME* name; 02335 02336 sinfos = PKCS7_get_signer_info(pkcs7); 02337 if ( sinfos ) 02338 { 02339 int num = sk_PKCS7_SIGNER_INFO_num(sinfos); 02340 for ( int i=0; i<num; i++ ) 02341 { 02342 si = sk_PKCS7_SIGNER_INFO_value (sinfos, i) ; 02343 ias = si->issuer_and_serial; 02344 name = ias->issuer; 02345 asnSerial = ias->serial; 02346 longSerial = ASN1_INTEGER_get( (ASN1_INTEGER*)asnSerial ); 02347 InfoLog( << "Signed with serial " << hex << longSerial ); 02348 InfoLog( << "Name " << name ); 02349 } 02350 } 02351 #endif 02352 02353 assert( mRootTlsCerts ); 02354 02355 switch (type) 02356 { 02357 case NID_pkcs7_signed: 02358 { 02359 int flags = 0; 02360 02361 if (isSelfSigned(sk_X509_value(signers,0))) 02362 { 02363 flags |= PKCS7_NOVERIFY; 02364 } 02365 02366 if ( PKCS7_verify(pkcs7, certs, mRootTlsCerts, pkcs7Bio, out, flags ) != 1 ) 02367 { 02368 ErrLog( << "Problems doing PKCS7_verify" ); 02369 02370 if ( sigStat ) 02371 { 02372 *sigStat = SignatureIsBad; 02373 } 02374 02375 while (1) 02376 { 02377 const char* file; 02378 int line; 02379 02380 unsigned long code = ERR_get_error_line(&file,&line); 02381 if ( code == 0 ) 02382 { 02383 break; 02384 } 02385 02386 char buf[256]; 02387 ERR_error_string_n(code,buf,sizeof(buf)); 02388 ErrLog( << buf ); 02389 InfoLog( << "Error code = " << code << " file=" << file << " line=" << line ); 02390 } 02391 BIO_free(in); 02392 BIO_free(out); 02393 BIO_free(pkcs7Bio); 02394 sk_X509_free(certs); 02395 PKCS7_free(pkcs7); 02396 return first; 02397 } 02398 if ( sigStat ) 02399 { 02400 if ( (flags & PKCS7_NOVERIFY) ) 02401 { 02402 if (isSelfSigned(sk_X509_value(signers,0))) 02403 { 02404 DebugLog( << "Signature is selfSigned"); 02405 *sigStat = SignatureSelfSigned; 02406 } 02407 else 02408 { 02409 DebugLog( << "Signature is notTrusted" ); 02410 *sigStat = SignatureNotTrusted; 02411 } 02412 } 02413 else 02414 { 02415 if (false) // !jf! TODO look for this cert in store 02416 { 02417 DebugLog( << "Signature is trusted" ); 02418 *sigStat = SignatureTrusted; 02419 } 02420 else 02421 { 02422 DebugLog( << "Signature is caTrusted" ); 02423 *sigStat = SignatureCATrusted; 02424 } 02425 } 02426 } 02427 } 02428 break; 02429 02430 default: 02431 BIO_free(in); 02432 BIO_free(out); 02433 BIO_free(pkcs7Bio); 02434 sk_X509_free(certs); 02435 PKCS7_free(pkcs7); 02436 ErrLog(<< "Got PKCS7 data that could not be handled type=" << type ); 02437 return 0; 02438 } 02439 02440 (void)BIO_flush(out); 02441 char* outBuf=0; 02442 long size = BIO_get_mem_data(out,&outBuf); 02443 assert( size >= 0 ); 02444 02445 Data outData(outBuf,size); 02446 DebugLog( << "uncoded body is <" << outData.escaped() << ">" ); 02447 02448 BIO_free(in); 02449 BIO_free(out); 02450 BIO_free(pkcs7Bio); 02451 sk_X509_free(certs); 02452 PKCS7_free(pkcs7); 02453 return first; 02454 } 02455 02456 02457 SSL_CTX* 02458 BaseSecurity::getTlsCtx () 02459 { 02460 assert(mTlsCtx); 02461 return mTlsCtx; 02462 } 02463 02464 02465 SSL_CTX* 02466 BaseSecurity::getSslCtx () 02467 { 02468 assert(mSslCtx); 02469 return mSslCtx; 02470 } 02471 02472 void 02473 BaseSecurity::getCertNames(X509 *cert, std::list<PeerName> &peerNames, 02474 bool useEmailAsSIP) 02475 { 02476 if(NULL == cert) 02477 return; 02478 02479 if(peerNames.size() > 0) 02480 peerNames.clear(); 02481 02482 Data commonName; 02483 02484 // look at the Common Name to find the peerName of the cert 02485 X509_NAME* subject = X509_get_subject_name(cert); 02486 if(NULL == subject) 02487 { 02488 ErrLog( << "Invalid certificate: subject not found "); 02489 return; 02490 } 02491 02492 int i =-1; 02493 while( true ) 02494 { 02495 i = X509_NAME_get_index_by_NID(subject, NID_commonName,i); 02496 if ( i == -1 ) 02497 { 02498 break; 02499 } 02500 assert( i != -1 ); 02501 X509_NAME_ENTRY* entry = X509_NAME_get_entry(subject,i); 02502 assert( entry ); 02503 02504 ASN1_STRING* s = X509_NAME_ENTRY_get_data(entry); 02505 assert( s ); 02506 02507 int t = M_ASN1_STRING_type(s); 02508 int l = M_ASN1_STRING_length(s); 02509 unsigned char* d = M_ASN1_STRING_data(s); 02510 Data name(d,l); 02511 DebugLog( << "got x509 string type=" << t << " len="<< l << " data=" << d ); 02512 assert( name.size() == (unsigned)l ); 02513 02514 DebugLog( << "Found common name in cert of " << name ); 02515 02516 commonName = name; 02517 } 02518 02519 #if 0 // junk code to print certificates extentions for debugging 02520 int numExt = X509_get_ext_count(cert); 02521 ErrLog(<< "Got peer certificate with " << numExt << " extentions" ); 02522 02523 for ( int i=0; i<numExt; i++ ) 02524 { 02525 X509_EXTENSION* ext = X509_get_ext(cert,i); 02526 assert( ext ); 02527 02528 const char* str = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext))); 02529 assert(str); 02530 DebugLog(<< "Got certificate extention" << str ); 02531 02532 if ( OBJ_obj2nid(X509_EXTENSION_get_object(ext)) == NID_subject_alt_name ) 02533 { 02534 DebugLog(<< "Got subjectAltName extention" ); 02535 } 02536 } 02537 #endif 02538 02539 // Look at the SubjectAltName, and if found, set as peerName 02540 GENERAL_NAMES* gens; 02541 gens = (GENERAL_NAMES*)X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); 02542 for(int i = 0; i < sk_GENERAL_NAME_num(gens); i++) 02543 { 02544 GENERAL_NAME* gen = sk_GENERAL_NAME_value(gens, i); 02545 02546 DebugLog(<< "subjectAltName of cert contains type <" << gen->type << ">" ); 02547 02548 if (gen->type == GEN_DNS) 02549 { 02550 ASN1_IA5STRING* asn = gen->d.dNSName; 02551 Data dns(asn->data, asn->length); 02552 PeerName peerName(SubjectAltName, dns); 02553 peerNames.push_back(peerName); 02554 InfoLog(<< "subjectAltName of TLS session cert contains DNS <" << dns << ">" ); 02555 } 02556 02557 if (gen->type == GEN_EMAIL) 02558 { 02559 if(useEmailAsSIP) 02560 { 02561 ASN1_IA5STRING* asn = gen->d.rfc822Name; 02562 Data email(asn->data, asn->length); 02563 PeerName peerName(SubjectAltName, email); 02564 peerNames.push_back(peerName); 02565 InfoLog(<< "subjectAltName of TLS session cert contains EMAIL <" << email << ">" ); 02566 } 02567 else 02568 DebugLog(<< "subjectAltName of cert has EMAIL type" ); 02569 } 02570 02571 if(gen->type == GEN_URI) 02572 { 02573 ASN1_IA5STRING* asn = gen->d.uniformResourceIdentifier; 02574 Uri uri(Data(asn->data, asn->length)); 02575 try 02576 { 02577 PeerName peerName(SubjectAltName, uri.host()); 02578 peerNames.push_back(peerName); 02579 InfoLog(<< "subjectAltName of TLS session cert contains URI <" << uri << ">" ); 02580 } 02581 catch (...) 02582 { 02583 InfoLog(<< "subjectAltName of TLS session cert contains unparseable URI"); 02584 } 02585 } 02586 } 02587 sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); 02588 02589 // If there are no peer names from the subjectAltName, then use the commonName 02590 if(peerNames.empty()) 02591 { 02592 PeerName peerName(CommonName, commonName); 02593 peerNames.push_back(peerName); 02594 } 02595 } 02596 02597 Data 02598 BaseSecurity::getCertName(X509 *cert) 02599 { 02600 Data certName; 02601 std::list<PeerName> cNames; 02602 02603 //get all the names (subjectAltName or CommonName) 02604 getCertNames(cert, cNames); 02605 02606 //prefere the subjectAltName 02607 for(std::list<PeerName>::const_iterator it = cNames.begin(); it != cNames.end(); it++) 02608 { 02609 if(it->mType == SubjectAltName) 02610 { 02611 return it->mName; 02612 } 02613 } 02614 02615 //if not subjectAltName found, get the CommonName 02616 for(std::list<PeerName>::const_iterator it = cNames.begin(); it != cNames.end(); it++) 02617 { 02618 if(it->mType == CommonName) 02619 { 02620 return it->mName; 02621 } 02622 } 02623 ErrLog(<< "This certificate doesn't have neither subjectAltName nor commonName"); 02624 return Data::Empty; 02625 } 02629 int 02630 BaseSecurity::matchHostName(const Data& certificateName, const Data& domainName) 02631 { 02632 if(mAllowWildcardCertificates) 02633 return matchHostNameWithWildcards(certificateName,domainName); 02634 return isEqualNoCase(certificateName,domainName); 02635 } 02640 int 02641 BaseSecurity::matchHostNameWithWildcards(const Data& certificateName, const Data& domainName) 02642 { 02643 const char *dot = NULL; 02644 02645 const char *certName = certificateName.c_str(); 02646 if(certName == NULL) 02647 return 0; 02648 02649 const char *domName = domainName.c_str(); 02650 if(domName == NULL) 02651 return 0; 02652 02653 dot = strchr(domName, '.'); 02654 if (dot == NULL) 02655 { 02656 char *pnt = (char *)strchr(certName, '.'); // bad 02657 /* hostname is not fully-qualified; unqualify the certName. */ 02658 if (pnt != NULL) 02659 { 02660 *pnt = '\0'; 02661 } 02662 } 02663 else 02664 { 02665 if (strncmp(certName, "*.", 2) == 0) 02666 { 02667 domName = dot + 1; 02668 certName += 2; 02669 } 02670 } 02671 return !strcasecmp(certName, domName); 02672 } 02673 02674 bool 02675 BaseSecurity::isSelfSigned(const X509 *cert) 02676 { 02677 int iRet = X509_NAME_cmp(cert->cert_info->issuer, cert->cert_info->subject); 02678 return (iRet == 0); 02679 } 02680 02681 void 02682 BaseSecurity::dumpAsn( char* name, Data data) 02683 { 02684 #if 0 // for debugging 02685 assert(name); 02686 02687 if (true) // dump asn.1 stuff to debug file 02688 { 02689 ofstream strm(name, std::ios_base::trunc); 02690 if ( !strm ) 02691 { 02692 ErrLog( <<"Could not write to " << name ); 02693 } 02694 else 02695 { 02696 strm.write( data.data() , data.size() ); 02697 } 02698 strm.flush(); 02699 } 02700 #endif 02701 } 02702 02703 X509* 02704 BaseSecurity::getDomainCert( const Data& domain ) 02705 { 02706 return mDomainCerts.count(domain) ? mDomainCerts[domain] : 0; 02707 } 02708 02709 X509* 02710 BaseSecurity::getUserCert( const Data& aor ) 02711 { 02712 return mUserCerts.count(aor) ? mUserCerts[aor] : 0; 02713 } 02714 02715 EVP_PKEY* 02716 BaseSecurity::getDomainKey( const Data& domain ) 02717 { 02718 return mDomainPrivateKeys.count(domain) ? mDomainPrivateKeys[domain] : 0; 02719 } 02720 02721 EVP_PKEY* 02722 BaseSecurity::getUserPrivateKey( const Data& aor ) 02723 { 02724 return mUserPrivateKeys.count(aor) ? mUserPrivateKeys[aor] : 0; 02725 } 02726 02727 #endif 02728 02729 02730 02731 02732 /* ==================================================================== 02733 * The Vovida Software License, Version 1.0 02734 * 02735 * Copyright (c) 2002-2005 Vovida Networks, Inc. All rights reserved. 02736 * 02737 * Redistribution and use in source and binary forms, with or without 02738 * modification, are permitted provided that the following conditions 02739 * are met: 02740 * 02741 * 1. Redistributions of source code must retain the above copyright 02742 * notice, this list of conditions and the following disclaimer. 02743 * 02744 * 2. Redistributions in binary form must reproduce the above copyright 02745 * notice, this list of conditions and the following disclaimer in 02746 * the documentation and/or other materials provided with the 02747 * distribution. 02748 * 02749 * 3. The names "VOCAL", "Vovida Open Communication Application Library", 02750 * and "Vovida Open Communication Application Library (VOCAL)" must 02751 * not be used to endorse or promote products derived from this 02752 * software without prior written permission. For written 02753 * permission, please contact vocal@vovida.org. 02754 * 02755 * 4. Products derived from this software may not be called "VOCAL", nor 02756 * may "VOCAL" appear in their name, without prior written 02757 * permission of Vovida Networks, Inc. 02758 * 02759 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED 02760 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 02761 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND 02762 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA 02763 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES 02764 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, 02765 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 02766 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 02767 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 02768 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 02769 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 02770 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 02771 * DAMAGE. 02772 * 02773 * ==================================================================== 02774 * 02775 * This software consists of voluntary contributions made by Vovida 02776 * Networks, Inc. and many individuals on behalf of Vovida Networks, 02777 * Inc. For more information on Vovida Networks, Inc., please see 02778 * <http://www.vovida.org/>. 02779 * 02780 */
1.7.5.1