reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
Security.cxx
Go to the documentation of this file.
1#if defined(HAVE_CONFIG_H)
2#include "config.h"
3#endif
4
5#ifdef USE_SSL
6
9
10#include <ostream>
11#include <fstream>
12#include <stdexcept>
13
22#include "rutil/ResipAssert.h"
24#include "rutil/DataStream.hxx"
25#include "rutil/Logger.hxx"
26#include "rutil/Random.hxx"
27#include "rutil/Socket.hxx"
28#include "rutil/Timer.hxx"
29#include "rutil/ParseBuffer.hxx"
30#include "rutil/DnsUtil.hxx"
31#include "rutil/FileSystem.hxx"
33
34#if !defined(WIN32)
35#include <sys/types.h>
36#include <sys/uio.h>
37#if defined(__ANDROID__)
38#include <fcntl.h>
39#else
40#include <sys/fcntl.h>
41#endif
42#include <unistd.h>
43#include <dirent.h>
44#endif
45
46#include <sys/types.h>
47#include <openssl/opensslv.h>
48#include <openssl/dh.h>
49#include <openssl/evp.h>
50#include <openssl/crypto.h>
51#include <openssl/err.h>
52#include <openssl/pem.h>
53#include <openssl/pkcs7.h>
54#include <openssl/ossl_typ.h>
55#include <openssl/rsa.h>
56#include <openssl/x509.h>
57#include <openssl/x509v3.h>
58#include <openssl/ssl.h>
59
60using namespace resip;
61using namespace std;
62
63#define RESIPROCATE_SUBSYSTEM Subsystem::SIP
64
65static const Data PEM(".pem");
66
67static const Data rootCert("root_cert_");
68static const Data domainCert("domain_cert_");
69static const Data domainKey("domain_key_");
70static const Data userCert("user_cert_");
71static const Data userKey("user_key_");
72static const Data unknownKey("user_key_");
73
74static const Data
76{
77 switch (pType)
78 {
79 case Security::RootCert: return rootCert;
80 case Security::DomainCert: return domainCert;
81 case Security::DomainPrivateKey: return domainKey;
82 case Security::UserCert: return userCert;
83 case Security::UserPrivateKey: return userKey;
84 default:
85 {
86 ErrLog( << "Unknown pem type prefix requested" << (int)(pType) );
87 resip_assert(0);
88 }
89 }
90 return unknownKey;
91}
92
93static Data
94getAor(const Data& filename, const Security::PEMType &pemType )
95{
96 const Data& prefix = pemTypePrefixes( pemType );
97 return filename.substr(prefix.size(), filename.size() - prefix.size() - PEM.size());
98}
99
100// Use static method and idx so it initializes on first call and after OpenSSL has performed it's initialization
102{
103 static int idx = SSL_get_ex_new_index(0, nullptr, nullptr, nullptr, nullptr);
104 return idx;
105}
106
107extern "C"
108{
109
110static int
111verifyCallback(int preverifyOk, X509_STORE_CTX* storeCtx)
112{
113 if (!preverifyOk)
114 {
115 char subjectNameBuf[256] = {0};
116 X509* cert = X509_STORE_CTX_get_current_cert(storeCtx); // Doesn't require X509_free call
117 int errorCode = X509_STORE_CTX_get_error(storeCtx);
118 // This is a nonnegative integer representing where in the certificate chain the error occurred.
119 // If it is zero it occurred in the end entity certificate, one if it is the certificate which
120 // signed the end entity certificate and so on.
121 int errorDepth = X509_STORE_CTX_get_error_depth(storeCtx);
122
123 if (cert)
124 {
125 // Use modern, safe subject name formatting
126 BIO* bio = BIO_new(BIO_s_mem());
127 if (bio)
128 {
129 const X509_NAME* subjectName = X509_get_subject_name(cert);
130 if (subjectName)
131 {
132 // RFC 2253 is the preferred format (readable and reversible)
133 X509_NAME_print_ex(bio, subjectName, 0, XN_FLAG_RFC2253);
134 BIO_gets(bio, subjectNameBuf, sizeof(subjectNameBuf));
135 }
136 BIO_free(bio);
137 }
138 }
139
140 // Retrieve the associated resip transport connection object (if available)
141 SSL* ssl = (SSL*)X509_STORE_CTX_get_ex_data(storeCtx, SSL_get_ex_data_X509_STORE_CTX_idx());
142 ConnectionBase* connection = nullptr;
143 if (ssl)
144 {
145 connection = (ConnectionBase*)SSL_get_ex_data(ssl, BaseSecurity::getResipConnectionExDataIdx());
146 }
147
148 Data errorString;
149 {
150 DataStream ds(errorString);
151 ds << "'" << X509_verify_cert_error_string(errorCode) << "', errorDepth=" << errorDepth << ", subjectName=[" << subjectNameBuf << "]";
152 }
153
154 if (connection)
155 {
156 connection->addAdditionalFailureString(errorString);
157 ErrLog(<< "Error when verifying peer's chain of certificates: tuple=" << connection->who() << ", error=" << errorString);
158 }
159 else
160 {
161 ErrLog(<< "Error when verifying peer's chain of certificates: error=" << errorString);
162 }
163 }
164
165 return preverifyOk;
166}
167
168}
169
170// .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.
172BaseSecurity::CipherList BaseSecurity::ExportableSuite("HIGH:RC4-SHA:-COMPLEMENTOFDEFAULT");
173BaseSecurity::CipherList BaseSecurity::StrongestSuite("HIGH:-COMPLEMENTOFDEFAULT");
174
185long BaseSecurity::OpenSSLCTXSetOptions = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION;
187
188Security::Security(const CipherList& cipherSuite, const Data& defaultPrivateKeyPassPhrase, const Data& dHParamsFilename) :
189 BaseSecurity(cipherSuite, defaultPrivateKeyPassPhrase, dHParamsFilename)
190{
191#ifdef WIN32
192 mPath = "C:\\sipCerts\\";
193#else
194 const char* env=getenv("HOME");
195 if(env)
196 {
197 mPath = env;
198 }
199 mPath += "/.sipCerts/";
200#endif
201}
202
203Security::Security(const Data& directory, const CipherList& cipherSuite, const Data& defaultPrivateKeyPassPhrase, const Data& dHParamsFilename) :
204 BaseSecurity(cipherSuite, defaultPrivateKeyPassPhrase, dHParamsFilename),
205 mPath(directory)
206{
207 // since the preloader won't work otherwise and VERY difficult to figure out.
208 if (!mPath.empty() && !mPath.postfix(Symbols::SLASH))
209 {
210 mPath += Symbols::SLASH;
211 }
212}
213
214void
216{
217 mCADirectories.push_back(caDirectory);
218 Data &_dir = mCADirectories.back();
219 if ( !_dir.postfix(Symbols::SLASH))
220 {
221 _dir += Symbols::SLASH;
222 }
223}
224
225void
227{
228 mCAFiles.push_back(caFile);
229}
230
231void
233{
234 FileSystem::Directory dir(_dir);
236 for (; it != dir.end(); ++it)
237 {
238 try
239 {
240 if (!it.is_directory()) // This can throw!
241 {
242 Data name = *it;
243 Data fileName = _dir + name;
244 loadCAFile(fileName);
245 }
246 }
247 catch (const BaseException& e)
248 {
249 ErrLog(<< "loadCADirectory: Some problem reading " << *it << ": " << e);
250 }
251 catch (...)
252 {
253 ErrLog(<< "loadCADirectory: Some problem reading " << *it);
254 }
255 }
256}
257
258void
260{
261 try
262 {
264 InfoLog(<<"Successfully loaded " << _file);
265 }
266 catch (Exception& e)
267 {
268 ErrLog(<< "loadCAFile: Some problem reading " << _file << ": " << e);
269 }
270 catch (...)
271 {
272 ErrLog(<< "loadCAFile: Some problem reading " << _file);
273 }
274}
275
276void
278{
279 int count = 0;
280#ifndef WIN32
281 // We only do this for UNIX platforms at present
282 // If no other source of trusted roots exists,
283 // and if mPath is a file, check if it is a root certificate
284 // or a collection of root certificates
285 struct stat s;
286 Data fileName(mPath);
287 if (fileName.postfix("/"))
288 {
289 fileName.truncate(fileName.size() - 1);
290 }
291 if (fileName.size() > 0)
292 {
293 StackLog(<< "calling stat() for " << fileName);
294 if (stat(fileName.c_str(), &s) < 0)
295 {
296 ErrLog(<< "Error calling stat() for " << fileName.c_str()
297 << ": " << strError(errno));
298 }
299 else
300 {
301 if (!S_ISDIR(s.st_mode))
302 {
303 WarningLog(<< "mPath argument is a file rather than a directory, "
304 "treating mPath as a file of trusted root certificates");
305 loadCAFile(fileName);
306 count++;
307 }
308 }
309 }
310#endif
311
312 FileSystem::Directory dir(mPath);
314 for (; it != dir.end(); ++it)
315 {
316 Data name = *it;
317
318 if (name.postfix(PEM))
319 {
320 Data fileName = mPath + name;
321 bool attemptedToLoad = true;
322
323 DebugLog(<< "Checking to load file " << name);
324 try
325 {
326 if (name.prefix(pemTypePrefixes(UserCert)))
327 {
328 addCertPEM(UserCert, getAor(name, UserCert), Data::fromFile(fileName), false);
329 }
330 else if (name.prefix(pemTypePrefixes(UserPrivateKey)))
331 {
333 }
334 else if (name.prefix(pemTypePrefixes(DomainCert)))
335 {
336 addCertPEM(DomainCert, getAor(name, DomainCert), Data::fromFile(fileName), false);
337 }
338 else if (name.prefix(pemTypePrefixes(DomainPrivateKey)))
339 {
341 }
342 else if (name.prefix(pemTypePrefixes(RootCert)))
343 {
345 }
346 else
347 {
348 DebugLog(<< "PEM file " << name << " does not have appropriate resip prefix, skipping...");
349 attemptedToLoad = false;
350 }
351 }
352 catch (const BaseException& e)
353 {
354 ErrLog(<< "Some problem reading " << fileName << ": " << e);
355 }
356 catch (...)
357 {
358 ErrLog(<< "Some problem reading " << fileName);
359 }
360
361 if (attemptedToLoad)
362 {
363 InfoLog(<< "Successfully loaded " << fileName);
364 count++;
365 }
366 }
367 }
368 InfoLog(<< "Files loaded by prefix: " << count);
369
370 if (count == 0 && mCADirectories.empty() && mCAFiles.empty() && mPath.size() > 0)
371 {
372 // If no other source of trusted roots exists,
373 // assume mPath was meant to be in mCADirectories
374 InfoLog(<< "No root certificates found using legacy prefixes, "
375 "treating mPath=" << mPath << " as a normal directory of root certs");
376 loadCADirectory(mPath);
377 }
378
379 std::list<Data>::iterator it_d = mCADirectories.begin();
380 for (; it_d != mCADirectories.end(); ++it_d)
381 {
382 loadCADirectory(*it_d);
383 }
384
385 std::list<Data>::iterator it_f = mCAFiles.begin();
386 for (; it_f != mCAFiles.end(); ++it_f)
387 {
388 loadCAFile(*it_f);
389 }
390}
391
392// Generic password callback to copy over provided userdata/password
393int pem_passwd_cb(char *buf, int size, int rwflag, void *password)
394{
395 if(password)
396 {
397 snprintf(buf, size, "%s", (char*)password);
398 return (int)strlen(buf);
399 }
400 else
401 {
402 return 0;
403 }
404}
405
406SSL_CTX*
407Security::createDomainCtx(const SSL_METHOD* method, const Data& domain, const Data& certificateFilename, const Data& privateKeyFilename, const Data& privateKeyPassPhrase)
408{
409 SSL_CTX* ctx = SSL_CTX_new(method);
410 resip_assert(ctx);
411
412 // Share the root certificate store with Security's own SSL_CTXs (every root
413 // certificate is added to it), so roots added after this transport was
414 // created are trusted too. set1 takes a reference of its own.
415 SSL_CTX_set1_cert_store(ctx, mRootSslCerts);
416
417 try
418 {
419 updateDomainCtx(ctx, domain, certificateFilename, privateKeyFilename, privateKeyPassPhrase);
420 }
421 catch(...)
422 {
423 SSL_CTX_free(ctx);
424 throw;
425 }
426
427 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, verifyCallback);
428 SSL_CTX_set_cipher_list(ctx, mCipherList.cipherList().c_str());
429 setDHParams(ctx);
430 SSL_CTX_set_options(ctx, BaseSecurity::OpenSSLCTXSetOptions);
431 SSL_CTX_clear_options(ctx, BaseSecurity::OpenSSLCTXClearOptions);
432
433 // A server that asks for client certificates (SSL_VERIFY_PEER) needs a
434 // session id context, or OpenSSL fails the handshake of any client that
435 // tries to resume a session (SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED)
436 // instead of doing a full one. Derived from the domain so sessions are
437 // only resumed in the context they were set up in.
438 const Data sessionContext(Data("resip:") + domain);
439 unsigned char sessionIdContext[EVP_MAX_MD_SIZE];
440 unsigned int sessionIdContextLength = 0;
441 if(EVP_Digest(sessionContext.data(), sessionContext.size(), sessionIdContext,
442 &sessionIdContextLength, EVP_sha256(), nullptr) != 1 ||
443 sessionIdContextLength > SSL_MAX_SID_CTX_LENGTH ||
444 SSL_CTX_set_session_id_context(ctx, sessionIdContext, sessionIdContextLength) != 1)
445 {
446 WarningLog(<< "Failed to set the TLS session id context for domain " << domain
447 << ", clients verified with a certificate can't resume sessions");
448 }
449
450 return ctx;
451}
452
453void
454Security::updateDomainCtx(SSL_CTX* ctx, const Data& domain, const Data& certificateFilename, const Data& privateKeyFilename, const Data& privateKeyPassPhrase)
455{
456 // Load domain cert chain and private key
457 if(!domain.empty())
458 {
459 // Set Private Key PassPhrase
460 SSL_CTX_set_default_passwd_cb(ctx, pem_passwd_cb);
461 if(!privateKeyPassPhrase.empty())
462 {
463 SSL_CTX_set_default_passwd_cb_userdata(ctx, (void*)privateKeyPassPhrase.c_str());
464 }
465 Data certFilename(certificateFilename.empty() ? mPath + pemTypePrefixes(DomainCert) + domain + PEM : certificateFilename);
466 if(SSL_CTX_use_certificate_chain_file(ctx, certFilename.c_str()) != 1)
467 {
468 ErrLog (<< "Error reading domain chain file " << certFilename);
469 throw BaseSecurity::Exception("Failed opening PEM chain file", __FILE__,__LINE__);
470 }
471
472 // Check if we have the domain cert in the main storage yet - needed for Identity header calculations
473 if(mDomainCerts.find(domain) == mDomainCerts.end())
474 {
475 // Add to storage
476 addCertPEM( DomainCert, domain, Data::fromFile(certFilename), false);
477 InfoLog(<< "Security::updateDomainCtx: Successfully loaded domain cert and added to Security storage, domain=" << domain << ", filename=" << certFilename);
478 }
479 else
480 {
481 InfoLog(<< "Security::updateDomainCtx: Successfully loaded domain cert, domain=" << domain << ", filename=" << certFilename);
482 }
483
484 Data keyFilename(privateKeyFilename.empty() ? mPath + pemTypePrefixes(DomainPrivateKey) + domain + PEM : privateKeyFilename);
485 if(SSL_CTX_use_PrivateKey_file(ctx, keyFilename.c_str(), SSL_FILETYPE_PEM) != 1)
486 {
487 ErrLog (<< "Error reading domain private key file " << keyFilename);
488 throw BaseSecurity::Exception("Failed opening PEM private key file", __FILE__,__LINE__);
489 }
490 if (!SSL_CTX_check_private_key(ctx))
491 {
492 ErrLog (<< "Invalid domain private key from file: " << keyFilename);
493 throw BaseSecurity::Exception("Invalid domain private key", __FILE__,__LINE__);
494 }
495
496 // Check if we have the domain cert in the main storage yet - needed for Identity header calculations
497 if(mDomainPrivateKeys.find(domain) == mDomainPrivateKeys.end())
498 {
499 // Add to storage
500 addPrivateKeyPEM( DomainPrivateKey, domain, Data::fromFile(keyFilename), false, privateKeyPassPhrase);
501 InfoLog(<< "Security::updateDomainCtx: Successfully loaded domain private key and added to Security storage, domain=" << domain << ", filename=" << keyFilename);
502 }
503 else
504 {
505 InfoLog(<< "Security::updateDomainCtx: Successfully loaded domain private key, domain=" << domain << ", filename=" << keyFilename);
506 }
507 }
508}
509
510void
511Security::onReadPEM(const Data& name, PEMType type, Data& buffer) const
512{
513 Data filename = mPath + pemTypePrefixes(type) + name + PEM;
514
515 InfoLog (<< "Reading PEM file " << filename << " for " << name);
516 // .dlb. extra copy
517 buffer = Data::fromFile(filename);
518}
519
520void
521Security::onWritePEM(const Data& name, PEMType type, const Data& buffer) const
522{
523 Data filename = mPath + pemTypePrefixes(type) + name + PEM;
524 InfoLog (<< "Writing PEM file " << filename << " for " << name);
525 ofstream str(filename.c_str(), ios::binary);
526 if (!str)
527 {
528 ErrLog (<< "Can't write to " << filename);
529 throw BaseSecurity::Exception("Failed opening PEM file", __FILE__,__LINE__);
530 }
531 else
532 {
533 str.write(buffer.data(), buffer.size());
534 if (!str)
535 {
536 ErrLog (<< "Failed writing to " << filename << " " << buffer.size() << " bytes");
537 throw BaseSecurity::Exception("Failed writing PEM file", __FILE__,__LINE__);
538 }
539 }
540}
541
542void
543Security::onRemovePEM(const Data& name, PEMType type) const
544{
545 resip_assert(0);
546 // TODO - should delete file
547}
548
549void
551 const Data& key,
552 const Data& certDER,
553 bool write)
554{
555 if( certDER.empty() )
556 {
557 ErrLog(<< "File is empty. Skipping.");
558 return;
559 }
560
561 X509* cert = 0;
562
563 unsigned const char* in = (unsigned const char*)certDER.data();
564 if (d2i_X509(&cert,&in,(long)certDER.size()) == 0)
565 {
566 ErrLog(<< "Could not read DER certificate from " << certDER );
567 throw BaseSecurity::Exception("Could not read DER certificate ",
568 __FILE__,__LINE__);
569 }
570 addCertX509(type,key,cert,write);
571}
572
573void
575 const Data& name,
576 const Data& certPEM,
577 bool write)
578{
579 if( certPEM.empty() )
580 {
581 ErrLog(<< name << " is empty. Skipping.");
582 return;
583 }
584 X509* cert=NULL;
585
586 BIO* in = BIO_new_mem_buf(const_cast<char*>(certPEM.c_str()), -1);
587 if ( !in )
588 {
589 ErrLog(<< "Could not create BIO buffer from '" << certPEM << "'");
590 throw Exception("Could not create BIO buffer", __FILE__,__LINE__);
591 }
592 while(!BIO_eof(in))
593 {
594 cert = PEM_read_bio_X509(in,0,0,0);
595 if (cert == NULL)
596 {
597 ErrLog( << "Could not load X509 cert from '" << certPEM << "'" );
598 BIO_free(in);
599 throw Exception("Could not load X509 cert from BIO buffer", __FILE__,__LINE__);
600 }
601
602 addCertX509(type,name,cert,write);
603 if(type != RootCert)
604 {
605 break;
606 }
607 }
608
609 BIO_free(in);
610}
611
612void
613BaseSecurity::addCertX509(PEMType type, const Data& key, X509* cert, bool write)
614{
615 switch (type)
616 {
617 case DomainCert:
618 {
619 mDomainCerts.insert(std::make_pair(key, cert));
620 }
621 break;
622 case UserCert:
623 {
624 mUserCerts.insert(std::make_pair(key, cert));
625 }
626 break;
627 case RootCert:
628 {
629 mRootCerts.push_back(cert);
630 X509_STORE_add_cert(mRootTlsCerts,cert);
631 X509_STORE_add_cert(mRootSslCerts,cert);
632 }
633 break;
634 default:
635 {
636 resip_assert(0);
637 }
638 }
639
640 if (write)
641 {
642 // creates a read/write BIO buffer.
643 BIO *out = BIO_new(BIO_s_mem());
644 if(!out)
645 {
646 ErrLog(<< "Failed to create BIO: this cert will not be added.");
647 resip_assert(0);
648 return;
649 }
650
651 try
652 {
653 int ret = PEM_write_bio_X509(out, cert);
654 if(!ret)
655 {
656 resip_assert(0);
657 throw Exception("PEM_write_bio_X509 failed: this cert will not be "
658 "added.", __FILE__,__LINE__);
659 }
660
661 (void)BIO_flush(out);
662 // get content in BIO buffer to our buffer.
663 char* p = 0;
664 size_t len = BIO_get_mem_data(out,&p);
665 if(!p || !len)
666 {
667 resip_assert(0);
668 throw Exception("BIO_get_mem_data failed: this cert will not be "
669 "added.", __FILE__,__LINE__);
670 }
671 Data buf(Data::Borrow, p, (Data::size_type)len);
672
673 this->onWritePEM(key, type, buf);
674 }
675 catch(Exception& e)
676 {
677 ErrLog(<<"Caught exception: " << e);
678 }
679 catch(std::exception& e)
680 {
681 ErrLog(<<"Caught unknown exception, rethrowing");
682 BIO_free(out);
683 throw e;
684 }
685 BIO_free(out);
686 }
687}
688
689bool
690BaseSecurity::hasCert(PEMType type, const Data& aor, bool logErrors) const
691{
692 resip_assert(!aor.empty());
693 const X509Map& certs = (type == DomainCert ? mDomainCerts : mUserCerts);
694
695 X509Map::const_iterator where = certs.find(aor);
696 if (where != certs.end())
697 {
698 return true;
699 }
700
701 try
702 {
703 Data certPEM;
704 onReadPEM(aor, type, certPEM);
705 if (certPEM.empty())
706 {
707 return false;
708 }
709 BaseSecurity* mutable_this = const_cast<BaseSecurity*>(this);
710 mutable_this->addCertPEM(type, aor, certPEM, false);
711 }
712 catch (const BaseException& e)
713 {
714 if(logErrors) ErrLog(<< "Caught exception: " << e);
715 return false;
716 }
717 catch (const std::exception& e)
718 {
719 if (logErrors) ErrLog(<< "Caught exception: " << e.what());
720 return false;
721 }
722 catch (...)
723 {
724 if (logErrors) ErrLog(<< "Caught exception: ");
725 return false;
726 }
727
728 resip_assert(certs.find(aor) != certs.end());
729
730 return true;
731}
732
733void
735{
736 resip_assert( !aor.empty() );
737 X509Map& certs = (type == DomainCert ? mDomainCerts : mUserCerts);
738
739 X509Map::iterator iter = certs.find(aor);
740 if (iter != certs.end())
741 {
742 X509_free(iter->second);
743 certs.erase(iter);
744
745 onRemovePEM(aor, type);
746 }
747
748 resip_assert( certs.find(aor) == certs.end() );
749}
750
751Data
752BaseSecurity::getCertDER (PEMType type, const Data& key) const
753{
754 resip_assert( !key.empty() );
755
756 if (hasCert(type, key) == false)
757 {
758 ErrLog(<< "Could not find certificate for '" << key << "'");
759 throw BaseSecurity::Exception("Could not find certificate", __FILE__,__LINE__);
760 }
761
762 const X509Map& certs = (type == DomainCert ? mDomainCerts : mUserCerts);
763 BaseSecurity::X509Map::const_iterator where = certs.find(key);
764 if (where == certs.end())
765 {
766 // not supposed to happen,
767 // hasCert() should have inserted a value into certs
768 // or we should have throwed.
769 resip_assert(0);
770 }
771
772 X509* x = where->second;
773 unsigned char* buffer=0;
774 int len = i2d_X509(x, &buffer);
775
776 // !kh!
777 // Although len == 0 is not an error, I am not sure what quite to do.
778 // Asserting for now.
779 resip_assert(len != 0);
780 if(len < 0)
781 {
782 ErrLog(<< "Could encode certificate of '" << key << "' to DER form");
783 throw BaseSecurity::Exception("Could encode certificate to DER form", __FILE__,__LINE__);
784 }
785 Data certDER((char*)buffer, len);
786 OPENSSL_free(buffer);
787 return certDER;
788}
789
790void
792 const Data& name,
793 EVP_PKEY* pKey,
794 bool write)
795{
796 PrivateKeyMap& privateKeys = (type == DomainPrivateKey ?
798
799 privateKeys.insert(std::make_pair(name, pKey));
800
801 if (write)
802 {
803 // figure out a passPhrase to encrypt with
804 char* kstr=NULL;
805 int klen=0;
806 if (type != DomainPrivateKey)
807 {
808 PassPhraseMap::const_iterator iter = mUserPassPhrases.find(name);
809 if(iter != mUserPassPhrases.end())
810 {
811 kstr = (char*)iter->second.c_str();
812 klen = (int)iter->second.size();
813 }
814 }
815
816 BIO *bio = BIO_new(BIO_s_mem());
817 if(!bio)
818 {
819 ErrLog(<< "BIO_new failed: cannot add private key.");
820 resip_assert(0);
821 }
822
823 try
824 {
825 resip_assert( EVP_des_ede3_cbc() );
826 const EVP_CIPHER* cipher = EVP_des_ede3_cbc();
827 if (kstr == NULL )
828 {
829 cipher = NULL;
830 }
831#if 0 // TODO - need to figure out what format to write in
832 int ret = PEM_write_bio_PrivateKey(bio, pKey, cipher,
833 (unsigned char*)kstr, klen,
834 NULL, NULL);
835#else
836 int ret = PEM_write_bio_PKCS8PrivateKey(bio, pKey, cipher,
837 kstr, klen,
838 NULL, NULL);
839#endif
840 if(!ret)
841 {
842 resip_assert(0);
843 throw Exception("PEM_write_bio_PKCS8PrivateKey failed: cannot add"
844 " private key.", __FILE__, __LINE__);
845 }
846
847 (void)BIO_flush(bio);
848 char* p = 0;
849 size_t len = BIO_get_mem_data(bio,&p);
850 if(!p || !len)
851 {
852 resip_assert(0);
853 throw Exception("BIO_get_mem_data failed: cannot add"
854 " private key.", __FILE__, __LINE__);
855 }
856 Data pem(Data::Borrow, p, (Data::size_type)len);
857 onWritePEM(name, type, pem );
858 }
859 catch(Exception& e)
860 {
861 ErrLog( << "Caught exception: " << e);
862 }
863 catch(std::exception& e)
864 {
865 ErrLog(<<"Caught unknown exception, rethrowing: " << e.what());
866 BIO_free(bio);
867 throw e;
868 }
869 BIO_free(bio);
870 }
871}
872
873void
875 const Data& name,
876 const Data& privateKeyDER,
877 bool write,
878 const Data& privateKeyPassPhrase)
879{
880 resip_assert( !name.empty() );
881 if( privateKeyDER.empty() )
882 {
883 ErrLog(<< name << " is empty. Skipping.");
884 return;
885 }
886
887 char* passPhrase = 0;
888 if (privateKeyPassPhrase.empty())
889 {
890 if (type == UserPrivateKey)
891 {
892 PassPhraseMap::const_iterator iter = mUserPassPhrases.find(name);
893 if(iter != mUserPassPhrases.end())
894 {
895 passPhrase = const_cast<char*>(iter->second.c_str());
896 }
897 }
898 else
899 {
901 {
902 passPhrase = const_cast<char*>(mDefaultPrivateKeyPassPhrase.c_str());
903 }
904 }
905 }
906 else
907 {
908 passPhrase = const_cast<char*>(privateKeyPassPhrase.c_str());
909 }
910
911 BIO* in = BIO_new_mem_buf(const_cast<char*>(privateKeyDER.c_str()), -1);
912 if ( !in )
913 {
914 ErrLog(<< "Could create BIO buffer from '" << privateKeyDER << "'");
915 throw Exception("Could not create BIO buffer", __FILE__,__LINE__);
916 }
917
918 try
919 {
920 EVP_PKEY* privateKey;
921 if (d2i_PKCS8PrivateKey_bio(in, &privateKey, 0, passPhrase) == 0)
922 {
923 ErrLog(<< "Could not read private key from <" << privateKeyDER << ">" );
924 throw Exception("Could not read private key ", __FILE__,__LINE__);
925 }
926
927 addPrivateKeyPKEY(type,name,privateKey,write);
928 }
929 catch(std::exception& e)
930 {
931 ErrLog(<<"Caught exception: ");
932 BIO_free(in);
933 throw e;
934 }
935
936 BIO_free(in);
937}
938
939void
941 const Data& name,
942 const Data& privateKeyPEM,
943 bool write,
944 const Data& privateKeyPassPhrase)
945{
946 resip_assert( !name.empty() );
947 if( privateKeyPEM.empty() )
948 {
949 ErrLog(<< name << " is empty. Skipping.");
950 return;
951 }
952
953 BIO* in = BIO_new_mem_buf(const_cast<char*>(privateKeyPEM.c_str()), -1);
954 if ( !in )
955 {
956 ErrLog(<< "Could create BIO buffer from '" << privateKeyPEM << "'");
957 throw Exception("Could not create BIO buffer", __FILE__,__LINE__);
958 }
959
960 char* passPhrase = 0;
961 try
962 {
963 if (privateKeyPassPhrase.empty())
964 {
965 if (type == UserPrivateKey)
966 {
967 PassPhraseMap::const_iterator iter = mUserPassPhrases.find(name);
968 if(iter != mUserPassPhrases.end())
969 {
970 passPhrase = const_cast<char*>(iter->second.c_str());
971 }
972 }
973 else
974 {
976 {
977 passPhrase = const_cast<char*>(mDefaultPrivateKeyPassPhrase.c_str());
978 }
979 }
980 }
981 else
982 {
983 passPhrase = const_cast<char*>(privateKeyPassPhrase.c_str());
984 }
985
986 EVP_PKEY* privateKey=0;
987 if ( ( privateKey = PEM_read_bio_PrivateKey(in, NULL, pem_passwd_cb, passPhrase)) == NULL)
988 {
989 char buffer[120];
990 unsigned long err = ERR_get_error();
991 ERR_error_string(err, buffer);
992 if(ERR_GET_LIB(err) == ERR_LIB_EVP && ERR_GET_REASON(err) == EVP_R_BAD_DECRYPT)
993 {
994 ErrLog(<< "Could not read private key (error=" << buffer << ") - likely incorrect password provided, may load correctly when transports are added with appropriate password");
995 }
996 else
997 {
998 ErrLog(<< "Could not read private key (error=" << buffer << ") from <" << privateKeyPEM << ">" );
999 }
1000 throw Exception("Could not read private key ", __FILE__,__LINE__);
1001 }
1002
1003 addPrivateKeyPKEY(type,name,privateKey,write);
1004 }
1005 catch(std::exception& e)
1006 {
1007 ErrLog(<<"Caught exception: ");
1008 BIO_free(in);
1009 throw e;
1010 }
1011
1012 BIO_free(in);
1013}
1014
1015bool
1017 const Data& key ) const
1018{
1019 resip_assert( !key.empty() );
1020
1021 const PrivateKeyMap& privateKeys = (type == DomainPrivateKey
1023
1024 PrivateKeyMap::const_iterator where = privateKeys.find(key);
1025 if (where != privateKeys.end())
1026 {
1027 return true;
1028 }
1029
1030 Data privateKeyPEM;
1031 try
1032 {
1033 onReadPEM(key, type, privateKeyPEM);
1034 BaseSecurity* mutable_this = const_cast<BaseSecurity*>(this);
1035 mutable_this->addPrivateKeyPEM(type, key, privateKeyPEM, false);
1036 }
1037 catch(std::exception& e)
1038 {
1039 ErrLog(<<"Caught exception: " << e.what());
1040 return false;
1041 }
1042 catch(...)
1043 {
1044 ErrLog(<<"Caught unknown class!");
1045 return false;
1046 }
1047
1048 return true;
1049}
1050
1051Data
1053 const Data& key) const
1054{
1055 resip_assert( !key.empty() );
1056
1057 if ( !hasPrivateKey(type, key) )
1058 {
1059 ErrLog(<< "Could find private key for '" << key << "'");
1060 throw Exception("Could not find private key", __FILE__,__LINE__);
1061 }
1062
1063 const PrivateKeyMap& privateKeys = (type == DomainPrivateKey ? mDomainPrivateKeys : mUserPrivateKeys);
1064
1065 PrivateKeyMap::const_iterator where = privateKeys.find(key);
1066 char* p = 0;
1067 if (type != DomainPrivateKey)
1068 {
1069 PassPhraseMap::const_iterator iter = mUserPassPhrases.find(key);
1070 if (iter != mUserPassPhrases.end())
1071 {
1072 p = const_cast<char*>(iter->second.c_str());
1073 }
1074 }
1075
1076 // !kh!
1077 // creates a read/write BIO buffer.
1078 BIO *out = BIO_new(BIO_s_mem());
1079 resip_assert(out);
1080 EVP_PKEY* pk = where->second;
1081 resip_assert(pk);
1082
1083 // write pk to out using key phrase p, with no cipher.
1084 int ret = PEM_write_bio_PrivateKey(out, pk, 0, 0, 0, 0, p); // parameters
1085 // are in the wrong order
1086 (void)ret;
1087 resip_assert(ret == 1);
1088
1089 // get content in BIO buffer to our buffer.
1090 // hand our buffer to a Data object.
1091 (void)BIO_flush(out);
1092 char* buf = 0;
1093 int len = BIO_get_mem_data(out, &buf);
1094 Data retVal(buf, len);
1095
1096 BIO_free(out);
1097
1098 return retVal;
1099}
1100
1101Data
1103 const Data& key) const
1104{
1105 resip_assert( !key.empty() );
1106
1107 if ( !hasPrivateKey(type, key) )
1108 {
1109 ErrLog(<< "Could not find private key for '" << key << "'");
1110 throw Exception("Could not find private key", __FILE__,__LINE__);
1111 }
1112
1113 const PrivateKeyMap& privateKeys = (type == DomainPrivateKey ? mDomainPrivateKeys : mUserPrivateKeys);
1114
1115 PrivateKeyMap::const_iterator where = privateKeys.find(key);
1116 char* p = 0;
1117 if (type != DomainPrivateKey)
1118 {
1119 PassPhraseMap::const_iterator iter = mUserPassPhrases.find(key);
1120 if(iter != mUserPassPhrases.end())
1121 {
1122 p = const_cast<char*>(iter->second.c_str());
1123 }
1124 }
1125
1126 // !kh!
1127 // creates a read/write BIO buffer.
1128 BIO *out = BIO_new(BIO_s_mem());
1129 resip_assert(out);
1130 EVP_PKEY* pk = where->second;
1131 resip_assert(pk);
1132
1133 // write pk to out using key phrase p, with no cipher.
1134 int ret = i2d_PKCS8PrivateKey_bio(out, pk, 0, 0, 0, 0, p);
1135 (void)ret;
1136 resip_assert(ret == 1);
1137
1138 // get content in BIO buffer to our buffer.
1139 // hand our buffer to a Data object.
1140 (void)BIO_flush(out);
1141 char* buf = 0;
1142 int len = BIO_get_mem_data(out, &buf);
1143 Data retVal(buf, len);
1144
1145 BIO_free(out);
1146
1147 return retVal;
1148}
1149
1150void
1152{
1153 resip_assert( !key.empty() );
1154
1156
1157 resip_assert( !key.empty() );
1158 PrivateKeyMap::iterator iter = privateKeys.find(key);
1159 if (iter != privateKeys.end())
1160 {
1161 EVP_PKEY_free(iter->second);
1162 privateKeys.erase(iter);
1163
1164 onRemovePEM(key, type);
1165 }
1166}
1167
1168
1169Security::Exception::Exception(const Data& msg, const Data& file, const int line)
1170: BaseException(msg,file,line)
1171{
1172}
1173
1174BaseSecurity::BaseSecurity (const CipherList& cipherSuite, const Data& defaultPrivateKeyPassPhrase, const Data& dHParamsFilename) :
1175 mTlsCtx(0),
1176 mSslCtx(0),
1177 mCipherList(cipherSuite),
1178 mDefaultPrivateKeyPassPhrase(defaultPrivateKeyPassPhrase),
1179 mDHParamsFilename(dHParamsFilename),
1180 mRootTlsCerts(0),
1181 mRootSslCerts(0)
1182{
1183 DebugLog(<< "BaseSecurity::BaseSecurity");
1184
1185 int ret;
1186 initialize();
1187
1188 mRootTlsCerts = X509_STORE_new();
1189 mRootSslCerts = X509_STORE_new();
1191
1192 mTlsCtx = SSL_CTX_new( TLS_method() );
1193 if (!mTlsCtx)
1194 {
1195 ErrLog(<< "SSL_CTX_new failed, dumping OpenSSL error stack:");
1196 while (ERR_peek_error())
1197 {
1198 char errBuf[120];
1199 ERR_error_string(ERR_get_error(), errBuf);
1200 ErrLog(<< "OpenSSL error stack: " << errBuf);
1201 }
1202 }
1203 SSL_CTX_set_min_proto_version(mTlsCtx, TLS1_VERSION);
1204 SSL_CTX_set_max_proto_version(mTlsCtx, TLS1_VERSION);
1206
1207 SSL_CTX_set_default_passwd_cb(mTlsCtx, pem_passwd_cb);
1208 SSL_CTX_set_cert_store(mTlsCtx, mRootTlsCerts);
1209 SSL_CTX_set_verify(mTlsCtx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, verifyCallback);
1210 ret = SSL_CTX_set_cipher_list(mTlsCtx, cipherSuite.cipherList().c_str());
1211 resip_assert(ret);
1213 SSL_CTX_set_options(mTlsCtx, BaseSecurity::OpenSSLCTXSetOptions);
1214 SSL_CTX_clear_options(mTlsCtx, BaseSecurity::OpenSSLCTXClearOptions);
1215
1216 mSslCtx = SSL_CTX_new( TLS_method() );
1218 SSL_CTX_set_default_passwd_cb(mSslCtx, pem_passwd_cb);
1219 SSL_CTX_set_cert_store(mSslCtx, mRootSslCerts);
1220 SSL_CTX_set_verify(mSslCtx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, verifyCallback);
1221 ret = SSL_CTX_set_cipher_list(mSslCtx,cipherSuite.cipherList().c_str());
1222 resip_assert(ret);
1224 SSL_CTX_set_options(mSslCtx, BaseSecurity::OpenSSLCTXSetOptions);
1225 SSL_CTX_clear_options(mSslCtx, BaseSecurity::OpenSSLCTXClearOptions);
1226}
1227
1228
1229template<class T, class Func>
1230void clearMap(T& m, Func& clearFunc)
1231{
1232 for (typename T::iterator it = m.begin(); it != m.end(); it++)
1233 {
1234 clearFunc(it->second);
1235 }
1236 m.clear();
1237}
1238
1239template<class T, class Func>
1240void clearList(T& m, Func& clearFunc)
1241{
1242 for (typename T::iterator it = m.begin(); it != m.end(); it++)
1243 {
1244 clearFunc(*it);
1245 }
1246 m.clear();
1247}
1248
1250{
1251 DebugLog(<< "BaseSecurity::~BaseSecurity");
1252
1253 // cleanup certificates
1254 clearList(mRootCerts, X509_free);
1255 clearMap(mDomainCerts, X509_free);
1256 clearMap(mUserCerts, X509_free);
1257
1258 // cleanup private keys
1259 clearMap(mDomainPrivateKeys, EVP_PKEY_free);
1260 clearMap(mUserPrivateKeys, EVP_PKEY_free);
1261
1262 // cleanup SSL_CTXes
1263 if (mTlsCtx)
1264 {
1265 SSL_CTX_free(mTlsCtx);mTlsCtx=0; // This free's X509_STORE (mRootTlsCerts)
1266 }
1267 if (mSslCtx)
1268 {
1269 SSL_CTX_free(mSslCtx);mSslCtx=0; // This free's X509_STORE (mRootSslCerts)
1270 }
1271
1272}
1273
1274void
1276{
1277 Timer::getTimeMs(); // initalize time offsets
1278}
1279
1282{
1283 // !kh!
1284 // need to be implemented.
1285 resip_assert(0); // TODO
1286 return CertificateInfoContainer();
1287}
1288
1289void
1290BaseSecurity::addRootCertPEM(const Data& x509PEMEncodedRootCerts)
1291{
1293#if 1
1294 addCertPEM(RootCert,Data::Empty,x509PEMEncodedRootCerts,false);
1295#else
1296 resip_assert( !x509PEMEncodedRootCerts.empty() );
1297
1298 static X509_LOOKUP_METHOD x509_pemstring_lookup =
1299 {
1300 "Load cert from PEM string into cache",
1301 NULL, /* new */
1302 NULL, /* free */
1303 NULL, /* init */
1304 NULL, /* shutdown */
1305 pemstring_ctrl,/* ctrl */
1306 NULL, /* get_by_subject */
1307 NULL, /* get_by_issuer_serial */
1308 NULL, /* get_by_fingerprint */
1309 NULL, /* get_by_alias */
1310 };
1311
1312 if (mRootCerts == 0)
1313 {
1314 mRootCerts = X509_STORE_new();
1315 }
1316
1318
1319 X509_LOOKUP* lookup = X509_STORE_add_lookup(mRootCerts, &x509_pemstring_lookup);
1320
1321 if (lookup == NULL)
1322 throw Exception("Error in BaseSecurity::addRootCertPEM()", __FILE__,__LINE__);
1323
1324 // !kh!
1325 // bug, no error handling here.
1326 X509_LOOKUP_ctrl(lookup, X509_L_FILE_LOAD, x509PEMEncodedRootCerts.c_str(), 0, 0);
1327#endif
1328}
1329
1330void
1331BaseSecurity::addDomainCertPEM(const Data& domainName, const Data& certPEM)
1332{
1333 addCertPEM(DomainCert, domainName, certPEM, false);
1334}
1335
1336void
1337BaseSecurity::addDomainCertDER(const Data& domainName, const Data& certDER)
1338{
1339 addCertDER(DomainCert, domainName, certDER, false);
1340}
1341
1342bool
1343BaseSecurity::hasDomainCert(const Data& domainName, bool logErrors) const
1344{
1345 return hasCert(DomainCert, domainName, logErrors);
1346}
1347
1348void
1350{
1351 return removeCert(DomainCert, domainName);
1352}
1353
1354Data
1355BaseSecurity::getDomainCertDER(const Data& domainName) const
1356{
1357 return getCertDER(DomainCert, domainName);
1358}
1359
1360void
1361BaseSecurity::addDomainPrivateKeyPEM(const Data& domainName, const Data& privateKeyPEM, const Data& privateKeyPassPhrase)
1362{
1363 addPrivateKeyPEM(DomainPrivateKey, domainName, privateKeyPEM, false, privateKeyPassPhrase);
1364}
1365
1366bool
1368{
1369 return hasPrivateKey(DomainPrivateKey, domainName);
1370}
1371
1372void
1374{
1376}
1377
1378Data
1380{
1381 return getPrivateKeyPEM(DomainPrivateKey, domainName);
1382}
1383
1384void
1385BaseSecurity::addUserCertPEM(const Data& aor, const Data& certPEM)
1386{
1387 addCertPEM(UserCert, aor, certPEM, false);
1388}
1389
1390void
1391BaseSecurity::addUserCertDER(const Data& aor, const Data& certDER)
1392{
1393 addCertDER(UserCert, aor, certDER, false);
1394}
1395
1396bool
1398{
1399 return hasCert(UserCert, aor);
1400}
1401
1402void
1404{
1405 removeCert(UserCert, aor);
1406}
1407
1408Data
1410{
1411 return getCertDER(UserCert, aor);
1412}
1413
1414void
1415BaseSecurity::setUserPassPhrase(const Data& aor, const Data& passPhrase)
1416{
1417 resip_assert(!aor.empty());
1418
1419 PassPhraseMap::iterator iter = mUserPassPhrases.find(aor);
1420 if (iter == mUserPassPhrases.end())
1421 {
1422 mUserPassPhrases.insert(std::make_pair(aor, passPhrase));
1423 }
1424}
1425
1426bool
1428{
1429 resip_assert(aor.empty());
1430
1431 PassPhraseMap::const_iterator iter = mUserPassPhrases.find(aor);
1432 if (iter == mUserPassPhrases.end())
1433 {
1434 return false;
1435 }
1436 else
1437 {
1438 return true;
1439 }
1440}
1441
1442void
1444{
1445 resip_assert(aor.empty());
1446
1447 PassPhraseMap::iterator iter = mUserPassPhrases.find(aor);
1448 if(iter != mUserPassPhrases.end())
1449 {
1450 mUserPassPhrases.erase(iter);
1451 }
1452}
1453
1454Data
1456{
1457 resip_assert(aor.empty());
1458
1459 PassPhraseMap::const_iterator iter = mUserPassPhrases.find(aor);
1460 if(iter == mUserPassPhrases.end())
1461 {
1462 return iter->second;
1463 }
1464 else
1465 {
1466 return Data::Empty;
1467 }
1468}
1469
1470void
1471BaseSecurity::addUserPrivateKeyPEM(const Data& aor, const Data& cert, const Data& privateKeyPassPhrase)
1472{
1473 addPrivateKeyPEM(UserPrivateKey, aor, cert, false, privateKeyPassPhrase);
1474}
1475
1476void
1477BaseSecurity::addUserPrivateKeyDER(const Data& aor, const Data& cert, const Data& privateKeyPassPhrase)
1478{
1479 addPrivateKeyDER(UserPrivateKey, aor, cert, false, privateKeyPassPhrase);
1480}
1481
1482bool
1484{
1485 return hasPrivateKey(UserPrivateKey, aor);
1486}
1487
1488void
1493
1494Data
1496{
1497 return getPrivateKeyPEM(UserPrivateKey, aor);
1498}
1499
1500Data
1502{
1503 return getPrivateKeyDER(UserPrivateKey, aor);
1504}
1505
1506void
1507BaseSecurity::generateUserCert (const Data& pAor, int expireDays, int keyLen )
1508{
1509 int ret;
1510
1511 InfoLog( <<"Generating new user cert for " << pAor );
1512
1513 Data domain;
1514 Data aor;
1515
1516 try
1517 {
1518 Uri uri( Data("sip:")+pAor );
1519 aor = uri.getAor();
1520 domain = uri.host();
1521 }
1522 catch (...)
1523 {
1524 ErrLog( <<"Invalid aor passed to generateUserCert");
1525 throw Exception("Bad aor passed to generateUserCert", __FILE__,__LINE__);
1526 }
1527
1528 // Make sure that necessary algorithms exist:
1529 resip_assert(EVP_sha256());
1530
1531 // An RSA key (the default public exponent is 65537)
1532 EVP_PKEY* privkey = NULL;
1533 EVP_PKEY_CTX* keyCtx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
1534 bool generated = keyCtx &&
1535 EVP_PKEY_keygen_init(keyCtx) == 1 &&
1536 EVP_PKEY_CTX_set_rsa_keygen_bits(keyCtx, keyLen) == 1 &&
1537 EVP_PKEY_keygen(keyCtx, &privkey) == 1;
1538 EVP_PKEY_CTX_free(keyCtx);
1539 if (!generated)
1540 {
1541 ErrLog( <<"Unable to generate a " << keyLen << " bit RSA key for " << aor );
1542 throw Exception("Unable to generate a key pair in generateUserCert", __FILE__,__LINE__);
1543 }
1544
1545 X509* cert = X509_new();
1546 resip_assert(cert);
1547
1548 X509_NAME* subject = X509_NAME_new();
1549 X509_EXTENSION* ext;
1550
1551 // set version to X509v3 (starts from 0)
1552 X509_set_version(cert, 2L);
1553
1554 // RFC 5280 4.1.2.2 wants a positive serial, and getCryptoRandom() fills a
1555 // whole int from RAND_bytes, so it is negative about half the time.
1556 int serial = Random::getCryptoRandom() & 0x7FFFFFFF;
1557 resip_assert(sizeof(int)==4);
1558 ASN1_INTEGER_set(X509_get_serialNumber(cert),serial);
1559
1560 ret = X509_NAME_add_entry_by_txt( subject, "O", MBSTRING_ASC,
1561 (unsigned char *) domain.data(), (int)domain.size(),
1562 -1, 0);
1563 resip_assert(ret);
1564 ret = X509_NAME_add_entry_by_txt( subject, "CN", MBSTRING_ASC,
1565 (unsigned char *) aor.data(), (int)aor.size(),
1566 -1, 0);
1567 resip_assert(ret);
1568
1569 ret = X509_set_issuer_name(cert, subject);
1570 resip_assert(ret);
1571 ret = X509_set_subject_name(cert, subject);
1572 resip_assert(ret);
1573 X509_NAME_free(subject); // the certificate holds copies
1574
1575 const long duration = 60*60*24*expireDays;
1576 X509_gmtime_adj(X509_getm_notBefore(cert),0);
1577 X509_gmtime_adj(X509_getm_notAfter(cert), duration);
1578
1579 ret = X509_set_pubkey(cert, privkey);
1580 resip_assert(ret);
1581
1582 Data subjectAltNameStr = Data("URI:sip:") + aor
1583 + Data(",URI:im:")+aor
1584 + Data(",URI:pres:")+aor;
1585 ext = X509V3_EXT_conf_nid( NULL , NULL , NID_subject_alt_name,
1586 (char*) subjectAltNameStr.c_str() );
1587 X509_add_ext( cert, ext, -1);
1588 X509_EXTENSION_free(ext);
1589
1590 static const char CA_FALSE[] = "CA:FALSE";
1591 ext = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints, CA_FALSE);
1592 ret = X509_add_ext( cert, ext, -1);
1593 resip_assert(ret);
1594 X509_EXTENSION_free(ext);
1595
1596 // TODO add extensions NID_subject_key_identifier and NID_authority_key_identifier
1597
1598 ret = X509_sign(cert, privkey, EVP_sha256());
1599 resip_assert(ret);
1600
1601 addCertX509( UserCert, aor, cert, true /* write */ );
1602 addPrivateKeyPKEY( UserPrivateKey, aor, privkey, true /* write */ );
1603}
1604
1606BaseSecurity::sign(const Data& senderAor, Contents* contents)
1607{
1608 resip_assert( contents );
1609
1610 // form the multipart
1612 multi->header(h_ContentType).param( p_micalg ) = "sha256";
1613 multi->header(h_ContentType).param( p_protocol ) = "application/pkcs7-signature";
1614
1615 // add the main body to it
1616 Contents* body = contents->clone();
1617 multi->parts().push_back( body );
1618
1619 Data bodyData;
1620 DataStream strm( bodyData );
1621 body->encodeHeaders( strm );
1622 body->encode( strm );
1623 strm.flush();
1624
1625 DebugLog( << "signing data <" << bodyData.escaped() << ">" );
1626 //Security::dumpAsn("resip-sign-out-data",bodyData);
1627
1628 const char* p = bodyData.data();
1629 int s = (int)bodyData.size();
1630 BIO* in=BIO_new_mem_buf( (void*)p,s);
1631 resip_assert(in);
1632 DebugLog( << "created in BIO");
1633
1634 BIO* out = BIO_new(BIO_s_mem()); // TODO - mem leak
1635 resip_assert(out);
1636 DebugLog( << "created out BIO" );
1637
1638 STACK_OF(X509)* chain = sk_X509_new_null();
1639 resip_assert(chain);
1640
1641 DebugLog( << "searching for cert/key for <" << senderAor << ">" );
1642 if (mUserCerts.find(senderAor) == mUserCerts.end() ||
1643 mUserPrivateKeys.find(senderAor) == mUserPrivateKeys.end())
1644 {
1645 BIO_free(in);
1646 BIO_free(out);
1647 sk_X509_free(chain);
1648 WarningLog (<< "Tried to sign with no cert or private key for " << senderAor);
1649 throw Exception("No cert or private key to sign with",__FILE__,__LINE__);
1650 }
1651
1652 X509* publicCert = mUserCerts[senderAor];
1653 EVP_PKEY* privateKey = mUserPrivateKeys[senderAor];
1654
1655 int rv = X509_check_private_key(publicCert, privateKey);
1656 if(!rv)
1657 {
1658 BIO_free(in);
1659 BIO_free(out);
1660 sk_X509_free(chain);
1661 ErrLog (<< "X509_check_private_key failed for " << senderAor);
1662 return 0;
1663 }
1664
1665 // compute the signature
1666 int flags = 0;
1667 flags |= PKCS7_BINARY;
1668 flags |= PKCS7_DETACHED;
1669 if ( true ) // don't do caps
1670 {
1671 flags |= PKCS7_NOSMIMECAP;
1672 flags |= PKCS7_NOATTR;
1673 }
1674 if ( true ) // don't do certs
1675 {
1676 flags |= PKCS7_NOCERTS;
1677 }
1678
1679 PKCS7* pkcs7 = PKCS7_sign( publicCert, privateKey, chain, in, flags);
1680 if ( !pkcs7 )
1681 {
1682 BIO_free(in);
1683 BIO_free(out);
1684 sk_X509_free(chain);
1685 ErrLog( << "Error creating PKCS7 signature object" );
1686 return 0;
1687 }
1688 DebugLog( << "created PKCS7 signature object " );
1689
1690 i2d_PKCS7_bio(out,pkcs7);
1691 (void)BIO_flush(out);
1692
1693 char* outBuf=0;
1694 long size = BIO_get_mem_data(out,&outBuf);
1695 resip_assert( size > 0 );
1696
1697 Data outData(outBuf,size);
1698 static const char RESIP_SIGN_OUT_SIG[] = "resip-sign-out-sig";
1699 Security::dumpAsn(RESIP_SIGN_OUT_SIG,outData);
1700
1701 Pkcs7SignedContents* sigBody = new Pkcs7SignedContents( outData );
1702 resip_assert( sigBody );
1703
1704 // add the signature to it
1705 sigBody->header(h_ContentType).param( p_name ) = "smime.p7s";
1706 sigBody->header(h_ContentDisposition).param( p_handling ) = "required";
1707 sigBody->header(h_ContentDisposition).param( p_filename ) = "smime.p7s";
1708 sigBody->header(h_ContentDisposition).value() = "attachment" ;
1709 sigBody->header(h_ContentTransferEncoding).value() = "binary";
1710 multi->parts().push_back( sigBody );
1711
1712 resip_assert( multi->parts().size() == 2 );
1713
1714 BIO_free(in);
1715 BIO_free(out);
1716 sk_X509_free(chain);
1717 PKCS7_free(pkcs7);
1718
1719 return multi;
1720}
1721
1722
1724BaseSecurity::encrypt(Contents* bodyIn, const Data& recipCertName )
1725{
1726 resip_assert( bodyIn );
1727
1728 int flags = 0 ;
1729 flags |= PKCS7_BINARY;
1730 flags |= PKCS7_NOCERTS;
1731
1732 Data bodyData;
1733 DataStream strm(bodyData);
1734 bodyIn->encodeHeaders(strm);
1735 bodyIn->encode( strm );
1736 strm.flush();
1737
1738 InfoLog( << "body data to encrypt is <" << bodyData.escaped() << ">" );
1739
1740 const char* p = bodyData.data();
1741 int s = (int)bodyData.size();
1742
1743 BIO* in = BIO_new_mem_buf( (void*)p,s);
1744 resip_assert(in);
1745 DebugLog( << "created in BIO");
1746
1747 BIO* out = BIO_new(BIO_s_mem());
1748 resip_assert(out);
1749 DebugLog( << "created out BIO" );
1750
1751 InfoLog( << "target cert name is <" << recipCertName << ">" );
1752 if (mUserCerts.find(recipCertName) == mUserCerts.end())
1753 {
1754 BIO_free(in);
1755 BIO_free(out);
1756 WarningLog (<< "Tried to encrypt with no cert or private key for " << recipCertName);
1757 throw Exception("No cert or private key to encrypt with",__FILE__,__LINE__);
1758 }
1759
1760 X509* cert = mUserCerts[recipCertName];
1761 resip_assert(cert);
1762
1763 STACK_OF(X509) *certs = sk_X509_new_null();
1764 resip_assert(certs);
1765 sk_X509_push(certs, cert);
1766
1767// if you think you need to change the following few lines, please email fluffy
1768// the value of OPENSSL_VERSION_NUMBER ( in opensslv.h ) and the signature of
1769// PKCS_encrypt found ( in pkcs7.h ) and the OS you are using
1770 const EVP_CIPHER* cipher = EVP_aes_128_cbc();
1771 resip_assert( cipher );
1772
1773 PKCS7* pkcs7 = PKCS7_encrypt( certs, in, cipher, flags);
1774 if ( !pkcs7 )
1775 {
1776 BIO_free(in);
1777 BIO_free(out);
1778 sk_X509_free(certs);
1779 ErrLog( << "Error creating PKCS7 encrypt object" );
1780 //throw Exception("Can't encrypt",__FILE__,__LINE__);
1781 return 0;
1782 }
1783 DebugLog( << "created PKCS7 encrypt object " );
1784
1785 i2d_PKCS7_bio(out,pkcs7);
1786
1787 (void)BIO_flush(out);
1788
1789 char* outBuf=0;
1790 long size = BIO_get_mem_data(out,&outBuf);
1791 resip_assert( size > 0 );
1792
1793 Data outData(outBuf,size);
1794 resip_assert( (long)outData.size() == size );
1795
1796 InfoLog( << "Encrypted body size is " << outData.size() );
1797 InfoLog( << "Encrypted body is <" << outData.escaped() << ">" );
1798
1799 static const char RESIP_ENCRYPT_OUT[] = "resip-encrypt-out";
1800 Security::dumpAsn(RESIP_ENCRYPT_OUT, outData);
1801
1802 Pkcs7Contents* outBody = new Pkcs7Contents( outData );
1803 resip_assert( outBody );
1804
1805 outBody->header(h_ContentType).param( p_smimeType ) = "enveloped-data";
1806 outBody->header(h_ContentType).param( p_name ) = "smime.p7m";
1807 outBody->header(h_ContentDisposition).param( p_handling ) = "required";
1808 outBody->header(h_ContentDisposition).param( p_filename ) = "smime.p7";
1809 outBody->header(h_ContentDisposition).value() = "attachment" ;
1810 outBody->header(h_ContentTransferEncoding).value() = "binary";
1811
1812 BIO_free(in);
1813 BIO_free(out);
1814 sk_X509_free(certs);
1815 PKCS7_free(pkcs7);
1816
1817 return outBody;
1818}
1819
1820
1822BaseSecurity::signAndEncrypt( const Data& senderAor, Contents* body, const Data& recipCertName )
1823{
1824 //assert(0);
1825 //return 0;
1826 return sign(senderAor, encrypt(body, recipCertName));
1827}
1828
1829
1830Data
1831BaseSecurity::computeIdentity( const Data& signerDomain, const Data& in ) const
1832{
1833 DebugLog( << "Compute identity for " << in );
1834
1835 PrivateKeyMap::const_iterator k(mDomainPrivateKeys.find(signerDomain));
1836 if (k == mDomainPrivateKeys.end())
1837 {
1838 InfoLog( << "No private key for " << signerDomain );
1839 throw Exception("Missing private key when computing identity",__FILE__,__LINE__);
1840 }
1841
1842 EVP_PKEY* pKey = k->second;
1843 resip_assert( pKey );
1844
1845 if ( EVP_PKEY_base_id(pKey) != EVP_PKEY_RSA )
1846 {
1847 ErrLog( << "Private key (type=" << EVP_PKEY_id(pKey) << ") for "
1848 << signerDomain << " is not of type RSA" );
1849 throw Exception("No RSA private key when computing identity",__FILE__,__LINE__);
1850 }
1851
1852 unsigned char digest[EVP_MAX_MD_SIZE];
1853 unsigned int digestSize = sizeof(digest);
1854 auto digestType = EVP_sha256();
1855 if (!EVP_Digest(in.data(), in.size(), digest, &digestSize, digestType, NULL))
1856 {
1857 ErrLog( << "Failed to compute digest of identity" );
1858 throw Exception("Failed to compute digest of identity",__FILE__, __LINE__);
1859 }
1860 DebugLog( << "hash of string is 0x" << Data(digest, digestSize).hex() );
1861
1862 // RSASSA-PKCS1-v1_5 signature of the SHA-256 digest
1863 unsigned char result[4096];
1864 size_t resultSize = sizeof(result);
1865 EVP_PKEY_CTX* signCtx = EVP_PKEY_CTX_new(pKey, NULL);
1866 bool signedOk = signCtx &&
1867 EVP_PKEY_sign_init(signCtx) == 1 &&
1868 EVP_PKEY_CTX_set_rsa_padding(signCtx, RSA_PKCS1_PADDING) == 1 &&
1869 EVP_PKEY_CTX_set_signature_md(signCtx, digestType) == 1 &&
1870 EVP_PKEY_sign(signCtx, result, &resultSize, digest, digestSize) == 1;
1871 EVP_PKEY_CTX_free(signCtx);
1872 if( !signedOk )
1873 {
1874 ErrLog(<< "Signing the identity digest failed");
1875 resip_assert(0);
1876 return Data::Empty;
1877 }
1878
1879 Data res(result,resultSize);
1880 DebugLog( << "rsa encrypt of hash is 0x"<< res.hex() );
1881
1882 Data enc = res.base64encode();
1883
1884 static const char IDENTITY_IN[] = "identity-in";
1885 static const char IDENTITY_IN_HASH[] = "identity-in-hash";
1886 static const char IDENTITY_IN_RSA[] = "identity-in-rsa";
1887 static const char IDENTITY_IN_BASE64[] = "identity-in-base64";
1888
1889 Security::dumpAsn(IDENTITY_IN, in );
1890 Security::dumpAsn(IDENTITY_IN_HASH, Data(digest, digestSize) );
1891 Security::dumpAsn(IDENTITY_IN_RSA,res);
1892 Security::dumpAsn(IDENTITY_IN_BASE64,enc);
1893
1894 return enc;
1895}
1896
1897
1898bool
1899BaseSecurity::checkIdentity( const Data& signerDomain, const Data& in, const Data& sigBase64, X509* pCert ) const
1900{
1901 X509* cert = pCert;
1902 if (!cert)
1903 {
1904 X509Map::const_iterator x=mDomainCerts.find(signerDomain);
1905 if (x == mDomainCerts.end())
1906 {
1907 ErrLog( << "No public key for " << signerDomain );
1908 throw Exception("Missing public key when verifying identity",__FILE__,__LINE__);
1909 }
1910 cert = x->second;
1911 }
1912
1913 DebugLog( << "Check identity for " << in );
1914 DebugLog( << " base64 data is " << sigBase64 );
1915
1916 Data sig = sigBase64.base64decode();
1917 DebugLog( << "decoded sig is 0x"<< sig.hex() );
1918
1919 unsigned char digest[EVP_MAX_MD_SIZE];
1920 unsigned int digestSize = sizeof(digest);
1921 auto digestType = EVP_sha256();
1922
1923 if (!EVP_Digest(in.data(), in.size(), digest, &digestSize, digestType, NULL))
1924 {
1925 ErrLog( << "Failed to compute digest of identity" );
1926 throw Exception("Failed to compute digest of identity",__FILE__, __LINE__);
1927 }
1928 DebugLog( << "hash of string is 0x" << Data(digest, digestSize).hex() );
1929
1930 EVP_PKEY* pKey = X509_get_pubkey( cert ); // a new reference
1931 if ( !pKey || EVP_PKEY_base_id(pKey) != EVP_PKEY_RSA )
1932 {
1933 ErrLog( << "Public key for " << signerDomain << " is not of type RSA" );
1934 EVP_PKEY_free(pKey);
1935 return false;
1936 }
1937
1938 // RSASSA-PKCS1-v1_5 signature of the SHA-256 digest
1939 EVP_PKEY_CTX* verifyCtx = EVP_PKEY_CTX_new(pKey, NULL);
1940 int ret = verifyCtx &&
1941 EVP_PKEY_verify_init(verifyCtx) == 1 &&
1942 EVP_PKEY_CTX_set_rsa_padding(verifyCtx, RSA_PKCS1_PADDING) == 1 &&
1943 EVP_PKEY_CTX_set_signature_md(verifyCtx, digestType) == 1 &&
1944 EVP_PKEY_verify(verifyCtx, (const unsigned char*)sig.data(), sig.size(), digest, digestSize) == 1;
1945 EVP_PKEY_CTX_free(verifyCtx);
1946 EVP_PKEY_free(pKey);
1947 DebugLog( << "rsa verify result is " << ret );
1948
1949 static const char IDENTITY_OUT_MSG[] = "identity-out-msg";
1950 static const char IDENTITY_OUT_BASE64[] = "identity-out-base64";
1951 static const char IDENTITY_OUT_SIG[] = "identity-out-sig";
1952 static const char IDENTITY_OUT_HASH[] = "identity-out-hash";
1953
1954 Security::dumpAsn(IDENTITY_OUT_MSG, in );
1955 Security::dumpAsn(IDENTITY_OUT_BASE64,sigBase64);
1956 Security::dumpAsn(IDENTITY_OUT_SIG, sig);
1957 Security::dumpAsn(IDENTITY_OUT_HASH, Data(digest, digestSize) );
1958
1959 return (ret != 0);
1960}
1961
1962
1963// TODO !SLG! RFC4474 has been deprecated by RFC8224 (Authenticated Identity Management). We should remove/adjust this code.
1964void
1966{
1967 unique_ptr<SecurityAttributes> sec(new SecurityAttributes);
1968 X509* cert=NULL;
1969
1970 try
1971 {
1972 if ( !certDer.empty() )
1973 {
1974 unsigned const char* in = (unsigned const char*)certDer.data();
1975 if (d2i_X509(&cert,&in,(long)certDer.size()) == 0)
1976 {
1977 DebugLog(<< "Could not read DER certificate from " << certDer );
1978 cert = NULL;
1979 }
1980 }
1981 if ( certDer.empty() || cert )
1982 {
1983 if ( checkIdentity(msg.const_header(h_From).uri().host(),
1985 msg.const_header(h_Identities).front().value(),
1986 cert ) )
1987 {
1988 sec->setIdentity(msg.const_header(h_From).uri().getAor());
1989 sec->setIdentityStrength(SecurityAttributes::Identity);
1990 }
1991 else
1992 {
1993 sec->setIdentity(msg.const_header(h_From).uri().getAor());
1994 sec->setIdentityStrength(SecurityAttributes::FailedIdentity);
1995 }
1996 }
1997 else
1998 {
1999 sec->setIdentity(msg.const_header(h_From).uri().getAor());
2000 sec->setIdentityStrength(SecurityAttributes::FailedIdentity);
2001 }
2002 }
2003 catch (BaseException& e)
2004 {
2005 ErrLog(<<"Caught exception: "<< e);
2006 sec->setIdentity(msg.const_header(h_From).uri().getAor());
2007 sec->setIdentityStrength(SecurityAttributes::FailedIdentity);
2008 }
2009 msg.setSecurityAttributes(std::move(sec));
2010 X509_free(cert);
2011}
2012
2013
2014Contents*
2015BaseSecurity::decrypt( const Data& decryptorAor, const Pkcs7Contents* contents)
2016{
2017
2018 DebugLog( << "decryptor Aor: <" << decryptorAor << ">" );
2019
2020 int flags=0;
2021 flags |= PKCS7_BINARY;
2022
2023 // for now, assume that this is only a singed message
2024 resip_assert( contents );
2025
2026 Data text = contents->getBodyData();
2027 DebugLog( << "uncode body = <" << text.escaped() << ">" );
2028 DebugLog( << "uncode body size = " << text.size() );
2029
2030 static const char RESIP_ASN_DECRYPT[] = "resip-asn-decrypt";
2031 Security::dumpAsn(RESIP_ASN_DECRYPT, text );
2032
2033 BIO* in = BIO_new_mem_buf( (void*)text.c_str(), (int)text.size());
2034 resip_assert(in);
2035 InfoLog( << "created in BIO");
2036
2037 BIO* out;
2038 out = BIO_new(BIO_s_mem());
2039 resip_assert(out);
2040 InfoLog( << "created out BIO" );
2041
2042 PKCS7* pkcs7 = d2i_PKCS7_bio(in, 0);
2043 if ( !pkcs7 )
2044 {
2045 ErrLog( << "Problems doing decode of PKCS7 object" );
2046
2047 while (1)
2048 {
2049 const char* file;
2050 int line;
2051
2052#if OPENSSL_VERSION_NUMBER < 0x30000000L
2053 unsigned long code = ERR_get_error_line(&file,&line);
2054#else
2055 unsigned long code = ERR_get_error_all(&file, &line, NULL, NULL, NULL);
2056#endif
2057 if ( code == 0 )
2058 {
2059 break;
2060 }
2061
2062 char buf[256];
2063 ERR_error_string_n(code,buf,sizeof(buf));
2064 ErrLog( << buf );
2065 InfoLog( << "Error code = " << code << " file=" << file << " line=" << line );
2066 }
2067
2068 BIO_free(in);
2069 BIO_free(out);
2070
2071 return 0;
2072 }
2073 (void)BIO_flush(in);
2074
2075 int type=OBJ_obj2nid(pkcs7->type);
2076 InfoLog( << "data is " << OBJ_nid2ln(type) );
2077
2078 STACK_OF(X509)* certs = sk_X509_new_null();
2079 resip_assert( certs );
2080
2081 // flags |= PKCS7_NOVERIFY;
2082
2084
2085 switch (type)
2086 {
2087 case NID_pkcs7_signedAndEnveloped:
2088 {
2089 BIO_free(in);
2090 BIO_free(out);
2091 sk_X509_free(certs);
2092 PKCS7_free(pkcs7);
2093 throw Exception("Signed and enveloped is not supported", __FILE__, __LINE__);
2094 }
2095 break;
2096
2097 case NID_pkcs7_enveloped:
2098 {
2099 if (mUserPrivateKeys.find(decryptorAor) == mUserPrivateKeys.end())
2100 {
2101 BIO_free(in);
2102 BIO_free(out);
2103 sk_X509_free(certs);
2104 PKCS7_free(pkcs7);
2105 InfoLog( << "Don't have a private key for " << decryptorAor << " for PKCS7_decrypt" );
2106 throw Exception("Missing private key", __FILE__, __LINE__);
2107 }
2108 else if (mUserCerts.find(decryptorAor) == mUserCerts.end())
2109 {
2110 BIO_free(in);
2111 BIO_free(out);
2112 sk_X509_free(certs);
2113 PKCS7_free(pkcs7);
2114 InfoLog( << "Don't have a public cert for " << decryptorAor << " for PKCS7_decrypt" );
2115 throw Exception("Missing cert", __FILE__, __LINE__);
2116 }
2117
2118 EVP_PKEY* privateKey = mUserPrivateKeys[decryptorAor];
2119 X509* publicCert = mUserCerts[decryptorAor];
2120
2121 if ( PKCS7_decrypt(pkcs7, privateKey, publicCert, out, flags ) != 1 )
2122 {
2123 ErrLog( << "Problems doing PKCS7_decrypt" );
2124 while (1)
2125 {
2126 const char* file;
2127 int line;
2128
2129#if OPENSSL_VERSION_NUMBER < 0x30000000L
2130 unsigned long code = ERR_get_error_line(&file,&line);
2131#else
2132 unsigned long code = ERR_get_error_all(&file, &line, NULL, NULL, NULL);
2133#endif
2134 if ( code == 0 )
2135 {
2136 break;
2137 }
2138
2139 char buf[256];
2140 ERR_error_string_n(code,buf,sizeof(buf));
2141 ErrLog( << buf );
2142 InfoLog( << "Error code = " << code << " file=" << file << " line=" << line );
2143 }
2144
2145 BIO_free(in);
2146 BIO_free(out);
2147 sk_X509_free(certs);
2148 PKCS7_free(pkcs7);
2149 return 0;
2150 }
2151 }
2152 break;
2153
2154 default:
2155 BIO_free(in);
2156 BIO_free(out);
2157 sk_X509_free(certs);
2158 PKCS7_free(pkcs7);
2159 ErrLog(<< "Got PKCS7 data that could not be handled type=" << type );
2160 throw Exception("Unsupported PKCS7 data type", __FILE__, __LINE__);
2161 }
2162
2163 (void)BIO_flush(out);
2164 BUF_MEM* bufMem;
2165 BIO_get_mem_ptr(out, &bufMem);
2166
2167 int len = (int)bufMem->length;
2168 char* buffer = new char[len];
2169 memcpy(buffer, bufMem->data, len);
2170
2171 (void)BIO_set_close(out, BIO_CLOSE);
2172 BIO_free(in);
2173 BIO_free(out);
2174 sk_X509_free(certs);
2175 PKCS7_free(pkcs7);
2176
2177 // parse out the header information and form new body.
2178 // TODO !jf! this is a really crappy parser - shoudl do proper mime stuff
2179 ParseBuffer pb(buffer, len);
2180
2181 const char* headerStart = pb.position();
2182
2183 // pull out contents type only
2184 pb.skipToChars("Content-Type");
2185 pb.assertNotEof();
2186
2188 pb.skipChar();
2189 pb.assertNotEof();
2190
2191 pb.skipWhitespace();
2192 const char* typeStart = pb.position();
2193 pb.assertNotEof();
2194
2195 // determine contents-type header buffer
2196 pb.skipToTermCRLF();
2197 pb.assertNotEof();
2198
2199 ParseBuffer subPb(typeStart, pb.position() - typeStart);
2200 Mime contentType;
2201 contentType.parse(subPb);
2202
2203 pb.assertNotEof();
2204
2205 // determine body start
2206 pb.reset(typeStart);
2207 const char* bodyStart = pb.skipToChars(Symbols::CRLFCRLF);
2208 pb.assertNotEof();
2209 bodyStart += 4;
2210
2211 // determine contents body buffer
2212 pb.skipToEnd();
2213 Data tmp;
2214 pb.data(tmp, bodyStart);
2215 // create contents against body
2216 Contents* ret = Contents::createContents(contentType, tmp);
2217 ret->addBuffer(buffer);
2218
2219 // pre-parse headers
2220 ParseBuffer headersPb(headerStart, bodyStart-4-headerStart);
2221 ret->preParseHeaders(headersPb);
2222
2223 InfoLog( << "Got body data of " << ret->getBodyData() );
2224
2225 return ret;
2226}
2227
2228
2229
2230
2231
2232Contents*
2234 Data* signedBy,
2235 SignatureStatus* sigStat )
2236{
2237 // RFC 1847: the signature covers the first body part exactly as it was
2238 // received. Take those bytes first, because the mutable parts() calls
2239 // below drop them. The Data is returned by value and keeps working after
2240 // that.
2241 const Data rawFirst = multi->getRawFirstPart();
2242
2243 if ( multi->parts().size() != 2 )
2244 {
2245 ErrLog(<< "Trying to decode a message with wrong number of contents " << multi->parts().size());
2246 throw Exception("Invalid contents passed to checkSignature", __FILE__, __LINE__);
2247 }
2248
2249 MultipartSignedContents::Parts::const_iterator it = multi->parts().begin();
2250 Contents* first = *it;
2251 ++it;
2252 resip_assert( it != multi->parts().end() );
2253 Contents* second = *it;
2254
2255 resip_assert( second );
2256 resip_assert( first );
2257
2258 InfoLog( << "message to signature-check is " << *first );
2259
2260 Pkcs7SignedContents* sig = dynamic_cast<Pkcs7SignedContents*>( second );
2261 if ( !sig )
2262 {
2263 ErrLog( << "Don't know how to deal with signature type " );
2264 //throw Exception("Invalid contents passed to checkSignature", __FILE__,
2265 //__LINE__);
2266 return first;
2267 }
2268 Data sigData = sig->getBodyData();
2269
2270 Data textData;
2271 if (!rawFirst.empty())
2272 {
2273 textData = rawFirst;
2274 }
2275 else
2276 {
2277 // Nothing recorded. Three ways to get here, and only the last one is
2278 // a defect:
2279 //
2280 // - the body was built locally rather than parsed, so the re-encoding
2281 // is both all there is and what goes on the wire;
2282 // - the body is a copy of one that had already been parsed. A copy
2283 // keeps the parts but not the view, and SipMessage::init() clones
2284 // mContents, so an ordinary message copy lands here;
2285 // - something upstream reached the body through the mutable parts().
2286 //
2287 // From here the three are indistinguishable, so say which path was
2288 // taken. Without this line a future caller that drops the bytes turns
2289 // into "signatures mysteriously stopped verifying" instead of something
2290 // greppable.
2291 InfoLog( << "No received bytes recorded for the first body part; "
2292 << "verifying against a re-encoding. Expected for a locally "
2293 << "built body and for a copy of an already parsed one; a "
2294 << "regression if this body was parsed here, which happens when "
2295 << "a caller reaches it through the mutable "
2296 << "MultipartMixedContents::parts()." );
2297
2298 DataStream strm( textData );
2299 first->encodeHeaders( strm );
2300 first->encode( strm );
2301 strm.flush();
2302 }
2303
2304 InfoLog( << "text <" << textData.escaped() << ">" );
2305 InfoLog( << "signature <" << sigData.escaped() << ">" );
2306
2307 static const char RESIP_ASN_UNCODE_SIGNED_TEXT[] = "resip-asn-uncode-signed-text";
2308 static const char RESIP_ASN_UNCODE_SIGNED_SIG[] = "resip-asn-uncode-signed-sig";
2309
2310 Security::dumpAsn( RESIP_ASN_UNCODE_SIGNED_TEXT, textData );
2311 Security::dumpAsn( RESIP_ASN_UNCODE_SIGNED_SIG, sigData );
2312
2313 BIO* in = BIO_new_mem_buf( (void*)sigData.data(),(int)sigData.size());
2314 resip_assert(in);
2315 InfoLog( << "created in BIO");
2316
2317 BIO* out = BIO_new(BIO_s_mem());
2318 resip_assert(out);
2319 InfoLog( << "created out BIO" );
2320
2321 BIO* pkcs7Bio = BIO_new_mem_buf( (void*) textData.data(),(int)textData.size());
2322 resip_assert(pkcs7Bio);
2323 InfoLog( << "created pkcs7 BIO");
2324
2325 PKCS7* pkcs7 = d2i_PKCS7_bio(in, 0);
2326 if ( !pkcs7 )
2327 {
2328 ErrLog( << "Problems doing decode of PKCS7 object <"
2329 << sigData.escaped() << ">" );
2330
2331 while (1)
2332 {
2333 const char* file;
2334 int line;
2335
2336#if OPENSSL_VERSION_NUMBER < 0x30000000L
2337 unsigned long code = ERR_get_error_line(&file,&line);
2338#else
2339 unsigned long code = ERR_get_error_all(&file, &line, NULL, NULL, NULL);
2340#endif
2341 if ( code == 0 )
2342 {
2343 break;
2344 }
2345
2346 char buf[256];
2347 ERR_error_string_n(code,buf,sizeof(buf));
2348 ErrLog( << buf );
2349 InfoLog( <<"Error code = "<< code <<" file=" << file << " line=" << line );
2350 }
2351 BIO_free(in);
2352 BIO_free(out);
2353 BIO_free(pkcs7Bio);
2354
2355 return first;
2356 }
2357 (void)BIO_flush(in);
2358
2359 int type=OBJ_obj2nid(pkcs7->type);
2360 InfoLog( << "data is " << OBJ_nid2ln(type) );
2361
2362 STACK_OF(X509)* certs = 0;
2363 certs = sk_X509_new_null();
2364 resip_assert( certs );
2365
2366 if ( *signedBy == Data::Empty )
2367 {
2368 //add all the certificates from mUserCerts stack to 'certs' stack
2369 for(X509Map::iterator it = mUserCerts.begin(); it != mUserCerts.end(); it++)
2370 {
2371 resip_assert(it->second);
2372 sk_X509_push(certs, it->second);
2373 }
2374 }
2375 else
2376 {
2377 if (mUserCerts.find( *signedBy ) != mUserCerts.end())
2378 {
2379 InfoLog( <<"Adding cert from " << *signedBy << " to check sig" );
2380 X509* cert = mUserCerts[ *signedBy ];
2381 resip_assert(cert);
2382 sk_X509_push(certs, cert);
2383 }
2384 }
2385
2386 int flags = 0;
2387 flags |= PKCS7_NOINTERN;
2388
2389 // matches on certificate issuer and serial number - they must be unique
2390 STACK_OF(X509)* signers = PKCS7_get0_signers(pkcs7, certs, flags);
2391 if ( signers )
2392 {
2393
2394 DebugLog( << "Found " << sk_X509_num(signers) << " signers." );
2395 for (int i=0; i<sk_X509_num(signers); i++)
2396 {
2397 X509* x = sk_X509_value(signers, i);
2398 InfoLog(<< "Got a signer <" << i << "> : " << getCertName(x) );
2399
2400 GENERAL_NAMES* gens = 0;
2401 gens = (GENERAL_NAMES*)X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL);
2402
2403 for (int j = 0; j < sk_GENERAL_NAME_num(gens); j++)
2404 {
2405 GENERAL_NAME* gen = sk_GENERAL_NAME_value(gens, j);
2406 if (gen->type == GEN_URI)
2407 {
2408 ASN1_IA5STRING* uri = gen->d.uniformResourceIdentifier;
2409 Data name(ASN1_STRING_get0_data(uri), ASN1_STRING_length(uri));
2410 InfoLog(<< "subjectAltName of signing cert contains <" << name << ">" );
2411 try
2412 {
2413 Uri n(name);
2414 if ( n.scheme() == "sip" )
2415 {
2416 *signedBy = name;
2417 InfoLog(<< "choose <" << name << "> signature" );
2418 }
2419 }
2420 catch (ParseException& e)
2421 {
2422 ErrLog(<<"Caught exception: "<< e);
2423 }
2424 }
2425 }
2426
2427 sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
2428 }
2429 }
2430 else
2431 {
2432 BIO_free(in);
2433 BIO_free(out);
2434 BIO_free(pkcs7Bio);
2435 sk_X509_free(certs);
2436 PKCS7_free(pkcs7);
2437 *sigStat = SignatureIsBad;
2438 InfoLog(<< "No valid signers of this messages" );
2439 return first;
2440 }
2441
2442#if 0
2443 // this is debugging information to get the serial number of the signed
2444 // information
2445 STACK_OF(PKCS7_SIGNER_INFO) *sinfos;
2446 PKCS7_SIGNER_INFO *si;
2447 PKCS7_ISSUER_AND_SERIAL *ias;
2448 ASN1_INTEGER* asnSerial;
2449 long longSerial;
2450 X509_NAME* name;
2451
2452 sinfos = PKCS7_get_signer_info(pkcs7);
2453 if ( sinfos )
2454 {
2455 int num = sk_PKCS7_SIGNER_INFO_num(sinfos);
2456 for ( int i=0; i<num; i++ )
2457 {
2458 si = sk_PKCS7_SIGNER_INFO_value (sinfos, i) ;
2459 ias = si->issuer_and_serial;
2460 name = ias->issuer;
2461 asnSerial = ias->serial;
2462 longSerial = ASN1_INTEGER_get( (ASN1_INTEGER*)asnSerial );
2463 InfoLog( << "Signed with serial " << hex << longSerial );
2464 InfoLog( << "Name " << name );
2465 }
2466 }
2467#endif
2468
2470
2471 switch (type)
2472 {
2473 case NID_pkcs7_signed:
2474 {
2475 int flags = 0;
2476
2477 if (isSelfSigned(sk_X509_value(signers,0)))
2478 {
2479 flags |= PKCS7_NOVERIFY;
2480 }
2481
2482 if ( PKCS7_verify(pkcs7, certs, mRootTlsCerts, pkcs7Bio, out, flags ) != 1 )
2483 {
2484 ErrLog( << "Problems doing PKCS7_verify" );
2485
2486 if ( sigStat )
2487 {
2488 *sigStat = SignatureIsBad;
2489 }
2490
2491 while (1)
2492 {
2493 const char* file;
2494 int line;
2495
2496#if OPENSSL_VERSION_NUMBER < 0x30000000L
2497 unsigned long code = ERR_get_error_line(&file,&line);
2498#else
2499 unsigned long code = ERR_get_error_all(&file, &line, NULL, NULL, NULL);
2500#endif
2501 if ( code == 0 )
2502 {
2503 break;
2504 }
2505
2506 char buf[256];
2507 ERR_error_string_n(code,buf,sizeof(buf));
2508 ErrLog( << buf );
2509 InfoLog( << "Error code = " << code << " file=" << file << " line=" << line );
2510 }
2511 BIO_free(in);
2512 BIO_free(out);
2513 BIO_free(pkcs7Bio);
2514 sk_X509_free(certs);
2515 PKCS7_free(pkcs7);
2516 return first;
2517 }
2518 if ( sigStat )
2519 {
2520 if ( (flags & PKCS7_NOVERIFY) )
2521 {
2522 if (isSelfSigned(sk_X509_value(signers,0)))
2523 {
2524 DebugLog( << "Signature is selfSigned");
2525 *sigStat = SignatureSelfSigned;
2526 }
2527 else
2528 {
2529 DebugLog( << "Signature is notTrusted" );
2530 *sigStat = SignatureNotTrusted;
2531 }
2532 }
2533 else
2534 {
2535 if (false) // !jf! TODO look for this cert in store
2536 {
2537 DebugLog( << "Signature is trusted" );
2538 *sigStat = SignatureTrusted;
2539 }
2540 else
2541 {
2542 DebugLog( << "Signature is caTrusted" );
2543 *sigStat = SignatureCATrusted;
2544 }
2545 }
2546 }
2547 }
2548 break;
2549
2550 default:
2551 BIO_free(in);
2552 BIO_free(out);
2553 BIO_free(pkcs7Bio);
2554 sk_X509_free(certs);
2555 PKCS7_free(pkcs7);
2556 ErrLog(<< "Got PKCS7 data that could not be handled type=" << type );
2557 return 0;
2558 }
2559
2560 (void)BIO_flush(out);
2561 char* outBuf=0;
2562 long size = BIO_get_mem_data(out,&outBuf);
2563 resip_assert( size >= 0 );
2564
2565 Data outData(outBuf,size);
2566 DebugLog( << "uncoded body is <" << outData.escaped() << ">" );
2567
2568 BIO_free(in);
2569 BIO_free(out);
2570 BIO_free(pkcs7Bio);
2571 sk_X509_free(certs);
2572 PKCS7_free(pkcs7);
2573 return first;
2574}
2575
2576
2577SSL_CTX*
2579{
2581 return mTlsCtx;
2582}
2583
2584
2585SSL_CTX*
2587{
2589 return mSslCtx;
2590}
2591
2592void
2593BaseSecurity::getCertNames(X509 *cert, std::list<PeerName> &peerNames,
2594 bool useEmailAsSIP)
2595{
2596 if(NULL == cert)
2597 return;
2598
2599 if(peerNames.size() > 0)
2600 peerNames.clear();
2601
2602 Data commonName;
2603
2604 // look at the Common Name to find the peerName of the cert
2605 const X509_NAME* subject = X509_get_subject_name(cert);
2606 if(NULL == subject)
2607 {
2608 ErrLog( << "Invalid certificate: subject not found ");
2609 return;
2610 }
2611
2612 int i =-1;
2613 while( true )
2614 {
2615 // OpenSSL 1.1.1 takes a non-const X509_NAME here, 3.0+ a const one
2616 i = X509_NAME_get_index_by_NID(const_cast<X509_NAME*>(subject), NID_commonName,i);
2617 if ( i == -1 )
2618 {
2619 break;
2620 }
2621 resip_assert( i != -1 );
2622 const X509_NAME_ENTRY* entry = X509_NAME_get_entry(subject,i);
2623 resip_assert( entry );
2624
2625 const ASN1_STRING* s = X509_NAME_ENTRY_get_data(entry);
2626 resip_assert( s );
2627
2628 int t = ASN1_STRING_type(s);
2629 int l = ASN1_STRING_length(s);
2630 const unsigned char* d = ASN1_STRING_get0_data(s);
2631 Data name(d,l);
2632 DebugLog( << "got x509 string type=" << t << " len="<< l << " data=" << d );
2633 resip_assert( name.size() == (unsigned)l );
2634
2635 DebugLog( << "Found common name in cert of " << name );
2636
2637 commonName = name;
2638 }
2639
2640#if 0 // junk code to print certificates extensions for debugging
2641 int numExt = X509_get_ext_count(cert);
2642 ErrLog(<< "Got peer certificate with " << numExt << " extensions" );
2643
2644 for ( int i=0; i<numExt; i++ )
2645 {
2646 X509_EXTENSION* ext = X509_get_ext(cert,i);
2647 resip_assert( ext );
2648
2649 const char* str = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext)));
2650 resip_assert(str);
2651 DebugLog(<< "Got certificate extension" << str );
2652
2653 if ( OBJ_obj2nid(X509_EXTENSION_get_object(ext)) == NID_subject_alt_name )
2654 {
2655 DebugLog(<< "Got subjectAltName extension" );
2656 }
2657 }
2658#endif
2659
2660 // Look at the SubjectAltName, and if found, set as peerName
2661 GENERAL_NAMES* gens;
2662 gens = (GENERAL_NAMES*)X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
2663 for(int i = 0; i < sk_GENERAL_NAME_num(gens); i++)
2664 {
2665 GENERAL_NAME* gen = sk_GENERAL_NAME_value(gens, i);
2666
2667 DebugLog(<< "subjectAltName of cert contains type <" << gen->type << ">" );
2668
2669 if (gen->type == GEN_DNS)
2670 {
2671 ASN1_IA5STRING* asn = gen->d.dNSName;
2672 Data dns(ASN1_STRING_get0_data(asn), ASN1_STRING_length(asn));
2673 PeerName peerName(SubjectAltName, dns);
2674 peerNames.push_back(peerName);
2675 InfoLog(<< "subjectAltName of TLS session cert contains DNS <" << dns << ">" );
2676 }
2677
2678 if (gen->type == GEN_EMAIL)
2679 {
2680 if(useEmailAsSIP)
2681 {
2682 ASN1_IA5STRING* asn = gen->d.rfc822Name;
2683 Data email(ASN1_STRING_get0_data(asn), ASN1_STRING_length(asn));
2684 PeerName peerName(SubjectAltName, email);
2685 peerNames.push_back(peerName);
2686 InfoLog(<< "subjectAltName of TLS session cert contains EMAIL <" << email << ">" );
2687 }
2688 else
2689 DebugLog(<< "subjectAltName of cert has EMAIL type" );
2690 }
2691
2692 if (gen->type == GEN_IPADD)
2693 {
2694 // RFC 3280 "For IP Version 4, as specified in RFC 791, the octet string
2695 // MUST contain exactly four octets. For IP Version 6, as specified in
2696 // RFC 1883, the octet string MUST contain exactly sixteen octets."
2697 ASN1_OCTET_STRING* asn = gen->d.iPAddress;
2698 const unsigned char* asnData = ASN1_STRING_get0_data(asn);
2699 const int asnLen = ASN1_STRING_length(asn);
2700 if (asnLen == 4)
2701 {
2702 uint32_t ip = (asnData[0] << 24) |
2703 (asnData[1] << 16) |
2704 (asnData[2] << 8) |
2705 (asnData[3]);
2706
2707 sockaddr_in sa;
2708 sa.sin_family = AF_INET;
2709 sa.sin_addr.s_addr = htonl(ip);
2710
2711 char addrStr[INET_ADDRSTRLEN];
2712 if (inet_ntop(sa.sin_family, &(sa.sin_addr), addrStr, INET_ADDRSTRLEN) != NULL)
2713 {
2714 Data ipv4(addrStr);
2715 PeerName peerName(SubjectAltName, ipv4);
2716 peerNames.push_back(peerName);
2717 InfoLog(<< "subjectAltName of TLS session cert contains IP ADDRESS <" << ipv4 << ">" );
2718 }
2719 }
2720 else if (asnLen == 16)
2721 {
2722 sockaddr_in6 sa;
2723 sa.sin6_family = AF_INET6;
2724 sa.sin6_addr.s6_addr[0] = asnData[0];
2725 sa.sin6_addr.s6_addr[1] = asnData[1];
2726 sa.sin6_addr.s6_addr[2] = asnData[2];
2727 sa.sin6_addr.s6_addr[3] = asnData[3];
2728 sa.sin6_addr.s6_addr[4] = asnData[4];
2729 sa.sin6_addr.s6_addr[5] = asnData[5];
2730 sa.sin6_addr.s6_addr[6] = asnData[6];
2731 sa.sin6_addr.s6_addr[7] = asnData[7];
2732 sa.sin6_addr.s6_addr[8] = asnData[8];
2733 sa.sin6_addr.s6_addr[9] = asnData[9];
2734 sa.sin6_addr.s6_addr[10] = asnData[10];
2735 sa.sin6_addr.s6_addr[11] = asnData[11];
2736 sa.sin6_addr.s6_addr[12] = asnData[12];
2737 sa.sin6_addr.s6_addr[13] = asnData[13];
2738 sa.sin6_addr.s6_addr[14] = asnData[14];
2739 sa.sin6_addr.s6_addr[15] = asnData[15];
2740
2741 char addrStr[INET6_ADDRSTRLEN];
2742 if (inet_ntop(sa.sin6_family, &(sa.sin6_addr), addrStr, INET6_ADDRSTRLEN) != NULL)
2743 {
2744 Data ipv6(addrStr);
2745 PeerName peerName(SubjectAltName, ipv6);
2746 peerNames.push_back(peerName);
2747 InfoLog(<< "subjectAltName of TLS session cert contains IP ADDRESS <" << ipv6 << ">" );
2748 }
2749 }
2750 else
2751 DebugLog(<< "subjectAltName of cert contains invalid IP ADDRESS" );
2752 }
2753
2754 if(gen->type == GEN_URI)
2755 {
2756 ASN1_IA5STRING* asn = gen->d.uniformResourceIdentifier;
2757 Data uriString(ASN1_STRING_get0_data(asn), ASN1_STRING_length(asn));
2758 try
2759 {
2760 // The Uri constructor parses, so it has to be inside the try: an
2761 // exception escaping from here would break the TLS handshake code
2762 Uri uri(uriString);
2763 PeerName peerName(SubjectAltName, uri.host());
2764 peerNames.push_back(peerName);
2765 InfoLog(<< "subjectAltName of TLS session cert contains URI <" << uri << ">" );
2766 }
2767 catch (...)
2768 {
2769 InfoLog(<< "subjectAltName of TLS session cert contains unparsable URI <" << uriString << ">, ignoring it");
2770 }
2771 }
2772 }
2773 sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
2774
2775 // If there are no peer names from the subjectAltName, then use the commonName,
2776 // if the certificate has one: an empty name would match an empty target domain
2777 if(peerNames.empty() && !commonName.empty())
2778 {
2779 PeerName peerName(CommonName, commonName);
2780 peerNames.push_back(peerName);
2781 }
2782}
2783
2784Data
2786{
2787 Data certName;
2788 std::list<PeerName> cNames;
2789
2790 //get all the names (subjectAltName or CommonName)
2791 getCertNames(cert, cNames);
2792
2793 //prefer the subjectAltName
2794 for(std::list<PeerName>::const_iterator it = cNames.begin(); it != cNames.end(); it++)
2795 {
2796 if(it->mType == SubjectAltName)
2797 {
2798 return it->mName;
2799 }
2800 }
2801
2802 //if not subjectAltName found, get the CommonName
2803 for(std::list<PeerName>::const_iterator it = cNames.begin(); it != cNames.end(); it++)
2804 {
2805 if(it->mType == CommonName)
2806 {
2807 return it->mName;
2808 }
2809 }
2810 ErrLog(<< "This certificate doesn't have neither subjectAltName nor commonName");
2811 return Data::Empty;
2812}
2816int
2817BaseSecurity::matchHostName(const Data& certificateName, const Data& domainName)
2818{
2819 // An empty name never identifies anyone, even when both are empty
2820 if(certificateName.empty() || domainName.empty())
2821 {
2822 return 0;
2823 }
2825 return matchHostNameWithWildcards(certificateName,domainName);
2826 return isEqualNoCase(certificateName,domainName);
2827}
2834{
2835 if(isEqualNoCase(typeName, "TLSv1"))
2836 {
2837 return SecurityTypes::TLSv1;
2838 }
2839 if(isEqualNoCase(typeName, "SSLv23") || isEqualNoCase(typeName, "DynamicTLS"))
2840 {
2842 }
2843 Data error = "Not a recognized SSL type: " + typeName;
2844 throw invalid_argument(error.c_str());
2845}
2850long
2852{
2853 return resip::parseOpenSSLCTXOption(optionName);
2854}
2862int
2863BaseSecurity::matchHostNameWithWildcards(const Data& certificateName, const Data& domainName)
2864{
2865 if(isEqualNoCase(certificateName, domainName))
2866 {
2867 return 1;
2868 }
2869
2870 static const Data wildcardLabel("*.");
2871 if(!certificateName.prefix(wildcardLabel) || DnsUtil::isIpAddress(domainName))
2872 {
2873 return 0;
2874 }
2875
2876 // What the wildcard's label is followed by has to be two labels or more,
2877 // otherwise "*.com" would match every host in a top-level domain
2878 const Data certificateBase = certificateName.substr(wildcardLabel.size());
2879 const Data::size_type baseDot = certificateBase.find(".");
2880 if(baseDot == Data::npos || baseDot == 0 || baseDot + 1 == certificateBase.size())
2881 {
2882 return 0;
2883 }
2884
2885 // The wildcard stands for the domain name's first label, which can't be empty
2886 const Data::size_type dot = domainName.find(".");
2887 if(dot == Data::npos || dot == 0)
2888 {
2889 return 0;
2890 }
2891 return isEqualNoCase(domainName.substr(dot + 1), certificateBase);
2892}
2893
2894bool
2896{
2897 X509 *mutableCert = const_cast<X509*>(cert);
2898 int iRet = X509_NAME_cmp(X509_get_issuer_name(mutableCert), X509_get_subject_name(mutableCert));
2899 return (iRet == 0);
2900}
2901
2902void
2903BaseSecurity::dumpAsn(const char* name, Data data)
2904{
2905#if 0 // for debugging
2906 resip_assert(name);
2907
2908 if (true) // dump asn.1 stuff to debug file
2909 {
2910 ofstream strm(name, std::ios_base::trunc);
2911 if ( !strm )
2912 {
2913 ErrLog( <<"Could not write to " << name );
2914 }
2915 else
2916 {
2917 strm.write( data.data() , data.size() );
2918 }
2919 strm.flush();
2920 }
2921#endif
2922}
2923
2924X509*
2926{
2927 auto it = mDomainCerts.find(domain);
2928 if (it != mDomainCerts.end())
2929 {
2930 return it->second;
2931 }
2932 return nullptr;
2933}
2934
2935X509*
2937{
2938 auto it = mUserCerts.find(aor);
2939 if (it != mUserCerts.end())
2940 {
2941 return it->second;
2942 }
2943 return nullptr;
2944}
2945
2946EVP_PKEY*
2948{
2949 auto it = mDomainPrivateKeys.find(domain);
2950 if (it != mDomainPrivateKeys.end())
2951 {
2952 return it->second;
2953 }
2954 return nullptr;
2955}
2956
2957EVP_PKEY*
2959{
2960 auto it = mUserPrivateKeys.find(aor);
2961 if (it != mUserPrivateKeys.end())
2962 {
2963 return it->second;
2964 }
2965 return nullptr;
2966}
2967
2968void
2970{
2972 {
2973 InfoLog(<< "Unable to load DH parameters (required for PFS): TlsDHParamsFilename not specified");
2974 }
2975 else
2976 {
2977 DebugLog(<< "Attempting to read DH parameters from " << mDHParamsFilename);
2978
2979 BIO* bio = BIO_new_file(mDHParamsFilename.c_str(), "r");
2980 if(bio == NULL)
2981 {
2982 WarningLog(<< "Unable to load DH parameters (required for PFS): BIO_new_file failed to open file " << mDHParamsFilename);
2983 ERR_clear_error();
2984 return;
2985 }
2986
2987 bool loaded = false;
2988#if OPENSSL_VERSION_NUMBER >= 0x30000000L
2989 // OpenSSL 3 deprecates the DH type and its functions: the parameters are read as an EVP_PKEY
2990 EVP_PKEY* dh = PEM_read_bio_Parameters(bio, NULL);
2991 if(dh == NULL || !(EVP_PKEY_is_a(dh, "DH") || EVP_PKEY_is_a(dh, "DHX")))
2992 {
2993 WarningLog(<< "Unable to load DH parameters (required for PFS): no DH parameters read from file " << mDHParamsFilename);
2994 EVP_PKEY_free(dh);
2995 }
2996 else if(!SSL_CTX_set0_tmp_dh_pkey(ctx, dh)) // takes dh, if it succeeds
2997 {
2998 WarningLog(<< "Unable to load DH parameters (required for PFS): SSL_CTX_set0_tmp_dh_pkey failed for file " << mDHParamsFilename);
2999 EVP_PKEY_free(dh);
3000 }
3001 else
3002 {
3003 loaded = true;
3004 }
3005#else
3006 DH* dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
3007 if(dh == NULL)
3008 {
3009 WarningLog(<< "Unable to load DH parameters (required for PFS): PEM_read_bio_DHparams failed for file " << mDHParamsFilename);
3010 }
3011 else
3012 {
3013 if(!SSL_CTX_set_tmp_dh(ctx, dh))
3014 {
3015 WarningLog(<< "Unable to load DH parameters (required for PFS): SSL_CTX_set_tmp_dh failed for file " << mDHParamsFilename);
3016 }
3017 else
3018 {
3019 loaded = true;
3020 }
3021 DH_free(dh);
3022 }
3023#endif
3024 BIO_free(bio);
3025
3026 if(loaded)
3027 {
3028#if OPENSSL_VERSION_NUMBER >= 0x30000000L
3029 uint64_t options;
3030#else
3031 long options;
3032#endif
3033 options = SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_SINGLE_DH_USE;
3034 options = SSL_CTX_set_options(ctx, options);
3035 DebugLog(<<"DH parameters loaded, PFS cipher-suites enabled");
3036 }
3037 else
3038 {
3039 ERR_clear_error(); // what failed is logged: don't leave it for the next OpenSSL call on this thread
3040 }
3041 }
3042}
3043
3044#endif
3045
3046
3047
3048
3049/* ====================================================================
3050* The Vovida Software License, Version 1.0
3051*
3052* Copyright (c) 2026 SIP Spectrum, Inc. https://www.sipspectrum.com
3053* Copyright (c) 2002-2005 Vovida Networks, Inc. All rights reserved.
3054*
3055* Redistribution and use in source and binary forms, with or without
3056* modification, are permitted provided that the following conditions
3057* are met:
3058*
3059* 1. Redistributions of source code must retain the above copyright
3060* notice, this list of conditions and the following disclaimer.
3061*
3062* 2. Redistributions in binary form must reproduce the above copyright
3063* notice, this list of conditions and the following disclaimer in
3064* the documentation and/or other materials provided with the
3065* distribution.
3066*
3067* 3. The names "VOCAL", "Vovida Open Communication Application Library",
3068* and "Vovida Open Communication Application Library (VOCAL)" must
3069* not be used to endorse or promote products derived from this
3070* software without prior written permission. For written
3071* permission, please contact vocal@vovida.org.
3072*
3073* 4. Products derived from this software may not be called "VOCAL", nor
3074* may "VOCAL" appear in their name, without prior written
3075* permission of Vovida Networks, Inc.
3076*
3077* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
3078* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
3079* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
3080* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
3081* NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
3082* IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
3083* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
3084* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
3085* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
3086* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3087* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
3088* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
3089* DAMAGE.
3090*
3091* ====================================================================
3092*
3093* This software consists of voluntary contributions made by Vovida
3094* Networks, Inc. and many individuals on behalf of Vovida Networks,
3095* Inc. For more information on Vovida Networks, Inc., please see
3096* <http://www.vovida.org/>.
3097*
3098*/
struct ssl_ctx_st SSL_CTX
struct evp_pkey_st EVP_PKEY
struct x509_st X509
struct ssl_st SSL
static Data digest("digest")
#define DebugLog(args_)
Definition Logger.hxx:128
#define StackLog(args_)
Definition Logger.hxx:125
#define InfoLog(args_)
Definition Logger.hxx:131
#define WarningLog(args_)
Definition Logger.hxx:134
#define ErrLog(args_)
Definition Logger.hxx:137
int verifyCallback(int iInCode, X509_STORE_CTX *pInStore)
#define resip_assert(x)
This file needs to work for both C and C++ code.
static const Data unknownKey("user_key_")
static const Data userKey("user_key_")
void clearList(T &m, Func &clearFunc)
static Data getAor(const Data &filename, const Security::PEMType &pemType)
Definition Security.cxx:94
static const Data rootCert("root_cert_")
static const Data PEM(".pem")
static const Data userCert("user_cert_")
static const Data domainKey("domain_key_")
int pem_passwd_cb(char *buf, int size, int rwflag, void *password)
Definition Security.cxx:393
static const Data pemTypePrefixes(Security::PEMType pType)
Definition Security.cxx:75
void clearMap(T &m, Func &clearFunc)
static const Data domainCert("domain_cert_")
Handles cross-platform sockets compatibility.
static const Data bodyData("Body")
static const struct nv flags[]
Definition adig.c:62
The abstract base-class for all exceptions thrown by resip code.
const char * what() const noexcept override
Data mDefaultPrivateKeyPassPhrase
Definition Security.hxx:234
void addCertDER(PEMType type, const Data &name, const Data &certDER, bool write)
Definition Security.cxx:550
EVP_PKEY * getUserPrivateKey(const Data &aor)
static int getResipConnectionExDataIdx()
Definition Security.cxx:101
virtual void onReadPEM(const Data &name, PEMType type, Data &buffer) const =0
Data getUserPassPhrase(const Data &aor) const
static SecurityTypes::SSLType parseSSLType(const Data &typeName)
Converts a string containing an SSL type name to the corresponding enum value.
Data getUserPrivateKeyDER(const Data &aor) const
static void dumpAsn(const char *, Data)
void generateUserCert(const Data &aor, int expireDays=365, int keyLen=2048)
void addUserCertPEM(const Data &aor, const Data &certPEM)
static long OpenSSLCTXClearOptions
Definition Security.hxx:92
MultipartSignedContents * signAndEncrypt(const Data &senderAor, Contents *, const Data &recipCertName)
bool hasUserCert(const Data &aor) const
void addPrivateKeyPEM(PEMType type, const Data &name, const Data &privateKeyPEM, bool write, const Data &privateKeyPassPhrase=Data::Empty)
Definition Security.cxx:940
void addCertPEM(PEMType type, const Data &name, const Data &certPEM, bool write)
Definition Security.cxx:574
void removeUserPrivateKey(const Data &aor)
PrivateKeyMap mUserPrivateKeys
Definition Security.hxx:247
Data computeIdentity(const Data &signerDomain, const Data &in) const
virtual ~BaseSecurity()
virtual void onWritePEM(const Data &name, PEMType type, const Data &buffer) const =0
void addRootCertPEM(const Data &x509PEMEncodedRootCerts)
void addUserCertDER(const Data &aor, const Data &certDER)
X509 * getUserCert(const Data &aor)
static Data getCertName(X509 *cert)
virtual void onRemovePEM(const Data &name, PEMType type) const =0
SSL_CTX * mTlsCtx
Note:
Definition Security.hxx:229
void addUserPrivateKeyDER(const Data &aor, const Data &certDER, const Data &privateKeyPassPhrase=Data::Empty)
Contents * checkSignature(MultipartSignedContents *, Data *signedBy, SignatureStatus *sigStat)
void setDHParams(SSL_CTX *ctx)
void addPrivateKeyDER(PEMType type, const Data &name, const Data &privateKeyDER, bool write, const Data &privateKeyPassPhrase=Data::Empty)
Definition Security.cxx:874
BaseSecurity(const CipherList &cipherSuite=StrongestSuite, const Data &defaultPrivateKeyPassPhrase=Data::Empty, const Data &dHParamsFilename=Data::Empty)
Data getPrivateKeyPEM(PEMType type, const Data &name) const
void setUserPassPhrase(const Data &aor, const Data &passPhrase)
void addCertX509(PEMType type, const Data &name, X509 *cert, bool write)
Definition Security.cxx:613
Data getDomainCertDER(const Data &domainName) const
EVP_PKEY * getDomainKey(const Data &domain)
SSL_CTX * getSslCtx()
static int matchHostNameWithWildcards(const Data &certificateName, const Data &domainName)
Matches a certificate name, which may hold a wildcard, against the domain name we connected to,...
static CipherList StrongestSuite
Definition Security.hxx:81
void removeDomainPrivateKey(const Data &domainName)
static void getCertNames(X509 *cert, std::list< PeerName > &peerNames, bool useEmailAsSIP=false)
static int matchHostName(const Data &certificateName, const Data &domainName)
Applies the certificate and domain name matching rules.
std::map< Data, EVP_PKEY * > PrivateKeyMap
Definition Security.hxx:215
Contents * decrypt(const Data &decryptorAor, const Pkcs7Contents *)
void removeDomainCert(const Data &domainName)
SSL_CTX * getTlsCtx()
CipherList mCipherList
Definition Security.hxx:233
bool checkIdentity(const Data &signerDomain, const Data &in, const Data &sig, X509 *cert=NULL) const
void removeCert(PEMType type, const Data &name)
Definition Security.cxx:734
void checkAndSetIdentity(SipMessage &msg, const Data &derCert=Data::Empty) const
static bool mAllowWildcardCertificates
Definition Security.hxx:266
void addPrivateKeyPKEY(PEMType type, const Data &name, EVP_PKEY *pKey, bool write)
Definition Security.cxx:791
bool hasUserPassPhrase(const Data &aor) const
static CipherList ExportableSuite
Definition Security.hxx:80
Data getDomainPrivateKeyPEM(const Data &domainName) const
void addDomainPrivateKeyPEM(const Data &domainName, const Data &privateKeyPEM, const Data &privateKeyPassPhrase=Data::Empty)
static bool isSelfSigned(const X509 *cert)
static void initialize()
bool hasCert(PEMType type, const Data &name, bool logErrors=true) const
Definition Security.cxx:690
void addUserPrivateKeyPEM(const Data &aor, const Data &certPEM, const Data &privateKeyPassPhrase=Data::Empty)
std::map< Data, X509 * > X509Map
Definition Security.hxx:213
Data getUserCertDER(const Data &aor) const
X509_STORE * mRootTlsCerts
Definition Security.hxx:239
PrivateKeyMap mDomainPrivateKeys
Definition Security.hxx:243
void removeUserCert(const Data &aor)
void addDomainCertDER(const Data &domainName, const Data &certDER)
Data getPrivateKeyDER(PEMType type, const Data &name) const
static long parseOpenSSLCTXOption(const Data &optionName)
Converts a string containing an OpenSSL option name (for SSL_CTX_set_options) to the numeric value fr...
X509_STORE * mRootSslCerts
Definition Security.hxx:240
bool hasUserPrivateKey(const Data &aor) const
void removePrivateKey(PEMType type, const Data &name)
void removeUserPassPhrase(const Data &aor)
static long OpenSSLCTXSetOptions
Note:
Definition Security.hxx:91
bool hasPrivateKey(PEMType type, const Data &name) const
PassPhraseMap mUserPassPhrases
Definition Security.hxx:246
X509 * getDomainCert(const Data &domain)
bool hasDomainPrivateKey(const Data &domainName) const
std::vector< CertificateInfo > CertificateInfoContainer
Definition Security.hxx:127
Data getCertDER(PEMType type, const Data &name) const
Definition Security.cxx:752
CertificateInfoContainer getRootCertDescriptions() const
void addDomainCertPEM(const Data &domainName, const Data &certPEM)
MultipartSignedContents * sign(const Data &senderAor, Contents *)
Data getUserPrivateKeyPEM(const Data &aor) const
Pkcs7Contents * encrypt(Contents *, const Data &recipCertName)
bool hasDomainCert(const Data &domainName, bool logErrors=true) const
void addAdditionalFailureString(const Data &additionalFailureString)
Base class for all SIP body types.
Definition Contents.hxx:51
void addBuffer(char *buf)
Definition Contents.cxx:668
virtual Data getBodyData() const
Definition Contents.cxx:661
const H_ContentType::Type & header(const H_ContentType &headerType) const
returns the value of the Content-Type header Throws an Contents::Exception if the header doesn't exis...
Definition Contents.cxx:280
EncodeStream & encodeHeaders(EncodeStream &str) const
encodes headers to an output stream
Definition Contents.cxx:588
static Contents * createContents(const Mime &contentType, const Data &contents)
factory method to create a Contents object from a mime type and a payload
Definition Contents.cxx:148
void preParseHeaders(ParseBuffer &pb)
Preforms preparsing on the headers stored in the ParseBuffer pb.
Definition Contents.cxx:453
virtual Contents * clone() const =0
returns a copy of a Contents object
An iostream that operates on an existing Data.
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Definition Data.hxx:90
Data base64decode() const
Performs RFC 3548 Base 64 decoding of the contents of this data.
Definition Data.cxx:2607
static const Data Empty
Constant that represents a zero-length data.
Definition Data.hxx:882
const char * c_str() const
Returns a null-terminated string representing.
Definition Data.cxx:1097
@ Borrow
The Data instance is borrowing the memory from the passed in buffer.
Definition Data.hxx:260
Data base64encode(bool useUrlSafe=false) const
Performs RFC 3548 Base 64 encoding of the contents of this data.
Definition Data.cxx:2682
static Data fromFile(const Data &filename)
Definition Data.cxx:2539
bool prefix(const Data &pre) const noexcept
Returns true if this Data starts with the bytes indicated by the passed-in Data.
Definition Data.cxx:1888
Data substr(size_type first, size_type count=Data::npos) const
Copies a portion of this Data into a new Data.
Definition Data.cxx:1932
bool empty() const noexcept
Checks whether the Data is empty.
Definition Data.hxx:591
size_t size_type
Definition Data.hxx:94
size_type size() const noexcept
Returns the number of bytes in this Data.
Definition Data.hxx:599
size_type find(const Data &match, size_type start=0) const
Finds a specified sequence of bytes in this Data.
Definition Data.cxx:1947
static const size_type npos
Represents an impossible position; returned to indicate failure to find.
Definition Data.hxx:887
Data hex() const
Returns a hexadecimal representation of the contents of this Data.
Definition Data.cxx:1577
Data escaped() const
Returns a representation of the contents of the data with any non-printable characters escaped.
Definition Data.cxx:1199
bool postfix(const Data &post) const noexcept
Returns true if this Data ends with the bytes indicated by the passed-in Data.
Definition Data.cxx:1910
const char * data() const noexcept
Returns a pointer to the contents of this Data.
Definition Data.hxx:608
static bool isIpAddress(const Data &ipAddress)
Definition DnsUtil.cxx:453
EncodeStream & encode(EncodeStream &str) const
Encodes this element to a stream, in the fashion it should be represented on the wire.
Represents the "media-type" element in the RFC 3261 grammar.
Definition Mime.hxx:20
virtual void parse(ParseBuffer &pb)
Definition Mime.cxx:120
Data getRawFirstPart() const
The first body part exactly as it arrived: header block, the empty line, and the body.
SIP body type for holding Multipart-Signed body contents (MIME content-type multipart/signed).
Provides string-parsing functionality with protection from buffer overflow.
CurrentPosition skipToEnd()
CurrentPosition skipWhitespace()
CurrentPosition skipToChars(const char *cs)
CurrentPosition skipToChar(char c)
CurrentPosition position() const
void reset(const char *pos)
void assertNotEof() const
CurrentPosition skipChar()
CurrentPosition skipToTermCRLF()
void data(Data &data, const char *start) const
make the passed in data share memory with the buffer (uses Data::Share)
BaseException used to indicate parse failures.
SIP body type for holding PKCS7 contents (MIME content-type application/pkcs7-mime).
SIP body type for holding PKCS7 Signed contents (MIME content-type application/pkcs7-signature).
static int getCryptoRandom()
Definition Random.cxx:330
const Uri & uri() const
void addCADirectory(const Data &caDirectory)
Definition Security.cxx:215
virtual void preload()
Definition Security.cxx:277
Security(const Data &pathToCerts, const CipherList &=StrongestSuite, const Data &defaultPrivateKeyPassPhrase=Data::Empty, const Data &dHParamsFilename=Data::Empty)
Definition Security.cxx:203
virtual SSL_CTX * createDomainCtx(const SSL_METHOD *method, const Data &domain, const Data &certificateFilename, const Data &privateKeyFilename, const Data &privateKeyPassPhrase)
Throws BaseSecurity::Exception if the certificate or private key can't be loaded; nothing is left all...
Definition Security.cxx:407
virtual void onWritePEM(const Data &name, PEMType type, const Data &buffer) const
Definition Security.cxx:521
virtual void onReadPEM(const Data &name, PEMType type, Data &buffer) const
Definition Security.cxx:511
virtual void updateDomainCtx(SSL_CTX *ctx, const Data &domain, const Data &certificateFilename, const Data &privateKeyFilename, const Data &privateKeyPassPhrase)
Loads the domain's certificate chain and private key into ctx.
Definition Security.cxx:454
virtual void onRemovePEM(const Data &name, PEMType type) const
Definition Security.cxx:543
void loadCAFile(const Data &fileName)
Definition Security.cxx:259
void addCAFile(const Data &caFile)
Definition Security.cxx:226
void loadCADirectory(const Data &directoryName)
Definition Security.cxx:232
Represents a SIP message.
void setSecurityAttributes(std::unique_ptr< SecurityAttributes >) noexcept
const RequestLine & const_header(const RequestLineType &l) const
Data getCanonicalIdentityString() const
static const char * COLON
Definition Symbols.hxx:15
static const char * SLASH
Definition Symbols.hxx:32
static const char * CRLFCRLF
Definition Symbols.hxx:22
static uint64_t getTimeMs()
Returns the current clock time in milliseconds.
Definition Timer.hxx:72
Represents the "SIP-URI" and "SIPS-URI" elements in the RFC 3261 grammar.
Definition Uri.hxx:22
Data getAor() const
Definition Uri.cxx:1095
Data & scheme()
Definition Uri.hxx:143
Data & host()
Definition Uri.hxx:40
SSLType
Note: Before adding to the SSLType enum, please see the comments about mTlsCtx in resip/stack/ssl/Sec...
dcm! – add UnusedChecking(_enum) below;
bool isEqualNoCase(const Data &left, const Data &right)
Definition Data.hxx:1116
unsigned long long uint64_t
Definition Stun.hxx:39
unsigned int uint32_t
Definition Stun.hxx:34
long parseOpenSSLCTXOption(const Data &optionName)
Converts an OpenSSL option name (eg.
H_Identitys h_Identities
Definition Headers.cxx:315
std::string strError(int err)
Definition compat.hxx:274