Validate a Timestamp Signature
Validating a document timestamp goes through the same call as any other
signature, PdfReader.ValidateSignatures, with a DocTimeStamp handler in the
list. Both the server URL and the hash algorithm can be left empty for
validation, since both come out of the token:
handler, err := sighandler.NewDocTimeStamp("", 0)
if err != nil {
return err
}
res, err := reader.ValidateSignatures([]model.SignatureHandler{handler})
if err != nil {
return err
}The result carries GeneralizedTime, the time the timestamp authority put in the
token, and IsVerified, which is true when the hash of the covered byte range
matches the message imprint inside the token.
Picking the timestamps out of the results
ValidateSignatures returns one result per field whose value dictionary has a
Type of Sig or DocTimeStamp, in document order, so a signed and timestamped
file yields at least two. The example narrows them down through the field the
result points back at:
for i, item := range res {
if d, ok := core.GetDict(item.Fields[0].V); ok && d.Get("SubFilter").String() == "ETSI.RFC3161" {
timestampRes[i] = item
}
}ETSI.RFC3161 is the subfilter every document timestamp carries, and it is also
what the handler’s IsApplicable matches on when the handler is chosen.
Limitations
A handler that is not applicable to a signature is not an error. Results for the
signatures nothing in the list can handle come back with IsSigned true and an
Errors entry reading “handler not set”, and the call still returns nil. Pass a
handler for every subfilter you care about, and check Errors rather than
assuming a returned result was validated.
A validation that fails outright is not an error either. When a handler’s
Validate returns an error, the message is appended to Errors and the result is
otherwise the zero value, so a corrupt timestamp reports as not signed and not
verified rather than failing the call.
ValidateSignatures returns nil, nil for a document with no AcroForm or no
fields. An empty slice means no signature fields, not a successful validation of
none, which is why the example treats it as a failure.
IsTrusted is never set by any handler in the SDK, and IsCrlFound and
IsOcspFound are only set by the PAdES handlers. Printing a result from a
DocTimeStamp handler therefore always reports “Untrusted certificate”, “CRL not
found” and “OCSP not found”, whatever the file actually contains. Building a trust
path and checking revocation is left to the caller, or to
sighandler.NewEtsiPAdES and the NewEtsiPAdESLevel* handlers.
Run the example
The example prints SignatureValidationResult.String() for every timestamp it
finds, which includes GeneralizedTime when it is set. Nothing is written; the
output goes to the terminal.
git clone https://github.com/unidoc/unipdf-examples.git
cd unipdf-examples/signatures
go run pdf_sign_validate_timestamp.go input.pdfIf this is your first time using UniPDF, follow the getting started guide to create an API key and set up your development environment.