mirror of https://github.com/dexidp/dex.git
20 changed files with 583 additions and 265 deletions
@ -0,0 +1,78 @@
|
||||
package signer |
||||
|
||||
import ( |
||||
"context" |
||||
"crypto/rand" |
||||
"crypto/rsa" |
||||
"encoding/hex" |
||||
"io" |
||||
|
||||
"github.com/go-jose/go-jose/v4" |
||||
) |
||||
|
||||
// MockConfig creates a mock signer with a static key for testing.
|
||||
type MockConfig struct { |
||||
Key *rsa.PrivateKey |
||||
} |
||||
|
||||
// Open creates a new mock signer.
|
||||
func (c *MockConfig) Open(_ context.Context) (Signer, error) { |
||||
if c.Key == nil { |
||||
// Generate a new key if not provided
|
||||
key, err := rsa.GenerateKey(rand.Reader, 2048) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
c.Key = key |
||||
} |
||||
|
||||
// Generate a key ID
|
||||
b := make([]byte, 20) |
||||
if _, err := io.ReadFull(rand.Reader, b); err != nil { |
||||
panic(err) |
||||
} |
||||
keyID := hex.EncodeToString(b) |
||||
|
||||
return &mockSigner{ |
||||
key: &jose.JSONWebKey{ |
||||
Key: c.Key, |
||||
KeyID: keyID, |
||||
Algorithm: "RS256", |
||||
Use: "sig", |
||||
}, |
||||
pubKey: &jose.JSONWebKey{ |
||||
Key: c.Key.Public(), |
||||
KeyID: keyID, |
||||
Algorithm: "RS256", |
||||
Use: "sig", |
||||
}, |
||||
}, nil |
||||
} |
||||
|
||||
// mockSigner is a simple signer that uses a static RSA key for testing.
|
||||
type mockSigner struct { |
||||
key *jose.JSONWebKey |
||||
pubKey *jose.JSONWebKey |
||||
} |
||||
|
||||
func (m *mockSigner) Sign(_ context.Context, payload []byte) (string, error) { |
||||
return signPayload(m.key, jose.RS256, payload) |
||||
} |
||||
|
||||
func (m *mockSigner) ValidationKeys(_ context.Context) ([]*jose.JSONWebKey, error) { |
||||
return []*jose.JSONWebKey{m.pubKey}, nil |
||||
} |
||||
|
||||
func (m *mockSigner) Algorithm(_ context.Context) (jose.SignatureAlgorithm, error) { |
||||
return jose.RS256, nil |
||||
} |
||||
|
||||
func (m *mockSigner) Start(_ context.Context) { |
||||
// Nothing to do for mock signer
|
||||
} |
||||
|
||||
// NewMockSigner creates a mock signer with the provided key for testing.
|
||||
// If key is nil, a new one will be generated.
|
||||
func NewMockSigner(key *rsa.PrivateKey) (Signer, error) { |
||||
return (&MockConfig{Key: key}).Open(context.Background()) |
||||
} |
||||
@ -0,0 +1,58 @@
|
||||
package signer |
||||
|
||||
import ( |
||||
"crypto/ecdsa" |
||||
"crypto/elliptic" |
||||
"crypto/rsa" |
||||
"errors" |
||||
"fmt" |
||||
|
||||
"github.com/go-jose/go-jose/v4" |
||||
) |
||||
|
||||
func signatureAlgorithm(jwk *jose.JSONWebKey) (alg jose.SignatureAlgorithm, err error) { |
||||
if jwk.Key == nil { |
||||
return alg, errors.New("no signing key") |
||||
} |
||||
switch key := jwk.Key.(type) { |
||||
case *rsa.PrivateKey: |
||||
// Because OIDC mandates that we support RS256, we always return that
|
||||
// value. In the future, we might want to make this configurable on a
|
||||
// per client basis. For example allowing PS256 or ECDSA variants.
|
||||
//
|
||||
// See https://github.com/dexidp/dex/issues/692
|
||||
return jose.RS256, nil |
||||
case *ecdsa.PrivateKey: |
||||
// We don't actually support ECDSA keys yet, but they're tested for
|
||||
// in case we want to in the future.
|
||||
//
|
||||
// These values are prescribed depending on the ECDSA key type. We
|
||||
// can't return different values.
|
||||
switch key.Params() { |
||||
case elliptic.P256().Params(): |
||||
return jose.ES256, nil |
||||
case elliptic.P384().Params(): |
||||
return jose.ES384, nil |
||||
case elliptic.P521().Params(): |
||||
return jose.ES512, nil |
||||
default: |
||||
return alg, errors.New("unsupported ecdsa curve") |
||||
} |
||||
default: |
||||
return alg, fmt.Errorf("unsupported signing key type %T", key) |
||||
} |
||||
} |
||||
|
||||
func signPayload(key *jose.JSONWebKey, alg jose.SignatureAlgorithm, payload []byte) (jws string, err error) { |
||||
signingKey := jose.SigningKey{Key: key, Algorithm: alg} |
||||
|
||||
signer, err := jose.NewSigner(signingKey, &jose.SignerOptions{}) |
||||
if err != nil { |
||||
return "", fmt.Errorf("new signer: %v", err) |
||||
} |
||||
signature, err := signer.Sign(payload) |
||||
if err != nil { |
||||
return "", fmt.Errorf("signing payload: %v", err) |
||||
} |
||||
return signature.CompactSerialize() |
||||
} |
||||
Loading…
Reference in new issue