In my question I stated that "there is no information about how to set" trust attributes. This is not correct as man openssl-x509
describes how to set these attributes:
-addtrust arg
Adds a trusted certificate use. Any object name can be used here but currently only clientAuth, serverAuth, emailProtection, and anyExtendedKeyUsage are defined. As of OpenSSL 1.1.0, the last of these blocks all purposes when
rejected or enables all purposes when trusted. Other OpenSSL applications may define additional uses.
To test that openssl s_client
honors an intermediate certificate as trust when validating the server's certificate chain during connection after I've set serverAuth
as a trusted attribute using openssl x509
to the internediate certificate, I did the following:
1.) Start a TLS server
openssl s_server -no-CAfile -no-CApath -no-CAstore -CAfile ./intermediate.cer -cert ./server.cer -key ./server.key -www
./intermediate.cer
is the signing certificate of ./server.cer
.
2.) Validating that openssl s_client
returns with Verify return code: 2 (unable to get issuer certificate)
when "trusting" the intermediate certificate:
$ openssl s_client -no-CApath -no-CAstore -CAfile ./intermediate.cer localhost:4433
CONNECTED(00000004)
Can't use SSL_get_servername
depth=1 C = US, O = Let's Encrypt, CN = R3
verify error:num=2:unable to get issuer certificate
issuer= C = US, O = Internet Security Research Group, CN = ISRG Root X1
verify return:1
depth=0 CN = <<DELETED>>
issuer= C = US, O = Let's Encrypt, CN = R3
verify return:1
---
Certificate chain
0 s:CN = <<DELETED>>
i:C = US, O = Let's Encrypt, CN = R3
a:PKEY: id-ecPublicKey, 256 (bit); sigalg: RSA-SHA256
v:NotBefore: Sep 22 XX:XX:XX 2023 GMT; NotAfter: Dec 21 XX:XX:XX 2023 GMT
1 s:C = US, O = Let's Encrypt, CN = R3
i:C = US, O = Internet Security Research Group, CN = ISRG Root X1
a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
v:NotBefore: Sep 4 00:00:00 2020 GMT; NotAfter: Sep 15 16:00:00 2025 GMT
---
Server certificate
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
subject=CN = <<DELETED>>
issuer=C = US, O = Let's Encrypt, CN = R3
---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: ECDSA
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 2746 bytes and written 377 bytes
Verification error: unable to get issuer certificate
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 256 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 2 (unable to get issuer certificate)
The connection attempt return with Verify return code: 2 (unable to get issuer certificate)
. This is expected as I did not specify -partial_chain
2.) Set trusted attribute
openssl x509 -in ./intermediate.cer -addtrust serverAuth -out ./intermediate-trusted.cer
Check that the trusted attribute has been set:
$ openssl x509 -noout -text -in ./intermediate-trusted.cer
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
91:2b:08:4a:cf:0c:18:a7:53:f6:d6:2e:25:a7:5f:5a
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = US, O = Internet Security Research Group, CN = ISRG Root X1
Validity
Not Before: Sep 4 00:00:00 2020 GMT
Not After : Sep 15 16:00:00 2025 GMT
Subject: C = US, O = Let's Encrypt, CN = R3
...
Trusted Uses:
TLS Web Server Authentication
No Rejected Uses.
4.) Connecting again using ./intermediate-trusted.cer
openssl s_client -no-CApath -no-CAstore -CAfile ./intermediate-trusted.cer localhost:4433
CONNECTED(00000004)
Can't use SSL_get_servername
depth=0 CN = <<DELETED>>
verify return:1
---
Certificate chain
0 s:CN = <<DELETED>>
i:C = US, O = Let's Encrypt, CN = R3
a:PKEY: id-ecPublicKey, 256 (bit); sigalg: RSA-SHA256
v:NotBefore: Sep 22 XX:XX:XX 2023 GMT; NotAfter: Dec 21 XX:XX:XX 2023 GMT
1 s:C = US, O = Let's Encrypt, CN = R3
i:C = US, O = Internet Security Research Group, CN = ISRG Root X1
a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
v:NotBefore: Sep 4 00:00:00 2020 GMT; NotAfter: Sep 15 16:00:00 2025 GMT
---
Server certificate
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
subject=CN = <<DELETED>>
issuer=C = US, O = Let's Encrypt, CN = R3
---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: ECDSA
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 2748 bytes and written 377 bytes
Verification: OK
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 256 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
This time openssl s_client
returns with Verify return code: 0 (ok)
which as far as I know indicates a successful handshake including vadliation of the certificate chain to a trust anchor. The trusted certificate is not a self-signed (i.e. not a root) certificate.