1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package verification
17
18 import (
19 "bytes"
20 "crypto/x509"
21 "encoding/asn1"
22 "fmt"
23 "hash"
24 "io"
25 "math/big"
26
27 "github.com/digitorus/pkcs7"
28 "github.com/digitorus/timestamp"
29 "github.com/pkg/errors"
30 )
31
32 var (
33
34 EKUOID = asn1.ObjectIdentifier{2, 5, 29, 37}
35 )
36
37
38 type VerifyOpts struct {
39
40
41 OID asn1.ObjectIdentifier
42
43 TSACertificate *x509.Certificate
44
45 Intermediates []*x509.Certificate
46
47 Roots []*x509.Certificate
48
49
50 Nonce *big.Int
51
52 CommonName string
53 }
54
55
56 func verifyESSCertID(tsaCert *x509.Certificate, opts VerifyOpts) error {
57 if opts.TSACertificate == nil {
58 return nil
59 }
60
61 if !bytes.Equal(opts.TSACertificate.RawIssuer, tsaCert.RawIssuer) {
62 return fmt.Errorf("TSR cert issuer does not match provided TSA cert issuer")
63 }
64
65 if opts.TSACertificate.SerialNumber.Cmp(tsaCert.SerialNumber) != 0 {
66 return fmt.Errorf("TSR cert serial number does not match provided TSA cert serial number")
67 }
68
69 return nil
70 }
71
72
73 func verifySubjectCommonName(cert *x509.Certificate, opts VerifyOpts) error {
74 if opts.CommonName == "" {
75 return nil
76 }
77
78 if cert.Subject.CommonName != opts.CommonName {
79 return fmt.Errorf("the certificate's subject Common Name %s does not match the provided Common Name %s", cert.Subject.CommonName, opts.CommonName)
80 }
81 return nil
82 }
83
84
85 func verifyEmbeddedLeafCert(tsaCert *x509.Certificate, opts VerifyOpts) error {
86 if opts.TSACertificate != nil && !opts.TSACertificate.Equal(tsaCert) {
87 return fmt.Errorf("certificate embedded in the TSR does not match the provided TSA certificate")
88 }
89 return nil
90 }
91
92
93 func verifyLeafCertCriticalEKU(cert *x509.Certificate) error {
94 var criticalEKU bool
95 for _, ext := range cert.Extensions {
96 if ext.Id.Equal(EKUOID) {
97 criticalEKU = ext.Critical
98 break
99 }
100 }
101 if !criticalEKU {
102 return errors.New("certificate must set EKU to critical")
103 }
104 return nil
105 }
106
107 func verifyLeafCert(ts timestamp.Timestamp, opts VerifyOpts) error {
108 if len(ts.Certificates) == 0 && opts.TSACertificate == nil {
109 return fmt.Errorf("leaf certificate must be present the in TSR or as a verify option")
110 }
111
112 errMsg := "failed to verify TSA certificate"
113
114 var leafCert *x509.Certificate
115 if len(ts.Certificates) != 0 {
116 leafCert = ts.Certificates[0]
117
118 err := verifyEmbeddedLeafCert(leafCert, opts)
119 if err != nil {
120 return fmt.Errorf("%s: %w", errMsg, err)
121 }
122 } else {
123 leafCert = opts.TSACertificate
124 }
125
126 err := verifyLeafCertCriticalEKU(leafCert)
127 if err != nil {
128 return fmt.Errorf("%s: %w", errMsg, err)
129 }
130
131 err = verifyESSCertID(leafCert, opts)
132 if err != nil {
133 return fmt.Errorf("%s: %w", errMsg, err)
134 }
135
136 err = verifySubjectCommonName(leafCert, opts)
137 if err != nil {
138 return fmt.Errorf("%s: %w", errMsg, err)
139 }
140
141
142
143 err = verifyLeafAndIntermediatesTimestampingEKU(leafCert, opts)
144 if err != nil {
145 return fmt.Errorf("failed to verify EKU on leaf certificate: %w", err)
146 }
147
148 return nil
149 }
150
151 func verifyExtendedKeyUsage(cert *x509.Certificate) error {
152 certEKULen := len(cert.ExtKeyUsage)
153 if certEKULen != 1 {
154 return fmt.Errorf("certificate has %d extended key usages, expected only one", certEKULen)
155 }
156
157 if cert.ExtKeyUsage[0] != x509.ExtKeyUsageTimeStamping {
158 return fmt.Errorf("leaf certificate EKU is not set to TimeStamping as required")
159 }
160 return nil
161 }
162
163
164
165 func verifyLeafAndIntermediatesTimestampingEKU(leafCert *x509.Certificate, opts VerifyOpts) error {
166 err := verifyExtendedKeyUsage(leafCert)
167 if err != nil {
168 return fmt.Errorf("failed to verify EKU on leaf certificate: %w", err)
169 }
170
171 for _, cert := range opts.Intermediates {
172 err := verifyExtendedKeyUsage(cert)
173 if err != nil {
174 return fmt.Errorf("failed to verify EKU on intermediate certificate: %w", err)
175 }
176 }
177 return nil
178 }
179
180
181 func verifyOID(oid []int, opts VerifyOpts) error {
182 if opts.OID == nil {
183 return nil
184 }
185 responseOID := opts.OID
186 if len(oid) != len(responseOID) {
187 return fmt.Errorf("OID lengths do not match")
188 }
189 for i, v := range oid {
190 if v != responseOID[i] {
191 return fmt.Errorf("OID content does not match")
192 }
193 }
194 return nil
195 }
196
197
198 func verifyNonce(requestNonce *big.Int, opts VerifyOpts) error {
199 if opts.Nonce == nil {
200 return nil
201 }
202 if opts.Nonce.Cmp(requestNonce) != 0 {
203 return fmt.Errorf("incoming nonce %d does not match TSR nonce %d", requestNonce, opts.Nonce)
204 }
205 return nil
206 }
207
208
209 func VerifyTimestampResponse(tsrBytes []byte, artifact io.Reader, opts VerifyOpts) (*timestamp.Timestamp, error) {
210
211
212 ts, err := timestamp.ParseResponse(tsrBytes)
213 if err != nil {
214 pe := timestamp.ParseError("")
215 if errors.As(err, &pe) {
216 return nil, fmt.Errorf("timestamp response is not valid: %w", err)
217 }
218 return nil, fmt.Errorf("error parsing response into Timestamp: %w", err)
219 }
220
221
222 if err = verifyTSRWithChain(ts, opts); err != nil {
223 return nil, err
224 }
225
226 if err = verifyNonce(ts.Nonce, opts); err != nil {
227 return nil, err
228 }
229
230 if err = verifyOID(ts.Policy, opts); err != nil {
231 return nil, err
232 }
233
234 if err = verifyLeafCert(*ts, opts); err != nil {
235 return nil, err
236 }
237
238
239 if err = verifyHashedMessages(ts.HashAlgorithm.New(), ts.HashedMessage, artifact); err != nil {
240 return nil, err
241 }
242
243
244 return ts, nil
245 }
246
247 func verifyTSRWithChain(ts *timestamp.Timestamp, opts VerifyOpts) error {
248 p7Message, err := pkcs7.Parse(ts.RawToken)
249 if err != nil {
250 return fmt.Errorf("error parsing hashed message: %w", err)
251 }
252
253 if opts.Roots == nil || len(opts.Roots) == 0 {
254 return fmt.Errorf("no root certificates provided for verifying the certificate chain")
255 }
256
257 rootCertPool := x509.NewCertPool()
258 for _, cert := range opts.Roots {
259 rootCertPool.AddCert(cert)
260 }
261
262 intermediateCertPool := x509.NewCertPool()
263 for _, cert := range opts.Intermediates {
264 intermediateCertPool.AddCert(cert)
265 }
266
267 x509Opts := x509.VerifyOptions{
268 Roots: rootCertPool,
269 Intermediates: intermediateCertPool,
270 }
271
272
273
274
275
276
277
278 if p7Message.Certificates == nil && opts.TSACertificate != nil {
279 p7Message.Certificates = []*x509.Certificate{opts.TSACertificate}
280 }
281
282 err = p7Message.VerifyWithOpts(x509Opts)
283 if err != nil {
284 return fmt.Errorf("error while verifying with chain: %w", err)
285 }
286
287 return nil
288 }
289
290
291 func verifyHashedMessages(hashAlg hash.Hash, hashedMessage []byte, artifactReader io.Reader) error {
292 h := hashAlg
293 if _, err := io.Copy(h, artifactReader); err != nil {
294 return fmt.Errorf("failed to create hash %w", err)
295 }
296 localHashedMsg := h.Sum(nil)
297
298 if !bytes.Equal(localHashedMsg, hashedMessage) {
299 return fmt.Errorf("hashed messages don't match")
300 }
301
302 return nil
303 }
304
View as plain text