1 package keyfunc 2 3 import ( 4 "crypto/ecdsa" 5 "crypto/ed25519" 6 "crypto/rsa" 7 "encoding/json" 8 ) 9 10 // GivenKey represents a cryptographic key that resides in a JWKS. In conjuncture with Options. 11 type GivenKey struct { 12 algorithm string 13 inter interface{} 14 } 15 16 // GivenKeyOptions represents the configuration options for a GivenKey. 17 type GivenKeyOptions struct { 18 // Algorithm is the given key's signing algorithm. Its value will be compared to unverified tokens' "alg" header. 19 // 20 // See RFC 8725 Section 3.1 for details. 21 // https://www.rfc-editor.org/rfc/rfc8725#section-3.1 22 // 23 // For a list of possible values, please see: 24 // https://www.rfc-editor.org/rfc/rfc7518#section-3.1 25 // https://www.iana.org/assignments/jose/jose.xhtml#web-signature-encryption-algorithms 26 Algorithm string 27 } 28 29 // NewGiven creates a JWKS from a map of given keys. 30 func NewGiven(givenKeys map[string]GivenKey) (jwks *JWKS) { 31 keys := make(map[string]parsedJWK) 32 33 for kid, given := range givenKeys { 34 keys[kid] = parsedJWK{ 35 algorithm: given.algorithm, 36 public: given.inter, 37 } 38 } 39 40 return &JWKS{ 41 keys: keys, 42 } 43 } 44 45 // NewGivenCustom creates a new GivenKey given an untyped variable. The key argument is expected to be a type supported 46 // by the jwt package used. 47 // 48 // Consider the options carefully as each field may have a security implication. 49 // 50 // See the https://pkg.go.dev/github.com/golang-jwt/jwt/v5#RegisterSigningMethod function for registering an unsupported 51 // signing method. 52 func NewGivenCustom(key interface{}, options GivenKeyOptions) (givenKey GivenKey) { 53 return GivenKey{ 54 algorithm: options.Algorithm, 55 inter: key, 56 } 57 } 58 59 // NewGivenECDSA creates a new GivenKey given an ECDSA public key. 60 // 61 // Consider the options carefully as each field may have a security implication. 62 func NewGivenECDSA(key *ecdsa.PublicKey, options GivenKeyOptions) (givenKey GivenKey) { 63 return GivenKey{ 64 algorithm: options.Algorithm, 65 inter: key, 66 } 67 } 68 69 // NewGivenEdDSA creates a new GivenKey given an EdDSA public key. 70 // 71 // Consider the options carefully as each field may have a security implication. 72 func NewGivenEdDSA(key ed25519.PublicKey, options GivenKeyOptions) (givenKey GivenKey) { 73 return GivenKey{ 74 algorithm: options.Algorithm, 75 inter: key, 76 } 77 } 78 79 // NewGivenHMAC creates a new GivenKey given an HMAC key in a byte slice. 80 // 81 // Consider the options carefully as each field may have a security implication. 82 func NewGivenHMAC(key []byte, options GivenKeyOptions) (givenKey GivenKey) { 83 return GivenKey{ 84 algorithm: options.Algorithm, 85 inter: key, 86 } 87 } 88 89 // NewGivenRSA creates a new GivenKey given an RSA public key. 90 // 91 // Consider the options carefully as each field may have a security implication. 92 func NewGivenRSA(key *rsa.PublicKey, options GivenKeyOptions) (givenKey GivenKey) { 93 return GivenKey{ 94 algorithm: options.Algorithm, 95 inter: key, 96 } 97 } 98 99 // NewGivenKeysFromJSON parses a raw JSON message into a map of key IDs (`kid`) to GivenKeys. The returned map is 100 // suitable for passing to `NewGiven()` or as `Options.GivenKeys` to `Get()` 101 func NewGivenKeysFromJSON(jwksBytes json.RawMessage) (map[string]GivenKey, error) { 102 // Parse by making a temporary JWKS instance. No need to lock its map since it doesn't escape this function. 103 j, err := NewJSON(jwksBytes) 104 if err != nil { 105 return nil, err 106 } 107 keys := make(map[string]GivenKey, len(j.keys)) 108 for kid, cryptoKey := range j.keys { 109 keys[kid] = GivenKey{ 110 algorithm: cryptoKey.algorithm, 111 inter: cryptoKey.public, 112 } 113 } 114 return keys, nil 115 } 116