TL;DR
This guide explains how RSA-PSS signature verification works within the CertificateVerify handshake message of TLS 1.3. It breaks down each step, from hashing to final validation, making it easier to understand this crucial part of secure communication.
Understanding the Process
The CertificateVerify message confirms that the server possesses the private key corresponding to the certificate presented during the handshake. RSA-PSS is a common signature scheme used for this purpose. Here’s how it works:
Step-by-Step Verification Guide
- Hashing the Data: The first step involves hashing the data that needs to be signed. This data includes information about the handshake itself, ensuring integrity.
- The specific hash function used is negotiated during the TLS handshake (e.g., SHA-256).
- The output of this hash function is a fixed-size digest.
- The salt length is determined by the chosen RSA key size (typically 32 bytes).
- The exact format of this construction is defined by the PKCS#1 v2.1 standard for RSA-PSS.
- This encryption process produces the signature, which is a block of data representing the signed message.
- This decoding process extracts relevant components, including the salt used during signing.
- The client also reconstructs the message using the received salt and the original hash digest.
- This decryption should produce a value that matches the reconstructed message from step 6.
- This includes verifying the salt length and other parameters.
- If any step fails, the handshake is terminated as it indicates a potential security breach or compromised key.
Example Code Snippet (Conceptual)
This is a simplified illustration and actual implementations are more complex.
# Assume 'signature' contains the received RSA-PSS signature
# Assume 'public_key' contains the server's public key
# Assume 'handshake_data' contains the original handshake data
try:
# Decode the signature to extract salt and other components
decoded_signature = decode_rsa_pss_signature(signature)
# Re-hash the handshake data
hashed_data = hash_function(handshake_data)
# Reconstruct the message using the received salt and hashed data
reconstructed_message = reconstruct_pss_message(hashed_data, decoded_signature.salt)
# Decrypt the signature with the public key
decrypted_message = decrypt_rsa(signature, public_key)
# Validate the PSS structure
if validate_pss(decrypted_message, reconstructed_message):
print("Signature is valid!")
else:
print("PSS validation failed.")
except Exception as e:
print(f"Signature verification error: {e}")
Important Considerations
- Key Size: Using sufficiently large RSA key sizes (e.g., 2048 bits or higher) is crucial for security.
- Padding Schemes: Always use secure padding schemes like RSA-PSS and avoid older, vulnerable schemes like PKCS#1 v1.5.
- Hash Function Choice: Select a strong hash function (e.g., SHA-256 or SHA-384) that is resistant to collisions.
- Library Usage: Utilize well-vetted cryptography libraries for implementing RSA-PSS signature verification to avoid common pitfalls and vulnerabilities.