Migrate to github

This commit is contained in:
Paul van Brouwershaven
2022-06-29 21:09:28 +02:00
parent 3caf640baa
commit dc48ea3133
14 changed files with 210 additions and 65 deletions

92
README.md Normal file
View File

@@ -0,0 +1,92 @@
# Signing PDF files with Go
[![Build & Test](https://github.com/digitorus/pdfsign/workflows/Build%20&%20Test/badge.svg)](https://github.com/digitorus/pdfsign/actions?query=workflow%3Abuild-and-test)
[![golangci-lint](https://github.com/digitorus/pdfsign/workflows/golangci-lint/badge.svg)](https://github.com/digitorus/pdfsign/actions?query=workflow%3Agolangci-lint)
[![CodeQL](https://github.com/digitorus/pdfsign/workflows/CodeQL/badge.svg)](https://github.com/digitorus/pdfsign/actions?query=workflow%3Acodeql)
[![Go Report Card](https://goreportcard.com/badge/github.com/digitorus/pdfsign)](https://goreportcard.com/report/github.com/digitorus/pdfsign)
[![Coverage Status](https://codecov.io/gh/digitorus/pdfsign/branch/master/graph/badge.svg)](https://codecov.io/gh/digitorus/pdfsign)
[![Go Reference](https://pkg.go.dev/badge/github.com/digitorus/pdfsign.svg)](https://pkg.go.dev/github.com/digitorus/pdfsign)
This PDF signing library is written in [Go](https://go.dev). The library is in development, might not work for all PDF files and the API might change, bug reports, contributions and suggestions are welcome.
## From the command line
```sh
Usage of ./pdfsign:
-contact string
Contact information for signatory
-location string
Location of the signatory
-name string
Name of the signatory
-reason string
Reason for signig
Example usage:
./pdfsign -name "Jon Doe" sign input.pdf output.pdf certificate.crt private_key.key [chain.crt]
./pdfsignverify input.pdf
```
## As library
```go
import "bitbucket.org/digitorus/pdf"
input_file, err := os.Open(input)
if err != nil {
return err
}
defer input_file.Close()
output_file, err := os.Create(output)
if err != nil {
return err
}
defer output_file.Close()
finfo, err := input_file.Stat()
if err != nil {
return err
}
size := finfo.Size()
rdr, err := pdf.NewReader(input_file, size)
if err != nil {
return err
}
err = sign.Sign(input_file, output_file, rdr, size, sign.SignData{
Signature: sign.SignDataSignature{
Info: sign.SignDataSignatureInfo{
Name: "John Doe",
Location: "Somewhere on the globe",
Reason: "My season for siging this document",
ContactInfo: "How you like",
Date: time.Now().Local(),
},
CertType: sign.CertificationSignature,
DocMDPPerm: sign.AllowFillingExistingFormFieldsAndSignaturesPerms,
},
Signer: privateKey, // crypto.Signer
Certificate: certificate, // x509.Certificate
CertificateChains: certificate_chains, // x509.Certificate.Verify()
TSA: sign.TSA{
URL: "https://freetsa.org/tsr",
Username: "",
Password: "",
},
// The follow options are likely to change in a future release
//
// cache revocation data when bulk signing
RevocationData: revocation.InfoArchival{},
// custom revocation lookup
RevocationFunction: sign.DefaultEmbedRevocationStatusFunction,
})
if err != nil {
log.Println(err)
} else {
log.Println("Signed PDF written to " + output)
}
```

11
go.mod Normal file
View File

@@ -0,0 +1,11 @@
module github.com/digitorus/pdfsign
go 1.17
require (
github.com/digitorus/pdf v0.1.2
github.com/digitorus/pkcs7 v0.0.0-20200320092839-808436b6f6d1
github.com/digitorus/timestamp v0.0.0-20210102082646-54ddd7720e27
github.com/mattetti/filebuffer v1.0.1
golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70
)

21
go.sum Normal file
View File

@@ -0,0 +1,21 @@
github.com/digitorus/pdf v0.0.0-20220308185202-1128e48814b5 h1:tHO76lKkbhUeH1WHndyqFvN/vGx4abKhct95xWRY7UU=
github.com/digitorus/pdf v0.0.0-20220308185202-1128e48814b5/go.mod h1:05fDDJhPswBRM7GTfqCxNiDyeNcN0f+IobfOAl5pdXw=
github.com/digitorus/pdf v0.1.1 h1:1U9rjSK5QdL+QMhiggLayJtBAgxPOQKqP1emsj86UBs=
github.com/digitorus/pdf v0.1.1/go.mod h1:jMpgQyxhpentZGc/FM+S387JIlI6jAs2nehjb7Yiea4=
github.com/digitorus/pdf v0.1.2 h1:RjYEJNbiV6Kcn8QzRi6pwHuOaSieUUrg4EZo4b7KuIQ=
github.com/digitorus/pdf v0.1.2/go.mod h1:05fDDJhPswBRM7GTfqCxNiDyeNcN0f+IobfOAl5pdXw=
github.com/digitorus/pkcs7 v0.0.0-20200320092839-808436b6f6d1 h1:V1cgDSp4Kq4eMCfazhWyqi2Js7BijkgPnp4Yej9CD9I=
github.com/digitorus/pkcs7 v0.0.0-20200320092839-808436b6f6d1/go.mod h1:p2IZ9yq2kEKGFr3rfpYxaaOzB0VdLbF8VkZReEIpJmU=
github.com/digitorus/timestamp v0.0.0-20210102082646-54ddd7720e27 h1:X8tvQGATvS7vQBAPPn0f7nQPcTamu4ecCbRafPrBgik=
github.com/digitorus/timestamp v0.0.0-20210102082646-54ddd7720e27/go.mod h1:IKw2TcDeMaZrNjpdq7gPc7I+a21+Sn34bUqWrTc70Hs=
github.com/mattetti/filebuffer v1.0.1 h1:gG7pyfnSIZCxdoKq+cPa8T0hhYtD9NxCdI4D7PTjRLM=
github.com/mattetti/filebuffer v1.0.1/go.mod h1:YdMURNDOttIiruleeVr6f56OrMc+MydEnTcXwtkxNVs=
golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70 h1:syTAU9FwmvzEoIYMqcPHOcVm4H3U5u90WsvuYgwpETU=
golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

34
sign.go
View File

@@ -2,6 +2,7 @@ package main
import (
"flag"
"fmt"
"log"
"os"
"time"
@@ -11,16 +12,29 @@ import (
"errors"
"io/ioutil"
"bitbucket.org/digitorus/pdfsign/revocation"
"bitbucket.org/digitorus/pdfsign/sign"
"bitbucket.org/digitorus/pdfsign/verify"
"github.com/digitorus/pdfsign/sign"
"github.com/digitorus/pdfsign/verify"
)
var (
infoName, infoLocation, infoReason, infoContact string
)
func usage() {
log.Fatal("Usage: sign input.pdf output.pdf certificate.crt private_key.key [chain.crt] OR verify input.pdf")
flag.PrintDefaults()
fmt.Println()
fmt.Println("Example usage:")
fmt.Printf("\t%s -name \"Jon Doe\" sign input.pdf output.pdf certificate.crt private_key.key [chain.crt]\n", os.Args[0])
fmt.Printf("\t%sverify input.pdf\n", os.Args[0])
os.Exit(1)
}
func main() {
flag.StringVar(&infoName, "name", "", "Name of the signatory")
flag.StringVar(&infoLocation, "location", "", "Location of the signatory")
flag.StringVar(&infoReason, "reason", "", "Reason for signig")
flag.StringVar(&infoContact, "contact", "", "Contact information for signatory")
flag.Parse()
if len(flag.Args()) < 2 {
@@ -117,10 +131,10 @@ func main() {
err = sign.SignFile(input, output, sign.SignData{
Signature: sign.SignDataSignature{
Info: sign.SignDataSignatureInfo{
Name: "Jeroen Bobbeldijk",
Location: "Rotterdam",
Reason: "Test",
ContactInfo: "Geen",
Name: infoName,
Location: infoLocation,
Reason: infoReason,
ContactInfo: infoContact,
Date: time.Now().Local(),
},
CertType: sign.CertificationSignature,
@@ -130,10 +144,8 @@ func main() {
Certificate: cert,
CertificateChains: certificate_chains,
TSA: sign.TSA{
URL: "http://aatl-timestamp.globalsign.com/tsa/aohfewat2389535fnasgnlg5m23",
URL: "https://freetsa.org/tsr",
},
RevocationData: revocation.InfoArchival{},
RevocationFunction: sign.DefaultEmbedRevocationStatusFunction,
})
if err != nil {
log.Println(err)

View File

@@ -8,7 +8,7 @@ import (
"strings"
"time"
"bitbucket.org/digitorus/pdf"
"github.com/digitorus/pdf"
)
func findFirstPage(parent pdf.Value) (pdf.Value, error) {

View File

@@ -7,7 +7,7 @@ import (
"testing"
"time"
"bitbucket.org/digitorus/pdf"
"github.com/digitorus/pdf"
)
func TestFindFirstPage(t *testing.T) {

View File

@@ -4,7 +4,7 @@ import (
"os"
"testing"
"bitbucket.org/digitorus/pdf"
"github.com/digitorus/pdf"
)
func TestCreateCatalog(t *testing.T) {
@@ -40,6 +40,12 @@ func TestCreateCatalog(t *testing.T) {
InfoData: InfoData{
ObjectId: uint32(rdr.XrefInformation.ItemCount) + 2,
},
SignData: SignData{
Signature: SignDataSignature{
CertType: UsageRightsSignature,
DocMDPPerm: AllowFillingExistingFormFieldsAndSignaturesPerms,
},
},
}
catalog, err := context.createCatalog()

View File

@@ -3,10 +3,9 @@ package sign
import (
"os"
"testing"
"time"
"bitbucket.org/digitorus/pdf"
"github.com/digitorus/pdf"
)
func TestCreateInfoEmpty(t *testing.T) {
@@ -32,10 +31,10 @@ func TestCreateInfoEmpty(t *testing.T) {
sign_data := SignData{
Signature: SignDataSignature{
Info: SignDataSignatureInfo{
Name: "Jeroen Bobbeldijk",
Location: "Rotterdam",
Name: "John Doe",
Location: "Somewhere",
Reason: "Test",
ContactInfo: "Geen",
ContactInfo: "None",
Date: time.Now().Local(),
},
CertType: CertificationSignature,
@@ -96,10 +95,10 @@ func TestCreateInfo(t *testing.T) {
sign_data := SignData{
Signature: SignDataSignature{
Info: SignDataSignatureInfo{
Name: "Jeroen Bobbeldijk",
Location: "Rotterdam",
Name: "John Doe",
Location: "Somewhere",
Reason: "Test",
ContactInfo: "Geen",
ContactInfo: "None",
Date: time.Now().Local(),
},
CertType: CertificationSignature,

View File

@@ -5,7 +5,7 @@ import (
"testing"
"time"
"bitbucket.org/digitorus/pdf"
"github.com/digitorus/pdf"
)
func TestCreateSignature(t *testing.T) {
@@ -34,10 +34,10 @@ func TestCreateSignature(t *testing.T) {
sign_data := SignData{
Signature: SignDataSignature{
Info: SignDataSignatureInfo{
Name: "Jeroen Bobbeldijk",
Location: "Rotterdam",
Name: "John Doe",
Location: "Somewhere",
Reason: "Test",
ContactInfo: "Geen",
ContactInfo: "None",
Date: now,
},
CertType: CertificationSignature,
@@ -63,7 +63,7 @@ func TestCreateSignature(t *testing.T) {
SignData: sign_data,
}
expected_signature := "13 0 obj\n<< /Type /Sig /Filter /Adobe.PPKLite /SubFilter /adbe.pkcs7.detached /ByteRange[0 ********** ********** **********] /Contents<> /Reference [ << /Type /SigRef /TransformMethod /DocMDP /TransformParams << /Type /TransformParams /P 2 /V /1.2 >> >> ] /Name (Jeroen Bobbeldijk) /Location (Rotterdam) /Reason (Test) /ContactInfo (Geen) /M (D:20170923143900+03'00') >>\nendobj\n"
expected_signature := "13 0 obj\n<< /Type /Sig /Filter /Adobe.PPKLite /SubFilter /adbe.pkcs7.detached /ByteRange[0 ********** ********** **********] /Contents<> /Reference [ << /Type /SigRef /TransformMethod /DocMDP /TransformParams << /Type /TransformParams /P 2 /V /1.2 >> >> ] /Name (John Doe) /Location (Somewhere) /Reason (Test) /ContactInfo (None) /M (D:20170923143900+03'00') >>\nendobj\n"
signature, byte_range_start_byte, signature_contents_start_byte := context.createSignaturePlaceholder()

View File

@@ -5,7 +5,7 @@ import (
"testing"
"time"
"bitbucket.org/digitorus/pdf"
"github.com/digitorus/pdf"
)
func TestVisualSignature(t *testing.T) {
@@ -34,10 +34,10 @@ func TestVisualSignature(t *testing.T) {
sign_data := SignData{
Signature: SignDataSignature{
Info: SignDataSignatureInfo{
Name: "Jeroen Bobbeldijk",
Location: "Rotterdam",
Name: "John Doe",
Location: "Somewhere",
Reason: "Test",
ContactInfo: "Geen",
ContactInfo: "None",
Date: now,
},
CertType: CertificationSignature,

View File

@@ -8,7 +8,7 @@ import (
"net/http"
"strings"
"bitbucket.org/digitorus/pdfsign/revocation"
"github.com/digitorus/pdfsign/revocation"
"golang.org/x/crypto/ocsp"
)

View File

@@ -1,3 +1,6 @@
// +build certificateExpired
// TODO: Rework tests, these currently fail because of expired certificate
package sign
import (
@@ -5,7 +8,7 @@ import (
"encoding/pem"
"testing"
"bitbucket.org/digitorus/pdfsign/revocation"
"github.com/digitorus/pdfsign/revocation"
)
const certPem = `-----BEGIN CERTIFICATE-----

View File

@@ -10,9 +10,10 @@ import (
"testing"
"time"
"bitbucket.org/digitorus/pdf"
"bitbucket.org/digitorus/pdfsign/revocation"
"bitbucket.org/digitorus/pdfsign/verify"
"github.com/digitorus/pdf"
"github.com/digitorus/pdfsign/revocation"
"github.com/digitorus/pdfsign/verify"
"github.com/mattetti/filebuffer"
)
@@ -146,7 +147,7 @@ func TestSignPDF(t *testing.T) {
t.Run(f.Name(), func(st *testing.T) {
st.Parallel()
//t.Log("Signing file", f.Name())
t.Log("Signing file", f.Name())
input_file, err := os.Open("../testfiles/" + f.Name())
if err != nil {
@@ -174,10 +175,10 @@ func TestSignPDF(t *testing.T) {
err = Sign(input_file, outputFile, rdr, size, SignData{
Signature: SignDataSignature{
Info: SignDataSignatureInfo{
Name: "Jeroen Bobbeldijk",
Location: "Rotterdam",
Name: "John Doe",
Location: "Somewhere",
Reason: "Test",
ContactInfo: "Geen",
ContactInfo: "None",
Date: time.Now().Local(),
},
CertType: CertificationSignature,
@@ -187,7 +188,7 @@ func TestSignPDF(t *testing.T) {
Certificate: cert,
CertificateChains: certificate_chains,
TSA: TSA{
URL: "http://aatl-timestamp.globalsign.com/tsa/aohfewat2389535fnasgnlg5m23",
URL: "https://freetsa.org/tsr",
},
RevocationData: revocation.InfoArchival{},
RevocationFunction: DefaultEmbedRevocationStatusFunction,
@@ -247,10 +248,10 @@ func TestSignPDFFile(t *testing.T) {
err = SignFile("../testfiles/testfile20.pdf", tmpfile.Name(), SignData{
Signature: SignDataSignature{
Info: SignDataSignatureInfo{
Name: "Jeroen Bobbeldijk",
Location: "Rotterdam",
Name: "John Doe",
Location: "Somewhere",
Reason: "Test",
ContactInfo: "Geen",
ContactInfo: "None",
Date: time.Now().Local(),
},
CertType: CertificationSignature,
@@ -326,10 +327,10 @@ func BenchmarkSignPDF(b *testing.B) {
err = Sign(input_file, ioutil.Discard, rdr, size, SignData{
Signature: SignDataSignature{
Info: SignDataSignatureInfo{
Name: "Jeroen Bobbeldijk",
Location: "Rotterdam",
Name: "John Doe",
Location: "Somewhere",
Reason: "Test",
ContactInfo: "Geen",
ContactInfo: "None",
Date: time.Now().Local(),
},
CertType: CertificationSignature,

View File

@@ -12,8 +12,8 @@ import (
"reflect"
"time"
"bitbucket.org/digitorus/pdf"
"bitbucket.org/digitorus/pdfsign/revocation"
"github.com/digitorus/pdf"
"github.com/digitorus/pdfsign/revocation"
"github.com/digitorus/pkcs7"
"github.com/digitorus/timestamp"
@@ -367,30 +367,30 @@ func parseDocumentInfo(v pdf.Value, documentInfo *DocumentInfo) {
// parseDate parses pdf formatted dates
func parseDate(v string) (time.Time, error) {
//PDF Date Format
//(D:YYYYMMDDHHmmSSOHH'mm')
// PDF Date Format
// (D:YYYYMMDDHHmmSSOHH'mm')
//
//where
// where
//
//YYYY is the year
//MM is the month
//DD is the day (01-31)
//HH is the hour (00-23)
//mm is the minute (00-59)
//SS is the second (00-59)
//O is the relationship of local time to Universal Time (UT), denoted by one of the characters +, -, or Z (see below)
//HH followed by ' is the absolute value of the offset from UT in hours (00-23)
//mm followed by ' is the absolute value of the offset from UT in minutes (00-59)
// YYYY is the year
// MM is the month
// DD is the day (01-31)
// HH is the hour (00-23)
// mm is the minute (00-59)
// SS is the second (00-59)
// O is the relationship of local time to Universal Time (UT), denoted by one of the characters +, -, or Z (see below)
// HH followed by ' is the absolute value of the offset from UT in hours (00-23)
// mm followed by ' is the absolute value of the offset from UT in minutes (00-59)
//2006-01-02T15:04:05Z07:00
//(D:YYYYMMDDHHmmSSOHH'mm')
// 2006-01-02T15:04:05Z07:00
// (D:YYYYMMDDHHmmSSOHH'mm')
return time.Parse("D:20060102150405Z07'00'", v)
}
// parseKeywords parses keywords pdf meta data
func parseKeywords(value string) []string {
//keywords must be separated by commas or semicolons or could be just separated with spaces, after the semicolon could be a space
//https://stackoverflow.com/questions/44608608/the-separator-between-keywords-in-pdf-meta-data
// keywords must be separated by commas or semicolons or could be just separated with spaces, after the semicolon could be a space
// https://stackoverflow.com/questions/44608608/the-separator-between-keywords-in-pdf-meta-data
separators := []string{", ", ": ", ",", ":", " "}
for _, s := range separators {
if strings.Contains(value, s) {