forked from TrueCloudLab/certificates
Allow o specify an hsm using the uri.
This commit is contained in:
parent
f1ef3fb351
commit
abdb56065d
6 changed files with 69 additions and 17 deletions
|
@ -113,11 +113,13 @@ type KeyVaultClient interface {
|
|||
//
|
||||
// - azurekms:name=key-name;vault=vault-name
|
||||
// - azurekms:name=key-name;vault=vault-name?version=key-version
|
||||
// - azurekms:name=key-name;vault=vault-name?hsm=true
|
||||
//
|
||||
// The scheme is "azurekms"; "name" is the key name; "vault" is the key vault
|
||||
// name where the key is located; "version" is an optional parameter that
|
||||
// defines the version of they key, if version is not given, the latest one will
|
||||
// be used.
|
||||
// be used; "hsm" defines if an HSM want to be used for this key, this is
|
||||
// specially useful when this is used from `step`.
|
||||
//
|
||||
// TODO(mariano): The implementation is using /services/keyvault/v7.1/keyvault
|
||||
// package, at some point Azure might create a keyvault client with all the
|
||||
|
@ -165,7 +167,7 @@ func (k *KeyVault) GetPublicKey(req *apiv1.GetPublicKeyRequest) (crypto.PublicKe
|
|||
return nil, errors.New("getPublicKeyRequest 'name' cannot be empty")
|
||||
}
|
||||
|
||||
vault, name, version, err := parseKeyName(req.Name)
|
||||
vault, name, version, _, err := parseKeyName(req.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -187,11 +189,18 @@ func (k *KeyVault) CreateKey(req *apiv1.CreateKeyRequest) (*apiv1.CreateKeyRespo
|
|||
return nil, errors.New("createKeyRequest 'name' cannot be empty")
|
||||
}
|
||||
|
||||
vault, name, _, err := parseKeyName(req.Name)
|
||||
vault, name, _, hsm, err := parseKeyName(req.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Override protection level to HSM only if it's not specified, and is given
|
||||
// in the uri.
|
||||
protectionLevel := req.ProtectionLevel
|
||||
if protectionLevel == apiv1.UnspecifiedProtectionLevel && hsm {
|
||||
protectionLevel = apiv1.HSM
|
||||
}
|
||||
|
||||
kt, ok := signatureAlgorithmMapping[req.SignatureAlgorithm]
|
||||
if !ok {
|
||||
return nil, errors.Errorf("keyVault does not support signature algorithm '%s'", req.SignatureAlgorithm)
|
||||
|
@ -216,7 +225,7 @@ func (k *KeyVault) CreateKey(req *apiv1.CreateKeyRequest) (*apiv1.CreateKeyRespo
|
|||
defer cancel()
|
||||
|
||||
resp, err := k.baseClient.CreateKey(ctx, vaultBaseURL(vault), name, keyvault.KeyCreateParameters{
|
||||
Kty: kt.KeyType(req.ProtectionLevel),
|
||||
Kty: kt.KeyType(protectionLevel),
|
||||
KeySize: keySize,
|
||||
Curve: kt.Curve,
|
||||
KeyOps: &[]keyvault.JSONWebKeyOperation{
|
||||
|
|
|
@ -202,11 +202,13 @@ func TestKeyVault_CreateKey(t *testing.T) {
|
|||
}{
|
||||
{"P-256", keyvault.EC, nil, keyvault.P256, ecJWK},
|
||||
{"P-256 HSM", keyvault.ECHSM, nil, keyvault.P256, ecJWK},
|
||||
{"P-256 HSM (uri)", keyvault.ECHSM, nil, keyvault.P256, ecJWK},
|
||||
{"P-256 Default", keyvault.EC, nil, keyvault.P256, ecJWK},
|
||||
{"P-384", keyvault.EC, nil, keyvault.P384, ecJWK},
|
||||
{"P-521", keyvault.EC, nil, keyvault.P521, ecJWK},
|
||||
{"RSA 0", keyvault.RSA, &value3072, "", rsaJWK},
|
||||
{"RSA 0 HSM", keyvault.RSAHSM, &value3072, "", rsaJWK},
|
||||
{"RSA 0 HSM (uri)", keyvault.RSAHSM, &value3072, "", rsaJWK},
|
||||
{"RSA 2048", keyvault.RSA, &value2048, "", rsaJWK},
|
||||
{"RSA 3072", keyvault.RSA, &value3072, "", rsaJWK},
|
||||
{"RSA 4096", keyvault.RSA, &value4096, "", rsaJWK},
|
||||
|
@ -269,6 +271,16 @@ func TestKeyVault_CreateKey(t *testing.T) {
|
|||
SigningKey: "azurekms:name=my-key;vault=my-vault",
|
||||
},
|
||||
}, false},
|
||||
{"ok P-256 HSM (uri)", fields{client}, args{&apiv1.CreateKeyRequest{
|
||||
Name: "azurekms:vault=my-vault;name=my-key?hsm=true",
|
||||
SignatureAlgorithm: apiv1.ECDSAWithSHA256,
|
||||
}}, &apiv1.CreateKeyResponse{
|
||||
Name: "azurekms:name=my-key;vault=my-vault",
|
||||
PublicKey: ecPub,
|
||||
CreateSignerRequest: apiv1.CreateSignerRequest{
|
||||
SigningKey: "azurekms:name=my-key;vault=my-vault",
|
||||
},
|
||||
}, false},
|
||||
{"ok P-256 Default", fields{client}, args{&apiv1.CreateKeyRequest{
|
||||
Name: "azurekms:vault=my-vault;name=my-key",
|
||||
}}, &apiv1.CreateKeyResponse{
|
||||
|
@ -322,6 +334,17 @@ func TestKeyVault_CreateKey(t *testing.T) {
|
|||
SigningKey: "azurekms:name=my-key;vault=my-vault",
|
||||
},
|
||||
}, false},
|
||||
{"ok RSA 0 HSM (uri)", fields{client}, args{&apiv1.CreateKeyRequest{
|
||||
Name: "azurekms:vault=my-vault;name=my-key;hsm=true",
|
||||
Bits: 0,
|
||||
SignatureAlgorithm: apiv1.SHA256WithRSAPSS,
|
||||
}}, &apiv1.CreateKeyResponse{
|
||||
Name: "azurekms:name=my-key;vault=my-vault",
|
||||
PublicKey: rsaPub,
|
||||
CreateSignerRequest: apiv1.CreateSignerRequest{
|
||||
SigningKey: "azurekms:name=my-key;vault=my-vault",
|
||||
},
|
||||
}, false},
|
||||
{"ok RSA 2048", fields{client}, args{&apiv1.CreateKeyRequest{
|
||||
Name: "azurekms:vault=my-vault;name=my-key",
|
||||
Bits: 2048,
|
||||
|
|
|
@ -25,7 +25,7 @@ type Signer struct {
|
|||
|
||||
// NewSigner creates a new signer using a key in the AWS KMS.
|
||||
func NewSigner(client KeyVaultClient, signingKey string) (crypto.Signer, error) {
|
||||
vault, name, version, err := parseKeyName(signingKey)
|
||||
vault, name, version, _, err := parseKeyName(signingKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -221,6 +221,12 @@ func TestSigner_Sign(t *testing.T) {
|
|||
{"fail sign length", "", keyvault.ES256, p256Digest, keyvault.KeyOperationResult{
|
||||
Result: &rsaSHA256ResultSig,
|
||||
}, nil},
|
||||
{"fail base64", "", keyvault.ES256, p256Digest, keyvault.KeyOperationResult{
|
||||
Result: func() *string {
|
||||
v := "😎"
|
||||
return &v
|
||||
}(),
|
||||
}, nil},
|
||||
}
|
||||
for _, e := range expects {
|
||||
value := base64.RawURLEncoding.EncodeToString(e.digest)
|
||||
|
@ -291,6 +297,9 @@ func TestSigner_Sign(t *testing.T) {
|
|||
{"fail sign length", fields{client, "https://my-vault.vault.azure.net/", "my-key", "", p256}, args{
|
||||
rand.Reader, p256Digest[:], crypto.SHA256,
|
||||
}, nil, true},
|
||||
{"fail base64", fields{client, "https://my-vault.vault.azure.net/", "my-key", "", p256}, args{
|
||||
rand.Reader, p256Digest[:], crypto.SHA256,
|
||||
}, nil, true},
|
||||
{"fail RSA-PSS salt length", fields{client, "https://my-vault.vault.azure.net/", "my-key", "", rsaPSSSHA256}, args{
|
||||
rand.Reader, rsaPSSSHA256Digest[:], &rsa.PSSOptions{
|
||||
SaltLength: 64,
|
||||
|
|
|
@ -42,11 +42,15 @@ func getKeyName(vault, name string, bundle keyvault.KeyBundle) string {
|
|||
// parseKeyName returns the key vault, name and version from URIs like:
|
||||
//
|
||||
// - azurekms:vault=key-vault;name=key-name
|
||||
// - azurekms:vault=key-vault;name=key-name;id=key-id
|
||||
// - azurekms:vault=key-vault;name=key-name?version=key-id
|
||||
// - azurekms:vault=key-vault;name=key-name?version=key-id&hsm=true
|
||||
//
|
||||
// The key-id defines the version of the key, if it is not passed the latest
|
||||
// version will be used.
|
||||
func parseKeyName(rawURI string) (vault, name, version string, err error) {
|
||||
//
|
||||
// HSM can also be passed to define the protection level if this is not given in
|
||||
// CreateQuery.
|
||||
func parseKeyName(rawURI string) (vault, name, version string, hsm bool, err error) {
|
||||
var u *uri.URI
|
||||
|
||||
u, err = uri.ParseWithScheme("azurekms", rawURI)
|
||||
|
@ -63,6 +67,7 @@ func parseKeyName(rawURI string) (vault, name, version string, err error) {
|
|||
return
|
||||
}
|
||||
version = u.Get("version")
|
||||
hsm = u.GetBool("hsm")
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -51,21 +51,24 @@ func Test_parseKeyName(t *testing.T) {
|
|||
wantVault string
|
||||
wantName string
|
||||
wantVersion string
|
||||
wantHsm bool
|
||||
wantErr bool
|
||||
}{
|
||||
{"ok", args{"azurekms:name=my-key;vault=my-vault?version=my-version"}, "my-vault", "my-key", "my-version", false},
|
||||
{"ok opaque version", args{"azurekms:name=my-key;vault=my-vault;version=my-version"}, "my-vault", "my-key", "my-version", false},
|
||||
{"ok no version", args{"azurekms:name=my-key;vault=my-vault"}, "my-vault", "my-key", "", false},
|
||||
{"fail scheme", args{"azure:name=my-key;vault=my-vault"}, "", "", "", true},
|
||||
{"fail parse uri", args{"azurekms:name=%ZZ;vault=my-vault"}, "", "", "", true},
|
||||
{"fail no name", args{"azurekms:vault=my-vault"}, "", "", "", true},
|
||||
{"fail empty name", args{"azurekms:name=;vault=my-vault"}, "", "", "", true},
|
||||
{"fail no vault", args{"azurekms:name=my-key"}, "", "", "", true},
|
||||
{"fail empty vault", args{"azurekms:name=my-key;vault="}, "", "", "", true},
|
||||
{"ok", args{"azurekms:name=my-key;vault=my-vault?version=my-version"}, "my-vault", "my-key", "my-version", false, false},
|
||||
{"ok opaque version", args{"azurekms:name=my-key;vault=my-vault;version=my-version"}, "my-vault", "my-key", "my-version", false, false},
|
||||
{"ok no version", args{"azurekms:name=my-key;vault=my-vault"}, "my-vault", "my-key", "", false, false},
|
||||
{"ok hsm", args{"azurekms:name=my-key;vault=my-vault?hsm=true"}, "my-vault", "my-key", "", true, false},
|
||||
{"ok hsm false", args{"azurekms:name=my-key;vault=my-vault?hsm=false"}, "my-vault", "my-key", "", false, false},
|
||||
{"fail scheme", args{"azure:name=my-key;vault=my-vault"}, "", "", "", false, true},
|
||||
{"fail parse uri", args{"azurekms:name=%ZZ;vault=my-vault"}, "", "", "", false, true},
|
||||
{"fail no name", args{"azurekms:vault=my-vault"}, "", "", "", false, true},
|
||||
{"fail empty name", args{"azurekms:name=;vault=my-vault"}, "", "", "", false, true},
|
||||
{"fail no vault", args{"azurekms:name=my-key"}, "", "", "", false, true},
|
||||
{"fail empty vault", args{"azurekms:name=my-key;vault="}, "", "", "", false, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
gotVault, gotName, gotVersion, err := parseKeyName(tt.args.rawURI)
|
||||
gotVault, gotName, gotVersion, gotHsm, err := parseKeyName(tt.args.rawURI)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("parseKeyName() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
|
@ -79,6 +82,9 @@ func Test_parseKeyName(t *testing.T) {
|
|||
if gotVersion != tt.wantVersion {
|
||||
t.Errorf("parseKeyName() gotVersion = %v, want %v", gotVersion, tt.wantVersion)
|
||||
}
|
||||
if gotHsm != tt.wantHsm {
|
||||
t.Errorf("parseKeyName() gotHsm = %v, want %v", gotHsm, tt.wantHsm)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue