From 397adb42916f4a13d5a5b8c13676ef8e97c031df Mon Sep 17 00:00:00 2001 From: Ying Li Date: Mon, 9 Nov 2015 13:05:52 -0800 Subject: [PATCH] Pad the ECDSA key that gets put into the Yubikey so it has 32 bytes. Apparently that is required by the template, and will error if it does not. Sometimes, ECDSA keys are generated which when encoded seems to only have 31 bytes. Signed-off-by: Ying Li Signed-off-by: David Lawrence Signed-off-by: Ying Li (github: endophage) --- trustmanager/yubikeystore.go | 17 ++++++++++++++++- trustmanager/yubikeystore_test.go | 27 +++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) 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)