add seed for random key generator (tested)
This commit is contained in:
parent
42f1089e6c
commit
da712abbb2
|
@ -13,6 +13,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.coolaj86.com/coolaj86/go-mockid/mockid"
|
"git.coolaj86.com/coolaj86/go-mockid/mockid"
|
||||||
|
"git.coolaj86.com/coolaj86/go-mockid/xkeypairs"
|
||||||
"git.rootprojects.org/root/keypairs"
|
"git.rootprojects.org/root/keypairs"
|
||||||
|
|
||||||
_ "github.com/joho/godotenv/autoload"
|
_ "github.com/joho/godotenv/autoload"
|
||||||
|
@ -91,7 +92,7 @@ func main() {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// TODO privB := keypairs.MarshalJWKPrivateKey(privkey)
|
// TODO privB := keypairs.MarshalJWKPrivateKey(privkey)
|
||||||
privB := mockid.MarshalJWKPrivateKey(privkey)
|
privB := xkeypairs.MarshalJWKPrivateKey(privkey)
|
||||||
fmt.Printf("Private Key:\n\t%s\n", string(privB))
|
fmt.Printf("Private Key:\n\t%s\n", string(privB))
|
||||||
pubB := keypairs.MarshalJWKPublicKey(keypairs.NewPublicKey(privkey.Public()))
|
pubB := keypairs.MarshalJWKPublicKey(keypairs.NewPublicKey(privkey.Public()))
|
||||||
fmt.Printf("Public Key:\n\t%s\n", string(pubB))
|
fmt.Printf("Public Key:\n\t%s\n", string(pubB))
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/binary"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"math/rand"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// options are the things that we may need to know about a request to fulfill it properly
|
||||||
|
type options struct {
|
||||||
|
KeyType string `json:"kty"`
|
||||||
|
Seed int64 `json:"-"`
|
||||||
|
SeedStr string `json:"seed"`
|
||||||
|
rndReader io.Reader `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func getOpts(r *http.Request) (*options, error) {
|
||||||
|
rndReader := RandomReader
|
||||||
|
tok := make(map[string]interface{})
|
||||||
|
decoder := json.NewDecoder(r.Body)
|
||||||
|
err := decoder.Decode(&tok)
|
||||||
|
if nil != err && io.EOF != err {
|
||||||
|
log.Printf("json decode error: %s", err)
|
||||||
|
return nil, errors.New("Bad Request: invalid json body")
|
||||||
|
}
|
||||||
|
defer r.Body.Close()
|
||||||
|
|
||||||
|
var seed int64
|
||||||
|
seedStr, _ := tok["seed"].(string)
|
||||||
|
if "" != seedStr {
|
||||||
|
if len(seedStr) > 256 {
|
||||||
|
return nil, errors.New("Bad Request: base64 seed should be <256 characters (and is truncated to 64-bits anyway)")
|
||||||
|
}
|
||||||
|
b := sha256.Sum256([]byte(seedStr))
|
||||||
|
seed, _ = binary.ReadVarint(bytes.NewReader(b[0:8]))
|
||||||
|
}
|
||||||
|
|
||||||
|
if 0 != seed {
|
||||||
|
rndReader = rand.New(rand.NewSource(seed))
|
||||||
|
}
|
||||||
|
|
||||||
|
kty, _ := tok["kty"].(string)
|
||||||
|
if "" == kty {
|
||||||
|
if 0 == rand.Intn(2) {
|
||||||
|
kty = "RSA"
|
||||||
|
} else {
|
||||||
|
kty = "EC"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &options{
|
||||||
|
KeyType: kty,
|
||||||
|
Seed: seed,
|
||||||
|
rndReader: rndReader,
|
||||||
|
}, nil
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"crypto/elliptic"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"git.coolaj86.com/coolaj86/go-mockid/xkeypairs"
|
||||||
|
"git.rootprojects.org/root/keypairs"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RandomReader may be overwritten for testing
|
||||||
|
var RandomReader io.Reader = rand.Reader
|
||||||
|
|
||||||
|
// GeneratePrivateJWK will create a new private key in JWK format
|
||||||
|
func GeneratePrivateJWK(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Printf("%s %s", r.Method, r.URL.Path)
|
||||||
|
if "POST" != r.Method {
|
||||||
|
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
opts, err := getOpts(r)
|
||||||
|
if nil != err {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
privkey := genPrivKey(opts)
|
||||||
|
|
||||||
|
jwk := xkeypairs.MarshalJWKPrivateKey(privkey)
|
||||||
|
w.Write(append(jwk, '\n'))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GeneratePrivateDER will create a new private key in a valid DER encoding
|
||||||
|
func GeneratePrivateDER(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Printf("%s %s\n", r.Method, r.URL.Path)
|
||||||
|
if "POST" != r.Method {
|
||||||
|
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
opts, err := getOpts(r)
|
||||||
|
if nil != err {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
privkey := genPrivKey(opts)
|
||||||
|
|
||||||
|
der, _ := xkeypairs.MarshalDERPrivateKey(privkey)
|
||||||
|
w.Write(der)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GeneratePrivatePEM will create a new private key in a valid PEM encoding
|
||||||
|
func GeneratePrivatePEM(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Printf("%s %s\n", r.Method, r.URL.Path)
|
||||||
|
if "POST" != r.Method {
|
||||||
|
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
opts, err := getOpts(r)
|
||||||
|
if nil != err {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
privkey := genPrivKey(opts)
|
||||||
|
|
||||||
|
privpem, _ := xkeypairs.MarshalPEMPrivateKey(privkey)
|
||||||
|
w.Write(privpem)
|
||||||
|
}
|
||||||
|
|
||||||
|
func genPrivKey(opts *options) keypairs.PrivateKey {
|
||||||
|
var privkey keypairs.PrivateKey
|
||||||
|
if "RSA" == opts.KeyType {
|
||||||
|
keylen := 2048
|
||||||
|
privkey, _ = rsa.GenerateKey(opts.rndReader, keylen)
|
||||||
|
} else {
|
||||||
|
privkey, _ = ecdsa.GenerateKey(elliptic.P256(), opts.rndReader)
|
||||||
|
}
|
||||||
|
return privkey
|
||||||
|
}
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"git.coolaj86.com/coolaj86/go-mockid/xkeypairs"
|
||||||
"git.rootprojects.org/root/keypairs"
|
"git.rootprojects.org/root/keypairs"
|
||||||
//jwt "github.com/dgrijalva/jwt-go"
|
//jwt "github.com/dgrijalva/jwt-go"
|
||||||
)
|
)
|
||||||
|
@ -94,7 +95,7 @@ func GenToken(host string, privkey keypairs.PrivateKey, query url.Values) (strin
|
||||||
protected := fmt.Sprintf(`{"typ":"JWT","alg":%q,"kid":"%s"}`, alg, thumbprint)
|
protected := fmt.Sprintf(`{"typ":"JWT","alg":%q,"kid":"%s"}`, alg, thumbprint)
|
||||||
protected64 := base64.RawURLEncoding.EncodeToString([]byte(protected))
|
protected64 := base64.RawURLEncoding.EncodeToString([]byte(protected))
|
||||||
|
|
||||||
exp, err := parseExp(query.Get("exp"))
|
exp, err := xkeypairs.ParseDuration(query.Get("exp"))
|
||||||
if nil != err {
|
if nil != err {
|
||||||
// cryptic error code
|
// cryptic error code
|
||||||
// TODO propagate error
|
// TODO propagate error
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package mockid
|
package mockid
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
|
@ -16,6 +17,8 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"git.coolaj86.com/coolaj86/go-mockid/mockid/api"
|
||||||
|
"git.coolaj86.com/coolaj86/go-mockid/xkeypairs"
|
||||||
"git.rootprojects.org/root/keypairs"
|
"git.rootprojects.org/root/keypairs"
|
||||||
//keypairs "github.com/big-squid/go-keypairs"
|
//keypairs "github.com/big-squid/go-keypairs"
|
||||||
//"github.com/big-squid/go-keypairs/keyfetch/uncached"
|
//"github.com/big-squid/go-keypairs/keyfetch/uncached"
|
||||||
|
@ -32,6 +35,7 @@ func (TestReader) Read(p []byte) (n int, err error) {
|
||||||
var testrnd = TestReader{}
|
var testrnd = TestReader{}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
api.RandomReader = testrnd
|
||||||
rndsrc = testrnd
|
rndsrc = testrnd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,6 +114,100 @@ func TestGenerateJWK(t *testing.T) {
|
||||||
//fmt.Printf("%#v\n", jwk)
|
//fmt.Printf("%#v\n", jwk)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGenWithSeed(t *testing.T) {
|
||||||
|
// Key A
|
||||||
|
client := srv.Client()
|
||||||
|
urlstr, _ := url.Parse(srv.URL + "/private.jwk.json")
|
||||||
|
res, err := client.Do(&http.Request{
|
||||||
|
Method: "POST",
|
||||||
|
URL: urlstr,
|
||||||
|
Body: ioutil.NopCloser(bytes.NewReader([]byte(`{"seed":"test"}`))),
|
||||||
|
})
|
||||||
|
if nil != err {
|
||||||
|
//t.Fatal(err)
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dataA, err := ioutil.ReadAll(res.Body)
|
||||||
|
if nil != err {
|
||||||
|
//t.Fatal(err)
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Key B
|
||||||
|
client = srv.Client()
|
||||||
|
urlstr, _ = url.Parse(srv.URL + "/private.jwk.json")
|
||||||
|
res, err = client.Do(&http.Request{
|
||||||
|
Method: "POST",
|
||||||
|
URL: urlstr,
|
||||||
|
Body: ioutil.NopCloser(bytes.NewReader([]byte(`{"seed":"test"}`))),
|
||||||
|
})
|
||||||
|
if nil != err {
|
||||||
|
//t.Fatal(err)
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dataB, err := ioutil.ReadAll(res.Body)
|
||||||
|
if nil != err {
|
||||||
|
//t.Fatal(err)
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if '{' != dataA[0] || len(dataA) < 100 || string(dataA) != string(dataB) {
|
||||||
|
t.Error(errors.New("keys with identical seeds should be identical"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGenWithRand(t *testing.T) {
|
||||||
|
// Key A
|
||||||
|
client := srv.Client()
|
||||||
|
urlstr, _ := url.Parse(srv.URL + "/private.jwk.json")
|
||||||
|
res, err := client.Do(&http.Request{
|
||||||
|
Method: "POST",
|
||||||
|
URL: urlstr,
|
||||||
|
Body: ioutil.NopCloser(bytes.NewReader([]byte(`{"seed":""}`))),
|
||||||
|
})
|
||||||
|
if nil != err {
|
||||||
|
//t.Fatal(err)
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dataA, err := ioutil.ReadAll(res.Body)
|
||||||
|
if nil != err {
|
||||||
|
//t.Fatal(err)
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Key B
|
||||||
|
client = srv.Client()
|
||||||
|
urlstr, _ = url.Parse(srv.URL + "/private.jwk.json")
|
||||||
|
res, err = client.Do(&http.Request{
|
||||||
|
Method: "POST",
|
||||||
|
URL: urlstr,
|
||||||
|
Body: ioutil.NopCloser(bytes.NewReader([]byte(`{"seed":""}`))),
|
||||||
|
})
|
||||||
|
if nil != err {
|
||||||
|
//t.Fatal(err)
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dataB, err := ioutil.ReadAll(res.Body)
|
||||||
|
if nil != err {
|
||||||
|
//t.Fatal(err)
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(dataA) == string(dataB) {
|
||||||
|
t.Error(errors.New("keys with identical seeds should yield identical keys"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestGeneratePEM(t *testing.T) {
|
func TestGeneratePEM(t *testing.T) {
|
||||||
client := srv.Client()
|
client := srv.Client()
|
||||||
urlstr, _ := url.Parse(srv.URL + "/priv.pem")
|
urlstr, _ := url.Parse(srv.URL + "/priv.pem")
|
||||||
|
@ -131,7 +229,7 @@ func TestGeneratePEM(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
key, err := ParsePEMPrivateKey(data)
|
key, err := xkeypairs.ParsePEMPrivateKey(data)
|
||||||
if nil != err {
|
if nil != err {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
|
|
116
mockid/route.go
116
mockid/route.go
|
@ -1,20 +1,14 @@
|
||||||
package mockid
|
package mockid
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/ecdsa"
|
|
||||||
"crypto/elliptic"
|
|
||||||
"crypto/rsa"
|
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"crypto/sha512"
|
"crypto/sha512"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
mathrand "math/rand"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -22,11 +16,14 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"git.coolaj86.com/coolaj86/go-mockid/mockid/api"
|
||||||
|
"git.coolaj86.com/coolaj86/go-mockid/xkeypairs"
|
||||||
"git.rootprojects.org/root/keypairs"
|
"git.rootprojects.org/root/keypairs"
|
||||||
"git.rootprojects.org/root/keypairs/keyfetch"
|
"git.rootprojects.org/root/keypairs/keyfetch"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Route returns an HTTP Mux containing the full API
|
||||||
func Route(jwksPrefix string, privkey keypairs.PrivateKey) http.Handler {
|
func Route(jwksPrefix string, privkey keypairs.PrivateKey) http.Handler {
|
||||||
Init()
|
Init()
|
||||||
|
|
||||||
|
@ -44,12 +41,12 @@ func Route(jwksPrefix string, privkey keypairs.PrivateKey) http.Handler {
|
||||||
// is this the expiration of the nonce itself? methinks maybe so
|
// is this the expiration of the nonce itself? methinks maybe so
|
||||||
//res.setHeader("Expires", "Sun, 10 Mar 2019 08:04:45 GMT");
|
//res.setHeader("Expires", "Sun, 10 Mar 2019 08:04:45 GMT");
|
||||||
// TODO use one of the registered domains
|
// TODO use one of the registered domains
|
||||||
//var indexUrl = "https://acme-staging-v02.api.letsencrypt.org/index"
|
//var indexURL = "https://acme-staging-v02.api.letsencrypt.org/index"
|
||||||
*/
|
*/
|
||||||
//var port = (state.config.ipc && state.config.ipc.port || state._ipc.port || undefined);
|
//var port = (state.config.ipc && state.config.ipc.port || state._ipc.port || undefined);
|
||||||
//var indexUrl = "http://localhost:" + port + "/index";
|
//var indexURL = "http://localhost:" + port + "/index";
|
||||||
indexUrl := baseURL + "/index"
|
indexURL := baseURL + "/index"
|
||||||
w.Header().Set("Link", "<"+indexUrl+">;rel=\"index\"")
|
w.Header().Set("Link", "<"+indexURL+">;rel=\"index\"")
|
||||||
w.Header().Set("Cache-Control", "max-age=0, no-cache, no-store")
|
w.Header().Set("Cache-Control", "max-age=0, no-cache, no-store")
|
||||||
w.Header().Set("Pragma", "no-cache")
|
w.Header().Set("Pragma", "no-cache")
|
||||||
//res.setHeader("Strict-Transport-Security", "max-age=604800");
|
//res.setHeader("Strict-Transport-Security", "max-age=604800");
|
||||||
|
@ -184,101 +181,11 @@ func Route(jwksPrefix string, privkey keypairs.PrivateKey) http.Handler {
|
||||||
fmt.Fprintf(w, token)
|
fmt.Fprintf(w, token)
|
||||||
})
|
})
|
||||||
|
|
||||||
getKty := func(r *http.Request) (string, error) {
|
http.HandleFunc("/private.jwk.json", api.GeneratePrivateJWK)
|
||||||
tok := make(map[string]interface{})
|
|
||||||
decoder := json.NewDecoder(r.Body)
|
|
||||||
err := decoder.Decode(&tok)
|
|
||||||
if nil != err && io.EOF != err {
|
|
||||||
log.Printf("json decode error: %s", err)
|
|
||||||
return "", errors.New("Bad Request: invalid json body")
|
|
||||||
}
|
|
||||||
defer r.Body.Close()
|
|
||||||
|
|
||||||
kty, _ := tok["kty"].(string)
|
http.HandleFunc("/priv.der", api.GeneratePrivateDER)
|
||||||
if "" == kty {
|
|
||||||
if 0 == mathrand.Intn(2) {
|
|
||||||
kty = "RSA"
|
|
||||||
} else {
|
|
||||||
kty = "EC"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return kty, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
http.HandleFunc("/private.jwk.json", func(w http.ResponseWriter, r *http.Request) {
|
http.HandleFunc("/priv.pem", api.GeneratePrivatePEM)
|
||||||
log.Printf("%s %s", r.Method, r.URL.Path)
|
|
||||||
if "POST" != r.Method {
|
|
||||||
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
kty, err := getKty(r)
|
|
||||||
if nil != err {
|
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var privkey keypairs.PrivateKey
|
|
||||||
if "RSA" == kty {
|
|
||||||
keylen := 2048
|
|
||||||
privkey, _ = rsa.GenerateKey(rndsrc, keylen)
|
|
||||||
} else {
|
|
||||||
privkey, _ = ecdsa.GenerateKey(elliptic.P256(), rndsrc)
|
|
||||||
}
|
|
||||||
|
|
||||||
jwk := MarshalJWKPrivateKey(privkey)
|
|
||||||
w.Write(append(jwk, '\n'))
|
|
||||||
})
|
|
||||||
|
|
||||||
http.HandleFunc("/priv.der", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
log.Printf("%s %s\n", r.Method, r.URL.Path)
|
|
||||||
if "POST" != r.Method {
|
|
||||||
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
kty, err := getKty(r)
|
|
||||||
if nil != err {
|
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var privkey keypairs.PrivateKey
|
|
||||||
if "RSA" == kty {
|
|
||||||
keylen := 2048
|
|
||||||
privkey, _ = rsa.GenerateKey(rndsrc, keylen)
|
|
||||||
} else {
|
|
||||||
privkey, _ = ecdsa.GenerateKey(elliptic.P256(), rndsrc)
|
|
||||||
}
|
|
||||||
|
|
||||||
der, _ := MarshalDERPrivateKey(privkey)
|
|
||||||
w.Write(der)
|
|
||||||
})
|
|
||||||
|
|
||||||
http.HandleFunc("/priv.pem", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
log.Printf("%s %s\n", r.Method, r.URL.Path)
|
|
||||||
if "POST" != r.Method {
|
|
||||||
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
kty, err := getKty(r)
|
|
||||||
if nil != err {
|
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var privkey keypairs.PrivateKey
|
|
||||||
if "RSA" == kty {
|
|
||||||
keylen := 2048
|
|
||||||
privkey, _ = rsa.GenerateKey(rndsrc, keylen)
|
|
||||||
} else {
|
|
||||||
privkey, _ = ecdsa.GenerateKey(elliptic.P256(), rndsrc)
|
|
||||||
}
|
|
||||||
|
|
||||||
privpem, _ := MarshalPEMPrivateKey(privkey)
|
|
||||||
w.Write(privpem)
|
|
||||||
})
|
|
||||||
|
|
||||||
http.HandleFunc("/inspect_token", func(w http.ResponseWriter, r *http.Request) {
|
http.HandleFunc("/inspect_token", func(w http.ResponseWriter, r *http.Request) {
|
||||||
token := r.Header.Get("Authorization")
|
token := r.Header.Get("Authorization")
|
||||||
|
@ -404,7 +311,7 @@ func Route(jwksPrefix string, privkey keypairs.PrivateKey) http.Handler {
|
||||||
|
|
||||||
http.HandleFunc("/key.jwk.json", func(w http.ResponseWriter, r *http.Request) {
|
http.HandleFunc("/key.jwk.json", func(w http.ResponseWriter, r *http.Request) {
|
||||||
log.Printf("%s %s", r.Method, r.URL.Path)
|
log.Printf("%s %s", r.Method, r.URL.Path)
|
||||||
jwk := string(MarshalJWKPrivateKey(privkey))
|
jwk := string(xkeypairs.MarshalJWKPrivateKey(privkey))
|
||||||
jwk = strings.Replace(jwk, `{"`, `{ "`, 1)
|
jwk = strings.Replace(jwk, `{"`, `{ "`, 1)
|
||||||
jwk = strings.Replace(jwk, `",`, `", `, -1)
|
jwk = strings.Replace(jwk, `",`, `", `, -1)
|
||||||
jwk = jwk[0 : len(jwk)-1]
|
jwk = jwk[0 : len(jwk)-1]
|
||||||
|
@ -474,6 +381,7 @@ func getBaseURL(r *http.Request) string {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HTTPError describes an error that should be propagated to the HTTP client
|
||||||
type HTTPError struct {
|
type HTTPError struct {
|
||||||
message string
|
message string
|
||||||
code int
|
code int
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package mockid
|
package xkeypairs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
|
@ -1,4 +1,4 @@
|
||||||
package mockid
|
package xkeypairs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -6,12 +6,13 @@ import (
|
||||||
"git.rootprojects.org/root/keypairs"
|
"git.rootprojects.org/root/keypairs"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ParsePEMPrivateKey will parse a PEM Private Key (or JWK or DER) but in future versions will fail to parse other key input types
|
||||||
func ParsePEMPrivateKey(block []byte) (keypairs.PrivateKey, error) {
|
func ParsePEMPrivateKey(block []byte) (keypairs.PrivateKey, error) {
|
||||||
// TODO do not parse DER or JWK
|
// TODO do not parse DER or JWK
|
||||||
return keypairs.ParsePrivateKey(block)
|
return keypairs.ParsePrivateKey(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseExp(exp string) (int, error) {
|
func ParseDuration(exp string) (int, error) {
|
||||||
if "" == exp {
|
if "" == exp {
|
||||||
exp = "15m"
|
exp = "15m"
|
||||||
}
|
}
|
Loading…
Reference in New Issue