ssl_context.C
1// -*- C++ -*-
2
3// Copyright (c) 2006-2012, Isode Limited, London, England.
4// All rights reserved.
5//
6// Acquisition and use of this software and related materials for any
7// purpose requires a written licence agreement from Isode Limited,
8// or a written licence from an organisation licenced by Isode Limited
9// to grant such a licence.
10
11//
12//
13// ssl_context.C
14//
15// SSL context using OpenSSL
16//
17// @VERSION@
18
19#include <sstream>
20#include <string>
21#include <map>
22#include <utility>
23
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>
33
34#include "Event_p.h"
35
36
37#define VERIFY_DEPTH_SHIFT 4
38#define VERIFY_CHOICE_MASK ((1<<VERIFY_DEPTH_SHIFT)-1)
39
40namespace SSLTLS {
41 std::string cipherSuites (const cipher_suites_t&);
42
43 Context *Context::Factory (Config *confobj, MSGstruct *msp)
44 {
45 if ( confobj == 0 )
46 return 0;
47
48 OpenSSLContext *ctx = new OpenSSLContext ();
49
50 if ( ctx->Configure (confobj, msp) == 0 )
51 return ctx;
52
53 delete ctx;
54
55 return 0;
56 }
57
58
59 //------------------------------------------------------
60 typedef std::map<TLS_CipherSuite,std::string> SuiteToName;
61 static SuiteToName suite_names;
62
63 const char*
64 suite_name(TLS_CipherSuite suite)
65 {
66 SuiteToName::const_iterator i = suite_names.find(suite);
67 return i==suite_names.end() ? "":i->second.c_str();
68 }
69
70 //------------------------------------------------------------------
71
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;
76
77 static void cipher_suites(cipher_suites_t& suites,const char* desc = 0)
78 {
79 SSL_CTX* myctx = SSL_CTX_new(SSLv23_method());
80 if (!myctx) {
81 // There are no cipher suites available, probably
82 return;
83 }
84 if (SSL_CTX_set_cipher_list(myctx, desc ? desc : "ALL:COMPLEMENTOFALL") == 0) {
85 return;
86 }
87 SSL* ssl = SSL_new(myctx);
88 STACK_OF(SSL_CIPHER) *ciphers = SSL_get_ciphers(ssl);
89
90 int n = sk_SSL_CIPHER_num(ciphers);
91
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);
95 if (!desc)
96 suite_names.insert(std::make_pair(id, SSL_CIPHER_get_name(c)));
97 suites.insert(id);
98 }
99 SSL_free(ssl);
100 SSL_CTX_free(myctx);
101 }
102
103 OpenSSLContext::~OpenSSLContext ()
104 {
105 if ( ctx != 0 )
106 SSL_CTX_free (ctx);
107 }
108
109 int OpenSSLContext::Configure (Config *confobj, MSGstruct *msp)
110 {
111 if ( ctx != 0 ) {
112 SSL_CTX_free (ctx);
113 ctx = 0;
114 }
115
116 if ( pthread_mutex_lock (&globalmutex) != 0 )
117 MSG_Base_Tmutexlock_LOG ("OpenSSLContext::Configure");
118
119 if ( !globalinit ) {
120 cipher_suites(available_suites);
121 cipher_suites(default_suites, "DEFAULT");
122 globalinit = true;
123 }
124
125 if ( pthread_mutex_unlock (&globalmutex) != 0 )
126 MSG_Base_Tunlock_LOG ("OpenSSLContext::Configure");
127
128 envptr = confobj->envptr;
129 dontTrustIdentities = confobj->dontTrustIdentities;
130
131 if ( !envptr.get() ) {
132 // Create ephemeral environment
133 have_tls_id = false;
134
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;
142 }
143
144 envptr = ICrypto::Environment::Init (0, 0, true, msp, allow_pkcs11);
145 if ( !envptr.get() ) return MSG2msgid (msp);
146
147 int idsloaded = 0;
148
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());
153
154 std::string tlskeyptr = ICRYPTO_TLS ":default::rsa-key";
155 if (OK == envptr->ConfigStr(tlskeyptr.c_str(), uri.c_str(), msp)) {
156 ++idsloaded;
157 have_tls_id = true;
158 id_uris.push_back(uri);
159 }
160 } else if (allow_pkcs11) {
161 std::string uri;
162 if (envptr->LoadPKCS11IdentityTLS(
163 confobj->pkcs11_module_path,
164 confobj->pkcs11_module_init,
165 confobj->pkcs11_user_pphr,
166 confobj->pkcs11_uri,
167 confobj->pkcs11_cert,
168 uri) != OK)
169 {
170 MSG_IOevent_SSLIDerror_LOG (confobj->pkcs11_uri.c_str());
171 } else {
172 ++idsloaded;
173 have_tls_id = true;
174 id_uris.push_back(uri);
175 MSG_IOevent_SSLID_LOG (confobj->pkcs11_uri.c_str());
176 }
177 } else if ( !have_tls_id && !confobj->identity.empty() ) {
178 bool file_found;
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());
184
185 } else if (idsloaded != 0) {
186 MSG_IOevent_SSLID_LOG (idpath.c_str());
187 }
188 if (idsloaded == 0 && file_found) {
189 // hmm .. no keys loaded .. may be bad news
190 MSG_IOevent_SSLnoIDs_LOG();
191 } else {
192 LOG_DEBUG(("TLS initialisation loaded %d identit%s",
193 idsloaded, idsloaded == 1 ? "y" : "ies" ));
194 }
195
196 have_tls_id = (idsloaded ? true : false);
197 }
198
199 if ( !confobj->trustedCA_File.empty() )
200 loadCAsfromPEM (confobj->trustedCA_File.c_str());
201
202 loadCertsFromFiles (confobj, confobj->trustedCA_Files, true);
203 loadCertsFromFiles (confobj, confobj->untrusted_Files, false);
204
205 std::string tlskeyprefix = ICRYPTO_TLS ":default::";
206
207 std::string suitesStr = cipherSuites(confobj->suites);
208 if ( suitesStr.empty() )
209 suitesStr = confobj->suitesstr;
210
211 if ( suitesStr.empty() ) {
212 MSG_IOevent_SSLnosuites_SET (msp);
213 return MSG_IOevent_SSLnosuites;
214 }
215
216 std::string key = tlskeyprefix + "cipher-suites";
217 int rc = envptr->ConfigStr (key.c_str(), suitesStr.c_str(), msp);
218 if ( rc != OK )
219 return rc;
220
221 if ( !confobj->DHparametersFile.empty() ) {
222 key = tlskeyprefix + "dhparams";
223 rc = envptr->ConfigStr (key.c_str(),
224 confobj->DHparametersFile.c_str(), msp);
225 if ( rc != OK )
226 return rc;
227 }
228
229 if ( !confobj->randomSeedFile.empty() ) {
230 (void) envptr->RandomFile(confobj->randomSeedFile.c_str(), msp);
231 // Just ignore any errors --- they're already logged
232 }
233
234 // Verification settings
235 if ( !confobj->LDAPhost.empty() ) {
236 char ldapport[12];
237 snprintf (ldapport, sizeof ldapport, "%d", confobj->LDAPport);
238
239 rc = envptr->ConfigStr (ICRYPTO_CONFIG ":lookup::ldap-host",
240 confobj->LDAPhost.c_str(), msp);
241 if ( rc != OK )
242 return rc;
243
244 rc = envptr->ConfigStr (ICRYPTO_CONFIG ":lookup::ldap-port",
245 ldapport, msp);
246 if ( rc != OK )
247 return rc;
248 }
249
250 if ( !confobj->OCSPresponder.empty() ) {
251 rc = envptr->ConfigStr (ICRYPTO_CONFIG ":lookup::ocsp-trusted-responder",
252 confobj->OCSPresponder.c_str(), msp);
253 if ( rc != OK )
254 return rc;
255 }
256
257 if ( !confobj->OCSPuri.empty() ) {
258 rc = envptr->ConfigStr (ICRYPTO_CONFIG ":lookup::ocsp-uri",
259 confobj->OCSPuri.c_str(), msp);
260 if ( rc != OK )
261 return rc;
262 }
263
264 rc = envptr->ConfigStr (ICRYPTO_CONFIG ":lookup::ocsp-use-nonce",
265 confobj->OCSPnonce ? "true" : "false", msp);
266 if ( rc != OK )
267 return rc;
268
269 rc = envptr->ConfigStr (ICRYPTO_CONFIG ":policy::check-crls",
270 confobj->checkRevocation ? "on" : "off",msp);
271 if ( rc != OK )
272 return rc;
273
274 convertLookupFlags (confobj->lookup_flags);
275
276 envptr->Reset();
277 }
278
279 try {
280 ctx = envptr->GetSSLContext (confobj->IDcontext,
281 confobj->confset.length() ?
282 confobj->confset.c_str() : 0);
283
284 } catch (MSGstruct message) {
285 *msp = message;
286 // This may be because TLS is not activated, or openssl has been
287 // tampered with. Let the caller check the error.
288 return MSG2msgid (msp);
289 }
290
291
292 // If using the default TLS config set from the security environment
293 // set some items from this configuration
294 if ( confobj->confset.empty() ) {
295 // Options
296 // Only cancel workaround cases which are not set in supportFlags
297 if ( confobj->supportFlags ) {
298 SSL_CTX_clear_options (ctx, SSL_OP_ALL);
299 SSL_CTX_set_options (ctx, confobj->supportFlags);
300 }
301
302 SSL_CTX_set_options (ctx, SSL_OP_NO_SSLv2); // Just to make sure
303
304 // Session handling
305 const char *idctx = confobj->IDcontext;
306
307 if (SSL_CTX_set_session_id_context(ctx,
308 (const unsigned char *)idctx,
309 strlen(idctx)) != 1)
310 return SSLError (msp, MSG_IOevent_SSLerror, "set_session_id");
311
312 long scto = confobj->sessionCacheTimeout;
313
314 if (scto > 0) {
315 (void)SSL_CTX_set_timeout(ctx, scto);
316 if (SSL_CTX_get_timeout(ctx) != scto)
317 LogSSLError (MSG_IOevent_SSLerror, "set_timeout");
318 }
319
320 char depthbuf[12];
321 snprintf (depthbuf, sizeof depthbuf, "%d", confobj->verify_depth);
322 if ( ICrypto::ConfigureSSL (ctx, "verify-depth", depthbuf, msp) != OK)
323 LOGmessage (msp);
324
325 choice = confobj->verify_choice;
326
327 const char *mode;
328 switch ( choice ) {
329 case tls_verify_none:
330 mode = "none";
331 break;
332 case tls_verify_require:
333 mode = "require";
334 break;
335 case tls_verify_optional:
336 mode = "optional";
337 break;
338 default:
339 mode = 0;
340 break;
341 }
342
343 if ( mode && ICrypto::ConfigureSSL (ctx, "verify-mode", mode, msp) != OK)
344 LOGmessage (msp);
345 }
346
347 return 0;
348 }
349
350 bool OpenSSLContext::IsUsable ()
351 {
352 if (!ctx) {
353 return false;
354 }
355
356 STACK_OF(SSL_CIPHER) *ciphers = SSL_CTX_get_ciphers(ctx);
357
358 // We always have the 3 default TLSv1.3 cipher suites and an
359 // ID is required for those (they're not anonymous)
360 return ciphers && (sk_SSL_CIPHER_num(ciphers) > 3 || have_tls_id);
361 }
362
363 //----------------
364 SSL *OpenSSLContext::GetSSL (tls_verify_client_choice &verify_choice)
365 {
366 SSL *ssl = SSL_new (ctx);
367
368 verify_choice = choice;
369
370 return ssl;
371 }
372
373//=========================================================================
374 void OpenSSLContext::loadCAsfromPEM (const char *name)
375 {
376 MSGstruct message;
377
378 if ( envptr->LoadCertsFromFile(name, true, &message, &trust_anchor_uris) != OK )
379 LOGmessage (&message);
380 }
381
382 void OpenSSLContext::loadCertsFromFiles (
383 Config *confobj, std::list<std::string>& DER_files, bool ista)
384 {
385 MSGstruct message;
386
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));
390
391 if ( envptr->LoadCertsFromFile(n.c_str(), ista, &message,
392 &trust_anchor_uris) != OK )
393 LOGmessage (&message);
394 }
395 }
396
397 std::list<X509*> OpenSSLContext::PullCertificates (const std::list<std::string>& uris)
398 {
399 std::list<X509*> certs;
400 for (auto certuri : uris) {
401 auto cert = envptr->GetCertificate(certuri.c_str());
402 if (cert.get()) {
403 X509* certp = cert.get()->GetX509();
404 if (certp) {
405 X509_up_ref(certp);
406 certs.push_back(certp);
407 }
408 }
409 }
410 return certs;
411 }
412
413 std::list<X509 *> OpenSSLContext::ServerCertificates (void)
414 {
415 return PullCertificates(id_uris);
416 }
417
418 size_t OpenSSLContext::GetNbIdentities() const {
419 return id_uris.size();
420 }
421
422 int OpenSSLContext::GetTlsInfo (const ICryptoKeyType keyType,
423 EVP_PKEY** key,
424 std::vector<std::string>& san,
425 std::vector<std::vector<unsigned char>>& cert_chain) const
426 {
427 for (auto uri : id_uris) {
428 auto idkey = envptr->GetPrivateKey(uri.c_str());
429 if (idkey == nullptr) {
430 return NOTOK;
431 }
432
433 auto idcert = envptr->GetCertificate(uri.c_str());
434 if (idcert == nullptr) {
435 return NOTOK;
436 }
437
438 if (idkey->Type() == keyType) {
439 *key = idkey->GetEVPkey();
440 X509* cert = idcert->GetX509();
441 X509_up_ref(cert);
442
443 GENERAL_NAMES* names = static_cast<GENERAL_NAMES*>(
444 X509_get_ext_d2i(cert, NID_subject_alt_name, nullptr, nullptr));
445 if (nullptr == names) {
446 X509_free(cert);
447 return NOTOK;
448 }
449
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);
453 // keep only DNS fields
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);
458 if (len < 0) {
459 GENERAL_NAMES_free(names);
460 X509_free(cert);
461 return NOTOK;
462 }
463
464 std::string str(reinterpret_cast<char *>(dns), len);
465 san.push_back(str);
466 OPENSSL_free(dns);
467 }
468 }
469
470 // according to documentation, `0` is failure, `1` is success
471 if (SSL_CTX_select_current_cert(this->ctx, cert) != 1) {
472 GENERAL_NAMES_free(names);
473 X509_free(cert);
474 return NOTOK;
475 }
476
477 STACK_OF(X509) *chain = 0;
478 if (SSL_CTX_get_extra_chain_certs(this->ctx, &chain) != 1) {
479 GENERAL_NAMES_free(names);
480 X509_free(cert);
481 return NOTOK;
482 }
483
484 {
485 // Add identity cert to the chain
486 unsigned char *dbytes = nullptr;
487 int dlen = i2d_X509(cert, &dbytes);
488 if (dlen < 0) {
489 cert_chain.clear();
490 GENERAL_NAMES_free(names);
491 X509_free(cert);
492 return NOTOK;
493 }
494
495 auto v = std::vector<unsigned char>(dbytes, dbytes + dlen);
496 OPENSSL_free(dbytes);
497 cert_chain.push_back(v);
498 }
499
500 GENERAL_NAMES_free(names);
501 X509_free(cert);
502
503 if (chain) {
504 // add rest of the chain
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);
510 if (dlen < 0) {
511 cert_chain.clear();
512 return NOTOK;
513 }
514 auto v = std::vector<unsigned char>(dbytes, dbytes + dlen);
515 cert_chain.push_back(v);
516 }
517 }
518
519 return OK;
520 }
521 }
522
523 return OK;
524 }
525
526 std::list<X509*> OpenSSLContext::GetTrustAnchors () const
527 {
528 // Trust Anchors
529 auto res = envptr->GetInternalTrustAnchors();
530
531 // External Trust anchors
532 auto extra_ta = const_cast<OpenSSLContext*>(this)->PullCertificates(trust_anchor_uris);
533 res.splice(res.end(), extra_ta);
534
535 // Id as anchors
536 if (!dontTrustIdentities) {
537 auto id = const_cast<OpenSSLContext*>(this)->PullCertificates(id_uris);
538 res.splice(res.end(), id);
539 }
540
541 return res;
542 }
543
544 void OpenSSLContext::convertLookupFlags (int lookup_flags)
545 {
546 static const struct {
547 const char *key;
548 int flag;
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 },
558 { 0, 0 }
559 };
560
561 if ( !lookup_flags ) return;
562
563 MSGstruct msg;
564
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) )
570 LOGmessage (&msg);
571 }
572 }
573
574 //------------------------------------------------------
575 int CheckHostname (X509 *cert, const char *hostname, MSGstruct *msp)
576 {
577 if ( strcasecmp (hostname, "localhost") == 0 )
578 hostname = getfullhostname();
579
580 bool dnsname = true;
581 const char *lastdot = strrchr (hostname, '.');
582 char addrdat[16];
583 int addrlen;
584
585 if ( hostname[0] == '[' || strchr (hostname, ':') ||
586 (lastdot && isdigit(lastdot[1])) ) {
587 // Address is IP address
588
589 stdbuf_t namecopy;
590
591 if ( hostname[0] == '[' ) {
592 // Need to remove '[]' for getaddrinfo
593 strncpy (namecopy, hostname+1, sizeof namecopy);
594 namecopy[sizeof namecopy -1] = '\0';
595
596 char *ket = strchr (namecopy, ']');
597 if ( ket ) *ket = '\0';
598
599 } else {
600 strncpy (namecopy, hostname, sizeof namecopy);
601 namecopy[sizeof namecopy -1] = '\0';
602 }
603
604 struct addrinfo hints;
605 memset (&hints, 0, sizeof hints);
606 hints.ai_flags = AI_NUMERICHOST;
607 hints.ai_socktype = SOCK_STREAM;
608
609 struct addrinfo *res;
610 int rc = getaddrinfo (namecopy, NULL, &hints, &res);
611 if ( rc != OK ) {
612 MSG_Address_NameLookup_SET (msp, gai_strerror(rc));
613 return MSG_Address_NameLookup;
614 }
615
616 switch ( res->ai_family ) {
617 case AF_INET:
618 {
619 dnsname = false;
620 struct sockaddr_in *sin =
621 reinterpret_cast<sockaddr_in *>(res->ai_addr);
622 addrlen = 4;
623 memcpy (addrdat, &sin->sin_addr.s_addr, addrlen);
624 break;
625 }
626
627 case AF_INET6:
628 {
629 dnsname = false;
630 struct sockaddr_in6 *sin6 =
631 reinterpret_cast<sockaddr_in6 *>(res->ai_addr);
632 addrlen = 16;
633 memcpy (addrdat, sin6->sin6_addr.s6_addr, addrlen);
634 break;
635 }
636
637 default:
638 // Revert to using the original string
639 break;
640 }
641 }
642
643 bool match = false;
644
645 // Look through subjectAltNames
646 int i = X509_get_ext_by_NID (cert, NID_subject_alt_name, -1);
647 if ( i >= 0 ) {
648 X509_EXTENSION *ex;
649 STACK_OF(GENERAL_NAME) *alt;
650
651 ex = X509_get_ext(cert, i);
652 alt = reinterpret_cast<STACK_OF(GENERAL_NAME) *>(X509V3_EXT_d2i(ex));
653 if (alt) {
654 int n, len1 = 0, len2 = 0;
655 const char *domain = NULL;
656 GENERAL_NAME *gn;
657
658 if (dnsname) {
659 len1 = strlen(hostname);
660 domain = strchr(hostname, '.');
661 if (domain) {
662 len2 = len1 - (domain-hostname);
663 }
664 }
665 n = sk_GENERAL_NAME_num(alt);
666 for (i=0; i<n; i++) {
667 char *sn;
668 int sl;
669 gn = sk_GENERAL_NAME_value(alt, i);
670 if (gn->type == GEN_DNS) {
671 if (!dnsname) continue;
672
673 /* RFC 4513 3.1.3.1 */
674 sn = (char *) ASN1_STRING_get0_data(gn->d.ia5);
675 sl = ASN1_STRING_length(gn->d.ia5);
676
677 /* ignore empty */
678 if (sl == 0) continue;
679
680 /* Is this an exact match? */
681 LOG_DEBUG (("testing DNS subjectAltName %s", sn));
682 if ((len1 == sl) && !strncasecmp(hostname, sn, len1)) {
683 LOG_DEBUG (("matched DNS subjectAltName %s", sn));
684 match = true;
685 break;
686 }
687
688 /* Is this a wildcard match? */
689 if (domain && (sn[0] == '*') && (sn[1] == '.') &&
690 (len2 == sl-1) && !strncasecmp(domain, &sn[1], len2)) {
691 LOG_DEBUG (("matched DNS subjectAltName %s", sn));
692 match = true;
693 break;
694 }
695
696 } else if (gn->type == GEN_IPADD) {
697 if (dnsname) continue;
698 /* RFC 4513 3.1.3.2 */
699 sn = (char *) ASN1_STRING_get0_data(gn->d.ia5);
700 sl = ASN1_STRING_length(gn->d.ia5);
701 LOG_DEBUG (("testing IP subjectAltName"));
702
703 if (sl == addrlen && memcmp(sn, addrdat, sl) == 0) {
704 LOG_DEBUG (("matched IP subjectAltName"));
705 match = true;
706 break;
707 }
708 }
709 }
710
711 GENERAL_NAMES_free(alt);
712 }
713 }
714
715 if (!match) {
716 /* No matches in subjectAltNames; see if there's a CN in the
717 * RDN of the certificate subject. RFC 4513 3.1.3
718 */
719
720 X509_NAME *xn;
721 char buf[2048];
722 buf[0] = '\0';
723
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) {
728
729 LOG_DEBUG (("No commonName RDN in peer certificate"));
730 goto cleanup;
731 }
732
733 LOG_DEBUG (("testing peer certificate subjectName CN %s", buf));
734
735 if (strcasecmp(hostname, buf) == 0 ) {
736 LOG_DEBUG (("matched peer certificate subjectName CN %s", buf));
737 match = true;
738 goto cleanup;
739 }
740
741 /* Note that RFC 4513 3.1.3 says that wildcard
742 * match of the subjectname should not be done.
743 * However, as per
744 * http://www.openldap.org/its/index.cgi?findid=5938
745 * this code, like OpenLDAP, will do the check:
746 *
747 * "This is because the Cert vendors themselves don't honor
748 * the RFC's when issuing wildcard certs, and was added so
749 * that their broken wildcard certs could still be used."
750 */
751 if (( buf[0] == '*' ) && ( buf[1] == '.' )) {
752 const char *domain = strchr(hostname,'.');
753 if (domain) {
754 size_t dlen = 0;
755 size_t sl;
756 sl = strlen(hostname);
757 dlen = sl - (domain-hostname);
758 sl = strlen(buf);
759
760 if (( dlen == sl-1) &&
761 !strncasecmp(domain, &buf[1], dlen)) {
762 LOG_DEBUG (("matched peer certificate subjectName (wildcard) %s", buf));
763 match = true;
764 goto cleanup;
765 }
766 }
767 }
768 LOG_DEBUG (("peer certificate subjectName does not match %s", buf));
769 }
770
771 cleanup:
772 if (match)
773 return OK;
774
775 MSG_IOevent_SSLhostname_SET (msp, hostname);
776 return MSG_IOevent_SSLhostname;
777 }
778
779 //------------------------------------------------------
780 int SSLError (MSGstruct *msp, int msgno, const char *ctx)
781 {
782 BIO *io = BIO_new(BIO_s_mem());
783 ERR_print_errors(io);
784 BIO_write(io, "\0", 1);
785
786 char *err;
787 BIO_get_mem_data(io, &err);
788
789 const char *argv[2];
790 argv[0] = ctx;
791 argv[1] = err;
792
793 MSGsetv (msp, msgno, 2, argv);
794
795 BIO_free(io);
796
797 return msgno;
798 }
799
800 std::string cipherSuites (const cipher_suites_t& suites)
801 {
802 std::ostringstream str;
803 bool started = false;
804
805 // If none configured, assume OpenSSL defaults
806 if ( suites.empty() )
807 return "DEFAULT";
808
809
810 for ( cipher_suites_t::const_iterator iter = suites.begin();
811 iter != suites.end(); ++iter ) {
812 SuiteToName::const_iterator np = suite_names.find(*iter);
813
814 if ( np == suite_names.end() )
815 continue;
816
817 if ( started ) {
818 str << ":";
819 } else {
820 started = true;
821 }
822 str << np->second;
823 }
824
825 if ( started ) {
826 str << ":@STRENGTH"; // Sorts by strength
827 return str.str();
828 } else {
829 return "";
830 }
831 }
832
833 static bool isAbsolutePath(const std::string& path) {
834 if (path == "") {
835 return false; // treat NULL and EMPTY as relative
836 }
837
838 if (path[0] == '/'
839#ifdef IC_WIN32
840 || path[0] == '\\' // this will catch network drives ('\\\\') too
841#endif
842 ) {
843 return true ; // not ideal .. '/' could be absolute
844 }
845
846#ifdef IC_WIN32
847 // see whether this might be a Drive-absolute path e.g. E:\...
848 if (path.length() > 2 &&
849 path[1] && path[2] &&
850 path[1] == ':' &&
851 (path[2] == '/' || path[2] == '\\') &&
852 isascii(path[0]) && isalpha(path[0])) {
853 return true;
854 }
855#endif
856
857 return false;
858 }
859
860 std::string Config::path(const std::string& file )
861 {
862 if ( file == "" )
863 return "";
864
865 bool abs = isAbsolutePath (file);
866
867 if ( abs )
868 return file;
869
870 if ( abs || defaultFileDirectory == "" ) {
871 return file;
872 } else {
873 return defaultFileDirectory + "/" + file;
874 }
875 }
876
877 Config::Config(const char*context)
878 : IDcontext(context),
879 supportFlags(SSL_OP_ALL|SSL_OP_CIPHER_SERVER_PREFERENCE|
880 SSL_OP_NO_SSLv2),
881 sessionCacheTimeout(3600L),
882 verify_choice(tls_verify_optional),
883 disable_rsa_blinding(false),
884 verify_depth(5),
885 LDAPport(389),
886 checkRevocation(0),
887 dontTrustIdentities(false),
888 OCSPnonce(false),
889 lookup_flags(0)
890 {}
891}
EVENTSVC_DLL const char * suite_name(TLS_CipherSuite)
Function returning a name for a cipher suite.
Definition ssl_context.C:64
Class for SSL configuration.
Definition SSLconfig.h:65
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
Definition SSLconfig.h:80
Class defining an SSL context.
Definition SSLconfig.h:123
static EVENTSVC_DLL Context * Factory(Config *confobj, MSGstruct *msp)
Factory method for context, creates concrete object.
Definition ssl_context.C:43

All rights reserved © 2002 - 2024 Isode Ltd.