Drastically simplify the method and logic; keep an in-memory cache and use that for most operations, only affecting the backend storage when needed.
This commit is contained in:
parent
c66f0918be
commit
b6b62f7dc1
|
@ -6,7 +6,11 @@ import (
|
|||
)
|
||||
|
||||
func Factory(conf *logical.BackendConfig) (logical.Backend, error) {
|
||||
return Backend().Setup(conf)
|
||||
b, err := Backend().Setup(conf)
|
||||
if err != nil {
|
||||
return b, err
|
||||
}
|
||||
return b, populateCRLs(conf.StorageView)
|
||||
}
|
||||
|
||||
func Backend() *framework.Backend {
|
||||
|
@ -17,7 +21,7 @@ func Backend() *framework.Backend {
|
|||
PathsSpecial: &logical.Paths{
|
||||
Root: []string{
|
||||
"certs/*",
|
||||
"crlsets/*",
|
||||
"crls/*",
|
||||
},
|
||||
|
||||
Unauthenticated: []string{
|
||||
|
|
|
@ -0,0 +1,261 @@
|
|||
package cert
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/fatih/structs"
|
||||
"github.com/hashicorp/vault/helper/certutil"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/hashicorp/vault/logical/framework"
|
||||
)
|
||||
|
||||
func pathCRLs(b *backend) *framework.Path {
|
||||
return &framework.Path{
|
||||
Pattern: "crls/" + framework.GenericNameRegex("name"),
|
||||
Fields: map[string]*framework.FieldSchema{
|
||||
"name": &framework.FieldSchema{
|
||||
Type: framework.TypeString,
|
||||
Description: "The name of the certificate",
|
||||
},
|
||||
|
||||
"crl": &framework.FieldSchema{
|
||||
Type: framework.TypeString,
|
||||
Description: `The public certificate that should be trusted.
|
||||
May be DER or PEM encoded. Note: the expiration time
|
||||
is ignored; if the CRL is no longer valid, delete it
|
||||
using the same name as specified here.`,
|
||||
},
|
||||
|
||||
"serial": &framework.FieldSchema{
|
||||
Type: framework.TypeString,
|
||||
Description: `If specified, for a read, information for this
|
||||
serial will be returned rather than the named CRL.
|
||||
This can be a hex-formatted string separated
|
||||
by : or -, or an integer string; this will be
|
||||
assumed to be base 10 unless prefixed by "0x"
|
||||
for base 16 or "0" for base 8.`,
|
||||
},
|
||||
},
|
||||
|
||||
Callbacks: map[logical.Operation]framework.OperationFunc{
|
||||
logical.DeleteOperation: b.pathCRLDelete,
|
||||
logical.ReadOperation: b.pathCRLRead,
|
||||
logical.WriteOperation: b.pathCRLWrite,
|
||||
},
|
||||
|
||||
HelpSynopsis: pathCRLsHelpSyn,
|
||||
HelpDescription: pathCRLsHelpDesc,
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
crls = map[string]CRLInfo{}
|
||||
crlUpdateMutex = &sync.RWMutex{}
|
||||
)
|
||||
|
||||
func populateCRLs(storage logical.Storage) error {
|
||||
crlUpdateMutex.Lock()
|
||||
defer crlUpdateMutex.Unlock()
|
||||
|
||||
keys, err := storage.List("crls/")
|
||||
if err != nil {
|
||||
return fmt.Errorf("error listing CRLs: %v", err)
|
||||
}
|
||||
if keys == nil || len(keys) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, key := range keys {
|
||||
entry, err := storage.Get("crls/" + key)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error loading CRL %s: %v", key, err)
|
||||
}
|
||||
if entry == nil {
|
||||
continue
|
||||
}
|
||||
var crlInfo CRLInfo
|
||||
err = entry.DecodeJSON(&crlInfo)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error decoding CRL %s: %v", key, err)
|
||||
}
|
||||
crls[key] = crlInfo
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func findSerialInCRLs(serial *big.Int) map[string]RevokedSerialInfo {
|
||||
crlUpdateMutex.RLock()
|
||||
defer crlUpdateMutex.RUnlock()
|
||||
ret := map[string]RevokedSerialInfo{}
|
||||
for key, crl := range crls {
|
||||
if crl.Serials == nil {
|
||||
continue
|
||||
}
|
||||
if info, ok := crl.Serials[serial.String()]; ok {
|
||||
ret[key] = info
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func parseSerialString(input string) (*big.Int, error) {
|
||||
ret := &big.Int{}
|
||||
|
||||
switch {
|
||||
case strings.Count(input, ":") > 0:
|
||||
serialBytes := certutil.ParseHexFormatted(input, ":")
|
||||
if serialBytes == nil {
|
||||
return nil, fmt.Errorf("error parsing serial %s", input)
|
||||
}
|
||||
ret.SetBytes(serialBytes)
|
||||
case strings.Count(input, "-") > 0:
|
||||
serialBytes := certutil.ParseHexFormatted(input, "-")
|
||||
if serialBytes == nil {
|
||||
return nil, fmt.Errorf("error parsing serial %s", input)
|
||||
}
|
||||
ret.SetBytes(serialBytes)
|
||||
default:
|
||||
var success bool
|
||||
ret, success = ret.SetString(input, 0)
|
||||
if !success {
|
||||
return nil, fmt.Errorf("error parsing serial %s", input)
|
||||
}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (b *backend) pathCRLDelete(
|
||||
req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
||||
name := strings.ToLower(d.Get("name").(string))
|
||||
if name == "" {
|
||||
return logical.ErrorResponse(`"name" parameter cannot be empty`), nil
|
||||
}
|
||||
|
||||
crlUpdateMutex.Lock()
|
||||
defer crlUpdateMutex.Unlock()
|
||||
|
||||
_, ok := crls[name]
|
||||
if !ok {
|
||||
return logical.ErrorResponse(fmt.Sprintf(
|
||||
"no such CRL %s", name,
|
||||
)), nil
|
||||
}
|
||||
|
||||
err := req.Storage.Delete("crls/" + name)
|
||||
if err != nil {
|
||||
return logical.ErrorResponse(fmt.Sprintf(
|
||||
"error deleting crl %s: %v", name, err),
|
||||
), nil
|
||||
}
|
||||
|
||||
delete(crls, name)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (b *backend) pathCRLRead(
|
||||
req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
||||
name := strings.ToLower(d.Get("name").(string))
|
||||
serialStr := d.Get("serial").(string)
|
||||
if name == "" && serialStr == "" {
|
||||
return logical.ErrorResponse(`"name" or "serial" parameter must be set`), nil
|
||||
}
|
||||
|
||||
crlUpdateMutex.RLock()
|
||||
defer crlUpdateMutex.RUnlock()
|
||||
|
||||
var retData map[string]interface{}
|
||||
|
||||
if serialStr != "" {
|
||||
serial, err := parseSerialString(serialStr)
|
||||
if err != nil {
|
||||
return logical.ErrorResponse(err.Error()), nil
|
||||
}
|
||||
|
||||
ret := findSerialInCRLs(serial)
|
||||
retData = structs.New(&ret).Map()
|
||||
} else {
|
||||
crl, ok := crls[name]
|
||||
if !ok {
|
||||
return logical.ErrorResponse(fmt.Sprintf(
|
||||
"no such CRL %s", name,
|
||||
)), nil
|
||||
}
|
||||
|
||||
retData = structs.New(&crl).Map()
|
||||
}
|
||||
|
||||
return &logical.Response{
|
||||
Data: retData,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (b *backend) pathCRLWrite(
|
||||
req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
||||
name := strings.ToLower(d.Get("name").(string))
|
||||
if name == "" {
|
||||
return logical.ErrorResponse(`"name" parameter cannot be empty`), nil
|
||||
}
|
||||
crl := d.Get("crl").(string)
|
||||
|
||||
certList, err := x509.ParseCRL([]byte(crl))
|
||||
if err != nil {
|
||||
return logical.ErrorResponse(fmt.Sprintf("failed to parse CRL: %v", err)), nil
|
||||
}
|
||||
if certList == nil {
|
||||
return logical.ErrorResponse("parsed CRL is nil"), nil
|
||||
}
|
||||
|
||||
crlUpdateMutex.Lock()
|
||||
defer crlUpdateMutex.Unlock()
|
||||
|
||||
crlInfo := CRLInfo{
|
||||
Serials: map[string]RevokedSerialInfo{},
|
||||
}
|
||||
for _, revokedCert := range certList.TBSCertList.RevokedCertificates {
|
||||
crlInfo.Serials[revokedCert.SerialNumber.String()] = RevokedSerialInfo{}
|
||||
}
|
||||
|
||||
entry, err := logical.StorageEntryJSON("crls/"+name, crlInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = req.Storage.Put(entry); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
crls[name] = crlInfo
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
type CRLInfo struct {
|
||||
Serials map[string]RevokedSerialInfo `json:"serials" structs:"serials" mapstructure:"serials"`
|
||||
}
|
||||
|
||||
type RevokedSerialInfo struct {
|
||||
}
|
||||
|
||||
const pathCRLsHelpSyn = `
|
||||
Manage Certificate Revocation Lists checked during authentication.
|
||||
`
|
||||
|
||||
const pathCRLsHelpDesc = `
|
||||
This endpoint allows you to create, read, update, and delete the Certificate
|
||||
Revocation Lists checked during authentication.
|
||||
|
||||
When any CRLs are in effect, any login will check the trust chains sent by a
|
||||
client against the submitted CRLs. Any chain containing a serial number revoked
|
||||
by one or more of the CRLs causes that chain to be marked as invalid for the
|
||||
authentication attempt. Conversely, *any* valid chain -- that is, a chain
|
||||
in which none of the serials are revoked by any CRL -- allows authentication.
|
||||
This allows authentication to succeed when interim parts of one chain have been
|
||||
revoked; for instance, if a certificate is signed by two intermediate CAs due to
|
||||
one of them expiring.
|
||||
`
|
|
@ -1,306 +0,0 @@
|
|||
package cert
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/vault/helper/certutil"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/hashicorp/vault/logical/framework"
|
||||
)
|
||||
|
||||
func pathCRLs(b *backend) *framework.Path {
|
||||
return &framework.Path{
|
||||
Pattern: "crls/" + framework.GenericNameRegex("name"),
|
||||
Fields: map[string]*framework.FieldSchema{
|
||||
"name": &framework.FieldSchema{
|
||||
Type: framework.TypeString,
|
||||
Description: "The name of the certificate",
|
||||
},
|
||||
|
||||
"crl": &framework.FieldSchema{
|
||||
Type: framework.TypeString,
|
||||
Description: `The public certificate that should be trusted.
|
||||
May be DER or PEM encoded. Note: the expiration time
|
||||
is ignored; if the CRL is no longer valid, delete it
|
||||
using the same name as specified here.`,
|
||||
},
|
||||
|
||||
"serial": &framework.FieldSchema{
|
||||
Type: framework.TypeString,
|
||||
Description: `If specified, for a read, information for this
|
||||
serial will be returned rather than the named CRL.
|
||||
CRL. For a delete, only this serial will be removed
|
||||
from the named CRL entry. This can be a hex-formatted
|
||||
string separated by : or -, or an integer string;
|
||||
this will be assumed to be base 10 unless prefixed
|
||||
by "0x" for base 16 or "0" for base 8.`,
|
||||
},
|
||||
},
|
||||
|
||||
Callbacks: map[logical.Operation]framework.OperationFunc{
|
||||
logical.DeleteOperation: b.pathCRLDelete,
|
||||
logical.ReadOperation: b.pathCRLRead,
|
||||
logical.WriteOperation: b.pathCRLWrite,
|
||||
},
|
||||
|
||||
HelpSynopsis: pathCRLsHelpSyn,
|
||||
HelpDescription: pathCRLsHelpDesc,
|
||||
}
|
||||
}
|
||||
|
||||
func parseSerialString(input string) (*big.Int, error) {
|
||||
ret := &big.Int{}
|
||||
|
||||
switch {
|
||||
case strings.Count(input, ":") > 0:
|
||||
serialBytes := certutil.ParseHexFormatted(input, ":")
|
||||
if serialBytes == nil {
|
||||
return nil, fmt.Errorf("error parsing serial %s", input)
|
||||
}
|
||||
ret.SetBytes(serialBytes)
|
||||
case strings.Count(input, "-") > 0:
|
||||
serialBytes := certutil.ParseHexFormatted(input, "-")
|
||||
if serialBytes == nil {
|
||||
return nil, fmt.Errorf("error parsing serial %s", input)
|
||||
}
|
||||
ret.SetBytes(serialBytes)
|
||||
default:
|
||||
var success bool
|
||||
ret, success = ret.SetString(input, 0)
|
||||
if !success {
|
||||
return nil, fmt.Errorf("error parsing serial %s", input)
|
||||
}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (b *backend) pathCRLDelete(
|
||||
req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
||||
name := strings.ToLower(d.Get("name").(string))
|
||||
if name == "" {
|
||||
return logical.ErrorResponse(`"name" parameter cannot be empty`), nil
|
||||
}
|
||||
|
||||
serialStr := d.Get("serial").(string)
|
||||
|
||||
if serialStr != "" {
|
||||
serial, err := parseSerialString(serialStr)
|
||||
if err != nil {
|
||||
return logical.ErrorResponse(err.Error()), nil
|
||||
}
|
||||
|
||||
err = b.deleteSerial(req.Storage, name, serial)
|
||||
if err != nil {
|
||||
return logical.ErrorResponse(fmt.Sprintf(
|
||||
"error deleting serial %s from CRL %s: %s", serial, name, err),
|
||||
), nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// deleteIndex is best effort to ensure it removes as much as possible if there is
|
||||
// a problem, so it does not currently return an error
|
||||
b.deleteIndex(req.Storage, name)
|
||||
|
||||
err := req.Storage.Delete("crls/set/" + name)
|
||||
if err != nil {
|
||||
return logical.ErrorResponse(fmt.Sprintf(
|
||||
"error deleting set %s: %s", name, err),
|
||||
), nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (b *backend) pathCRLRead(
|
||||
req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
||||
name := strings.ToLower(d.Get("name").(string))
|
||||
if name == "" {
|
||||
return logical.ErrorResponse(`"name" parameter cannot be empty`), nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
/*
|
||||
return &logical.Response{
|
||||
Data: map[string]interface{}{
|
||||
"certificate": cert.Certificate,
|
||||
"display_name": cert.DisplayName,
|
||||
"policies": strings.Join(cert.Policies, ","),
|
||||
"ttl": duration / time.Second,
|
||||
},
|
||||
}, nil
|
||||
*/
|
||||
}
|
||||
|
||||
func (b *backend) pathCRLWrite(
|
||||
req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
||||
name := strings.ToLower(d.Get("name").(string))
|
||||
if name == "" {
|
||||
return logical.ErrorResponse(`"name" parameter cannot be empty`), nil
|
||||
}
|
||||
crl := d.Get("crl").(string)
|
||||
|
||||
certList, err := x509.ParseCRL([]byte(crl))
|
||||
if err != nil {
|
||||
return logical.ErrorResponse(fmt.Sprintf("failed to parse CRL: %v", err)), nil
|
||||
}
|
||||
if certList == nil {
|
||||
return logical.ErrorResponse("parsed CRL is nil"), nil
|
||||
}
|
||||
|
||||
entry, err := logical.StorageEntryJSON("crls/set/"+name, crl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = req.Storage.Put(entry); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Clear out old entries if this is replacing a previously-set CRL.
|
||||
// In practice this is what the index is for; it lets us store
|
||||
// the certs individually for storage efficiency but ensure we can
|
||||
// clean up properly. So use it to clean up.
|
||||
// N.B.: This is best-effort. The worst thing that can happen is
|
||||
// some wasted storage.
|
||||
b.deleteIndex(req.Storage, name)
|
||||
|
||||
crlSetIndex := []*big.Int{}
|
||||
for _, revokedCert := range certList.TBSCertList.RevokedCertificates {
|
||||
crlSetIndex = append(crlSetIndex, revokedCert.SerialNumber)
|
||||
}
|
||||
|
||||
entry, err = logical.StorageEntryJSON("crls/index/"+name, crlSetIndex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = req.Storage.Put(entry); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, revokedSerial := range crlSetIndex {
|
||||
entry, err = logical.StorageEntryJSON("crls/serial/"+revokedSerial.String(),
|
||||
&RevokedSerialInfo{
|
||||
name: nil,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = req.Storage.Put(entry); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (b *backend) deleteIndex(storage logical.Storage, name string) {
|
||||
entry, err := storage.Get("crls/index/" + name)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if entry == nil {
|
||||
return
|
||||
}
|
||||
|
||||
crlSetIndex := []*big.Int{}
|
||||
var revokedSerialInfo RevokedSerialInfo
|
||||
|
||||
err = entry.DecodeJSON(&crlSetIndex)
|
||||
if err != nil {
|
||||
goto destroyIndex
|
||||
}
|
||||
|
||||
for _, serial := range crlSetIndex {
|
||||
entry, err := storage.Get("crls/serial/" + serial.String())
|
||||
if err != nil {
|
||||
goto deleteSerial
|
||||
}
|
||||
err = entry.DecodeJSON(&revokedSerialInfo)
|
||||
// In theory we could now delete the serial when it still exists in a CRL set,
|
||||
// but if we can't decode it something is wrong with the entry anyways, and
|
||||
// we're not going to be able to decode it when checking revocation either.
|
||||
if err != nil {
|
||||
goto deleteSerial
|
||||
}
|
||||
|
||||
delete(revokedSerialInfo, name)
|
||||
if len(revokedSerialInfo) > 0 {
|
||||
entry, err = logical.StorageEntryJSON("crls/serial/"+serial.String(), revokedSerialInfo)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
storage.Put(entry)
|
||||
continue
|
||||
}
|
||||
deleteSerial:
|
||||
storage.Delete("crls/serial/" + serial.String())
|
||||
}
|
||||
|
||||
destroyIndex:
|
||||
storage.Delete("crls/index/" + name)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (b *backend) deleteSerial(storage logical.Storage, name string, serial *big.Int) error {
|
||||
var revokedSerialInfo RevokedSerialInfo
|
||||
entry, err := storage.Get("crls/serial/" + serial.String())
|
||||
if err != nil {
|
||||
return fmt.Errorf("error retrieving entry for serial %s: %s", serial, err)
|
||||
}
|
||||
if entry == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
err = entry.DecodeJSON(&revokedSerialInfo)
|
||||
// In theory we could now delete the serial when it still exists in a CRL set,
|
||||
// but if we can't decode it something is wrong with the entry anyways, and
|
||||
// we're not going to be able to decode it when checking revocation either.
|
||||
if err != nil {
|
||||
goto deleteSerial
|
||||
}
|
||||
|
||||
delete(revokedSerialInfo, name)
|
||||
|
||||
if len(revokedSerialInfo) > 0 {
|
||||
entry, err := logical.StorageEntryJSON("crls/serial/"+serial.String(), revokedSerialInfo)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating updated storage entry for serial %s: %s", serial, err)
|
||||
}
|
||||
err = storage.Put(entry)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error storing updated entry for serial %s: %s", serial, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
deleteSerial:
|
||||
err = storage.Delete("crls/serial/" + serial.String())
|
||||
if err != nil {
|
||||
return fmt.Errorf("error deleting serial entry for serial %s: %s", serial, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type RevokedSerialInfo map[string]interface{}
|
||||
|
||||
//FIXME
|
||||
const pathCRLsHelpSyn = `
|
||||
Manage trusted certificates used for authentication.
|
||||
`
|
||||
|
||||
const pathCRLsHelpDesc = `
|
||||
This endpoint allows you to create, read, update, and delete trusted certificates
|
||||
that are allowed to authenticate.
|
||||
|
||||
Deleting a certificate will not revoke auth for prior authenticated connections.
|
||||
To do this, do a revoke on "login". If you don't need to revoke login immediately,
|
||||
then the next renew will cause the lease to expire.
|
||||
`
|
|
@ -5,7 +5,6 @@ import (
|
|||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/vault/logical"
|
||||
|
@ -50,10 +49,7 @@ func (b *backend) pathLogin(
|
|||
return logical.ErrorResponse("invalid certificate or no client certificate supplied"), nil
|
||||
}
|
||||
|
||||
validChain, err := b.checkRevocation(req.Storage, trustedChains)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error checking revocation: %v", err)
|
||||
}
|
||||
validChain := b.checkForValidChain(req.Storage, trustedChains)
|
||||
if !validChain {
|
||||
return logical.ErrorResponse(
|
||||
"no chain containing non-revoked certificates could be found for this login certificate",
|
||||
|
@ -139,37 +135,22 @@ func (b *backend) loadTrustedCerts(store logical.Storage) (pool *x509.CertPool,
|
|||
return
|
||||
}
|
||||
|
||||
func (b *backend) checkRevocation(store logical.Storage, chains [][]*x509.Certificate) (bool, error) {
|
||||
var revokedSerialInfo RevokedSerialInfo
|
||||
func (b *backend) checkForValidChain(store logical.Storage, chains [][]*x509.Certificate) bool {
|
||||
var badChain bool
|
||||
for _, chain := range chains {
|
||||
badChain = false
|
||||
for _, cert := range chain {
|
||||
entry, err := store.Get("crls/serial/" + cert.SerialNumber.String())
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("error looking up revoked serials: %v", err)
|
||||
}
|
||||
if entry != nil {
|
||||
err := entry.DecodeJSON(&revokedSerialInfo)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("error decoding revoked serial entry: %v", err)
|
||||
}
|
||||
if len(revokedSerialInfo) > 0 {
|
||||
// At least one active CRL is revoking this cert, so try the next chain
|
||||
badCRLs := findSerialInCRLs(cert.SerialNumber)
|
||||
if len(badCRLs) != 0 {
|
||||
badChain = true
|
||||
break
|
||||
} else {
|
||||
// We shouldn't have a stored entry with zero sets referring to it,
|
||||
// so it was accidentally orphaned; delete it
|
||||
store.Delete("crls/serial/" + cert.SerialNumber.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
if !badChain {
|
||||
return true, nil
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
return false
|
||||
}
|
||||
|
||||
// parsePEM parses a PEM encoded x509 certificate
|
||||
|
|
Loading…
Reference in New Issue