Add P384 and P521 support to Transit (#7551)

This commit is contained in:
Jeff Mitchell 2019-10-03 12:32:43 -04:00 committed by GitHub
parent 71cb7cbf18
commit 6d1e804a22
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 213 additions and 28 deletions

View file

@ -16,6 +16,8 @@ func TestTransit_BackupRestore(t *testing.T) {
// Test signing/verification after a restore for supported keys
testBackupRestore(t, "ecdsa-p256", "sign-verify")
testBackupRestore(t, "ecdsa-p384", "sign-verify")
testBackupRestore(t, "ecdsa-p521", "sign-verify")
testBackupRestore(t, "ed25519", "sign-verify")
testBackupRestore(t, "rsa-2048", "sign-verify")
testBackupRestore(t, "rsa-4096", "sign-verify")
@ -24,6 +26,8 @@ func TestTransit_BackupRestore(t *testing.T) {
testBackupRestore(t, "aes256-gcm96", "hmac-verify")
testBackupRestore(t, "chacha20-poly1305", "hmac-verify")
testBackupRestore(t, "ecdsa-p256", "hmac-verify")
testBackupRestore(t, "ecdsa-p384", "hmac-verify")
testBackupRestore(t, "ecdsa-p521", "hmac-verify")
testBackupRestore(t, "ed25519", "hmac-verify")
testBackupRestore(t, "rsa-2048", "hmac-verify")
testBackupRestore(t, "rsa-4096", "hmac-verify")

View file

@ -49,6 +49,14 @@ func TestTransit_ConfigSettings(t *testing.T) {
req.Data["type"] = "ecdsa-p256"
doReq(req)
req.Path = "keys/p384"
req.Data["type"] = "ecdsa-p384"
doReq(req)
req.Path = "keys/p521"
req.Data["type"] = "ecdsa-p521"
doReq(req)
delete(req.Data, "type")
req.Path = "keys/aes/rotate"
@ -69,6 +77,18 @@ func TestTransit_ConfigSettings(t *testing.T) {
doReq(req)
doReq(req)
req.Path = "keys/p384/rotate"
doReq(req)
doReq(req)
doReq(req)
doReq(req)
req.Path = "keys/p521/rotate"
doReq(req)
doReq(req)
doReq(req)
doReq(req)
req.Path = "keys/aes/config"
// Too high
req.Data["min_decryption_version"] = 7
@ -98,6 +118,11 @@ func TestTransit_ConfigSettings(t *testing.T) {
doReq(req)
req.Path = "keys/p256/config"
doReq(req)
req.Path = "keys/p384/config"
doReq(req)
req.Path = "keys/p521/config"
doReq(req)
req.Data = map[string]interface{}{
"plaintext": "abcd",
@ -215,4 +240,24 @@ func TestTransit_ConfigSettings(t *testing.T) {
testHMAC(4, true)
testHMAC(3, true)
testHMAC(2, false)
key = "p384"
testSignVerify(5, true)
testSignVerify(4, true)
testSignVerify(3, true)
testSignVerify(2, false)
testHMAC(5, true)
testHMAC(4, true)
testHMAC(3, true)
testHMAC(2, false)
key = "p521"
testSignVerify(5, true)
testSignVerify(4, true)
testSignVerify(3, true)
testSignVerify(2, false)
testHMAC(5, true)
testHMAC(4, true)
testHMAC(3, true)
testHMAC(2, false)
}

View file

@ -232,7 +232,7 @@ func (b *backend) pathEncryptWrite(ctx context.Context, req *logical.Request, d
polReq.KeyType = keysutil.KeyType_AES256_GCM96
case "chacha20-poly1305":
polReq.KeyType = keysutil.KeyType_ChaCha20_Poly1305
case "ecdsa-p256":
case "ecdsa-p256", "ecdsa-p384", "ecdsa-p521":
return logical.ErrorResponse(fmt.Sprintf("key type %v not supported for this operation", keyType)), logical.ErrInvalidRequest
default:
return logical.ErrorResponse(fmt.Sprintf("unknown key type %v", keyType)), logical.ErrInvalidRequest

View file

@ -164,8 +164,17 @@ func getExportKey(policy *keysutil.Policy, key *keysutil.KeyEntry, exportType st
case exportTypeSigningKey:
switch policy.Type {
case keysutil.KeyType_ECDSA_P256:
ecKey, err := keyEntryToECPrivateKey(key, elliptic.P256())
case keysutil.KeyType_ECDSA_P256, keysutil.KeyType_ECDSA_P384, keysutil.KeyType_ECDSA_P521:
var curve elliptic.Curve
switch policy.Type {
case keysutil.KeyType_ECDSA_P384:
curve = elliptic.P384()
case keysutil.KeyType_ECDSA_P521:
curve = elliptic.P521()
default:
curve = elliptic.P256()
}
ecKey, err := keyEntryToECPrivateKey(key, curve)
if err != nil {
return "", err
}

View file

@ -14,10 +14,14 @@ func TestTransit_Export_KeyVersion_ExportsCorrectVersion(t *testing.T) {
verifyExportsCorrectVersion(t, "encryption-key", "aes256-gcm96")
verifyExportsCorrectVersion(t, "encryption-key", "chacha20-poly1305")
verifyExportsCorrectVersion(t, "signing-key", "ecdsa-p256")
verifyExportsCorrectVersion(t, "signing-key", "ecdsa-p384")
verifyExportsCorrectVersion(t, "signing-key", "ecdsa-p521")
verifyExportsCorrectVersion(t, "signing-key", "ed25519")
verifyExportsCorrectVersion(t, "hmac-key", "aes256-gcm96")
verifyExportsCorrectVersion(t, "hmac-key", "chacha20-poly1305")
verifyExportsCorrectVersion(t, "hmac-key", "ecdsa-p256")
verifyExportsCorrectVersion(t, "hmac-key", "ecdsa-p384")
verifyExportsCorrectVersion(t, "hmac-key", "ecdsa-p521")
verifyExportsCorrectVersion(t, "hmac-key", "ed25519")
}
@ -271,6 +275,8 @@ func TestTransit_Export_SigningDoesNotSupportSigning_ReturnsError(t *testing.T)
func TestTransit_Export_EncryptionDoesNotSupportEncryption_ReturnsError(t *testing.T) {
testTransit_Export_EncryptionDoesNotSupportEncryption_ReturnsError(t, "ecdsa-p256")
testTransit_Export_EncryptionDoesNotSupportEncryption_ReturnsError(t, "ecdsa-p384")
testTransit_Export_EncryptionDoesNotSupportEncryption_ReturnsError(t, "ecdsa-p521")
testTransit_Export_EncryptionDoesNotSupportEncryption_ReturnsError(t, "ed25519")
}

View file

@ -46,7 +46,7 @@ func (b *backend) pathKeys() *framework.Path {
Default: "aes256-gcm96",
Description: `
The type of key to create. Currently, "aes256-gcm96" (symmetric), "ecdsa-p256"
(asymmetric), 'ed25519' (asymmetric), 'rsa-2048' (asymmetric), 'rsa-4096'
(asymmetric), "ecdsa-p384" (asymmetric), "ecdsa-p521" (asymmetric), "ed25519" (asymmetric), "rsa-2048" (asymmetric), "rsa-4096"
(asymmetric) are supported. Defaults to "aes256-gcm96".
`,
},
@ -145,6 +145,10 @@ func (b *backend) pathPolicyWrite(ctx context.Context, req *logical.Request, d *
polReq.KeyType = keysutil.KeyType_ChaCha20_Poly1305
case "ecdsa-p256":
polReq.KeyType = keysutil.KeyType_ECDSA_P256
case "ecdsa-p384":
polReq.KeyType = keysutil.KeyType_ECDSA_P384
case "ecdsa-p521":
polReq.KeyType = keysutil.KeyType_ECDSA_P521
case "ed25519":
polReq.KeyType = keysutil.KeyType_ED25519
case "rsa-2048":
@ -263,7 +267,7 @@ func (b *backend) pathPolicyRead(ctx context.Context, req *logical.Request, d *f
}
resp.Data["keys"] = retKeys
case keysutil.KeyType_ECDSA_P256, keysutil.KeyType_ED25519, keysutil.KeyType_RSA2048, keysutil.KeyType_RSA4096:
case keysutil.KeyType_ECDSA_P256, keysutil.KeyType_ECDSA_P384, keysutil.KeyType_ECDSA_P521, keysutil.KeyType_ED25519, keysutil.KeyType_RSA2048, keysutil.KeyType_RSA4096:
retKeys := map[string]map[string]interface{}{}
for k, v := range p.Keys {
key := asymKey{
@ -277,6 +281,10 @@ func (b *backend) pathPolicyRead(ctx context.Context, req *logical.Request, d *f
switch p.Type {
case keysutil.KeyType_ECDSA_P256:
key.Name = elliptic.P256().Params().Name
case keysutil.KeyType_ECDSA_P384:
key.Name = elliptic.P384().Params().Name
case keysutil.KeyType_ECDSA_P521:
key.Name = elliptic.P521().Params().Name
case keysutil.KeyType_ED25519:
if p.Derived {
if len(context) == 0 {

View file

@ -58,6 +58,13 @@ func TestTransit_Issue_2958(t *testing.T) {
t.Fatal(err)
}
_, err = client.Logical().Write("transit/keys/foobar", map[string]interface{}{
"type": "ecdsa-p384",
})
if err != nil {
t.Fatal(err)
}
_, err = client.Logical().Write("transit/keys/bar", map[string]interface{}{
"type": "ed25519",
})
@ -70,6 +77,11 @@ func TestTransit_Issue_2958(t *testing.T) {
t.Fatal(err)
}
_, err = client.Logical().Read("transit/keys/foobar")
if err != nil {
t.Fatal(err)
}
_, err = client.Logical().Read("transit/keys/bar")
if err != nil {
t.Fatal(err)

View file

@ -3,6 +3,7 @@ package transit
import (
"context"
"encoding/base64"
"fmt"
"strconv"
"strings"
"testing"
@ -24,7 +25,19 @@ type signOutcome struct {
keyValid bool
}
func TestTransit_SignVerify_P256(t *testing.T) {
func TestTransit_SignVerify_ECDSA(t *testing.T) {
t.Run("256", func(t *testing.T) {
testTransit_SignVerify_ECDSA(t, 256)
})
t.Run("384", func(t *testing.T) {
testTransit_SignVerify_ECDSA(t, 384)
})
t.Run("521", func(t *testing.T) {
testTransit_SignVerify_ECDSA(t, 521)
})
}
func testTransit_SignVerify_ECDSA(t *testing.T, bits int) {
b, storage := createBackendWithSysView(t)
// First create a key
@ -33,7 +46,7 @@ func TestTransit_SignVerify_P256(t *testing.T) {
Operation: logical.UpdateOperation,
Path: "keys/foo",
Data: map[string]interface{}{
"type": "ecdsa-p256",
"type": fmt.Sprintf("ecdsa-p%d", bits),
},
}
_, err := b.HandleRequest(context.Background(), req)
@ -52,35 +65,77 @@ func TestTransit_SignVerify_P256(t *testing.T) {
// Useful code to output a key for openssl verification
/*
{
key := p.Keys[p.LatestVersion]
if bits == 384 {
var curve elliptic.Curve
switch bits {
case 521:
curve = elliptic.P521()
case 384:
curve = elliptic.P384()
default:
curve = elliptic.P256()
}
key := p.Keys[strconv.Itoa(p.LatestVersion)]
keyBytes, _ := x509.MarshalECPrivateKey(&ecdsa.PrivateKey{
PublicKey: ecdsa.PublicKey{
Curve: elliptic.P256(),
X: key.X,
Y: key.Y,
Curve: curve,
X: key.EC_X,
Y: key.EC_Y,
},
D: key.D,
D: key.EC_D,
})
pemBlock := &pem.Block{
Type: "EC PRIVATE KEY",
Bytes: keyBytes,
}
pemBytes := pem.EncodeToMemory(pemBlock)
t.Fatalf("X: %s, Y: %s, D: %s, marshaled: %s", key.X.Text(16), key.Y.Text(16), key.D.Text(16), string(pemBytes))
t.Fatalf("X: %s, Y: %s, D: %s, marshaled: %s", key.EC_X.Text(16), key.EC_Y.Text(16), key.EC_D.Text(16), string(pemBytes))
}
*/
var xString, yString, dString string
switch bits {
case 384:
xString = "703457a84e48bfcb037cfb509f1870d2aa5b74c109c2f24624ab21444492575229f8711453e5c656dab596b4e26db30e"
yString = "411c5b7092a893dc8b7af39de3d21d1c26f45b27616baeac4c479ef3c9f21c194b5ac501dee47ba2b2cb243a54256524"
dString = "3de3e4fd2ecbc490e956f41f5003a1e57a84763cec7b722fa3427cf461a1148ea4d5206023bcce0422289f6633730759"
/*
-----BEGIN EC PRIVATE KEY-----
MIGkAgEBBDA94+T9LsvEkOlW9B9QA6HleoR2POx7ci+jQnz0YaEUjqTVIGAjvM4E
IiifZjNzB1mgBwYFK4EEACKhZANiAARwNFeoTki/ywN8+1CfGHDSqlt0wQnC8kYk
qyFERJJXUin4cRRT5cZW2rWWtOJtsw5BHFtwkqiT3It6853j0h0cJvRbJ2FrrqxM
R57zyfIcGUtaxQHe5HuissskOlQlZSQ=
-----END EC PRIVATE KEY-----
*/
case 521:
xString = "1913f75fc044fe5d1f871c2629a377462fd819b174a41d3ec7d04ebd5ae35475ff8de544f4e19a9aa6b16a8f67af479be6884e00ca3147dc24d5924d66ac395e04b"
yString = "4919406b90d8323fdb5c9c4f48259c56ebcea37b40ad1a82bbbfad62a9b9c2dce515772274b84725471c7d0b7c62e10c23296b1a9d2b2586ada67735ff5d9fffc4"
dString = "1867d0fcd9bac4c5821b70a6b13117499438f8c274579c0aba254fbd85fa98892c3608576197d5534366a9aab0f904155bec46d800d23a57f7f053d91526568b09"
/*
-----BEGIN EC PRIVATE KEY-----
MIHcAgEBBEIAGGfQ/Nm6xMWCG3CmsTEXSZQ4+MJ0V5wKuiVPvYX6mIksNghXYZfV
U0Nmqaqw+QQVW+xG2ADSOlf38FPZFSZWiwmgBwYFK4EEACOhgYkDgYYABAGRP3X8
BE/l0fhxwmKaN3Ri/YGbF0pB0+x9BOvVrjVHX/jeVE9OGamqaxao9nr0eb5ohOAM
oxR9wk1ZJNZqw5XgSwBJGUBrkNgyP9tcnE9IJZxW686je0CtGoK7v61iqbnC3OUV
dyJ0uEclRxx9C3xi4QwjKWsanSslhq2mdzX/XZ//xA==
-----END EC PRIVATE KEY-----
*/
default:
xString = "7336010a6da5935113d26d9ea4bb61b3b8d102c9a8083ed432f9b58fd7e80686"
yString = "4040aa31864691a8a9e7e3ec9250e85425b797ad7be34ba8df62bfbad45ebb0e"
dString = "99e5569be8683a2691dfc560ca9dfa71e887867a3af60635a08a3e3655aba3ef"
}
keyEntry := p.Keys[strconv.Itoa(p.LatestVersion)]
_, ok := keyEntry.EC_X.SetString("7336010a6da5935113d26d9ea4bb61b3b8d102c9a8083ed432f9b58fd7e80686", 16)
_, ok := keyEntry.EC_X.SetString(xString, 16)
if !ok {
t.Fatal("could not set X")
}
_, ok = keyEntry.EC_Y.SetString("4040aa31864691a8a9e7e3ec9250e85425b797ad7be34ba8df62bfbad45ebb0e", 16)
_, ok = keyEntry.EC_Y.SetString(yString, 16)
if !ok {
t.Fatal("could not set Y")
}
_, ok = keyEntry.EC_D.SetString("99e5569be8683a2691dfc560ca9dfa71e887867a3af60635a08a3e3655aba3ef", 16)
_, ok = keyEntry.EC_D.SetString(dString, 16)
if !ok {
t.Fatal("could not set D")
}
@ -157,7 +212,14 @@ func TestTransit_SignVerify_P256(t *testing.T) {
verifyRequest(req, true, "", sig[0:len(sig)-2])
// Test a signature generated with the same key by openssl
sig = `vault:v1:MEUCIAgnEl9V8P305EBAlz68Nq4jZng5fE8k6MactcnlUw9dAiEAvJVePg3dazW6MaW7lRAVtEz82QJDVmR98tXCl8Pc7DA=`
switch bits {
case 384:
sig = `vault:v1:MGUCMHHZLRN/3ehWuWACfSCMLtFtNEAdx6Rkwon2Lx6FWCyXCXqH6A8Pz8er0Qkgvm2ElQIxAO922LmUeYzHmDSfC5is/TjFu3b4Fb+1XtoBXncc2u4t2vSuTAxEv7WMh2D2YDdxeA==`
case 521:
sig = `vault:v1:MIGIAkIBYhspOgSs/K/NUWtlBN+CfYe1IVFpUbQNSqdjT7s+QKcr6GKmdGLIQAXw0q6K0elBgzi1wgLjxwdscwMeW7tm/QQCQgDzdITGlUEd9Z7DOfLCnDP4X8pGsfO60Tvsh/BN44drZsHLtXYBXLczB/XZfIWAsPMuI5F7ExwVNbmQP0FBVri/QQ==`
default:
sig = `vault:v1:MEUCIAgnEl9V8P305EBAlz68Nq4jZng5fE8k6MactcnlUw9dAiEAvJVePg3dazW6MaW7lRAVtEz82QJDVmR98tXCl8Pc7DA=`
}
verifyRequest(req, false, "", sig)
// Test algorithm selection in the path

View file

@ -333,7 +333,7 @@ func (lm *LockManager) GetPolicy(ctx context.Context, req PolicyRequest) (retP *
return nil, false, fmt.Errorf("convergent encryption requires derivation to be enabled")
}
case KeyType_ECDSA_P256:
case KeyType_ECDSA_P256, KeyType_ECDSA_P384, KeyType_ECDSA_P521:
if req.Derived || req.Convergent {
cleanup()
return nil, false, fmt.Errorf("key derivation and convergent encryption not supported for keys of type %v", req.KeyType)

View file

@ -55,6 +55,8 @@ const (
KeyType_RSA2048
KeyType_RSA4096
KeyType_ChaCha20_Poly1305
KeyType_ECDSA_P384
KeyType_ECDSA_P521
)
const (
@ -105,7 +107,7 @@ func (kt KeyType) DecryptionSupported() bool {
func (kt KeyType) SigningSupported() bool {
switch kt {
case KeyType_ECDSA_P256, KeyType_ED25519, KeyType_RSA2048, KeyType_RSA4096:
case KeyType_ECDSA_P256, KeyType_ECDSA_P384, KeyType_ECDSA_P521, KeyType_ED25519, KeyType_RSA2048, KeyType_RSA4096:
return true
}
return false
@ -113,7 +115,7 @@ func (kt KeyType) SigningSupported() bool {
func (kt KeyType) HashSignatureInput() bool {
switch kt {
case KeyType_ECDSA_P256, KeyType_RSA2048, KeyType_RSA4096:
case KeyType_ECDSA_P256, KeyType_ECDSA_P384, KeyType_ECDSA_P521, KeyType_RSA2048, KeyType_RSA4096:
return true
}
return false
@ -135,6 +137,10 @@ func (kt KeyType) String() string {
return "chacha20-poly1305"
case KeyType_ECDSA_P256:
return "ecdsa-p256"
case KeyType_ECDSA_P384:
return "ecdsa-p384"
case KeyType_ECDSA_P521:
return "ecdsa-p521"
case KeyType_ED25519:
return "ed25519"
case KeyType_RSA2048:
@ -1063,12 +1069,25 @@ func (p *Policy) Sign(ver int, context, input []byte, hashAlgorithm HashType, si
var pubKey []byte
var err error
switch p.Type {
case KeyType_ECDSA_P256:
curveBits := 256
case KeyType_ECDSA_P256, KeyType_ECDSA_P384, KeyType_ECDSA_P521:
var curveBits int
var curve elliptic.Curve
switch p.Type {
case KeyType_ECDSA_P384:
curveBits = 384
curve = elliptic.P384()
case KeyType_ECDSA_P521:
curveBits = 521
curve = elliptic.P521()
default:
curveBits = 256
curve = elliptic.P256()
}
keyParams := p.Keys[strconv.Itoa(ver)]
key := &ecdsa.PrivateKey{
PublicKey: ecdsa.PublicKey{
Curve: elliptic.P256(),
Curve: curve,
X: keyParams.EC_X,
Y: keyParams.EC_Y,
},
@ -1242,7 +1261,17 @@ func (p *Policy) VerifySignature(context, input []byte, hashAlgorithm HashType,
}
switch p.Type {
case KeyType_ECDSA_P256:
case KeyType_ECDSA_P256, KeyType_ECDSA_P384, KeyType_ECDSA_P521:
var curve elliptic.Curve
switch p.Type {
case KeyType_ECDSA_P384:
curve = elliptic.P384()
case KeyType_ECDSA_P521:
curve = elliptic.P521()
default:
curve = elliptic.P256()
}
var ecdsaSig ecdsaSignature
switch marshaling {
@ -1267,7 +1296,7 @@ func (p *Policy) VerifySignature(context, input []byte, hashAlgorithm HashType,
keyParams := p.Keys[strconv.Itoa(ver)]
key := &ecdsa.PublicKey{
Curve: elliptic.P256(),
Curve: curve,
X: keyParams.EC_X,
Y: keyParams.EC_Y,
}
@ -1378,8 +1407,18 @@ func (p *Policy) Rotate(ctx context.Context, storage logical.Storage) (retErr er
}
entry.Key = newKey
case KeyType_ECDSA_P256:
privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
case KeyType_ECDSA_P256, KeyType_ECDSA_P384, KeyType_ECDSA_P521:
var curve elliptic.Curve
switch p.Type {
case KeyType_ECDSA_P384:
curve = elliptic.P384()
case KeyType_ECDSA_P521:
curve = elliptic.P521()
default:
curve = elliptic.P256()
}
privKey, err := ecdsa.GenerateKey(curve, rand.Reader)
if err != nil {
return err
}