@@ -641,6 +641,56 @@ bool ssl_options_t::handshake(
641641 return true ;
642642}
643643
644+ std::string get_hr_ssl_fingerprint (const X509 *cert, const EVP_MD *fdig)
645+ {
646+ unsigned int j;
647+ unsigned int n;
648+ unsigned char md[EVP_MAX_MD_SIZE ];
649+ std::string fingerprint;
650+
651+ CHECK_AND_ASSERT_THROW_MES (cert && fdig, " Pointer args to get_hr_ssl_fingerprint cannot be null" );
652+
653+ if (!X509_digest (cert, fdig, md, &n))
654+ {
655+ const unsigned long ssl_err_val = static_cast <int >(ERR_get_error ());
656+ const boost::system::error_code ssl_err_code = boost::asio::error::ssl_errors (static_cast <int >(ssl_err_val));
657+ MERROR (" Failed to create SSL fingerprint: " << ERR_reason_error_string (ssl_err_val));
658+ throw boost::system::system_error (ssl_err_code, ERR_reason_error_string (ssl_err_val));
659+ }
660+ fingerprint.resize (n * 3 - 1 );
661+ char *out = &fingerprint[0 ];
662+ for (j = 0 ; j < n; ++j)
663+ {
664+ snprintf (out, 3 + (j + 1 < n), " %02X%s" , md[j], (j + 1 == n) ? " " : " :" );
665+ out += 3 ;
666+ }
667+ return fingerprint;
668+ }
669+
670+ std::string get_hr_ssl_fingerprint_from_file (const std::string& cert_path, const EVP_MD *fdig) {
671+ // Open file for reading
672+ FILE * fp = fopen (cert_path.c_str (), " r" );
673+ if (!fp)
674+ {
675+ const boost::system::error_code err_code (errno, boost::system::system_category ());
676+ throw boost::system::system_error (err_code, " Failed to open certificate file '" + cert_path + " '" );
677+ }
678+ std::unique_ptr<FILE , decltype (&fclose)> file (fp, &fclose);
679+
680+ // Extract certificate structure from file
681+ X509 * ssl_cert_handle = PEM_read_X509 (file.get (), NULL , NULL , NULL );
682+ if (!ssl_cert_handle) {
683+ const unsigned long ssl_err_val = static_cast <int >(ERR_get_error ());
684+ const boost::system::error_code ssl_err_code = boost::asio::error::ssl_errors (static_cast <int >(ssl_err_val));
685+ MERROR (" OpenSSL error occurred while loading certificate at '" + cert_path + " '" );
686+ throw boost::system::system_error (ssl_err_code, ERR_reason_error_string (ssl_err_val));
687+ }
688+ std::unique_ptr<X509 , decltype (&X509_free)> ssl_cert (ssl_cert_handle, &X509_free);
689+
690+ // Get the fingerprint from X509 structure
691+ return get_hr_ssl_fingerprint (ssl_cert.get (), fdig);
692+ }
693+
644694bool ssl_support_from_string (ssl_support_t &ssl, boost::string_ref s)
645695{
646696 if (s == " enabled" )
@@ -705,6 +755,29 @@ boost::system::error_code store_ssl_keys(boost::asio::ssl::context& ssl, const b
705755 return boost::asio::error::ssl_errors (ERR_get_error ());
706756 if (std::fclose (file.release ()) != 0 )
707757 return {errno, boost::system::system_category ()};
758+
759+ // write SHA-256 fingerprint file
760+ const boost::filesystem::path fp_file{base.string () + " .fingerprint" };
761+ file.reset (std::fopen (fp_file.string ().c_str (), " w" ));
762+ if (!file)
763+ return {errno, boost::system::system_category ()};
764+ const auto fp_perms = (boost::filesystem::owner_read | boost::filesystem::group_read | boost::filesystem::others_read);
765+ boost::filesystem::permissions (fp_file, fp_perms, error);
766+ if (error)
767+ return error;
768+ try
769+ {
770+ const std::string fingerprint = get_hr_ssl_fingerprint (ssl_cert);
771+ if (fingerprint.length () != fwrite (fingerprint.c_str (), sizeof (char ), fingerprint.length (), file.get ()))
772+ return {errno, boost::system::system_category ()};
773+ }
774+ catch (const boost::system::system_error& fperr)
775+ {
776+ return fperr.code ();
777+ }
778+ if (std::fclose (file.release ()) != 0 )
779+ return {errno, boost::system::system_category ()};
780+
708781 return error;
709782}
710783
0 commit comments