24#include <isode/base/crypto.h>
25#include <openssl/err.h>
26#include <openssl/rand.h>
27#include <openssl/ssl.h>
28#include <isode/compat/stream.h>
29#include <isode/crypto/x509.h>
30#include <isode/crypto/verify.h>
31#include <isode/messages/base.h>
32#include <isode/messages/address.h>
37#define VERIFY_DEPTH_SHIFT 4
38#define VERIFY_CHOICE_MASK ((1<<VERIFY_DEPTH_SHIFT)-1)
41 std::string cipherSuites (
const cipher_suites_t&);
48 OpenSSLContext *ctx =
new OpenSSLContext ();
50 if ( ctx->Configure (confobj, msp) == 0 )
60 typedef std::map<TLS_CipherSuite,std::string> SuiteToName;
61 static SuiteToName suite_names;
66 SuiteToName::const_iterator i = suite_names.find(suite);
67 return i==suite_names.end() ?
"":i->second.c_str();
72 pthread_mutex_t OpenSSLContext::globalmutex = PTHREAD_MUTEX_INITIALIZER;
73 bool OpenSSLContext::globalinit =
false;
74 cipher_suites_t OpenSSLContext::available_suites;
75 cipher_suites_t OpenSSLContext::default_suites;
77 static void cipher_suites(cipher_suites_t& suites,
const char* desc = 0)
79 SSL_CTX* myctx = SSL_CTX_new(SSLv23_method());
84 if (SSL_CTX_set_cipher_list(myctx, desc ? desc :
"ALL:COMPLEMENTOFALL") == 0) {
87 SSL* ssl = SSL_new(myctx);
88 STACK_OF(SSL_CIPHER) *ciphers = SSL_get_ciphers(ssl);
90 int n = sk_SSL_CIPHER_num(ciphers);
92 for (
int i = 0; i < n; i++) {
93 const SSL_CIPHER *c = sk_SSL_CIPHER_value(ciphers, i);
94 TLS_CipherSuite
id = cipher_id(c);
96 suite_names.insert(std::make_pair(
id, SSL_CIPHER_get_name(c)));
103 OpenSSLContext::~OpenSSLContext ()
109 int OpenSSLContext::Configure (Config *confobj, MSGstruct *msp)
116 if ( pthread_mutex_lock (&globalmutex) != 0 )
117 MSG_Base_Tmutexlock_LOG (
"OpenSSLContext::Configure");
120 cipher_suites(available_suites);
121 cipher_suites(default_suites,
"DEFAULT");
125 if ( pthread_mutex_unlock (&globalmutex) != 0 )
126 MSG_Base_Tunlock_LOG (
"OpenSSLContext::Configure");
128 envptr = confobj->envptr;
129 dontTrustIdentities = confobj->dontTrustIdentities;
131 if ( !envptr.get() ) {
135 bool allow_pkcs11 = !confobj->pkcs11_uri.empty();
136 if (allow_pkcs11 && (confobj->pkcs11_module_path.empty() ||
137 confobj->pkcs11_user_pphr.empty() ||
138 confobj->pkcs11_cert.empty())) {
139 MSG_IOevent_SSLerror_LOG(
"PKCS11",
140 "tlsPKCS11ModulePath, tlsPKCS11PPhr, tlsPKCS11URI and tlsPKCS11Cert must all be set.");
141 allow_pkcs11 =
false;
144 envptr = ICrypto::Environment::Init (0, 0,
true, msp, allow_pkcs11);
145 if ( !envptr.get() )
return MSG2msgid (msp);
149 if (!confobj->identity_p12Bytes.empty()) {
150 auto p12_bytes = confobj->identity_p12Bytes.c_str();
151 auto p12_len = confobj->identity_p12Bytes.size();
152 auto uri = envptr->LoadPKCS12FromMemory(p12_bytes, p12_len, confobj->identity_passphrase.c_str());
154 std::string tlskeyptr = ICRYPTO_TLS
":default::rsa-key";
155 if (OK == envptr->ConfigStr(tlskeyptr.c_str(), uri.c_str(), msp)) {
158 id_uris.push_back(uri);
160 }
else if (allow_pkcs11) {
162 if (envptr->LoadPKCS11IdentityTLS(
163 confobj->pkcs11_module_path,
164 confobj->pkcs11_module_init,
165 confobj->pkcs11_user_pphr,
167 confobj->pkcs11_cert,
170 MSG_IOevent_SSLIDerror_LOG (confobj->pkcs11_uri.c_str());
174 id_uris.push_back(uri);
175 MSG_IOevent_SSLID_LOG (confobj->pkcs11_uri.c_str());
177 }
else if ( !have_tls_id && !confobj->identity.empty() ) {
179 std::string idpath(confobj->path(confobj->identity));
180 if (envptr->LoadTLSIdentities(
181 idpath, !confobj->dontTrustIdentities,
182 idsloaded, id_uris, file_found) != OK) {
183 MSG_IOevent_SSLIDerror_LOG (idpath.c_str());
185 }
else if (idsloaded != 0) {
186 MSG_IOevent_SSLID_LOG (idpath.c_str());
188 if (idsloaded == 0 && file_found) {
190 MSG_IOevent_SSLnoIDs_LOG();
192 LOG_DEBUG((
"TLS initialisation loaded %d identit%s",
193 idsloaded, idsloaded == 1 ?
"y" :
"ies" ));
196 have_tls_id = (idsloaded ? true :
false);
199 if ( !confobj->trustedCA_File.empty() )
200 loadCAsfromPEM (confobj->trustedCA_File.c_str());
202 loadCertsFromFiles (confobj, confobj->trustedCA_Files,
true);
203 loadCertsFromFiles (confobj, confobj->untrusted_Files,
false);
205 std::string tlskeyprefix = ICRYPTO_TLS
":default::";
207 std::string suitesStr = cipherSuites(confobj->suites);
208 if ( suitesStr.empty() )
209 suitesStr = confobj->suitesstr;
211 if ( suitesStr.empty() ) {
212 MSG_IOevent_SSLnosuites_SET (msp);
213 return MSG_IOevent_SSLnosuites;
216 std::string key = tlskeyprefix +
"cipher-suites";
217 int rc = envptr->ConfigStr (key.c_str(), suitesStr.c_str(), msp);
221 if ( !confobj->DHparametersFile.empty() ) {
222 key = tlskeyprefix +
"dhparams";
223 rc = envptr->ConfigStr (key.c_str(),
224 confobj->DHparametersFile.c_str(), msp);
229 if ( !confobj->randomSeedFile.empty() ) {
230 (void) envptr->RandomFile(confobj->randomSeedFile.c_str(), msp);
235 if ( !confobj->LDAPhost.empty() ) {
237 snprintf (ldapport,
sizeof ldapport,
"%d", confobj->LDAPport);
239 rc = envptr->ConfigStr (ICRYPTO_CONFIG
":lookup::ldap-host",
240 confobj->LDAPhost.c_str(), msp);
244 rc = envptr->ConfigStr (ICRYPTO_CONFIG
":lookup::ldap-port",
250 if ( !confobj->OCSPresponder.empty() ) {
251 rc = envptr->ConfigStr (ICRYPTO_CONFIG
":lookup::ocsp-trusted-responder",
252 confobj->OCSPresponder.c_str(), msp);
257 if ( !confobj->OCSPuri.empty() ) {
258 rc = envptr->ConfigStr (ICRYPTO_CONFIG
":lookup::ocsp-uri",
259 confobj->OCSPuri.c_str(), msp);
264 rc = envptr->ConfigStr (ICRYPTO_CONFIG
":lookup::ocsp-use-nonce",
265 confobj->OCSPnonce ?
"true" :
"false", msp);
269 rc = envptr->ConfigStr (ICRYPTO_CONFIG
":policy::check-crls",
270 confobj->checkRevocation ?
"on" :
"off",msp);
274 convertLookupFlags (confobj->lookup_flags);
280 ctx = envptr->GetSSLContext (confobj->IDcontext,
281 confobj->confset.length() ?
282 confobj->confset.c_str() : 0);
284 }
catch (MSGstruct message) {
288 return MSG2msgid (msp);
294 if ( confobj->confset.empty() ) {
297 if ( confobj->supportFlags ) {
298 SSL_CTX_clear_options (ctx, SSL_OP_ALL);
299 SSL_CTX_set_options (ctx, confobj->supportFlags);
302 SSL_CTX_set_options (ctx, SSL_OP_NO_SSLv2);
305 const char *idctx = confobj->IDcontext;
307 if (SSL_CTX_set_session_id_context(ctx,
308 (
const unsigned char *)idctx,
310 return SSLError (msp, MSG_IOevent_SSLerror,
"set_session_id");
312 long scto = confobj->sessionCacheTimeout;
315 (void)SSL_CTX_set_timeout(ctx, scto);
316 if (SSL_CTX_get_timeout(ctx) != scto)
317 LogSSLError (MSG_IOevent_SSLerror,
"set_timeout");
321 snprintf (depthbuf,
sizeof depthbuf,
"%d", confobj->verify_depth);
322 if ( ICrypto::ConfigureSSL (ctx,
"verify-depth", depthbuf, msp) != OK)
325 choice = confobj->verify_choice;
329 case tls_verify_none:
332 case tls_verify_require:
335 case tls_verify_optional:
343 if ( mode && ICrypto::ConfigureSSL (ctx,
"verify-mode", mode, msp) != OK)
350 bool OpenSSLContext::IsUsable ()
356 STACK_OF(SSL_CIPHER) *ciphers = SSL_CTX_get_ciphers(ctx);
360 return ciphers && (sk_SSL_CIPHER_num(ciphers) > 3 || have_tls_id);
364 SSL *OpenSSLContext::GetSSL (tls_verify_client_choice &verify_choice)
366 SSL *ssl = SSL_new (ctx);
368 verify_choice = choice;
374 void OpenSSLContext::loadCAsfromPEM (
const char *name)
378 if ( envptr->LoadCertsFromFile(name,
true, &message, &trust_anchor_uris) != OK )
379 LOGmessage (&message);
382 void OpenSSLContext::loadCertsFromFiles (
383 Config *confobj, std::list<std::string>& DER_files,
bool ista)
387 for (std::list<std::string>::const_iterator i=DER_files.begin();
388 i != DER_files.end(); ++i) {
389 std::string n(confobj->path(*i));
391 if ( envptr->LoadCertsFromFile(n.c_str(), ista, &message,
392 &trust_anchor_uris) != OK )
393 LOGmessage (&message);
397 std::list<X509*> OpenSSLContext::PullCertificates (
const std::list<std::string>& uris)
399 std::list<X509*> certs;
400 for (
auto certuri : uris) {
401 auto cert = envptr->GetCertificate(certuri.c_str());
403 X509* certp = cert.get()->GetX509();
406 certs.push_back(certp);
413 std::list<X509 *> OpenSSLContext::ServerCertificates (
void)
415 return PullCertificates(id_uris);
418 size_t OpenSSLContext::GetNbIdentities()
const {
419 return id_uris.size();
422 int OpenSSLContext::GetTlsInfo (
const ICryptoKeyType keyType,
424 std::vector<std::string>& san,
425 std::vector<std::vector<unsigned char>>& cert_chain)
const
427 for (
auto uri : id_uris) {
428 auto idkey = envptr->GetPrivateKey(uri.c_str());
429 if (idkey ==
nullptr) {
433 auto idcert = envptr->GetCertificate(uri.c_str());
434 if (idcert ==
nullptr) {
438 if (idkey->Type() == keyType) {
439 *key = idkey->GetEVPkey();
440 X509* cert = idcert->GetX509();
443 GENERAL_NAMES* names =
static_cast<GENERAL_NAMES*
>(
444 X509_get_ext_d2i(cert, NID_subject_alt_name,
nullptr,
nullptr));
445 if (
nullptr == names) {
450 const int nb_names = sk_GENERAL_NAME_num(names);
451 for (
int i = 0; i < nb_names; i++) {
452 GENERAL_NAME* name = sk_GENERAL_NAME_value(names, i);
454 if (name->type == GEN_DNS) {
455 ASN1_STRING *asn1_str = name->d.dNSName;
456 unsigned char* dns =
nullptr;
457 int len = ASN1_STRING_to_UTF8(&dns, asn1_str);
459 GENERAL_NAMES_free(names);
464 std::string str(
reinterpret_cast<char *
>(dns), len);
471 if (SSL_CTX_select_current_cert(this->ctx, cert) != 1) {
472 GENERAL_NAMES_free(names);
477 STACK_OF(X509) *chain = 0;
478 if (SSL_CTX_get_extra_chain_certs(this->ctx, &chain) != 1) {
479 GENERAL_NAMES_free(names);
486 unsigned char *dbytes =
nullptr;
487 int dlen = i2d_X509(cert, &dbytes);
490 GENERAL_NAMES_free(names);
495 auto v = std::vector<unsigned char>(dbytes, dbytes + dlen);
496 OPENSSL_free(dbytes);
497 cert_chain.push_back(v);
500 GENERAL_NAMES_free(names);
505 const int len = sk_X509_num(chain);
506 for (
int i = 0; i < len; i++) {
507 unsigned char *dbytes =
nullptr;
508 X509 *x509 = sk_X509_value(chain, i);
509 int dlen = i2d_X509(x509, &dbytes);
514 auto v = std::vector<unsigned char>(dbytes, dbytes + dlen);
515 cert_chain.push_back(v);
526 std::list<X509*> OpenSSLContext::GetTrustAnchors ()
const
529 auto res = envptr->GetInternalTrustAnchors();
532 auto extra_ta =
const_cast<OpenSSLContext*
>(
this)->PullCertificates(trust_anchor_uris);
533 res.splice(res.end(), extra_ta);
536 if (!dontTrustIdentities) {
537 auto id =
const_cast<OpenSSLContext*
>(
this)->PullCertificates(id_uris);
538 res.splice(res.end(), id);
544 void OpenSSLContext::convertLookupFlags (
int lookup_flags)
546 static const struct {
549 } lookup_flag_trans[] = {
550 {
"avoid-ocsp-configured", LOOKUP_AVOID_OCSP_CONFIGURED },
551 {
"avoid-ocsp-uri", LOOKUP_AVOID_OCSP_URI },
552 {
"avoid-crl-configured", LOOKUP_AVOID_CRL_CONFIGURED },
553 {
"avoid-crl-uri", LOOKUP_AVOID_CRL_URI },
554 {
"avoid-cert-configured", LOOKUP_AVOID_CERT_CONFIGURED },
555 {
"avoid-cert-uri", LOOKUP_AVOID_CERT_URI },
556 {
"avoid-freshestcrl", LOOKUP_AVOID_FRESHESTCRL },
557 {
"avoid-ocsp-httpget", LOOKUP_AVOID_OCSP_HTTPGET },
561 if ( !lookup_flags )
return;
565 for (
int n = 1; lookup_flag_trans[n].flag; n++ )
566 if ( lookup_flags & lookup_flag_trans[n].flag ) {
567 std::string key = ICRYPTO_CONFIG
":lookup::";
568 key += lookup_flag_trans[n].key;
569 if ( !envptr->ConfigStr (key.c_str(),
"true", &msg) )
575 int CheckHostname (X509 *cert,
const char *hostname, MSGstruct *msp)
577 if ( strcasecmp (hostname,
"localhost") == 0 )
578 hostname = getfullhostname();
581 const char *lastdot = strrchr (hostname,
'.');
585 if ( hostname[0] ==
'[' || strchr (hostname,
':') ||
586 (lastdot && isdigit(lastdot[1])) ) {
591 if ( hostname[0] ==
'[' ) {
593 strncpy (namecopy, hostname+1,
sizeof namecopy);
594 namecopy[
sizeof namecopy -1] =
'\0';
596 char *ket = strchr (namecopy,
']');
597 if ( ket ) *ket =
'\0';
600 strncpy (namecopy, hostname,
sizeof namecopy);
601 namecopy[
sizeof namecopy -1] =
'\0';
604 struct addrinfo hints;
605 memset (&hints, 0,
sizeof hints);
606 hints.ai_flags = AI_NUMERICHOST;
607 hints.ai_socktype = SOCK_STREAM;
609 struct addrinfo *res;
610 int rc = getaddrinfo (namecopy, NULL, &hints, &res);
612 MSG_Address_NameLookup_SET (msp, gai_strerror(rc));
613 return MSG_Address_NameLookup;
616 switch ( res->ai_family ) {
620 struct sockaddr_in *sin =
621 reinterpret_cast<sockaddr_in *
>(res->ai_addr);
623 memcpy (addrdat, &sin->sin_addr.s_addr, addrlen);
630 struct sockaddr_in6 *sin6 =
631 reinterpret_cast<sockaddr_in6 *
>(res->ai_addr);
633 memcpy (addrdat, sin6->sin6_addr.s6_addr, addrlen);
646 int i = X509_get_ext_by_NID (cert, NID_subject_alt_name, -1);
649 STACK_OF(GENERAL_NAME) *alt;
651 ex = X509_get_ext(cert, i);
652 alt =
reinterpret_cast<STACK_OF(GENERAL_NAME) *
>(X509V3_EXT_d2i(ex));
654 int n, len1 = 0, len2 = 0;
655 const char *domain = NULL;
659 len1 = strlen(hostname);
660 domain = strchr(hostname,
'.');
662 len2 = len1 - (domain-hostname);
665 n = sk_GENERAL_NAME_num(alt);
666 for (i=0; i<n; i++) {
669 gn = sk_GENERAL_NAME_value(alt, i);
670 if (gn->type == GEN_DNS) {
671 if (!dnsname)
continue;
674 sn = (
char *) ASN1_STRING_get0_data(gn->d.ia5);
675 sl = ASN1_STRING_length(gn->d.ia5);
678 if (sl == 0)
continue;
681 LOG_DEBUG ((
"testing DNS subjectAltName %s", sn));
682 if ((len1 == sl) && !strncasecmp(hostname, sn, len1)) {
683 LOG_DEBUG ((
"matched DNS subjectAltName %s", sn));
689 if (domain && (sn[0] ==
'*') && (sn[1] ==
'.') &&
690 (len2 == sl-1) && !strncasecmp(domain, &sn[1], len2)) {
691 LOG_DEBUG ((
"matched DNS subjectAltName %s", sn));
696 }
else if (gn->type == GEN_IPADD) {
697 if (dnsname)
continue;
699 sn = (
char *) ASN1_STRING_get0_data(gn->d.ia5);
700 sl = ASN1_STRING_length(gn->d.ia5);
701 LOG_DEBUG ((
"testing IP subjectAltName"));
703 if (sl == addrlen && memcmp(sn, addrdat, sl) == 0) {
704 LOG_DEBUG ((
"matched IP subjectAltName"));
711 GENERAL_NAMES_free(alt);
724 LOG_DEBUG ((
"peer certificate has no matching subjectAltName"));
725 xn = X509_get_subject_name(cert);
726 if( X509_NAME_get_text_by_NID( xn, NID_commonName,
727 buf,
sizeof(buf)) == -1) {
729 LOG_DEBUG ((
"No commonName RDN in peer certificate"));
733 LOG_DEBUG ((
"testing peer certificate subjectName CN %s", buf));
735 if (strcasecmp(hostname, buf) == 0 ) {
736 LOG_DEBUG ((
"matched peer certificate subjectName CN %s", buf));
751 if (( buf[0] ==
'*' ) && ( buf[1] ==
'.' )) {
752 const char *domain = strchr(hostname,
'.');
756 sl = strlen(hostname);
757 dlen = sl - (domain-hostname);
760 if (( dlen == sl-1) &&
761 !strncasecmp(domain, &buf[1], dlen)) {
762 LOG_DEBUG ((
"matched peer certificate subjectName (wildcard) %s", buf));
768 LOG_DEBUG ((
"peer certificate subjectName does not match %s", buf));
775 MSG_IOevent_SSLhostname_SET (msp, hostname);
776 return MSG_IOevent_SSLhostname;
780 int SSLError (MSGstruct *msp,
int msgno,
const char *ctx)
782 BIO *io = BIO_new(BIO_s_mem());
783 ERR_print_errors(io);
784 BIO_write(io,
"\0", 1);
787 BIO_get_mem_data(io, &err);
793 MSGsetv (msp, msgno, 2, argv);
800 std::string cipherSuites (
const cipher_suites_t& suites)
802 std::ostringstream str;
803 bool started =
false;
806 if ( suites.empty() )
810 for ( cipher_suites_t::const_iterator iter = suites.begin();
811 iter != suites.end(); ++iter ) {
812 SuiteToName::const_iterator np = suite_names.find(*iter);
814 if ( np == suite_names.end() )
833 static bool isAbsolutePath(
const std::string& path) {
848 if (path.length() > 2 &&
849 path[1] && path[2] &&
851 (path[2] ==
'/' || path[2] ==
'\\') &&
852 isascii(path[0]) && isalpha(path[0])) {
865 bool abs = isAbsolutePath (file);
877 Config::Config(
const char*context)
878 : IDcontext(context),
879 supportFlags(SSL_OP_ALL|SSL_OP_CIPHER_SERVER_PREFERENCE|
881 sessionCacheTimeout(3600L),
882 verify_choice(tls_verify_optional),
883 disable_rsa_blinding(false),
887 dontTrustIdentities(false),
EVENTSVC_DLL const char * suite_name(TLS_CipherSuite)
Function returning a name for a cipher suite.
Class for SSL configuration.
EVENTSVC_DLL std::string path(const std::string &file)
Build a complete filesystem path from directory and filename.
std::string defaultFileDirectory
default filesystem directory location
Class defining an SSL context.
static EVENTSVC_DLL Context * Factory(Config *confobj, MSGstruct *msp)
Factory method for context, creates concrete object.