En digital signatur registrerar vem som har signerat ett dokument. En betrodd tidsstämpel registrerar när, och den tiden kommer från en oberoende tidsstämpelmyndighet (TSA) snarare än klockan på signerarens dator. Denna handledning visar hur du signerar ett Word‑dokument med en tidsstämplad XAdES‑T‑signatur i Python och sedan bekräftar att tidsstämpeln finns i filen.
Viktiga slutsatser
- Ställ in båda
SignOptions.xml_dsig_level = XmlDsigLevel.X_AD_ES_TochSignOptions.timestamp_settings. Endast en av dem ger en signatur utan tidsstämpel, och inget felmeddelande informerar dig om det. - Aspose.Words begär tidsstämpeln under
DigitalSignatureUtil.sign, så det anropet kräver nätverksåtkomst till TSA. - DOCX och DOC filer kan tidsstämplas. ODT-filer kan inte.
DigitalSignature.is_validkontrollerar signaturen, inte tidsstämpeln. Bekräfta tidsstämpeln separat.
Vad ett betrott tidsstämpel lägger till en signatur
Varje signatur som Aspose.Words skapar innehåller en signeringstid, som sätts av SignOptions.sign_time. Det värdet kommer från undertecknarens maskin, så vem som helst som bestrider dokumentet kan också bestrida tiden.
En XAdES‑T‑signatur lägger till oberoende bevis. Efter att dokumentet har signerats skickar Aspose.Words en hash av signaturvärdet till en TSA. TSA:n returnerar en RFC 3161‑token, signerad med sitt eget certifikat, som binder hashen till en specifik tid. Den token lagras i signaturen. En verifierare kan sedan visa att signaturen existerade vid den tidpunkten, vilket är särskilt viktigt när signaturcertifikatet senare löper ut eller återkallas.
Förutsättningar
Innan du kör exemplet, se till att du har:
- Aspose.Words for Python via .NET 26.9 eller senare. Installera eller uppgradera från PyPI:
pip install --upgrade "aspose-words>=26.9"
- Ett signeringscertifikat i PKCS#12-format (
.pfxeller.p12) och dess lösenord. - En tidsstämpelauktoritets-URL. Exemplet använder FreeTSA (
https://freetsa.org/tsr), en gratis offentlig TSA som är praktisk för testning. För produktionsdokument, använd den TSA som din organisation eller certifikatleverantör rekommenderar, eftersom de som granskar dina dokument måste lita på den TSA:s certifikat. - TSA-referenser, endast om din TSA kräver autentisering.
Utan en licens kör Aspose.Words i evalueringsläge med begränsningar. En tillfällig licens tar bort dem medan du testar.
Signera ett Word‑dokument med en betrodd tidsstämpel
Följande skript signerar en DOCX‑fil med en XAdES‑T‑signatur och bäddar in en tidsstämpel från 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}")
Så fungerar koden
CertificateHolder.createläser den privata nyckeln och certifikatkedjan från.pfx-filen. Ett felaktigt lösenord misslyckas här, innan någon signering påbörjas.XmlDsigLevel.X_AD_ES_Tinstruerar Aspose.Words att bygga en XAdES‑T‑signatur, vilket är XAdES‑EPES plus en signatur‑tidsstämpel.DigitalSignatureTimestampSettingsinnehåller TSA‑URL:en, ett valfritt användarnamn och lösenord samt en valfri timeout. Tomma strängar är okej för en TSA som accepterar anonyma förfrågningar. Om TSA svarar med en HTTP‑autentiseringsutmaning skickar Aspose.Words de referenser du angav.DigitalSignatureUtil.signskriver en signerad kopia tillOUTPUT_DOCoch lämnar indatafilen oförändrad. Signera ett osignerat dokument: om indata redan har en signatur innehåller utdata både den befintliga signaturen och den nya.
Kontrollera att tidsstämpeln har bäddats in
DigitalSignature‑objekten som Aspose.Words returnerar visar inte tidsstämpeln, och is_valid kontrollerar den inte. Vid testning rapporterade ett dokument vars tidsstämpel‑token hade avsiktligt korruptats fortfarande is_valid som True. För att bekräfta tidsstämpeln, titta i signatur‑XML‑filen som lagras i DOCX‑paketet:
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")
För ett signerat DOCX bör du se en liknande utskrift:
Signer: CN=Your Name | valid: True
_xmlsignatures/sig1.xml: timestamp embedded (saved to timestamp-token.der)
För att läsa tiden som TSA certifierade, skicka den sparade token till OpenSSL:
openssl ts -reply -token_in -in timestamp-token.der -token_out -text
Raden Time stamp visar den certifierade tiden i GMT, och raden TSA identifierar den myndighet som utfärdade den.
Denna kontroll läser DOCX‑paketformatet. En DOC‑fil lagrar sin signatur i en binär behållare, så det ZIP‑baserade skriptet gäller inte för den.
Felsökning av signering och tidsstämpelfel
| Symptom | Trolig orsak | Vad du ska göra |
|---|---|---|
| Signeringen lyckas, men ingen tidsstämpel har lagts till | Endast en av xml_dsig_level = X_AD_ES_T och timestamp_settings var inställd | Ställ in båda innan du anropar sign. Med XML_D_SIG eller X_AD_ES_EPES ignoreras tidsstämpelinställningarna. |
RuntimeError som nämner (401) Unauthorized | TSA:n kräver autentiseringsuppgifter, eller så är uppgifterna felaktiga | Skicka med användarnamn och lösenord som utfärdats av din TSA-leverantör. |
RuntimeError som nämner en nekad anslutning eller ett proxyfel | TSA‑URL:en är felaktig, eller en brandvägg eller proxy blockerar begäran | Kontrollera URL:en och bekräfta att maskinen som kör ditt skript kan nå TSA:n. |
RuntimeError som nämner The operation has timed out | TSA:n svarade inte inom tidsgränsen | Försök igen, eller skicka med en längre timeout till DigitalSignatureTimestampSettings. |
| En tom utdatafil återstår efter ett fel | sign skapar destinationsfilen innan TSA‑begäran misslyckas | Ta bort destinationsfilen innan du försöker igen, eller skriv till en temporär sökväg och byt namn på den efter ett lyckat anrop. |
RuntimeError som säger att tidsstämpling inte stöds av detta filformat | Inmatningen är en ODT‑fil | Tidsstämpla DOCX‑ eller DOC‑filer, eller konvertera till PDF och använd PDF‑signeringsvägen som beskrivs nedan. |
No usable version of libssl was found, eller en krasch på grund av ett saknat ICU‑paket, på Linux | Python‑paketets medföljande .NET‑runtime kräver OpenSSL 1.1 och en stödjande ICU‑version | Installera OpenSSL 1.1, eller installera en stödjande ICU. Om din applikation inte behöver kultur‑specifik formatering, sätt DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 för ICU‑felet. |
Alternativ: Tidsstämpel för en signatur i PDF‑utdata
Om dina mottagare behöver en PDF snarare än en signerad Word‑fil, behöver du inte DigitalSignatureUtil. Signera och tidsstämpla PDF‑filen vid sparande genom att sätta PdfSaveOptions.digital_signature_details.timestamp_settings till ett PdfDigitalSignatureTimestampSettings‑objekt. Denna metod har funnits tillgänglig mycket längre än 26.9. PdfDigitalSignatureTimestampSettings‑referensen innehåller ett komplett exempel.
Nästa steg
För att lägga till signaturlinjer, signera med en signaturlinje‑bild eller ta bort befintliga signaturer, se Work with Digital Signatures i Aspose.Words for Python-dokumentationen.
Vanliga frågor
Vad tillför en betrodd tidsstämpel till en digital signatur?
En tidsstämpelmyndighet (TSA) intygar den tid då signaturen skapades. Den tiden kommer från en oberoende tredje part snarare än undertecknarens datorklocka, och den låter en verifierare visa att signaturen fanns innan signeringscertifikatet gick ut eller revokerades.Vilken version av Aspose.Words stödjer tidsstämpling i DigitalSignatureUtil?
Version 26.9 av Aspose.Words for Python via .NET lade tillSignOptions.timestamp_settings,XmlDsigLevel.X_AD_ES_Toch klassenDigitalSignatureTimestampSettings. Tidigare versioner kan endast tidsstämpla signaturer i PDF-utdata.Behöver jag ange både xml_dsig_level och timestamp_settings?
Ja. Om endast en av dem är angiven, signerar Aspose.Words fortfarande dokumentet men begär eller bäddar inte in en tidsstämpel, och det kastar inget fel.Vilka filformat kan tidsstämplas?
DOCX- och DOC-filer som signeras medX_AD_ES_Tfår en tidsstämpel. Att signera en ODT-fil med en tidsstämpel ger ett fel som säger att formatet inte stödjer tidsstämpling.Bekräftar is_valid att tidsstämpeln är giltig?
Nej.DigitalSignature.is_validkontrollerar själva signaturen. För att bekräfta tidsstämpeln, kontrollera att signaturens XML innehåller en tidsstämpel‑token och inspektera token med ett verktyg som OpenSSL.Vad händer om TSA inte kan nås?
DigitalSignatureUtil.signkastar ettRuntimeErrorsom beskriver nätverks-, autentiserings- eller tidsgräns‑problemet. Destinationssökvägen kan bli en tom fil, så ta bort den innan du försöker igen.
