go-attestation/attributecert/attributecert.go
Eric Chiang 6cfb57c8eb attributecert: update names that golint complains about
golint current generates complaints:

        var oidTpmIdLabel should be oidTpmIDLabel
        var oidTcgPlatformManufacturerIdV2 should be oidTcgPlatformManufacturerIDV2
        var oidTcgPlatformConfigUri should be oidTcgPlatformConfigURI

Update names to satisfy golint.

The following commands were run to generate this change:

        gopls rename -w attributecert.go:44:2 oidTpmIDLabel
        gopls rename -w attributecert.go:54:2 oidTcgPlatformManufacturerIDV2
        gopls rename -w attributecert.go:55:2 oidTcgPlatformConfigURI
        gopls rename -w attributecert.go:163:6 authKeyID
        gopls rename -w attributecert.go:164:2 ID
        gopls rename -w attributecert.go:171:2 ID
        gopls rename -w attributecert.go:178:2 ID
        gopls rename -w attributecert.go:210:2 BaseCertificateID
        gopls rename -w attributecert.go:232:2 ID
        gopls rename -w attributecert.go:304:2 ID
        gopls rename -w attributecert.go:309:2 ID
        gopls rename -w attributecert.go:390:2 ComponentManufacturerID
        sed -i 's/Uri/URI/g' attributecert.go
        git clean -f

Updates #131
2019-11-06 11:09:02 +01:00

714 lines
24 KiB
Go

