Add sign functionality
This commit is contained in:
149
sign/sign.go
Normal file
149
sign/sign.go
Normal file
@@ -0,0 +1,149 @@
|
||||
package sign
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/x509"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"bitbucket.org/digitorus/pdf"
|
||||
)
|
||||
|
||||
type CatalogData struct {
|
||||
ObjectId uint32
|
||||
Length int64
|
||||
RootString string
|
||||
}
|
||||
|
||||
type SignData struct {
|
||||
ObjectId uint32
|
||||
Signature SignDataSignature
|
||||
Signer crypto.Signer
|
||||
Certificate *x509.Certificate
|
||||
CertificateChain []*x509.Certificate
|
||||
}
|
||||
|
||||
type SignDataSignature struct {
|
||||
Approval bool
|
||||
CertType uint32
|
||||
Info SignDataSignatureInfo
|
||||
}
|
||||
|
||||
type SignDataSignatureInfo struct {
|
||||
Name string
|
||||
Location string
|
||||
Reason string
|
||||
ContactInfo string
|
||||
Date time.Time
|
||||
}
|
||||
|
||||
type SignContext struct {
|
||||
InputFile *os.File
|
||||
OutputFile *os.File
|
||||
SignData SignData
|
||||
CatalogData CatalogData
|
||||
PDFReader *pdf.Reader
|
||||
NewXrefStart int64
|
||||
ByteRangeStartByte int64
|
||||
SignatureContentsStartByte int64
|
||||
ByteRangeValues []int64
|
||||
}
|
||||
|
||||
func SignFile(input string, output string, sign_data SignData) error {
|
||||
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
|
||||
}
|
||||
|
||||
sign_data.ObjectId = uint32(rdr.XrefInformation.ItemCount) + 1
|
||||
|
||||
context := SignContext{
|
||||
PDFReader: rdr,
|
||||
InputFile: input_file,
|
||||
OutputFile: output_file,
|
||||
CatalogData: CatalogData{
|
||||
ObjectId: uint32(rdr.XrefInformation.ItemCount),
|
||||
},
|
||||
SignData: sign_data,
|
||||
}
|
||||
|
||||
err = context.SignPDF()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (context *SignContext) SignPDF() error {
|
||||
// Write the PDF file to the output up til the xref.
|
||||
if err := writePartFromSourceFileToTargetFile(context.InputFile, context.OutputFile, 0, context.PDFReader.XrefInformation.StartPos); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
catalog, err := context.createCatalog()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
context.CatalogData.Length = int64(len(catalog))
|
||||
|
||||
// Write the new catalog object.
|
||||
if _, err := context.OutputFile.Write([]byte(catalog)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create the signature object
|
||||
signature_object, byte_range_start_byte, signature_contents_start_byte := context.createSignaturePlaceholder()
|
||||
|
||||
// Positions are relative to old start position of xref table.
|
||||
byte_range_start_byte += context.PDFReader.XrefInformation.StartPos + int64(len(catalog))
|
||||
signature_contents_start_byte += context.PDFReader.XrefInformation.StartPos + int64(len(catalog))
|
||||
|
||||
context.ByteRangeStartByte = byte_range_start_byte
|
||||
context.SignatureContentsStartByte = signature_contents_start_byte
|
||||
|
||||
// Write the new signature object.
|
||||
if _, err := context.OutputFile.Write([]byte(signature_object)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Calculate the new start position of the xref table.
|
||||
context.NewXrefStart = context.PDFReader.XrefInformation.StartPos + int64(len(signature_object)) + int64(len(catalog))
|
||||
|
||||
if err := context.writeXref(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := context.writeTrailer(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := context.updateByteRange(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := context.replaceSignature(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
Reference in New Issue
Block a user