File: pki.go

package info (click to toggle)
golang-github-notaryproject-tspclient-go 0.2.0-2
  • links: PTS, VCS
  • area: main
  • in suites: experimental, forky, sid, trixie
  • size: 772 kB
  • sloc: makefile: 20
file content (149 lines) | stat: -rw-r--r-- 5,789 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// Copyright The Notary Project Authors.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package pki contains Status of a timestamping response defined in RFC 3161.
package pki

import (
	"encoding/asn1"
	"errors"
	"fmt"
	"strconv"
)

// ErrUnknownStatus is used when PKIStatus is not supported
var ErrUnknownStatus = errors.New("unknown PKIStatus")

// ErrUnknownFailureInfo is used when PKIFailureInfo is not supported or does
// not exists
var ErrUnknownFailureInfo = errors.New("unknown PKIFailureInfo")

// Status is PKIStatus defined in RFC 3161 2.4.2.
type Status int

const (
	StatusGranted                Status = 0 // you got exactly what you asked for
	StatusGrantedWithMods        Status = 1 // you got something like what you asked for
	StatusRejection              Status = 2 // you don't get it, more information elsewhere in the message
	StatusWaiting                Status = 3 // the request body part has not yet been processed, expect to hear more later
	StatusRevocationWarning      Status = 4 // this message contains a warning that a revocation is imminent
	StatusRevocationNotification Status = 5 // notification that a revocation has occurred
)

// String converts Status to string
func (s Status) String() string {
	switch s {
	case StatusGranted:
		return "granted"
	case StatusGrantedWithMods:
		return "granted with modifications"
	case StatusRejection:
		return "rejected"
	case StatusWaiting:
		return "the request body part has not yet been processed, expect to hear more later"
	case StatusRevocationWarning:
		return "warning: a revocation is imminent"
	case StatusRevocationNotification:
		return "a revocation has occurred"
	default:
		return "unknown PKIStatus " + strconv.Itoa(int(s))
	}
}

// FailureInfo is PKIFailureInfo defined in RFC 3161 2.4.2.
type FailureInfo int

const (
	FailureInfoBadAlg              FailureInfo = 0  // unrecognized or unsupported Algorithm Identifier
	FailureInfoBadRequest          FailureInfo = 2  // transaction not permitted or supported
	FailureInfoBadDataFormat       FailureInfo = 5  // the data submitted has the wrong format
	FailureInfoTimeNotAvailable    FailureInfo = 14 // the TSA's time source is not available
	FailureInfoUnacceptedPolicy    FailureInfo = 15 // the requested TSA policy is not supported by the TSA.
	FailureInfoUnacceptedExtension FailureInfo = 16 // the requested extension is not supported by the TSA.
	FailureInfoAddInfoNotAvailable FailureInfo = 17 // the additional information requested could not be understood or is not available
	FailureInfoSystemFailure       FailureInfo = 25 // the request cannot be handled due to system failure
)

// failureInfos is an array of supported PKIFailureInfo
var failureInfos = []FailureInfo{
	FailureInfoBadAlg,
	FailureInfoBadRequest,
	FailureInfoBadDataFormat,
	FailureInfoTimeNotAvailable,
	FailureInfoUnacceptedPolicy,
	FailureInfoUnacceptedExtension,
	FailureInfoAddInfoNotAvailable,
	FailureInfoSystemFailure,
}

// Error converts a FailureInfo to an error
func (fi FailureInfo) Error() error {
	switch fi {
	case FailureInfoBadAlg:
		return errors.New("unrecognized or unsupported Algorithm Identifier")
	case FailureInfoBadRequest:
		return errors.New("transaction not permitted or supported")
	case FailureInfoBadDataFormat:
		return errors.New("the data submitted has the wrong format")
	case FailureInfoTimeNotAvailable:
		return errors.New("the TSA's time source is not available")
	case FailureInfoUnacceptedPolicy:
		return errors.New("the requested TSA policy is not supported by the TSA")
	case FailureInfoUnacceptedExtension:
		return errors.New("the requested extension is not supported by the TSA")
	case FailureInfoAddInfoNotAvailable:
		return errors.New("the additional information requested could not be understood or is not available")
	case FailureInfoSystemFailure:
		return errors.New("the request cannot be handled due to system failure")
	default:
		return errors.New("unknown PKIFailureInfo " + strconv.Itoa(int(fi)))
	}
}

// StatusInfo contains status codes and failure information for PKI messages.
//
//	PKIStatusInfo ::= SEQUENCE {
//	 status          PKIStatus,
//	 statusString    PKIFreeText     OPTIONAL,
//	 failInfo        PKIFailureInfo  OPTIONAL }
//
//	PKIStatus        ::= INTEGER
//	PKIFreeText      ::= SEQUENCE SIZE (1..MAX) OF UTF8String
//	PKIFailureInfo   ::= BIT STRING
//
// Reference: RFC 3161 2.4.2
type StatusInfo struct {
	Status       Status
	StatusString []string       `asn1:"optional,utf8"`
	FailInfo     asn1.BitString `asn1:"optional"`
}

// Err return nil when si Status is StatusGranted or StatusGrantedWithMods
//
// Otherwise, Err returns an error with FailInfo if any.
func (si StatusInfo) Err() error {
	if si.Status != StatusGranted && si.Status != StatusGrantedWithMods {
		var errs []error
		for _, fi := range failureInfos {
			if si.FailInfo.At(int(fi)) != 0 {
				errs = append(errs, fi.Error())
			}
		}
		if len(errs) != 0 {
			// there is FailInfo, wrap them into a FailureInfoError
			return fmt.Errorf("invalid response with status code %d: %s. Failure info: %w", si.Status, si.Status.String(), &FailureInfoError{Detail: errors.Join(errs...)})
		}
		return fmt.Errorf("invalid response with status code %d: %s", si.Status, si.Status.String())
	}
	return nil
}