mirror of
https://github.com/smallstep/certificates.git
synced 2024-11-11 07:11:00 +00:00
Use base64 encoded signing key format
This commit is contained in:
parent
1f5f756fce
commit
1bf807add3
@ -885,6 +885,10 @@ func TestHandler_NewOrder(t *testing.T) {
|
||||
u := fmt.Sprintf("%s/acme/%s/order/ordID",
|
||||
baseURL.String(), escProvName)
|
||||
|
||||
fakeWireSigningKey := `-----BEGIN PUBLIC KEY-----
|
||||
MCowBQYDK2VwAyEA5c+4NKZSNQcR1T8qN6SjwgdPZQ0Ge12Ylx/YeGAJ35k=
|
||||
-----END PUBLIC KEY-----`
|
||||
|
||||
type test struct {
|
||||
ca acme.CertificateAuthority
|
||||
db acme.DB
|
||||
@ -1737,7 +1741,9 @@ func TestHandler_NewOrder(t *testing.T) {
|
||||
Now: time.Now,
|
||||
},
|
||||
},
|
||||
DPOP: &wire.DPOPOptions{},
|
||||
DPOP: &wire.DPOPOptions{
|
||||
SigningKey: []byte(fakeWireSigningKey),
|
||||
},
|
||||
},
|
||||
})
|
||||
acc := &acme.Account{ID: "accID"}
|
||||
|
@ -51,6 +51,9 @@ func newWireProvisionerWithOptions(t *testing.T, options *provisioner.Options) *
|
||||
}
|
||||
|
||||
func TestWireIntegration(t *testing.T) {
|
||||
fakeKey := `-----BEGIN PUBLIC KEY-----
|
||||
MCowBQYDK2VwAyEA5c+4NKZSNQcR1T8qN6SjwgdPZQ0Ge12Ylx/YeGAJ35k=
|
||||
-----END PUBLIC KEY-----`
|
||||
prov := newWireProvisionerWithOptions(t, &provisioner.Options{
|
||||
Wire: &wire.Options{
|
||||
OIDC: &wire.OIDCOptions{
|
||||
@ -72,7 +75,9 @@ func TestWireIntegration(t *testing.T) {
|
||||
Now: time.Now,
|
||||
},
|
||||
},
|
||||
DPOP: &wire.DPOPOptions{},
|
||||
DPOP: &wire.DPOPOptions{
|
||||
SigningKey: []byte(fakeKey),
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
|
@ -490,10 +490,9 @@ func wireDPOP01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSO
|
||||
return WrapErrorISE(err, "invalid Go template registered for 'target'")
|
||||
}
|
||||
|
||||
key := dpopOptions.GetSigningKey()
|
||||
params := verifyParams{
|
||||
token: dpopPayload.AccessToken,
|
||||
key: key,
|
||||
key: dpopOptions.GetSigningKey(),
|
||||
kid: kid,
|
||||
issuer: issuer,
|
||||
wireID: wireID,
|
||||
@ -548,7 +547,7 @@ type wireDpopToken map[string]any
|
||||
|
||||
type verifyParams struct {
|
||||
token string
|
||||
key string
|
||||
key crypto.PublicKey
|
||||
issuer string
|
||||
kid string
|
||||
wireID wire.ID
|
||||
@ -557,23 +556,13 @@ type verifyParams struct {
|
||||
}
|
||||
|
||||
func parseAndVerifyWireAccessToken(v verifyParams) (*wireAccessToken, *wireDpopToken, error) {
|
||||
k, err := pemutil.Parse([]byte(v.key)) // TODO(hs): move this to earlier in the configuration process? Do it once?
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed parsing public key: %w", err)
|
||||
}
|
||||
|
||||
pk, ok := k.(ed25519.PublicKey) // TODO(hs): allow more key types
|
||||
if !ok {
|
||||
return nil, nil, fmt.Errorf("unexpected type: %T", k)
|
||||
}
|
||||
|
||||
jwt, err := jose.ParseSigned(v.token)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed parsing token: %w", err)
|
||||
}
|
||||
|
||||
var accessToken wireAccessToken
|
||||
if err = jwt.Claims(pk, &accessToken); err != nil {
|
||||
if err = jwt.Claims(v.key, &accessToken); err != nil {
|
||||
return nil, nil, fmt.Errorf("failed getting token claims: %w", err)
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,7 @@ import (
|
||||
"go.step.sm/crypto/jose"
|
||||
"go.step.sm/crypto/keyutil"
|
||||
"go.step.sm/crypto/minica"
|
||||
"go.step.sm/crypto/pemutil"
|
||||
"go.step.sm/crypto/x509util"
|
||||
|
||||
"github.com/smallstep/certificates/acme/wire"
|
||||
@ -4305,10 +4306,11 @@ func createSubjectAltNameExtension(dnsNames, emailAddresses x509util.MultiString
|
||||
}
|
||||
|
||||
func Test_parseAndVerifyWireAccessToken(t *testing.T) {
|
||||
key := `
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
key := `-----BEGIN PUBLIC KEY-----
|
||||
MCowBQYDK2VwAyEA5c+4NKZSNQcR1T8qN6SjwgdPZQ0Ge12Ylx/YeGAJ35k=
|
||||
-----END PUBLIC KEY-----` // TODO(hs): different format?
|
||||
-----END PUBLIC KEY-----`
|
||||
publicKey, err := pemutil.Parse([]byte(key))
|
||||
require.NoError(t, err)
|
||||
issuer := "https://wire.example.com/clients/314845990100130665/access-token"
|
||||
kid := "QAv6C9q47Cyfd1u9z6uX3V_o-t11S8p81wLH-oTRlh0"
|
||||
wireID := wire.ID{
|
||||
@ -4327,7 +4329,7 @@ MCowBQYDK2VwAyEA5c+4NKZSNQcR1T8qN6SjwgdPZQ0Ge12Ylx/YeGAJ35k=
|
||||
|
||||
at, dpop, err := parseAndVerifyWireAccessToken(verifyParams{
|
||||
token: token,
|
||||
key: key,
|
||||
key: publicKey,
|
||||
kid: kid,
|
||||
issuer: issuer,
|
||||
wireID: wireID,
|
||||
|
@ -2,23 +2,31 @@ package wire
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"errors"
|
||||
"fmt"
|
||||
"text/template"
|
||||
|
||||
"go.step.sm/crypto/pemutil"
|
||||
)
|
||||
|
||||
type DPOPOptions struct {
|
||||
// Public part of the signing key for DPoP access token
|
||||
SigningKey string `json:"key"`
|
||||
SigningKey []byte `json:"key"`
|
||||
// URI template acme client must call to fetch the DPoP challenge proof (an access token from wire-server)
|
||||
Target string `json:"target"`
|
||||
}
|
||||
|
||||
func (o *DPOPOptions) GetSigningKey() string {
|
||||
func (o *DPOPOptions) GetSigningKey() crypto.PublicKey {
|
||||
if o == nil {
|
||||
return ""
|
||||
return nil
|
||||
}
|
||||
return o.SigningKey
|
||||
k, err := pemutil.Parse(o.SigningKey) // TODO(hs): do this once?
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return k
|
||||
}
|
||||
|
||||
func (o *DPOPOptions) GetTarget() string {
|
||||
@ -44,6 +52,9 @@ func (o *DPOPOptions) EvaluateTarget(deviceID string) (string, error) {
|
||||
}
|
||||
|
||||
func (o *DPOPOptions) validate() error {
|
||||
if _, err := pemutil.Parse(o.SigningKey); err != nil {
|
||||
return fmt.Errorf("failed parsing key: %w", err)
|
||||
}
|
||||
if _, err := template.New("DeviceID").Parse(o.GetTarget()); err != nil {
|
||||
return fmt.Errorf("failed parsing template: %w", err)
|
||||
}
|
||||
|
@ -8,6 +8,10 @@ import (
|
||||
)
|
||||
|
||||
func TestOptions_Validate(t *testing.T) {
|
||||
key := []byte(`-----BEGIN PUBLIC KEY-----
|
||||
MCowBQYDK2VwAyEA5c+4NKZSNQcR1T8qN6SjwgdPZQ0Ge12Ylx/YeGAJ35k=
|
||||
-----END PUBLIC KEY-----`)
|
||||
|
||||
type fields struct {
|
||||
OIDC *OIDCOptions
|
||||
DPOP *DPOPOptions
|
||||
@ -26,7 +30,9 @@ func TestOptions_Validate(t *testing.T) {
|
||||
},
|
||||
Config: &Config{},
|
||||
},
|
||||
DPOP: &DPOPOptions{},
|
||||
DPOP: &DPOPOptions{
|
||||
SigningKey: key,
|
||||
},
|
||||
},
|
||||
expectedErr: nil,
|
||||
},
|
||||
@ -90,6 +96,22 @@ func TestOptions_Validate(t *testing.T) {
|
||||
},
|
||||
expectedErr: errors.New("no DPoP options available"),
|
||||
},
|
||||
{
|
||||
name: "fail/invalid-key",
|
||||
fields: fields{
|
||||
OIDC: &OIDCOptions{
|
||||
Provider: &Provider{
|
||||
IssuerURL: "https://example.com",
|
||||
},
|
||||
Config: &Config{},
|
||||
},
|
||||
DPOP: &DPOPOptions{
|
||||
SigningKey: []byte{0x00},
|
||||
Target: "",
|
||||
},
|
||||
},
|
||||
expectedErr: errors.New(`failed validating DPoP options: failed parsing key: error decoding PEM: not a valid PEM encoded block`),
|
||||
},
|
||||
{
|
||||
name: "fail/target-template",
|
||||
fields: fields{
|
||||
@ -100,7 +122,8 @@ func TestOptions_Validate(t *testing.T) {
|
||||
Config: &Config{},
|
||||
},
|
||||
DPOP: &DPOPOptions{
|
||||
Target: "{{}",
|
||||
SigningKey: key,
|
||||
Target: "{{}",
|
||||
},
|
||||
},
|
||||
expectedErr: errors.New(`failed validating DPoP options: failed parsing template: template: DeviceID:1: unexpected "}" in command`),
|
||||
|
Loading…
Reference in New Issue
Block a user