I' following along the book "Realworld Cryptography", in chapter 9 where the TLS protocol is introduced, they mention:

Following [authentication], the server can use its certified long-term key pair to sign all handshake messages that have been received and previously sent in what is called a CertificateVerify message. [...] The signature in the CertificateVerify message proves to the client what the server has seen so far. [...] Take a few moments to understand why an attacker cannot replace the server's ephemeral public key in the presence of the CertificateVerify message.

I looked up some more documentation and found this description of what CertificateVerify does:

The Certificate Verify message is how the server proves ownership of the certificate's private key without revealing the private key itself: the entire handshake up to this point is hashed, and that hash is signed using the private key. The client can then compute the same hash and verify the signature using the public key.

From what I understand:

  • The client and the server keep a "list" of TLS handshake messages they exchanged.
  • The authentication part of TLS happens (for sake of simplicity, say only one-sided.)
  • The server computes a hash of the exchanged handshake messages, signs that hash with its long-term private key. Sends the hash back to the client in a CertificateVerify message.
  • Client has the pub key of the server. Uses this to verify the signature of CertificateVerify.

But if we assume that really a MITM attacker replaced the servers ephemeral pub key, then they could also replace the CertificateVerify message?


2 Answers 2


The adversary could modify or replace the CertificateVerify message, but the digital signature that forms part of the message would not pass the validation process unless either:

  • the adversary was either able to forge signatures associated with the server's public key or
  • if they were able to have the client associate a different public key with the server.

Unforgeability is a property that we hope is built into all digital signature schemes, which should block the first bullet. The second bullet is defended against because the server's public signing key should be the subject of long term validation certificate that has the server's public key signed by a chain of trust of Certifying Authorities anchored in a signature by a root Certifying Authority whose public key is distributed as part of the validating software (such as a browser or operating system). Only if the adversary can subvert this chain of trust can they get a client to accept an alternative public key for the server.

  • 2
    $\begingroup$ I think I see ... the client can verify that the pub key it received from the server is really associated with the server by verifying the pub key is signed by a trusted CA. This verification already happens before CertificateVerify. Now if the MITM replaces the CertificateVerify, they can only sign it with the MITM's key pair, but validation would fail bc. client validates the signature using the trusted server's pub key. (Unless the MITM forges the servers key, as you mentioned.) $\endgroup$
    – BMBM
    Jul 17, 2022 at 8:02

The answer is very simple actually and I will provide a simple explanation for the moment because of lack of time, but if you like I can dive deeper into the details, but I think you can find them by yourself.

Take Wikipedia's certificate for example (it has expired actually but we want it for demonstration purposes only) from here. Beware that this isn't the actual form that the certificate is sent, this is a more abstract notation of ASN.1 format. The certificate is represented in ASN.1 syntax and then the X.690 standard is used for converting to BER, CER, DER formats, which are the formats of the actual certificates.

        Version: 3 (0x2)
        Serial Number:
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = US, O = Let's Encrypt, CN = R3
            Not Before: Jul 15 08:01:49 2021 GMT
            Not After : Oct 13 08:01:48 2021 GMT
        Subject: CN = *.wikipedia.org
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                ASN1 OID: prime256v1
                NIST CURVE: P-256
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature
            X509v3 Extended Key Usage:
                TLS Web Server Authentication, TLS Web Client Authentication
            X509v3 Basic Constraints: critical
            X509v3 Subject Key Identifier:
            X509v3 Authority Key Identifier:

            Authority Information Access:
                OCSP - URI:http://r3.o.lencr.org
                CA Issuers - URI:http://r3.i.lencr.org/

            X509v3 Subject Alternative Name:
                DNS:*.m.mediawiki.org, DNS:*.m.wikibooks.org, DNS:*.m.wikidata.org, DNS:*.m.wikimedia.org, DNS:*.m.wikinews.org, DNS:*.m.wikipedia.org, DNS:*.m.wikiquote.org, DNS:*.m.wikisource.org, DNS:*.m.wikiversity.org, DNS:*.m.wikivoyage.org, DNS:*.m.wiktionary.org, DNS:*.mediawiki.org, DNS:*.planet.wikimedia.org, DNS:*.wikibooks.org, DNS:*.wikidata.org, DNS:*.wikimedia.org, DNS:*.wikimediafoundation.org, DNS:*.wikinews.org, DNS:*.wikipedia.org, DNS:*.wikiquote.org, DNS:*.wikisource.org, DNS:*.wikiversity.org, DNS:*.wikivoyage.org, DNS:*.wiktionary.org, DNS:*.wmfusercontent.org, DNS:mediawiki.org, DNS:w.wiki, DNS:wikibooks.org, DNS:wikidata.org, DNS:wikimedia.org, DNS:wikimediafoundation.org, DNS:wikinews.org, DNS:wikipedia.org, DNS:wikiquote.org, DNS:wikisource.org, DNS:wikiversity.org, DNS:wikivoyage.org, DNS:wiktionary.org, DNS:wmfusercontent.org
            X509v3 Certificate Policies:
                  CPS: http://cps.letsencrypt.org

            CT Precertificate SCTs:
                Signed Certificate Timestamp:
                    Version   : v1 (0x0)
                    Log ID    : F6:5C:94:2F:D1:77:30:22:14:54:18:08:30:94:56:8E:
                    Timestamp : Jul 15 09:01:49.274 2021 GMT
                    Extensions: none
                    Signature : ecdsa-with-SHA256
                Signed Certificate Timestamp:
                    Version   : v1 (0x0)
                    Log ID    : 6F:53:76:AC:31:F0:31:19:D8:99:00:A4:51:15:FF:77:
                    Timestamp : Jul 15 09:01:50.105 2021 GMT
                    Extensions: none
                    Signature : ecdsa-with-SHA256
    Signature Algorithm: sha256WithRSAEncryption

