Compare commits
	
		
			2 Commits
		
	
	
		
			6a22bfecc4
			...
			3f7513364a
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 3f7513364a | ||
|  | 499949ba52 | 
							
								
								
									
										2
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.mod
									
									
									
									
									
								
							| @ -4,7 +4,7 @@ go 1.13 | |||||||
| 
 | 
 | ||||||
| require ( | require ( | ||||||
| 	git.rootprojects.org/root/hashcash v1.0.1 | 	git.rootprojects.org/root/hashcash v1.0.1 | ||||||
| 	git.rootprojects.org/root/keypairs v0.5.2 | 	git.rootprojects.org/root/keypairs v0.6.5 | ||||||
| 	github.com/google/uuid v1.1.1 | 	github.com/google/uuid v1.1.1 | ||||||
| 	github.com/joho/godotenv v1.3.0 | 	github.com/joho/godotenv v1.3.0 | ||||||
| 	github.com/mailgun/mailgun-go/v3 v3.6.4 | 	github.com/mailgun/mailgun-go/v3 v3.6.4 | ||||||
|  | |||||||
							
								
								
									
										4
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								go.sum
									
									
									
									
									
								
							| @ -1,7 +1,7 @@ | |||||||
| git.rootprojects.org/root/hashcash v1.0.1 h1:PkzwZu4CR5q/hwAntJdvcmNhmP0ONhetMo7rYhIZhZ0= | git.rootprojects.org/root/hashcash v1.0.1 h1:PkzwZu4CR5q/hwAntJdvcmNhmP0ONhetMo7rYhIZhZ0= | ||||||
| git.rootprojects.org/root/hashcash v1.0.1/go.mod h1:HdoULUe94o1NVMES5K6aP3p8QGQiIia73F1HNZ1+FkQ= | git.rootprojects.org/root/hashcash v1.0.1/go.mod h1:HdoULUe94o1NVMES5K6aP3p8QGQiIia73F1HNZ1+FkQ= | ||||||
| git.rootprojects.org/root/keypairs v0.5.2 h1:jr+drUUm/REaCDJTl5gT3kF2PwlXygcLsBZlqoKTZZw= | git.rootprojects.org/root/keypairs v0.6.5 h1:sdRAQD/O/JBS8+ZxUewXnY+cjQVDNH3TmcS+KtANZqA= | ||||||
| git.rootprojects.org/root/keypairs v0.5.2/go.mod h1:WGI8PadOp+4LjUuI+wNlSwcJwFtY8L9XuNjuO3213HA= | git.rootprojects.org/root/keypairs v0.6.5/go.mod h1:WGI8PadOp+4LjUuI+wNlSwcJwFtY8L9XuNjuO3213HA= | ||||||
| github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||||||
| github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||||
| github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ= | github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ= | ||||||
|  | |||||||
| @ -13,7 +13,6 @@ 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" | ||||||
| @ -92,7 +91,7 @@ func main() { | |||||||
| 	}() | 	}() | ||||||
| 
 | 
 | ||||||
| 	// TODO privB := keypairs.MarshalJWKPrivateKey(privkey) | 	// TODO privB := keypairs.MarshalJWKPrivateKey(privkey) | ||||||
| 	privB := xkeypairs.MarshalJWKPrivateKey(privkey) | 	privB := keypairs.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)) | ||||||
|  | |||||||
| @ -13,6 +13,7 @@ import ( | |||||||
| 	"net/http" | 	"net/http" | ||||||
| 
 | 
 | ||||||
| 	"git.coolaj86.com/coolaj86/go-mockid/xkeypairs" | 	"git.coolaj86.com/coolaj86/go-mockid/xkeypairs" | ||||||
|  | 	"git.rootprojects.org/root/keypairs" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| /* | /* | ||||||
| @ -47,8 +48,8 @@ func getOpts(r *http.Request) (*xkeypairs.KeyOptions, error) { | |||||||
| 		Key:  key, | 		Key:  key, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	opts.Claims, _ = tok["claims"].(xkeypairs.Object) | 	opts.Claims, _ = tok["claims"].(keypairs.Object) | ||||||
| 	opts.Header, _ = tok["header"].(xkeypairs.Object) | 	opts.Header, _ = tok["header"].(keypairs.Object) | ||||||
| 
 | 
 | ||||||
| 	var n int | 	var n int | ||||||
| 	if 0 != seed { | 	if 0 != seed { | ||||||
|  | |||||||
| @ -45,7 +45,7 @@ func GeneratePrivateJWK(w http.ResponseWriter, r *http.Request) { | |||||||
| 
 | 
 | ||||||
| 	privkey := xkeypairs.GenPrivKey(opts) | 	privkey := xkeypairs.GenPrivKey(opts) | ||||||
| 
 | 
 | ||||||
| 	jwk := xkeypairs.MarshalJWKPrivateKey(privkey) | 	jwk := keypairs.MarshalJWKPrivateKey(privkey) | ||||||
| 	w.Write(append(jwk, '\n')) | 	w.Write(append(jwk, '\n')) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -68,7 +68,7 @@ func GeneratePublicDER(w http.ResponseWriter, r *http.Request) { | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	b, _ := xkeypairs.MarshalDERPublicKey(privkey.Public()) | 	b, _ := keypairs.MarshalDERPublicKey(privkey.Public()) | ||||||
| 
 | 
 | ||||||
| 	w.Write(b) | 	w.Write(b) | ||||||
| } | } | ||||||
| @ -88,7 +88,7 @@ func GeneratePrivateDER(w http.ResponseWriter, r *http.Request) { | |||||||
| 
 | 
 | ||||||
| 	privkey := xkeypairs.GenPrivKey(opts) | 	privkey := xkeypairs.GenPrivKey(opts) | ||||||
| 
 | 
 | ||||||
| 	der, _ := xkeypairs.MarshalDERPrivateKey(privkey) | 	der, _ := keypairs.MarshalDERPrivateKey(privkey) | ||||||
| 	w.Write(der) | 	w.Write(der) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -111,7 +111,7 @@ func GeneratePublicPEM(w http.ResponseWriter, r *http.Request) { | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	b, _ := xkeypairs.MarshalPEMPublicKey(privkey.Public()) | 	b, _ := keypairs.MarshalPEMPublicKey(privkey.Public()) | ||||||
| 
 | 
 | ||||||
| 	w.Write(b) | 	w.Write(b) | ||||||
| } | } | ||||||
| @ -131,7 +131,7 @@ func GeneratePrivatePEM(w http.ResponseWriter, r *http.Request) { | |||||||
| 
 | 
 | ||||||
| 	privkey := xkeypairs.GenPrivKey(opts) | 	privkey := xkeypairs.GenPrivKey(opts) | ||||||
| 
 | 
 | ||||||
| 	privpem, _ := xkeypairs.MarshalPEMPrivateKey(privkey) | 	privpem, _ := keypairs.MarshalPEMPrivateKey(privkey) | ||||||
| 	w.Write(privpem) | 	w.Write(privpem) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ import ( | |||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 
 | 
 | ||||||
| 	"git.coolaj86.com/coolaj86/go-mockid/xkeypairs" | 	"git.rootprojects.org/root/keypairs" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // SignJWS will create an uncompressed JWT with the given payload | // SignJWS will create an uncompressed JWT with the given payload | ||||||
| @ -40,7 +40,7 @@ func sign(w http.ResponseWriter, r *http.Request, jwt bool) { | |||||||
| 		header["_seed"] = opts.Seed | 		header["_seed"] = opts.Seed | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	jws, err := xkeypairs.SignClaims(privkey, header, opts.Claims) | 	jws, err := keypairs.SignClaims(privkey, header, opts.Claims) | ||||||
| 	if nil != err { | 	if nil != err { | ||||||
| 		http.Error(w, err.Error(), http.StatusBadRequest) | 		http.Error(w, err.Error(), http.StatusBadRequest) | ||||||
| 		return | 		return | ||||||
| @ -48,7 +48,7 @@ func sign(w http.ResponseWriter, r *http.Request, jwt bool) { | |||||||
| 
 | 
 | ||||||
| 	var b []byte | 	var b []byte | ||||||
| 	if jwt { | 	if jwt { | ||||||
| 		s := xkeypairs.JWSToJWT(jws) | 		s := keypairs.JWSToJWT(jws) | ||||||
| 		w.Write(append([]byte(s), '\n')) | 		w.Write(append([]byte(s), '\n')) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -9,7 +9,7 @@ import ( | |||||||
| 	"strings" | 	"strings" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"git.coolaj86.com/coolaj86/go-mockid/xkeypairs" | 	"git.rootprojects.org/root/keypairs" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // Verify will verify both JWT and uncompressed JWS | // Verify will verify both JWT and uncompressed JWS | ||||||
| @ -19,7 +19,7 @@ func Verify(w http.ResponseWriter, r *http.Request) { | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	jws := &xkeypairs.JWS{} | 	jws := &keypairs.JWS{} | ||||||
| 
 | 
 | ||||||
| 	authzParts := strings.Split(r.Header.Get("Authorization"), " ") | 	authzParts := strings.Split(r.Header.Get("Authorization"), " ") | ||||||
| 	lenAuthz := len(authzParts) | 	lenAuthz := len(authzParts) | ||||||
| @ -75,16 +75,12 @@ func Verify(w http.ResponseWriter, r *http.Request) { | |||||||
| 		jws.Claims["exp"] = float64(time.Now().Add(5 * time.Minute).Unix()) | 		jws.Claims["exp"] = float64(time.Now().Add(5 * time.Minute).Unix()) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ok, err := xkeypairs.VerifyClaims(nil, jws) | 	errs := keypairs.VerifyClaims(nil, jws) | ||||||
| 	if nil != err { | 	if 0 == len(errs) { | ||||||
| 		log.Printf("jws verify error: %s", err) | 		log.Printf("jws verify error: %s", errs) | ||||||
| 		http.Error(w, "Bad Request: could not verify JWS claims", http.StatusBadRequest) | 		http.Error(w, "Bad Request: could not verify JWS claims", http.StatusBadRequest) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	if !ok { |  | ||||||
| 		http.Error(w, "Bad Request: invalid JWS signature", http.StatusBadRequest) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	b := []byte(`{"success":true}`) | 	b := []byte(`{"success":true}`) | ||||||
| 	w.Write(append(b, '\n')) | 	w.Write(append(b, '\n')) | ||||||
|  | |||||||
| @ -66,11 +66,13 @@ type OTPResponse struct { | |||||||
| 	HTTPResponse | 	HTTPResponse | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // Contact represents a map between an identifier and some users | ||||||
| type Contact struct { | type Contact struct { | ||||||
| 	Email    string   `json:"email"` | 	Email    string   `json:"email"` | ||||||
| 	Subjects []string `json:"subjects"` | 	Subjects []string `json:"subjects"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // Subject represents a map between a user and some identifiers | ||||||
| type Subject struct { | type Subject struct { | ||||||
| 	Subject string               `json:"subject"` | 	Subject string               `json:"subject"` | ||||||
| 	Emails  map[string]time.Time `json:"emails"` | 	Emails  map[string]time.Time `json:"emails"` | ||||||
| @ -109,7 +111,7 @@ func Route(jwksPrefix string, privkey keypairs.PrivateKey) http.Handler { | |||||||
| 	if nil != err { | 	if nil != err { | ||||||
| 		signingKey = xkeypairs.GenPrivKey(&xkeypairs.KeyOptions{}) | 		signingKey = xkeypairs.GenPrivKey(&xkeypairs.KeyOptions{}) | ||||||
| 		_ = os.MkdirAll(jwksPrefix+"/private", 0750) | 		_ = os.MkdirAll(jwksPrefix+"/private", 0750) | ||||||
| 		b := xkeypairs.MarshalJWKPrivateKey(signingKey) | 		b := keypairs.MarshalJWKPrivateKey(signingKey) | ||||||
| 		if err := ioutil.WriteFile(privKeyJWKPath, b, 0600); nil != err { | 		if err := ioutil.WriteFile(privKeyJWKPath, b, 0600); nil != err { | ||||||
| 			panic(err) | 			panic(err) | ||||||
| 		} | 		} | ||||||
| @ -320,10 +322,10 @@ func Route(jwksPrefix string, privkey keypairs.PrivateKey) http.Handler { | |||||||
| 		uuid, _ := uuid.NewRandom() | 		uuid, _ := uuid.NewRandom() | ||||||
| 		nonce, _ := uuid.MarshalBinary() | 		nonce, _ := uuid.MarshalBinary() | ||||||
| 		baseURL := getBaseURL(r) | 		baseURL := getBaseURL(r) | ||||||
| 		tok, err := xkeypairs.SignClaims( | 		tok, err := keypairs.SignClaims( | ||||||
| 			signingKey, | 			signingKey, | ||||||
| 			xkeypairs.Object{}, | 			keypairs.Object{}, | ||||||
| 			xkeypairs.Object{ | 			keypairs.Object{ | ||||||
| 				"sub": sub, | 				"sub": sub, | ||||||
| 				"iss": baseURL + "/", | 				"iss": baseURL + "/", | ||||||
| 				"jti": base64.RawURLEncoding.EncodeToString(nonce), | 				"jti": base64.RawURLEncoding.EncodeToString(nonce), | ||||||
| @ -336,7 +338,7 @@ func Route(jwksPrefix string, privkey keypairs.PrivateKey) http.Handler { | |||||||
| 			fmt.Fprintf(w, "%s", err) | 			fmt.Fprintf(w, "%s", err) | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 		otp.AccessToken = xkeypairs.JWSToJWT(tok) | 		otp.AccessToken = keypairs.JWSToJWT(tok) | ||||||
| 		b, _ := json.Marshal(&OTPResponse{ | 		b, _ := json.Marshal(&OTPResponse{ | ||||||
| 			HTTPResponse: HTTPResponse{Success: true}, | 			HTTPResponse: HTTPResponse{Success: true}, | ||||||
| 			OTP:          *otp, | 			OTP:          *otp, | ||||||
| @ -461,7 +463,7 @@ func Route(jwksPrefix string, privkey keypairs.PrivateKey) http.Handler { | |||||||
| 	http.HandleFunc("/api/new-account", func(w http.ResponseWriter, r *http.Request) { | 	http.HandleFunc("/api/new-account", func(w http.ResponseWriter, r *http.Request) { | ||||||
| 		myURL := getBaseURL(r) + r.URL.Path | 		myURL := getBaseURL(r) + r.URL.Path | ||||||
| 
 | 
 | ||||||
| 		jws := &xkeypairs.JWS{} | 		jws := &keypairs.JWS{} | ||||||
| 
 | 
 | ||||||
| 		decoder := json.NewDecoder(r.Body) | 		decoder := json.NewDecoder(r.Body) | ||||||
| 		if err := decoder.Decode(jws); nil != err { | 		if err := decoder.Decode(jws); nil != err { | ||||||
| @ -504,11 +506,8 @@ func Route(jwksPrefix string, privkey keypairs.PrivateKey) http.Handler { | |||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		ok, err := xkeypairs.VerifyClaims(nil, jws) | 		errs := keypairs.VerifyClaims(nil, jws) | ||||||
| 		if nil != err || !ok { | 		if 0 != len(errs) { | ||||||
| 			if nil != err { |  | ||||||
| 				log.Printf("jws verify error: %s", err) |  | ||||||
| 			} |  | ||||||
| 			http.Error(w, "Bad Request", http.StatusBadRequest) | 			http.Error(w, "Bad Request", http.StatusBadRequest) | ||||||
| 			fmt.Fprintf(w, `{"error":"could not verify JWS claims"}`+"\n") | 			fmt.Fprintf(w, `{"error":"could not verify JWS claims"}`+"\n") | ||||||
| 			return | 			return | ||||||
| @ -530,7 +529,7 @@ func Route(jwksPrefix string, privkey keypairs.PrivateKey) http.Handler { | |||||||
| 		) | 		) | ||||||
| 		if nil != err { | 		if nil != err { | ||||||
| 			http.Error(w, "Bad Request", http.StatusBadRequest) | 			http.Error(w, "Bad Request", http.StatusBadRequest) | ||||||
| 			msg, _ := json.Marshal(err.Error()) | 			msg, _ := json.Marshal(err) | ||||||
| 			fmt.Fprintf(w, `{"error":%s}`+"\n", msg) | 			fmt.Fprintf(w, `{"error":%s}`+"\n", msg) | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| @ -684,7 +683,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(xkeypairs.MarshalJWKPrivateKey(privkey)) | 		jwk := string(keypairs.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] | ||||||
| @ -816,6 +815,7 @@ func verifyToken(token string) (*InspectableToken, error) { | |||||||
| 	return inspected, nil | 	return inspected, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // OTP is the one-time password for auth | ||||||
| type OTP struct { | type OTP struct { | ||||||
| 	//Attempts    int       `json:"attempts"` | 	//Attempts    int       `json:"attempts"` | ||||||
| 	CreatedAt   time.Time `json:"created_at"` | 	CreatedAt   time.Time `json:"created_at"` | ||||||
|  | |||||||
							
								
								
									
										5
									
								
								vendor/git.rootprojects.org/root/keypairs/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								vendor/git.rootprojects.org/root/keypairs/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | /keypairs | ||||||
|  | /dist/ | ||||||
|  | 
 | ||||||
|  | .DS_Store | ||||||
|  | .*.sw* | ||||||
							
								
								
									
										41
									
								
								vendor/git.rootprojects.org/root/keypairs/.goreleaser.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								vendor/git.rootprojects.org/root/keypairs/.goreleaser.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | |||||||
|  | # This is an example goreleaser.yaml file with some sane defaults. | ||||||
|  | # Make sure to check the documentation at http://goreleaser.com | ||||||
|  | before: | ||||||
|  |   hooks: | ||||||
|  |     - go generate ./... | ||||||
|  | builds: | ||||||
|  |   - id: keypairs | ||||||
|  |     main: ./cmd/keypairs/keypairs.go | ||||||
|  |     env: | ||||||
|  |       - CGO_ENABLED=0 | ||||||
|  |     flags: | ||||||
|  |       - -mod=vendor | ||||||
|  |     goos: | ||||||
|  |       - linux | ||||||
|  |       - windows | ||||||
|  |       - darwin | ||||||
|  |       - freebsd | ||||||
|  |     goarch: | ||||||
|  |       - amd64 | ||||||
|  |       - arm | ||||||
|  |       - arm64 | ||||||
|  | archives: | ||||||
|  |   - replacements: | ||||||
|  |       386: i386 | ||||||
|  |       amd64: x86-64 | ||||||
|  |       arm64: aarch64 | ||||||
|  |     format_overrides: | ||||||
|  |       - goos: windows | ||||||
|  |         format: zip | ||||||
|  | env_files: | ||||||
|  |   github_token: ~/.config/goreleaser/github_token.txt | ||||||
|  | checksum: | ||||||
|  |   name_template: 'checksums.txt' | ||||||
|  | snapshot: | ||||||
|  |   name_template: "{{ .Tag }}-next" | ||||||
|  | changelog: | ||||||
|  |   sort: asc | ||||||
|  |   filters: | ||||||
|  |     exclude: | ||||||
|  |       - '^docs:' | ||||||
|  |       - '^test:' | ||||||
							
								
								
									
										1
									
								
								vendor/git.rootprojects.org/root/keypairs/AUTHORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								vendor/git.rootprojects.org/root/keypairs/AUTHORS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | AJ ONeal <aj@therootcompany.com> (https://therootcompany.com) | ||||||
							
								
								
									
										10
									
								
								vendor/git.rootprojects.org/root/keypairs/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								vendor/git.rootprojects.org/root/keypairs/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,4 +1,4 @@ | |||||||
| # go-keypairs | # [keypairs](https://git.rootprojects.org/root/keypairs) | ||||||
| 
 | 
 | ||||||
| JSON Web Key (JWK) support and type safety lightly placed over top of Go's `crypto/ecdsa` and `crypto/rsa` | JSON Web Key (JWK) support and type safety lightly placed over top of Go's `crypto/ecdsa` and `crypto/rsa` | ||||||
| 
 | 
 | ||||||
| @ -14,9 +14,9 @@ jwk, err := keypairs.MarshalJWKPublicKey(pub, time.Now().Add(2 * time.Day)) | |||||||
| kid, err := keypairs.ThumbprintPublicKey(pub) | kid, err := keypairs.ThumbprintPublicKey(pub) | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| # API Documentation | # GoDoc API Documentation | ||||||
| 
 | 
 | ||||||
| See <https://godoc.org/github.com/big-squid/go-keypairs> | See <https://pkg.go.dev/git.rootprojects.org/root/keypairs> | ||||||
| 
 | 
 | ||||||
| # Philosophy | # Philosophy | ||||||
| 
 | 
 | ||||||
| @ -56,8 +56,8 @@ between the ASN.1, x509, PEM, and JWK formats. | |||||||
| 
 | 
 | ||||||
| # LICENSE | # LICENSE | ||||||
| 
 | 
 | ||||||
| Copyright (c) 2020-present AJ ONeal | Copyright (c) 2020-present AJ ONeal \ | ||||||
| Copyright (c) 2018-2019 Big Squid, Inc. | Copyright (c) 2018-2019 Big Squid, Inc. | ||||||
| 
 | 
 | ||||||
| This work is licensed under the terms of the MIT license. | This work is licensed under the terms of the MIT license. \ | ||||||
| For a copy, see <https://opensource.org/licenses/MIT>. | For a copy, see <https://opensource.org/licenses/MIT>. | ||||||
|  | |||||||
							
								
								
									
										19
									
								
								vendor/git.rootprojects.org/root/keypairs/cli_test.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								vendor/git.rootprojects.org/root/keypairs/cli_test.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | |||||||
|  | #!/bin/bash | ||||||
|  | set -u | ||||||
|  | 
 | ||||||
|  | go build -mod=vendor cmd/keypairs/*.go | ||||||
|  | ./keypairs gen > testkey.jwk.json 2> testpub.jwk.json | ||||||
|  | 
 | ||||||
|  | ./keypairs sign --exp 1h ./testkey.jwk.json '{"foo":"bar"}' > testjwt.txt 2> testjws.json | ||||||
|  | 
 | ||||||
|  | echo "" | ||||||
|  | echo "Should pass:" | ||||||
|  | ./keypairs verify ./testpub.jwk.json testjwt.txt > /dev/null | ||||||
|  | ./keypairs verify ./testpub.jwk.json "$(cat testjwt.txt)" > /dev/null | ||||||
|  | ./keypairs verify ./testpub.jwk.json testjws.json > /dev/null | ||||||
|  | ./keypairs verify ./testpub.jwk.json "$(cat testjws.json)" > /dev/null | ||||||
|  | 
 | ||||||
|  | echo "" | ||||||
|  | echo "Should fail:" | ||||||
|  | ./keypairs sign --exp -1m ./testkey.jwk.json '{"bar":"foo"}' > errjwt.txt 2> errjws.json | ||||||
|  | ./keypairs verify ./testpub.jwk.json errjwt.txt > /dev/null | ||||||
							
								
								
									
										69
									
								
								vendor/git.rootprojects.org/root/keypairs/generate.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								vendor/git.rootprojects.org/root/keypairs/generate.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,69 @@ | |||||||
|  | package keypairs | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"crypto/ecdsa" | ||||||
|  | 	"crypto/elliptic" | ||||||
|  | 	"crypto/rand" | ||||||
|  | 	"crypto/rsa" | ||||||
|  | 	"io" | ||||||
|  | 	mathrand "math/rand" | ||||||
|  | 	"time" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | var randReader io.Reader = rand.Reader | ||||||
|  | var allowMocking = false | ||||||
|  | 
 | ||||||
|  | // KeyOptions are the things that we may need to know about a request to fulfill it properly | ||||||
|  | type keyOptions struct { | ||||||
|  | 	//Key     string `json:"key"` | ||||||
|  | 	KeyType  string `json:"kty"` | ||||||
|  | 	mockSeed int64  //`json:"-"` | ||||||
|  | 	//SeedStr string `json:"seed"` | ||||||
|  | 	//Claims  Object `json:"claims"` | ||||||
|  | 	//Header  Object `json:"header"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (o *keyOptions) nextReader() io.Reader { | ||||||
|  | 	if allowMocking { | ||||||
|  | 		return o.maybeMockReader() | ||||||
|  | 	} | ||||||
|  | 	return randReader | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // NewDefaultPrivateKey generates a key with reasonable strength. | ||||||
|  | // Today that means a 256-bit equivalent - either RSA 2048 or EC P-256. | ||||||
|  | func NewDefaultPrivateKey() PrivateKey { | ||||||
|  | 	// insecure random is okay here, | ||||||
|  | 	// it's just used for a coin toss | ||||||
|  | 	mathrand.Seed(time.Now().UnixNano()) | ||||||
|  | 	coin := mathrand.Int() | ||||||
|  | 
 | ||||||
|  | 	// the idea here is that we want to make | ||||||
|  | 	// it dead simple to support RSA and EC | ||||||
|  | 	// so it shouldn't matter which is used | ||||||
|  | 	if 0 == coin%2 { | ||||||
|  | 		return newPrivateKey(&keyOptions{ | ||||||
|  | 			KeyType: "RSA", | ||||||
|  | 		}) | ||||||
|  | 	} | ||||||
|  | 	return newPrivateKey(&keyOptions{ | ||||||
|  | 		KeyType: "EC", | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // newPrivateKey generates a 256-bit entropy RSA or ECDSA private key | ||||||
|  | func newPrivateKey(opts *keyOptions) PrivateKey { | ||||||
|  | 	var privkey PrivateKey | ||||||
|  | 
 | ||||||
|  | 	if "RSA" == opts.KeyType { | ||||||
|  | 		keylen := 2048 | ||||||
|  | 		privkey, _ = rsa.GenerateKey(opts.nextReader(), keylen) | ||||||
|  | 		if allowMocking { | ||||||
|  | 			privkey = maybeDerandomizeMockKey(privkey, keylen, opts) | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		// TODO: EC keys may also suffer the same random problems in the future | ||||||
|  | 		privkey, _ = ecdsa.GenerateKey(elliptic.P256(), opts.nextReader()) | ||||||
|  | 	} | ||||||
|  | 	return privkey | ||||||
|  | } | ||||||
							
								
								
									
										69
									
								
								vendor/git.rootprojects.org/root/keypairs/jwk.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								vendor/git.rootprojects.org/root/keypairs/jwk.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,69 @@ | |||||||
|  | package keypairs | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // JWK abstracts EC and RSA keys | ||||||
|  | type JWK interface { | ||||||
|  | 	marshalJWK() ([]byte, error) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ECJWK is the EC variant | ||||||
|  | type ECJWK struct { | ||||||
|  | 	KeyID string   `json:"kid,omitempty"` | ||||||
|  | 	Curve string   `json:"crv"` | ||||||
|  | 	X     string   `json:"x"` | ||||||
|  | 	Y     string   `json:"y"` | ||||||
|  | 	Use   []string `json:"use,omitempty"` | ||||||
|  | 	Seed  string   `json:"_seed,omitempty"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (k *ECJWK) marshalJWK() ([]byte, error) { | ||||||
|  | 	return []byte(fmt.Sprintf(`{"crv":%q,"kty":"EC","x":%q,"y":%q}`, k.Curve, k.X, k.Y)), nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // RSAJWK is the RSA variant | ||||||
|  | type RSAJWK struct { | ||||||
|  | 	KeyID string   `json:"kid,omitempty"` | ||||||
|  | 	Exp   string   `json:"e"` | ||||||
|  | 	N     string   `json:"n"` | ||||||
|  | 	Use   []string `json:"use,omitempty"` | ||||||
|  | 	Seed  string   `json:"_seed,omitempty"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (k *RSAJWK) marshalJWK() ([]byte, error) { | ||||||
|  | 	return []byte(fmt.Sprintf(`{"e":%q,"kty":"RSA","n":%q}`, k.Exp, k.N)), nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  | // ToPublicJWK exposes only the public parts | ||||||
|  | func ToPublicJWK(pubkey PublicKey) JWK { | ||||||
|  | 	switch k := pubkey.Key().(type) { | ||||||
|  | 	case *ecdsa.PublicKey: | ||||||
|  | 		return ECToPublicJWK(k) | ||||||
|  | 	case *rsa.PublicKey: | ||||||
|  | 		return RSAToPublicJWK(k) | ||||||
|  | 	default: | ||||||
|  | 		panic(errors.New("impossible key type")) | ||||||
|  | 		//return nil | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ECToPublicJWK will output the most minimal version of an EC JWK (no key id, no "use" flag, nada) | ||||||
|  | func ECToPublicJWK(k *ecdsa.PublicKey) *ECJWK { | ||||||
|  | 	return &ECJWK{ | ||||||
|  | 		Curve: k.Curve.Params().Name, | ||||||
|  | 		X:     base64.RawURLEncoding.EncodeToString(k.X.Bytes()), | ||||||
|  | 		Y:     base64.RawURLEncoding.EncodeToString(k.Y.Bytes()), | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // RSAToPublicJWK will output the most minimal version of an RSA JWK (no key id, no "use" flag, nada) | ||||||
|  | func RSAToPublicJWK(p *rsa.PublicKey) *RSAJWK { | ||||||
|  | 	return &RSAJWK{ | ||||||
|  | 		Exp: base64.RawURLEncoding.EncodeToString(big.NewInt(int64(p.E)).Bytes()), | ||||||
|  | 		N:   base64.RawURLEncoding.EncodeToString(p.N.Bytes()), | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | */ | ||||||
							
								
								
									
										63
									
								
								vendor/git.rootprojects.org/root/keypairs/jws.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								vendor/git.rootprojects.org/root/keypairs/jws.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,63 @@ | |||||||
|  | package keypairs | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"encoding/base64" | ||||||
|  | 	"encoding/json" | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"strings" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // JWS is a parsed JWT, representation as signable/verifiable and human-readable parts | ||||||
|  | type JWS struct { | ||||||
|  | 	Header    Object `json:"header"`    // JSON | ||||||
|  | 	Claims    Object `json:"claims"`    // JSON | ||||||
|  | 	Protected string `json:"protected"` // base64 | ||||||
|  | 	Payload   string `json:"payload"`   // base64 | ||||||
|  | 	Signature string `json:"signature"` // base64 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // JWSToJWT joins JWS parts into a JWT as {ProtectedHeader}.{SerializedPayload}.{Signature}. | ||||||
|  | func JWSToJWT(jwt *JWS) string { | ||||||
|  | 	return fmt.Sprintf( | ||||||
|  | 		"%s.%s.%s", | ||||||
|  | 		jwt.Protected, | ||||||
|  | 		jwt.Payload, | ||||||
|  | 		jwt.Signature, | ||||||
|  | 	) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // JWTToJWS splits the JWT into its JWS segments | ||||||
|  | func JWTToJWS(jwt string) (jws *JWS) { | ||||||
|  | 	jwt = strings.TrimSpace(jwt) | ||||||
|  | 	parts := strings.Split(jwt, ".") | ||||||
|  | 	if 3 != len(parts) { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	return &JWS{ | ||||||
|  | 		Protected: parts[0], | ||||||
|  | 		Payload:   parts[1], | ||||||
|  | 		Signature: parts[2], | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // DecodeComponents decodes JWS Header and Claims | ||||||
|  | func (jws *JWS) DecodeComponents() error { | ||||||
|  | 	protected, err := base64.RawURLEncoding.DecodeString(jws.Protected) | ||||||
|  | 	if nil != err { | ||||||
|  | 		return errors.New("invalid JWS header base64Url encoding") | ||||||
|  | 	} | ||||||
|  | 	if err := json.Unmarshal([]byte(protected), &jws.Header); nil != err { | ||||||
|  | 		return errors.New("invalid JWS header") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	payload, err := base64.RawURLEncoding.DecodeString(jws.Payload) | ||||||
|  | 	if nil != err { | ||||||
|  | 		return errors.New("invalid JWS payload base64Url encoding") | ||||||
|  | 	} | ||||||
|  | 	if err := json.Unmarshal([]byte(payload), &jws.Claims); nil != err { | ||||||
|  | 		return errors.New("invalid JWS claims") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
							
								
								
									
										171
									
								
								vendor/git.rootprojects.org/root/keypairs/marshal.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								vendor/git.rootprojects.org/root/keypairs/marshal.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,171 @@ | |||||||
|  | package keypairs | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"crypto" | ||||||
|  | 	"crypto/ecdsa" | ||||||
|  | 	"crypto/rsa" | ||||||
|  | 	"crypto/x509" | ||||||
|  | 	"encoding/base64" | ||||||
|  | 	"encoding/pem" | ||||||
|  | 	"fmt" | ||||||
|  | 	"log" | ||||||
|  | 	"math/big" | ||||||
|  | 	mathrand "math/rand" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // MarshalPEMPublicKey outputs the given public key as JWK | ||||||
|  | func MarshalPEMPublicKey(pubkey crypto.PublicKey) ([]byte, error) { | ||||||
|  | 	block, err := marshalDERPublicKey(pubkey) | ||||||
|  | 	if nil != err { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return pem.EncodeToMemory(block), nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // MarshalDERPublicKey outputs the given public key as JWK | ||||||
|  | func MarshalDERPublicKey(pubkey crypto.PublicKey) ([]byte, error) { | ||||||
|  | 	block, err := marshalDERPublicKey(pubkey) | ||||||
|  | 	if nil != err { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return block.Bytes, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // marshalDERPublicKey outputs the given public key as JWK | ||||||
|  | func marshalDERPublicKey(pubkey crypto.PublicKey) (*pem.Block, error) { | ||||||
|  | 
 | ||||||
|  | 	var der []byte | ||||||
|  | 	var typ string | ||||||
|  | 	var err error | ||||||
|  | 	switch k := pubkey.(type) { | ||||||
|  | 	case *rsa.PublicKey: | ||||||
|  | 		der = x509.MarshalPKCS1PublicKey(k) | ||||||
|  | 		typ = "RSA PUBLIC KEY" | ||||||
|  | 	case *ecdsa.PublicKey: | ||||||
|  | 		typ = "PUBLIC KEY" | ||||||
|  | 		der, err = x509.MarshalPKIXPublicKey(k) | ||||||
|  | 		if nil != err { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 	default: | ||||||
|  | 		panic("Developer Error: impossible key type") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return &pem.Block{ | ||||||
|  | 		Bytes: der, | ||||||
|  | 		Type:  typ, | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // MarshalJWKPrivateKey outputs the given private key as JWK | ||||||
|  | func MarshalJWKPrivateKey(privkey PrivateKey) []byte { | ||||||
|  | 	// thumbprint keys are alphabetically sorted and only include the necessary public parts | ||||||
|  | 	switch k := privkey.(type) { | ||||||
|  | 	case *rsa.PrivateKey: | ||||||
|  | 		return MarshalRSAPrivateKey(k) | ||||||
|  | 	case *ecdsa.PrivateKey: | ||||||
|  | 		return MarshalECPrivateKey(k) | ||||||
|  | 	default: | ||||||
|  | 		// this is unreachable because we know the types that we pass in | ||||||
|  | 		log.Printf("keytype: %t, %+v\n", privkey, privkey) | ||||||
|  | 		panic(ErrInvalidPublicKey) | ||||||
|  | 		//return nil | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // MarshalDERPrivateKey outputs the given private key as ASN.1 DER | ||||||
|  | func MarshalDERPrivateKey(privkey PrivateKey) ([]byte, error) { | ||||||
|  | 	// thumbprint keys are alphabetically sorted and only include the necessary public parts | ||||||
|  | 	switch k := privkey.(type) { | ||||||
|  | 	case *rsa.PrivateKey: | ||||||
|  | 		return x509.MarshalPKCS1PrivateKey(k), nil | ||||||
|  | 	case *ecdsa.PrivateKey: | ||||||
|  | 		return x509.MarshalECPrivateKey(k) | ||||||
|  | 	default: | ||||||
|  | 		// this is unreachable because we know the types that we pass in | ||||||
|  | 		log.Printf("keytype: %t, %+v\n", privkey, privkey) | ||||||
|  | 		panic(ErrInvalidPublicKey) | ||||||
|  | 		//return nil, nil | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func marshalDERPrivateKey(privkey PrivateKey) (*pem.Block, error) { | ||||||
|  | 	var typ string | ||||||
|  | 	var bytes []byte | ||||||
|  | 	var err error | ||||||
|  | 
 | ||||||
|  | 	switch k := privkey.(type) { | ||||||
|  | 	case *rsa.PrivateKey: | ||||||
|  | 		if 0 == mathrand.Intn(2) { | ||||||
|  | 			typ = "PRIVATE KEY" | ||||||
|  | 			bytes, err = x509.MarshalPKCS8PrivateKey(k) | ||||||
|  | 			if nil != err { | ||||||
|  | 				return nil, err | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			typ = "RSA PRIVATE KEY" | ||||||
|  | 			bytes = x509.MarshalPKCS1PrivateKey(k) | ||||||
|  | 		} | ||||||
|  | 		return &pem.Block{ | ||||||
|  | 			Type:  typ, | ||||||
|  | 			Bytes: bytes, | ||||||
|  | 		}, nil | ||||||
|  | 	case *ecdsa.PrivateKey: | ||||||
|  | 		if 0 == mathrand.Intn(2) { | ||||||
|  | 			typ = "PRIVATE KEY" | ||||||
|  | 			bytes, err = x509.MarshalPKCS8PrivateKey(k) | ||||||
|  | 		} else { | ||||||
|  | 			typ = "EC PRIVATE KEY" | ||||||
|  | 			bytes, err = x509.MarshalECPrivateKey(k) | ||||||
|  | 		} | ||||||
|  | 		if nil != err { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		return &pem.Block{ | ||||||
|  | 			Type:  typ, | ||||||
|  | 			Bytes: bytes, | ||||||
|  | 		}, nil | ||||||
|  | 	default: | ||||||
|  | 		// this is unreachable because we know the types that we pass in | ||||||
|  | 		log.Printf("keytype: %t, %+v\n", privkey, privkey) | ||||||
|  | 		panic(ErrInvalidPublicKey) | ||||||
|  | 		//return nil, nil | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // MarshalPEMPrivateKey outputs the given private key as ASN.1 PEM | ||||||
|  | func MarshalPEMPrivateKey(privkey PrivateKey) ([]byte, error) { | ||||||
|  | 	block, err := marshalDERPrivateKey(privkey) | ||||||
|  | 	if nil != err { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return pem.EncodeToMemory(block), nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // MarshalECPrivateKey will output the given private key as JWK | ||||||
|  | func MarshalECPrivateKey(k *ecdsa.PrivateKey) []byte { | ||||||
|  | 	crv := k.Curve.Params().Name | ||||||
|  | 	d := base64.RawURLEncoding.EncodeToString(k.D.Bytes()) | ||||||
|  | 	x := base64.RawURLEncoding.EncodeToString(k.X.Bytes()) | ||||||
|  | 	y := base64.RawURLEncoding.EncodeToString(k.Y.Bytes()) | ||||||
|  | 	return []byte(fmt.Sprintf( | ||||||
|  | 		`{"crv":%q,"d":%q,"kty":"EC","x":%q,"y":%q}`, | ||||||
|  | 		crv, d, x, y, | ||||||
|  | 	)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // MarshalRSAPrivateKey will output the given private key as JWK | ||||||
|  | func MarshalRSAPrivateKey(pk *rsa.PrivateKey) []byte { | ||||||
|  | 	e := base64.RawURLEncoding.EncodeToString(big.NewInt(int64(pk.E)).Bytes()) | ||||||
|  | 	n := base64.RawURLEncoding.EncodeToString(pk.N.Bytes()) | ||||||
|  | 	d := base64.RawURLEncoding.EncodeToString(pk.D.Bytes()) | ||||||
|  | 	p := base64.RawURLEncoding.EncodeToString(pk.Primes[0].Bytes()) | ||||||
|  | 	q := base64.RawURLEncoding.EncodeToString(pk.Primes[1].Bytes()) | ||||||
|  | 	dp := base64.RawURLEncoding.EncodeToString(pk.Precomputed.Dp.Bytes()) | ||||||
|  | 	dq := base64.RawURLEncoding.EncodeToString(pk.Precomputed.Dq.Bytes()) | ||||||
|  | 	qi := base64.RawURLEncoding.EncodeToString(pk.Precomputed.Qinv.Bytes()) | ||||||
|  | 	return []byte(fmt.Sprintf( | ||||||
|  | 		`{"d":%q,"dp":%q,"dq":%q,"e":%q,"kty":"RSA","n":%q,"p":%q,"q":%q,"qi":%q}`, | ||||||
|  | 		d, dp, dq, e, n, p, q, qi, | ||||||
|  | 	)) | ||||||
|  | } | ||||||
							
								
								
									
										46
									
								
								vendor/git.rootprojects.org/root/keypairs/mock.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								vendor/git.rootprojects.org/root/keypairs/mock.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,46 @@ | |||||||
|  | package keypairs | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"crypto/rsa" | ||||||
|  | 	"io" | ||||||
|  | 	"log" | ||||||
|  | 	mathrand "math/rand" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // this shananigans is only for testing and debug API stuff | ||||||
|  | func (o *keyOptions) maybeMockReader() io.Reader { | ||||||
|  | 	if !allowMocking { | ||||||
|  | 		panic("mock method called when mocking is not allowed") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if 0 == o.mockSeed { | ||||||
|  | 		return randReader | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	log.Println("WARNING: MOCK: using insecure reader") | ||||||
|  | 	return mathrand.New(mathrand.NewSource(o.mockSeed)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const maxRetry = 16 | ||||||
|  | 
 | ||||||
|  | func maybeDerandomizeMockKey(privkey PrivateKey, keylen int, opts *keyOptions) PrivateKey { | ||||||
|  | 	if 0 != opts.mockSeed { | ||||||
|  | 		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 | ||||||
|  | 				// See https://github.com/square/go-jose/issues/189 | ||||||
|  | 				if otherCmp < 0 { | ||||||
|  | 					privkey = otherkey | ||||||
|  | 				} | ||||||
|  | 				break | ||||||
|  | 			} | ||||||
|  | 			if maxRetry == i-1 { | ||||||
|  | 				log.Printf("error: coinflip landed on heads %d times", maxRetry) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return privkey | ||||||
|  | } | ||||||
							
								
								
									
										165
									
								
								vendor/git.rootprojects.org/root/keypairs/sign.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								vendor/git.rootprojects.org/root/keypairs/sign.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,165 @@ | |||||||
|  | package keypairs | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"crypto" | ||||||
|  | 	"crypto/ecdsa" | ||||||
|  | 	"crypto/rsa" | ||||||
|  | 	"crypto/sha256" | ||||||
|  | 	"encoding/base64" | ||||||
|  | 	"encoding/json" | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io" | ||||||
|  | 	mathrand "math/rand" // to be used for good, not evil | ||||||
|  | 	"time" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // Object is a type alias representing generic JSON data | ||||||
|  | type Object = map[string]interface{} | ||||||
|  | 
 | ||||||
|  | // SignClaims adds `typ`, `kid` (or `jwk`), and `alg` in the header and expects claims for `jti`, `exp`, `iss`, and `iat` | ||||||
|  | func SignClaims(privkey PrivateKey, header Object, claims Object) (*JWS, error) { | ||||||
|  | 	var randsrc io.Reader = randReader | ||||||
|  | 	seed, _ := header["_seed"].(int64) | ||||||
|  | 	if 0 != seed { | ||||||
|  | 		randsrc = mathrand.New(mathrand.NewSource(seed)) | ||||||
|  | 		//delete(header, "_seed") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	protected, header, err := headerToProtected(NewPublicKey(privkey.Public()), header) | ||||||
|  | 	if nil != err { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	protected64 := base64.RawURLEncoding.EncodeToString(protected) | ||||||
|  | 
 | ||||||
|  | 	payload, err := claimsToPayload(claims) | ||||||
|  | 	if nil != err { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	payload64 := base64.RawURLEncoding.EncodeToString(payload) | ||||||
|  | 
 | ||||||
|  | 	signable := fmt.Sprintf(`%s.%s`, protected64, payload64) | ||||||
|  | 	hash := sha256.Sum256([]byte(signable)) | ||||||
|  | 
 | ||||||
|  | 	sig := Sign(privkey, hash[:], randsrc) | ||||||
|  | 	sig64 := base64.RawURLEncoding.EncodeToString(sig) | ||||||
|  | 	//log.Printf("\n(Sign)\nSignable: %s", signable) | ||||||
|  | 	//log.Printf("Hash: %s", hash) | ||||||
|  | 	//log.Printf("Sig: %s", sig64) | ||||||
|  | 
 | ||||||
|  | 	return &JWS{ | ||||||
|  | 		Header:    header, | ||||||
|  | 		Claims:    claims, | ||||||
|  | 		Protected: protected64, | ||||||
|  | 		Payload:   payload64, | ||||||
|  | 		Signature: sig64, | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func headerToProtected(pub PublicKey, header Object) ([]byte, Object, error) { | ||||||
|  | 	if nil == header { | ||||||
|  | 		header = Object{} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Only supporting 2048-bit and P256 keys right now | ||||||
|  | 	// because that's all that's practical and well-supported. | ||||||
|  | 	// No security theatre here. | ||||||
|  | 	alg := "ES256" | ||||||
|  | 	switch pub.Key().(type) { | ||||||
|  | 	case *rsa.PublicKey: | ||||||
|  | 		alg = "RS256" | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if selfSign, _ := header["_jwk"].(bool); selfSign { | ||||||
|  | 		delete(header, "_jwk") | ||||||
|  | 		any := Object{} | ||||||
|  | 		_ = json.Unmarshal(MarshalJWKPublicKey(pub), &any) | ||||||
|  | 		header["jwk"] = any | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// TODO what are the acceptable values? JWT. JWS? others? | ||||||
|  | 	header["typ"] = "JWT" | ||||||
|  | 	if _, ok := header["jwk"]; !ok { | ||||||
|  | 		thumbprint := ThumbprintPublicKey(pub) | ||||||
|  | 		kid, _ := header["kid"].(string) | ||||||
|  | 		if "" != kid && thumbprint != kid { | ||||||
|  | 			return nil, nil, errors.New("'kid' should be the key's thumbprint") | ||||||
|  | 		} | ||||||
|  | 		header["kid"] = thumbprint | ||||||
|  | 	} | ||||||
|  | 	header["alg"] = alg | ||||||
|  | 
 | ||||||
|  | 	protected, err := json.Marshal(header) | ||||||
|  | 	if nil != err { | ||||||
|  | 		return nil, nil, err | ||||||
|  | 	} | ||||||
|  | 	return protected, header, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func claimsToPayload(claims Object) ([]byte, error) { | ||||||
|  | 	if nil == claims { | ||||||
|  | 		claims = Object{} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	var dur time.Duration | ||||||
|  | 	jti, _ := claims["jti"].(string) | ||||||
|  | 	insecure, _ := claims["insecure"].(bool) | ||||||
|  | 
 | ||||||
|  | 	switch exp := claims["exp"].(type) { | ||||||
|  | 	case time.Duration: | ||||||
|  | 		// TODO: MUST this go first? | ||||||
|  | 		// int64(time.Duration) vs time.Duration(int64) | ||||||
|  | 		dur = exp | ||||||
|  | 	case string: | ||||||
|  | 		var err error | ||||||
|  | 		dur, err = time.ParseDuration(exp) | ||||||
|  | 		// TODO s, err := time.ParseDuration(dur) | ||||||
|  | 		if nil != err { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 	case int: | ||||||
|  | 		dur = time.Second * time.Duration(exp) | ||||||
|  | 	case int64: | ||||||
|  | 		dur = time.Second * time.Duration(exp) | ||||||
|  | 	case float64: | ||||||
|  | 		dur = time.Second * time.Duration(exp) | ||||||
|  | 	default: | ||||||
|  | 		dur = 0 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if "" == jti && 0 == dur && !insecure { | ||||||
|  | 		return nil, errors.New("token must have jti or exp as to be expirable / cancellable") | ||||||
|  | 	} | ||||||
|  | 	claims["exp"] = time.Now().Add(dur).Unix() | ||||||
|  | 
 | ||||||
|  | 	return json.Marshal(claims) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Sign signs both RSA and ECDSA. Use `nil` or `crypto/rand.Reader` except for debugging. | ||||||
|  | func Sign(privkey PrivateKey, hash []byte, rand io.Reader) []byte { | ||||||
|  | 	if nil == rand { | ||||||
|  | 		rand = randReader | ||||||
|  | 	} | ||||||
|  | 	var sig []byte | ||||||
|  | 
 | ||||||
|  | 	if len(hash) != 32 { | ||||||
|  | 		panic("only 256-bit hashes for 2048-bit and 256-bit keys are supported") | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	switch k := privkey.(type) { | ||||||
|  | 	case *rsa.PrivateKey: | ||||||
|  | 		sig, _ = rsa.SignPKCS1v15(rand, k, crypto.SHA256, hash) | ||||||
|  | 	case *ecdsa.PrivateKey: | ||||||
|  | 		r, s, _ := ecdsa.Sign(rand, k, hash[:]) | ||||||
|  | 		rb := r.Bytes() | ||||||
|  | 		for len(rb) < 32 { | ||||||
|  | 			rb = append([]byte{0}, rb...) | ||||||
|  | 		} | ||||||
|  | 		sb := s.Bytes() | ||||||
|  | 		for len(rb) < 32 { | ||||||
|  | 			sb = append([]byte{0}, sb...) | ||||||
|  | 		} | ||||||
|  | 		sig = append(rb, sb...) | ||||||
|  | 	} | ||||||
|  | 	return sig | ||||||
|  | } | ||||||
							
								
								
									
										174
									
								
								vendor/git.rootprojects.org/root/keypairs/verify.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								vendor/git.rootprojects.org/root/keypairs/verify.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,174 @@ | |||||||
|  | package keypairs | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"crypto" | ||||||
|  | 	"crypto/ecdsa" | ||||||
|  | 	"crypto/rsa" | ||||||
|  | 	"crypto/sha256" | ||||||
|  | 	"crypto/subtle" | ||||||
|  | 	"encoding/base64" | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"log" | ||||||
|  | 	"math/big" | ||||||
|  | 	"time" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // VerifyClaims will check the signature of a parsed JWT | ||||||
|  | func VerifyClaims(pubkey PublicKey, jws *JWS) (errs []error) { | ||||||
|  | 	kid, _ := jws.Header["kid"].(string) | ||||||
|  | 	jwkmap, hasJWK := jws.Header["jwk"].(Object) | ||||||
|  | 	//var jwk JWK = nil | ||||||
|  | 
 | ||||||
|  | 	seed, _ := jws.Header["_seed"].(int64) | ||||||
|  | 	seedf64, _ := jws.Header["_seed"].(float64) | ||||||
|  | 	kty, _ := jws.Header["_kty"].(string) | ||||||
|  | 	if 0 == seed { | ||||||
|  | 		seed = int64(seedf64) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	var pub PublicKey = nil | ||||||
|  | 	if hasJWK { | ||||||
|  | 		pub, errs = selfsignCheck(jwkmap, errs) | ||||||
|  | 	} else { | ||||||
|  | 		opts := &keyOptions{mockSeed: seed, KeyType: kty} | ||||||
|  | 		pub, errs = pubkeyCheck(pubkey, kid, opts, errs) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	jti, _ := jws.Claims["jti"].(string) | ||||||
|  | 	expf64, _ := jws.Claims["exp"].(float64) | ||||||
|  | 	exp := int64(expf64) | ||||||
|  | 	if 0 == exp { | ||||||
|  | 		if "" == jti { | ||||||
|  | 			err := errors.New("one of 'jti' or 'exp' must exist for token expiry") | ||||||
|  | 			errs = append(errs, err) | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		if time.Now().Unix() > exp { | ||||||
|  | 			err := fmt.Errorf("token expired at %d (%s)", exp, time.Unix(exp, 0)) | ||||||
|  | 			errs = append(errs, err) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	signable := fmt.Sprintf("%s.%s", jws.Protected, jws.Payload) | ||||||
|  | 	hash := sha256.Sum256([]byte(signable)) | ||||||
|  | 	sig, err := base64.RawURLEncoding.DecodeString(jws.Signature) | ||||||
|  | 	if nil != err { | ||||||
|  | 		err := fmt.Errorf("could not decode signature: %w", err) | ||||||
|  | 		errs = append(errs, err) | ||||||
|  | 		return errs | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	//log.Printf("\n(Verify)\nSignable: %s", signable) | ||||||
|  | 	//log.Printf("Hash: %s", hash) | ||||||
|  | 	//log.Printf("Sig: %s", jws.Signature) | ||||||
|  | 	if nil == pub { | ||||||
|  | 		err := fmt.Errorf("token signature could not be verified") | ||||||
|  | 		errs = append(errs, err) | ||||||
|  | 	} else if !Verify(pub, hash[:], sig) { | ||||||
|  | 		err := fmt.Errorf("token signature is not valid") | ||||||
|  | 		errs = append(errs, err) | ||||||
|  | 	} | ||||||
|  | 	return errs | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func selfsignCheck(jwkmap Object, errs []error) (PublicKey, []error) { | ||||||
|  | 	var pub PublicKey = nil | ||||||
|  | 	log.Println("Security TODO: did not check jws.Claims[\"sub\"] against 'jwk'") | ||||||
|  | 	log.Println("Security TODO: did not check jws.Claims[\"iss\"]") | ||||||
|  | 	kty := jwkmap["kty"] | ||||||
|  | 	var err error | ||||||
|  | 	if "RSA" == kty { | ||||||
|  | 		e, _ := jwkmap["e"].(string) | ||||||
|  | 		n, _ := jwkmap["n"].(string) | ||||||
|  | 		k, _ := (&RSAJWK{ | ||||||
|  | 			Exp: e, | ||||||
|  | 			N:   n, | ||||||
|  | 		}).marshalJWK() | ||||||
|  | 		pub, err = ParseJWKPublicKey(k) | ||||||
|  | 		if nil != err { | ||||||
|  | 			return nil, append(errs, err) | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		crv, _ := jwkmap["crv"].(string) | ||||||
|  | 		x, _ := jwkmap["x"].(string) | ||||||
|  | 		y, _ := jwkmap["y"].(string) | ||||||
|  | 		k, _ := (&ECJWK{ | ||||||
|  | 			Curve: crv, | ||||||
|  | 			X:     x, | ||||||
|  | 			Y:     y, | ||||||
|  | 		}).marshalJWK() | ||||||
|  | 		pub, err = ParseJWKPublicKey(k) | ||||||
|  | 		if nil != err { | ||||||
|  | 			return nil, append(errs, err) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return pub, errs | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func pubkeyCheck(pubkey PublicKey, kid string, opts *keyOptions, errs []error) (PublicKey, []error) { | ||||||
|  | 	var pub PublicKey = nil | ||||||
|  | 
 | ||||||
|  | 	if "" == kid { | ||||||
|  | 		err := errors.New("token should have 'kid' or 'jwk' in header to identify the public key") | ||||||
|  | 		errs = append(errs, err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if nil == pubkey { | ||||||
|  | 		if allowMocking { | ||||||
|  | 			if 0 == opts.mockSeed { | ||||||
|  | 				err := errors.New("the debug API requires '_seed' to accompany 'kid'") | ||||||
|  | 				errs = append(errs, err) | ||||||
|  | 			} | ||||||
|  | 			if "" == opts.KeyType { | ||||||
|  | 				err := errors.New("the debug API requires '_kty' to accompany '_seed'") | ||||||
|  | 				errs = append(errs, err) | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if 0 == opts.mockSeed || "" == opts.KeyType { | ||||||
|  | 				return nil, errs | ||||||
|  | 			} | ||||||
|  | 			privkey := newPrivateKey(opts) | ||||||
|  | 			pub = NewPublicKey(privkey.Public()) | ||||||
|  | 			return pub, errs | ||||||
|  | 		} | ||||||
|  | 		err := errors.New("no matching public key") | ||||||
|  | 		errs = append(errs, err) | ||||||
|  | 	} else { | ||||||
|  | 		pub = pubkey | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if nil != pub && "" != kid { | ||||||
|  | 		if 1 != subtle.ConstantTimeCompare([]byte(kid), []byte(pub.Thumbprint())) { | ||||||
|  | 			err := errors.New("'kid' does not match the public key thumbprint") | ||||||
|  | 			errs = append(errs, err) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return pub, errs | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Verify will check the signature of a hash | ||||||
|  | func Verify(pubkey PublicKey, hash []byte, sig []byte) bool { | ||||||
|  | 
 | ||||||
|  | 	switch pub := pubkey.Key().(type) { | ||||||
|  | 	case *rsa.PublicKey: | ||||||
|  | 		//log.Printf("RSA VERIFY") | ||||||
|  | 		// TODO Size(key) to detect key size ? | ||||||
|  | 		//alg := "SHA256" | ||||||
|  | 		// TODO: this hasn't been tested yet | ||||||
|  | 		if err := rsa.VerifyPKCS1v15(pub, crypto.SHA256, hash, sig); nil != err { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 		return true | ||||||
|  | 	case *ecdsa.PublicKey: | ||||||
|  | 		r := &big.Int{} | ||||||
|  | 		r.SetBytes(sig[0:32]) | ||||||
|  | 		s := &big.Int{} | ||||||
|  | 		s.SetBytes(sig[32:]) | ||||||
|  | 		return ecdsa.Verify(pub, hash, r, s) | ||||||
|  | 	default: | ||||||
|  | 		panic("impossible condition: non-rsa/non-ecdsa key") | ||||||
|  | 		//return false | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										2
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							| @ -1,6 +1,6 @@ | |||||||
| # git.rootprojects.org/root/hashcash v1.0.1 | # git.rootprojects.org/root/hashcash v1.0.1 | ||||||
| git.rootprojects.org/root/hashcash | git.rootprojects.org/root/hashcash | ||||||
| # git.rootprojects.org/root/keypairs v0.5.2 | # git.rootprojects.org/root/keypairs v0.6.5 | ||||||
| git.rootprojects.org/root/keypairs | git.rootprojects.org/root/keypairs | ||||||
| git.rootprojects.org/root/keypairs/keyfetch | git.rootprojects.org/root/keypairs/keyfetch | ||||||
| git.rootprojects.org/root/keypairs/keyfetch/uncached | git.rootprojects.org/root/keypairs/keyfetch/uncached | ||||||
|  | |||||||
| @ -3,22 +3,30 @@ package xkeypairs | |||||||
| import ( | import ( | ||||||
| 	"crypto/ecdsa" | 	"crypto/ecdsa" | ||||||
| 	"crypto/elliptic" | 	"crypto/elliptic" | ||||||
|  | 	"crypto/rand" | ||||||
| 	"crypto/rsa" | 	"crypto/rsa" | ||||||
| 	"io" | 	"io" | ||||||
| 	"log" | 	"log" | ||||||
| 	"math/rand" | 	mathrand "math/rand" | ||||||
| 
 | 
 | ||||||
| 	"git.rootprojects.org/root/keypairs" | 	"git.rootprojects.org/root/keypairs" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | const maxRetry = 16 | ||||||
|  | 
 | ||||||
|  | // RandomReader may be overwritten for testing | ||||||
|  | var RandomReader io.Reader = rand.Reader | ||||||
|  | 
 | ||||||
|  | //var RandomReader = rand.Reader | ||||||
|  | 
 | ||||||
| // KeyOptions are the things that we may need to know about a request to fulfill it properly | // KeyOptions are the things that we may need to know about a request to fulfill it properly | ||||||
| type KeyOptions struct { | type KeyOptions struct { | ||||||
| 	Key     string          `json:"key"` | 	Key     string          `json:"key"` | ||||||
| 	KeyType string          `json:"kty"` | 	KeyType string          `json:"kty"` | ||||||
| 	Seed    int64           `json:"-"` | 	Seed    int64           `json:"-"` | ||||||
| 	SeedStr string          `json:"seed"` | 	SeedStr string          `json:"seed"` | ||||||
| 	Claims  Object `json:"claims"` | 	Claims  keypairs.Object `json:"claims"` | ||||||
| 	Header  Object `json:"header"` | 	Header  keypairs.Object `json:"header"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // this shananigans is only for testing and debug API stuff | // this shananigans is only for testing and debug API stuff | ||||||
| @ -26,7 +34,7 @@ func (o *KeyOptions) MyFooNextReader() io.Reader { | |||||||
| 	if 0 == o.Seed { | 	if 0 == o.Seed { | ||||||
| 		return RandomReader | 		return RandomReader | ||||||
| 	} | 	} | ||||||
| 	return rand.New(rand.NewSource(o.Seed)) | 	return mathrand.New(mathrand.NewSource(o.Seed)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // GenPrivKey generates a 256-bit entropy RSA or ECDSA private key | // GenPrivKey generates a 256-bit entropy RSA or ECDSA private key | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user