options: support multiple signing keys

This commit is contained in:
Caleb Doxsey 2022-12-20 11:11:52 -07:00
parent c048af7523
commit 41b51d04ef
12 changed files with 223 additions and 67 deletions

View file

@ -2,7 +2,6 @@ package handlers
import (
"bytes"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
@ -19,23 +18,21 @@ import (
// JWKSHandler returns the /.well-known/pomerium/jwks.json handler.
func JWKSHandler(
rawSigningKey string,
signingKey []byte,
additionalKeys ...any,
) http.Handler {
return cors.AllowAll().Handler(httputil.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error {
var jwks struct {
Keys []any `json:"keys"`
}
if rawSigningKey != "" {
decodedCert, err := base64.StdEncoding.DecodeString(rawSigningKey)
if err != nil {
return httputil.NewError(http.StatusInternalServerError, errors.New("bad base64 encoding for signing key"))
}
jwk, err := cryptutil.PublicJWKFromBytes(decodedCert)
if len(signingKey) > 0 {
ks, err := cryptutil.PublicJWKsFromBytes(signingKey)
if err != nil {
return httputil.NewError(http.StatusInternalServerError, errors.New("bad signing key"))
}
jwks.Keys = append(jwks.Keys, *jwk)
for _, k := range ks {
jwks.Keys = append(jwks.Keys, *k)
}
}
jwks.Keys = append(jwks.Keys, additionalKeys...)

View file

@ -19,13 +19,19 @@ import (
func TestJWKSHandler(t *testing.T) {
t.Parallel()
signingKey, err := cryptutil.NewSigningKey()
signingKey1, err := cryptutil.NewSigningKey()
require.NoError(t, err)
signingKey2, err := cryptutil.NewSigningKey()
require.NoError(t, err)
rawSigningKey, err := cryptutil.EncodePrivateKey(signingKey)
rawSigningKey1, err := cryptutil.EncodePrivateKey(signingKey1)
require.NoError(t, err)
rawSigningKey2, err := cryptutil.EncodePrivateKey(signingKey2)
require.NoError(t, err)
jwkSigningKey, err := cryptutil.PublicJWKFromBytes(rawSigningKey)
jwkSigningKey1, err := cryptutil.PublicJWKFromBytes(rawSigningKey1)
require.NoError(t, err)
jwkSigningKey2, err := cryptutil.PublicJWKFromBytes(rawSigningKey2)
require.NoError(t, err)
hpkePrivateKey, err := hpke.GeneratePrivateKey()
@ -36,24 +42,36 @@ func TestJWKSHandler(t *testing.T) {
r := httptest.NewRequest(http.MethodOptions, "/", nil)
r.Header.Set("Origin", "https://www.example.com")
r.Header.Set("Access-Control-Request-Method", "GET")
handlers.JWKSHandler("", hpkePrivateKey.PublicKey()).ServeHTTP(w, r)
handlers.JWKSHandler(nil, hpkePrivateKey.PublicKey()).ServeHTTP(w, r)
assert.Equal(t, http.StatusNoContent, w.Result().StatusCode)
})
t.Run("keys", func(t *testing.T) {
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/", nil)
handlers.JWKSHandler(base64.StdEncoding.EncodeToString(rawSigningKey), hpkePrivateKey.PublicKey()).ServeHTTP(w, r)
handlers.JWKSHandler(
append(rawSigningKey1, rawSigningKey2...),
hpkePrivateKey.PublicKey(),
).ServeHTTP(w, r)
var expect any = map[string]any{
"keys": []any{
map[string]any{
"kty": "EC",
"kid": jwkSigningKey.KeyID,
"kid": jwkSigningKey1.KeyID,
"crv": "P-256",
"alg": "ES256",
"use": "sig",
"x": base64.RawURLEncoding.EncodeToString(jwkSigningKey.Key.(*ecdsa.PublicKey).X.Bytes()),
"y": base64.RawURLEncoding.EncodeToString(jwkSigningKey.Key.(*ecdsa.PublicKey).Y.Bytes()),
"x": base64.RawURLEncoding.EncodeToString(jwkSigningKey1.Key.(*ecdsa.PublicKey).X.Bytes()),
"y": base64.RawURLEncoding.EncodeToString(jwkSigningKey1.Key.(*ecdsa.PublicKey).Y.Bytes()),
},
map[string]any{
"kty": "EC",
"kid": jwkSigningKey2.KeyID,
"crv": "P-256",
"alg": "ES256",
"use": "sig",
"x": base64.RawURLEncoding.EncodeToString(jwkSigningKey2.Key.(*ecdsa.PublicKey).X.Bytes()),
"y": base64.RawURLEncoding.EncodeToString(jwkSigningKey2.Key.(*ecdsa.PublicKey).Y.Bytes()),
},
map[string]any{
"kty": "OKP",