diff options
Diffstat (limited to 'http/http_connection.h')
-rw-r--r-- | http/http_connection.h | 156 |
1 files changed, 155 insertions, 1 deletions
diff --git a/http/http_connection.h b/http/http_connection.h index 7cab789..78805a6 100644 --- a/http/http_connection.h +++ b/http/http_connection.h @@ -263,6 +263,141 @@ class Connection // mechanism parser->body_limit(httpReqBodyLimit); req.emplace(parser->get()); + +#ifdef BMCWEB_ENABLE_MUTUAL_TLS_AUTHENTICATION + adaptor.set_verify_callback( + [this](bool preverified, boost::asio::ssl::verify_context& ctx) { + // We always return true to allow full auth flow + if (!preverified) + { + return true; + } + + X509_STORE_CTX* cts = ctx.native_handle(); + if (cts == nullptr) + { + return true; + } + + // Get certificate + X509* peerCert = + X509_STORE_CTX_get_current_cert(ctx.native_handle()); + if (peerCert == nullptr) + { + return true; + } + + // Check if certificate is OK + int error = X509_STORE_CTX_get_error(cts); + if (error != X509_V_OK) + { + return true; + } + // Check that we have reached final certificate in chain + int32_t depth = X509_STORE_CTX_get_error_depth(cts); + if (depth != 0) + + { + BMCWEB_LOG_DEBUG + << "Certificate verification in progress (depth " + << depth << "), waiting to reach final depth"; + return true; + } + + BMCWEB_LOG_DEBUG << "Certificate verification of final depth"; + + // Verify KeyUsage + bool isKeyUsageDigitalSignature = false; + bool isKeyUsageKeyAgreement = false; + + ASN1_BIT_STRING* usage = static_cast<ASN1_BIT_STRING*>( + X509_get_ext_d2i(peerCert, NID_key_usage, NULL, NULL)); + + if (usage == nullptr) + { + return true; + } + + for (int i = 0; i < usage->length; i++) + { + if (KU_DIGITAL_SIGNATURE & usage->data[i]) + { + isKeyUsageDigitalSignature = true; + } + if (KU_KEY_AGREEMENT & usage->data[i]) + { + isKeyUsageKeyAgreement = true; + } + } + + if (!isKeyUsageDigitalSignature || !isKeyUsageKeyAgreement) + { + BMCWEB_LOG_DEBUG << "Certificate ExtendedKeyUsage does " + "not allow provided certificate to " + "be used for user authentication"; + return true; + } + + // Determine that ExtendedKeyUsage includes Client Auth + + stack_st_ASN1_OBJECT* extUsage = + static_cast<stack_st_ASN1_OBJECT*>(X509_get_ext_d2i( + peerCert, NID_ext_key_usage, NULL, NULL)); + + if (extUsage == nullptr) + { + return true; + } + + bool isExKeyUsageClientAuth = false; + for (int i = 0; i < sk_ASN1_OBJECT_num(extUsage); i++) + { + if (NID_client_auth == + OBJ_obj2nid(sk_ASN1_OBJECT_value(extUsage, i))) + { + isExKeyUsageClientAuth = true; + break; + } + } + + // Certificate has to have proper key usages set + if (!isExKeyUsageClientAuth) + { + BMCWEB_LOG_DEBUG << "Certificate ExtendedKeyUsage does " + "not allow provided certificate to " + "be used for user authentication"; + return true; + } + std::string sslUser; + // Extract username contained in CommonName + sslUser.resize(256, '\0'); + + int status = X509_NAME_get_text_by_NID( + X509_get_subject_name(peerCert), NID_commonName, + sslUser.data(), static_cast<int>(sslUser.size())); + + if (status == -1) + { + return true; + } + + size_t lastChar = sslUser.find('\0'); + if (lastChar == std::string::npos || lastChar == 0) + { + return true; + } + sslUser.resize(lastChar - 1); + + session = + persistent_data::SessionStore::getInstance() + .generateUserSession( + sslUser, + crow::persistent_data::PersistenceType::TIMEOUT); + + return true; + }); +#endif // BMCWEB_ENABLE_MUTUAL_TLS_AUTHENTICATION + #ifdef BMCWEB_ENABLE_DEBUG connectionCount++; BMCWEB_LOG_DEBUG << this << " Connection open, total " @@ -344,6 +479,16 @@ class Connection req->middlewareContext = static_cast<void*>(&ctx); req->ioService = static_cast<decltype(req->ioService)>( &adaptor.get_executor().context()); + +#ifdef BMCWEB_ENABLE_MUTUAL_TLS_AUTHENTICATION + if (auto sp = session.lock()) + { + BMCWEB_LOG_DEBUG << "TLS session: " << sp->uniqueId + << " will be used for this request."; + req->session = sp; + } +#endif // BMCWEB_ENABLE_MUTUAL_TLS_AUTHENTICATION + detail::middlewareCallHelper< 0U, decltype(ctx), decltype(*middlewares), Middlewares...>( *middlewares, *req, res, ctx); @@ -391,12 +536,18 @@ class Connection } void close() { - if constexpr (std::is_same_v<Adaptor, boost::beast::ssl_stream< boost::asio::ip::tcp::socket>>) { adaptor.next_layer().close(); +#ifdef BMCWEB_ENABLE_MUTUAL_TLS_AUTHENTICATION + if (auto sp = session.lock()) + { + BMCWEB_LOG_DEBUG << "Removing TLS session: " << sp->uniqueId; + persistent_data::SessionStore::getInstance().removeSession(sp); + } +#endif // BMCWEB_ENABLE_MUTUAL_TLS_AUTHENTICATION } else { @@ -652,6 +803,9 @@ class Connection std::optional<crow::Request> req; crow::Response res; +#ifdef BMCWEB_ENABLE_MUTUAL_TLS_AUTHENTICATION + std::weak_ptr<crow::persistent_data::UserSession> session; +#endif // BMCWEB_ENABLE_MUTUAL_TLS_AUTHENTICATION const std::string& serverName; |