From 6b50f5bf1005c0a361fa584b75d677c6ca5a3c84 Mon Sep 17 00:00:00 2001 From: Pervakov Grigorii Date: Wed, 20 Mar 2024 19:27:33 +0000 Subject: [PATCH 1/3] Reload certificate chain during certificate reload --- src/Server/CertificateReloader.cpp | 20 +++++++-- src/Server/CertificateReloader.h | 2 +- .../configs/WithChain.crt | 43 +++++++++++++++++++ .../configs/WithChain.key | 27 ++++++++++++ .../test_reload_certificate/test.py | 15 +++++++ 5 files changed, 103 insertions(+), 4 deletions(-) create mode 100644 tests/integration/test_reload_certificate/configs/WithChain.crt create mode 100644 tests/integration/test_reload_certificate/configs/WithChain.key diff --git a/src/Server/CertificateReloader.cpp b/src/Server/CertificateReloader.cpp index c974f450c9a..c93ef380665 100644 --- a/src/Server/CertificateReloader.cpp +++ b/src/Server/CertificateReloader.cpp @@ -30,8 +30,22 @@ int CertificateReloader::setCertificate(SSL * ssl) if (!current) return -1; - SSL_use_certificate(ssl, const_cast(current->cert.certificate())); - SSL_use_PrivateKey(ssl, const_cast(static_cast(current->key))); + if (current->certs_chain.size() < 1) + return -1; + + int ret; + ret = SSL_clear_chain_certs(ssl); + if (!ret) + return ret; + ret = SSL_use_certificate(ssl, const_cast(current->certs_chain[0].certificate())); + if (!ret) + return ret; + for (auto cert = current->certs_chain.begin() + 1; cert != current->certs_chain.end(); cert++) { + ret = SSL_add1_chain_cert(ssl, const_cast(cert->certificate())); + if (!ret) + return ret; + } + ret = SSL_use_PrivateKey(ssl, const_cast(static_cast(current->key))); int err = SSL_check_private_key(ssl); if (err != 1) @@ -100,7 +114,7 @@ void CertificateReloader::tryLoad(const Poco::Util::AbstractConfiguration & conf CertificateReloader::Data::Data(std::string cert_path, std::string key_path, std::string pass_phrase) - : cert(cert_path), key(/* public key */ "", /* private key */ key_path, pass_phrase) + : certs_chain(Poco::Crypto::X509Certificate::readPEM(cert_path)), key(/* public key */ "", /* private key */ key_path, pass_phrase) { } diff --git a/src/Server/CertificateReloader.h b/src/Server/CertificateReloader.h index 028914e682f..5ab799037d5 100644 --- a/src/Server/CertificateReloader.h +++ b/src/Server/CertificateReloader.h @@ -70,7 +70,7 @@ private: struct Data { - Poco::Crypto::X509Certificate cert; + Poco::Crypto::X509Certificate::List certs_chain; Poco::Crypto::EVPPKey key; Data(std::string cert_path, std::string key_path, std::string pass_phrase); diff --git a/tests/integration/test_reload_certificate/configs/WithChain.crt b/tests/integration/test_reload_certificate/configs/WithChain.crt new file mode 100644 index 00000000000..c75ee533f26 --- /dev/null +++ b/tests/integration/test_reload_certificate/configs/WithChain.crt @@ -0,0 +1,43 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIUSChEeHqJus9jzKmD/L3Tw0x4OwcwDQYJKoZIhvcNAQEL +BQAwQTEaMBgGA1UEAwwRZGVtby5tbG9wc2h1Yi5jb20xCzAJBgNVBAYTAlVTMRYw +FAYDVQQHDA1TYW4gRnJhbnNpc2NvMCAXDTI0MDMyMDE5MTE1OVoYDzIxMjQwMjI1 +MTkxMTU5WjBxMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQG +A1UEBwwNU2FuIEZyYW5zaXNjbzEPMA0GA1UECgwGRm9vQmFyMRAwDgYDVQQLDAdG +b28gQmFyMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQDM//0s6AX988J86HzxX95irGa9cJIfY24UDBXVkO3gREiwj1Uf +bpvpxCcwADMuFdggsJlppWa3q+PNJ/eoVwdl3gG0WXaZp1rcuv6ltxdQAUtgfMAb +5p7HwsO7rCTGJBwa62Jg+E79j+V8rZWfaJRfNtY0p7eauWIrqLA0Gyse+lRayPHI +hsR9+0qedF+qziFpbNxpW8DHrpIrLb8LEao1BCYQ44koBXjkrXeR6OidXw/gek8+ +9M2GLxy6ubQ7hrcYwVWpFOKLLZLmyYDgescM6AIU904o1bN0yJ5rM7a1+f150qp6 +ttZlya0sJH0lm3gzEsqb6Fbh+Dw/9Lsp66sDAgMBAAGjUTBPMB8GA1UdIwQYMBaA +FMjyDUyXujACeQa2G+4I8ic5HVBiMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgTwMBQG +A1UdEQQNMAuCCWxvY2FsaG9zdDANBgkqhkiG9w0BAQsFAAOCAQEABEWEaVDqv9Za +bFpD/JEMIFVqe5ANKAnbbff0/vFJQ7yFmsL8/G4bbdd8uidRgE4WgoeNUscCnfk+ +kjb1vFjvY4/cBYITn41Pz5I7lQMH+BaR5gHb1oJVlJavQ2vsaeMuyDJaNmumejmU +YnoKZRwwb6SCXujS2MKgKl+jL5OkZk60i+nJhIXfxwMNmlvtqADSU5Z3VMagq8hj +DnEsxTz8PptuVaLVT4kcZm9gZpDEW2KPMZhNCv/g7EzQv8r3WnFGqumMGBO82ZE0 +mUh/Chrhss/meVK0FqTTBjOlex7R0GiJBCDfZGYTWIVdND4ICdZ1OpGWid5CXbfQ +sWBrbBaEyw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDYzCCAkugAwIBAgIUR0PldYYSk3DAifgb600kvqjaCAIwDQYJKoZIhvcNAQEL +BQAwQTEaMBgGA1UEAwwRZGVtby5tbG9wc2h1Yi5jb20xCzAJBgNVBAYTAlVTMRYw +FAYDVQQHDA1TYW4gRnJhbnNpc2NvMB4XDTI0MDMyMDE5MTEzMVoXDTI1MDMxMTE5 +MTEzMVowQTEaMBgGA1UEAwwRZGVtby5tbG9wc2h1Yi5jb20xCzAJBgNVBAYTAlVT +MRYwFAYDVQQHDA1TYW4gRnJhbnNpc2NvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAqL3k6Pexu1KR8fc84fRmu0hYon7+xOPmtFSzspeN+DJNe5oDO6x0 +RzTQkgtDoxTcq32O290r3uURnDmnvNubz5yTpM1Zcz/kuSNpHLJh4yyZsXRsB21v +lb3bhjqyn6rkfoQzIMekt7clPQS0dWdU2T+lwn6XBVShOyB/W7ysP309ofQGXV+T +VFyU+lgZc2WjK6611QDCpTXgRc/UKUfU5460BnTCylP6jzBOWBZb8FX6dYBzS4U2 +yISvOXagxJVruoWjscc35ln6HBQ8bu/fI8Q0n1/ROlm785Bsd/LpVw465kklwQwS +FY3FQkiedD1fyszXO4Yq5PARw54AGKbAyQIDAQABo1MwUTAdBgNVHQ4EFgQUyPIN +TJe6MAJ5BrYb7gjyJzkdUGIwHwYDVR0jBBgwFoAUyPINTJe6MAJ5BrYb7gjyJzkd +UGIwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAYyl27sxwrjz5 +qcqwbLYv2eFIR6VZzvHfknSK1ht1jzMkXxvAOjETbYwqwWquWwMHOD2X4q5d57nu +qYAE9YE27HFzknPQkDdzwJ0u4dKi28PK8tM6dqDK46LSal/MEUxXGuzW3TRyJXrl +lPi+Wh6gZRRiANJ+giEwvQ+8k6eURHrhtL7yZqT+swi+jP4h6S4mmHmsaOj4VoP/ +NCFoRZud5SCd7RZV+fzNfxhLHI9I2c2gFycBDZOEdlrIZHM6EoaDb3i9kDVbnZqG +Zj/+k/NwCKg5UiDap6Z7Xj7w0chSppg3DMcsxGeQ9vQcMtydNu5fSK4CozNqxObb +hGBJrQylAw== +-----END CERTIFICATE----- diff --git a/tests/integration/test_reload_certificate/configs/WithChain.key b/tests/integration/test_reload_certificate/configs/WithChain.key new file mode 100644 index 00000000000..eb55458b143 --- /dev/null +++ b/tests/integration/test_reload_certificate/configs/WithChain.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEAzP/9LOgF/fPCfOh88V/eYqxmvXCSH2NuFAwV1ZDt4ERIsI9V +H26b6cQnMAAzLhXYILCZaaVmt6vjzSf3qFcHZd4BtFl2mada3Lr+pbcXUAFLYHzA +G+aex8LDu6wkxiQcGutiYPhO/Y/lfK2Vn2iUXzbWNKe3mrliK6iwNBsrHvpUWsjx +yIbEfftKnnRfqs4haWzcaVvAx66SKy2/CxGqNQQmEOOJKAV45K13kejonV8P4HpP +PvTNhi8curm0O4a3GMFVqRTiiy2S5smA4HrHDOgCFPdOKNWzdMieazO2tfn9edKq +erbWZcmtLCR9JZt4MxLKm+hW4fg8P/S7KeurAwIDAQABAoIBAQDIT6LtzFJ+kT+L +mgjsOocs19UUavj9XsTjJeP36UPnDhIRJB1DN2t2Astf5fIcqA+l8aoWRx6Vfop7 +nwAqJ8/8w+/acEipX5Qzdyz4dG19Kaajw4JcQP8JptBng4/zZLlpvHNG2ZslvQO6 +zksTlrbUStsIXJHVyCubCZwTbjC2dJlc97705DZAk/8L7FkljmyJws2xwQZlxdQG +FZ+8IrAqpWJC55EPfKo6+QsKEc9hh4N/MQW483V5yCuw9dLShcEMDGuxcHGFHif8 +BrwImih0rIwj9tTDY9pw6aJ5+80tVStNLDk+1eQRME6Fy/c7RG/sm/lj+P0YOI7F +jH4wyXVRAoGBAOc+rFNpM/CgRZD4VXQ+gV1+PLdaqUUU3UXAPfNWkrMIr0u4+tmg +OMMkXaM7B/ps7o5+Rcj+tO1VAvl6m7uM376szC3Ex8JA0XBDmJrJKfEQCHkzvkdf +wywVBeAR4f3D2+9Meh1XSNRqGU+Anb48neTyVYzPNIoK8ZmtZID49GfVAoGBAOLy +EX1TT1xwE/VwDy5BeJQzyZ+xwevie/960RIYooLeb31NLhOcX142b8U7XRMtiqdd +wfsT5SbjnrATBponKZELO7LwE+Z4djo2+O6JZjYB5/t/Z6r7qfOaTTlJEl8VJKo4 +F+qAsqKo0Q9EpkRUeNdcOjDzkuEikw9IlhS0VEt3AoGAWLHoRQH4AxZmOGmX1UNY +OTT/MtCaVj3fdS58VIZjNDpjiibESI601txu8fnlYH9BrPPv7l0LpnBR+MC3VON+ +ulLq6a8tc2uLKYUz1kLMTIL6zQo0tImdgZ36p+wUA1KJXCq4N+LPs3GSjbTmTB5R +7Yuplp2vKDd0XZ5tCy7yB5UCgYEA3ppoE1DTSC1bNmSLT2jCuEOv4ic+unw1+lti +lWh6hvldzD8XEf9RAB1PNtvKqNQD67SoX/mczK956OVQlYYSXIXzMcoRCwBfnyxq +sbct/Y2TGXpXmjwt8JcKZkVJcuBPTXOl6cwA7FHAdkR0/hMJUNzS608PZCtAqj4d +kANtp3MCgYEA3plv6RYYDZsUdJmIcdIvr/LxWTSqYf37LQM//k+OXo+zWMxgnUNv +AEqDlNWP+bw3yJlU1bQS2o1Z+hKzDgqDZtaVVVDgdVsUaDSW0EsJpedWXoGqJdrw +yxhB7RYi1tQsXHbR1iyT5hH0ZlV7s0XIKRU4U8MP05av099+++YKhks= +-----END RSA PRIVATE KEY----- diff --git a/tests/integration/test_reload_certificate/test.py b/tests/integration/test_reload_certificate/test.py index 1718e440629..86140c83dfd 100644 --- a/tests/integration/test_reload_certificate/test.py +++ b/tests/integration/test_reload_certificate/test.py @@ -13,6 +13,8 @@ node = cluster.add_instance( "configs/second.key", "configs/ECcert.crt", "configs/ECcert.key", + "configs/WithChain.crt", + "configs/WithChain.key", "configs/WithPassPhrase.crt", "configs/WithPassPhrase.key", "configs/cert.xml", @@ -158,3 +160,16 @@ def test_cert_with_pass_phrase(): check_certificate_switch( "first", "WithPassPhrase", pass_phrase_second=pass_phrase_for_cert ) + + +def test_chain_reload(): + """Check cert chain reload""" + check_certificate_switch("first", "WithChain") + assert ( + node.exec_in_container([ + "bash", + "-c", + "openssl s_client -showcerts -servername localhost -connect localhost:8443 /dev/null | grep 'BEGIN CERTIFICATE' | wc -l", + ]) + == "2\n" + ) From 570dc32b077994e31257fc3b99cfd0f1bf4287bc Mon Sep 17 00:00:00 2001 From: Pervakov Grigorii Date: Thu, 21 Mar 2024 08:58:20 +0000 Subject: [PATCH 2/3] fix style --- src/Server/CertificateReloader.cpp | 47 ++++++++++--------- .../test_reload_certificate/test.py | 12 +++-- 2 files changed, 33 insertions(+), 26 deletions(-) diff --git a/src/Server/CertificateReloader.cpp b/src/Server/CertificateReloader.cpp index c93ef380665..c01e1fc9808 100644 --- a/src/Server/CertificateReloader.cpp +++ b/src/Server/CertificateReloader.cpp @@ -22,7 +22,6 @@ int callSetCertificate(SSL * ssl, [[maybe_unused]] void * arg) } - /// This is callback for OpenSSL. It will be called on every connection to obtain a certificate and private key. int CertificateReloader::setCertificate(SSL * ssl) { @@ -30,31 +29,37 @@ int CertificateReloader::setCertificate(SSL * ssl) if (!current) return -1; - if (current->certs_chain.size() < 1) + if (current->certs_chain.empty()) return -1; - int ret; - ret = SSL_clear_chain_certs(ssl); - if (!ret) - return ret; - ret = SSL_use_certificate(ssl, const_cast(current->certs_chain[0].certificate())); - if (!ret) - return ret; - for (auto cert = current->certs_chain.begin() + 1; cert != current->certs_chain.end(); cert++) { - ret = SSL_add1_chain_cert(ssl, const_cast(cert->certificate())); - if (!ret) - return ret; - } - ret = SSL_use_PrivateKey(ssl, const_cast(static_cast(current->key))); - - int err = SSL_check_private_key(ssl); - if (err != 1) + if (auto err = SSL_clear_chain_certs(ssl)) { - std::string msg = Poco::Net::Utility::getLastError(); - LOG_ERROR(log, "Unusable key-pair {}", msg); + LOG_ERROR(log, "Clear certificates {}", Poco::Net::Utility::getLastError()); + return -1; + } + if (auto err = SSL_use_certificate(ssl, const_cast(current->certs_chain[0].certificate()))) + { + LOG_ERROR(log, "Use certificate {}", Poco::Net::Utility::getLastError()); + return -1; + } + for (auto cert = current->certs_chain.begin() + 1; cert != current->certs_chain.end(); cert++) + { + if (auto err = SSL_add1_chain_cert(ssl, const_cast(cert->certificate()))) + { + LOG_ERROR(log, "Add certificate to chain {}", Poco::Net::Utility::getLastError()); + return -1; + } + } + if (auto err = SSL_use_PrivateKey(ssl, const_cast(static_cast(current->key)))) + { + LOG_ERROR(log, "Use private key {}", Poco::Net::Utility::getLastError()); + return -1; + } + if (auto err = SSL_check_private_key(ssl)) + { + LOG_ERROR(log, "Unusable key-pair {}", Poco::Net::Utility::getLastError()); return -1; } - return 1; } diff --git a/tests/integration/test_reload_certificate/test.py b/tests/integration/test_reload_certificate/test.py index 86140c83dfd..f0efc4e0bbd 100644 --- a/tests/integration/test_reload_certificate/test.py +++ b/tests/integration/test_reload_certificate/test.py @@ -166,10 +166,12 @@ def test_chain_reload(): """Check cert chain reload""" check_certificate_switch("first", "WithChain") assert ( - node.exec_in_container([ - "bash", - "-c", - "openssl s_client -showcerts -servername localhost -connect localhost:8443 /dev/null | grep 'BEGIN CERTIFICATE' | wc -l", - ]) + node.exec_in_container( + [ + "bash", + "-c", + "openssl s_client -showcerts -servername localhost -connect localhost:8443 /dev/null | grep 'BEGIN CERTIFICATE' | wc -l", + ] + ) == "2\n" ) From a2ad832dfe4aba122cb208e132fa5acc6026e020 Mon Sep 17 00:00:00 2001 From: Pervakov Grigorii Date: Mon, 25 Mar 2024 17:13:30 +0000 Subject: [PATCH 3/3] fix error handling --- src/Server/CertificateReloader.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Server/CertificateReloader.cpp b/src/Server/CertificateReloader.cpp index c01e1fc9808..311ece67bce 100644 --- a/src/Server/CertificateReloader.cpp +++ b/src/Server/CertificateReloader.cpp @@ -32,30 +32,30 @@ int CertificateReloader::setCertificate(SSL * ssl) if (current->certs_chain.empty()) return -1; - if (auto err = SSL_clear_chain_certs(ssl)) + if (auto err = SSL_clear_chain_certs(ssl); err != 1) { LOG_ERROR(log, "Clear certificates {}", Poco::Net::Utility::getLastError()); return -1; } - if (auto err = SSL_use_certificate(ssl, const_cast(current->certs_chain[0].certificate()))) + if (auto err = SSL_use_certificate(ssl, const_cast(current->certs_chain[0].certificate())); err != 1) { LOG_ERROR(log, "Use certificate {}", Poco::Net::Utility::getLastError()); return -1; } for (auto cert = current->certs_chain.begin() + 1; cert != current->certs_chain.end(); cert++) { - if (auto err = SSL_add1_chain_cert(ssl, const_cast(cert->certificate()))) + if (auto err = SSL_add1_chain_cert(ssl, const_cast(cert->certificate())); err != 1) { LOG_ERROR(log, "Add certificate to chain {}", Poco::Net::Utility::getLastError()); return -1; } } - if (auto err = SSL_use_PrivateKey(ssl, const_cast(static_cast(current->key)))) + if (auto err = SSL_use_PrivateKey(ssl, const_cast(static_cast(current->key))); err != 1) { LOG_ERROR(log, "Use private key {}", Poco::Net::Utility::getLastError()); return -1; } - if (auto err = SSL_check_private_key(ssl)) + if (auto err = SSL_check_private_key(ssl); err != 1) { LOG_ERROR(log, "Unusable key-pair {}", Poco::Net::Utility::getLastError()); return -1;