CVE-2025-52556
rfc3161-client fails to verify TSR signature, allowing attacker to introduce TSR signature.
- CVSS 9.3
- CWE-347
- Cryptographic
- Remote
rfc3161-client is a Python library implementing the Time-Stamp Protocol (TSP) described in RFC 3161. Prior to version 1.0.3, there is a flaw in the timestamp response signature verification logic. In particular, chain verification is performed against the TSR's embedded certificates up to the trusted root(s), but fails to verify the TSR's own signature against the timestamping leaf certificates. Consequently, vulnerable versions perform insufficient signature validation to properly consider a TSR verified, as the attacker can introduce any TSR signature so long as the embedded leaf chains up to some root TSA. This issue has been patched in version 1.0.3. There is no workaround for this issue.
- CWE
- CWE-347
- CVSS base score
- 9.3
- Published
- 2025-06-21
- OWASP
- A09 Security Misconfiguration
- Orthogonal defect classification
- Interface
- Code defect classification
- Incorrect Functionality
- Category
- Cryptographic
- Subcategory
- Cryptographic Implementation Error
- Accessibility scope
- Remote
- Impact
- Unauthorized Access
- Affected component
- rfc3161-clie
- Fixed by upgrading
- Yes
Solution
Upgrade to version 1.0.3.
Vulnerable code sample
import OpenSSL.crypto
import requests
from rfc3161 import TimeStampRequest, TimeStampResponse
def insecure_verify_tsr(tsr_bytes, trusted_certs):
# VULNERABLE: This code is susceptible to crypto weakness
"""
Vulnerable TSR verification logic. This mimics the insufficient validation
present in rfc3161 < 1.0.3. It validates the certificate chain but NOT the
TSR's signature against the timestamping leaf certificate itself.
Args:
tsr_bytes: The TimeStampResponse (TSR) in bytes.
trusted_certs: A list of trusted root certificates (OpenSSL.crypto.X509 objects).
Returns:
True if the TSR appears valid (chain is valid), False otherwise.:
THIS DOES NOT GUARANTEE THE TSR IS ACTUALLY VALID.
"""
tsr = TimeStampResponse(tsr_bytes)
try:
cert = tsr.get_tsa_certificate()
intermediate_certs = tsr.get_intermediate_certificates()
store = OpenSSL.crypto.X509Store()
for trusted_cert in trusted_certs:
store.add_cert(trusted_cert)
for intermediate_cert in intermediate_certs:
store.add_cert(intermediate_cert)
store_ctx = OpenSSL.crypto.X509StoreContext(store, cert)
store_ctx.verify_certificate() # Verify the chain up to the root
# INSECURE: Missing verification of the TSR's signature against the leaf cert
return True # Chain verification passed, but TSR signature not verified
except OpenSSL.crypto.X509StoreContextError as e:
print(f"Chain verification failed: {e}")
return False
except Exception as e:
print(f"Error during verification: {e}")
return False
def main():
# Dummy trusted root certificate (replace with your actual trusted TSA root)
# This is a placeholder. In a real scenario, this should be a trusted root.
trusted_cert_pem = b"""-----BEGIN CERTIFICATE-----
MIIDZTCCAk2gAwIBAgIJAK9JkiHw9q9bMA0GCSqGSIb3DQEBCwUAMDwxCzAJBgNV
BAYTAlVTMREwDwYDVQQKEwhFeGFtcGxlIENBMRIwEAYDVQQDEwlFeGFtcGxlIENB
MB4XDTI0MDYxMjIyNDgyNVoXDTI1MDYxMjIyNDgyNVowPDELMAkGA1UEBhMCVVMx
ETAPBgNVBAoTCEV4YW1wbGUgQ0ExEjAQBgNVBAMTCUV4YW1wbGUgQ0EwggEiMA0G
CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC+bWp/9u9248y/n88p2rS9QpQ2/nU+
6o1gG42vU0+mHh21i1Xm6Vb+uQG7x4nN9/e9U+n3/v/1H949i8/489a8/r9698/
4+v+98/r9+v8/3v/9/v/9+v/9/v/9+v8/3v/9/v/9+v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/
3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/
9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8/3v/9/v/9+v8Patched code sample
import hashlib
from cryptography import x509
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.backends import default_backend
def verify_tsr_signature(tsr_bytes, tsa_cert_bytes):
# SECURE: This version prevents crypto weakness
"""
Verifies the Time Stamp Response (TSR) signature against the TSA certificate.
Args:
tsr_bytes (bytes): The raw bytes of the Time Stamp Response (TSR).
tsa_cert_bytes (bytes): The raw bytes of the trusted TSA certificate.
Returns:
bool: True if the signature is valid, False otherwise.
"""
try:
from asn1crypto import tsp
# Parse the TSR using asn1crypto
tsr = tsp.TimeStampResp.load(tsr_bytes)
status = tsr['status']
status_code = status['statusString'][0].native if 'statusString' in status else 'Unknown Status'
if status['status'].native != 'granted':
print(f"TSR status indicates failure: {status_code}")
return False
# Extract the TimeStampToken
timestamp_token = tsr['timeStampToken']
# Verify the TimeStampToken's content type
if timestamp_token['content_type'].native != 'signed-data':
print("Invalid TimeStampToken content type.")
return False
# Extract the signed data
signed_data = timestamp_token['content']
# Extract the encap_content_info
encap_content_info = signed_data['encap_content_info']
# Extract the message_imprint (the hash of the original data)
message_imprint = encap_content_info['e_content']
# Extract the SignerInfo structure. We assume there is only one signer.
signer_info = signed_data['signer_infos'][0]
# Extract the signature_value
signature_value = signer_info['signature'].native
# Find the corresponding certificate from the certificates within the signed data.
certificates = signed_data['certificates']
# Get the issuer_serial from the signer_info
issuer_serial = signer_info['issuer_and_serial_number']
found_cert = None
for cert in certificates:
if cert['tbs_certificate']['issuer'].native == issuer_serial['issuer'].native and \
cert['tbs_certificate']['serial_number'].native == issuer_serial['serial_number'].native:
found_cert = cert
break
if found_cert is None:
print("No matching certificate found in TSR's certificate list.")
return False
# Convert asn1crypto certificate to cryptography certificate.
cert_bytes = found_cert.dump()
cert = x509.load_der_certificate(cert_bytes, default_backend())
# Prepare the data to be verified. This is the "tbs_certificate" (to be signed) portion.
tbs_content = signed_data['encap_content_info'].dump() # This should be the correct TBS content
# Verify the signature
public_key = cert.public_key()
algorithm = signer_info['signature_algorithm']['algorithm'].native
if algorithm == 'rsassa_pkcs1v15':
public_key.verify(
signature_value,
tbs_content,
padding.PKCS1v15(),
hashes.SHA256()
)
elif algorithm == 'ecdsa':
public_key.verify(
signature_value,
tbs_content,
ec.ECDSA(hashes.SHA256()) # Requires from cryptography.hazmat.primitives import hashes, ec
)
else:
print(f"Unsupported signature algorithm: {algorithm}")
return False
return True
except Exception as e:
print(f"Error verifying TSR signature: {e}")
return FalsePayload
# This is a conceptual example. Crafting a real exploit requires deep understanding
# of the rfc3161 protocol, ASN.1 encoding, and X.509 certificates. This is NOT
# a ready-to-use exploit. It only illustrates the concept.
# In a real exploit, this would be a crafted TimeStampResponse (TSR) blob.
# The important elements are:
# 1. A malicious signature on the TSR, signed by a key you control (attacker_key).
# 2. A certificate chain embedded in the TSR that leads from a fake "leaf" certificate
# (fake_leaf_cert) up to a real, trusted root CA. This exploits the vulnerability
# that the library doesn't properly check the TSR's signature against the leaf.
# The vulnerability lies in the rfc3161 library trusting the certificate chain leading to a root CA,
# without actually verifying the TSR's signature against the leaf certificate in that chain.
# This payload needs to be ASN.1 encoded according to RFC 3161. This is a simplified representation.
# Replace placeholders with actual crafted values.
payload = b"""
-----BEGIN TIME-STAMP RESPONSE-----
{
"status": "granted", # Or other valid status
"status_string": "Operation completed successfully",
"time_stamp_token": {
"version": 1,
"message_imprint": {
"hash_algorithm": "sha256",
"hashed_message": "..." # Hash of the original data being timestamped
},
"serial_number": 12345,
"gen_time": "2024-01-01T00:00:00Z",
"trust_anchor": "...", # Identifier for trusted root CA, needed to trick the validation to complete successfully
"tsa": { # This field contains certificates, where the vulnerable code only check validity chain for the signing CA and *not* the TSR signature itself
"certs": [
fake_leaf_cert.to_der(),
intermediate_ca_cert.to_der(),
# ... potentially more intermediate CAs
],
"signer_info": {
"signature": attacker_signature.to_der(), # MALICIOUS signature, crafted by the attacker
"digest_algorithm": "sha256", # Consistent Hash Alg of attacker signature
"certificate": fake_leaf_cert.to_der() # Certificate, which is used to chain up to the real root CA and to compute the attacker signature
}
}
}
}
-----END TIME-STAMP RESPONSE-----
"""
# Remember to replace the placeholders with real values encoded in ASN.1 DER format.
Cite this entry
@misc{vaitp:cve202552556,
title = {{rfc3161-client fails to verify TSR signature, allowing attacker to introduce TSR signature.
}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2025},
note = {VAITP Python Vulnerability Dataset, entry CVE-2025-52556},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2025-52556/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.
The supreme art of war is to subdue the enemy without fighting.
Sun Tzu – “The Art of War”
:: Shaping the future through research and ingenuity ::
