methods for creating protocol types

This commit is contained in:
Ben Toews 2017-11-20 16:08:10 -07:00
Родитель 0fc8e3cc0d
Коммит 05aed43318
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: E9C423BE17EFEE70
7 изменённых файлов: 276 добавлений и 40 удалений

Просмотреть файл

@ -10,6 +10,11 @@ type AnySet struct {
Elements []asn1.RawValue `asn1:"set"`
}
// NewAnySet creates a new AnySet.
func NewAnySet(elts ...asn1.RawValue) AnySet {
return AnySet{elts}
}
// DecodeAnySet manually decodes a SET OF ANY type, since Go's parser can't
// handle them.
func DecodeAnySet(rv asn1.RawValue) (as AnySet, err error) {

Просмотреть файл

@ -53,8 +53,8 @@ var (
// X509 extensions
oidSubjectKeyIdentifier = asn1.ObjectIdentifier{2, 5, 29, 14}
// digestAlgorithmHash maps digest OIDs to crypto.Hash values.
digestAlgorithmHash = map[string]crypto.Hash{
// digestAlgorithmToHash maps digest OIDs to crypto.Hash values.
digestAlgorithmToHash = map[string]crypto.Hash{
oidDigestAlgorithmSHA1.String(): crypto.SHA1,
oidDigestAlgorithmMD5.String(): crypto.MD5,
oidDigestAlgorithmSHA256.String(): crypto.SHA256,
@ -62,9 +62,23 @@ var (
oidDigestAlgorithmSHA512.String(): crypto.SHA512,
}
// signatureAlgorithmToDigestAlgorithm maps x509.SignatureAlgorithm to
// digestAlgorithm OIDs.
signatureAlgorithmToDigestAlgorithm = map[x509.SignatureAlgorithm]asn1.ObjectIdentifier{
x509.SHA1WithRSA: oidDigestAlgorithmSHA1,
x509.MD5WithRSA: oidDigestAlgorithmMD5,
x509.SHA256WithRSA: oidDigestAlgorithmSHA256,
x509.SHA384WithRSA: oidDigestAlgorithmSHA384,
x509.SHA512WithRSA: oidDigestAlgorithmSHA512,
x509.ECDSAWithSHA1: oidDigestAlgorithmSHA1,
x509.ECDSAWithSHA256: oidDigestAlgorithmSHA256,
x509.ECDSAWithSHA384: oidDigestAlgorithmSHA384,
x509.ECDSAWithSHA512: oidDigestAlgorithmSHA512,
}
// digestAlgorithmHash maps digest and signature OIDs to
// x509.SignatureAlgorithm values.
signatureAlgorithmHash = map[string]map[string]x509.SignatureAlgorithm{
signatureAlgorithms = map[string]map[string]x509.SignatureAlgorithm{
oidSignatureAlgorithmRSA.String(): map[string]x509.SignatureAlgorithm{
oidDigestAlgorithmSHA1.String(): x509.SHA1WithRSA,
oidDigestAlgorithmMD5.String(): x509.MD5WithRSA,
@ -119,6 +133,25 @@ type EncapsulatedContentInfo struct {
EContent asn1.RawValue `asn1:"optional,explicit,tag:0"`
}
// NewDataEncapsulatedContentInfo creates a new EncapsulatedContentInfo of type
// id-data.
func NewDataEncapsulatedContentInfo(data []byte) (EncapsulatedContentInfo, error) {
octetString, err := asn1.Marshal(data)
if err != nil {
return EncapsulatedContentInfo{}, err
}
return EncapsulatedContentInfo{
EContentType: oidData,
EContent: asn1.RawValue{
Class: asn1.ClassContextSpecific,
Tag: 0,
Bytes: octetString,
IsCompound: true,
},
}, nil
}
// DataEContent gets the EContent assuming EContentType is data. A nil byte
// slice is returned if the OPTIONAL eContent field is missing.
func (eci EncapsulatedContentInfo) DataEContent() ([]byte, error) {
@ -152,6 +185,27 @@ type Attribute struct {
RawValue asn1.RawValue
}
// NewAttribute creates a single-value Attribute.
func NewAttribute(typ asn1.ObjectIdentifier, val interface{}) (attr Attribute, err error) {
var der []byte
if der, err = asn1.Marshal(val); err != nil {
return
}
var rv asn1.RawValue
if _, err = asn1.Unmarshal(der, &rv); err != nil {
return
}
if err = NewAnySet(rv).Encode(&attr.RawValue); err != nil {
return
}
attr.Type = typ
return
}
// Value further decodes the attribute Value as a SET OF ANY, which Go's asn1
// parser can't handle directly.
func (a Attribute) Value() (AnySet, error) {
@ -243,6 +297,29 @@ type IssuerAndSerialNumber struct {
SerialNumber *big.Int
}
// NewIssuerAndSerialNumber creates a IssuerAndSerialNumber SID for the given
// cert.
func NewIssuerAndSerialNumber(cert *x509.Certificate) (rv asn1.RawValue, err error) {
sid := IssuerAndSerialNumber{
SerialNumber: new(big.Int).Set(cert.SerialNumber),
}
if _, err = asn1.Unmarshal(cert.RawIssuer, &sid.Issuer); err != nil {
return
}
var der []byte
if der, err = asn1.Marshal(sid); err != nil {
return
}
if _, err = asn1.Unmarshal(der, &rv); err != nil {
return
}
return
}
// SignerInfo ::= SEQUENCE {
// version CMSVersion,
// sid SignerIdentifier,
@ -342,7 +419,7 @@ func (si SignerInfo) subjectKeyIdentifierSID() ([]byte, error) {
// Hash gets the crypto.Hash associated with this SignerInfo's DigestAlgorithm.
// 0 is returned for unrecognized algorithms.
func (si SignerInfo) Hash() crypto.Hash {
return digestAlgorithmHash[si.DigestAlgorithm.Algorithm.String()]
return digestAlgorithmToHash[si.DigestAlgorithm.Algorithm.String()]
}
// X509SignatureAlgorithm gets the x509.SignatureAlgorithm that should be used
@ -353,7 +430,7 @@ func (si SignerInfo) X509SignatureAlgorithm() x509.SignatureAlgorithm {
digestOID = si.DigestAlgorithm.Algorithm.String()
)
return signatureAlgorithmHash[sigOID][digestOID]
return signatureAlgorithms[sigOID][digestOID]
}
// GetContentTypeAttribute gets the signed ContentType attribute from the

Просмотреть файл

@ -11,27 +11,170 @@ import (
"time"
)
func TestEncapsulatedContentInfo(t *testing.T) {
ci, _ := ParseContentInfo(fixtureSignatureOpenSSLAttached)
sd, _ := ci.SignedDataContent()
oldECI := sd.EncapContentInfo
oldData, err := oldECI.DataEContent()
if err != nil {
t.Fatal(err)
}
newECI, err := NewDataEncapsulatedContentInfo(oldData)
if err != nil {
t.Fatal(err)
}
newData, err := newECI.DataEContent()
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(oldData, newData) {
t.Fatal("ECI data round trip mismatch: ", oldData, " != ", newData)
}
oldDER, err := asn1.Marshal(oldECI)
if err != nil {
t.Fatal(err)
}
newDER, err := asn1.Marshal(newECI)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(oldDER, newDER) {
t.Fatal("ECI round trip mismatch: ", oldDER, " != ", newDER)
}
}
func TestMessageDigestAttribute(t *testing.T) {
ci, _ := ParseContentInfo(fixtureSignatureOpenSSLAttached)
sd, _ := ci.SignedDataContent()
si := sd.SignerInfos[0]
oldAttrVal, err := si.GetMessageDigestAttribute()
if err != nil {
t.Fatal(err)
}
var oldAttr Attribute
for _, attr := range si.SignedAttrs {
if attr.Type.Equal(oidAttributeMessageDigest) {
oldAttr = attr
break
}
}
newAttr, err := NewAttribute(oidAttributeMessageDigest, oldAttrVal)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(oldAttr.RawValue.Bytes, newAttr.RawValue.Bytes) {
t.Fatal("raw value mismatch")
}
oldDER, err := asn1.Marshal(oldAttr)
if err != nil {
t.Fatal(err)
}
newDER, err := asn1.Marshal(newAttr)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(oldDER, newDER) {
t.Fatal("der mismatch")
}
}
func TestContentTypeAttribute(t *testing.T) {
ci, _ := ParseContentInfo(fixtureSignatureOpenSSLAttached)
sd, _ := ci.SignedDataContent()
si := sd.SignerInfos[0]
oldAttrVal, err := si.GetContentTypeAttribute()
if err != nil {
t.Fatal(err)
}
var oldAttr Attribute
for _, attr := range si.SignedAttrs {
if attr.Type.Equal(oidAttributeContentType) {
oldAttr = attr
break
}
}
newAttr, err := NewAttribute(oidAttributeContentType, oldAttrVal)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(oldAttr.RawValue.Bytes, newAttr.RawValue.Bytes) {
t.Fatal("raw value mismatch")
}
oldDER, err := asn1.Marshal(oldAttr)
if err != nil {
t.Fatal(err)
}
newDER, err := asn1.Marshal(newAttr)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(oldDER, newDER) {
t.Fatal("der mismatch")
}
}
func TestIssuerAndSerialNumber(t *testing.T) {
ci, _ := ParseContentInfo(fixtureSignatureOpenSSLAttached)
sd, _ := ci.SignedDataContent()
si := sd.SignerInfos[0]
certs, _ := sd.X509Certificates()
cert, _ := si.FindCertificate(certs)
newISN, err := NewIssuerAndSerialNumber(cert)
if err != nil {
t.Fatal(err)
}
oldDER, _ := asn1.Marshal(si.SID)
newDER, _ := asn1.Marshal(newISN)
if !bytes.Equal(oldDER, newDER) {
t.Fatal("SID mismatch")
}
}
func TestParseFixtureSignatureOne(t *testing.T) {
ParseContentInfoHelper(t, fixtureSignatureOne)
testParseContentInfo(t, fixtureSignatureOne)
}
func TestParseSignatureGPGSM(t *testing.T) {
ParseContentInfoHelper(t, fixtureSignatureGPGSM)
testParseContentInfo(t, fixtureSignatureGPGSM)
}
func TestParseSignatureNoCertsGPGSM(t *testing.T) {
ParseContentInfoHelper(t, fixtureSignatureNoCertsGPGSM)
testParseContentInfo(t, fixtureSignatureNoCertsGPGSM)
}
func TestParseSignatureOpenSSLAttached(t *testing.T) {
ParseContentInfoHelper(t, fixtureSignatureOpenSSLAttached)
testParseContentInfo(t, fixtureSignatureOpenSSLAttached)
}
func TestParseSignatureOpenSSLDetached(t *testing.T) {
ParseContentInfoHelper(t, fixtureSignatureOpenSSLDetached)
testParseContentInfo(t, fixtureSignatureOpenSSLDetached)
}
func ParseContentInfoHelper(t *testing.T, ber []byte) {
func testParseContentInfo(t *testing.T, ber []byte) {
ci, err := ParseContentInfo(ber)
if err != nil {
t.Fatal(err)

10
sign.go Normal file
Просмотреть файл

@ -0,0 +1,10 @@
package cms
import (
"crypto"
"crypto/x509"
)
func (sd *SignedData) Sign(cert *x509.Certificate, signer crypto.Signer) error {
return nil
}

30
signed_data.go Normal file
Просмотреть файл

@ -0,0 +1,30 @@
package cms
import "github.com/mastahyeti/cms/protocol"
// SignedData represents a signed message or detached signature.
type SignedData struct {
psd protocol.SignedData
}
// ParseSignedData parses a SignedData from BER encoded data.
func ParseSignedData(ber []byte) (*SignedData, error) {
ci, err := protocol.ParseContentInfo(ber)
if err != nil {
return nil, err
}
psd, err := ci.SignedDataContent()
if err != nil {
return nil, err
}
return &SignedData{psd}, nil
}
// GetData gets the encapsulated data from the SignedData. Nil will be returned
// if this is a detached signature. A protocol.ErrWrongType will be returned if
// the SignedData encapsulates something other than data (1.2.840.113549.1.7.1).
func (sd *SignedData) GetData() ([]byte, error) {
return sd.psd.EncapContentInfo.DataEContent()
}

Просмотреть файл

@ -5,37 +5,8 @@ import (
"crypto/x509"
"errors"
"fmt"
"github.com/mastahyeti/cms/protocol"
)
// SignedData represents a signed message or detached signature.
type SignedData struct {
psd protocol.SignedData
}
// ParseSignedData parses a SignedData from BER encoded data.
func ParseSignedData(ber []byte) (*SignedData, error) {
ci, err := protocol.ParseContentInfo(ber)
if err != nil {
return nil, err
}
psd, err := ci.SignedDataContent()
if err != nil {
return nil, err
}
return &SignedData{psd}, nil
}
// Data gets the encapsulated data from the SignedData. Nil will be returned if
// this is a detached signature. A protocol.ErrWrongType will be returned if the
// SignedData encapsulates something other than data (1.2.840.113549.1.7.1).
func (sd *SignedData) Data() ([]byte, error) {
return sd.psd.EncapContentInfo.DataEContent()
}
// Verify verifies the SingerInfos' signatures.
func (sd *SignedData) Verify() error {
data, err := sd.psd.EncapContentInfo.DataEContent()

Просмотреть файл