package mockid import ( "bytes" "crypto/ecdsa" "crypto/elliptic" "crypto/rsa" "encoding/json" "errors" "fmt" "io/ioutil" "log" mathrand "math/rand" "net/http" "net/http/httptest" "net/url" "os" "testing" "git.coolaj86.com/coolaj86/go-mockid/mockid/api" "git.coolaj86.com/coolaj86/go-mockid/xkeypairs" "git.rootprojects.org/root/keypairs" //keypairs "github.com/big-squid/go-keypairs" //"github.com/big-squid/go-keypairs/keyfetch/uncached" ) var srv *httptest.Server type TestReader struct{} func (TestReader) Read(p []byte) (n int, err error) { return mathrand.Read(p) } var testrnd = TestReader{} func init() { api.RandomReader = testrnd rndsrc = testrnd } func TestMain(m *testing.M) { mathrand.Seed(0) // Predictable results os.Setenv("SALT", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX") jwksPrefix := "public-jwks" err := os.MkdirAll(jwksPrefix, 0755) if nil != err { fmt.Fprintf(os.Stderr, "couldn't write %q: %s", jwksPrefix, err) os.Exit(1) } privkey, _ := ecdsa.GenerateKey(elliptic.P256(), rndsrc) mux := Route(jwksPrefix, privkey) srv = httptest.NewServer(mux) //fs := http.FileServer(http.Dir("public")) //http.Handle("/", fs) os.Exit(m.Run()) } func TestGenerateJWK(t *testing.T) { client := srv.Client() urlstr, _ := url.Parse(srv.URL + "/private.jwk.json") //fmt.Println("URL:", srv.URL, urlstr) res, err := client.Do(&http.Request{ Method: "POST", URL: urlstr, }) if nil != err { //t.Fatal(err) t.Error(err) return } data, err := ioutil.ReadAll(res.Body) if nil != err { //t.Fatal(err) t.Error(err) return } jwk := map[string]string{} err = json.Unmarshal(data, &jwk) if nil != err { //t.Fatal(err) t.Error(err) return } if "" == jwk["d"] { t.Fatal("Missing key 'd' from supposed private key") } key, err := keypairs.ParsePrivateKey(data) if nil != err { t.Error(err) return } switch key.(type) { case *rsa.PrivateKey: // no-op log.Println("is RSA") case *ecdsa.PrivateKey: // no-op log.Println("is EC") default: t.Fatal(errors.New("impossible key type")) } //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 } // See https://github.com/square/go-jose/issues/189 for i := 0; i < 8; i++ { // 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) { log.Println(string(dataA)) log.Println(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) { client := srv.Client() urlstr, _ := url.Parse(srv.URL + "/priv.pem") //fmt.Println("URL:", srv.URL, urlstr) res, err := client.Do(&http.Request{ Method: "POST", URL: urlstr, }) if nil != err { //t.Fatal(err) t.Error(err) return } data, err := ioutil.ReadAll(res.Body) if nil != err { //t.Fatal(err) t.Error(err) return } key, err := xkeypairs.ParsePEMPrivateKey(data) if nil != err { t.Error(err) return } switch key.(type) { case *rsa.PrivateKey: // no-op log.Println("is RSA") case *ecdsa.PrivateKey: // no-op log.Println("is EC") default: t.Fatal(errors.New("impossible key type")) } //fmt.Printf("%#v\n", key) }