1
2
3 package timestamp
4
5 import (
6 "crypto"
7 "crypto/rand"
8 "crypto/x509"
9 "crypto/x509/pkix"
10 "encoding/asn1"
11 "fmt"
12 "io"
13 "math/big"
14 "strconv"
15 "strings"
16 "time"
17
18 "github.com/digitorus/pkcs7"
19 )
20
21
22
23 type FailureInfo int
24
25 const (
26
27 UnknownFailureInfo FailureInfo = -1
28
29 BadAlgorithm FailureInfo = 0
30
31 BadRequest FailureInfo = 2
32
33 BadDataFormat FailureInfo = 5
34
35 TimeNotAvailable FailureInfo = 14
36
37
38 UnacceptedPolicy FailureInfo = 15
39
40
41 UnacceptedExtension FailureInfo = 16
42
43
44 AddInfoNotAvailable FailureInfo = 17
45
46
47 SystemFailure FailureInfo = 25
48 )
49
50 func (f FailureInfo) String() string {
51 switch f {
52 case BadAlgorithm:
53 return "unrecognized or unsupported Algorithm Identifier"
54 case BadRequest:
55 return "transaction not permitted or supported"
56 case BadDataFormat:
57 return "the data submitted has the wrong format"
58 case TimeNotAvailable:
59 return "the TSA's time source is not available"
60 case UnacceptedPolicy:
61 return "the requested TSA policy is not supported by the TSA"
62 case UnacceptedExtension:
63 return "the requested extension is not supported by the TSA"
64 case AddInfoNotAvailable:
65 return "the additional information requested could not be understood or is not available"
66 case SystemFailure:
67 return "the request cannot be handled due to system failure"
68 default:
69 return "unknown failure"
70 }
71 }
72
73
74
75 type Status int
76
77 const (
78
79
80 Granted Status = 0
81
82
83 GrantedWithMods Status = 1
84
85 Rejection Status = 2
86
87 Waiting Status = 3
88
89 RevocationWarning Status = 4
90
91 RevocationNotification Status = 5
92 )
93
94 func (s Status) String() string {
95 switch s {
96 case Granted:
97 return "the request is granted"
98 case GrantedWithMods:
99 return "the request is granted with modifications"
100 case Rejection:
101 return "the request is rejected"
102 case Waiting:
103 return "the request is waiting"
104 case RevocationWarning:
105 return "revocation is imminent"
106 case RevocationNotification:
107 return "revocation has occurred"
108 default:
109 return "unknown status: " + strconv.Itoa(int(s))
110 }
111 }
112
113
114 type ParseError string
115
116 func (p ParseError) Error() string {
117 return string(p)
118 }
119
120
121
122 type Request struct {
123 HashAlgorithm crypto.Hash
124 HashedMessage []byte
125
126
127
128 Certificates bool
129
130
131
132 TSAPolicyOID asn1.ObjectIdentifier
133
134
135
136 Nonce *big.Int
137
138
139
140
141
142
143 Extensions []pkix.Extension
144
145
146
147
148
149
150 ExtraExtensions []pkix.Extension
151 }
152
153
154 func ParseRequest(bytes []byte) (*Request, error) {
155 var err error
156 var rest []byte
157 var req request
158
159 if rest, err = asn1.Unmarshal(bytes, &req); err != nil {
160 return nil, err
161 }
162 if len(rest) > 0 {
163 return nil, ParseError("trailing data in Time-Stamp request")
164 }
165
166 if len(req.MessageImprint.HashedMessage) == 0 {
167 return nil, ParseError("Time-Stamp request contains no hashed message")
168 }
169
170 hashFunc := getHashAlgorithmFromOID(req.MessageImprint.HashAlgorithm.Algorithm)
171 if hashFunc == crypto.Hash(0) {
172 return nil, ParseError("Time-Stamp request uses unknown hash function")
173 }
174
175 return &Request{
176 HashAlgorithm: hashFunc,
177 HashedMessage: req.MessageImprint.HashedMessage,
178 Certificates: req.CertReq,
179 Nonce: req.Nonce,
180 TSAPolicyOID: req.ReqPolicy,
181 Extensions: req.Extensions,
182 }, nil
183 }
184
185
186 func (req *Request) Marshal() ([]byte, error) {
187 request := request{
188 Version: 1,
189 MessageImprint: messageImprint{
190 HashAlgorithm: pkix.AlgorithmIdentifier{
191 Algorithm: getOIDFromHashAlgorithm(req.HashAlgorithm),
192 Parameters: asn1.RawValue{
193 Tag: 5,
194 },
195 },
196 HashedMessage: req.HashedMessage,
197 },
198 CertReq: req.Certificates,
199 Extensions: req.ExtraExtensions,
200 }
201
202 if req.TSAPolicyOID != nil {
203 request.ReqPolicy = req.TSAPolicyOID
204 }
205 if req.Nonce != nil {
206 request.Nonce = req.Nonce
207 }
208 reqBytes, err := asn1.Marshal(request)
209 if err != nil {
210 return nil, err
211 }
212 return reqBytes, nil
213 }
214
215
216
217 type Timestamp struct {
218
219 RawToken []byte
220
221 HashAlgorithm crypto.Hash
222 HashedMessage []byte
223
224 Time time.Time
225 Accuracy time.Duration
226 SerialNumber *big.Int
227 Policy asn1.ObjectIdentifier
228 Ordering bool
229 Nonce *big.Int
230 Qualified bool
231
232 Certificates []*x509.Certificate
233
234
235 AddTSACertificate bool
236
237
238
239
240
241
242 Extensions []pkix.Extension
243
244
245
246
247
248 ExtraExtensions []pkix.Extension
249 }
250
251
252
253
254
255
256 func ParseResponse(bytes []byte) (*Timestamp, error) {
257 var err error
258 var rest []byte
259 var resp response
260
261 if rest, err = asn1.Unmarshal(bytes, &resp); err != nil {
262 return nil, err
263 }
264 if len(rest) > 0 {
265 return nil, ParseError("trailing data in Time-Stamp response")
266 }
267
268 if resp.Status.Status > 0 {
269 var fis string
270 fi := resp.Status.FailureInfo()
271 if fi != UnknownFailureInfo {
272 fis = fi.String()
273 }
274 return nil, fmt.Errorf("%s: %s (%v)",
275 resp.Status.Status.String(),
276 strings.Join(resp.Status.StatusString, ","),
277 fis)
278 }
279
280 if len(resp.TimeStampToken.Bytes) == 0 {
281 return nil, ParseError("no pkcs7 data in Time-Stamp response")
282 }
283
284 return Parse(resp.TimeStampToken.FullBytes)
285 }
286
287
288
289
290
291
292 func Parse(bytes []byte) (*Timestamp, error) {
293 var addTSACertificate bool
294 p7, err := pkcs7.Parse(bytes)
295 if err != nil {
296 return nil, err
297 }
298
299 if len(p7.Certificates) > 0 {
300 if err = p7.Verify(); err != nil {
301 return nil, err
302 }
303 addTSACertificate = true
304 } else {
305 addTSACertificate = false
306 }
307
308 var inf tstInfo
309 if _, err = asn1.Unmarshal(p7.Content, &inf); err != nil {
310 return nil, err
311 }
312
313 if len(inf.MessageImprint.HashedMessage) == 0 {
314 return nil, ParseError("Time-Stamp response contains no hashed message")
315 }
316
317 ret := &Timestamp{
318 RawToken: bytes,
319 HashedMessage: inf.MessageImprint.HashedMessage,
320 Time: inf.Time,
321 Accuracy: time.Duration((time.Second * time.Duration(inf.Accuracy.Seconds)) +
322 (time.Millisecond * time.Duration(inf.Accuracy.Milliseconds)) +
323 (time.Microsecond * time.Duration(inf.Accuracy.Microseconds))),
324 SerialNumber: inf.SerialNumber,
325 Policy: inf.Policy,
326 Ordering: inf.Ordering,
327 Nonce: inf.Nonce,
328 Certificates: p7.Certificates,
329 AddTSACertificate: addTSACertificate,
330 Extensions: inf.Extensions,
331 }
332
333 ret.HashAlgorithm = getHashAlgorithmFromOID(inf.MessageImprint.HashAlgorithm.Algorithm)
334 if ret.HashAlgorithm == crypto.Hash(0) {
335 return nil, ParseError("Time-Stamp response uses unknown hash function")
336 }
337
338 if oidInExtensions(asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 3}, inf.Extensions) {
339 ret.Qualified = true
340 }
341 return ret, nil
342 }
343
344
345 type RequestOptions struct {
346
347
348 Hash crypto.Hash
349
350
351 Certificates bool
352
353
354
355 TSAPolicyOID asn1.ObjectIdentifier
356
357
358
359 Nonce *big.Int
360 }
361
362 func (opts *RequestOptions) hash() crypto.Hash {
363 if opts == nil || opts.Hash == 0 {
364 return crypto.SHA256
365 }
366 return opts.Hash
367 }
368
369
370
371 func CreateRequest(r io.Reader, opts *RequestOptions) ([]byte, error) {
372 hashFunc := opts.hash()
373
374 if !hashFunc.Available() {
375 return nil, x509.ErrUnsupportedAlgorithm
376 }
377 h := opts.hash().New()
378
379 b := make([]byte, h.Size())
380 for {
381 n, err := r.Read(b)
382 if err == io.EOF {
383 break
384 }
385
386 _, err = h.Write(b[:n])
387 if err != nil {
388 return nil, fmt.Errorf("failed to create hash")
389 }
390 }
391
392 req := &Request{
393 HashAlgorithm: opts.hash(),
394 HashedMessage: h.Sum(nil),
395 }
396 if opts != nil {
397 req.Certificates = opts.Certificates
398 }
399 if opts != nil && opts.TSAPolicyOID != nil {
400 req.TSAPolicyOID = opts.TSAPolicyOID
401 }
402 if opts != nil && opts.Nonce != nil {
403 req.Nonce = opts.Nonce
404 }
405 return req.Marshal()
406 }
407
408
409
410
411
412
413 func (t *Timestamp) CreateResponseWithOpts(signingCert *x509.Certificate, priv crypto.Signer, opts crypto.SignerOpts) ([]byte, error) {
414 messageImprint := getMessageImprint(t.HashAlgorithm, t.HashedMessage)
415
416 tsaSerialNumber, err := generateTSASerialNumber()
417 if err != nil {
418 return nil, err
419 }
420 tstInfo, err := t.populateTSTInfo(messageImprint, t.Policy, tsaSerialNumber, signingCert)
421 if err != nil {
422 return nil, err
423 }
424 signature, err := t.generateSignedData(tstInfo, priv, signingCert, opts)
425 if err != nil {
426 return nil, err
427 }
428 timestampRes := response{
429 Status: pkiStatusInfo{
430 Status: Granted,
431 },
432 TimeStampToken: asn1.RawValue{FullBytes: signature},
433 }
434 tspResponseBytes, err := asn1.Marshal(timestampRes)
435 if err != nil {
436 return nil, err
437 }
438 return tspResponseBytes, nil
439 }
440
441
442
443
444
445
446
447
448
449
450 func (t *Timestamp) CreateResponse(signingCert *x509.Certificate, priv crypto.Signer) ([]byte, error) {
451 return t.CreateResponseWithOpts(signingCert, priv, crypto.SHA256)
452 }
453
454
455 func CreateErrorResponse(pkiStatus Status, pkiFailureInfo FailureInfo) ([]byte, error) {
456 var bs asn1.BitString
457 setFlag(&bs, int(pkiFailureInfo))
458
459 timestampRes := response{
460 Status: pkiStatusInfo{
461 Status: pkiStatus,
462 FailInfo: bs,
463 },
464 }
465 tspResponseBytes, err := asn1.Marshal(timestampRes)
466 if err != nil {
467 return nil, err
468 }
469 return tspResponseBytes, nil
470 }
471
472 func setFlag(bs *asn1.BitString, i int) {
473 for l := len(bs.Bytes); l < 4; l++ {
474 (*bs).Bytes = append((*bs).Bytes, byte(0))
475 (*bs).BitLength = len((*bs).Bytes) * 8
476 }
477 b := i / 8
478 p := uint(7 - (i - 8*b))
479 (*bs).Bytes[b] = (*bs).Bytes[b] | (1 << p)
480 bs.BitLength = asn1BitLength(bs.Bytes)
481 bs.Bytes = bs.Bytes[0 : (bs.BitLength/8)+1]
482 }
483
484 func getMessageImprint(hashAlgorithm crypto.Hash, hashedMessage []byte) messageImprint {
485 messageImprint := messageImprint{
486 HashAlgorithm: pkix.AlgorithmIdentifier{
487 Algorithm: getOIDFromHashAlgorithm(hashAlgorithm),
488 Parameters: asn1.NullRawValue,
489 },
490 HashedMessage: hashedMessage,
491 }
492 return messageImprint
493 }
494
495 func generateTSASerialNumber() (*big.Int, error) {
496 randomBytes := make([]byte, 20)
497 _, err := rand.Read(randomBytes)
498 if err != nil {
499 return nil, err
500 }
501 serialNumber := big.NewInt(0)
502 serialNumber = serialNumber.SetBytes(randomBytes)
503 return serialNumber, nil
504 }
505
506 func (t *Timestamp) populateTSTInfo(messageImprint messageImprint, policyOID asn1.ObjectIdentifier, tsaSerialNumber *big.Int, tsaCert *x509.Certificate) ([]byte, error) {
507 dirGeneralName, err := asn1.Marshal(asn1.RawValue{Tag: 4, Class: 2, IsCompound: true, Bytes: tsaCert.RawSubject})
508 if err != nil {
509 return nil, err
510 }
511 tstInfo := tstInfo{
512 Version: 1,
513 Policy: policyOID,
514 MessageImprint: messageImprint,
515 SerialNumber: tsaSerialNumber,
516 Time: t.Time,
517 TSA: asn1.RawValue{Tag: 0, Class: 2, IsCompound: true, Bytes: dirGeneralName},
518 Ordering: t.Ordering,
519 }
520 if t.Nonce != nil {
521 tstInfo.Nonce = t.Nonce
522 }
523 if t.Accuracy != 0 {
524 if t.Accuracy < time.Microsecond {
525
526 tstInfo.Accuracy.Microseconds = 1
527 } else {
528 seconds := t.Accuracy.Truncate(time.Second)
529 tstInfo.Accuracy.Seconds = int64(seconds.Seconds())
530 ms := (t.Accuracy - seconds).Truncate(time.Millisecond)
531 if ms != 0 {
532 tstInfo.Accuracy.Milliseconds = int64(ms.Milliseconds())
533 }
534 microSeconds := (t.Accuracy - seconds - ms).Truncate(time.Microsecond)
535 if microSeconds != 0 {
536 tstInfo.Accuracy.Microseconds = int64(microSeconds.Microseconds())
537 }
538 }
539 }
540 if len(t.ExtraExtensions) != 0 {
541 tstInfo.Extensions = t.ExtraExtensions
542 }
543 if t.Qualified && !oidInExtensions(asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 3}, t.ExtraExtensions) {
544 qcStatements := []qcStatement{{
545 StatementID: asn1.ObjectIdentifier{0, 4, 0, 19422, 1, 1},
546 }}
547 asn1QcStats, err := asn1.Marshal(qcStatements)
548 if err != nil {
549 return nil, err
550 }
551 tstInfo.Extensions = append(tstInfo.Extensions, pkix.Extension{
552 Id: []int{1, 3, 6, 1, 5, 5, 7, 1, 3},
553 Value: asn1QcStats,
554 Critical: false,
555 })
556 }
557 tstInfoBytes, err := asn1.Marshal(tstInfo)
558 if err != nil {
559 return nil, err
560 }
561 return tstInfoBytes, nil
562 }
563
564 func (t *Timestamp) populateSigningCertificateV2Ext(certificate *x509.Certificate) ([]byte, error) {
565 if !t.HashAlgorithm.Available() {
566 return nil, x509.ErrUnsupportedAlgorithm
567 }
568 if t.HashAlgorithm.HashFunc() == crypto.SHA1 {
569 return nil, fmt.Errorf("for SHA1 use ESSCertID instead of ESSCertIDv2")
570 }
571
572 h := t.HashAlgorithm.HashFunc().New()
573 _, err := h.Write(certificate.Raw)
574 if err != nil {
575 return nil, fmt.Errorf("failed to create hash")
576 }
577
578 var hashAlg pkix.AlgorithmIdentifier
579
580
581 if t.HashAlgorithm.HashFunc() != crypto.SHA256 {
582 hashAlg = pkix.AlgorithmIdentifier{
583 Algorithm: hashOIDs[t.HashAlgorithm.HashFunc()],
584 Parameters: asn1.NullRawValue,
585 }
586 }
587
588 signingCertificateV2 := signingCertificateV2{
589 Certs: []essCertIDv2{{
590 HashAlgorithm: hashAlg,
591 CertHash: h.Sum(nil),
592 IssuerSerial: issuerAndSerial{
593 IssuerName: generalNames{
594 Name: asn1.RawValue{Tag: 4, Class: 2, IsCompound: true, Bytes: certificate.RawIssuer},
595 },
596 SerialNumber: certificate.SerialNumber,
597 },
598 }},
599 }
600 signingCertV2Bytes, err := asn1.Marshal(signingCertificateV2)
601 if err != nil {
602 return nil, err
603 }
604 return signingCertV2Bytes, nil
605 }
606
607
608
609 func digestAlgorithmToOID(hash crypto.Hash) (asn1.ObjectIdentifier, error) {
610 switch hash {
611 case crypto.SHA1:
612 return pkcs7.OIDDigestAlgorithmSHA1, nil
613 case crypto.SHA256:
614 return pkcs7.OIDDigestAlgorithmSHA256, nil
615 case crypto.SHA384:
616 return pkcs7.OIDDigestAlgorithmSHA384, nil
617 case crypto.SHA512:
618 return pkcs7.OIDDigestAlgorithmSHA512, nil
619 }
620 return nil, pkcs7.ErrUnsupportedAlgorithm
621 }
622
623 func (t *Timestamp) generateSignedData(tstInfo []byte, signer crypto.Signer, certificate *x509.Certificate, opts crypto.SignerOpts) ([]byte, error) {
624 signedData, err := pkcs7.NewSignedData(tstInfo)
625 if err != nil {
626 return nil, err
627 }
628
629 alg, err := digestAlgorithmToOID(opts.HashFunc())
630 if err != nil {
631 return nil, err
632 }
633 signedData.SetDigestAlgorithm(alg)
634 signedData.SetContentType(asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 16, 1, 4})
635 signedData.GetSignedData().Version = 3
636
637 signingCertV2Bytes, err := t.populateSigningCertificateV2Ext(certificate)
638 if err != nil {
639 return nil, err
640 }
641
642 signerInfoConfig := pkcs7.SignerInfoConfig{
643 ExtraSignedAttributes: []pkcs7.Attribute{
644 {
645 Type: asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 16, 2, 47},
646 Value: asn1.RawValue{FullBytes: signingCertV2Bytes},
647 },
648 },
649 }
650 if !t.AddTSACertificate {
651 signerInfoConfig.SkipCertificates = true
652 }
653
654 if len(t.Certificates) > 0 {
655 err = signedData.AddSignerChain(certificate, signer, t.Certificates, signerInfoConfig)
656 } else {
657 err = signedData.AddSigner(certificate, signer, signerInfoConfig)
658 }
659 if err != nil {
660 return nil, err
661 }
662
663 signature, err := signedData.Finish()
664 if err != nil {
665 return nil, err
666 }
667 return signature, nil
668 }
669
670
671
672
673 func oidInExtensions(oid asn1.ObjectIdentifier, extensions []pkix.Extension) bool {
674 for _, e := range extensions {
675 if e.Id.Equal(oid) {
676 return true
677 }
678 }
679 return false
680 }
681
View as plain text