Una firma digitale registra chi ha firmato un documento. Un timestamp attendibile registra quando, e quel tempo proviene da un’autorità di timestamp indipendente (TSA) piuttosto che dall’orologio del computer del firmatario. Questo tutorial mostra come firmare un documento Word con una firma XAdES‑T con timestamp in Python, quindi confermare che il timestamp sia presente nel file.

Punti chiave

  • Imposta entrambi SignOptions.xml_dsig_level = XmlDsigLevel.X_AD_ES_T e SignOptions.timestamp_settings. Uno solo produce una firma senza timestamp e nessun errore lo segnala.
  • Aspose.Words richiede il timestamp durante DigitalSignatureUtil.sign, quindi quella chiamata necessita di accesso di rete al TSA.
  • I file DOCX e DOC possono essere timbrati. I file ODT no.
  • DigitalSignature.is_valid verifica la firma, non il timestamp. Verifica il timestamp separatamente.

Cosa aggiunge un timestamp attendibile a una firma

Ogni firma creata da Aspose.Words contiene un orario di firma, impostato da SignOptions.sign_time. Tale valore proviene dal computer del firmatario, quindi chiunque contesti il documento può contestare anche l’ora.

Una firma XAdES‑T aggiunge prove indipendenti. Dopo che il documento è stato firmato, Aspose.Words invia un hash del valore della firma a un TSA. Il TSA restituisce un token RFC 3161, firmato con il proprio certificato, che associa l’hash a un momento specifico. Quel token è memorizzato all’interno della firma. Un verificatore può quindi dimostrare che la firma esisteva in quel momento, il che è particolarmente importante quando il certificato di firma scade o viene revocato in seguito.

Prerequisiti

Prima di eseguire l’esempio, assicurati di avere:

