func (si SignerInfo) GetContentTypeAttribute() (asn1.ObjectIdentifier, error) {
	rv, err := si.SignedAttrs.GetOnlyAttributeValueBytes(oid.AttributeContentType)
	if err != nil {
		return nil, err
	}
	var ct asn1.ObjectIdentifier
	if rest, err := asn1.Unmarshal(rv.FullBytes, &ct); err != nil {
		return nil, err
	} else if len(rest) > 0 {
		return nil, ErrTrailingData
	}
	return ct, nil
}
GetContentTypeAttribute gets the signed ContentType attribute from the
SignerInfo.
package protocol
import (
	"bytes"
	"crypto"
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	_ "crypto/sha1"  
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/asn1"
	"errors"
	"fmt"
	"math/big"
	"sort"
	"time"
	"github.com/github/ietf-cms/oid"
)
type ASN1Error struct {
	Message string
}
func (err ASN1Error) Error() string {
	return fmt.Sprintf("cms/protocol: ASN.1 Error — %s", err.Message)
}
var (
	ErrWrongType = errors.New("cms/protocol: wrong choice or any type")
	ErrNoCertificate = errors.New("no certificate found")
	ErrUnsupported = ASN1Error{"unsupported type or version"}
	ErrTrailingData = ASN1Error{"unexpected trailing data"}
)
type ContentInfo struct {
	ContentType asn1.ObjectIdentifier
	Content     asn1.RawValue `asn1:"explicit,tag:0"`
}
func ParseContentInfo(ber []byte) (ci ContentInfo, err error) {
	var der []byte
	if der, err = BER2DER(ber); err != nil {
		return
	}
	var rest []byte
	if rest, err = asn1.Unmarshal(der, &ci); err != nil {
		return
	}
	if len(rest) > 0 {
		err = ErrTrailingData
	}
	return
}
func (ci ContentInfo) SignedDataContent() (*SignedData, error) {
	if !ci.ContentType.Equal(oid.ContentTypeSignedData) {
		return nil, ErrWrongType
	}
	sd := new(SignedData)
	if rest, err := asn1.Unmarshal(ci.Content.Bytes, sd); err != nil {
		return nil, err
	} else if len(rest) > 0 {
		return nil, ErrTrailingData
	}
	return sd, nil
}
type EncapsulatedContentInfo struct {
	EContentType asn1.ObjectIdentifier
	EContent     asn1.RawValue `asn1:"optional,explicit,tag:0"`
}
func NewDataEncapsulatedContentInfo(data []byte) (EncapsulatedContentInfo, error) {
	return NewEncapsulatedContentInfo(oid.ContentTypeData, data)
}
func NewEncapsulatedContentInfo(contentType asn1.ObjectIdentifier, content []byte) (EncapsulatedContentInfo, error) {
	octets, err := asn1.Marshal(asn1.RawValue{
		Class:      asn1.ClassUniversal,
		Tag:        asn1.TagOctetString,
		Bytes:      content,
		IsCompound: false,
	})
	if err != nil {
		return EncapsulatedContentInfo{}, err
	}
	return EncapsulatedContentInfo{
		EContentType: contentType,
		EContent: asn1.RawValue{
			Class:      asn1.ClassContextSpecific,
			Tag:        0,
			Bytes:      octets,
			IsCompound: true,
		},
	}, nil
}
func (eci EncapsulatedContentInfo) EContentValue() ([]byte, error) {
	if eci.EContent.Bytes == nil {
		return nil, nil
	}
	var octets asn1.RawValue
	if rest, err := asn1.Unmarshal(eci.EContent.Bytes, &octets); err != nil {
		return nil, err
	} else if len(rest) > 0 {
		return nil, ErrTrailingData
	}
	if octets.Class != asn1.ClassUniversal || octets.Tag != asn1.TagOctetString {
		return nil, ASN1Error{"bad tag or class"}
	}
	var value []byte
	if octets.IsCompound {
		rest := octets.Bytes
		for len(rest) > 0 {
			var err error
			if rest, err = asn1.Unmarshal(rest, &octets); err != nil {
				return nil, err
			}
			if octets.Class != asn1.ClassUniversal || octets.Tag != asn1.TagOctetString || octets.IsCompound {
				return nil, ASN1Error{"bad class or tag"}
			}
			value = append(value, octets.Bytes...)
		}
	} else {
		value = octets.Bytes
	}
	return value, nil
}
func (eci EncapsulatedContentInfo) IsTypeData() bool {
	return eci.EContentType.Equal(oid.ContentTypeData)
}
func (eci EncapsulatedContentInfo) DataEContent() ([]byte, error) {
	if !eci.IsTypeData() {
		return nil, ErrWrongType
	}
	return eci.EContentValue()
}
type Attribute struct {
	Type asn1.ObjectIdentifier
	RawValue asn1.RawValue
}
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
}
func (a Attribute) Value() (AnySet, error) {
	return DecodeAnySet(a.RawValue)
}
type Attributes []Attribute
func (attrs Attributes) MarshaledForSigning() ([]byte, error) {
	seq, err := asn1.Marshal(struct {
		Attributes `asn1:"set"`
	}{attrs})
	if err != nil {
		return nil, err
	}
	var raw asn1.RawValue
	if _, err = asn1.Unmarshal(seq, &raw); err != nil {
		return nil, err
	}
	return raw.Bytes, nil
}
func (attrs Attributes) MarshaledForVerification() ([]byte, error) {
	seq, err := asn1.Marshal(struct {
		Attributes `asn1:"sequence"`
	}{attrs})
	if err != nil {
		return nil, err
	}
	var raw asn1.RawValue
	if _, err = asn1.Unmarshal(seq, &raw); err != nil {
		return nil, err
	}
	raw.Bytes[0] = 0x31
	return raw.Bytes, nil
}
func (attrs Attributes) GetOnlyAttributeValueBytes(oid asn1.ObjectIdentifier) (rv asn1.RawValue, err error) {
	var vals []AnySet
	if vals, err = attrs.GetValues(oid); err != nil {
		return
	}
	if len(vals) != 1 {
		err = ASN1Error{"bad attribute count"}
		return
	}
	if len(vals[0].Elements) != 1 {
		err = ASN1Error{"bad attribute element count"}
		return
	}
	return vals[0].Elements[0], nil
}
func (attrs Attributes) GetValues(oid asn1.ObjectIdentifier) ([]AnySet, error) {
	if attrs == nil {
		return nil, nil
	}
	vals := []AnySet{}
	for _, attr := range attrs {
		if attr.Type.Equal(oid) {
			val, err := attr.Value()
			if err != nil {
				return nil, err
			}
			vals = append(vals, val)
		}
	}
	return vals, nil
}
func (attrs Attributes) HasAttribute(oid asn1.ObjectIdentifier) bool {
	for _, attr := range attrs {
		if attr.Type.Equal(oid) {
			return true
		}
	}
	return false
}
type IssuerAndSerialNumber struct {
	Issuer       asn1.RawValue
	SerialNumber *big.Int
}
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
}
type SignerInfo struct {
	Version            int
	SID                asn1.RawValue
	DigestAlgorithm    pkix.AlgorithmIdentifier
	SignedAttrs        Attributes `asn1:"optional,tag:0"`
	SignatureAlgorithm pkix.AlgorithmIdentifier
	Signature          []byte
	UnsignedAttrs      Attributes `asn1:"set,optional,tag:1"`
}
func (si SignerInfo) FindCertificate(certs []*x509.Certificate) (*x509.Certificate, error) {
	switch si.Version {
	case 1:  
		isn, err := si.issuerAndSerialNumberSID()
		if err != nil {
			return nil, err
		}
		for _, cert := range certs {
			if bytes.Equal(cert.RawIssuer, isn.Issuer.FullBytes) && isn.SerialNumber.Cmp(cert.SerialNumber) == 0 {
				return cert, nil
			}
		}
	case 3:  
		ski, err := si.subjectKeyIdentifierSID()
		if err != nil {
			return nil, err
		}
		for _, cert := range certs {
			for _, ext := range cert.Extensions {
				if oid.ExtensionSubjectKeyIdentifier.Equal(ext.Id) {
					if bytes.Equal(ski, ext.Value) {
						return cert, nil
					}
				}
			}
		}
	default:
		return nil, ErrUnsupported
	}
	return nil, ErrNoCertificate
}
func (si SignerInfo) issuerAndSerialNumberSID() (isn IssuerAndSerialNumber, err error) {
	if si.SID.Class != asn1.ClassUniversal || si.SID.Tag != asn1.TagSequence {
		err = ErrWrongType
		return
	}
	var rest []byte
	if rest, err = asn1.Unmarshal(si.SID.FullBytes, &isn); err == nil && len(rest) > 0 {
		err = ErrTrailingData
	}
	return
}
func (si SignerInfo) subjectKeyIdentifierSID() ([]byte, error) {
	if si.SID.Class != asn1.ClassContextSpecific || si.SID.Tag != 0 {
		return nil, ErrWrongType
	}
	return si.SID.Bytes, nil
}
func (si SignerInfo) Hash() (crypto.Hash, error) {
	algo := si.DigestAlgorithm.Algorithm.String()
	hash := oid.DigestAlgorithmToCryptoHash[algo]
	if hash == 0 || !hash.Available() {
		return 0, ErrUnsupported
	}
	return hash, nil
}
func (si SignerInfo) X509SignatureAlgorithm() x509.SignatureAlgorithm {
	var (
		sigOID    = si.SignatureAlgorithm.Algorithm.String()
		digestOID = si.DigestAlgorithm.Algorithm.String()
	)
	if sa := oid.SignatureAlgorithmToX509SignatureAlgorithm[sigOID]; sa != x509.UnknownSignatureAlgorithm {
		return sa
	}
	return oid.PublicKeyAndDigestAlgorithmToX509SignatureAlgorithm[sigOID][digestOID]
}