When you submit a request for certificate to a Certificate authority you provide all the fields such as Subject and Subject Public Key Info. As you can see inside Subject Public Key Info there exists the public key (a P-256 point) of the subject who makes the signing request. The whole file is hashed and then signed with Let's Encrypt RSA key. The signature is contained at the bottom of the certificate. It is the RSA signature of the SHA256 hash of the CA.

When someone visits *.wikipedia.org or the other domain names in the TLS handshake he receives this certificate in the Certificate message of the handshake send by the server. In order to check the validity of the certificate he must fetch the corresponding RSA key with which the certificate was signed and check the validity of the signature after hashing the certificate except for the last part of it which is the signature.

But if we assume that really a MITM attacker replaced the servers ephemeral pub key, then they could also replace the CertificateVerify message?

Here comes Certificate Verify into play. Because the certificate is public (in TLS1.2 it is sent unencrypted but in TLS1.3 as mentioned in the comments it isn't sent in plain format, it is actually send encrypted with the preestablished master secret and the agreed symmetric algorithm and mode) because anyone can initiate a connection to *.wikipedia.org and get the certificate and try to impersonate *.wikipedia.org up to prior CertificateVerify message. Now in the Certificate Verify message the server signs a hash of the whole handshake up to this point, more specifically the content of the hash is calculated as follows :

Transcript-Hash(Handshake Context, Certificate)


Transcript-Hash(M1, M2, ... Mn) = Hash(M1 || M2 || ... || Mn) 

and sends it to the client. Then the client for verification can simply compute the same hash of the handshake messages up to this point and and verify the signature if it matches with the public key that the CA signed in the certificate. Now the client can verify that the one that send the certificate is actually holding the corresponding private key of the public key that was singed in the certificate.

Even, if the MITM attacker replaced the ephemeral or the long term public key of the server, he cannot forge the signature provided for another public key by the CA. Now the only attack vector of the attacker is to make the CA sign his own public key for a domain he doesn't own (e.g. *.wikipedia.org) which cannot happen because before CA signs your certificate you have to prove that you own this domain.

  • 2
    $\begingroup$ Actually in TLS1.3 the cert (and signature) is sent after key agreement, and is encrypted thereby (it wasn't in 1.2 and below). But the cert is validated and the signature verified before the connection is considered usable. Also ECDSA signature is not verified by 'match[ing]' the hash. $\endgroup$ Jul 17, 2022 at 2:19
  • $\begingroup$ I will update my answer with complete details when I have time. $\endgroup$
    – tur11ng
    Jul 17, 2022 at 10:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.