1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package pkcs9
18
19 import (
20 "bytes"
21 "crypto"
22 "crypto/hmac"
23 "encoding/asn1"
24 "errors"
25 "fmt"
26 "net/http"
27
28 "github.com/sassoftware/relic/lib/pkcs7"
29 "github.com/sassoftware/relic/lib/x509tools"
30 )
31
32
33
34
35 func NewRequest(url string, hash crypto.Hash, hashValue []byte) (msg *TimeStampReq, req *http.Request, err error) {
36 alg, ok := x509tools.PkixDigestAlgorithm(hash)
37 if !ok {
38 return nil, nil, errors.New("unknown digest algorithm")
39 }
40 msg = &TimeStampReq{
41 Version: 1,
42 MessageImprint: MessageImprint{
43 HashAlgorithm: alg,
44 HashedMessage: hashValue,
45 },
46 Nonce: x509tools.MakeSerial(),
47 CertReq: true,
48 }
49 reqbytes, err := asn1.Marshal(*msg)
50 if err != nil {
51 return
52 }
53 req, err = http.NewRequest("POST", url, bytes.NewReader(reqbytes))
54 if err != nil {
55 return
56 }
57 req.Header.Set("Content-Type", "application/timestamp-query")
58 return
59 }
60
61
62 func (req *TimeStampReq) ParseResponse(body []byte) (*pkcs7.ContentInfoSignedData, error) {
63 respmsg := new(TimeStampResp)
64 if rest, err := asn1.Unmarshal(body, respmsg); err != nil {
65 return nil, fmt.Errorf("pkcs9: unmarshalling response: %s", err)
66 } else if len(rest) != 0 {
67 return nil, errors.New("pkcs9: trailing bytes in response")
68 } else if respmsg.Status.Status > StatusGrantedWithMods {
69 return nil, fmt.Errorf("pkcs9: request denied: status=%d failureInfo=%x", respmsg.Status.Status, respmsg.Status.FailInfo.Bytes)
70 }
71 if err := req.SanityCheckToken(&respmsg.TimeStampToken); err != nil {
72 return nil, fmt.Errorf("pkcs9: token sanity check failed: %s", err)
73 }
74 return &respmsg.TimeStampToken, nil
75 }
76
77
78 func (req *TimeStampReq) SanityCheckToken(psd *pkcs7.ContentInfoSignedData) error {
79 if _, err := psd.Content.Verify(nil, false); err != nil {
80 return err
81 }
82 info, err := unpackTokenInfo(psd)
83 if err != nil {
84 return err
85 }
86 if req.Nonce.Cmp(info.Nonce) != 0 {
87 return errors.New("request nonce mismatch")
88 }
89 if !hmac.Equal(info.MessageImprint.HashedMessage, req.MessageImprint.HashedMessage) {
90 return errors.New("message imprint mismatch")
91 }
92 return nil
93 }
94
95
96 func unpackTokenInfo(psd *pkcs7.ContentInfoSignedData) (*TSTInfo, error) {
97 infobytes, err := psd.Content.ContentInfo.Bytes()
98 if err != nil {
99 return nil, fmt.Errorf("unpack TSTInfo: %s", err)
100 } else if infobytes[0] == 0x04 {
101
102 _, err = asn1.Unmarshal(infobytes, &infobytes)
103 if err != nil {
104 return nil, fmt.Errorf("unpack TSTInfo: %s", err)
105 }
106 }
107 info := new(TSTInfo)
108 if _, err := asn1.Unmarshal(infobytes, info); err != nil {
109 return nil, fmt.Errorf("unpack TSTInfo: %s", err)
110 }
111 return info, nil
112 }
113
View as plain text