Use timestamp package for TSA

This commit is contained in:
Paul van Brouwershaven
2022-06-30 18:05:16 +02:00
parent b0aed91f8a
commit 4fe43c0794
3 changed files with 35 additions and 47 deletions

2
go.mod
View File

@@ -5,7 +5,7 @@ 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/digitorus/timestamp v0.0.0-20220630150916-a1b00e34b289
github.com/mattetti/filebuffer v1.0.1
golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70
)

4
go.sum
View File

@@ -8,6 +8,10 @@ github.com/digitorus/pkcs7 v0.0.0-20200320092839-808436b6f6d1 h1:V1cgDSp4Kq4eMCf
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/digitorus/timestamp v0.0.0-20220630080933-558840f252f5 h1:zYpNMBe+1x3h0FMTJThci7KimEldiiOrn0ENMP6+I/8=
github.com/digitorus/timestamp v0.0.0-20220630080933-558840f252f5/go.mod h1:IKw2TcDeMaZrNjpdq7gPc7I+a21+Sn34bUqWrTc70Hs=
github.com/digitorus/timestamp v0.0.0-20220630150916-a1b00e34b289 h1:WIoYZV4zZKwIymytM65i+WgqyTN/ElCf7KddV01C+0s=
github.com/digitorus/timestamp v0.0.0-20220630150916-a1b00e34b289/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=

View File

@@ -15,18 +15,6 @@ import (
"github.com/digitorus/timestamp"
)
type pkiStatusInfo struct {
Status int
StatusString string `asn1:"optional"`
FailInfo int `asn1:"optional"`
}
// 2.4.2. Response Format
type TSAResponse struct {
Status pkiStatusInfo
TimeStampToken asn1.RawValue
}
var signatureByteRangePlaceholder = "/ByteRange[0 ********** ********** **********]"
func (context *SignContext) createSignaturePlaceholder() (dssd string, byte_range_start_byte int64, signature_contents_start_byte int64) {
@@ -134,7 +122,9 @@ func (context *SignContext) fetchRevocationData() error {
}
func (context *SignContext) createSignature() ([]byte, error) {
context.OutputBuffer.Seek(0, 0)
if _, err := context.OutputBuffer.Seek(0, 0); err != nil {
return nil, err
}
// Sadly we can't efficiently sign a file, we need to read all the bytes we want to sign.
file_content := context.OutputBuffer.Buff.Bytes()
@@ -147,7 +137,7 @@ func (context *SignContext) createSignature() ([]byte, error) {
// Initialize pkcs7 signer.
signed_data, err := pkcs7.NewSignedData(sign_content)
if err != nil {
return nil, err
return nil, fmt.Errorf("new signed data: %w", err)
}
signer_config := pkcs7.SignerInfoConfig{
@@ -167,7 +157,7 @@ func (context *SignContext) createSignature() ([]byte, error) {
// Add the signer and sign the data.
if err := signed_data.AddSignerChain(context.SignData.Certificate, context.SignData.Signer, certificate_chain, signer_config); err != nil {
return nil, err
return nil, fmt.Errorf("add signer chain: %w", err)
}
// PDF needs a detached signature, meaning the content isn't included.
@@ -178,36 +168,26 @@ func (context *SignContext) createSignature() ([]byte, error) {
timestamp_response, err := context.GetTSA(signature_data.SignerInfos[0].EncryptedDigest)
if err != nil {
return nil, err
return nil, fmt.Errorf("get timestamp: %w", err)
}
var rest []byte
var resp TSAResponse
if rest, err = asn1.Unmarshal(timestamp_response, &resp); err != nil {
return nil, err
}
if len(rest) > 0 {
return nil, errors.New("trailing data in Time-Stamp response")
}
if resp.Status.Status > 0 {
return nil, errors.New(fmt.Sprintf("%s: %s", timestamp.FailureInfo(resp.Status.FailInfo).String(), resp.Status.StatusString))
}
_, err = pkcs7.Parse(resp.TimeStampToken.FullBytes)
ts, err := timestamp.ParseResponse(timestamp_response)
if err != nil {
return nil, err
return nil, fmt.Errorf("parse timestamp: %w", err)
}
if len(resp.TimeStampToken.Bytes) == 0 {
return nil, errors.New("no pkcs7 data in Time-Stamp response")
_, err = pkcs7.Parse(ts.RawToken)
if err != nil {
return nil, fmt.Errorf("parse timestamp token: %w", err)
}
timestamp_attribute := pkcs7.Attribute{
Type: asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 16, 2, 14},
Value: resp.TimeStampToken,
Value: asn1.RawValue{FullBytes: ts.RawToken},
}
if err := signature_data.SignerInfos[0].SetUnauthenticatedAttributes([]pkcs7.Attribute{timestamp_attribute}); err != nil {
return nil, err
}
signature_data.SignerInfos[0].SetUnauthenticatedAttributes([]pkcs7.Attribute{timestamp_attribute})
}
return signed_data.Finish()
@@ -219,13 +199,13 @@ func (context *SignContext) GetTSA(sign_content []byte) (timestamp_response []by
Certificates: true,
})
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to create request: %w", err)
}
ts_request_reader := bytes.NewReader(ts_request)
req, err := http.NewRequest("POST", context.SignData.TSA.URL, ts_request_reader)
if err != nil {
return nil, fmt.Errorf("error requesting timestamp (%s): %w", context.SignData.TSA.URL, err)
return nil, fmt.Errorf("failed to prepare request (%s): %w", context.SignData.TSA.URL, err)
}
req.Header.Add("Content-Type", "application/timestamp-query")
@@ -247,18 +227,16 @@ func (context *SignContext) GetTSA(sign_content []byte) (timestamp_response []by
if err == nil {
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
err = errors.New("non success response (" + strconv.Itoa(code) + "): " + string(body))
} else {
err = errors.New("non success response (" + strconv.Itoa(code) + ")")
return nil, errors.New("non success response (" + strconv.Itoa(code) + "): " + string(body))
}
return nil, err
return nil, errors.New("non success response (" + strconv.Itoa(code) + ")")
}
defer resp.Body.Close()
timestamp_response_body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to read response: %w", err)
}
return timestamp_response_body, nil
@@ -267,7 +245,7 @@ func (context *SignContext) GetTSA(sign_content []byte) (timestamp_response []by
func (context *SignContext) replaceSignature() error {
signature, err := context.createSignature()
if err != nil {
return err
return fmt.Errorf("failed to create signature: %w", err)
}
dst := make([]byte, hex.EncodedLen(len(signature)))
@@ -280,17 +258,23 @@ func (context *SignContext) replaceSignature() error {
return context.SignPDF()
}
context.OutputBuffer.Seek(0, 0)
if _, err := context.OutputBuffer.Seek(0, 0); err != nil {
return err
}
file_content := context.OutputBuffer.Buff.Bytes()
context.OutputBuffer.Write(file_content[:(context.ByteRangeValues[0] + context.ByteRangeValues[1] + 1)])
if _, err := context.OutputBuffer.Write(file_content[:(context.ByteRangeValues[0] + context.ByteRangeValues[1] + 1)]); err != nil {
return err
}
// Write new ByteRange.
if _, err := context.OutputBuffer.Write([]byte(dst)); err != nil {
return err
}
context.OutputBuffer.Write(file_content[(context.ByteRangeValues[0]+context.ByteRangeValues[1]+1)+int64(len(dst)):])
if _, err := context.OutputBuffer.Write(file_content[(context.ByteRangeValues[0]+context.ByteRangeValues[1]+1)+int64(len(dst)):]); err != nil {
return err
}
return nil
}