unipdf/model/sighandler/sighandler_pkcs7.go
Alexey Pavlyukov a69d788171
Add timestamp signature handler (#301)
* Add timestamp signature handler

* Add timestamp signature handler test

* fix PR issues

* fix PR issues

* fix PR issues

* Fix

Co-authored-by: Gunnsteinn Hall <gunnsteinn.hall@gmail.com>
2020-04-22 20:21:53 +00:00

177 lines
4.7 KiB
Go

/*
* This file is subject to the terms and conditions defined in
* file 'LICENSE.md', which is part of this source code package.
*/
package sighandler
import (
"bytes"
"crypto/rsa"
"crypto/x509"
"errors"
"fmt"
"github.com/unidoc/pkcs7"
"github.com/unidoc/unipdf/v3/core"
"github.com/unidoc/unipdf/v3/model"
)
// Adobe PKCS7 detached signature handler.
type adobePKCS7Detached struct {
privateKey *rsa.PrivateKey
certificate *x509.Certificate
emptySignature bool
emptySignatureLen int
}
// NewEmptyAdobePKCS7Detached creates a new Adobe.PPKMS/Adobe.PPKLite adbe.pkcs7.detached
// signature handler. The generated signature is empty and of size signatureLen.
// The signatureLen parameter can be 0 for the signature validation.
func NewEmptyAdobePKCS7Detached(signatureLen int) (model.SignatureHandler, error) {
return &adobePKCS7Detached{
emptySignature: true,
emptySignatureLen: signatureLen,
}, nil
}
// NewAdobePKCS7Detached creates a new Adobe.PPKMS/Adobe.PPKLite adbe.pkcs7.detached signature handler.
// Both parameters may be nil for the signature validation.
func NewAdobePKCS7Detached(privateKey *rsa.PrivateKey, certificate *x509.Certificate) (model.SignatureHandler, error) {
return &adobePKCS7Detached{
certificate: certificate,
privateKey: privateKey,
}, nil
}
// InitSignature initialises the PdfSignature.
func (a *adobePKCS7Detached) InitSignature(sig *model.PdfSignature) error {
if !a.emptySignature {
if a.certificate == nil {
return errors.New("certificate must not be nil")
}
if a.privateKey == nil {
return errors.New("privateKey must not be nil")
}
}
handler := *a
sig.Handler = &handler
sig.Filter = core.MakeName("Adobe.PPKLite")
sig.SubFilter = core.MakeName("adbe.pkcs7.detached")
sig.Reference = nil
digest, err := handler.NewDigest(sig)
if err != nil {
return err
}
digest.Write([]byte("calculate the Contents field size"))
return handler.Sign(sig, digest)
}
func (a *adobePKCS7Detached) getCertificate(sig *model.PdfSignature) (*x509.Certificate, error) {
if a.certificate != nil {
return a.certificate, nil
}
var certData []byte
switch certObj := sig.Cert.(type) {
case *core.PdfObjectString:
certData = certObj.Bytes()
case *core.PdfObjectArray:
if certObj.Len() == 0 {
return nil, errors.New("no signature certificates found")
}
for _, obj := range certObj.Elements() {
certStr, ok := core.GetString(obj)
if !ok {
return nil, fmt.Errorf("invalid certificate object type in signature certificate chain: %T", obj)
}
certData = append(certData, certStr.Bytes()...)
}
default:
return nil, fmt.Errorf("invalid signature certificate object type: %T", certObj)
}
certs, err := x509.ParseCertificates(certData)
if err != nil {
return nil, err
}
return certs[0], nil
}
// NewDigest creates a new digest.
func (a *adobePKCS7Detached) NewDigest(sig *model.PdfSignature) (model.Hasher, error) {
return bytes.NewBuffer(nil), nil
}
// Validate validates PdfSignature.
func (a *adobePKCS7Detached) Validate(sig *model.PdfSignature, digest model.Hasher) (model.SignatureValidationResult, error) {
signed := sig.Contents.Bytes()
p7, err := pkcs7.Parse(signed)
if err != nil {
return model.SignatureValidationResult{}, err
}
buffer := digest.(*bytes.Buffer)
p7.Content = buffer.Bytes()
if err = p7.Verify(); err != nil {
return model.SignatureValidationResult{}, err
}
return model.SignatureValidationResult{
IsSigned: true,
IsVerified: true,
}, nil
}
// Sign sets the Contents fields.
func (a *adobePKCS7Detached) Sign(sig *model.PdfSignature, digest model.Hasher) error {
if a.emptySignature {
sigLen := a.emptySignatureLen
if sigLen <= 0 {
sigLen = 8192
}
sig.Contents = core.MakeHexString(string(make([]byte, sigLen)))
return nil
}
buffer := digest.(*bytes.Buffer)
signedData, err := pkcs7.NewSignedData(buffer.Bytes())
if err != nil {
return err
}
// Add the signing cert and private key
if err := signedData.AddSigner(a.certificate, a.privateKey, pkcs7.SignerInfoConfig{}); err != nil {
return err
}
// Call Detach() is you want to remove content from the signature
// and generate an S/MIME detached signature
signedData.Detach()
// Finish() to obtain the signature bytes
detachedSignature, err := signedData.Finish()
if err != nil {
return err
}
data := make([]byte, 8192)
copy(data, detachedSignature)
sig.Contents = core.MakeHexString(string(data))
return nil
}
// IsApplicable returns true if the signature handler is applicable for the PdfSignature
func (a *adobePKCS7Detached) IsApplicable(sig *model.PdfSignature) bool {
if sig == nil || sig.Filter == nil || sig.SubFilter == nil {
return false
}
return (*sig.Filter == "Adobe.PPKMS" || *sig.Filter == "Adobe.PPKLite") && *sig.SubFilter == "adbe.pkcs7.detached"
}