diff options
Diffstat (limited to 'include/ssl_key_handler.hpp')
-rw-r--r-- | include/ssl_key_handler.hpp | 567 |
1 files changed, 309 insertions, 258 deletions
diff --git a/include/ssl_key_handler.hpp b/include/ssl_key_handler.hpp index 4eac8035f5..47893bfb5e 100644 --- a/include/ssl_key_handler.hpp +++ b/include/ssl_key_handler.hpp @@ -10,304 +10,355 @@ #include <openssl/rand.h> #include <openssl/rsa.h> #include <openssl/ssl.h> -#include <random> + #include <boost/asio.hpp> +#include <random> -namespace ensuressl { +namespace ensuressl +{ static void initOpenssl(); static void cleanupOpenssl(); static EVP_PKEY *createRsaKey(); static EVP_PKEY *createEcKey(); static void handleOpensslError(); -inline bool verifyOpensslKeyCert(const std::string &filepath) { - bool privateKeyValid = false; - bool certValid = false; - - std::cout << "Checking certs in file " << filepath << "\n"; - - FILE *file = fopen(filepath.c_str(), "r"); - if (file != NULL) { - EVP_PKEY *pkey = PEM_read_PrivateKey(file, NULL, NULL, NULL); - int rc; - if (pkey != nullptr) { - RSA *rsa = EVP_PKEY_get1_RSA(pkey); - if (rsa != nullptr) { - std::cout << "Found an RSA key\n"; - if (RSA_check_key(rsa) == 1) { - // private_key_valid = true; - } else { - std::cerr << "Key not valid error number " << ERR_get_error() << "\n"; - } - RSA_free(rsa); - } else { - EC_KEY *ec = EVP_PKEY_get1_EC_KEY(pkey); - if (ec != nullptr) { - std::cout << "Found an EC key\n"; - if (EC_KEY_check_key(ec) == 1) { - privateKeyValid = true; - } else { - std::cerr << "Key not valid error number " << ERR_get_error() - << "\n"; - } - EC_KEY_free(ec); - } - } - - if (privateKeyValid) { - X509 *x509 = PEM_read_X509(file, NULL, NULL, NULL); - if (x509 == nullptr) { - std::cout << "error getting x509 cert " << ERR_get_error() << "\n"; - } else { - rc = X509_verify(x509, pkey); - if (rc == 1) { - certValid = true; - } else { - std::cerr << "Error in verifying private key signature " - << ERR_get_error() << "\n"; - } +inline bool verifyOpensslKeyCert(const std::string &filepath) +{ + bool privateKeyValid = false; + bool certValid = false; + + std::cout << "Checking certs in file " << filepath << "\n"; + + FILE *file = fopen(filepath.c_str(), "r"); + if (file != NULL) + { + EVP_PKEY *pkey = PEM_read_PrivateKey(file, NULL, NULL, NULL); + int rc; + if (pkey != nullptr) + { + RSA *rsa = EVP_PKEY_get1_RSA(pkey); + if (rsa != nullptr) + { + std::cout << "Found an RSA key\n"; + if (RSA_check_key(rsa) == 1) + { + // private_key_valid = true; + } + else + { + std::cerr << "Key not valid error number " + << ERR_get_error() << "\n"; + } + RSA_free(rsa); + } + else + { + EC_KEY *ec = EVP_PKEY_get1_EC_KEY(pkey); + if (ec != nullptr) + { + std::cout << "Found an EC key\n"; + if (EC_KEY_check_key(ec) == 1) + { + privateKeyValid = true; + } + else + { + std::cerr << "Key not valid error number " + << ERR_get_error() << "\n"; + } + EC_KEY_free(ec); + } + } + + if (privateKeyValid) + { + X509 *x509 = PEM_read_X509(file, NULL, NULL, NULL); + if (x509 == nullptr) + { + std::cout << "error getting x509 cert " << ERR_get_error() + << "\n"; + } + else + { + rc = X509_verify(x509, pkey); + if (rc == 1) + { + certValid = true; + } + else + { + std::cerr << "Error in verifying private key signature " + << ERR_get_error() << "\n"; + } + } + } + + EVP_PKEY_free(pkey); } - } - - EVP_PKEY_free(pkey); + fclose(file); } - fclose(file); - } - return certValid; + return certValid; } -inline void generateSslCertificate(const std::string &filepath) { - FILE *pFile = NULL; - std::cout << "Generating new keys\n"; - initOpenssl(); - - // std::cerr << "Generating RSA key"; - // EVP_PKEY *pRsaPrivKey = create_rsa_key(); - - std::cerr << "Generating EC key\n"; - EVP_PKEY *pRsaPrivKey = createEcKey(); - if (pRsaPrivKey != nullptr) { - std::cerr << "Generating x509 Certificate\n"; - // Use this code to directly generate a certificate - X509 *x509; - x509 = X509_new(); - if (x509 != nullptr) { - // get a random number from the RNG for the certificate serial number - // If this is not random, regenerating certs throws broswer errors - std::random_device rd; - int serial = rd(); - - ASN1_INTEGER_set(X509_get_serialNumber(x509), serial); - - // not before this moment - X509_gmtime_adj(X509_get_notBefore(x509), 0); - // Cert is valid for 10 years - X509_gmtime_adj(X509_get_notAfter(x509), 60L * 60L * 24L * 365L * 10L); - - // set the public key to the key we just generated - X509_set_pubkey(x509, pRsaPrivKey); - - // get the subject name - X509_NAME *name; - name = X509_get_subject_name(x509); - - X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, - reinterpret_cast<const unsigned char *>("US"), - -1, -1, 0); - X509_NAME_add_entry_by_txt( - name, "O", MBSTRING_ASC, - reinterpret_cast<const unsigned char *>("Intel BMC"), -1, -1, 0); - X509_NAME_add_entry_by_txt( - name, "CN", MBSTRING_ASC, - reinterpret_cast<const unsigned char *>("testhost"), -1, -1, 0); - // set the CSR options - X509_set_issuer_name(x509, name); - - // Sign the certificate with our private key - X509_sign(x509, pRsaPrivKey, EVP_sha256()); - - pFile = fopen(filepath.c_str(), "wt"); - - if (pFile != nullptr) { - PEM_write_PrivateKey(pFile, pRsaPrivKey, NULL, NULL, 0, 0, NULL); - - PEM_write_X509(pFile, x509); - fclose(pFile); - pFile = NULL; - } - - X509_free(x509); - } +inline void generateSslCertificate(const std::string &filepath) +{ + FILE *pFile = NULL; + std::cout << "Generating new keys\n"; + initOpenssl(); + + // std::cerr << "Generating RSA key"; + // EVP_PKEY *pRsaPrivKey = create_rsa_key(); + + std::cerr << "Generating EC key\n"; + EVP_PKEY *pRsaPrivKey = createEcKey(); + if (pRsaPrivKey != nullptr) + { + std::cerr << "Generating x509 Certificate\n"; + // Use this code to directly generate a certificate + X509 *x509; + x509 = X509_new(); + if (x509 != nullptr) + { + // get a random number from the RNG for the certificate serial + // number If this is not random, regenerating certs throws broswer + // errors + std::random_device rd; + int serial = rd(); + + ASN1_INTEGER_set(X509_get_serialNumber(x509), serial); + + // not before this moment + X509_gmtime_adj(X509_get_notBefore(x509), 0); + // Cert is valid for 10 years + X509_gmtime_adj(X509_get_notAfter(x509), + 60L * 60L * 24L * 365L * 10L); + + // set the public key to the key we just generated + X509_set_pubkey(x509, pRsaPrivKey); + + // get the subject name + X509_NAME *name; + name = X509_get_subject_name(x509); + + X509_NAME_add_entry_by_txt( + name, "C", MBSTRING_ASC, + reinterpret_cast<const unsigned char *>("US"), -1, -1, 0); + X509_NAME_add_entry_by_txt( + name, "O", MBSTRING_ASC, + reinterpret_cast<const unsigned char *>("Intel BMC"), -1, -1, + 0); + X509_NAME_add_entry_by_txt( + name, "CN", MBSTRING_ASC, + reinterpret_cast<const unsigned char *>("testhost"), -1, -1, 0); + // set the CSR options + X509_set_issuer_name(x509, name); + + // Sign the certificate with our private key + X509_sign(x509, pRsaPrivKey, EVP_sha256()); + + pFile = fopen(filepath.c_str(), "wt"); + + if (pFile != nullptr) + { + PEM_write_PrivateKey(pFile, pRsaPrivKey, NULL, NULL, 0, 0, + NULL); + + PEM_write_X509(pFile, x509); + fclose(pFile); + pFile = NULL; + } + + X509_free(x509); + } - EVP_PKEY_free(pRsaPrivKey); - pRsaPrivKey = NULL; - } + EVP_PKEY_free(pRsaPrivKey); + pRsaPrivKey = NULL; + } - // cleanup_openssl(); + // cleanup_openssl(); } -EVP_PKEY *createRsaKey() { - RSA *pRSA = NULL; +EVP_PKEY *createRsaKey() +{ + RSA *pRSA = NULL; #if OPENSSL_VERSION_NUMBER < 0x00908000L - pRSA = RSA_generate_key(2048, RSA_3, NULL, NULL); + pRSA = RSA_generate_key(2048, RSA_3, NULL, NULL); #else - RSA_generate_key_ex(pRSA, 2048, NULL, NULL); + RSA_generate_key_ex(pRSA, 2048, NULL, NULL); #endif - EVP_PKEY *pKey = EVP_PKEY_new(); - if ((pRSA != nullptr) && (pKey != nullptr) && - EVP_PKEY_assign_RSA(pKey, pRSA)) { - /* pKey owns pRSA from now */ - if (RSA_check_key(pRSA) <= 0) { - fprintf(stderr, "RSA_check_key failed.\n"); - handleOpensslError(); - EVP_PKEY_free(pKey); - pKey = NULL; - } - } else { - handleOpensslError(); - if (pRSA != nullptr) { - RSA_free(pRSA); - pRSA = NULL; + EVP_PKEY *pKey = EVP_PKEY_new(); + if ((pRSA != nullptr) && (pKey != nullptr) && + EVP_PKEY_assign_RSA(pKey, pRSA)) + { + /* pKey owns pRSA from now */ + if (RSA_check_key(pRSA) <= 0) + { + fprintf(stderr, "RSA_check_key failed.\n"); + handleOpensslError(); + EVP_PKEY_free(pKey); + pKey = NULL; + } } - if (pKey != nullptr) { - EVP_PKEY_free(pKey); - pKey = NULL; + else + { + handleOpensslError(); + if (pRSA != nullptr) + { + RSA_free(pRSA); + pRSA = NULL; + } + if (pKey != nullptr) + { + EVP_PKEY_free(pKey); + pKey = NULL; + } } - } - return pKey; + return pKey; } -EVP_PKEY *createEcKey() { - EVP_PKEY *pKey = NULL; - int eccgrp = 0; - eccgrp = OBJ_txt2nid("prime256v1"); - - EC_KEY *myecc = EC_KEY_new_by_curve_name(eccgrp); - if (myecc != nullptr) { - EC_KEY_set_asn1_flag(myecc, OPENSSL_EC_NAMED_CURVE); - EC_KEY_generate_key(myecc); - pKey = EVP_PKEY_new(); - if (pKey != nullptr) { - if (EVP_PKEY_assign_EC_KEY(pKey, myecc)) { - /* pKey owns pRSA from now */ - if (EC_KEY_check_key(myecc) <= 0) { - fprintf(stderr, "EC_check_key failed.\n"); +EVP_PKEY *createEcKey() +{ + EVP_PKEY *pKey = NULL; + int eccgrp = 0; + eccgrp = OBJ_txt2nid("prime256v1"); + + EC_KEY *myecc = EC_KEY_new_by_curve_name(eccgrp); + if (myecc != nullptr) + { + EC_KEY_set_asn1_flag(myecc, OPENSSL_EC_NAMED_CURVE); + EC_KEY_generate_key(myecc); + pKey = EVP_PKEY_new(); + if (pKey != nullptr) + { + if (EVP_PKEY_assign_EC_KEY(pKey, myecc)) + { + /* pKey owns pRSA from now */ + if (EC_KEY_check_key(myecc) <= 0) + { + fprintf(stderr, "EC_check_key failed.\n"); + } + } } - } } - } - return pKey; + return pKey; } -void initOpenssl() { +void initOpenssl() +{ #if OPENSSL_VERSION_NUMBER < 0x10100000L - SSL_load_error_strings(); - OpenSSL_add_all_algorithms(); - RAND_load_file("/dev/urandom", 1024); + SSL_load_error_strings(); + OpenSSL_add_all_algorithms(); + RAND_load_file("/dev/urandom", 1024); #endif } -void cleanupOpenssl() { - CRYPTO_cleanup_all_ex_data(); - ERR_free_strings(); +void cleanupOpenssl() +{ + CRYPTO_cleanup_all_ex_data(); + ERR_free_strings(); #if OPENSSL_VERSION_NUMBER < 0x10100000L - ERR_remove_thread_state(0); + ERR_remove_thread_state(0); #endif - EVP_cleanup(); + EVP_cleanup(); } -void handleOpensslError() { ERR_print_errors_fp(stderr); } -inline void ensureOpensslKeyPresentAndValid(const std::string &filepath) { - bool pemFileValid = false; +void handleOpensslError() +{ + ERR_print_errors_fp(stderr); +} +inline void ensureOpensslKeyPresentAndValid(const std::string &filepath) +{ + bool pemFileValid = false; - pemFileValid = verifyOpensslKeyCert(filepath); + pemFileValid = verifyOpensslKeyCert(filepath); - if (!pemFileValid) { - std::cerr << "Error in verifying signature, regenerating\n"; - generateSslCertificate(filepath); - } + if (!pemFileValid) + { + std::cerr << "Error in verifying signature, regenerating\n"; + generateSslCertificate(filepath); + } } -inline boost::asio::ssl::context getSslContext( - const std::string &ssl_pem_file) { - boost::asio::ssl::context mSslContext{boost::asio::ssl::context::sslv23}; - mSslContext.set_options(boost::asio::ssl::context::default_workarounds | - boost::asio::ssl::context::no_sslv2 | - boost::asio::ssl::context::no_sslv3 | - boost::asio::ssl::context::single_dh_use | - boost::asio::ssl::context::no_tlsv1 | - boost::asio::ssl::context::no_tlsv1_1); - - // m_ssl_context.set_verify_mode(boost::asio::ssl::verify_peer); - mSslContext.use_certificate_file(ssl_pem_file, - boost::asio::ssl::context::pem); - mSslContext.use_private_key_file(ssl_pem_file, - boost::asio::ssl::context::pem); - - // Set up EC curves to auto (boost asio doesn't have a method for this) - // There is a pull request to add this. Once this is included in an asio - // drop, use the right way - // http://stackoverflow.com/questions/18929049/boost-asio-with-ecdsa-certificate-issue - if (SSL_CTX_set_ecdh_auto(mSslContext.native_handle(), 1) != 1) { - BMCWEB_LOG_ERROR << "Error setting tmp ecdh list\n"; - } - - // From mozilla "compatibility" - std::string mozillaCompatibilityCiphers = - "ECDHE-ECDSA-CHACHA20-POLY1305:" - "ECDHE-RSA-CHACHA20-POLY1305:" - "ECDHE-ECDSA-AES128-GCM-SHA256:" - "ECDHE-RSA-AES128-GCM-SHA256:" - "ECDHE-ECDSA-AES256-GCM-SHA384:" - "ECDHE-RSA-AES256-GCM-SHA384:" - "DHE-RSA-AES128-GCM-SHA256:" - "DHE-RSA-AES256-GCM-SHA384:" - "ECDHE-ECDSA-AES128-SHA256:" - "ECDHE-RSA-AES128-SHA256:" - "ECDHE-ECDSA-AES128-SHA:" - "ECDHE-RSA-AES256-SHA384:" - "ECDHE-RSA-AES128-SHA:" - "ECDHE-ECDSA-AES256-SHA384:" - "ECDHE-ECDSA-AES256-SHA:" - "ECDHE-RSA-AES256-SHA:" - "DHE-RSA-AES128-SHA256:" - "DHE-RSA-AES128-SHA:" - "DHE-RSA-AES256-SHA256:" - "DHE-RSA-AES256-SHA:" - "ECDHE-ECDSA-DES-CBC3-SHA:" - "ECDHE-RSA-DES-CBC3-SHA:" - "EDH-RSA-DES-CBC3-SHA:" - "AES128-GCM-SHA256:" - "AES256-GCM-SHA384:" - "AES128-SHA256:" - "AES256-SHA256:" - "AES128-SHA:" - "AES256-SHA:" - "DES-CBC3-SHA:" - "!DSS"; - - // From mozilla "modern" - std::string mozillaModernCiphers = - "ECDHE-ECDSA-AES256-GCM-SHA384:" - "ECDHE-RSA-AES256-GCM-SHA384:" - "ECDHE-ECDSA-CHACHA20-POLY1305:" - "ECDHE-RSA-CHACHA20-POLY1305:" - "ECDHE-ECDSA-AES128-GCM-SHA256:" - "ECDHE-RSA-AES128-GCM-SHA256:" - "ECDHE-ECDSA-AES256-SHA384:" - "ECDHE-RSA-AES256-SHA384:" - "ECDHE-ECDSA-AES128-SHA256:" - "ECDHE-RSA-AES128-SHA256"; - - std::string aesOnlyCiphers = "AES128+EECDH:AES128+EDH:!aNULL:!eNULL"; - - if (SSL_CTX_set_cipher_list(mSslContext.native_handle(), - mozillaCompatibilityCiphers.c_str()) != 1) { - BMCWEB_LOG_ERROR << "Error setting cipher list\n"; - } - return mSslContext; +inline boost::asio::ssl::context getSslContext(const std::string &ssl_pem_file) +{ + boost::asio::ssl::context mSslContext{boost::asio::ssl::context::sslv23}; + mSslContext.set_options(boost::asio::ssl::context::default_workarounds | + boost::asio::ssl::context::no_sslv2 | + boost::asio::ssl::context::no_sslv3 | + boost::asio::ssl::context::single_dh_use | + boost::asio::ssl::context::no_tlsv1 | + boost::asio::ssl::context::no_tlsv1_1); + + // m_ssl_context.set_verify_mode(boost::asio::ssl::verify_peer); + mSslContext.use_certificate_file(ssl_pem_file, + boost::asio::ssl::context::pem); + mSslContext.use_private_key_file(ssl_pem_file, + boost::asio::ssl::context::pem); + + // Set up EC curves to auto (boost asio doesn't have a method for this) + // There is a pull request to add this. Once this is included in an asio + // drop, use the right way + // http://stackoverflow.com/questions/18929049/boost-asio-with-ecdsa-certificate-issue + if (SSL_CTX_set_ecdh_auto(mSslContext.native_handle(), 1) != 1) + { + BMCWEB_LOG_ERROR << "Error setting tmp ecdh list\n"; + } + + // From mozilla "compatibility" + std::string mozillaCompatibilityCiphers = "ECDHE-ECDSA-CHACHA20-POLY1305:" + "ECDHE-RSA-CHACHA20-POLY1305:" + "ECDHE-ECDSA-AES128-GCM-SHA256:" + "ECDHE-RSA-AES128-GCM-SHA256:" + "ECDHE-ECDSA-AES256-GCM-SHA384:" + "ECDHE-RSA-AES256-GCM-SHA384:" + "DHE-RSA-AES128-GCM-SHA256:" + "DHE-RSA-AES256-GCM-SHA384:" + "ECDHE-ECDSA-AES128-SHA256:" + "ECDHE-RSA-AES128-SHA256:" + "ECDHE-ECDSA-AES128-SHA:" + "ECDHE-RSA-AES256-SHA384:" + "ECDHE-RSA-AES128-SHA:" + "ECDHE-ECDSA-AES256-SHA384:" + "ECDHE-ECDSA-AES256-SHA:" + "ECDHE-RSA-AES256-SHA:" + "DHE-RSA-AES128-SHA256:" + "DHE-RSA-AES128-SHA:" + "DHE-RSA-AES256-SHA256:" + "DHE-RSA-AES256-SHA:" + "ECDHE-ECDSA-DES-CBC3-SHA:" + "ECDHE-RSA-DES-CBC3-SHA:" + "EDH-RSA-DES-CBC3-SHA:" + "AES128-GCM-SHA256:" + "AES256-GCM-SHA384:" + "AES128-SHA256:" + "AES256-SHA256:" + "AES128-SHA:" + "AES256-SHA:" + "DES-CBC3-SHA:" + "!DSS"; + + // From mozilla "modern" + std::string mozillaModernCiphers = "ECDHE-ECDSA-AES256-GCM-SHA384:" + "ECDHE-RSA-AES256-GCM-SHA384:" + "ECDHE-ECDSA-CHACHA20-POLY1305:" + "ECDHE-RSA-CHACHA20-POLY1305:" + "ECDHE-ECDSA-AES128-GCM-SHA256:" + "ECDHE-RSA-AES128-GCM-SHA256:" + "ECDHE-ECDSA-AES256-SHA384:" + "ECDHE-RSA-AES256-SHA384:" + "ECDHE-ECDSA-AES128-SHA256:" + "ECDHE-RSA-AES128-SHA256"; + + std::string aesOnlyCiphers = "AES128+EECDH:AES128+EDH:!aNULL:!eNULL"; + + if (SSL_CTX_set_cipher_list(mSslContext.native_handle(), + mozillaCompatibilityCiphers.c_str()) != 1) + { + BMCWEB_LOG_ERROR << "Error setting cipher list\n"; + } + return mSslContext; } -} // namespace ensuressl +} // namespace ensuressl #endif
\ No newline at end of file |