|
|
@ -16,9 +16,31 @@ import ( |
|
|
|
// RandomReader may be overwritten for testing
|
|
|
|
var RandomReader io.Reader = rand.Reader |
|
|
|
|
|
|
|
// GeneratePublicJWK will create a new private key in JWK format
|
|
|
|
func GeneratePublicJWK(w http.ResponseWriter, r *http.Request) { |
|
|
|
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, err := getPrivKey(opts) |
|
|
|
if nil != err { |
|
|
|
http.Error(w, err.Error(), http.StatusBadRequest) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
jwk := keypairs.MarshalJWKPublicKey(keypairs.NewPublicKey(privkey.Public())) |
|
|
|
w.Write(append(jwk, '\n')) |
|
|
|
} |
|
|
|
|
|
|
|
// 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 |
|
|
@ -36,9 +58,32 @@ func GeneratePrivateJWK(w http.ResponseWriter, r *http.Request) { |
|
|
|
w.Write(append(jwk, '\n')) |
|
|
|
} |
|
|
|
|
|
|
|
// GeneratePublicDER will create a new private key in JWK format
|
|
|
|
func GeneratePublicDER(w http.ResponseWriter, r *http.Request) { |
|
|
|
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, err := getPrivKey(opts) |
|
|
|
if nil != err { |
|
|
|
http.Error(w, err.Error(), http.StatusBadRequest) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
b, _ := xkeypairs.MarshalDERPublicKey(privkey.Public()) |
|
|
|
|
|
|
|
w.Write(b) |
|
|
|
} |
|
|
|
|
|
|
|
// GeneratePrivateDER will create a new private key in a valid DER encoding
|
|
|
|
func GeneratePrivateDER(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 |
|
|
@ -56,9 +101,32 @@ func GeneratePrivateDER(w http.ResponseWriter, r *http.Request) { |
|
|
|
w.Write(der) |
|
|
|
} |
|
|
|
|
|
|
|
// GeneratePublicPEM will create a new private key in JWK format
|
|
|
|
func GeneratePublicPEM(w http.ResponseWriter, r *http.Request) { |
|
|
|
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, err := getPrivKey(opts) |
|
|
|
if nil != err { |
|
|
|
http.Error(w, err.Error(), http.StatusBadRequest) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
b, _ := xkeypairs.MarshalPEMPublicKey(privkey.Public()) |
|
|
|
|
|
|
|
w.Write(b) |
|
|
|
} |
|
|
|
|
|
|
|
// GeneratePrivatePEM will create a new private key in a valid PEM encoding
|
|
|
|
func GeneratePrivatePEM(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 |
|
|
@ -76,15 +144,24 @@ func GeneratePrivatePEM(w http.ResponseWriter, r *http.Request) { |
|
|
|
w.Write(privpem) |
|
|
|
} |
|
|
|
|
|
|
|
const maxRetry = 16 |
|
|
|
|
|
|
|
func getPrivKey(opts *options) (keypairs.PrivateKey, error) { |
|
|
|
if "" != opts.Key { |
|
|
|
return keypairs.ParsePrivateKey([]byte(opts.Key)) |
|
|
|
} |
|
|
|
return genPrivKey(opts), nil |
|
|
|
} |
|
|
|
|
|
|
|
func genPrivKey(opts *options) keypairs.PrivateKey { |
|
|
|
var privkey keypairs.PrivateKey |
|
|
|
|
|
|
|
if "RSA" == opts.KeyType { |
|
|
|
keylen := 2048 |
|
|
|
rndReader := opts.nextReader() |
|
|
|
privkey, _ = rsa.GenerateKey(rndReader, keylen) |
|
|
|
if rndReader != RandomReader { |
|
|
|
for i := 0; i < 16; i++ { |
|
|
|
otherkey, _ := rsa.GenerateKey(opts.nextRand(), keylen) |
|
|
|
privkey, _ = rsa.GenerateKey(opts.nextReader(), keylen) |
|
|
|
if 0 != opts.Seed { |
|
|
|
for i := 0; i < maxRetry; i++ { |
|
|
|
otherkey, _ := rsa.GenerateKey(opts.nextReader(), keylen) |
|
|
|
otherCmp := otherkey.D.Cmp(privkey.(*rsa.PrivateKey).D) |
|
|
|
if 0 != otherCmp { |
|
|
|
// There are two possible keys, choose the lesser D value
|
|
|
@ -94,9 +171,13 @@ func genPrivKey(opts *options) keypairs.PrivateKey { |
|
|
|
} |
|
|
|
break |
|
|
|
} |
|
|
|
if maxRetry == i-1 { |
|
|
|
log.Printf("error: coinflip landed on heads %d times", maxRetry) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
// TODO: EC keys may also suffer the same random problems in the future
|
|
|
|
privkey, _ = ecdsa.GenerateKey(elliptic.P256(), opts.nextReader()) |
|
|
|
} |
|
|
|
return privkey |
|
|
|