| Daviid |
24-11-2025 09:39:34 |
Ejemplo Registro de Eventos
Alguien tiene un ejemplo de registro de evento? Firmado y sin firmar?
Creo que tengo uno pero VALIDe me da error, EADTrust también me falla.
Este código me sale todo bien, pero es ChatGPT así que....
Código:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Full XAdES-EPES validation script
# Validates:
# - Canonicalization of SignedInfo
# - Digest of SignedProperties
# - Digest of the enveloped document
# - SignatureValue (RSA-SHA256)
# - Certificate used for signing
# - XAdES EPES requirements: SigningCertificate, SignaturePolicyIdentifier
import base64
import hashlib
import urllib.request
from lxml import etree
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography import x509
XML_FILE = r"firmado.xml"
NS = {
"ds": "http://www.w3.org/2000/09/xmldsig#",
"xades": "http://uri.etsi.org/01903/v1.3.2#",
}
def c14n(node, with_comments=False):
"""Returns canonicalized XML for a node."""
return etree.tostring(
node,
method="c14n",
exclusive=True,
with_comments=with_comments
)
def sha256(data):
return base64.b64encode(hashlib.sha256(data).digest()).decode()
def sha1(data):
return base64.b64encode(hashlib.sha1(data).digest()).decode()
def load_xml():
parser = etree.XMLParser(remove_blank_text=True)
return etree.parse(XML_FILE, parser)
def extract_certificate(cert_b64):
cert_bytes = base64.b64decode(cert_b64)
return x509.load_der_x509_certificate(cert_bytes)
def validate_reference_digest(node, expected_digest):
canon = c14n(node)
digest = sha256(canon)
return digest == expected_digest, digest
def validate_signature_value(public_key, signed_info_c14n, signature_value):
try:
public_key.verify(
signature_value,
signed_info_c14n,
padding.PKCS1v15(),
hashes.SHA256()
)
return True
except Exception:
return False
def main():
print("Loading XML…")
doc = load_xml()
signature = doc.find(".//ds:Signature", NS)
signed_info = signature.find("ds:SignedInfo", NS)
signature_value_el = signature.find("ds:SignatureValue", NS)
key_info = signature.find("ds:KeyInfo/ds:X509Data/ds:X509Certificate", NS)
# Extract certificate
cert_b64 = key_info.text.strip()
cert = extract_certificate(cert_b64)
public_key = cert.public_key()
# Canonicalize SignedInfo
signed_info_c14n = c14n(signed_info)
# Decode SignatureValue
signature_value = base64.b64decode(signature_value_el.text.strip())
print("\n=== Step 1: Validate SignatureValue (RSA-SHA256) ===")
if validate_signature_value(public_key, signed_info_c14n, signature_value):
print("✔ SignatureValue is VALID")
else:
print("✘ SignatureValue is INVALID")
print("\n=== Step 2: Validate each Reference digest ===")
references = signed_info.findall("ds:Reference", NS)
for ref in references:
uri = ref.get("URI")
expected_digest = ref.find("ds:DigestValue", NS).text.strip()
if uri.startswith("#"):
target_id = uri[1:]
target = doc.find(f".//*[@Id='{target_id}']")
else:
# Empty URI => enveloped signing of root element
target = doc.getroot()
# Root must exclude the <Signature> itself (enveloped signature transform)
transforms = ref.find("ds:Transforms", NS)
if transforms is not None:
for t in transforms.findall("ds:Transform", NS):
algo = t.get("Algorithm")
if algo == "http://www.w3.org/2000/09/xmldsig#enveloped-signature":
sig_node = signature
sig_node.getparent().remove(sig_node)
valid, computed_digest = validate_reference_digest(target, expected_digest)
print(f"\nReference URI='{uri}'")
print(f"Expected digest: {expected_digest}")
print(f"Computed digest: {computed_digest}")
print("✔ Digest VALID" if valid else "✘ Digest INVALID")
print("\n=== Step 3: Validate XAdES SignedProperties digest ===")
signed_props_ref = signature.find(
"ds:SignedInfo/ds:Reference[@Type='http://uri.etsi.org/01903#SignedProperties']",
NS
)
if signed_props_ref is not None:
uri = signed_props_ref.get("URI")[1:]
expected_digest = signed_props_ref.find("ds:DigestValue", NS).text.strip()
signed_props = signature.find(
f"ds:Object/xades:QualifyingProperties/xades:SignedProperties[@Id='{uri}']",
NS
)
valid, computed_digest = validate_reference_digest(signed_props, expected_digest)
print(f"Expected: {expected_digest}")
print(f"Computed: {computed_digest}")
print("✔ SignedProperties digest VALID" if valid else "✘ SignedProperties digest INVALID")
print("\n=== Step 4: Validate SigningCertificate digest (XAdES requirement) ===")
signing_cert = signature.find(
"ds:Object/xades:QualifyingProperties/xades:SignedProperties/"
"xades:SignedSignatureProperties/xades:SigningCertificate/"
"xades:Cert/xades:CertDigest/ds:DigestValue",
NS
)
method = signature.find(
"ds:Object/xades:QualifyingProperties/xades:SignedProperties/"
"xades:SignedSignatureProperties/xades:SigningCertificate/"
"xades:Cert/xades:CertDigest/ds:DigestMethod",
NS
).get("Algorithm")
expected_cert_digest = signing_cert.text.strip()
if method == "http://www.w3.org/2000/09/xmldsig#sha1":
computed_cert_digest = sha1(cert.public_bytes(serialization.Encoding.DER))
else:
computed_cert_digest = sha256(cert.public_bytes(serialization.Encoding.DER))
print(f"Expected: {expected_cert_digest}")
print(f"Computed: {computed_cert_digest}")
if expected_cert_digest == computed_cert_digest:
print("✔ SigningCertificate digest VALID")
else:
print("✘ SigningCertificate digest INVALID")
print("\n=== Step 5: Validate XAdES SignaturePolicyHash (EPES) ===")
policy_hash_el = signature.find(
"ds:Object/xades:QualifyingProperties/xades:SignedProperties/"
"xades:SignedSignatureProperties/xades:SignaturePolicyIdentifier/"
"xades:SignaturePolicyId/xades:SigPolicyHash/ds:DigestValue",
NS
)
policy_method = signature.find(
"ds:Object/xades:QualifyingProperties/xades:SignedProperties/"
"xades:SignedSignatureProperties/xades:SignaturePolicyIdentifier/"
"xades:SignaturePolicyId/xades:SigPolicyHash/ds:DigestMethod",
NS
).get("Algorithm")
expected_policy_hash = policy_hash_el.text.strip()
print(f"Policy digest given in XML: {expected_policy_hash}")
print(f"Digest method: {policy_method}")
print("\nValidating policy hash...")
policy_identifier_el = signature.find(
"ds:Object/xades:QualifyingProperties/xades:SignedProperties/"
"xades:SignedSignatureProperties/xades:SignaturePolicyIdentifier/"
"xades:SignaturePolicyId/xades:SigPolicyId/xades:Identifier",
NS
)
if policy_identifier_el is None:
print("✘ No policy identifier found")
else:
policy_identifier = policy_identifier_el.text.strip()
print(f"Policy Identifier: {policy_identifier}")
try:
if policy_identifier.startswith("urn:oid:"):
if policy_identifier == "urn:oid:2.16.724.1.3.1.1.2.1.9":
policy_url = "https://sede.administracion.gob.es/politica_de_firma_anexo_1.pdf"
else:
raise ValueError(f"Unknown OID: {policy_identifier}")
else:
policy_url = policy_identifier
with urllib.request.urlopen(policy_url) as response:
policy_data = response.read()
if policy_method == "http://www.w3.org/2000/09/xmldsig#sha1":
computed_hash = base64.b64encode(hashlib.sha1(policy_data).digest()).decode()
elif policy_method == "http://www.w3.org/2001/04/xmlenc#sha256":
computed_hash = base64.b64encode(hashlib.sha256(policy_data).digest()).decode()
else:
print(f"Unsupported digest method: {policy_method}")
computed_hash = None
if computed_hash:
print(f"Computed policy hash: {computed_hash}")
if computed_hash == expected_policy_hash:
print("✔ Policy hash VALID")
else:
print("✘ Policy hash INVALID")
except Exception as e:
print(f"Error fetching or computing policy hash: {e}")
print("\n=== VALIDATION FINISHED ===")
if __name__ == "__main__":
main()
|