I know in TLS, the client would send a CertificateVerify message for the server to confirm the client’s identity through means such as CA but what if the client never sent this information?
Is it possible for an attacker to use this opportunity to hijack the client’s session through packet sniffing and create it’s own "pre-master secret" to communicate with the server?
I’m looking for an helping hand with my https nginx setup. I require my application to be exposed through an nginx frontend, offloading TLS. Easy !
The thing is, I need to have Certificate-based client authentication, and my application cannot be advertising a list of CAs it accepts as it will disclose information about my clients.
As a result I am building up a solution based on the optional_no_ca parameter of nginx.
Sadly, this workflow is not discussed on the TLS RFC, and I’m willing to confirm that the CertificateVerify is still part of the verifications done by Nginx/OpenSSL .
I’m willing to do my authentication in 2 phases :
1- ClientCertificate & TLS validation – On Nginx ( to avoid replay and certificate forgery )
2- Certificate validity, CAs and CN validation on Application.
This can only be secure if the CertificateVerify is done properly on Nginx side, as it will be impossible for my application to do it, since it’s not terminating TLS itself ( and cannot ).
Would anyone have confirmations ? Or ideas on how to test this without falling down to scappy ?
I’m debugging a TLS v1.3 client program, which always failed to verify the signature in server’s
CertificateVerify, so I’m learning the procedures for verifying a signature in
CertificateVerify handshake message sent from server.
Here’s my understanding after reading RFC8446 and related articles, is there anything wrong or I’m misunderstanding ?
It is mandatory to support signature scheme
rsa_pss_rsae_sha256, RSASSA-PSS algorithm must be used in
To generate RSA signature in
CertificateVerify on server side, one must generate “digital signature”, that is a concatenation of (1) octet
0x20 consecutively repeated 64 times, (2) the context string
TLS 1.3, server CertificateVerify, (3) A single byte
0x00 as the separator (4) the hash output of hankshake messages until server’s
Certificate, in other words :
Transcript-Hash(ClientHello || ServerHello || EncryptedExtension || server Certificate)
(assume the server doesn’t send
rsa_pss_rsae_sha256 is used, then hash the “digital signature” described above with SHA-256.
Encode the hash output of “digital signature” using (1) an PKCS#1 PSS algorithm, (2) salt length (equal to hash output size of
rsa_pss_rsae_sha256 , based on assumption above)
Encrypt the PSS-encoded value above using (1) RSA encryption algorithm (2) RSA private key corresponding to the certificate sent in previous
Certificate handshake message.
The encrypted(signed) value above is the signature of the server’s handshake message
Here’s how the client verifies signature from server’s
CertificateVerify. Is there anything wrong or I’m misunderstanding ?
Generate “digital signature” as described above, the hash output of handshake messages
Transcript-Hash(ClientHello .... server Certificate) is also the same as described above, then hash the “digital signature” according to the chosen signature scheme (assume it’s
Decrypt the signature in the
CertificateVerify using (1) RSA public key extracted from server’s certificate in the previous handshake message
Certificate, (2) RSA encryption algorithm.
Verify the decrypted value in the step above, with the hash output of “digital signature” in the first step, using (1) PKCS#1 PSS decode function, and (2) appropriate salt length (e.g. output size of SHA-256)
Thanks for reading, any suggestion / tip is appreciated.