Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: cms package #181

Closed
wants to merge 32 commits into from
Closed
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
9532a70
Squashed commit of the following:
JeyJeyGao Nov 29, 2023
d7b0dfd
test: add unit test
JeyJeyGao Dec 7, 2023
b4a9974
fix: add license
JeyJeyGao Dec 7, 2023
e9e197a
fix: optimize test
JeyJeyGao Dec 7, 2023
04ec318
fix: update test
JeyJeyGao Dec 7, 2023
bc10be8
fix: update comment
JeyJeyGao Dec 7, 2023
61b69a5
fix: resolve comments
JeyJeyGao Dec 20, 2023
6b38b5c
fix: resolve comments
JeyJeyGao Dec 25, 2023
130f0aa
fix: update
JeyJeyGao Dec 25, 2023
11152dd
fix: update
JeyJeyGao Dec 25, 2023
5c41184
fix: remove common errors
JeyJeyGao Dec 25, 2023
de606a7
feat: added cms
JeyJeyGao Dec 26, 2023
a235ec2
fix: resolve comment
JeyJeyGao Jan 2, 2024
b2e46de
fix: update code
JeyJeyGao Jan 3, 2024
92506db
fix: resolve comments
JeyJeyGao Jan 4, 2024
4b6650a
fix: add signer info version validation
JeyJeyGao Jan 4, 2024
7b3b7df
fix: resolve comments
JeyJeyGao Jan 5, 2024
fd195f9
test: add part of the unit test
JeyJeyGao Jan 5, 2024
a1f356a
fix: add unit test for signed attributes
JeyJeyGao Jan 8, 2024
f1a72e8
test: add part of the unit test
JeyJeyGao Jan 8, 2024
3d022f1
Squashed commit of the following:
JeyJeyGao Jan 8, 2024
eeaef58
Squashed commit of the following:
JeyJeyGao Jan 8, 2024
323dec0
fix: added VerifySigner
JeyJeyGao Jan 11, 2024
7680cf8
fix: update test
JeyJeyGao Jan 11, 2024
c4889e8
fix: export GetCertificate
JeyJeyGao Jan 15, 2024
fee5145
fix: update Verify process
JeyJeyGao Jan 15, 2024
b4d80e7
test: add the test with an invalid signer info and a valid signer info
JeyJeyGao Jan 15, 2024
1218829
Merge branch 'main' into feat/cms_pkg
JeyJeyGao Jan 15, 2024
4f6e3c1
fix: update VerifySigner
JeyJeyGao Jan 15, 2024
d05f4f4
fix: resolve comments
JeyJeyGao Jan 16, 2024
818f7c0
fix: add ctx
JeyJeyGao Jan 16, 2024
4c97c11
fix(test): update test comment
JeyJeyGao Jan 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
185 changes: 185 additions & 0 deletions internal/crypto/cms/cms.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,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 signatures in Cryptographic Message Syntax (CMS) / PKCS7
// defined in RFC 5652.
JeyJeyGao marked this conversation as resolved.
Show resolved Hide resolved
//
// References:
// - RFC 5652 Cryptographic Message Syntax (CMS): https://datatracker.ietf.org/doc/html/rfc5652
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
}

// Attributes struct is used to represent a collection of attributes.
//
// 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"`
}

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

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