vendor
This commit is contained in:
362
vendor/github.com/google/certificate-transparency-go/x509/revoked.go
generated
vendored
Normal file
362
vendor/github.com/google/certificate-transparency-go/x509/revoked.go
generated
vendored
Normal file
@ -0,0 +1,362 @@
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package x509
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/pem"
|
||||
"time"
|
||||
|
||||
"github.com/google/certificate-transparency-go/asn1"
|
||||
"github.com/google/certificate-transparency-go/x509/pkix"
|
||||
)
|
||||
|
||||
var (
|
||||
// OID values for CRL extensions (TBSCertList.Extensions), RFC 5280 s5.2.
|
||||
OIDExtensionCRLNumber = asn1.ObjectIdentifier{2, 5, 29, 20}
|
||||
OIDExtensionDeltaCRLIndicator = asn1.ObjectIdentifier{2, 5, 29, 27}
|
||||
OIDExtensionIssuingDistributionPoint = asn1.ObjectIdentifier{2, 5, 29, 28}
|
||||
// OID values for CRL entry extensions (RevokedCertificate.Extensions), RFC 5280 s5.3
|
||||
OIDExtensionCRLReasons = asn1.ObjectIdentifier{2, 5, 29, 21}
|
||||
OIDExtensionInvalidityDate = asn1.ObjectIdentifier{2, 5, 29, 24}
|
||||
OIDExtensionCertificateIssuer = asn1.ObjectIdentifier{2, 5, 29, 29}
|
||||
)
|
||||
|
||||
// RevocationReasonCode represents the reason for a certificate revocation; see RFC 5280 s5.3.1.
|
||||
type RevocationReasonCode asn1.Enumerated
|
||||
|
||||
// RevocationReasonCode values.
|
||||
var (
|
||||
Unspecified = RevocationReasonCode(0)
|
||||
KeyCompromise = RevocationReasonCode(1)
|
||||
CACompromise = RevocationReasonCode(2)
|
||||
AffiliationChanged = RevocationReasonCode(3)
|
||||
Superseded = RevocationReasonCode(4)
|
||||
CessationOfOperation = RevocationReasonCode(5)
|
||||
CertificateHold = RevocationReasonCode(6)
|
||||
RemoveFromCRL = RevocationReasonCode(8)
|
||||
PrivilegeWithdrawn = RevocationReasonCode(9)
|
||||
AACompromise = RevocationReasonCode(10)
|
||||
)
|
||||
|
||||
// ReasonFlag holds a bitmask of applicable revocation reasons, from RFC 5280 s4.2.1.13
|
||||
type ReasonFlag int
|
||||
|
||||
// ReasonFlag values.
|
||||
const (
|
||||
UnusedFlag ReasonFlag = 1 << iota
|
||||
KeyCompromiseFlag
|
||||
CACompromiseFlag
|
||||
AffiliationChangedFlag
|
||||
SupersededFlag
|
||||
CessationOfOperationFlag
|
||||
CertificateHoldFlag
|
||||
PrivilegeWithdrawnFlag
|
||||
AACompromiseFlag
|
||||
)
|
||||
|
||||
// CertificateList represents the ASN.1 structure of the same name from RFC 5280, s5.1.
|
||||
// It has the same content as pkix.CertificateList, but the contents include parsed versions
|
||||
// of any extensions.
|
||||
type CertificateList struct {
|
||||
Raw asn1.RawContent
|
||||
TBSCertList TBSCertList
|
||||
SignatureAlgorithm pkix.AlgorithmIdentifier
|
||||
SignatureValue asn1.BitString
|
||||
}
|
||||
|
||||
// ExpiredAt reports whether now is past the expiry time of certList.
|
||||
func (certList *CertificateList) ExpiredAt(now time.Time) bool {
|
||||
return now.After(certList.TBSCertList.NextUpdate)
|
||||
}
|
||||
|
||||
// Indication of whether extensions need to be critical or non-critical. Extensions that
|
||||
// can be either are omitted from the map.
|
||||
var listExtCritical = map[string]bool{
|
||||
// From RFC 5280...
|
||||
OIDExtensionAuthorityKeyId.String(): false, // s5.2.1
|
||||
OIDExtensionIssuerAltName.String(): false, // s5.2.2
|
||||
OIDExtensionCRLNumber.String(): false, // s5.2.3
|
||||
OIDExtensionDeltaCRLIndicator.String(): true, // s5.2.4
|
||||
OIDExtensionIssuingDistributionPoint.String(): true, // s5.2.5
|
||||
OIDExtensionFreshestCRL.String(): false, // s5.2.6
|
||||
OIDExtensionAuthorityInfoAccess.String(): false, // s5.2.7
|
||||
}
|
||||
|
||||
var certExtCritical = map[string]bool{
|
||||
// From RFC 5280...
|
||||
OIDExtensionCRLReasons.String(): false, // s5.3.1
|
||||
OIDExtensionInvalidityDate.String(): false, // s5.3.2
|
||||
OIDExtensionCertificateIssuer.String(): true, // s5.3.3
|
||||
}
|
||||
|
||||
// IssuingDistributionPoint represents the ASN.1 structure of the same
|
||||
// name
|
||||
type IssuingDistributionPoint struct {
|
||||
DistributionPoint distributionPointName `asn1:"optional,tag:0"`
|
||||
OnlyContainsUserCerts bool `asn1:"optional,tag:1"`
|
||||
OnlyContainsCACerts bool `asn1:"optional,tag:2"`
|
||||
OnlySomeReasons asn1.BitString `asn1:"optional,tag:3"`
|
||||
IndirectCRL bool `asn1:"optional,tag:4"`
|
||||
OnlyContainsAttributeCerts bool `asn1:"optional,tag:5"`
|
||||
}
|
||||
|
||||
// TBSCertList represents the ASN.1 structure of the same name from RFC
|
||||
// 5280, section 5.1. It has the same content as pkix.TBSCertificateList
|
||||
// but the extensions are included in a parsed format.
|
||||
type TBSCertList struct {
|
||||
Raw asn1.RawContent
|
||||
Version int
|
||||
Signature pkix.AlgorithmIdentifier
|
||||
Issuer pkix.RDNSequence
|
||||
ThisUpdate time.Time
|
||||
NextUpdate time.Time
|
||||
RevokedCertificates []*RevokedCertificate
|
||||
Extensions []pkix.Extension
|
||||
// Cracked out extensions:
|
||||
AuthorityKeyID []byte
|
||||
IssuerAltNames GeneralNames
|
||||
CRLNumber int
|
||||
BaseCRLNumber int // -1 if no delta CRL present
|
||||
IssuingDistributionPoint IssuingDistributionPoint
|
||||
IssuingDPFullNames GeneralNames
|
||||
FreshestCRLDistributionPoint []string
|
||||
OCSPServer []string
|
||||
IssuingCertificateURL []string
|
||||
}
|
||||
|
||||
// ParseCertificateList parses a CertificateList (e.g. a CRL) from the given
|
||||
// bytes. It's often the case that PEM encoded CRLs will appear where they
|
||||
// should be DER encoded, so this function will transparently handle PEM
|
||||
// encoding as long as there isn't any leading garbage.
|
||||
func ParseCertificateList(clBytes []byte) (*CertificateList, error) {
|
||||
if bytes.HasPrefix(clBytes, pemCRLPrefix) {
|
||||
block, _ := pem.Decode(clBytes)
|
||||
if block != nil && block.Type == pemType {
|
||||
clBytes = block.Bytes
|
||||
}
|
||||
}
|
||||
return ParseCertificateListDER(clBytes)
|
||||
}
|
||||
|
||||
// ParseCertificateListDER parses a DER encoded CertificateList from the given bytes.
|
||||
// For non-fatal errors, this function returns both an error and a CertificateList
|
||||
// object.
|
||||
func ParseCertificateListDER(derBytes []byte) (*CertificateList, error) {
|
||||
var errs Errors
|
||||
// First parse the DER into the pkix structures.
|
||||
pkixList := new(pkix.CertificateList)
|
||||
if rest, err := asn1.Unmarshal(derBytes, pkixList); err != nil {
|
||||
errs.AddID(ErrInvalidCertList, err)
|
||||
return nil, &errs
|
||||
} else if len(rest) != 0 {
|
||||
errs.AddID(ErrTrailingCertList)
|
||||
return nil, &errs
|
||||
}
|
||||
|
||||
// Transcribe the revoked certs but crack out extensions.
|
||||
revokedCerts := make([]*RevokedCertificate, len(pkixList.TBSCertList.RevokedCertificates))
|
||||
for i, pkixRevoked := range pkixList.TBSCertList.RevokedCertificates {
|
||||
revokedCerts[i] = parseRevokedCertificate(pkixRevoked, &errs)
|
||||
if revokedCerts[i] == nil {
|
||||
return nil, &errs
|
||||
}
|
||||
}
|
||||
|
||||
certList := CertificateList{
|
||||
Raw: derBytes,
|
||||
TBSCertList: TBSCertList{
|
||||
Raw: pkixList.TBSCertList.Raw,
|
||||
Version: pkixList.TBSCertList.Version,
|
||||
Signature: pkixList.TBSCertList.Signature,
|
||||
Issuer: pkixList.TBSCertList.Issuer,
|
||||
ThisUpdate: pkixList.TBSCertList.ThisUpdate,
|
||||
NextUpdate: pkixList.TBSCertList.NextUpdate,
|
||||
RevokedCertificates: revokedCerts,
|
||||
Extensions: pkixList.TBSCertList.Extensions,
|
||||
CRLNumber: -1,
|
||||
BaseCRLNumber: -1,
|
||||
},
|
||||
SignatureAlgorithm: pkixList.SignatureAlgorithm,
|
||||
SignatureValue: pkixList.SignatureValue,
|
||||
}
|
||||
|
||||
// Now crack out extensions.
|
||||
for _, e := range certList.TBSCertList.Extensions {
|
||||
if expectCritical, present := listExtCritical[e.Id.String()]; present {
|
||||
if e.Critical && !expectCritical {
|
||||
errs.AddID(ErrUnexpectedlyCriticalCertListExtension, e.Id)
|
||||
} else if !e.Critical && expectCritical {
|
||||
errs.AddID(ErrUnexpectedlyNonCriticalCertListExtension, e.Id)
|
||||
}
|
||||
}
|
||||
switch {
|
||||
case e.Id.Equal(OIDExtensionAuthorityKeyId):
|
||||
// RFC 5280 s5.2.1
|
||||
var a authKeyId
|
||||
if rest, err := asn1.Unmarshal(e.Value, &a); err != nil {
|
||||
errs.AddID(ErrInvalidCertListAuthKeyID, err)
|
||||
} else if len(rest) != 0 {
|
||||
errs.AddID(ErrTrailingCertListAuthKeyID)
|
||||
}
|
||||
certList.TBSCertList.AuthorityKeyID = a.Id
|
||||
case e.Id.Equal(OIDExtensionIssuerAltName):
|
||||
// RFC 5280 s5.2.2
|
||||
if err := parseGeneralNames(e.Value, &certList.TBSCertList.IssuerAltNames); err != nil {
|
||||
errs.AddID(ErrInvalidCertListIssuerAltName, err)
|
||||
}
|
||||
case e.Id.Equal(OIDExtensionCRLNumber):
|
||||
// RFC 5280 s5.2.3
|
||||
if rest, err := asn1.Unmarshal(e.Value, &certList.TBSCertList.CRLNumber); err != nil {
|
||||
errs.AddID(ErrInvalidCertListCRLNumber, err)
|
||||
} else if len(rest) != 0 {
|
||||
errs.AddID(ErrTrailingCertListCRLNumber)
|
||||
}
|
||||
if certList.TBSCertList.CRLNumber < 0 {
|
||||
errs.AddID(ErrNegativeCertListCRLNumber, certList.TBSCertList.CRLNumber)
|
||||
}
|
||||
case e.Id.Equal(OIDExtensionDeltaCRLIndicator):
|
||||
// RFC 5280 s5.2.4
|
||||
if rest, err := asn1.Unmarshal(e.Value, &certList.TBSCertList.BaseCRLNumber); err != nil {
|
||||
errs.AddID(ErrInvalidCertListDeltaCRL, err)
|
||||
} else if len(rest) != 0 {
|
||||
errs.AddID(ErrTrailingCertListDeltaCRL)
|
||||
}
|
||||
if certList.TBSCertList.BaseCRLNumber < 0 {
|
||||
errs.AddID(ErrNegativeCertListDeltaCRL, certList.TBSCertList.BaseCRLNumber)
|
||||
}
|
||||
case e.Id.Equal(OIDExtensionIssuingDistributionPoint):
|
||||
parseIssuingDistributionPoint(e.Value, &certList.TBSCertList.IssuingDistributionPoint, &certList.TBSCertList.IssuingDPFullNames, &errs)
|
||||
case e.Id.Equal(OIDExtensionFreshestCRL):
|
||||
// RFC 5280 s5.2.6
|
||||
if err := parseDistributionPoints(e.Value, &certList.TBSCertList.FreshestCRLDistributionPoint); err != nil {
|
||||
errs.AddID(ErrInvalidCertListFreshestCRL, err)
|
||||
return nil, err
|
||||
}
|
||||
case e.Id.Equal(OIDExtensionAuthorityInfoAccess):
|
||||
// RFC 5280 s5.2.7
|
||||
var aia []authorityInfoAccess
|
||||
if rest, err := asn1.Unmarshal(e.Value, &aia); err != nil {
|
||||
errs.AddID(ErrInvalidCertListAuthInfoAccess, err)
|
||||
} else if len(rest) != 0 {
|
||||
errs.AddID(ErrTrailingCertListAuthInfoAccess)
|
||||
}
|
||||
|
||||
for _, v := range aia {
|
||||
// GeneralName: uniformResourceIdentifier [6] IA5String
|
||||
if v.Location.Tag != tagURI {
|
||||
continue
|
||||
}
|
||||
switch {
|
||||
case v.Method.Equal(OIDAuthorityInfoAccessOCSP):
|
||||
certList.TBSCertList.OCSPServer = append(certList.TBSCertList.OCSPServer, string(v.Location.Bytes))
|
||||
case v.Method.Equal(OIDAuthorityInfoAccessIssuers):
|
||||
certList.TBSCertList.IssuingCertificateURL = append(certList.TBSCertList.IssuingCertificateURL, string(v.Location.Bytes))
|
||||
}
|
||||
// TODO(drysdale): cope with more possibilities
|
||||
}
|
||||
default:
|
||||
if e.Critical {
|
||||
errs.AddID(ErrUnhandledCriticalCertListExtension, e.Id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if errs.Fatal() {
|
||||
return nil, &errs
|
||||
}
|
||||
if errs.Empty() {
|
||||
return &certList, nil
|
||||
}
|
||||
return &certList, &errs
|
||||
}
|
||||
|
||||
func parseIssuingDistributionPoint(data []byte, idp *IssuingDistributionPoint, name *GeneralNames, errs *Errors) {
|
||||
// RFC 5280 s5.2.5
|
||||
if rest, err := asn1.Unmarshal(data, idp); err != nil {
|
||||
errs.AddID(ErrInvalidCertListIssuingDP, err)
|
||||
} else if len(rest) != 0 {
|
||||
errs.AddID(ErrTrailingCertListIssuingDP)
|
||||
}
|
||||
|
||||
typeCount := 0
|
||||
if idp.OnlyContainsUserCerts {
|
||||
typeCount++
|
||||
}
|
||||
if idp.OnlyContainsCACerts {
|
||||
typeCount++
|
||||
}
|
||||
if idp.OnlyContainsAttributeCerts {
|
||||
typeCount++
|
||||
}
|
||||
if typeCount > 1 {
|
||||
errs.AddID(ErrCertListIssuingDPMultipleTypes, idp.OnlyContainsUserCerts, idp.OnlyContainsCACerts, idp.OnlyContainsAttributeCerts)
|
||||
}
|
||||
for _, fn := range idp.DistributionPoint.FullName {
|
||||
if _, err := parseGeneralName(fn.FullBytes, name, false); err != nil {
|
||||
errs.AddID(ErrCertListIssuingDPInvalidFullName, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RevokedCertificate represents the unnamed ASN.1 structure that makes up the
|
||||
// revokedCertificates member of the TBSCertList structure from RFC 5280, s5.1.
|
||||
// It has the same content as pkix.RevokedCertificate but the extensions are
|
||||
// included in a parsed format.
|
||||
type RevokedCertificate struct {
|
||||
pkix.RevokedCertificate
|
||||
// Cracked out extensions:
|
||||
RevocationReason RevocationReasonCode
|
||||
InvalidityDate time.Time
|
||||
Issuer GeneralNames
|
||||
}
|
||||
|
||||
func parseRevokedCertificate(pkixRevoked pkix.RevokedCertificate, errs *Errors) *RevokedCertificate {
|
||||
result := RevokedCertificate{RevokedCertificate: pkixRevoked}
|
||||
for _, e := range pkixRevoked.Extensions {
|
||||
if expectCritical, present := certExtCritical[e.Id.String()]; present {
|
||||
if e.Critical && !expectCritical {
|
||||
errs.AddID(ErrUnexpectedlyCriticalRevokedCertExtension, e.Id)
|
||||
} else if !e.Critical && expectCritical {
|
||||
errs.AddID(ErrUnexpectedlyNonCriticalRevokedCertExtension, e.Id)
|
||||
}
|
||||
}
|
||||
switch {
|
||||
case e.Id.Equal(OIDExtensionCRLReasons):
|
||||
// RFC 5280, s5.3.1
|
||||
var reason asn1.Enumerated
|
||||
if rest, err := asn1.Unmarshal(e.Value, &reason); err != nil {
|
||||
errs.AddID(ErrInvalidRevocationReason, err)
|
||||
} else if len(rest) != 0 {
|
||||
errs.AddID(ErrTrailingRevocationReason)
|
||||
}
|
||||
result.RevocationReason = RevocationReasonCode(reason)
|
||||
case e.Id.Equal(OIDExtensionInvalidityDate):
|
||||
// RFC 5280, s5.3.2
|
||||
if rest, err := asn1.Unmarshal(e.Value, &result.InvalidityDate); err != nil {
|
||||
errs.AddID(ErrInvalidRevocationInvalidityDate, err)
|
||||
} else if len(rest) != 0 {
|
||||
errs.AddID(ErrTrailingRevocationInvalidityDate)
|
||||
}
|
||||
case e.Id.Equal(OIDExtensionCertificateIssuer):
|
||||
// RFC 5280, s5.3.3
|
||||
if err := parseGeneralNames(e.Value, &result.Issuer); err != nil {
|
||||
errs.AddID(ErrInvalidRevocationIssuer, err)
|
||||
}
|
||||
default:
|
||||
if e.Critical {
|
||||
errs.AddID(ErrUnhandledCriticalRevokedCertExtension, e.Id)
|
||||
}
|
||||
}
|
||||
}
|
||||
return &result
|
||||
}
|
||||
|
||||
// CheckCertificateListSignature checks that the signature in crl is from c.
|
||||
func (c *Certificate) CheckCertificateListSignature(crl *CertificateList) error {
|
||||
algo := SignatureAlgorithmFromAI(crl.SignatureAlgorithm)
|
||||
return c.CheckSignature(algo, crl.TBSCertList.Raw, crl.SignatureValue.RightAlign())
|
||||
}
|
Reference in New Issue
Block a user