3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,3 +0,0 @@
|
|||||||
pdfsign
|
|
||||||
certs/
|
|
||||||
.realize/
|
|
@@ -1,58 +0,0 @@
|
|||||||
package config
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/BurntSushi/toml"
|
|
||||||
"github.com/asaskevich/govalidator"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
govalidator.SetFieldsRequiredByDefault(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
DefaultLocation string = "./pdfsign.conf" // Default location of the config file
|
|
||||||
Settings Config // Initialized once inside Read method Settings are stored in memory.
|
|
||||||
)
|
|
||||||
|
|
||||||
// Config is the root of the config
|
|
||||||
type Config struct {
|
|
||||||
//Info:
|
|
||||||
//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) {
|
|
||||||
|
|
||||||
_, err := os.Stat(configfile)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Config file is missing: ", configfile)
|
|
||||||
}
|
|
||||||
|
|
||||||
var c Config
|
|
||||||
if _, err := toml.DecodeFile(configfile, &c); err != nil {
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.ValidateFields(); err != nil {
|
|
||||||
log.Fatal("Config is not valid: ", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
Settings = c
|
|
||||||
}
|
|
@@ -1,37 +0,0 @@
|
|||||||
package config_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"bitbucket.org/digitorus/littlewatcher/src/config"
|
|
||||||
"github.com/BurntSushi/toml"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestConfig(t *testing.T) {
|
|
||||||
const configContent = `
|
|
||||||
staticPath = "../static"
|
|
||||||
`
|
|
||||||
|
|
||||||
var c config.Config
|
|
||||||
|
|
||||||
if _, err := toml.Decode(configContent, &c); err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Root
|
|
||||||
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)
|
|
||||||
}
|
|
318
sign.go
318
sign.go
@@ -11,246 +11,134 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"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"
|
||||||
)
|
)
|
||||||
|
|
||||||
// usage is a usage function for the flags package.
|
|
||||||
func usage() {
|
func usage() {
|
||||||
fmt.Fprintf(os.Stderr, "Pdfsign is a tool to sign and verifyPDF PDF digital signatures\n\n")
|
log.Fatal("Usage: sign input.pdf output.pdf certificate.crt private_key.key [chain.crt] OR verify input.pdf")
|
||||||
fmt.Fprintf(os.Stderr, "Usage:\n\n")
|
|
||||||
fmt.Fprintf(os.Stderr, "\tpdfsign command [arguments]\n\n")
|
|
||||||
fmt.Fprintf(os.Stderr, "The commands are:\n\n")
|
|
||||||
fmt.Fprintf(os.Stderr, "\tsign \t\tsign single PDF document\n")
|
|
||||||
fmt.Fprintf(os.Stderr, "\tverifyPDF \t\tverifyPDF signature of single PDF document\n")
|
|
||||||
fmt.Fprintf(os.Stderr, "\tserve \t\tserve web API with signing capabilities. API documentation url\n")
|
|
||||||
fmt.Fprintf(os.Stderr, "\twatch \t\tautomatically sign PDF files inside a folder\n")
|
|
||||||
fmt.Fprintf(os.Stderr, "\n\n")
|
|
||||||
flag.PrintDefaults()
|
|
||||||
os.Exit(2)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// if no flags provided print usage
|
flag.Parse()
|
||||||
if len(os.Args) == 1 {
|
|
||||||
|
if len(flag.Args()) < 2 {
|
||||||
usage()
|
usage()
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch os.Args[1] {
|
method := flag.Arg(0)
|
||||||
case "sign":
|
if method != "sign" && method != "verify" {
|
||||||
simpleSign()
|
usage()
|
||||||
case "verifyPDF":
|
|
||||||
verifyPDF()
|
|
||||||
case "serve":
|
|
||||||
case "watch":
|
|
||||||
default:
|
|
||||||
fmt.Printf("%q is not valid command.\n", os.Args[1])
|
|
||||||
os.Exit(2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func verifyPDF() {
|
|
||||||
verifyCommand := flag.NewFlagSet("verifyPDF", flag.ExitOnError)
|
|
||||||
input := verifyCommand.String("in", "", "")
|
|
||||||
|
|
||||||
input_file, err := os.Open(*input)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
defer input_file.Close()
|
|
||||||
|
|
||||||
resp, err := verify.Verify(input_file)
|
|
||||||
log.Println(resp)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func simpleSign() {
|
|
||||||
signCommand := flag.NewFlagSet("sign", flag.ExitOnError)
|
|
||||||
input := signCommand.String("in", "", "Input PDF file")
|
|
||||||
output := signCommand.String("out", "", "Output PDF file")
|
|
||||||
crt := signCommand.String("crt", "", "Certificate")
|
|
||||||
key := signCommand.String("key", "", "Private key")
|
|
||||||
crtChain := signCommand.String("chain", "", "Certificate chain")
|
|
||||||
help := signCommand.Bool("help", false, "Show this help")
|
|
||||||
|
|
||||||
signCommand.Parse(os.Args[2:])
|
|
||||||
usageText := `usageText: pdfsign sign -in input.pdf -out output.pdf -crt certificate.crt -key private_key.key [-chain chain.crt]\n\n")
|
|
||||||
Description
|
|
||||||
`
|
|
||||||
if *help == true {
|
|
||||||
fmt.Println(usageText)
|
|
||||||
signCommand.PrintDefaults()
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if signCommand.Parsed() == false || *input == "" || *output == "" || *crt == "" || *key == "" {
|
input := flag.Arg(1)
|
||||||
fmt.Println(usageText)
|
if len(input) == 0 {
|
||||||
signCommand.PrintDefaults()
|
usage()
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
certificate_data, err := ioutil.ReadFile(*crt)
|
if method == "verify" {
|
||||||
if err != nil {
|
input_file, err := os.Open(input)
|
||||||
log.Fatal(err)
|
if err != nil {
|
||||||
}
|
log.Fatal(err)
|
||||||
certificate_data_block, _ := pem.Decode(certificate_data)
|
}
|
||||||
if certificate_data_block == nil {
|
defer input_file.Close()
|
||||||
log.Fatal(errors.New("failed to parse PEM block containing the certificate"))
|
|
||||||
}
|
resp, err := verify.Verify(input_file)
|
||||||
cert, err := x509.ParseCertificate(certificate_data_block.Bytes)
|
log.Println(resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Println(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
key_data, err := ioutil.ReadFile(*key)
|
if method == "sign" {
|
||||||
if err != nil {
|
if len(flag.Args()) < 5 {
|
||||||
log.Fatal(err)
|
usage()
|
||||||
}
|
}
|
||||||
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 {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
certificate_chains, err := getCertificateChains(*crtChain, cert)
|
output := flag.Arg(2)
|
||||||
if err != nil {
|
if len(output) == 0 {
|
||||||
log.Fatal(err)
|
usage()
|
||||||
}
|
}
|
||||||
|
|
||||||
var data sign.SignData
|
certificate_data, err := ioutil.ReadFile(flag.Arg(3))
|
||||||
data.Signer = pkey
|
if err != nil {
|
||||||
data.Certificate = cert
|
log.Fatal(err)
|
||||||
data.CertificateChains = certificate_chains
|
|
||||||
signWithConfig(*input, *output, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func p11sign() {
|
}
|
||||||
//if len(flag.Args()) < 2 {
|
certificate_data_block, _ := pem.Decode(certificate_data)
|
||||||
// usage()
|
if certificate_data_block == nil {
|
||||||
//}
|
log.Fatal(errors.New("failed to parse PEM block containing the certificate"))
|
||||||
//
|
}
|
||||||
//method := flag.Arg(0)
|
|
||||||
//if method != "sign" && method != "verifyPDF" {
|
|
||||||
// usage()
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//input := flag.Arg(1)
|
|
||||||
//if len(input) == 0 {
|
|
||||||
// usage()
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//if method == "verifyPDF" {
|
|
||||||
// input_file, err := os.Open(input)
|
|
||||||
// if err != nil {
|
|
||||||
// log.Fatal(err)
|
|
||||||
// }
|
|
||||||
// defer input_file.Close()
|
|
||||||
//
|
|
||||||
// resp, err := verify.Verify(input_file)
|
|
||||||
// log.Println(resp)
|
|
||||||
// if err != nil {
|
|
||||||
// log.Println(err)
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//if method == "sign" {
|
|
||||||
// if len(flag.Args()) < 4 {
|
|
||||||
// usage()
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// output := flag.Arg(2)
|
|
||||||
// if len(output) == 0 {
|
|
||||||
// usage()
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // 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) {
|
cert, err := x509.ParseCertificate(certificate_data_block.Bytes)
|
||||||
certificate_chains := make([][]*x509.Certificate, 0)
|
if err != nil {
|
||||||
if crtChain == "" {
|
log.Fatal(err)
|
||||||
return certificate_chains, nil
|
}
|
||||||
}
|
|
||||||
|
|
||||||
chain_data, err := ioutil.ReadFile(crtChain)
|
key_data, err := ioutil.ReadFile(flag.Arg(4))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
certificate_pool := x509.NewCertPool()
|
key_data_block, _ := pem.Decode(key_data)
|
||||||
certificate_pool.AppendCertsFromPEM(chain_data)
|
if key_data_block == nil {
|
||||||
certificate_chains, err = cert.Verify(x509.VerifyOptions{
|
log.Fatal(errors.New("failed to parse PEM block containing the private key"))
|
||||||
Intermediates: certificate_pool,
|
}
|
||||||
CurrentTime: cert.NotBefore,
|
|
||||||
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
|
|
||||||
})
|
|
||||||
|
|
||||||
return certificate_chains, err
|
pkey, err := x509.ParsePKCS1PrivateKey(key_data_block.Bytes)
|
||||||
}
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
func signWithConfig(input, output string, data sign.SignData) {
|
certificate_chains := make([][]*x509.Certificate, 0)
|
||||||
err := sign.SignFile(input, output, sign.SignData{
|
|
||||||
Signature: sign.SignDataSignature{
|
if flag.Arg(5) != "" {
|
||||||
Info: sign.SignDataSignatureInfo{
|
certificate_pool := x509.NewCertPool()
|
||||||
Name: "Jeroen Bobbeldijk",
|
if err != nil {
|
||||||
Location: "Rotterdam",
|
log.Fatal(err)
|
||||||
Reason: "Test",
|
}
|
||||||
ContactInfo: "Geen",
|
|
||||||
Date: time.Now().Local(),
|
chain_data, err := ioutil.ReadFile(flag.Arg(5))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
certificate_pool.AppendCertsFromPEM(chain_data)
|
||||||
|
certificate_chains, err = cert.Verify(x509.VerifyOptions{
|
||||||
|
Intermediates: certificate_pool,
|
||||||
|
CurrentTime: cert.NotBefore,
|
||||||
|
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = sign.SignFile(input, output, sign.SignData{
|
||||||
|
Signature: sign.SignDataSignature{
|
||||||
|
Info: sign.SignDataSignatureInfo{
|
||||||
|
Name: "Jeroen Bobbeldijk",
|
||||||
|
Location: "Rotterdam",
|
||||||
|
Reason: "Test",
|
||||||
|
ContactInfo: "Geen",
|
||||||
|
Date: time.Now().Local(),
|
||||||
|
},
|
||||||
|
CertType: 2,
|
||||||
|
Approval: false,
|
||||||
},
|
},
|
||||||
CertType: 2,
|
Signer: pkey,
|
||||||
Approval: false,
|
Certificate: cert,
|
||||||
},
|
CertificateChains: certificate_chains,
|
||||||
Signer: data.Signer,
|
TSA: sign.TSA{
|
||||||
Certificate: data.Certificate,
|
URL: "http://aatl-timestamp.globalsign.com/tsa/aohfewat2389535fnasgnlg5m23",
|
||||||
CertificateChains: data.CertificateChains,
|
},
|
||||||
TSA: sign.TSA{
|
RevocationData: revocation.InfoArchival{},
|
||||||
URL: "http://aatl-timestamp.globalsign.com/tsa/aohfewat2389535fnasgnlg5m23",
|
RevocationFunction: sign.DefaultEmbedRevocationStatusFunction,
|
||||||
},
|
})
|
||||||
RevocationData: revocation.InfoArchival{},
|
if err != nil {
|
||||||
RevocationFunction: sign.DefaultEmbedRevocationStatusFunction,
|
log.Println(err)
|
||||||
})
|
} else {
|
||||||
if err != nil {
|
log.Println("Signed PDF written to " + output)
|
||||||
log.Println(err)
|
}
|
||||||
} else {
|
|
||||||
log.Println("Signed PDF written to " + output)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -12,11 +12,11 @@ import (
|
|||||||
|
|
||||||
"bitbucket.org/digitorus/pdf"
|
"bitbucket.org/digitorus/pdf"
|
||||||
"bitbucket.org/digitorus/pdfsign/revocation"
|
"bitbucket.org/digitorus/pdfsign/revocation"
|
||||||
"crypto"
|
|
||||||
"github.com/digitorus/pkcs7"
|
"github.com/digitorus/pkcs7"
|
||||||
"github.com/digitorus/timestamp"
|
"github.com/digitorus/timestamp"
|
||||||
"golang.org/x/crypto/ocsp"
|
|
||||||
"log"
|
"log"
|
||||||
|
"golang.org/x/crypto/ocsp"
|
||||||
|
"crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Response struct {
|
type Response struct {
|
||||||
|
Reference in New Issue
Block a user