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
|
||||||
// - azurekms:name=key-name;vault=vault-name?version=key-version
|
// - 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
|
// 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
|
// 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
|
// 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
|
// TODO(mariano): The implementation is using /services/keyvault/v7.1/keyvault
|
||||||
// package, at some point Azure might create a keyvault client with all the
|
// 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")
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
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")
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
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]
|
kt, ok := signatureAlgorithmMapping[req.SignatureAlgorithm]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.Errorf("keyVault does not support signature algorithm '%s'", req.SignatureAlgorithm)
|
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()
|
defer cancel()
|
||||||
|
|
||||||
resp, err := k.baseClient.CreateKey(ctx, vaultBaseURL(vault), name, keyvault.KeyCreateParameters{
|
resp, err := k.baseClient.CreateKey(ctx, vaultBaseURL(vault), name, keyvault.KeyCreateParameters{
|
||||||
Kty: kt.KeyType(req.ProtectionLevel),
|
Kty: kt.KeyType(protectionLevel),
|
||||||
KeySize: keySize,
|
KeySize: keySize,
|
||||||
Curve: kt.Curve,
|
Curve: kt.Curve,
|
||||||
KeyOps: &[]keyvault.JSONWebKeyOperation{
|
KeyOps: &[]keyvault.JSONWebKeyOperation{
|
||||||
|
|
|
@ -202,11 +202,13 @@ func TestKeyVault_CreateKey(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{"P-256", keyvault.EC, nil, keyvault.P256, ecJWK},
|
{"P-256", keyvault.EC, nil, keyvault.P256, ecJWK},
|
||||||
{"P-256 HSM", keyvault.ECHSM, 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-256 Default", keyvault.EC, nil, keyvault.P256, ecJWK},
|
||||||
{"P-384", keyvault.EC, nil, keyvault.P384, ecJWK},
|
{"P-384", keyvault.EC, nil, keyvault.P384, ecJWK},
|
||||||
{"P-521", keyvault.EC, nil, keyvault.P521, ecJWK},
|
{"P-521", keyvault.EC, nil, keyvault.P521, ecJWK},
|
||||||
{"RSA 0", keyvault.RSA, &value3072, "", rsaJWK},
|
{"RSA 0", keyvault.RSA, &value3072, "", rsaJWK},
|
||||||
{"RSA 0 HSM", keyvault.RSAHSM, &value3072, "", rsaJWK},
|
{"RSA 0 HSM", keyvault.RSAHSM, &value3072, "", rsaJWK},
|
||||||
|
{"RSA 0 HSM (uri)", keyvault.RSAHSM, &value3072, "", rsaJWK},
|
||||||
{"RSA 2048", keyvault.RSA, &value2048, "", rsaJWK},
|
{"RSA 2048", keyvault.RSA, &value2048, "", rsaJWK},
|
||||||
{"RSA 3072", keyvault.RSA, &value3072, "", rsaJWK},
|
{"RSA 3072", keyvault.RSA, &value3072, "", rsaJWK},
|
||||||
{"RSA 4096", keyvault.RSA, &value4096, "", 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",
|
SigningKey: "azurekms:name=my-key;vault=my-vault",
|
||||||
},
|
},
|
||||||
}, false},
|
}, 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{
|
{"ok P-256 Default", fields{client}, args{&apiv1.CreateKeyRequest{
|
||||||
Name: "azurekms:vault=my-vault;name=my-key",
|
Name: "azurekms:vault=my-vault;name=my-key",
|
||||||
}}, &apiv1.CreateKeyResponse{
|
}}, &apiv1.CreateKeyResponse{
|
||||||
|
@ -322,6 +334,17 @@ func TestKeyVault_CreateKey(t *testing.T) {
|
||||||
SigningKey: "azurekms:name=my-key;vault=my-vault",
|
SigningKey: "azurekms:name=my-key;vault=my-vault",
|
||||||
},
|
},
|
||||||
}, false},
|
}, 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{
|
{"ok RSA 2048", fields{client}, args{&apiv1.CreateKeyRequest{
|
||||||
Name: "azurekms:vault=my-vault;name=my-key",
|
Name: "azurekms:vault=my-vault;name=my-key",
|
||||||
Bits: 2048,
|
Bits: 2048,
|
||||||
|
|
|
@ -25,7 +25,7 @@ type Signer struct {
|
||||||
|
|
||||||
// NewSigner creates a new signer using a key in the AWS KMS.
|
// NewSigner creates a new signer using a key in the AWS KMS.
|
||||||
func NewSigner(client KeyVaultClient, signingKey string) (crypto.Signer, error) {
|
func NewSigner(client KeyVaultClient, signingKey string) (crypto.Signer, error) {
|
||||||
vault, name, version, err := parseKeyName(signingKey)
|
vault, name, version, _, err := parseKeyName(signingKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -221,6 +221,12 @@ func TestSigner_Sign(t *testing.T) {
|
||||||
{"fail sign length", "", keyvault.ES256, p256Digest, keyvault.KeyOperationResult{
|
{"fail sign length", "", keyvault.ES256, p256Digest, keyvault.KeyOperationResult{
|
||||||
Result: &rsaSHA256ResultSig,
|
Result: &rsaSHA256ResultSig,
|
||||||
}, nil},
|
}, nil},
|
||||||
|
{"fail base64", "", keyvault.ES256, p256Digest, keyvault.KeyOperationResult{
|
||||||
|
Result: func() *string {
|
||||||
|
v := "😎"
|
||||||
|
return &v
|
||||||
|
}(),
|
||||||
|
}, nil},
|
||||||
}
|
}
|
||||||
for _, e := range expects {
|
for _, e := range expects {
|
||||||
value := base64.RawURLEncoding.EncodeToString(e.digest)
|
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{
|
{"fail sign length", fields{client, "https://my-vault.vault.azure.net/", "my-key", "", p256}, args{
|
||||||
rand.Reader, p256Digest[:], crypto.SHA256,
|
rand.Reader, p256Digest[:], crypto.SHA256,
|
||||||
}, nil, true},
|
}, 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{
|
{"fail RSA-PSS salt length", fields{client, "https://my-vault.vault.azure.net/", "my-key", "", rsaPSSSHA256}, args{
|
||||||
rand.Reader, rsaPSSSHA256Digest[:], &rsa.PSSOptions{
|
rand.Reader, rsaPSSSHA256Digest[:], &rsa.PSSOptions{
|
||||||
SaltLength: 64,
|
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:
|
// 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
|
||||||
// - 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
|
// The key-id defines the version of the key, if it is not passed the latest
|
||||||
// version will be used.
|
// 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
|
var u *uri.URI
|
||||||
|
|
||||||
u, err = uri.ParseWithScheme("azurekms", rawURI)
|
u, err = uri.ParseWithScheme("azurekms", rawURI)
|
||||||
|
@ -63,6 +67,7 @@ func parseKeyName(rawURI string) (vault, name, version string, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
version = u.Get("version")
|
version = u.Get("version")
|
||||||
|
hsm = u.GetBool("hsm")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,21 +51,24 @@ func Test_parseKeyName(t *testing.T) {
|
||||||
wantVault string
|
wantVault string
|
||||||
wantName string
|
wantName string
|
||||||
wantVersion string
|
wantVersion string
|
||||||
|
wantHsm bool
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{"ok", args{"azurekms:name=my-key;vault=my-vault?version=my-version"}, "my-vault", "my-key", "my-version", false},
|
{"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},
|
{"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},
|
{"ok no version", args{"azurekms:name=my-key;vault=my-vault"}, "my-vault", "my-key", "", false, false},
|
||||||
{"fail scheme", args{"azure:name=my-key;vault=my-vault"}, "", "", "", true},
|
{"ok hsm", args{"azurekms:name=my-key;vault=my-vault?hsm=true"}, "my-vault", "my-key", "", true, false},
|
||||||
{"fail parse uri", args{"azurekms:name=%ZZ;vault=my-vault"}, "", "", "", true},
|
{"ok hsm false", args{"azurekms:name=my-key;vault=my-vault?hsm=false"}, "my-vault", "my-key", "", false, false},
|
||||||
{"fail no name", args{"azurekms:vault=my-vault"}, "", "", "", true},
|
{"fail scheme", args{"azure:name=my-key;vault=my-vault"}, "", "", "", false, true},
|
||||||
{"fail empty name", args{"azurekms:name=;vault=my-vault"}, "", "", "", true},
|
{"fail parse uri", args{"azurekms:name=%ZZ;vault=my-vault"}, "", "", "", false, true},
|
||||||
{"fail no vault", args{"azurekms:name=my-key"}, "", "", "", true},
|
{"fail no name", args{"azurekms:vault=my-vault"}, "", "", "", false, true},
|
||||||
{"fail empty vault", args{"azurekms:name=my-key;vault="}, "", "", "", 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 {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
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 {
|
if (err != nil) != tt.wantErr {
|
||||||
t.Errorf("parseKeyName() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("parseKeyName() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
return
|
return
|
||||||
|
@ -79,6 +82,9 @@ func Test_parseKeyName(t *testing.T) {
|
||||||
if gotVersion != tt.wantVersion {
|
if gotVersion != tt.wantVersion {
|
||||||
t.Errorf("parseKeyName() gotVersion = %v, want %v", 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