@@ -4,10 +4,14 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"bitbucket.org/digitorus/pdfsign/sign"
|
|
||||||
"github.com/BurntSushi/toml"
|
"github.com/BurntSushi/toml"
|
||||||
|
"github.com/asaskevich/govalidator"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
govalidator.SetFieldsRequiredByDefault(true)
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
DefaultLocation string = "./pdfsign.conf" // Default location of the config file
|
DefaultLocation string = "./pdfsign.conf" // Default location of the config file
|
||||||
Settings Config // Initialized once inside Read method Settings are stored in memory.
|
Settings Config // Initialized once inside Read method Settings are stored in memory.
|
||||||
@@ -15,8 +19,24 @@ var (
|
|||||||
|
|
||||||
// Config is the root of the config
|
// Config is the root of the config
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Info sign.SignDataSignatureInfo
|
//Info:
|
||||||
TSA sign.TSA
|
//Name: "Jeroen Bobbeldijk",
|
||||||
|
//Location: "Rotterdam",
|
||||||
|
//Reason: "Test",
|
||||||
|
//ContactInfo: "Geen",
|
||||||
|
//CertType: 2,
|
||||||
|
//Approval: false,
|
||||||
|
//TSA: sign.TSA{
|
||||||
|
//URL: "http://aatl-timestamp.globalsign.com/tsa/aohfewat2389535fnasgnlg5m23",
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateFields validates all the fields of the config
|
||||||
|
func (c Config) ValidateFields() error {
|
||||||
|
_, err := govalidator.ValidateStruct(c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Read(configfile string) {
|
func Read(configfile string) {
|
||||||
@@ -30,5 +50,9 @@ func Read(configfile string) {
|
|||||||
if _, err := toml.DecodeFile(configfile, &c); err != nil {
|
if _, err := toml.DecodeFile(configfile, &c); err != nil {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := c.ValidateFields(); err != nil {
|
||||||
|
log.Fatal("Config is not valid: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
Settings = c
|
Settings = c
|
||||||
}
|
}
|
||||||
|
@@ -20,5 +20,18 @@ staticPath = "../static"
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Root
|
// Root
|
||||||
assert.Equal(t, "../static", c)
|
assert.Equal(t, "../static", c.StaticPath)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidation(t *testing.T) {
|
||||||
|
const configContent = ``
|
||||||
|
|
||||||
|
var c config.Config
|
||||||
|
if _, err := toml.Decode(configContent, &c); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := c.ValidateFields()
|
||||||
|
assert.NotNil(t, err)
|
||||||
}
|
}
|
||||||
|
310
sign.go
310
sign.go
@@ -13,13 +13,9 @@ import (
|
|||||||
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"crypto"
|
|
||||||
|
|
||||||
"bitbucket.org/digitorus/pdfsign/config"
|
|
||||||
"bitbucket.org/digitorus/pdfsign/revocation"
|
"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.
|
||||||
@@ -74,144 +70,18 @@ func verifyPDF() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSignDataFlags(f *flag.FlagSet) sign.SignData {
|
|
||||||
// Signature info
|
|
||||||
name := f.String("info-name", config.Settings.Info.Name, "Signature info name")
|
|
||||||
location := f.String("info-location", config.Settings.Info.Location, "Signature info location")
|
|
||||||
reason := f.String("info-reason", config.Settings.Info.Reason, "Signature info reason")
|
|
||||||
contact := f.String("info-contact", config.Settings.Info.ContactInfo, "Signature info contact")
|
|
||||||
// Signature other
|
|
||||||
approval := f.Bool("approval", false, "Approval")
|
|
||||||
certType := f.Uint("type", 0, "Certificate type")
|
|
||||||
|
|
||||||
// TSA
|
|
||||||
tsaUrl := f.String("tsa-url", "", "tsaUrl")
|
|
||||||
tsaUsername := f.String("tsa-username", "", "tsaUsername")
|
|
||||||
tsaPassword := f.String("tsa-password", "", "tsaPassword")
|
|
||||||
|
|
||||||
var sd sign.SignData
|
|
||||||
sd.Signature.Info.Name = *name
|
|
||||||
sd.Signature.Info.Location = *location
|
|
||||||
sd.Signature.Info.Reason = *reason
|
|
||||||
sd.Signature.Info.ContactInfo = *contact
|
|
||||||
sd.Signature.CertType = uint32(*certType)
|
|
||||||
sd.Signature.Approval = *approval
|
|
||||||
sd.TSA.URL = *tsaUrl
|
|
||||||
sd.TSA.Username = *tsaUsername
|
|
||||||
sd.TSA.Password = *tsaPassword
|
|
||||||
return sd
|
|
||||||
}
|
|
||||||
|
|
||||||
func simpleSign() {
|
func simpleSign() {
|
||||||
signCommand := flag.NewFlagSet("sign", flag.ExitOnError)
|
signCommand := flag.NewFlagSet("sign", flag.ExitOnError)
|
||||||
configPath := signCommand.String("config", "", "Path to config file")
|
|
||||||
signCommand.Parse(os.Args[2:])
|
|
||||||
if *configPath != "" {
|
|
||||||
config.Read(*configPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
inputPath := signCommand.String("in", "", "Input PDF file")
|
|
||||||
outputPath := signCommand.String("out", "", "Output PDF file")
|
|
||||||
crtPath := signCommand.String("crt", "", "Certificate")
|
|
||||||
keyPath := signCommand.String("key", "", "Private key")
|
|
||||||
crtChainPath := signCommand.String("chain", "", "Certificate chain")
|
|
||||||
help := signCommand.Bool("help", false, "Show this help")
|
|
||||||
signData := getSignDataFlags(signCommand)
|
|
||||||
signCommand.Parse(os.Args[2:])
|
|
||||||
|
|
||||||
usageText := `usage: pdfsign sign -in input.pdf -out output.pdf -crt certificate.crt -key private_key.key [-chain chain.crt]")
|
|
||||||
Description
|
|
||||||
`
|
|
||||||
if *help == true {
|
|
||||||
fmt.Println(usageText)
|
|
||||||
signCommand.PrintDefaults()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if signCommand.Parsed() == false || *inputPath == "" || *outputPath == "" || *crtPath == "" || *keyPath == "" {
|
|
||||||
fmt.Println(usageText)
|
|
||||||
signCommand.PrintDefaults()
|
|
||||||
os.Exit(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
cert, signer, err := getCertSignerPair(*crtPath, *keyPath)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
} else {
|
|
||||||
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() {
|
|
||||||
signCommand := flag.NewFlagSet("sign", flag.ExitOnError)
|
|
||||||
configPath := signCommand.String("config", "", "Path to config file")
|
|
||||||
signCommand.Parse(os.Args[2:])
|
|
||||||
if *configPath != "" {
|
|
||||||
config.Read(*configPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
input := signCommand.String("in", "", "Input PDF file")
|
input := signCommand.String("in", "", "Input PDF file")
|
||||||
output := signCommand.String("out", "", "Output PDF file")
|
output := signCommand.String("out", "", "Output PDF file")
|
||||||
libPath := signCommand.String("lib", "", "Path to PKCS11 library")
|
crt := signCommand.String("crt", "", "Certificate")
|
||||||
pass := signCommand.String("pass", "", "PKCS11 password")
|
key := signCommand.String("key", "", "Private key")
|
||||||
crtChain := 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")
|
||||||
|
|
||||||
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 := `usageText: pdfsign sign -in input.pdf -out output.pdf -crt certificate.crt -key private_key.key [-chain chain.crt]\n\n")
|
||||||
|
|
||||||
Description
|
Description
|
||||||
|
|
||||||
`
|
`
|
||||||
if *help == true {
|
if *help == true {
|
||||||
fmt.Println(usageText)
|
fmt.Println(usageText)
|
||||||
@@ -219,13 +89,34 @@ Description
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if signCommand.Parsed() == false || *input == "" || *output == "" || *pass == "" {
|
if signCommand.Parsed() == false || *input == "" || *output == "" || *crt == "" || *key == "" {
|
||||||
fmt.Println(usageText)
|
fmt.Println(usageText)
|
||||||
signCommand.PrintDefaults()
|
signCommand.PrintDefaults()
|
||||||
os.Exit(2)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
cert, signer, err := getP11CertSignerPair(*libPath, *pass)
|
certificate_data, err := ioutil.ReadFile(*crt)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
certificate_data_block, _ := pem.Decode(certificate_data)
|
||||||
|
if certificate_data_block == nil {
|
||||||
|
log.Fatal(errors.New("failed to parse PEM block containing the certificate"))
|
||||||
|
}
|
||||||
|
cert, err := x509.ParseCertificate(certificate_data_block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
key_data, err := ioutil.ReadFile(*key)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
key_data_block, _ := pem.Decode(key_data)
|
||||||
|
if key_data_block == nil {
|
||||||
|
log.Fatal(errors.New("failed to parse PEM block containing the private key"))
|
||||||
|
}
|
||||||
|
pkey, err := x509.ParsePKCS1PrivateKey(key_data_block.Bytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -236,55 +127,82 @@ Description
|
|||||||
}
|
}
|
||||||
|
|
||||||
var data sign.SignData
|
var data sign.SignData
|
||||||
|
data.Signer = pkey
|
||||||
data.Certificate = cert
|
data.Certificate = cert
|
||||||
data.Signer = signer
|
|
||||||
data.CertificateChains = certificate_chains
|
data.CertificateChains = certificate_chains
|
||||||
if err := signWithConfig(*input, *output, data); err != nil {
|
signWithConfig(*input, *output, data)
|
||||||
log.Println(err)
|
|
||||||
} else {
|
|
||||||
log.Println("Signed PDF written to " + *output)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getP11CertSignerPair(libPath, pass string) (*x509.Certificate, crypto.Signer, error) {
|
func p11sign() {
|
||||||
var certificate *x509.Certificate
|
//if len(flag.Args()) < 2 {
|
||||||
var signer crypto.Signer
|
// usage()
|
||||||
|
//}
|
||||||
// pkcs11 key
|
//
|
||||||
lib, err := pkcs11.FindLib(libPath)
|
//method := flag.Arg(0)
|
||||||
if err != nil {
|
//if method != "sign" && method != "verify" {
|
||||||
return certificate, signer, err
|
// usage()
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
// Load Library
|
//input := flag.Arg(1)
|
||||||
ctx := pkcs11.New(lib)
|
//if len(input) == 0 {
|
||||||
if ctx == nil {
|
// usage()
|
||||||
return certificate, signer, errors.New("Failed to load library")
|
//}
|
||||||
}
|
//
|
||||||
err = ctx.Initialize()
|
//if method == "verify" {
|
||||||
if err != nil {
|
// input_file, err := os.Open(input)
|
||||||
return certificate, signer, err
|
// if err != nil {
|
||||||
}
|
// log.Fatal(err)
|
||||||
// login
|
// }
|
||||||
session, err := pkcs11.CreateSession(ctx, 0, pass, false)
|
// defer input_file.Close()
|
||||||
if err != nil {
|
//
|
||||||
return certificate, signer, err
|
// resp, err := verify.Verify(input_file)
|
||||||
}
|
// log.Println(resp)
|
||||||
// select the first certificate
|
// if err != nil {
|
||||||
cert, ckaId, err := pkcs11.GetCert(ctx, session, nil)
|
// log.Println(err)
|
||||||
if err != nil {
|
// }
|
||||||
return certificate, signer, err
|
//}
|
||||||
}
|
//
|
||||||
certificate = cert
|
//if method == "sign" {
|
||||||
|
// if len(flag.Args()) < 4 {
|
||||||
// private key
|
// usage()
|
||||||
pkey, err := pkcs11.InitPrivateKey(ctx, session, ckaId)
|
// }
|
||||||
if err != nil {
|
//
|
||||||
return certificate, signer, err
|
// output := flag.Arg(2)
|
||||||
}
|
// if len(output) == 0 {
|
||||||
signer = pkey
|
// usage()
|
||||||
|
// }
|
||||||
return certificate, signer, nil
|
//
|
||||||
|
// // pkcs11 key
|
||||||
|
// lib, err := pkcs11.FindLib("/lib64/libeTPkcs11.so")
|
||||||
|
// if err != nil {
|
||||||
|
// log.Fatal(err)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // Load Library
|
||||||
|
// ctx := pkcs11.New(lib)
|
||||||
|
// if ctx == nil {
|
||||||
|
// log.Fatal("Failed to load library")
|
||||||
|
// }
|
||||||
|
// err = ctx.Initialize()
|
||||||
|
// if err != nil {
|
||||||
|
// log.Fatal(err)
|
||||||
|
// }
|
||||||
|
// // login
|
||||||
|
// session, err := pkcs11.CreateSession(ctx, 0, flag.Arg(3), false)
|
||||||
|
// if err != nil {
|
||||||
|
// log.Fatal(err)
|
||||||
|
// }
|
||||||
|
// // select the first certificate
|
||||||
|
// cert, ckaId, err := pkcs11.GetCert(ctx, session, nil)
|
||||||
|
// if err != nil {
|
||||||
|
// log.Fatal(err)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // private key
|
||||||
|
// pkey, err := pkcs11.InitPrivateKey(ctx, session, ckaId)
|
||||||
|
// if err != nil {
|
||||||
|
// log.Fatal(err)
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCertificateChains(crtChain string, cert *x509.Certificate) ([][]*x509.Certificate, error) {
|
func getCertificateChains(crtChain string, cert *x509.Certificate) ([][]*x509.Certificate, error) {
|
||||||
@@ -308,25 +226,31 @@ func getCertificateChains(crtChain string, cert *x509.Certificate) ([][]*x509.Ce
|
|||||||
return certificate_chains, err
|
return certificate_chains, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func signWithConfig(input, output string, d sign.SignData) error {
|
func signWithConfig(input, output string, data sign.SignData) {
|
||||||
err := sign.SignFile(input, output, sign.SignData{
|
err := sign.SignFile(input, output, sign.SignData{
|
||||||
Signature: sign.SignDataSignature{
|
Signature: sign.SignDataSignature{
|
||||||
Info: sign.SignDataSignatureInfo{
|
Info: sign.SignDataSignatureInfo{
|
||||||
Name: d.Signature.Info.Name,
|
Name: "Jeroen Bobbeldijk",
|
||||||
Location: d.Signature.Info.Location,
|
Location: "Rotterdam",
|
||||||
Reason: d.Signature.Info.Reason,
|
Reason: "Test",
|
||||||
ContactInfo: d.Signature.Info.ContactInfo,
|
ContactInfo: "Geen",
|
||||||
Date: time.Now().Local(),
|
Date: time.Now().Local(),
|
||||||
},
|
},
|
||||||
CertType: d.Signature.CertType,
|
CertType: 2,
|
||||||
Approval: d.Signature.Approval,
|
Approval: false,
|
||||||
|
},
|
||||||
|
Signer: data.Signer,
|
||||||
|
Certificate: data.Certificate,
|
||||||
|
CertificateChains: data.CertificateChains,
|
||||||
|
TSA: sign.TSA{
|
||||||
|
URL: "http://aatl-timestamp.globalsign.com/tsa/aohfewat2389535fnasgnlg5m23",
|
||||||
},
|
},
|
||||||
Signer: d.Signer,
|
|
||||||
Certificate: d.Certificate,
|
|
||||||
CertificateChains: d.CertificateChains,
|
|
||||||
TSA: d.TSA,
|
|
||||||
RevocationData: revocation.InfoArchival{},
|
RevocationData: revocation.InfoArchival{},
|
||||||
RevocationFunction: sign.DefaultEmbedRevocationStatusFunction,
|
RevocationFunction: sign.DefaultEmbedRevocationStatusFunction,
|
||||||
})
|
})
|
||||||
return err
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
} else {
|
||||||
|
log.Println("Signed PDF written to " + output)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user