2 * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
9 /* DEBUG: section 83 SSL accelerator support */
13 /* MS Visual Studio Projects are monolithic, so we need the following
14 * #if to exclude the SSL code from compile process when not needed.
18 #include "acl/FilledChecklist.h"
19 #include "anyp/PortCfg.h"
24 #include "ipc/MemMap.h"
25 #include "security/CertError.h"
26 #include "security/Session.h"
27 #include "SquidConfig.h"
28 #include "SquidTime.h"
30 #include "ssl/Config.h"
31 #include "ssl/ErrorDetail.h"
32 #include "ssl/gadgets.h"
33 #include "ssl/support.h"
38 // TODO: Move ssl_ex_index_* global variables from global.cc here.
39 int ssl_ex_index_ssl_untrusted_chain
= -1;
41 static Ssl::CertsIndexedList SquidUntrustedCerts
;
43 const EVP_MD
*Ssl::DefaultSignHash
= NULL
;
45 std::vector
<const char *> Ssl::BumpModeStr
= {
58 \defgroup ServerProtocolSSLInternal Server-Side SSL Internals
59 \ingroup ServerProtocolSSLAPI
62 /// \ingroup ServerProtocolSSLInternal
64 ssl_ask_password_cb(char *buf
, int size
, int rwflag
, void *userdata
)
70 snprintf(cmdline
, sizeof(cmdline
), "\"%s\" \"%s\"", Config
.Program
.ssl_password
, (const char *)userdata
);
71 in
= popen(cmdline
, "r");
73 if (fgets(buf
, size
, in
))
77 while (len
> 0 && (buf
[len
- 1] == '\n' || buf
[len
- 1] == '\r'))
87 /// \ingroup ServerProtocolSSLInternal
89 ssl_ask_password(SSL_CTX
* context
, const char * prompt
)
91 if (Config
.Program
.ssl_password
) {
92 SSL_CTX_set_default_passwd_cb(context
, ssl_ask_password_cb
);
93 SSL_CTX_set_default_passwd_cb_userdata(context
, (void *)prompt
);
97 #if HAVE_LIBSSL_SSL_CTX_SET_TMP_RSA_CALLBACK
99 ssl_temp_rsa_cb(SSL
* ssl
, int anInt
, int keylen
)
101 static RSA
*rsa_512
= NULL
;
102 static RSA
*rsa_1024
= NULL
;
111 rsa_512
= RSA_generate_key(512, RSA_F4
, NULL
, NULL
);
121 rsa_1024
= RSA_generate_key(1024, RSA_F4
, NULL
, NULL
);
129 debugs(83, DBG_IMPORTANT
, "ssl_temp_rsa_cb: Unexpected key length " << keylen
);
134 debugs(83, DBG_IMPORTANT
, "ssl_temp_rsa_cb: Failed to generate key " << keylen
);
139 if (Debug::Enabled(83, 5))
140 PEM_write_RSAPrivateKey(debug_log
, rsa
, NULL
, NULL
, 0, NULL
, NULL
);
142 debugs(83, DBG_IMPORTANT
, "Generated ephemeral RSA key of length " << keylen
);
150 maybeSetupRsaCallback(Security::ContextPointer
&ctx
)
152 #if HAVE_LIBSSL_SSL_CTX_SET_TMP_RSA_CALLBACK
153 debugs(83, 9, "Setting RSA key generation callback.");
154 SSL_CTX_set_tmp_rsa_callback(ctx
.get(), ssl_temp_rsa_cb
);
158 int Ssl::asn1timeToString(ASN1_TIME
*tm
, char *buf
, int len
)
162 bio
= BIO_new(BIO_s_mem());
164 if (ASN1_TIME_print(bio
, tm
))
165 write
= BIO_read(bio
, buf
, len
-1);
172 int Ssl::matchX509CommonNames(X509
*peer_cert
, void *check_data
, int (*check_func
)(void *check_data
, ASN1_STRING
*cn_data
))
176 X509_NAME
*name
= X509_get_subject_name(peer_cert
);
178 for (int i
= X509_NAME_get_index_by_NID(name
, NID_commonName
, -1); i
>= 0; i
= X509_NAME_get_index_by_NID(name
, NID_commonName
, i
)) {
180 ASN1_STRING
*cn_data
= X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name
, i
));
182 if ( (*check_func
)(check_data
, cn_data
) == 0)
186 STACK_OF(GENERAL_NAME
) * altnames
;
187 altnames
= (STACK_OF(GENERAL_NAME
)*)X509_get_ext_d2i(peer_cert
, NID_subject_alt_name
, NULL
, NULL
);
190 int numalts
= sk_GENERAL_NAME_num(altnames
);
191 for (int i
= 0; i
< numalts
; ++i
) {
192 const GENERAL_NAME
*check
= sk_GENERAL_NAME_value(altnames
, i
);
193 if (check
->type
!= GEN_DNS
) {
196 ASN1_STRING
*cn_data
= check
->d
.dNSName
;
198 if ( (*check_func
)(check_data
, cn_data
) == 0) {
199 sk_GENERAL_NAME_pop_free(altnames
, GENERAL_NAME_free
);
203 sk_GENERAL_NAME_pop_free(altnames
, GENERAL_NAME_free
);
208 static int check_domain( void *check_data
, ASN1_STRING
*cn_data
)
211 const char *server
= (const char *)check_data
;
213 if (cn_data
->length
== 0)
214 return 1; // zero length cn, ignore
216 if (cn_data
->length
> (int)sizeof(cn
) - 1)
217 return 1; //if does not fit our buffer just ignore
219 char *s
= reinterpret_cast<char*>(cn_data
->data
);
221 for (int i
= 0; i
< cn_data
->length
; ++i
, ++d
, ++s
) {
223 return 1; // always a domain mismatch. contains 0x00
226 cn
[cn_data
->length
] = '\0';
227 debugs(83, 4, "Verifying server domain " << server
<< " to certificate name/subjectAltName " << cn
);
228 return matchDomainName(server
, (cn
[0] == '*' ? cn
+ 1 : cn
), mdnRejectSubsubDomains
);
231 bool Ssl::checkX509ServerValidity(X509
*cert
, const char *server
)
233 return matchX509CommonNames(cert
, (void *)server
, check_domain
);
236 #if !HAVE_LIBCRYPTO_X509_STORE_CTX_GET0_CERT
237 static inline X509
*X509_STORE_CTX_get0_cert(X509_STORE_CTX
*ctx
)
243 /// \ingroup ServerProtocolSSLInternal
245 ssl_verify_cb(int ok
, X509_STORE_CTX
* ctx
)
247 // preserve original ctx->error before SSL_ calls can overwrite it
248 Security::ErrorCode error_no
= ok
? SSL_ERROR_NONE
: X509_STORE_CTX_get_error(ctx
);
250 char buffer
[256] = "";
251 SSL
*ssl
= (SSL
*)X509_STORE_CTX_get_ex_data(ctx
, SSL_get_ex_data_X509_STORE_CTX_idx());
252 SSL_CTX
*sslctx
= SSL_get_SSL_CTX(ssl
);
253 SBuf
*server
= (SBuf
*)SSL_get_ex_data(ssl
, ssl_ex_index_server
);
254 void *dont_verify_domain
= SSL_CTX_get_ex_data(sslctx
, ssl_ctx_ex_index_dont_verify_domain
);
255 ACLChecklist
*check
= (ACLChecklist
*)SSL_get_ex_data(ssl
, ssl_ex_index_cert_error_check
);
256 X509
*peeked_cert
= (X509
*)SSL_get_ex_data(ssl
, ssl_ex_index_ssl_peeked_cert
);
257 Security::CertPointer peer_cert
;
258 peer_cert
.resetAndLock(X509_STORE_CTX_get0_cert(ctx
));
260 X509_NAME_oneline(X509_get_subject_name(peer_cert
.get()), buffer
, sizeof(buffer
));
262 // detect infinite loops
263 uint32_t *validationCounter
= static_cast<uint32_t *>(SSL_get_ex_data(ssl
, ssl_ex_index_ssl_validation_counter
));
264 if (!validationCounter
) {
265 validationCounter
= new uint32_t(1);
266 SSL_set_ex_data(ssl
, ssl_ex_index_ssl_validation_counter
, validationCounter
);
268 // overflows allowed if SQUID_CERT_VALIDATION_ITERATION_MAX >= UINT32_MAX
269 (*validationCounter
)++;
272 if ((*validationCounter
) >= SQUID_CERT_VALIDATION_ITERATION_MAX
) {
273 ok
= 0; // or the validation loop will never stop
274 error_no
= SQUID_X509_V_ERR_INFINITE_VALIDATION
;
275 debugs(83, 2, "SQUID_X509_V_ERR_INFINITE_VALIDATION: " <<
276 *validationCounter
<< " iterations while checking " << buffer
);
280 debugs(83, 5, "SSL Certificate signature OK: " << buffer
);
282 // Check for domain mismatch only if the current certificate is the peer certificate.
283 if (!dont_verify_domain
&& server
&& peer_cert
.get() == X509_STORE_CTX_get_current_cert(ctx
)) {
284 if (!Ssl::checkX509ServerValidity(peer_cert
.get(), server
->c_str())) {
285 debugs(83, 2, "SQUID_X509_V_ERR_DOMAIN_MISMATCH: Certificate " << buffer
<< " does not match domainname " << server
);
287 error_no
= SQUID_X509_V_ERR_DOMAIN_MISMATCH
;
292 if (ok
&& peeked_cert
) {
293 // Check whether the already peeked certificate matches the new one.
294 if (X509_cmp(peer_cert
.get(), peeked_cert
) != 0) {
295 debugs(83, 2, "SQUID_X509_V_ERR_CERT_CHANGE: Certificate " << buffer
<< " does not match peeked certificate");
297 error_no
= SQUID_X509_V_ERR_CERT_CHANGE
;
302 Security::CertPointer broken_cert
;
303 broken_cert
.resetAndLock(X509_STORE_CTX_get_current_cert(ctx
));
305 broken_cert
= peer_cert
;
307 Security::CertErrors
*errs
= static_cast<Security::CertErrors
*>(SSL_get_ex_data(ssl
, ssl_ex_index_ssl_errors
));
308 const int depth
= X509_STORE_CTX_get_error_depth(ctx
);
310 errs
= new Security::CertErrors(Security::CertError(error_no
, broken_cert
, depth
));
311 if (!SSL_set_ex_data(ssl
, ssl_ex_index_ssl_errors
, (void *)errs
)) {
312 debugs(83, 2, "Failed to set ssl error_no in ssl_verify_cb: Certificate " << buffer
);
316 } else // remember another error number
317 errs
->push_back_unique(Security::CertError(error_no
, broken_cert
, depth
));
319 if (const char *err_descr
= Ssl::GetErrorDescr(error_no
))
320 debugs(83, 5, err_descr
<< ": " << buffer
);
322 debugs(83, DBG_IMPORTANT
, "SSL unknown certificate error " << error_no
<< " in " << buffer
);
324 // Check if the certificate error can be bypassed.
325 // Infinity validation loop errors can not bypassed.
326 if (error_no
!= SQUID_X509_V_ERR_INFINITE_VALIDATION
) {
328 ACLFilledChecklist
*filledCheck
= Filled(check
);
329 assert(!filledCheck
->sslErrors
);
330 filledCheck
->sslErrors
= new Security::CertErrors(Security::CertError(error_no
, broken_cert
));
331 filledCheck
->serverCert
= peer_cert
;
332 if (check
->fastCheck() == ACCESS_ALLOWED
) {
333 debugs(83, 3, "bypassing SSL error " << error_no
<< " in " << buffer
);
336 debugs(83, 5, "confirming SSL error " << error_no
);
338 delete filledCheck
->sslErrors
;
339 filledCheck
->sslErrors
= NULL
;
340 filledCheck
->serverCert
.reset();
342 // If the certificate validator is used then we need to allow all errors and
343 // pass them to certficate validator for more processing
344 else if (Ssl::TheConfig
.ssl_crt_validator
) {
350 if (Ssl::TheConfig
.ssl_crt_validator
) {
351 // Check if we have stored certificates chain. Store if not.
352 if (!SSL_get_ex_data(ssl
, ssl_ex_index_ssl_cert_chain
)) {
353 STACK_OF(X509
) *certStack
= X509_STORE_CTX_get1_chain(ctx
);
354 if (certStack
&& !SSL_set_ex_data(ssl
, ssl_ex_index_ssl_cert_chain
, certStack
))
355 sk_X509_pop_free(certStack
, X509_free
);
359 if (!ok
&& !SSL_get_ex_data(ssl
, ssl_ex_index_ssl_error_detail
) ) {
361 // Find the broken certificate. It may be intermediate.
362 Security::CertPointer
broken_cert(peer_cert
); // reasonable default if search fails
363 // Our SQUID_X509_V_ERR_DOMAIN_MISMATCH implies peer_cert is at fault.
364 if (error_no
!= SQUID_X509_V_ERR_DOMAIN_MISMATCH
) {
365 if (auto *last_used_cert
= X509_STORE_CTX_get_current_cert(ctx
))
366 broken_cert
.resetAndLock(last_used_cert
);
369 auto *errDetail
= new Ssl::ErrorDetail(error_no
, peer_cert
.get(), broken_cert
.get());
370 if (!SSL_set_ex_data(ssl
, ssl_ex_index_ssl_error_detail
, errDetail
)) {
371 debugs(83, 2, "Failed to set Ssl::ErrorDetail in ssl_verify_cb: Certificate " << buffer
);
379 // "dup" function for SSL_get_ex_new_index("cert_err_check")
380 #if SQUID_USE_CONST_CRYPTO_EX_DATA_DUP
382 ssl_dupAclChecklist(CRYPTO_EX_DATA
*, const CRYPTO_EX_DATA
*, void *,
386 ssl_dupAclChecklist(CRYPTO_EX_DATA
*, CRYPTO_EX_DATA
*, void *,
390 // We do not support duplication of ACLCheckLists.
391 // If duplication is needed, we can count copies with cbdata.
396 // "free" function for SSL_get_ex_new_index("cert_err_check")
398 ssl_freeAclChecklist(void *, void *ptr
, CRYPTO_EX_DATA
*,
401 delete static_cast<ACLChecklist
*>(ptr
); // may be NULL
404 // "free" function for SSL_get_ex_new_index("ssl_error_detail")
406 ssl_free_ErrorDetail(void *, void *ptr
, CRYPTO_EX_DATA
*,
409 Ssl::ErrorDetail
*errDetail
= static_cast <Ssl::ErrorDetail
*>(ptr
);
414 ssl_free_SslErrors(void *, void *ptr
, CRYPTO_EX_DATA
*,
417 Security::CertErrors
*errs
= static_cast <Security::CertErrors
*>(ptr
);
421 // "free" function for SSL_get_ex_new_index("ssl_ex_index_ssl_validation_counter")
423 ssl_free_int(void *, void *ptr
, CRYPTO_EX_DATA
*,
426 uint32_t *counter
= static_cast <uint32_t *>(ptr
);
430 /// \ingroup ServerProtocolSSLInternal
431 /// Callback handler function to release STACK_OF(X509) "ex" data stored
432 /// in an SSL object.
434 ssl_free_CertChain(void *, void *ptr
, CRYPTO_EX_DATA
*,
437 STACK_OF(X509
) *certsChain
= static_cast <STACK_OF(X509
) *>(ptr
);
438 sk_X509_pop_free(certsChain
,X509_free
);
441 // "free" function for X509 certificates
443 ssl_free_X509(void *, void *ptr
, CRYPTO_EX_DATA
*,
446 X509
*cert
= static_cast <X509
*>(ptr
);
450 // "free" function for SBuf
452 ssl_free_SBuf(void *, void *ptr
, CRYPTO_EX_DATA
*,
455 SBuf
*buf
= static_cast <SBuf
*>(ptr
);
460 Ssl::Initialize(void)
462 static bool initialized
= false;
467 SSL_load_error_strings();
468 SSLeay_add_ssl_algorithms();
470 #if HAVE_OPENSSL_ENGINE_H
471 if (::Config
.SSL
.ssl_engine
) {
472 ENGINE_load_builtin_engines();
474 if (!(e
= ENGINE_by_id(::Config
.SSL
.ssl_engine
)))
475 fatalf("Unable to find SSL engine '%s'\n", ::Config
.SSL
.ssl_engine
);
477 if (!ENGINE_set_default(e
, ENGINE_METHOD_ALL
)) {
478 const int ssl_error
= ERR_get_error();
479 fatalf("Failed to initialise SSL engine: %s\n", Security::ErrorString(ssl_error
));
483 if (::Config
.SSL
.ssl_engine
)
484 fatalf("Your OpenSSL has no SSL engine support\n");
487 const char *defName
= ::Config
.SSL
.certSignHash
? ::Config
.SSL
.certSignHash
: SQUID_SSL_SIGN_HASH_IF_NONE
;
488 Ssl::DefaultSignHash
= EVP_get_digestbyname(defName
);
489 if (!Ssl::DefaultSignHash
)
490 fatalf("Sign hash '%s' is not supported\n", defName
);
492 ssl_ex_index_server
= SSL_get_ex_new_index(0, (void *) "server", NULL
, NULL
, ssl_free_SBuf
);
493 ssl_ctx_ex_index_dont_verify_domain
= SSL_CTX_get_ex_new_index(0, (void *) "dont_verify_domain", NULL
, NULL
, NULL
);
494 ssl_ex_index_cert_error_check
= SSL_get_ex_new_index(0, (void *) "cert_error_check", NULL
, &ssl_dupAclChecklist
, &ssl_freeAclChecklist
);
495 ssl_ex_index_ssl_error_detail
= SSL_get_ex_new_index(0, (void *) "ssl_error_detail", NULL
, NULL
, &ssl_free_ErrorDetail
);
496 ssl_ex_index_ssl_peeked_cert
= SSL_get_ex_new_index(0, (void *) "ssl_peeked_cert", NULL
, NULL
, &ssl_free_X509
);
497 ssl_ex_index_ssl_errors
= SSL_get_ex_new_index(0, (void *) "ssl_errors", NULL
, NULL
, &ssl_free_SslErrors
);
498 ssl_ex_index_ssl_cert_chain
= SSL_get_ex_new_index(0, (void *) "ssl_cert_chain", NULL
, NULL
, &ssl_free_CertChain
);
499 ssl_ex_index_ssl_validation_counter
= SSL_get_ex_new_index(0, (void *) "ssl_validation_counter", NULL
, NULL
, &ssl_free_int
);
500 ssl_ex_index_ssl_untrusted_chain
= SSL_get_ex_new_index(0, (void *) "ssl_untrusted_chain", NULL
, NULL
, &ssl_free_CertChain
);
504 configureSslContext(Security::ContextPointer
&ctx
, AnyP::PortCfg
&port
)
507 SSL_CTX_set_options(ctx
.get(), port
.secure
.parsedOptions
);
509 if (port
.sslContextSessionId
)
510 SSL_CTX_set_session_id_context(ctx
.get(), (const unsigned char *)port
.sslContextSessionId
, strlen(port
.sslContextSessionId
));
512 if (port
.secure
.parsedFlags
& SSL_FLAG_NO_SESSION_REUSE
) {
513 SSL_CTX_set_session_cache_mode(ctx
.get(), SSL_SESS_CACHE_OFF
);
516 if (Config
.SSL
.unclean_shutdown
) {
517 debugs(83, 5, "Enabling quiet SSL shutdowns (RFC violation).");
519 SSL_CTX_set_quiet_shutdown(ctx
.get(), 1);
522 if (!port
.secure
.sslCipher
.isEmpty()) {
523 debugs(83, 5, "Using chiper suite " << port
.secure
.sslCipher
<< ".");
525 if (!SSL_CTX_set_cipher_list(ctx
.get(), port
.secure
.sslCipher
.c_str())) {
526 ssl_error
= ERR_get_error();
527 debugs(83, DBG_CRITICAL
, "ERROR: Failed to set SSL cipher suite '" << port
.secure
.sslCipher
<< "': " << Security::ErrorString(ssl_error
));
532 maybeSetupRsaCallback(ctx
);
534 port
.secure
.updateContextEecdh(ctx
);
535 port
.secure
.updateContextCa(ctx
);
537 if (port
.clientCA
.get()) {
539 if (STACK_OF(X509_NAME
) *clientca
= SSL_dup_CA_list(port
.clientCA
.get())) {
540 SSL_CTX_set_client_CA_list(ctx
.get(), clientca
);
542 ssl_error
= ERR_get_error();
543 debugs(83, DBG_CRITICAL
, "ERROR: Failed to dupe the client CA list: " << Security::ErrorString(ssl_error
));
547 if (port
.secure
.parsedFlags
& SSL_FLAG_DELAYED_AUTH
) {
548 debugs(83, 9, "Not requesting client certificates until acl processing requires one");
549 SSL_CTX_set_verify(ctx
.get(), SSL_VERIFY_NONE
, NULL
);
551 debugs(83, 9, "Requiring client certificates.");
552 SSL_CTX_set_verify(ctx
.get(), SSL_VERIFY_PEER
| SSL_VERIFY_FAIL_IF_NO_PEER_CERT
, ssl_verify_cb
);
555 port
.secure
.updateContextCrl(ctx
);
558 debugs(83, 9, "Not requiring any client certificates");
559 SSL_CTX_set_verify(ctx
.get(), SSL_VERIFY_NONE
, NULL
);
562 if (port
.secure
.parsedFlags
& SSL_FLAG_DONT_VERIFY_DOMAIN
)
563 SSL_CTX_set_ex_data(ctx
.get(), ssl_ctx_ex_index_dont_verify_domain
, (void *) -1);
565 Security::SetSessionCacheCallbacks(ctx
);
571 Ssl::InitServerContext(Security::ContextPointer
&ctx
, AnyP::PortCfg
&port
)
576 if (!SSL_CTX_use_certificate(ctx
.get(), port
.signingCert
.get())) {
577 const int ssl_error
= ERR_get_error();
578 const auto &keys
= port
.secure
.certs
.front();
579 debugs(83, DBG_CRITICAL
, "ERROR: Failed to acquire TLS certificate '" << keys
.certFile
<< "': " << Security::ErrorString(ssl_error
));
583 if (!SSL_CTX_use_PrivateKey(ctx
.get(), port
.signPkey
.get())) {
584 const int ssl_error
= ERR_get_error();
585 const auto &keys
= port
.secure
.certs
.front();
586 debugs(83, DBG_CRITICAL
, "ERROR: Failed to acquire TLS private key '" << keys
.privateKeyFile
<< "': " << Security::ErrorString(ssl_error
));
590 Ssl::addChainToSslContext(ctx
, port
.certsToChain
.get());
593 debugs(83, DBG_IMPORTANT, "Using certificate in " << certfile);
595 if (!SSL_CTX_use_certificate_chain_file(ctx.get(), certfile)) {
596 ssl_error = ERR_get_error();
597 debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire SSL certificate '" << certfile << "': " << Security::ErrorString(ssl_error));
601 debugs(83, DBG_IMPORTANT, "Using private key in " << keyfile);
602 ssl_ask_password(ctx.get(), keyfile);
604 if (!SSL_CTX_use_PrivateKey_file(ctx.get(), keyfile, SSL_FILETYPE_PEM)) {
605 ssl_error = ERR_get_error();
606 debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire SSL private key '" << keyfile << "': " << Security::ErrorString(ssl_error));
610 debugs(83, 5, "Comparing private and public SSL keys.");
612 if (!SSL_CTX_check_private_key(ctx.get())) {
613 ssl_error = ERR_get_error();
614 debugs(83, DBG_CRITICAL, "ERROR: SSL private key '" << certfile << "' does not match public key '" <<
615 keyfile << "': " << Security::ErrorString(ssl_error));
620 if (!configureSslContext(ctx
, port
)) {
621 debugs(83, DBG_CRITICAL
, "ERROR: Configuring static SSL context");
629 Ssl::InitClientContext(Security::ContextPointer
&ctx
, Security::PeerOptions
&peer
, long fl
)
634 if (!peer
.sslCipher
.isEmpty()) {
635 debugs(83, 5, "Using chiper suite " << peer
.sslCipher
<< ".");
637 const char *cipher
= peer
.sslCipher
.c_str();
638 if (!SSL_CTX_set_cipher_list(ctx
.get(), cipher
)) {
639 const int ssl_error
= ERR_get_error();
640 fatalf("Failed to set SSL cipher suite '%s': %s\n",
641 cipher
, Security::ErrorString(ssl_error
));
645 if (!peer
.certs
.empty()) {
646 // TODO: support loading multiple cert/key pairs
647 auto &keys
= peer
.certs
.front();
648 if (!keys
.certFile
.isEmpty()) {
649 debugs(83, DBG_IMPORTANT
, "Using certificate in " << keys
.certFile
);
651 const char *certfile
= keys
.certFile
.c_str();
652 if (!SSL_CTX_use_certificate_chain_file(ctx
.get(), certfile
)) {
653 const int ssl_error
= ERR_get_error();
654 fatalf("Failed to acquire SSL certificate '%s': %s\n",
655 certfile
, Security::ErrorString(ssl_error
));
658 debugs(83, DBG_IMPORTANT
, "Using private key in " << keys
.privateKeyFile
);
659 const char *keyfile
= keys
.privateKeyFile
.c_str();
660 ssl_ask_password(ctx
.get(), keyfile
);
662 if (!SSL_CTX_use_PrivateKey_file(ctx
.get(), keyfile
, SSL_FILETYPE_PEM
)) {
663 const int ssl_error
= ERR_get_error();
664 fatalf("Failed to acquire SSL private key '%s': %s\n",
665 keyfile
, Security::ErrorString(ssl_error
));
668 debugs(83, 5, "Comparing private and public SSL keys.");
670 if (!SSL_CTX_check_private_key(ctx
.get())) {
671 const int ssl_error
= ERR_get_error();
672 fatalf("SSL private key '%s' does not match public key '%s': %s\n",
673 certfile
, keyfile
, Security::ErrorString(ssl_error
));
678 maybeSetupRsaCallback(ctx
);
680 if (fl
& SSL_FLAG_DONT_VERIFY_PEER
) {
681 debugs(83, 2, "NOTICE: Peer certificates are not verified for validity!");
682 SSL_CTX_set_verify(ctx
.get(), SSL_VERIFY_NONE
, NULL
);
684 debugs(83, 9, "Setting certificate verification callback.");
685 SSL_CTX_set_verify(ctx
.get(), SSL_VERIFY_PEER
| SSL_VERIFY_FAIL_IF_NO_PEER_CERT
, ssl_verify_cb
);
691 /// \ingroup ServerProtocolSSLInternal
693 ssl_get_attribute(X509_NAME
* name
, const char *attribute_name
)
695 static char buffer
[1024];
698 if (strcmp(attribute_name
, "DN") == 0) {
699 X509_NAME_oneline(name
, buffer
, sizeof(buffer
));
701 int nid
= OBJ_txt2nid(const_cast<char *>(attribute_name
));
703 debugs(83, DBG_IMPORTANT
, "WARNING: Unknown SSL attribute name '" << attribute_name
<< "'");
706 X509_NAME_get_text_by_NID(name
, nid
, buffer
, sizeof(buffer
));
709 return *buffer
? buffer
: nullptr;
712 /// \ingroup ServerProtocolSSLInternal
714 Ssl::GetX509UserAttribute(X509
* cert
, const char *attribute_name
)
722 name
= X509_get_subject_name(cert
);
724 ret
= ssl_get_attribute(name
, attribute_name
);
730 Ssl::GetX509Fingerprint(X509
* cert
, const char *)
732 static char buf
[1024];
737 unsigned char md
[EVP_MAX_MD_SIZE
];
738 if (!X509_digest(cert
, EVP_sha1(), md
, &n
))
741 assert(3 * n
+ 1 < sizeof(buf
));
744 for (unsigned int i
=0; i
< n
; ++i
, s
+= 3) {
745 const char term
= (i
+ 1 < n
) ? ':' : '\0';
746 snprintf(s
, 4, "%02X%c", md
[i
], term
);
752 /// \ingroup ServerProtocolSSLInternal
754 Ssl::GetX509CAAttribute(X509
* cert
, const char *attribute_name
)
763 name
= X509_get_issuer_name(cert
);
765 ret
= ssl_get_attribute(name
, attribute_name
);
770 const char *sslGetUserAttribute(SSL
*ssl
, const char *attribute_name
)
775 X509
*cert
= SSL_get_peer_certificate(ssl
);
777 const char *attr
= Ssl::GetX509UserAttribute(cert
, attribute_name
);
783 const char *sslGetCAAttribute(SSL
*ssl
, const char *attribute_name
)
788 X509
*cert
= SSL_get_peer_certificate(ssl
);
790 const char *attr
= Ssl::GetX509CAAttribute(cert
, attribute_name
);
797 sslGetUserEmail(SSL
* ssl
)
799 return sslGetUserAttribute(ssl
, "emailAddress");
803 sslGetUserCertificatePEM(SSL
*ssl
)
807 static char *str
= NULL
;
816 cert
= SSL_get_peer_certificate(ssl
);
821 mem
= BIO_new(BIO_s_mem());
823 PEM_write_bio_X509(mem
, cert
);
825 len
= BIO_get_mem_data(mem
, &ptr
);
827 str
= (char *)xmalloc(len
+ 1);
829 memcpy(str
, ptr
, len
);
841 sslGetUserCertificateChainPEM(SSL
*ssl
)
843 STACK_OF(X509
) *chain
;
845 static char *str
= NULL
;
855 chain
= SSL_get_peer_cert_chain(ssl
);
858 return sslGetUserCertificatePEM(ssl
);
860 mem
= BIO_new(BIO_s_mem());
862 for (i
= 0; i
< sk_X509_num(chain
); ++i
) {
863 X509
*cert
= sk_X509_value(chain
, i
);
864 PEM_write_bio_X509(mem
, cert
);
867 len
= BIO_get_mem_data(mem
, &ptr
);
869 str
= (char *)xmalloc(len
+ 1);
870 memcpy(str
, ptr
, len
);
878 /// Create SSL context and apply ssl certificate and private key to it.
879 Security::ContextPointer
880 Ssl::createSSLContext(Security::CertPointer
& x509
, Ssl::EVP_PKEY_Pointer
& pkey
, AnyP::PortCfg
&port
)
882 Security::ContextPointer
ctx(port
.secure
.createBlankContext());
884 if (!SSL_CTX_use_certificate(ctx
.get(), x509
.get()))
885 return Security::ContextPointer();
887 if (!SSL_CTX_use_PrivateKey(ctx
.get(), pkey
.get()))
888 return Security::ContextPointer();
890 if (!configureSslContext(ctx
, port
))
891 return Security::ContextPointer();
896 Security::ContextPointer
897 Ssl::generateSslContextUsingPkeyAndCertFromMemory(const char * data
, AnyP::PortCfg
&port
)
899 Security::CertPointer cert
;
900 Ssl::EVP_PKEY_Pointer pkey
;
901 if (!readCertAndPrivateKeyFromMemory(cert
, pkey
, data
) || !cert
|| !pkey
)
902 return Security::ContextPointer();
904 return createSSLContext(cert
, pkey
, port
);
907 Security::ContextPointer
908 Ssl::generateSslContext(CertificateProperties
const &properties
, AnyP::PortCfg
&port
)
910 Security::CertPointer cert
;
911 Ssl::EVP_PKEY_Pointer pkey
;
912 if (!generateSslCertificate(cert
, pkey
, properties
) || !cert
|| !pkey
)
913 return Security::ContextPointer();
915 return createSSLContext(cert
, pkey
, port
);
919 Ssl::chainCertificatesToSSLContext(Security::ContextPointer
&ctx
, AnyP::PortCfg
&port
)
922 // Add signing certificate to the certificates chain
923 X509
*signingCert
= port
.signingCert
.get();
924 if (SSL_CTX_add_extra_chain_cert(ctx
.get(), signingCert
)) {
925 // increase the certificate lock
926 X509_up_ref(signingCert
);
928 const int ssl_error
= ERR_get_error();
929 debugs(33, DBG_IMPORTANT
, "WARNING: can not add signing certificate to SSL context chain: " << Security::ErrorString(ssl_error
));
931 Ssl::addChainToSslContext(ctx
, port
.certsToChain
.get());
935 Ssl::configureUnconfiguredSslContext(Security::ContextPointer
&ctx
, Ssl::CertSignAlgorithm signAlgorithm
,AnyP::PortCfg
&port
)
937 if (ctx
&& signAlgorithm
== Ssl::algSignTrusted
)
938 Ssl::chainCertificatesToSSLContext(ctx
, port
);
942 Ssl::configureSSL(SSL
*ssl
, CertificateProperties
const &properties
, AnyP::PortCfg
&port
)
944 Security::CertPointer cert
;
945 Ssl::EVP_PKEY_Pointer pkey
;
946 if (!generateSslCertificate(cert
, pkey
, properties
))
955 if (!SSL_use_certificate(ssl
, cert
.get()))
958 if (!SSL_use_PrivateKey(ssl
, pkey
.get()))
965 Ssl::configureSSLUsingPkeyAndCertFromMemory(SSL
*ssl
, const char *data
, AnyP::PortCfg
&port
)
967 Security::CertPointer cert
;
968 Ssl::EVP_PKEY_Pointer pkey
;
969 if (!readCertAndPrivateKeyFromMemory(cert
, pkey
, data
))
975 if (!SSL_use_certificate(ssl
, cert
.get()))
978 if (!SSL_use_PrivateKey(ssl
, pkey
.get()))
985 Ssl::verifySslCertificate(Security::ContextPointer
&ctx
, CertificateProperties
const &properties
)
987 #if HAVE_SSL_CTX_GET0_CERTIFICATE
988 X509
* cert
= SSL_CTX_get0_certificate(ctx
.get());
989 #elif SQUID_USE_SSLGETCERTIFICATE_HACK
990 // SSL_get_certificate is buggy in openssl versions 1.0.1d and 1.0.1e
991 // Try to retrieve certificate directly from Security::ContextPointer object
992 X509
***pCert
= (X509
***)ctx
->cert
;
993 X509
* cert
= pCert
&& *pCert
? **pCert
: NULL
;
994 #elif SQUID_SSLGETCERTIFICATE_BUGGY
998 // Temporary ssl for getting X509 certificate from SSL_CTX.
999 Security::SessionPointer
ssl(Security::NewSessionObject(ctx
));
1000 X509
* cert
= SSL_get_certificate(ssl
.get());
1004 ASN1_TIME
* time_notBefore
= X509_get_notBefore(cert
);
1005 ASN1_TIME
* time_notAfter
= X509_get_notAfter(cert
);
1006 bool ret
= (X509_cmp_current_time(time_notBefore
) < 0 && X509_cmp_current_time(time_notAfter
) > 0);
1010 return certificateMatchesProperties(cert
, properties
);
1014 Ssl::setClientSNI(SSL
*ssl
, const char *fqdn
)
1016 //The SSL_CTRL_SET_TLSEXT_HOSTNAME is a openssl macro which indicates
1017 // if the TLS servername extension (SNI) is enabled in openssl library.
1018 #if defined(SSL_CTRL_SET_TLSEXT_HOSTNAME)
1019 if (!SSL_set_tlsext_host_name(ssl
, fqdn
)) {
1020 const int ssl_error
= ERR_get_error();
1021 debugs(83, 3, "WARNING: unable to set TLS servername extension (SNI): " <<
1022 Security::ErrorString(ssl_error
) << "\n");
1027 debugs(83, 7, "no support for TLS servername extension (SNI)\n");
1033 Ssl::addChainToSslContext(Security::ContextPointer
&ctx
, STACK_OF(X509
) *chain
)
1038 for (int i
= 0; i
< sk_X509_num(chain
); ++i
) {
1039 X509
*cert
= sk_X509_value(chain
, i
);
1040 if (SSL_CTX_add_extra_chain_cert(ctx
.get(), cert
)) {
1041 // increase the certificate lock
1044 const int ssl_error
= ERR_get_error();
1045 debugs(83, DBG_IMPORTANT
, "WARNING: can not add certificate to SSL context chain: " << Security::ErrorString(ssl_error
));
1051 hasAuthorityInfoAccessCaIssuers(X509
*cert
)
1053 AUTHORITY_INFO_ACCESS
*info
;
1056 info
= static_cast<AUTHORITY_INFO_ACCESS
*>(X509_get_ext_d2i(cert
, NID_info_access
, NULL
, NULL
));
1060 static char uri
[MAX_URL
];
1063 for (int i
= 0; i
< sk_ACCESS_DESCRIPTION_num(info
); i
++) {
1064 ACCESS_DESCRIPTION
*ad
= sk_ACCESS_DESCRIPTION_value(info
, i
);
1065 if (OBJ_obj2nid(ad
->method
) == NID_ad_ca_issuers
) {
1066 if (ad
->location
->type
== GEN_URI
) {
1068 reinterpret_cast<const char *>(
1069 #if HAVE_LIBCRYPTO_ASN1_STRING_GET0_DATA
1070 ASN1_STRING_get0_data(ad
->location
->d
.uniformResourceIdentifier
)
1072 ASN1_STRING_data(ad
->location
->d
.uniformResourceIdentifier
)
1080 AUTHORITY_INFO_ACCESS_free(info
);
1081 return uri
[0] != '\0' ? uri
: nullptr;
1085 Ssl::loadCerts(const char *certsFile
, Ssl::CertsIndexedList
&list
)
1087 BIO
*in
= BIO_new_file(certsFile
, "r");
1089 debugs(83, DBG_IMPORTANT
, "Failed to open '" << certsFile
<< "' to load certificates");
1094 while((aCert
= PEM_read_bio_X509(in
, NULL
, NULL
, NULL
))) {
1095 static char buffer
[2048];
1096 X509_NAME_oneline(X509_get_subject_name(aCert
), buffer
, sizeof(buffer
));
1097 list
.insert(std::pair
<SBuf
, X509
*>(SBuf(buffer
), aCert
));
1099 debugs(83, 4, "Loaded " << list
.size() << " certificates from file: '" << certsFile
<< "'");
1104 /// quickly find the issuer certificate of a certificate cert in the
1105 /// Ssl::CertsIndexedList list
1107 findCertIssuerFast(Ssl::CertsIndexedList
&list
, X509
*cert
)
1109 static char buffer
[2048];
1111 if (X509_NAME
*issuerName
= X509_get_issuer_name(cert
))
1112 X509_NAME_oneline(issuerName
, buffer
, sizeof(buffer
));
1116 const auto ret
= list
.equal_range(SBuf(buffer
));
1117 for (Ssl::CertsIndexedList::iterator it
= ret
.first
; it
!= ret
.second
; ++it
) {
1118 X509
*issuer
= it
->second
;
1119 if (X509_check_issued(issuer
, cert
) == X509_V_OK
) {
1126 /// slowly find the issuer certificate of a given cert using linear search
1128 findCertIssuer(Security::CertList
const &list
, X509
*cert
)
1130 for (Security::CertList::const_iterator it
= list
.begin(); it
!= list
.end(); ++it
) {
1131 if (X509_check_issued(it
->get(), cert
) == X509_V_OK
)
1138 Ssl::uriOfIssuerIfMissing(X509
*cert
, Security::CertList
const &serverCertificates
)
1140 if (!cert
|| !serverCertificates
.size())
1143 if (!findCertIssuer(serverCertificates
, cert
)) {
1144 //if issuer is missing
1145 if (!findCertIssuerFast(SquidUntrustedCerts
, cert
)) {
1146 // and issuer not found in local untrusted certificates database
1147 if (const char *issuerUri
= hasAuthorityInfoAccessCaIssuers(cert
)) {
1148 // There is a URI where we can download a certificate.
1157 Ssl::missingChainCertificatesUrls(std::queue
<SBuf
> &URIs
, Security::CertList
const &serverCertificates
)
1159 if (!serverCertificates
.size())
1162 for (const auto &i
: serverCertificates
) {
1163 if (const char *issuerUri
= uriOfIssuerIfMissing(i
.get(), serverCertificates
))
1164 URIs
.push(SBuf(issuerUri
));
1169 Ssl::SSL_add_untrusted_cert(SSL
*ssl
, X509
*cert
)
1171 STACK_OF(X509
) *untrustedStack
= static_cast <STACK_OF(X509
) *>(SSL_get_ex_data(ssl
, ssl_ex_index_ssl_untrusted_chain
));
1172 if (!untrustedStack
) {
1173 untrustedStack
= sk_X509_new_null();
1174 if (!SSL_set_ex_data(ssl
, ssl_ex_index_ssl_untrusted_chain
, untrustedStack
)) {
1175 sk_X509_pop_free(untrustedStack
, X509_free
);
1176 throw TextException("Failed to attach untrusted certificates chain");
1179 sk_X509_push(untrustedStack
, cert
);
1182 /// Search for the issuer certificate of cert in sk list.
1184 sk_x509_findIssuer(STACK_OF(X509
) *sk
, X509
*cert
)
1189 const int skItemsNum
= sk_X509_num(sk
);
1190 for (int i
= 0; i
< skItemsNum
; ++i
) {
1191 X509
*issuer
= sk_X509_value(sk
, i
);
1192 if (X509_check_issued(issuer
, cert
) == X509_V_OK
)
1198 /// add missing issuer certificates to untrustedCerts
1200 completeIssuers(X509_STORE_CTX
*ctx
, STACK_OF(X509
) *untrustedCerts
)
1202 debugs(83, 2, "completing " << sk_X509_num(untrustedCerts
) << " OpenSSL untrusted certs using " << SquidUntrustedCerts
.size() << " configured untrusted certificates");
1204 #if HAVE_LIBCRYPTO_X509_VERIFY_PARAM_GET_DEPTH
1205 const X509_VERIFY_PARAM
*param
= X509_STORE_CTX_get0_param(ctx
);
1206 int depth
= X509_VERIFY_PARAM_get_depth(param
);
1208 int depth
= ctx
->param
->depth
;
1210 X509
*current
= X509_STORE_CTX_get0_cert(ctx
);
1212 for (i
= 0; current
&& (i
< depth
); ++i
) {
1213 if (X509_check_issued(current
, current
) == X509_V_OK
) {
1214 // either ctx->cert is itself self-signed or untrustedCerts
1215 // aready contain the self-signed current certificate
1219 // untrustedCerts is short, not worth indexing
1220 X509
*issuer
= sk_x509_findIssuer(untrustedCerts
, current
);
1222 if ((issuer
= findCertIssuerFast(SquidUntrustedCerts
, current
)))
1223 sk_X509_push(untrustedCerts
, issuer
);
1229 debugs(83, 2, "exceeded the maximum certificate chain length: " << depth
);
1232 /// OpenSSL certificate validation callback.
1234 untrustedToStoreCtx_cb(X509_STORE_CTX
*ctx
,void *data
)
1236 debugs(83, 4, "Try to use pre-downloaded intermediate certificates\n");
1238 SSL
*ssl
= static_cast<SSL
*>(X509_STORE_CTX_get_ex_data(ctx
, SSL_get_ex_data_X509_STORE_CTX_idx()));
1239 STACK_OF(X509
) *sslUntrustedStack
= static_cast <STACK_OF(X509
) *>(SSL_get_ex_data(ssl
, ssl_ex_index_ssl_untrusted_chain
));
1241 // OpenSSL already maintains ctx->untrusted but we cannot modify
1242 // internal OpenSSL list directly. We have to give OpenSSL our own
1243 // list, but it must include certificates on the OpenSSL ctx->untrusted
1244 #if HAVE_LIBCRYPTO_X509_STORE_CTX_GET0_UNTRUSTED
1245 STACK_OF(X509
) *oldUntrusted
= X509_STORE_CTX_get0_untrusted(ctx
);
1247 STACK_OF(X509
) *oldUntrusted
= ctx
->untrusted
;
1249 STACK_OF(X509
) *sk
= sk_X509_dup(oldUntrusted
); // oldUntrusted is always not NULL
1251 for (int i
= 0; i
< sk_X509_num(sslUntrustedStack
); ++i
) {
1252 X509
*cert
= sk_X509_value(sslUntrustedStack
, i
);
1253 sk_X509_push(sk
, cert
);
1256 // If the local untrusted certificates internal database is used
1257 // run completeIssuers to add missing certificates if possible.
1258 if (SquidUntrustedCerts
.size() > 0)
1259 completeIssuers(ctx
, sk
);
1261 X509_STORE_CTX_set_chain(ctx
, sk
); // No locking/unlocking, just sets ctx->untrusted
1262 int ret
= X509_verify_cert(ctx
);
1263 #if HAVE_LIBCRYPTO_X509_STORE_CTX_SET0_UNTRUSTED
1264 X509_STORE_CTX_set0_untrusted(ctx
, oldUntrusted
);
1266 X509_STORE_CTX_set_chain(ctx
, oldUntrusted
); // Set back the old untrusted list
1268 sk_X509_free(sk
); // Release sk list
1273 Ssl::useSquidUntrusted(SSL_CTX
*sslContext
)
1275 SSL_CTX_set_cert_verify_callback(sslContext
, untrustedToStoreCtx_cb
, NULL
);
1279 Ssl::loadSquidUntrusted(const char *path
)
1281 return Ssl::loadCerts(path
, SquidUntrustedCerts
);
1285 Ssl::unloadSquidUntrusted()
1287 if (SquidUntrustedCerts
.size()) {
1288 for (Ssl::CertsIndexedList::iterator it
= SquidUntrustedCerts
.begin(); it
!= SquidUntrustedCerts
.end(); ++it
) {
1289 X509_free(it
->second
);
1291 SquidUntrustedCerts
.clear();
1296 \ingroup ServerProtocolSSLInternal
1297 * Read certificate from file.
1298 * See also: static readSslX509Certificate function, gadgets.cc file
1300 static X509
* readSslX509CertificatesChain(char const * certFilename
, STACK_OF(X509
)* chain
)
1304 Ssl::BIO_Pointer
bio(BIO_new(BIO_s_file()));
1307 if (!BIO_read_filename(bio
.get(), certFilename
))
1309 X509
*certificate
= PEM_read_bio_X509(bio
.get(), NULL
, NULL
, NULL
);
1311 if (certificate
&& chain
) {
1313 if (X509_check_issued(certificate
, certificate
) == X509_V_OK
)
1314 debugs(83, 5, "Certificate is self-signed, will not be chained");
1316 // and add to the chain any other certificate exist in the file
1317 while (X509
*ca
= PEM_read_bio_X509(bio
.get(), NULL
, NULL
, NULL
)) {
1318 if (!sk_X509_push(chain
, ca
))
1319 debugs(83, DBG_IMPORTANT
, "WARNING: unable to add CA certificate to cert chain");
1327 void Ssl::readCertChainAndPrivateKeyFromFiles(Security::CertPointer
& cert
, EVP_PKEY_Pointer
& pkey
, X509_STACK_Pointer
& chain
, char const * certFilename
, char const * keyFilename
)
1329 if (keyFilename
== NULL
)
1330 keyFilename
= certFilename
;
1332 if (certFilename
== NULL
)
1333 certFilename
= keyFilename
;
1335 debugs(83, DBG_IMPORTANT
, "Using certificate in " << certFilename
);
1338 chain
.reset(sk_X509_new_null());
1340 debugs(83, DBG_IMPORTANT
, "WARNING: unable to allocate memory for cert chain");
1341 // XXX: ssl_ask_password_cb needs SSL_CTX_set_default_passwd_cb_userdata()
1342 // so this may not fully work iff Config.Program.ssl_password is set.
1343 pem_password_cb
*cb
= ::Config
.Program
.ssl_password
? &ssl_ask_password_cb
: NULL
;
1344 pkey
.resetWithoutLocking(readSslPrivateKey(keyFilename
, cb
));
1345 cert
.resetWithoutLocking(readSslX509CertificatesChain(certFilename
, chain
.get()));
1347 debugs(83, DBG_IMPORTANT
, "WARNING: missing cert in '" << certFilename
<< "'");
1349 debugs(83, DBG_IMPORTANT
, "WARNING: missing private key in '" << keyFilename
<< "'");
1350 } else if (!X509_check_private_key(cert
.get(), pkey
.get())) {
1351 debugs(83, DBG_IMPORTANT
, "WARNING: X509_check_private_key() failed to verify signing cert");
1353 return; // everything is okay
1359 bool Ssl::generateUntrustedCert(Security::CertPointer
&untrustedCert
, EVP_PKEY_Pointer
&untrustedPkey
, Security::CertPointer
const &cert
, EVP_PKEY_Pointer
const & pkey
)
1361 // Generate the self-signed certificate, using a hard-coded subject prefix
1362 Ssl::CertificateProperties certProperties
;
1363 if (const char *cn
= CommonHostName(cert
.get())) {
1364 certProperties
.commonName
= "Not trusted by \"";
1365 certProperties
.commonName
+= cn
;
1366 certProperties
.commonName
+= "\"";
1367 } else if (const char *org
= getOrganization(cert
.get())) {
1368 certProperties
.commonName
= "Not trusted by \"";
1369 certProperties
.commonName
+= org
;
1370 certProperties
.commonName
+= "\"";
1372 certProperties
.commonName
= "Not trusted";
1373 certProperties
.setCommonName
= true;
1374 // O, OU, and other CA subject fields will be mimicked
1375 // Expiration date and other common properties will be mimicked
1376 certProperties
.signAlgorithm
= Ssl::algSignSelf
;
1377 certProperties
.signWithPkey
.resetAndLock(pkey
.get());
1378 certProperties
.mimicCert
.resetAndLock(cert
.get());
1379 return Ssl::generateSslCertificate(untrustedCert
, untrustedPkey
, certProperties
);
1382 #endif /* USE_OPENSSL */