certificates/authority/authority.go
2018-10-08 21:48:44 -07:00

97 lines
2.5 KiB
Go

package authority
import (
"crypto/sha256"
realx509 "crypto/x509"
"encoding/hex"
"sync"
"time"
"github.com/smallstep/cli/crypto/pemutil"
"github.com/smallstep/cli/crypto/x509util"
)
// Authority implements the Certificate Authority internal interface.
type Authority struct {
config *Config
rootX509Crt *realx509.Certificate
intermediateIdentity *x509util.Identity
validateOnce bool
certificates *sync.Map
ottMap *sync.Map
startTime time.Time
provisionerIDIndex *sync.Map
encryptedKeyIndex *sync.Map
provisionerKeySetIndex *sync.Map
// Do not re-initialize
initOnce bool
}
// New creates and initiates a new Authority type.
func New(config *Config) (*Authority, error) {
if err := config.Validate(); err != nil {
return nil, err
}
var a = &Authority{
config: config,
certificates: new(sync.Map),
ottMap: new(sync.Map),
provisionerIDIndex: new(sync.Map),
encryptedKeyIndex: new(sync.Map),
provisionerKeySetIndex: new(sync.Map),
}
if err := a.init(); err != nil {
return nil, err
}
return a, nil
}
// init performs validation and initializes the fields of an Authority struct.
func (a *Authority) init() error {
// Check if handler has already been validated/initialized.
if a.initOnce {
return nil
}
var err error
// First load the root using our modified pem/x509 package.
a.rootX509Crt, err = pemutil.ReadCertificate(a.config.Root)
if err != nil {
return err
}
// Add root certificate to the certificate map
sum := sha256.Sum256(a.rootX509Crt.Raw)
a.certificates.Store(hex.EncodeToString(sum[:]), a.rootX509Crt)
// Decrypt and load intermediate public / private key pair.
if len(a.config.Password) > 0 {
a.intermediateIdentity, err = x509util.LoadIdentityFromDisk(
a.config.IntermediateCert,
a.config.IntermediateKey,
pemutil.WithPassword([]byte(a.config.Password)),
)
if err != nil {
return err
}
} else {
a.intermediateIdentity, err = x509util.LoadIdentityFromDisk(a.config.IntermediateCert, a.config.IntermediateKey)
if err != nil {
return err
}
}
for _, p := range a.config.AuthorityConfig.Provisioners {
a.provisionerIDIndex.Store(p.Key.KeyID, p)
if len(p.EncryptedKey) != 0 {
a.encryptedKeyIndex.Store(p.Key.KeyID, p.EncryptedKey)
}
}
a.startTime = time.Now()
// Set flag indicating that initialization has been completed, and should
// not be repeated.
a.initOnce = true
return nil
}