mirror of https://github.com/docker/docs.git
Replace the pkcs11 library with interfaces for easier testing.
Signed-off-by: Ying Li <ying.li@docker.com> Signed-off-by: David Lawrence <david.lawrence@docker.com> Signed-off-by: Ying Li <ying.li@docker.com> (github: endophage)
This commit is contained in:
parent
7108450a21
commit
09c0f9d05b
|
|
@ -0,0 +1,40 @@
|
|||
// +build pkcs11
|
||||
|
||||
// an interface around the pkcs11 library, so that things can be mocked out
|
||||
// for testing
|
||||
|
||||
package yubikey
|
||||
|
||||
import "github.com/miekg/pkcs11"
|
||||
|
||||
// IPKCS11 is an interface for wrapping github.com/miekg/pkcs11
|
||||
type pkcs11LibLoader func(module string) IPKCS11Ctx
|
||||
|
||||
func defaultLoader(module string) IPKCS11Ctx {
|
||||
return pkcs11.New(module)
|
||||
}
|
||||
|
||||
// IPKCS11Ctx is an interface for wrapping the parts of
|
||||
// github.com/miekg/pkcs11.Ctx that yubikeystore requires
|
||||
type IPKCS11Ctx interface {
|
||||
Destroy()
|
||||
Initialize() error
|
||||
Finalize() error
|
||||
GetSlotList(tokenPresent bool) ([]uint, error)
|
||||
OpenSession(slotID uint, flags uint) (pkcs11.SessionHandle, error)
|
||||
CloseSession(sh pkcs11.SessionHandle) error
|
||||
Login(sh pkcs11.SessionHandle, userType uint, pin string) error
|
||||
Logout(sh pkcs11.SessionHandle) error
|
||||
CreateObject(sh pkcs11.SessionHandle, temp []*pkcs11.Attribute) (
|
||||
pkcs11.ObjectHandle, error)
|
||||
DestroyObject(sh pkcs11.SessionHandle, oh pkcs11.ObjectHandle) error
|
||||
GetAttributeValue(sh pkcs11.SessionHandle, o pkcs11.ObjectHandle,
|
||||
a []*pkcs11.Attribute) ([]*pkcs11.Attribute, error)
|
||||
FindObjectsInit(sh pkcs11.SessionHandle, temp []*pkcs11.Attribute) error
|
||||
FindObjects(sh pkcs11.SessionHandle, max int) (
|
||||
[]pkcs11.ObjectHandle, bool, error)
|
||||
FindObjectsFinal(sh pkcs11.SessionHandle) error
|
||||
SignInit(sh pkcs11.SessionHandle, m []*pkcs11.Mechanism,
|
||||
o pkcs11.ObjectHandle) error
|
||||
Sign(sh pkcs11.SessionHandle, message []byte) ([]byte, error)
|
||||
}
|
||||
|
|
@ -112,17 +112,21 @@ type YubiPrivateKey struct {
|
|||
data.ECDSAPublicKey
|
||||
passRetriever passphrase.Retriever
|
||||
slot []byte
|
||||
libLoader pkcs11LibLoader
|
||||
}
|
||||
|
||||
type YubikeySigner struct {
|
||||
YubiPrivateKey
|
||||
}
|
||||
|
||||
func NewYubiPrivateKey(slot []byte, pubKey data.ECDSAPublicKey, passRetriever passphrase.Retriever) *YubiPrivateKey {
|
||||
func NewYubiPrivateKey(slot []byte, pubKey data.ECDSAPublicKey,
|
||||
passRetriever passphrase.Retriever) *YubiPrivateKey {
|
||||
|
||||
return &YubiPrivateKey{
|
||||
ECDSAPublicKey: pubKey,
|
||||
passRetriever: passRetriever,
|
||||
slot: slot,
|
||||
libLoader: defaultLoader,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -135,6 +139,10 @@ func (ys *YubikeySigner) Public() crypto.PublicKey {
|
|||
return publicKey
|
||||
}
|
||||
|
||||
func (y *YubiPrivateKey) setLibLoader(loader pkcs11LibLoader) {
|
||||
y.libLoader = loader
|
||||
}
|
||||
|
||||
// CryptoSigner returns a crypto.Signer tha wraps the YubiPrivateKey. Needed for
|
||||
// Certificate generation only
|
||||
func (y *YubiPrivateKey) CryptoSigner() crypto.Signer {
|
||||
|
|
@ -153,7 +161,7 @@ func (y YubiPrivateKey) SignatureAlgorithm() data.SigAlgorithm {
|
|||
}
|
||||
|
||||
func (y *YubiPrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error) {
|
||||
ctx, session, err := SetupHSMEnv(pkcs11Lib)
|
||||
ctx, session, err := SetupHSMEnv(pkcs11Lib, y.libLoader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -186,7 +194,7 @@ func ensurePrivateKeySize(payload []byte) []byte {
|
|||
|
||||
// addECDSAKey adds a key to the yubikey
|
||||
func addECDSAKey(
|
||||
ctx *pkcs11.Ctx,
|
||||
ctx IPKCS11Ctx,
|
||||
session pkcs11.SessionHandle,
|
||||
privKey data.PrivateKey,
|
||||
pkcs11KeyID []byte,
|
||||
|
|
@ -255,7 +263,7 @@ func addECDSAKey(
|
|||
return nil
|
||||
}
|
||||
|
||||
func getECDSAKey(ctx *pkcs11.Ctx, session pkcs11.SessionHandle, pkcs11KeyID []byte) (*data.ECDSAPublicKey, string, error) {
|
||||
func getECDSAKey(ctx IPKCS11Ctx, session pkcs11.SessionHandle, pkcs11KeyID []byte) (*data.ECDSAPublicKey, string, error) {
|
||||
findTemplate := []*pkcs11.Attribute{
|
||||
pkcs11.NewAttribute(pkcs11.CKA_TOKEN, true),
|
||||
pkcs11.NewAttribute(pkcs11.CKA_ID, pkcs11KeyID),
|
||||
|
|
@ -313,7 +321,7 @@ func getECDSAKey(ctx *pkcs11.Ctx, session pkcs11.SessionHandle, pkcs11KeyID []by
|
|||
}
|
||||
|
||||
// Sign returns a signature for a given signature request
|
||||
func sign(ctx *pkcs11.Ctx, session pkcs11.SessionHandle, pkcs11KeyID []byte, passRetriever passphrase.Retriever, payload []byte) ([]byte, error) {
|
||||
func sign(ctx IPKCS11Ctx, session pkcs11.SessionHandle, pkcs11KeyID []byte, passRetriever passphrase.Retriever, payload []byte) ([]byte, error) {
|
||||
err := login(ctx, session, passRetriever, pkcs11.CKU_USER, USER_PIN)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error logging in: %v", err)
|
||||
|
|
@ -367,7 +375,7 @@ func sign(ctx *pkcs11.Ctx, session pkcs11.SessionHandle, pkcs11KeyID []byte, pas
|
|||
return sig[:], nil
|
||||
}
|
||||
|
||||
func yubiRemoveKey(ctx *pkcs11.Ctx, session pkcs11.SessionHandle, pkcs11KeyID []byte, passRetriever passphrase.Retriever, keyID string) error {
|
||||
func yubiRemoveKey(ctx IPKCS11Ctx, session pkcs11.SessionHandle, pkcs11KeyID []byte, passRetriever passphrase.Retriever, keyID string) error {
|
||||
err := login(ctx, session, passRetriever, pkcs11.CKU_SO, SO_USER_PIN)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -408,7 +416,7 @@ func yubiRemoveKey(ctx *pkcs11.Ctx, session pkcs11.SessionHandle, pkcs11KeyID []
|
|||
return nil
|
||||
}
|
||||
|
||||
func yubiListKeys(ctx *pkcs11.Ctx, session pkcs11.SessionHandle) (keys map[string]yubiSlot, err error) {
|
||||
func yubiListKeys(ctx IPKCS11Ctx, session pkcs11.SessionHandle) (keys map[string]yubiSlot, err error) {
|
||||
keys = make(map[string]yubiSlot)
|
||||
findTemplate := []*pkcs11.Attribute{
|
||||
pkcs11.NewAttribute(pkcs11.CKA_TOKEN, true),
|
||||
|
|
@ -501,7 +509,7 @@ func yubiListKeys(ctx *pkcs11.Ctx, session pkcs11.SessionHandle) (keys map[strin
|
|||
return
|
||||
}
|
||||
|
||||
func getNextEmptySlot(ctx *pkcs11.Ctx, session pkcs11.SessionHandle) ([]byte, error) {
|
||||
func getNextEmptySlot(ctx IPKCS11Ctx, session pkcs11.SessionHandle) ([]byte, error) {
|
||||
findTemplate := []*pkcs11.Attribute{
|
||||
pkcs11.NewAttribute(pkcs11.CKA_TOKEN, true),
|
||||
}
|
||||
|
|
@ -571,6 +579,7 @@ type YubiKeyStore struct {
|
|||
passRetriever passphrase.Retriever
|
||||
keys map[string]yubiSlot
|
||||
backupStore trustmanager.KeyStore
|
||||
libLoader pkcs11LibLoader
|
||||
}
|
||||
|
||||
// NewYubiKeyStore returns a YubiKeyStore, given a backup key store to write any
|
||||
|
|
@ -582,6 +591,7 @@ func NewYubiKeyStore(backupStore trustmanager.KeyStore, passphraseRetriever pass
|
|||
passRetriever: passphraseRetriever,
|
||||
keys: make(map[string]yubiSlot),
|
||||
backupStore: backupStore,
|
||||
libLoader: defaultLoader,
|
||||
}
|
||||
s.ListKeys() // populate keys field
|
||||
return s, nil
|
||||
|
|
@ -593,11 +603,15 @@ func (s YubiKeyStore) Name() string {
|
|||
return "yubikey"
|
||||
}
|
||||
|
||||
func (s *YubiKeyStore) setLibLoader(loader pkcs11LibLoader) {
|
||||
s.libLoader = loader
|
||||
}
|
||||
|
||||
func (s *YubiKeyStore) ListKeys() map[string]string {
|
||||
if len(s.keys) > 0 {
|
||||
return buildKeyMap(s.keys)
|
||||
}
|
||||
ctx, session, err := SetupHSMEnv(pkcs11Lib)
|
||||
ctx, session, err := SetupHSMEnv(pkcs11Lib, s.libLoader)
|
||||
if err != nil {
|
||||
logrus.Debugf("Failed to initialize PKCS11 environment: %s", err.Error())
|
||||
return nil
|
||||
|
|
@ -625,7 +639,7 @@ func (s *YubiKeyStore) addKey(
|
|||
return fmt.Errorf("yubikey only supports storing root keys, got %s for key: %s", role, keyID)
|
||||
}
|
||||
|
||||
ctx, session, err := SetupHSMEnv(pkcs11Lib)
|
||||
ctx, session, err := SetupHSMEnv(pkcs11Lib, s.libLoader)
|
||||
if err != nil {
|
||||
logrus.Debugf("Failed to initialize PKCS11 environment: %s", err.Error())
|
||||
return err
|
||||
|
|
@ -668,7 +682,7 @@ func (s *YubiKeyStore) addKey(
|
|||
// GetKey retrieves a key from the Yubikey only (it does not look inside the
|
||||
// backup store)
|
||||
func (s *YubiKeyStore) GetKey(keyID string) (data.PrivateKey, string, error) {
|
||||
ctx, session, err := SetupHSMEnv(pkcs11Lib)
|
||||
ctx, session, err := SetupHSMEnv(pkcs11Lib, s.libLoader)
|
||||
if err != nil {
|
||||
logrus.Debugf("Failed to initialize PKCS11 environment: %s", err.Error())
|
||||
return nil, "", err
|
||||
|
|
@ -700,7 +714,7 @@ func (s *YubiKeyStore) GetKey(keyID string) (data.PrivateKey, string, error) {
|
|||
// RemoveKey deletes a key from the Yubikey only (it does not remove it from the
|
||||
// backup store)
|
||||
func (s *YubiKeyStore) RemoveKey(keyID string) error {
|
||||
ctx, session, err := SetupHSMEnv(pkcs11Lib)
|
||||
ctx, session, err := SetupHSMEnv(pkcs11Lib, s.libLoader)
|
||||
if err != nil {
|
||||
logrus.Debugf("Failed to initialize PKCS11 environment: %s", err.Error())
|
||||
return nil
|
||||
|
|
@ -741,18 +755,20 @@ func (s *YubiKeyStore) ImportKey(pemBytes []byte, keyPath string) error {
|
|||
return s.addKey(privKey.ID(), "root", privKey, false)
|
||||
}
|
||||
|
||||
func cleanup(ctx *pkcs11.Ctx, session pkcs11.SessionHandle) {
|
||||
func cleanup(ctx IPKCS11Ctx, session pkcs11.SessionHandle) {
|
||||
ctx.CloseSession(session)
|
||||
ctx.Finalize()
|
||||
ctx.Destroy()
|
||||
}
|
||||
|
||||
// SetupHSMEnv is a method that depends on the existences
|
||||
func SetupHSMEnv(libraryPath string) (*pkcs11.Ctx, pkcs11.SessionHandle, error) {
|
||||
func SetupHSMEnv(libraryPath string, libLoader pkcs11LibLoader) (
|
||||
IPKCS11Ctx, pkcs11.SessionHandle, error) {
|
||||
|
||||
if libraryPath == "" {
|
||||
return nil, 0, errors.New("No library found.")
|
||||
}
|
||||
p := pkcs11.New(libraryPath)
|
||||
p := libLoader(libraryPath)
|
||||
|
||||
if p == nil {
|
||||
return nil, 0, errors.New("Failed to init library")
|
||||
|
|
@ -786,7 +802,7 @@ func YubikeyAccessible() bool {
|
|||
if pkcs11Lib == "" {
|
||||
return false
|
||||
}
|
||||
ctx, session, err := SetupHSMEnv(pkcs11Lib)
|
||||
ctx, session, err := SetupHSMEnv(pkcs11Lib, defaultLoader)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
|
@ -794,7 +810,7 @@ func YubikeyAccessible() bool {
|
|||
return true
|
||||
}
|
||||
|
||||
func login(ctx *pkcs11.Ctx, session pkcs11.SessionHandle, passRetriever passphrase.Retriever, userFlag uint, defaultPassw string) error {
|
||||
func login(ctx IPKCS11Ctx, session pkcs11.SessionHandle, passRetriever passphrase.Retriever, userFlag uint, defaultPassw string) error {
|
||||
// try default password
|
||||
err := ctx.Login(session, userFlag, defaultPassw)
|
||||
if err == nil {
|
||||
|
|
|
|||
Loading…
Reference in New Issue