File: cms.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 (185 lines) | stat: -rw-r--r-- 6,370 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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
// 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 cms verifies Signed-Data defined in RFC 5652 Cryptographic Message
// Syntax (CMS) / PKCS7
//
// References:
// - RFC 5652 Cryptographic Message Syntax (CMS)
package cms

import (
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/asn1"
	"math/big"
)

// ContentInfo struct is used to represent the content of a CMS message,
// which can be encrypted, signed, or both.
//
// References: RFC 5652 3 ContentInfo Type
//
//	ContentInfo ::= SEQUENCE {
//	  contentType ContentType,
//	  content [0] EXPLICIT ANY DEFINED BY contentType }
type ContentInfo struct {
	// ContentType field specifies the type of the content, which can be one of
	// several predefined types, such as data, signedData, envelopedData, or
	// encryptedData. Only signedData is supported currently.
	ContentType asn1.ObjectIdentifier

	// Content field contains the actual content of the message.
	Content asn1.RawValue `asn1:"explicit,tag:0"`
}

// SignedData struct is used to represent a signed CMS message, which contains
// one or more signatures that are used to verify the authenticity and integrity
// of the message.
//
// Reference: RFC 5652 5.1 SignedData
//
//	SignedData ::= SEQUENCE {
//	 version             CMSVersion,
//	 digestAlgorithms    DigestAlgorithmIdentifiers,
//	 encapContentInfo    EncapsulatedContentInfo,
//	 certificates        [0] IMPLICIT CertificateSet             OPTIONAL,
//	 crls                [1] IMPLICIT CertificateRevocationLists OPTIONAL,
//	 signerInfos         SignerInfos }
type SignedData struct {
	// Version field specifies the syntax version number of the SignedData.
	Version int

	// DigestAlgorithmIdentifiers field specifies the digest algorithms used
	// by one or more signatures in SignerInfos.
	DigestAlgorithmIdentifiers []pkix.AlgorithmIdentifier `asn1:"set"`

	// EncapsulatedContentInfo field specifies the content that is signed.
	EncapsulatedContentInfo EncapsulatedContentInfo

	// Certificates field contains the certificates that are used to verify the
	// signatures in SignerInfos.
	Certificates asn1.RawValue `asn1:"optional,tag:0"`

	// CRLs field contains the Certificate Revocation Lists that are used to
	// verify the signatures in SignerInfos.
	CRLs []x509.RevocationList `asn1:"optional,tag:1"`

	// SignerInfos field contains one or more signatures.
	SignerInfos []SignerInfo `asn1:"set"`
}

// EncapsulatedContentInfo struct is used to represent the content of a CMS
// message.
//
// References: RFC 5652 5.2 EncapsulatedContentInfo
//
//	EncapsulatedContentInfo ::= SEQUENCE {
//	 eContentType    ContentType,
//	 eContent        [0] EXPLICIT OCTET STRING   OPTIONAL }
type EncapsulatedContentInfo struct {
	// ContentType is an object identifier. The object identifier uniquely
	// specifies the content type.
	ContentType asn1.ObjectIdentifier

	// Content field contains the actual content of the message.
	Content []byte `asn1:"explicit,optional,tag:0"`
}

// SignerInfo struct is used to represent a signature and related information
// that is needed to verify the signature.
//
// Reference: RFC 5652 5.3 SignerInfo
//
//	SignerInfo ::= SEQUENCE {
//	 version             CMSVersion,
//	 sid                 SignerIdentifier,
//	 digestAlgorithm     DigestAlgorithmIdentifier,
//	 signedAttrs         [0] IMPLICIT SignedAttributes   OPTIONAL,
//	 signatureAlgorithm  SignatureAlgorithmIdentifier,
//	 signature           SignatureValue,
//	 unsignedAttrs       [1] IMPLICIT UnsignedAttributes OPTIONAL }
//
// Only version 1 is supported. As defined in RFC 5652 5.3, SignerIdentifier
// is IssuerAndSerialNumber when version is 1.
type SignerInfo struct {
	// Version field specifies the syntax version number of the SignerInfo.
	Version int

	// SignerIdentifier field specifies the signer's certificate. Only IssuerAndSerialNumber
	// is supported currently.
	SignerIdentifier IssuerAndSerialNumber

	// DigestAlgorithm field specifies the digest algorithm used by the signer.
	DigestAlgorithm pkix.AlgorithmIdentifier

	// SignedAttributes field contains a collection of attributes that are
	// signed.
	SignedAttributes Attributes `asn1:"optional,tag:0"`

	// SignatureAlgorithm field specifies the signature algorithm used by the
	// signer.
	SignatureAlgorithm pkix.AlgorithmIdentifier

	// Signature field contains the actual signature.
	Signature []byte

	// UnsignedAttributes field contains a collection of attributes that are
	// not signed.
	UnsignedAttributes Attributes `asn1:"optional,tag:1"`
}

// IssuerAndSerialNumber struct is used to identify a certificate.
//
// Reference: RFC 5652 5.3 SignerIdentifier
//
//	IssuerAndSerialNumber ::= SEQUENCE {
//	 issuer          Name,
//	 serialNumber    CertificateSerialNumber }
type IssuerAndSerialNumber struct {
	// Issuer field identifies the certificate issuer.
	Issuer asn1.RawValue

	// SerialNumber field identifies the certificate.
	SerialNumber *big.Int
}

// Attribute struct is used to represent a attribute with type and values.
//
// Reference: RFC 5652 5.3 SignerInfo
//
//	Attribute ::= SEQUENCE {
//	  attrType    OBJECT IDENTIFIER,
//	  attrValues  SET OF AttributeValue }
type Attribute struct {
	// Type field specifies the type of the attribute.
	Type asn1.ObjectIdentifier

	// Values field contains the actual value of the attribute.
	Values asn1.RawValue `asn1:"set"`
}

// Attributes ::= SET SIZE (0..MAX) OF Attribute
type Attributes []Attribute

// Get tries to find the attribute by the given identifier, parse and store
// the result in the value pointed to by out.
func (a Attributes) Get(identifier asn1.ObjectIdentifier, out any) error {
	for _, attribute := range a {
		if identifier.Equal(attribute.Type) {
			_, err := asn1.Unmarshal(attribute.Values.Bytes, out)
			return err
		}
	}
	return ErrAttributeNotFound
}