diff --git a/trustmanager/yubikeystore.go b/trustmanager/yubikeystore.go index d113ca1899..e44bb2ba98 100644 --- a/trustmanager/yubikeystore.go +++ b/trustmanager/yubikeystore.go @@ -30,6 +30,9 @@ const ( KeymodeTouch = 1 // touch enabled KeymodePinOnce = 2 // require pin entry once KeymodePinAlways = 4 // require pin entry all the time + + // the key size, when importing a key into yubikey, MUST be 32 bytes + ecdsaPrivateKeySize = 32 ) // what key mode to use when generating keys @@ -136,6 +139,18 @@ func (y *YubiPrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts return sig, nil } +// If a byte array is less than the number of bytes specified by +// ecdsaPrivateKeySize, left-zero-pad the byte array until +// it is the required size. +func ensurePrivateKeySize(payload []byte) []byte { + final := payload + if len(payload) < ecdsaPrivateKeySize { + final = make([]byte, ecdsaPrivateKeySize) + copy(final[ecdsaPrivateKeySize-len(payload):], payload) + } + return final +} + // addECDSAKey adds a key to the yubikey func addECDSAKey( ctx *pkcs11.Ctx, @@ -161,7 +176,7 @@ func addECDSAKey( return err } - ecdsaPrivKeyD := ecdsaPrivKey.D.Bytes() + ecdsaPrivKeyD := ensurePrivateKeySize(ecdsaPrivKey.D.Bytes()) logrus.Debugf("Getting D bytes: %v\n", ecdsaPrivKeyD) template, err := NewCertificate(role) diff --git a/trustmanager/yubikeystore_test.go b/trustmanager/yubikeystore_test.go index 4aac0c0ec8..b769404cc4 100644 --- a/trustmanager/yubikeystore_test.go +++ b/trustmanager/yubikeystore_test.go @@ -4,6 +4,7 @@ package trustmanager import ( "crypto/rand" + "reflect" "testing" "github.com/docker/notary/passphrase" @@ -25,6 +26,32 @@ func clearAllKeys(t *testing.T) { } } +func TestEnsurePrivateKeySizePassesThroughRightSizeArrays(t *testing.T) { + fullByteArray := make([]byte, ecdsaPrivateKeySize) + for i := range fullByteArray { + fullByteArray[i] = byte(1) + } + + result := ensurePrivateKeySize(fullByteArray) + assert.True(t, reflect.DeepEqual(fullByteArray, result)) +} + +// The pad32Byte helper function left zero-pads byte arrays that are less than +// ecdsaPrivateKeySize bytes +func TestEnsurePrivateKeySizePadsLessThanRequiredSizeArrays(t *testing.T) { + shortByteArray := make([]byte, ecdsaPrivateKeySize/2) + for i := range shortByteArray { + shortByteArray[i] = byte(1) + } + + expected := append( + make([]byte, ecdsaPrivateKeySize-ecdsaPrivateKeySize/2), + shortByteArray...) + + result := ensurePrivateKeySize(shortByteArray) + assert.True(t, reflect.DeepEqual(expected, result)) +} + func testAddKey(t *testing.T, store *YubiKeyStore) (data.PrivateKey, error) { privKey, err := GenerateECDSAKey(rand.Reader) assert.NoError(t, err)