bool SSLManager::_setupPEM(const std::string& keyFile , const std::string& password) { _password = password; if ( SSL_CTX_use_certificate_chain_file( _context , keyFile.c_str() ) != 1 ) { error() << "cannot read certificate file: " << keyFile << ' ' << _getSSLErrorMessage(ERR_get_error()) << endl; return false; } // If password is empty, use default OpenSSL callback, which uses the terminal // to securely request the password interactively from the user. if (!password.empty()) { SSL_CTX_set_default_passwd_cb_userdata( _context , this ); SSL_CTX_set_default_passwd_cb( _context, &SSLManager::password_cb ); } if ( SSL_CTX_use_PrivateKey_file( _context , keyFile.c_str() , SSL_FILETYPE_PEM ) != 1 ) { error() << "cannot read key file: " << keyFile << ' ' << _getSSLErrorMessage(ERR_get_error()) << endl; return false; } // Verify that the certificate and the key go together. if (SSL_CTX_check_private_key(_context) != 1) { error() << "SSL certificate validation: " << _getSSLErrorMessage(ERR_get_error()) << endl; return false; } return true; }
bool SSLManager::_setupPEM(const std::string& keyFile , const std::string& password) { _password = password; if ( SSL_CTX_use_certificate_chain_file( _context , keyFile.c_str() ) != 1 ) { error() << "cannot read certificate file: " << keyFile << ' ' << _getSSLErrorMessage(ERR_get_error()) << endl; return false; } SSL_CTX_set_default_passwd_cb_userdata( _context , this ); SSL_CTX_set_default_passwd_cb( _context, &SSLManager::password_cb ); if ( SSL_CTX_use_PrivateKey_file( _context , keyFile.c_str() , SSL_FILETYPE_PEM ) != 1 ) { error() << "cannot read key file: " << keyFile << ' ' << _getSSLErrorMessage(ERR_get_error()) << endl; return false; } // Verify that the certificate and the key go together. if (SSL_CTX_check_private_key(_context) != 1) { error() << "SSL certificate validation: " << _getSSLErrorMessage(ERR_get_error()) << endl; return false; } return true; }
SSL* SSLManager::_secure(int fd) { // This just ensures that SSL multithreading support is set up for this thread, // if it's not already. SSLThreadInfo::get(); SSL * ssl = SSL_new(_context); massert(15861, _getSSLErrorMessage(ERR_get_error()), ssl); int status = SSL_set_fd( ssl , fd ); massert(16510, _getSSLErrorMessage(ERR_get_error()), status == 1); return ssl; }
SSLManager::SSLManager(const Params& params) : _validateCertificates(false), _weakValidation(params.weakCertificateValidation) { SSL_library_init(); SSL_load_error_strings(); ERR_load_crypto_strings(); if (params.fipsMode) { _setupFIPS(); } // Add all digests and ciphers to OpenSSL's internal table // so that encryption/decryption is backwards compatible OpenSSL_add_all_algorithms(); _context = SSL_CTX_new(SSLv23_method()); massert(15864, mongoutils::str::stream() << "can't create SSL Context: " << _getSSLErrorMessage(ERR_get_error()), _context); // Activate all bug workaround options, to support buggy client SSL's. SSL_CTX_set_options(_context, SSL_OP_ALL); // If renegotiation is needed, don't return from recv() or send() until it's successful. // Note: this is for blocking sockets only. SSL_CTX_set_mode(_context, SSL_MODE_AUTO_RETRY); // Set context within which session can be reused int status = SSL_CTX_set_session_id_context( _context, static_cast<unsigned char*>(static_cast<void*>(&_context)), sizeof(_context)); if (!status) { uasserted(16768,"ssl initialization problem"); } SSLThreadInfo::init(); SSLThreadInfo::get(); if (!params.pemfile.empty()) { if (!_setupPEM(params.pemfile, params.pempwd)) { uasserted(16562, "ssl initialization problem"); } } if (!params.cafile.empty()) { // Set up certificate validation with a certificate authority if (!_setupCA(params.cafile)) { uasserted(16563, "ssl initialization problem"); } } if (!params.crlfile.empty()) { if (!_setupCRL(params.crlfile)) { uasserted(16582, "ssl initialization problem"); } } }
void SSLManager::_setupFIPS() { // Turn on FIPS mode if requested. int status = FIPS_mode_set(1); if (!status) { error() << "can't activate FIPS mode: " << _getSSLErrorMessage(ERR_get_error()) << endl; fassertFailed(16703); } log() << "FIPS 140-2 mode activated" << endl; }
bool SSLManager::_setupCA(const std::string& caFile) { // Load trusted CA if (SSL_CTX_load_verify_locations(_context, caFile.c_str(), NULL) != 1) { error() << "cannot read certificate authority file: " << caFile << " " << _getSSLErrorMessage(ERR_get_error()) << endl; return false; } // Set SSL to require peer (client) certificate verification // if a certificate is presented SSL_CTX_set_verify(_context, SSL_VERIFY_PEER, &SSLManager::verify_cb); _validateCertificates = true; return true; }
void SSLManager::_setupFIPS() { // Turn on FIPS mode if requested. scoped_lock lk(fipsMtx); if (fipsActivated) { return; } int status = FIPS_mode_set(1); if (!status) { error() << "can't activate FIPS mode: " << _getSSLErrorMessage(ERR_get_error()) << endl; fassertFailed(16703); } log() << "FIPS 140-2 mode activated" << endl; fipsActivated = true; }
bool SSLManager::_setupCRL(const std::string& crlFile) { X509_STORE *store = SSL_CTX_get_cert_store(_context); fassert(16583, store); X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK); X509_LOOKUP *lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); fassert(16584, lookup); int status = X509_load_crl_file(lookup, crlFile.c_str(), X509_FILETYPE_PEM); if (status == 0) { error() << "cannot read CRL file: " << crlFile << ' ' << _getSSLErrorMessage(ERR_get_error()) << endl; return false; } log() << "ssl imported " << status << " revoked certificate" << ((status == 1) ? "" : "s") << " from the revocation list." << endl; return true; }
void SSLManager::_handleSSLError(int code) { switch (code) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: // should not happen because we turned on AUTO_RETRY // However, it turns out this CAN happen during a connect, if the other side // accepts the socket connection but fails to do the SSL handshake in a timely // manner. error() << "SSL error: " << code << ", possibly timed out during connect" << endl; throw SocketException(SocketException::CONNECT_ERROR, ""); break; case SSL_ERROR_SYSCALL: if (code < 0) { error() << "socket error: " << errnoWithDescription() << endl; throw SocketException(SocketException::CONNECT_ERROR, ""); } error() << "could not negotiate SSL connection: EOF detected" << endl; throw SocketException(SocketException::CONNECT_ERROR, ""); break; case SSL_ERROR_SSL: { int ret = ERR_get_error(); error() << _getSSLErrorMessage(ret) << endl; throw SocketException(SocketException::CONNECT_ERROR, ""); break; } case SSL_ERROR_ZERO_RETURN: error() << "could not negotiate SSL connection: EOF detected" << endl; throw SocketException(SocketException::CONNECT_ERROR, ""); break; default: error() << "unrecognized SSL error" << endl; throw SocketException(SocketException::CONNECT_ERROR, ""); break; } }
void SSLManager::_handleSSLError(int code) { switch (code) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: // should not happen because we turned on AUTO_RETRY error() << "SSL error: " << code << endl; fassertFailed( 16676 ); break; case SSL_ERROR_SYSCALL: if (code < 0) { error() << "socket error: " << errnoWithDescription() << endl; throw SocketException(SocketException::CONNECT_ERROR, ""); } error() << "could not negotiate SSL connection: EOF detected" << endl; throw SocketException(SocketException::CONNECT_ERROR, ""); break; case SSL_ERROR_SSL: { int ret = ERR_get_error(); error() << _getSSLErrorMessage(ret) << endl; throw SocketException(SocketException::CONNECT_ERROR, ""); break; } case SSL_ERROR_ZERO_RETURN: error() << "could not negotiate SSL connection: EOF detected" << endl; throw SocketException(SocketException::CONNECT_ERROR, ""); break; default: error() << "unrecognized SSL error" << endl; throw SocketException(SocketException::CONNECT_ERROR, ""); break; } }