Hashicorp Vault Transit Engine API
allows signing of data and verification of signatures. It offers more features like
encryption/decryption, hashing, random bytes generation, but in this post we’re concerned
only with the signing part of the API and more specifically with converting public keys
returned by the Vault API to JWK
format.
Example response when fetching a public key from Vault:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
curl -X GET https://myvault.com/v1/transit/keys/keyname
{
"data":
{
"keys":
{
"1":
{
"creation_time": "2022-06-13T12:21:27.257274629Z",
"name": "P-256",
"public_key": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERTx/2cyYcGVSIRP/826S32BiZxSg\nnzyXgRYmKP8N2l26ec/MwCdsHIEyraX1ZYqwMUT4wO9fqFiGsRKyMBpPnQ==\n-----END PUBLIC KEY-----\n"
}
},
"latest_version": 1,
"type": "ecdsa-p256"
}
}
|
Convert public key to JWK
Some keys like ED25519
are just random bytes and are returned as base64.StdEncoding string, while other key types
like ECDSA
and RSA
have some structure and are returned as PEM encoded keys.
Below is an example function that creates a
jose.JSONWebKey
from a Vault public key.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
package example
import (
"crypto/ed25519"
"crypto/x509"
"encoding/pem"
"fmt"
"github.com/square/go-jose/v3"
)
func jwkFromPEM(keyname string, keytype string, pemKey string) (*jose.JSONWebKey, error) {
var key interface{}
switch keytype {
case "ed25519":
pk, err := base64.StdEncoding.DecodeString(pemKey)
if err != nil {
return nil, fmt.Errorf("failed to decode ed25519 key: %v", err)
}
key = ed25519.PublicKey(pk)
case "ecdsa-p256", "ecdsa-p384", "ecdsa-p521", "rsa-2048", "rsa-4096":
block, _ := pem.Decode([]byte(pemKey))
if block == nil {
return nil, fmt.Errorf("no public key found during PEM decode")
}
var err error
key, err = x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, err
}
default:
return nil, fmt.Errorf("unsupported key type: %s", keytype)
}
return &jose.JSONWebKey{
KeyID: keyname,
Key: key,
}, nil
}
|
Example JSON encoding of a converted JWK ECDSA-P256 public key would look like:
1
2
3
4
5
6
7
|
{
"kid": "keyname",
"kty": "EC",
"crv": "P-256",
"x": "RTx_2cyYcGVSIRP_826S32BiZxSgnzyXgRYmKP8N2l0",
"y": "unnPzMAnbByBMq2l9WWKsDFE-MDvX6hYhrESsjAaT50"
}
|