162
sign.go
162
sign.go
@@ -4,12 +4,22 @@ import (
|
|||||||
"flag"
|
"flag"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/pem"
|
||||||
|
"errors"
|
||||||
|
"io/ioutil"
|
||||||
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"crypto"
|
||||||
|
|
||||||
"bitbucket.org/digitorus/pdfsign/config"
|
"bitbucket.org/digitorus/pdfsign/config"
|
||||||
|
"bitbucket.org/digitorus/pdfsign/revocation"
|
||||||
"bitbucket.org/digitorus/pdfsign/sign"
|
"bitbucket.org/digitorus/pdfsign/sign"
|
||||||
"bitbucket.org/digitorus/pdfsign/verify"
|
"bitbucket.org/digitorus/pdfsign/verify"
|
||||||
|
"bitbucket.org/digitorus/pkcs11"
|
||||||
)
|
)
|
||||||
|
|
||||||
// usage is a usage function for the flags package.
|
// usage is a usage function for the flags package.
|
||||||
@@ -124,18 +134,64 @@ Description
|
|||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err := newSigner(*crtPath, *keyPath, *crtChainPath)
|
cert, signer, err := getCertSignerPair(*crtPath, *keyPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.sign(*inputPath, *outputPath, signData); err != nil {
|
certificate_chains, err := getCertificateChains(*crtChainPath, cert)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
signData.Signer = signer
|
||||||
|
signData.Certificate = cert
|
||||||
|
signData.CertificateChains = certificate_chains
|
||||||
|
if err := signWithConfig(*inputPath, *outputPath, signData); err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
} else {
|
} else {
|
||||||
log.Println("Signed PDF written to " + *outputPath)
|
log.Println("Signed PDF written to " + *outputPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getCertSignerPair(crtPath, keyPath string) (*x509.Certificate, crypto.Signer, error) {
|
||||||
|
var certificate *x509.Certificate
|
||||||
|
var signer crypto.Signer
|
||||||
|
|
||||||
|
// Set certificate
|
||||||
|
certificate_data, err := ioutil.ReadFile(crtPath)
|
||||||
|
if err != nil {
|
||||||
|
return certificate, signer, err
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
certificate_data_block, _ := pem.Decode(certificate_data)
|
||||||
|
if certificate_data_block == nil {
|
||||||
|
return certificate, signer, errors.New("failed to parse PEM block containing the certificate")
|
||||||
|
}
|
||||||
|
cert, err := x509.ParseCertificate(certificate_data_block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return certificate, signer, err
|
||||||
|
}
|
||||||
|
certificate = cert
|
||||||
|
|
||||||
|
// Set key
|
||||||
|
key_data, err := ioutil.ReadFile(keyPath)
|
||||||
|
if err != nil {
|
||||||
|
return certificate, signer, err
|
||||||
|
}
|
||||||
|
key_data_block, _ := pem.Decode(key_data)
|
||||||
|
if key_data_block == nil {
|
||||||
|
return certificate, signer, errors.New("failed to parse PEM block containing the private key")
|
||||||
|
}
|
||||||
|
pkey, err := x509.ParsePKCS1PrivateKey(key_data_block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return certificate, signer, err
|
||||||
|
}
|
||||||
|
signer = pkey
|
||||||
|
|
||||||
|
return certificate, signer, nil
|
||||||
|
}
|
||||||
|
|
||||||
func p11sign() {
|
func p11sign() {
|
||||||
signCommand := flag.NewFlagSet("sign", flag.ExitOnError)
|
signCommand := flag.NewFlagSet("sign", flag.ExitOnError)
|
||||||
configPath := signCommand.String("config", "", "Path to config file")
|
configPath := signCommand.String("config", "", "Path to config file")
|
||||||
@@ -148,9 +204,9 @@ func p11sign() {
|
|||||||
output := signCommand.String("out", "", "Output PDF file")
|
output := signCommand.String("out", "", "Output PDF file")
|
||||||
libPath := signCommand.String("lib", "", "Path to PKCS11 library")
|
libPath := signCommand.String("lib", "", "Path to PKCS11 library")
|
||||||
pass := signCommand.String("pass", "", "PKCS11 password")
|
pass := signCommand.String("pass", "", "PKCS11 password")
|
||||||
crtChainPath := signCommand.String("chain", "", "Certificate chain")
|
crtChain := signCommand.String("chain", "", "Certificate chain")
|
||||||
help := signCommand.Bool("help", false, "Show this help")
|
help := signCommand.Bool("help", false, "Show this help")
|
||||||
signData := getSignDataFlags(signCommand)
|
|
||||||
signCommand.Parse(os.Args[2:])
|
signCommand.Parse(os.Args[2:])
|
||||||
usageText := `Usage: pdfsign sign -in input.pdf -out output.pdf -pass pkcs11-password [-chain chain.crt]")
|
usageText := `Usage: pdfsign sign -in input.pdf -out output.pdf -pass pkcs11-password [-chain chain.crt]")
|
||||||
|
|
||||||
@@ -169,14 +225,108 @@ Description
|
|||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err := newP11Signer(*libPath, *pass, *crtChainPath)
|
cert, signer, err := getP11CertSignerPair(*libPath, *pass)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.sign(*input, *output, signData); err != nil {
|
certificate_chains, err := getCertificateChains(*crtChain, cert)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var data sign.SignData
|
||||||
|
data.Certificate = cert
|
||||||
|
data.Signer = signer
|
||||||
|
data.CertificateChains = certificate_chains
|
||||||
|
if err := signWithConfig(*input, *output, data); err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
} else {
|
} else {
|
||||||
log.Println("Signed PDF written to " + *output)
|
log.Println("Signed PDF written to " + *output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getP11CertSignerPair(libPath, pass string) (*x509.Certificate, crypto.Signer, error) {
|
||||||
|
var certificate *x509.Certificate
|
||||||
|
var signer crypto.Signer
|
||||||
|
|
||||||
|
// pkcs11 key
|
||||||
|
lib, err := pkcs11.FindLib(libPath)
|
||||||
|
if err != nil {
|
||||||
|
return certificate, signer, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load Library
|
||||||
|
ctx := pkcs11.New(lib)
|
||||||
|
if ctx == nil {
|
||||||
|
return certificate, signer, errors.New("Failed to load library")
|
||||||
|
}
|
||||||
|
err = ctx.Initialize()
|
||||||
|
if err != nil {
|
||||||
|
return certificate, signer, err
|
||||||
|
}
|
||||||
|
// login
|
||||||
|
session, err := pkcs11.CreateSession(ctx, 0, pass, false)
|
||||||
|
if err != nil {
|
||||||
|
return certificate, signer, err
|
||||||
|
}
|
||||||
|
// select the first certificate
|
||||||
|
cert, ckaId, err := pkcs11.GetCert(ctx, session, nil)
|
||||||
|
if err != nil {
|
||||||
|
return certificate, signer, err
|
||||||
|
}
|
||||||
|
certificate = cert
|
||||||
|
|
||||||
|
// private key
|
||||||
|
pkey, err := pkcs11.InitPrivateKey(ctx, session, ckaId)
|
||||||
|
if err != nil {
|
||||||
|
return certificate, signer, err
|
||||||
|
}
|
||||||
|
signer = pkey
|
||||||
|
|
||||||
|
return certificate, signer, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCertificateChains(crtChain string, cert *x509.Certificate) ([][]*x509.Certificate, error) {
|
||||||
|
certificate_chains := make([][]*x509.Certificate, 0)
|
||||||
|
if crtChain == "" {
|
||||||
|
return certificate_chains, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
chain_data, err := ioutil.ReadFile(crtChain)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
certificate_pool := x509.NewCertPool()
|
||||||
|
certificate_pool.AppendCertsFromPEM(chain_data)
|
||||||
|
certificate_chains, err = cert.Verify(x509.VerifyOptions{
|
||||||
|
Intermediates: certificate_pool,
|
||||||
|
CurrentTime: cert.NotBefore,
|
||||||
|
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
|
||||||
|
})
|
||||||
|
|
||||||
|
return certificate_chains, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func signWithConfig(input, output string, d sign.SignData) error {
|
||||||
|
err := sign.SignFile(input, output, sign.SignData{
|
||||||
|
Signature: sign.SignDataSignature{
|
||||||
|
Info: sign.SignDataSignatureInfo{
|
||||||
|
Name: d.Signature.Info.Name,
|
||||||
|
Location: d.Signature.Info.Location,
|
||||||
|
Reason: d.Signature.Info.Reason,
|
||||||
|
ContactInfo: d.Signature.Info.ContactInfo,
|
||||||
|
Date: time.Now().Local(),
|
||||||
|
},
|
||||||
|
CertType: d.Signature.CertType,
|
||||||
|
Approval: d.Signature.Approval,
|
||||||
|
},
|
||||||
|
Signer: d.Signer,
|
||||||
|
Certificate: d.Certificate,
|
||||||
|
CertificateChains: d.CertificateChains,
|
||||||
|
TSA: d.TSA,
|
||||||
|
RevocationData: revocation.InfoArchival{},
|
||||||
|
RevocationFunction: sign.DefaultEmbedRevocationStatusFunction,
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
154
signer.go
154
signer.go
@@ -1,154 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto"
|
|
||||||
"crypto/x509"
|
|
||||||
"encoding/pem"
|
|
||||||
"errors"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"bitbucket.org/digitorus/pdfsign/revocation"
|
|
||||||
"bitbucket.org/digitorus/pdfsign/sign"
|
|
||||||
"bitbucket.org/digitorus/pkcs11"
|
|
||||||
)
|
|
||||||
|
|
||||||
type signer struct {
|
|
||||||
certificate *x509.Certificate
|
|
||||||
signer crypto.Signer
|
|
||||||
certificateChains [][]*x509.Certificate
|
|
||||||
}
|
|
||||||
|
|
||||||
func newSigner(crtPath, keyPath, crtChainPath string) (*signer, error) {
|
|
||||||
var s signer
|
|
||||||
|
|
||||||
// Set certificate
|
|
||||||
certificate_data, err := ioutil.ReadFile(crtPath)
|
|
||||||
if err != nil {
|
|
||||||
return &s, err
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
certificate_data_block, _ := pem.Decode(certificate_data)
|
|
||||||
if certificate_data_block == nil {
|
|
||||||
return &s, errors.New("failed to parse PEM block containing the certificate")
|
|
||||||
}
|
|
||||||
cert, err := x509.ParseCertificate(certificate_data_block.Bytes)
|
|
||||||
if err != nil {
|
|
||||||
return &s, err
|
|
||||||
}
|
|
||||||
s.certificate = cert
|
|
||||||
|
|
||||||
// Set key
|
|
||||||
key_data, err := ioutil.ReadFile(keyPath)
|
|
||||||
if err != nil {
|
|
||||||
return &s, err
|
|
||||||
}
|
|
||||||
key_data_block, _ := pem.Decode(key_data)
|
|
||||||
if key_data_block == nil {
|
|
||||||
return &s, errors.New("failed to parse PEM block containing the private key")
|
|
||||||
}
|
|
||||||
pkey, err := x509.ParsePKCS1PrivateKey(key_data_block.Bytes)
|
|
||||||
if err != nil {
|
|
||||||
return &s, err
|
|
||||||
}
|
|
||||||
s.signer = pkey
|
|
||||||
|
|
||||||
certificate_chains, err := getCertificateChains(crtChainPath, cert)
|
|
||||||
if err != nil {
|
|
||||||
return &s, err
|
|
||||||
}
|
|
||||||
s.certificateChains = certificate_chains
|
|
||||||
|
|
||||||
return &s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func newP11Signer(libPath, pass, crtChainPath string) (*signer, error) {
|
|
||||||
var s signer
|
|
||||||
|
|
||||||
// pkcs11 key
|
|
||||||
lib, err := pkcs11.FindLib(libPath)
|
|
||||||
if err != nil {
|
|
||||||
return &s, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load Library
|
|
||||||
ctx := pkcs11.New(lib)
|
|
||||||
if ctx == nil {
|
|
||||||
return &s, errors.New("Failed to load library")
|
|
||||||
}
|
|
||||||
err = ctx.Initialize()
|
|
||||||
if err != nil {
|
|
||||||
return &s, err
|
|
||||||
}
|
|
||||||
// login
|
|
||||||
session, err := pkcs11.CreateSession(ctx, 0, pass, false)
|
|
||||||
if err != nil {
|
|
||||||
return &s, err
|
|
||||||
}
|
|
||||||
// select the first certificate
|
|
||||||
cert, ckaId, err := pkcs11.GetCert(ctx, session, nil)
|
|
||||||
if err != nil {
|
|
||||||
return &s, err
|
|
||||||
}
|
|
||||||
s.certificate = cert
|
|
||||||
|
|
||||||
// private key
|
|
||||||
pkey, err := pkcs11.InitPrivateKey(ctx, session, ckaId)
|
|
||||||
if err != nil {
|
|
||||||
return &s, err
|
|
||||||
}
|
|
||||||
s.signer = pkey
|
|
||||||
|
|
||||||
certificate_chains, err := getCertificateChains(crtChainPath, cert)
|
|
||||||
if err != nil {
|
|
||||||
return &s, err
|
|
||||||
}
|
|
||||||
s.certificateChains = certificate_chains
|
|
||||||
|
|
||||||
return &s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getCertificateChains(crtChainPath string, cert *x509.Certificate) ([][]*x509.Certificate, error) {
|
|
||||||
certificate_chains := make([][]*x509.Certificate, 0)
|
|
||||||
if crtChainPath == "" {
|
|
||||||
return certificate_chains, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
chain_data, err := ioutil.ReadFile(crtChainPath)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
certificate_pool := x509.NewCertPool()
|
|
||||||
certificate_pool.AppendCertsFromPEM(chain_data)
|
|
||||||
certificate_chains, err = cert.Verify(x509.VerifyOptions{
|
|
||||||
Intermediates: certificate_pool,
|
|
||||||
CurrentTime: cert.NotBefore,
|
|
||||||
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
|
|
||||||
})
|
|
||||||
|
|
||||||
return certificate_chains, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *signer) sign(input, output string, d sign.SignData) error {
|
|
||||||
err := sign.SignFile(input, output, sign.SignData{
|
|
||||||
Signature: sign.SignDataSignature{
|
|
||||||
Info: sign.SignDataSignatureInfo{
|
|
||||||
Name: d.Signature.Info.Name,
|
|
||||||
Location: d.Signature.Info.Location,
|
|
||||||
Reason: d.Signature.Info.Reason,
|
|
||||||
ContactInfo: d.Signature.Info.ContactInfo,
|
|
||||||
Date: time.Now().Local(),
|
|
||||||
},
|
|
||||||
CertType: d.Signature.CertType,
|
|
||||||
Approval: d.Signature.Approval,
|
|
||||||
},
|
|
||||||
Signer: s.signer,
|
|
||||||
Certificate: s.certificate,
|
|
||||||
CertificateChains: s.certificateChains,
|
|
||||||
TSA: d.TSA,
|
|
||||||
RevocationData: revocation.InfoArchival{},
|
|
||||||
RevocationFunction: sign.DefaultEmbedRevocationStatusFunction,
|
|
||||||
})
|
|
||||||
return err
|
|
||||||
}
|
|
Reference in New Issue
Block a user