pip install --upgrade "aspose-words>=26.9"
  • Un certificato di firma in formato PKCS#12 (.pfx o .p12) e la sua password.
  • Un URL dell’autorità di timestamp. L’esempio utilizza FreeTSA (https://freetsa.org/tsr), un TSA pubblico gratuito comodo per i test. Per i documenti di produzione, utilizzare il TSA raccomandato dalla tua organizzazione o dal fornitore del certificato, poiché le persone che verificano i tuoi documenti devono fidarsi del certificato di quel TSA.
  • Credenziali TSA, solo se il tuo TSA richiede l’autenticazione.

Senza una licenza, Aspose.Words funziona in modalità di valutazione con limitazioni. Una licenza temporanea le rimuove durante il test.

Firma un documento Word con un timestamp attendibile

Il seguente script firma un file DOCX con una firma XAdES‑T e incorpora un timestamp dal TSA.

import datetime
import aspose.words as aw

# Replace these values with your own files and credentials.
INPUT_DOC = "contract.docx"
OUTPUT_DOC = "contract-signed.docx"
CERT_FILE = "signing-cert.pfx"
CERT_PASSWORD = "your-pfx-password"

TSA_URL = "https://freetsa.org/tsr"
TSA_USER = ""       # Fill in only if your TSA requires authentication.
TSA_PASSWORD = ""

# Load the signing certificate from a PKCS#12 file.
cert_holder = aw.digitalsignatures.CertificateHolder.create(
    file_name=CERT_FILE, password=CERT_PASSWORD)

# Request an XAdES-T signature and point it at a timestamp authority.
sign_options = aw.digitalsignatures.SignOptions()
sign_options.xml_dsig_level = aw.digitalsignatures.XmlDsigLevel.X_AD_ES_T
sign_options.timestamp_settings = aw.digitalsignatures.DigitalSignatureTimestampSettings(
    server_url=TSA_URL,
    user_name=TSA_USER,
    password=TSA_PASSWORD,
    timeout=datetime.timedelta(seconds=60),  # Default is 100 seconds.
)

# Sign the document. Aspose.Words contacts the TSA during this call.
aw.digitalsignatures.DigitalSignatureUtil.sign(
    src_file_name=INPUT_DOC,
    dst_file_name=OUTPUT_DOC,
    cert_holder=cert_holder,
    sign_options=sign_options,
)
print(f"Signed with a trusted timestamp: {OUTPUT_DOC}")

Come funziona il codice

  • CertificateHolder.create legge la chiave privata e la catena di certificati dal file .pfx. Una password errata fallisce qui, prima che inizi qualsiasi firma.
  • XmlDsigLevel.X_AD_ES_T indica ad Aspose.Words di creare una firma XAdES‑T, che è XAdES‑EPES più un timestamp della firma.
  • DigitalSignatureTimestampSettings contiene l’URL del TSA, un nome utente e password opzionali e un timeout opzionale. Stringhe vuote vanno bene per un TSA che accetta richieste anonime. Se il TSA risponde con una sfida di autenticazione HTTP, Aspose.Words invia le credenziali fornite.
  • DigitalSignatureUtil.sign scrive una copia firmata in OUTPUT_DOC e lascia invariato il file di input. Firma un documento non firmato: se l’input ha già una firma, l’output contiene sia la firma esistente sia quella nuova.

Verifica che il timestamp sia stato incorporato

Gli oggetti DigitalSignature restituiti da Aspose.Words non espongono il timestamp e is_valid non lo verifica. Durante i test, un documento il cui token di timestamp era stato deliberatamente corrotto segnalava comunque is_valid come True. Per confermare il timestamp, guarda all’interno del file XML della firma memorizzato nel pacchetto DOCX:

import base64
import re
import zipfile
import aspose.words as aw

SIGNED_DOC = "contract-signed.docx"

# 1. Check the signature itself.
for sig in aw.digitalsignatures.DigitalSignatureUtil.load_signatures(SIGNED_DOC):
    print(f"Signer: {sig.subject_name} | valid: {sig.is_valid}")

# 2. Check that a timestamp token was embedded, and save it for inspection.
with zipfile.ZipFile(SIGNED_DOC) as package:
    for part in package.namelist():
        if part.startswith("_xmlsignatures/sig") and part.endswith(".xml"):
            xml = package.read(part).decode("utf-8")
            match = re.search(r"<(?:\w+:)?EncapsulatedTimeStamp[^>]*>([^<]+)<", xml)
            if match:
                with open("timestamp-token.der", "wb") as f:
                    f.write(base64.b64decode(match.group(1)))
                print(f"{part}: timestamp embedded (saved to timestamp-token.der)")
            else:
                print(f"{part}: no timestamp found")

Per un DOCX firmato, dovresti vedere un output simile a questo:

Signer: CN=Your Name | valid: True
_xmlsignatures/sig1.xml: timestamp embedded (saved to timestamp-token.der)

Per leggere l’ora certificata dal TSA, passa il token salvato a OpenSSL:

openssl ts -reply -token_in -in timestamp-token.der -token_out -text

La riga Time stamp mostra l’ora certificata in GMT, e la riga TSA identifica l’autorità che l’ha emessa.

Questo controllo legge il formato del pacchetto DOCX. Un file DOC memorizza la sua firma in un contenitore binario, quindi lo script basato su ZIP non si applica.

Risoluzione dei problemi di firma e timestamp

SintomoCausa probabileCosa fare
La firma ha successo, ma nessun timestamp è incorporatoÈ stata impostata solo una delle opzioni xml_dsig_level = X_AD_ES_T e timestamp_settingsImposta entrambe prima di chiamare sign. Con XML_D_SIG o X_AD_ES_EPES, le impostazioni del timestamp vengono ignorate.
RuntimeError che menziona (401) UnauthorizedIl TSA richiede credenziali, o le credenziali sono errateFornisci il nome utente e la password rilasciati dal tuo provider TSA.
RuntimeError che menziona una connessione rifiutata o un errore di proxyL’URL del TSA è errato, oppure un firewall o un proxy blocca la richiestaVerifica l’URL e conferma che la macchina che esegue lo script possa raggiungere il TSA.
RuntimeError che menziona The operation has timed outIl TSA non ha risposto entro il timeoutRiprova, oppure passa un valore timeout più lungo a DigitalSignatureTimestampSettings.
Un file di output vuoto rimane dopo un erroresign crea il file di destinazione prima che la richiesta al TSA falliscaElimina il file di destinazione prima di riprovare, oppure scrivi in un percorso temporaneo e rinominalo dopo una chiamata riuscita.
RuntimeError che indica che il timestamp non è supportato da questo formato di fileL’input è un file ODTApplica il timestamp a file DOCX o DOC, oppure converti in PDF e utilizza il percorso di firma PDF descritto di seguito.
No usable version of libssl was found, o un crash relativo a un pacchetto ICU mancante, su LinuxIl runtime .NET incluso nel pacchetto Python richiede OpenSSL 1.1 e una versione ICU supportataInstalla OpenSSL 1.1, oppure installa una ICU supportata. Se la tua applicazione non necessita di formattazione specifica per la cultura, imposta DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 per l’errore ICU.

Alternativa: Apporre un timestamp a una firma nell’output PDF

Se i tuoi destinatari hanno bisogno di un PDF anziché di un file Word firmato, non è necessario DigitalSignatureUtil. Firma e apponi un timestamp al PDF durante il salvataggio impostando PdfSaveOptions.digital_signature_details.timestamp_settings su un oggetto PdfDigitalSignatureTimestampSettings. Questa modalità è disponibile da molto più tempo rispetto alla 26.9. Il riferimento PdfDigitalSignatureTimestampSettings include un esempio completo.

Prossimi Passi

Per aggiungere linee di firma, firmare con un’immagine di linea di firma o rimuovere firme esistenti, vedere Lavorare con le firme digitali nella documentazione di Aspose.Words for Python.

FAQs

  1. Cosa aggiunge un timestamp attendibile a una firma digitale?
    Un’autorità di timestamp (TSA) certifica l’ora in cui è stata creata la firma. Tale ora proviene da una terza parte indipendente anziché dall’orologio del computer del firmatario, e consente a chi verifica di dimostrare che la firma esisteva prima che il certificato di firma scadesse o fosse revocato.

  2. Quale versione di Aspose.Words supporta il timestamping in DigitalSignatureUtil?
    La versione 26.9 di Aspose.Words for Python via .NET ha aggiunto SignOptions.timestamp_settings, XmlDsigLevel.X_AD_ES_T e la classe DigitalSignatureTimestampSettings. Le versioni precedenti possono aggiungere timestamp solo alle firme nell’output PDF.

  3. Devo impostare sia xml_dsig_level che timestamp_settings?
    Sì. Se ne è impostato solo uno, Aspose.Words firma comunque il documento ma non richiede né incorpora un timestamp, e non genera un errore.

  4. Quali formati di file possono essere timestampati?
    I file DOCX e DOC firmati con X_AD_ES_T ricevono un timestamp. Firmare un file ODT con un timestamp genera un errore che indica che il formato non supporta il timestamping.

  5. is_valid conferma che il timestamp è valido?
    No. DigitalSignature.is_valid verifica solo la firma stessa. Per confermare il timestamp, controlla che l’XML della firma contenga un token di timestamp e ispeziona il token con uno strumento come OpenSSL.

  6. Cosa succede se il TSA non è raggiungibile?
    DigitalSignatureUtil.sign genera un RuntimeError che descrive il problema di rete, autenticazione o timeout. Il percorso di destinazione potrebbe rimanere come un file vuoto, quindi è consigliabile eliminarlo prima di riprovare.

Ottieni una Licenza Gratuita e Supporto