// Copyright 2009 The Go Authors. All rights reserved.
// Copyright 2019 Google, LLC.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package attributecert parses X.509-encoded attribute certificates.
package attributecert
import (
"bytes"
"crypto"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"errors"
"fmt"
"math/big"
"time"
)
var (
oidExtensionSubjectDirectoryAttributes = []int{2, 5, 29, 9}
oidExtensionSubjectAltName = []int{2, 5, 29, 17}
oidExtensionCertificatePolicies = []int{2, 5, 29, 32}
oidExtensionAuthorityKeyIdentifier = []int{2, 5, 29, 35}
oidAuthorityInfoAccess = []int{1, 3, 6, 1, 5, 5, 7, 1, 1}
oidCpsCertificatePolicy = []int{1, 3, 6, 1, 5, 5, 7, 2, 1}
oidAttributeUserNotice = []int{1, 3, 6, 1, 5, 5, 7, 2, 2}
oidAuthorityInfoAccessOcsp = []int{1, 3, 6, 1, 5, 5, 7, 48, 1}
oidAuthorityInfoAccessIssuers = []int{1, 3, 6, 1, 5, 5, 7, 48, 2}
oidTcgCertificatePolicy = []int{1, 2, 840, 113741, 1, 5, 2, 4}
oidTcgAttribute = []int{2, 23, 133, 2}
oidTpmManufacturer = []int{2, 23, 133, 2, 1}
oidTpmModel = []int{2, 23, 133, 2, 2}
oidTpmVersion = []int{2, 23, 133, 2, 3}
oidTcgPlatformManufacturerStrV1 = []int{2, 23, 133, 2, 4}
oidTcgPlatformModelV1 = []int{2, 23, 133, 2, 5}
oidTcgPlatformVersionV1 = []int{2, 23, 133, 2, 6}
oidSecurityQualities = []int{2, 23, 133, 2, 10}
oidTpmProtectionProfile = []int{2, 23, 133, 2, 11}
oidTpmSecurityTarget = []int{2, 23, 133, 2, 12}
oidTbbProtectionProfile = []int{2, 23, 133, 2, 13}
oidTbbSecurityTarget = []int{2, 23, 133, 2, 14}
oidTpmIDLabel = []int{2, 23, 133, 2, 15}
oidTpmSpecification = []int{2, 23, 133, 2, 16}
oidTcgPlatformSpecification = []int{2, 23, 133, 2, 17}
oidTpmSecurityAssertions = []int{2, 23, 133, 2, 18}
oidTbbSecurityAssertions = []int{2, 23, 133, 2, 19}
oidTcgCredentialSpecification = []int{2, 23, 133, 2, 23}
oidTcgCredentialType = []int{2, 23, 133, 2, 25}
oidTcgPlatformClass = []int{2, 23, 133, 5}
oidTcgCommon = []int{2, 23, 133, 5, 1}
oidTcgPlatformManufacturerStrV2 = []int{2, 23, 133, 5, 1, 1}
oidTcgPlatformManufacturerIDV2 = []int{2, 23, 133, 5, 1, 2}
oidTcgPlatformConfigURI = []int{2, 23, 133, 5, 1, 3}
oidTcgPlatformModelV2 = []int{2, 23, 133, 5, 1, 4}
oidTcgPlatformVersionV2 = []int{2, 23, 133, 5, 1, 5}
oidTcgPlatformSerialV2 = []int{2, 23, 133, 5, 1, 6}
oidTcgPlatformConfiguration = []int{2, 23, 133, 5, 1, 7}
oidTcgPlatformConfigurationV1 = []int{2, 23, 133, 5, 1, 7, 1}
oidTcgPlatformConfigurationV2 = []int{2, 23, 133, 5, 1, 7, 2}
)
var (
oidSignatureRSAPSS = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 10}
oidSignatureEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112}
oidSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1}
oidSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2}
oidSHA512 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 3}
oidMGF1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 8}
)
var signatureAlgorithmDetails = []struct {
algo x509.SignatureAlgorithm
name string
oid asn1.ObjectIdentifier
pubKeyAlgo x509.PublicKeyAlgorithm
hash crypto.Hash
}{
{x509.SHA256WithRSAPSS, "SHA256-RSAPSS", oidSignatureRSAPSS, x509.RSA, crypto.SHA256},
{x509.SHA384WithRSAPSS, "SHA384-RSAPSS", oidSignatureRSAPSS, x509.RSA, crypto.SHA384},
{x509.SHA512WithRSAPSS, "SHA512-RSAPSS", oidSignatureRSAPSS, x509.RSA, crypto.SHA512},
{x509.PureEd25519, "Ed25519", oidSignatureEd25519, x509.Ed25519, crypto.Hash(0) /* no pre-hashing */},
}
// pssParameters reflects the parameters in an AlgorithmIdentifier that
// specifies RSA PSS. See RFC 3447, Appendix A.2.3.
type pssParameters struct {
// The following three fields are not marked as
// optional because the default values specify SHA-1,
// which is no longer suitable for use in signatures.
Hash pkix.AlgorithmIdentifier `asn1:"explicit,tag:0"`
MGF pkix.AlgorithmIdentifier `asn1:"explicit,tag:1"`
SaltLength int `asn1:"explicit,tag:2"`
TrailerField int `asn1:"optional,explicit,tag:3,default:1"`
}
func getSignatureAlgorithmFromAI(ai pkix.AlgorithmIdentifier) x509.SignatureAlgorithm {
if ai.Algorithm.Equal(oidSignatureEd25519) {
// RFC 8410, Section 3
// > For all of the OIDs, the parameters MUST be absent.
if len(ai.Parameters.FullBytes) != 0 {
return x509.UnknownSignatureAlgorithm
}
}
if !ai.Algorithm.Equal(oidSignatureRSAPSS) {
for _, details := range signatureAlgorithmDetails {
if ai.Algorithm.Equal(details.oid) {
return details.algo
}
}
return x509.UnknownSignatureAlgorithm
}
// RSA PSS is special because it encodes important parameters
// in the Parameters.
var params pssParameters
if _, err := asn1.Unmarshal(ai.Parameters.FullBytes, &params); err != nil {
return x509.UnknownSignatureAlgorithm
}
var mgf1HashFunc pkix.AlgorithmIdentifier
if _, err := asn1.Unmarshal(params.MGF.Parameters.FullBytes, &mgf1HashFunc); err != nil {
return x509.UnknownSignatureAlgorithm
}
// PSS is greatly overburdened with options. This code forces them into
// three buckets by requiring that the MGF1 hash function always match the
// message hash function (as recommended in RFC 3447, Section 8.1), that the
// salt length matches the hash length, and that the trailer field has the
// default value.
if (len(params.Hash.Parameters.FullBytes) != 0 && !bytes.Equal(params.Hash.Parameters.FullBytes, asn1.NullBytes)) ||
!params.MGF.Algorithm.Equal(oidMGF1) ||
!mgf1HashFunc.Algorithm.Equal(params.Hash.Algorithm) ||
(len(mgf1HashFunc.Parameters.FullBytes) != 0 && !bytes.Equal(mgf1HashFunc.Parameters.FullBytes, asn1.NullBytes)) ||
params.TrailerField != 1 {
return x509.UnknownSignatureAlgorithm
}
switch {
case params.Hash.Algorithm.Equal(oidSHA256) && params.SaltLength == 32:
return x509.SHA256WithRSAPSS
case params.Hash.Algorithm.Equal(oidSHA384) && params.SaltLength == 48:
return x509.SHA384WithRSAPSS
case params.Hash.Algorithm.Equal(oidSHA512) && params.SaltLength == 64:
return x509.SHA512WithRSAPSS
}
return x509.UnknownSignatureAlgorithm
}
//RFC 5280 4.2.2.1
type authorityInfoAccess struct {
Method asn1.ObjectIdentifier
Location asn1.RawValue
}
//RFC 5280 4.2.1.1
type authKeyID struct {
ID []byte `asn1:"optional,tag:0"`
IssuerName asn1.RawValue `asn1:"set,optional,tag:1"`
SerialNumber *big.Int `asn1:"optional,tag:2"`
}
//RFC 5280 4.2.1.4
type cpsPolicy struct {
ID asn1.ObjectIdentifier
Value string
}
//RFC 5280 4.2.1.4
type policyInformation struct {
Raw asn1.RawContent
ID asn1.ObjectIdentifier
Policy asn1.RawValue
}
//RFC 5280 4.1.2.5
type validity struct {
NotBefore, NotAfter time.Time
}
//RFC 5280 4.2.1.4
type NoticeReference struct {
Organization string
NoticeNumbers []int
}
//RFC 5280 4.2.1.4
type userNotice struct {
NoticeRef NoticeReference `asn1:"optional"`
ExplicitText string `asn1:"optional"`
}
//RFC 5755 4.1
type objectDigestInfo struct {
DigestedObjectType asn1.Enumerated
OtherObjectTypeID asn1.ObjectIdentifier
DigestAlgorithm pkix.AlgorithmIdentifier
ObjectDigest asn1.BitString
}
//RFC 5755 4.1
type attCertIssuer struct {
IssuerName asn1.RawValue `asn1:"set,optional"`
BaseCertificateID issuerSerial `asn1:"optional,tag:0"`
ObjectDigestInfo objectDigestInfo `asn1:"optional,tag:1"`
}
//RFC 5755 4.1
type issuerSerial struct {
Raw asn1.RawContent
Issuer asn1.RawValue
Serial *big.Int
IssuerUID asn1.BitString `asn1:"optional"`
}
//RFC 5755 4.1
type holder struct {
Raw asn1.RawContent
BaseCertificateID issuerSerial `asn1:"optional,tag:0"`
EntityName pkix.Extension `asn1:"optional,tag:1"`
ObjectDigestInfo objectDigestInfo `asn1:"optional,tag:2"`
}
//RFC 5755 4.1
type attribute struct {
ID asn1.ObjectIdentifier
RawValues []asn1.RawValue `asn1:"set"`
}
//RFC 5755 4.1
type tbsAttributeCertificate struct {
Raw asn1.RawContent
Version int
Holder holder
Issuer attCertIssuer `asn1:"tag:0"`
SignatureAlgorithm pkix.AlgorithmIdentifier
SerialNumber *big.Int
Validity validity
Attributes []attribute
IssuerUniqueID asn1.BitString `asn1:"optional"`
Extensions []pkix.Extension `asn1:"optional"`
}
type attributeCertificate struct {
Raw asn1.RawContent
TBSAttributeCertificate tbsAttributeCertificate
SignatureAlgorithm pkix.AlgorithmIdentifier
SignatureValue asn1.BitString
}
type Certholder struct {
Issuer pkix.Name
Serial *big.Int
}
type AttributeCertificate struct {
Raw []byte // Complete ASN.1 DER content (certificate, signature algorithm and signature).
RawTBSAttributeCertificate []byte // Certificate part of raw ASN.1 DER content.
Signature []byte
SignatureAlgorithm x509.SignatureAlgorithm
Version int
SerialNumber *big.Int
Holder Certholder
Issuer pkix.Name
Subject pkix.Name
NotBefore, NotAfter time.Time // Validity bounds.
TCGPlatformSpecification TCGPlatformSpecification
TBBSecurityAssertions TBBSecurityAssertions
PlatformManufacturer string
PlatformModel string
PlatformVersion string
PlatformSerial string
CredentialSpecification string
UserNotice userNotice
}
// ParseAttributeCertificate parses a single attribute certificate from the
// given ASN.1 DER data.
func ParseAttributeCertificate(asn1Data []byte) (*AttributeCertificate, error) {
var cert attributeCertificate
rest, err := asn1.Unmarshal(asn1Data, &cert)
if err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, asn1.SyntaxError{Msg: "attributecert: trailing data"}
}
return parseAttributeCertificate(&cert)
}
type PlatformDataSequence []PlatformDataSET
type PlatformDataSET []pkix.AttributeTypeAndValue
type TCGData struct {
ID asn1.ObjectIdentifier
Data string
}
type TCGDirectoryEntry struct {
ID asn1.ObjectIdentifier
Data asn1.RawValue
}
type TCGSpecificationVersion struct {
MajorVersion int
MinorVersion int
Revision int
}
type TCGPlatformSpecification struct {
Version TCGSpecificationVersion
}
type TCGCredentialSpecification struct {
Version TCGSpecificationVersion
}
type TCGCredentialType struct {
CertificateType asn1.ObjectIdentifier
}
type FipsLevel struct {
Version string
Level asn1.Enumerated
Plus bool
}
type CommonCriteriaMeasures struct {
Version string
AssuranceLevel asn1.Enumerated
EvaluationStatus asn1.Enumerated
Plus bool
StrengthOfFunction asn1.Enumerated `asn1:"optional,tag=0"`
ProfileOid asn1.ObjectIdentifier `asn1:"optional,tag=1"`
ProfileURI string `asn1:"optional,tag=2"`
TargetOid asn1.ObjectIdentifier `asn1:"optional,tag=3"`
TargetURI asn1.ObjectIdentifier `asn1:"optional,tag=4"`
}
type TBBSecurityAssertions struct {
Version int
CcInfo CommonCriteriaMeasures `asn1:"optional,tag=0"`
FipsLevel FipsLevel `asn1:"optional,tag=1"`
RtmType asn1.Enumerated `asn1:"optional,tag=2"`
Iso9000Certified bool `asn1:"optional"`
Iso9000URI string `asn1:"optional"`
}
type Property struct {
PropertyName string
PropertyValue string
Status asn1.Enumerated `asn1:"optional,tag=0"`
}
type AttributeCertificateIdentifier struct {
HashAlgorithm pkix.AlgorithmIdentifier
HashOverSignatureValue string
}
type CertificateIdentifier struct {
AttributeCertIdentifier AttributeCertificateIdentifier `asn1:"optional,tag=0"`
GenericCertIdientifier issuerSerial `asn1:"optional,tag=1"`
}
type ComponentAddress struct {
AddressType asn1.ObjectIdentifier
AddressValue string
}
type ComponentClass struct {
ComponentClassRegistry asn1.ObjectIdentifier
ComponentClassValue string
}
type ComponentIdentifierV2 struct {
ComponentClass ComponentClass
ComponentManufacturer string
ComponentModel string
ComponentSerial string `asn1:"optional,tag=0"`
ComponentRevision string `asn1:"optional,tag=1"`
ComponentManufacturerID int `asn1:"optional,tag=2"`
FieldReplaceable bool `asn1:"optional,tag=3"`
ComponentAddresses []ComponentAddress `asn1:"optional,tag=4"`
ComponentPlatformCert CertificateIdentifier `asn1:"optional,tag=5"`
ComponentPlatformCertURI string `asn1:"optional,tag=6"`
Status asn1.Enumerated `asn1:"optional,tag=7"`
}
type URIReference struct {
UniformResourceIdentifier string
HashAlgorithm pkix.AlgorithmIdentifier `asn1:"optional"`
HashValue string `asn1:"optional"`
}
type PlatformConfigurationV2 struct {
ComponentIdentifiers []ComponentIdentifierV2 `asn1:"optional,tag=0"`
ComponentIdentifiersURI URIReference `asn1:"optional,tag=1"`
PlatformProperties []Property `asn1:"optional,tag=2"`
PlatformPropertiesURI URIReference `asn1:"optional,tag=3"`
}
type ComponentIdentifierV1 struct {
ComponentManufacturer string
ComponentModel string
ComponentSerial string `asn1:"optional,tag=0"`
ComponentRevision string `asn1:"optional,tag=1"`
ComponentManufacturerId int `asn1:"optional,tag=2"`
FieldReplaceable bool `asn1:"optional,tag=3"`
ComponentAddresses []ComponentAddress `asn1:"optional,tag=4"`
}
type PlatformConfigurationV1 struct {
ComponentIdentifiers []ComponentIdentifierV1 `asn1:"optional,tag=0"`
PlatformProperties []Property `asn1:"optional,tag=1"`
PlatformPropertiesURI []URIReference `asn1:"optional,tag=2"`
}
func unmarshalSAN(v asn1.RawValue) ([]pkix.AttributeTypeAndValue, error) {
if v.Tag == asn1.TagSet {
var e pkix.AttributeTypeAndValue
if _, err := asn1.Unmarshal(v.Bytes, &e); err != nil {
return nil, err
}
return []pkix.AttributeTypeAndValue{e}, nil
} else if v.Tag == asn1.TagOctetString {
var attributes []pkix.AttributeTypeAndValue
var platformData PlatformDataSequence
rest, err := asn1.Unmarshal(v.Bytes, &platformData)
if err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, errors.New("attributecert: trailing data after X.509 subject")
}
for _, e := range platformData {
for _, e2 := range e {
attributes = append(attributes, e2)
}
}
return attributes, nil
}
return nil, fmt.Errorf("attributecert: unexpected SAN type %v", v.Tag)
}
func parseAttributeCertificate(in *attributeCertificate) (*AttributeCertificate, error) {
out := &AttributeCertificate{
Raw: in.Raw,
RawTBSAttributeCertificate: in.TBSAttributeCertificate.Raw,
Signature: in.SignatureValue.RightAlign(),
SignatureAlgorithm: getSignatureAlgorithmFromAI(in.TBSAttributeCertificate.SignatureAlgorithm),
Version: in.TBSAttributeCertificate.Version + 1,
SerialNumber: in.TBSAttributeCertificate.SerialNumber,
}
var v asn1.RawValue
if _, err := asn1.Unmarshal(in.TBSAttributeCertificate.Issuer.IssuerName.Bytes, &v); err != nil {
return nil, err
}
var issuer pkix.RDNSequence
if rest, err := asn1.Unmarshal(v.Bytes, &issuer); err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, errors.New("attributecert: trailing data after X.509 subject")
}
out.Issuer.FillFromRDNSequence(&issuer)
if _, err := asn1.Unmarshal(in.TBSAttributeCertificate.Holder.BaseCertificateID.Issuer.Bytes, &v); err != nil {
return nil, err
}
var holder pkix.RDNSequence
if rest, err := asn1.Unmarshal(v.Bytes, &holder); err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, errors.New("attributecert: trailing data after X.509 subject")
}
out.Holder.Issuer.FillFromRDNSequence(&holder)
out.Holder.Serial = in.TBSAttributeCertificate.Holder.BaseCertificateID.Serial
out.NotBefore = in.TBSAttributeCertificate.Validity.NotBefore
out.NotAfter = in.TBSAttributeCertificate.Validity.NotAfter
for _, attribute := range in.TBSAttributeCertificate.Attributes {
switch {
case attribute.ID.Equal(oidAttributeUserNotice):
if _, err := asn1.Unmarshal(attribute.RawValues[0].FullBytes, &out.UserNotice); err != nil {
return nil, err
}
case attribute.ID.Equal(oidTcgPlatformSpecification):
if _, err := asn1.Unmarshal(attribute.RawValues[0].FullBytes, &out.TCGPlatformSpecification); err != nil {
return nil, err
}
case attribute.ID.Equal(oidTbbSecurityAssertions):
if _, err := asn1.Unmarshal(attribute.RawValues[0].FullBytes, &out.TBBSecurityAssertions); err != nil {
return nil, err
}
case attribute.ID.Equal(oidTcgCredentialSpecification):
var credentialSpecification TCGCredentialSpecification
if _, err := asn1.Unmarshal(attribute.RawValues[0].FullBytes, &credentialSpecification); err != nil {
var credentialSpecification TCGSpecificationVersion
if _, err := asn1.Unmarshal(attribute.RawValues[0].FullBytes, &credentialSpecification); err != nil {
return nil, err
}
}
case attribute.ID.Equal(oidTcgCredentialType):
var credentialType TCGCredentialType
if _, err := asn1.Unmarshal(attribute.RawValues[0].FullBytes, &credentialType); err != nil {
return nil, err
}
case attribute.ID.Equal(oidTcgPlatformConfigurationV1):
var platformConfiguration PlatformConfigurationV1
if _, err := asn1.Unmarshal(attribute.RawValues[0].FullBytes, &platformConfiguration); err != nil {
return nil, err
}
case attribute.ID.Equal(oidTcgPlatformConfigurationV2):
var platformConfiguration PlatformConfigurationV2
if _, err := asn1.Unmarshal(attribute.RawValues[0].FullBytes, &platformConfiguration); err != nil {
return nil, err
}
case attribute.ID.Equal(oidTcgPlatformConfigURI):
var platformConfigurationURI URIReference
if _, err := asn1.Unmarshal(attribute.RawValues[0].FullBytes, &platformConfigurationURI); err != nil {
return nil, err
}
default:
return nil, fmt.Errorf("attributecert: unknown attribute %v", attribute.ID)
}
}
for _, extension := range in.TBSAttributeCertificate.Extensions {
switch {
case extension.Id.Equal(oidExtensionSubjectAltName):
var seq asn1.RawValue
rest, err := asn1.Unmarshal(extension.Value, &seq)
if err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, errors.New("attributecert: trailing data after X.509 extension")
}
rest = seq.Bytes
for len(rest) > 0 {
var v asn1.RawValue
rest, err = asn1.Unmarshal(rest, &v)
if err != nil {
return nil, err
}
tcgdata, err := unmarshalSAN(v)
if err != nil {
return nil, fmt.Errorf("attributecert: failed to unmarshal SAN: %v", err)
}
for _, e := range tcgdata {
switch {
case e.Type.Equal(oidTcgPlatformManufacturerStrV1):
out.PlatformManufacturer = e.Value.(string)
case e.Type.Equal(oidTcgPlatformModelV1):
out.PlatformModel = e.Value.(string)
case e.Type.Equal(oidTcgPlatformVersionV1):
out.PlatformVersion = e.Value.(string)
case e.Type.Equal(oidTcgCredentialSpecification):
// This OID appears to be misused in this context
out.PlatformSerial = e.Value.(string)
case e.Type.Equal(oidTcgPlatformManufacturerStrV2):
out.PlatformManufacturer = e.Value.(string)
case e.Type.Equal(oidTcgPlatformManufacturerIDV2):
// We can't parse these out at present
break
case e.Type.Equal(oidTcgPlatformModelV2):
out.PlatformModel = e.Value.(string)
case e.Type.Equal(oidTcgPlatformVersionV2):
out.PlatformVersion = e.Value.(string)
case e.Type.Equal(oidTcgPlatformSerialV2):
out.PlatformSerial = e.Value.(string)
default:
return nil, fmt.Errorf("attributecert: unhandled attribute: %v", e.Type)
}
}
}
case extension.Id.Equal(oidExtensionSubjectDirectoryAttributes):
var seq asn1.RawValue
rest, err := asn1.Unmarshal(extension.Value, &seq)
if err != nil {
return nil, err
} else if len(rest) != 0 {
return nil, errors.New("attributecert: trailing data after X.509 extension")
}
rest = seq.Bytes
for len(rest) > 0 {
var e TCGDirectoryEntry
rest, err = asn1.Unmarshal(rest, &e)
if err != nil {
return nil, err
}
switch {
case e.ID.Equal(oidTcgPlatformSpecification):
var platformSpecification TCGPlatformSpecification
_, err := asn1.Unmarshal(e.Data.Bytes, &platformSpecification)
if err != nil {
return nil, err
}
out.TCGPlatformSpecification = platformSpecification
case e.ID.Equal(oidTbbSecurityAssertions):
var securityAssertions TBBSecurityAssertions
_, err := asn1.Unmarshal(e.Data.Bytes, &securityAssertions)
if err != nil {
return nil, err
}
out.TBBSecurityAssertions = securityAssertions
default:
return nil, fmt.Errorf("attributecert: unhandled TCG directory attribute: %v", e.ID)
}
}
case extension.Id.Equal(oidExtensionCertificatePolicies):
var policies []policyInformation
_, err := asn1.Unmarshal(extension.Value, &policies)
if err != nil {
return nil, err
}
for _, policy := range policies {
if policy.ID.Equal(oidTcgCertificatePolicy) {
var subpolicies []policyInformation
_, err := asn1.Unmarshal(policy.Policy.FullBytes, &subpolicies)
if err != nil {
return nil, err
}
for _, subpolicy := range subpolicies {
switch {
case subpolicy.ID.Equal(oidCpsCertificatePolicy):
var cpsPolicy cpsPolicy
_, err := asn1.Unmarshal(subpolicy.Raw, &cpsPolicy)
if err != nil {
return nil, err
}
case subpolicy.ID.Equal(oidAttributeUserNotice):
var userNotice string
_, err := asn1.Unmarshal(subpolicy.Policy.Bytes, &userNotice)
if err != nil {
return nil, err
}
default:
return nil, fmt.Errorf("attributecert: unhandled certificate policy: %v", subpolicy.ID)
}
}
}
}
case extension.Id.Equal(oidExtensionAuthorityKeyIdentifier):
var a authKeyID
_, err := asn1.Unmarshal(extension.Value, &a)
if err != nil {
return nil, err
}
case extension.Id.Equal(oidAuthorityInfoAccess):
var aia []authorityInfoAccess
_, err := asn1.Unmarshal(extension.Value, &aia)
if err != nil {
return nil, err
}
for _, v := range aia {
if v.Method.Equal(oidAuthorityInfoAccessOcsp) {
//TODO
} else if v.Method.Equal(oidAuthorityInfoAccessIssuers) {
//TODO
} else {
return nil, fmt.Errorf("attributecert: unhandled Authority Info Access type %v", v.Method)
}
}
default:
return nil, fmt.Errorf("attributecert: unknown extension ID %v", extension.Id)
}
}
return out, nil
}
// CheckSignatureFrom verifies that the signature on c is a valid signature
// from parent.
func (c *AttributeCertificate) CheckSignatureFrom(parent *x509.Certificate) error {
// RFC 5280, 4.2.1.9:
// "If the basic constraints extension is not present in a version 3
// certificate, or the extension is present but the cA boolean is not
// asserted, then the certified public key MUST NOT be used to verify
// certificate signatures."
if parent.Version == 3 && !parent.BasicConstraintsValid ||
parent.BasicConstraintsValid && !parent.IsCA {
return x509.ConstraintViolationError{}
}
if parent.KeyUsage != 0 && parent.KeyUsage&x509.KeyUsageCertSign == 0 {
return x509.ConstraintViolationError{}
}
if parent.PublicKeyAlgorithm == x509.UnknownPublicKeyAlgorithm {
return x509.ErrUnsupportedAlgorithm
}
// TODO(agl): don't ignore the path length constraint.
return parent.CheckSignature(c.SignatureAlgorithm, c.RawTBSAttributeCertificate, c.Signature)
}