Skip to content

MichaelFraser99/go-jose

Repository files navigation

Go Jose

A Go implementation of the JOSE suite of specifications — JWS (RFC 7515), JWA (RFC 7518), JWK (RFC 7517), and JWT (RFC 7519).

Requirements

  • Go 1.21 or higher

Installation

go get github.com/MichaelFraser99/go-jose

Algorithms Supported

Currently, the module supports the following asymmetric algorithms:

  • ES256
  • ES384
  • ES512
  • RS256
  • RS384
  • RS512
  • PS256
  • PS384
  • PS512

Also supported are the following HMAC with SHA2 symmetric algorithms:

  • HS256
  • HS384
  • HS512

Please note Validator objects cannot be created for HMAC algorithms. When creating a new Signer an optional secret key can be passed as []byte. If none provided, a random key is instead generated and can be retrieved with the Public method. This returns an object of type SecretKey defined as so:

type SecretKey []byte

func (s *SecretKey) Equal(x crypto.PublicKey) bool {
	secretKey, ok := x.(*SecretKey)
	if !ok {
		return false
	}

	return bytes.Equal(*s, *secretKey)
}

Algorithms are represented inside this module with the following type:

type Algorithm int

with the following methods defined

func (a Algorithm) String() string

String returns the string representation of that algorithm (i.e. "RS256" or "HS384")

func GetAlgorithm(alg string) *Algorithm

GetAlgorithm takes in a string and returns a pointer to the relevant algorithm type or nil if an invalid string provided

Signers

To create a Signer object use the GetSigner method. This takes in an algorithm and an optional Opts object (defines a bit size used for RSA keys) and returns a crypto.Signer implementation complete with generated key pair. The below example shows how to generate a signer for ES256:

signer, err := jose.GetSigner(model.ES256, nil)

The GetSignerFromPrivateKey method can also be used. This takes in an algorithm and a pointer to a crypto.PrivateKey implementation. The below example shows how to generate a signer for ES256:

signer, err := jose.GetSignerFromPrivateKey(model.ES256, privateKey)

Signing Contract

The Sign method follows JOSE conventions per RFC 7518 rather than Go's crypto.Signer contract. It supports two modes:

  • JOSE mode (opts == nil or opts.HashFunc() == 0): pass the raw JWS Signing Input — the signer hashes it internally using the algorithm's designated hash. This is the expected usage for JWS operations.
  • Pre-hashed mode (opts.HashFunc() != 0): pass an already-hashed digest — the signer skips internal hashing. This supports interoperability with callers following Go's crypto.Signer convention.

A SignerOpts implementation is provided:

type SignerOpts struct {
	Hash crypto.Hash
}

ValidateSignature always expects the raw signing input (not pre-hashed) and hashes internally.

Validators

In addition to the packaged signers, a validator type is also included for each algorithm. This can be constructed in one of two ways:

The GetValidator method takes in a crypto.PublicKey implementation and returns a validator instance. The below example shows how to generate a validator for ES256:

// Construct a validator from a public key
validator, err := jose.GetValidator(model.ES256, publicKey)

// Construct a validator from a signer instance
signer, err := jose.GetSigner(model.ES256, nil)
validator, err := jose.GetValidator(signer.Alg(), signer.Public())

The GetValidatorFromJwk method takes in the bytes of a jwk format public key and returns a validator instance. The below example shows how to generate a validator for ES256:

// Construct a validator from a jwk public key
validator, err := jose.GetValidatorFromJwk(model.ES256, publicKeyBytes)

The validator object has a method ValidateSignature which takes in the bytes of the digest and signature and returns a boolean indicating whether the signature is valid. The below example shows how to validate a signature:

// Validate a signature
validator, err := jose.GetValidator(model.ES256, publicKey)

valid, err := validator.ValidateSignature(digest, signature)

Finally, validators expose their PublicKey with the Public() method

validator, err := jose.GetValidator(model.ES256, publicKey)
pk := validator.Public()

Jwks

This library includes two methods for converting keys into JWK format

All JWK methods include in the returned map a KID suggestion based on the public key component

PublicJwk takes in a pointer to a public key and returns a map[string]string containing the jwk representation of the provided public key

// Direct from a public key
jwkMap, err := PublicJwk(publicKey)

// From a Signer
signer, err := jose.GetSigner(model.ES256, nil)
publicKey := signer.Public
jwkMap, err := PublicJwk(&publicKey)

Also included is a method to convert an existing public key JWK back into it's respective public key

The value returned is a pointer to the respective public key *ecdsa.PublicKey or *rsa.PublicKey

PublicFromJwk(jwk map[string]any) (crypto.PublicKey, error)

JWTs

This library includes two methods for jwt handling

The first is for signing a jwt from provided signer implementation, head map, and body map

If the head does not include the typ claim, the method will insert a value of "JWT"

Additionally, if the crypto.Signer implementation provided is one of the implementations defined in this module, the alg claim is also added (if not already present)

New(signer crypto.Signer, head, body map[string]any) (*string, error) {

The second provides basic jwt validation and returns the decoded head and body values as instances of map[string]any

If present, the iat, nbf, and exp claims will also be validated

Validate(publicKey crypto.PublicKey, jwt string) (head, body map[string]any, err error)

Errors

This package defines the following errors:

  • InvalidSignature - The provided signature does not match the digest
  • UnsupportedAlgorithm - The algorithm specified is not currently supported
  • InvalidPublicKey - The provided public key is invalid
  • SigningError - An error occurred while signing the token

About

A Go implementation of the JOSE suite of specifications - JWE, JWK, JWS, and JWT

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages