Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Intermediate certificates required in CA certificate file #773

Open
emiliosic opened this issue Jan 24, 2025 · 0 comments
Open

Intermediate certificates required in CA certificate file #773

emiliosic opened this issue Jan 24, 2025 · 0 comments

Comments

@emiliosic
Copy link

Testing SIPp back to back using TLS, intermediate certificates are required to be as part of the CA certificate file.
The expectation is that the certificate chain is sent as part of the end-entity certificate. This is the intermediate certificate(s) and the end-entity certificate.
However this always fails unless the intermediate certificate is already include in the CA.

The setup can be recreated as:

  • Create a CA certificate with OpenSSL.
  • With that CA, create two intermediate certificates, let's call them intermediate client and intermediate server.
  • With the client intermediate, sign a certificate request for the UAC certificate.
  • With the server intermediate, sign a certificate request for the UAS certificate.

Run the UAS as:

sipp -sn uas \
-t l1 \
-tls_ca /opt/ca.crt \
-tls_cert /opt/server/tls.crt \
-tls_key /opt/server/tls.key \
-tls_version 1.3 \
-i 172.17.0.3 \
-p 5061

Then run the UAC as:

sipp -sn uac \
-m 10 \
-t l1 \
-tls_ca /opt/ca.crt \
-tls_cert /opt/client/tls.crt \
-tls_key /opt/client/tls.key \
-tls_version 1.3 \
-i 172.17.0.2 \
-p 5061 \
172.17.0.3:5061

In this case, running these in separate containers, but it doesn't matter.

If the CA.crt has only the root CA, as it should, the following errors are seen:
UAS: Error in SSL_accept: SSL protocol error. SSL I/O function returned SSL_ERROR_SSL
UAC: Unable to connect a TCP socket.

running the same with trace, see this on the UAC: verify error:num=20:unable to get local issuer certificate:depth=0

With the same setup, if the intermediate certificate is appended from server/tls.crt into ca.crt, then it works.

The root cause is that OpenSSL is reading only the first certificate passed via tls_cert.
Looking at src/sslsocket.cpp, find that it's using SSL_CTX_use_certificate_file() to read it instead of SSL_CTX_use_certificate_chain_file, which reads the whole PEM file into a STACK_OF(X509) struct.
OpenSSL documents it here: https://docs.openssl.org/master/man3/SSL_CTX_use_certificate/
where under the notes section, states:

SSL_CTX_use_certificate_chain_file() should be used instead of the SSL_CTX_use_certificate_file() function in order to allow the use of complete certificate chains even when no trusted CA storage is used or when the CA issuing the certificate shall not be added to the trusted CA storage.

Hence the proposed patch:

--- original/src/sslsocket.cpp	2024-08-07 08:41:36.000000000 +0000
+++ patched/src/sslsocket.cpp	2025-01-24 03:24:23.960424129 +0000
@@ -352,21 +352,19 @@
     SSL_CTX_set_default_passwd_cb(sip_trp_ssl_ctx_client,
                                   passwd_call_back_routine);

-    if (SSL_CTX_use_certificate_file(sip_trp_ssl_ctx,
-                                     tls_cert_name,
-                                     SSL_FILETYPE_PEM) != 1) {
+    if (SSL_CTX_use_certificate_chain_file(sip_trp_ssl_ctx,
+                                     tls_cert_name) != 1) {
         char errbuf[256] = {'\0'};
         ERR_error_string_n(ERR_get_error(), errbuf, sizeof(errbuf));
-        ERROR("TLS_init_context: SSL_CTX_use_certificate_file failed: %s", errbuf);
+        ERROR("TLS_init_context: SSL_CTX_use_certificate_chain_file failed: %s", errbuf);
         return TLS_INIT_ERROR;
     }

-    if (SSL_CTX_use_certificate_file(sip_trp_ssl_ctx_client,
-                                     tls_cert_name,
-                                     SSL_FILETYPE_PEM) != 1) {
+    if (SSL_CTX_use_certificate_chain_file(sip_trp_ssl_ctx_client,
+                                     tls_cert_name) != 1) {
         char errbuf[256] = {'\0'};
         ERR_error_string_n(ERR_get_error(), errbuf, sizeof(errbuf));
-        ERROR("TLS_init_context: SSL_CTX_use_certificate_file (client) failed: %s", errbuf);
+        ERROR("TLS_init_context: SSL_CTX_use_certificate_chain_file (client) failed: %s", errbuf);
         return TLS_INIT_ERROR;
     }
     if (SSL_CTX_use_PrivateKey_file(sip_trp_ssl_ctx,

This works in my setup.
Note that discovered this in a Kubernetes environment, where cert-manager is used to issue certificates, and intermediate certificates are used.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant