github.com/avenga/couper@v1.12.2/accesscontrol/jwk/jwk.go (about) 1 package jwk 2 3 import ( 4 "crypto/ecdsa" 5 "crypto/elliptic" 6 "crypto/rsa" 7 "crypto/x509" 8 "encoding/base64" 9 "encoding/json" 10 "fmt" 11 "math/big" 12 ) 13 14 type JWK struct { 15 Key interface{} 16 KeyID string 17 KeyType string 18 Algorithm string 19 Use string 20 } 21 22 type rawJWK struct { 23 Alg string `json:"alg"` 24 Kid string `json:"kid"` 25 Kty string `json:"kty"` 26 Use string `json:"use"` 27 // RSA public key 28 E *base64URLEncodedField `json:"e"` 29 N *base64URLEncodedField `json:"n"` 30 X5c []*base64EncodedField `json:"x5c"` 31 // ECDSA public key 32 Crv string `json:"crv"` 33 X *base64URLEncodedField `json:"x"` 34 Y *base64URLEncodedField `json:"y"` 35 //X5t *base64URLEncodedField `json:"x5t"` 36 //X5tS256" *base64URLEncodedField `json:"x5t#S256"` 37 } 38 39 func (j *JWK) UnmarshalJSON(data []byte) error { 40 raw := &rawJWK{} 41 err := json.Unmarshal(data, raw) 42 if err != nil { 43 // TODO log warning properly 44 fmt.Printf("Invalid JWK: %v\n", err) 45 return nil 46 } 47 48 var key interface{} 49 jwk := &JWK{KeyID: raw.Kid, Algorithm: raw.Alg, KeyType: raw.Kty, Use: raw.Use} 50 51 switch raw.Kty { 52 case "RSA": 53 key, err = getPublicKeyFromX5c(raw.X5c) 54 if err != nil { 55 // TODO log warning properly 56 fmt.Printf("Invalid x5c: %v\n", err) 57 return nil 58 } 59 60 if key != nil { 61 jwk.Key = key 62 } else if raw.N != nil && raw.E != nil { 63 jwk.Key = &rsa.PublicKey{ 64 N: raw.N.toBigInt(), 65 E: raw.E.toInt(), 66 } 67 } else { 68 // TODO log warning properly 69 fmt.Printf("Ignoring invalid %s key: %q\n", raw.Kty, raw.Kid) 70 return nil 71 } 72 case "EC": 73 key, err = getPublicKeyFromX5c(raw.X5c) 74 if err != nil { 75 // TODO log warning properly 76 fmt.Printf("Invalid x5c: %v\n", err) 77 return nil 78 } 79 80 if key != nil { 81 jwk.Key = key 82 } else { 83 curve, err := getCurve(raw.Crv) 84 if err == nil && raw.X != nil && raw.Y != nil { 85 jwk.Key = &ecdsa.PublicKey{ 86 Curve: curve, 87 X: raw.X.toBigInt(), 88 Y: raw.Y.toBigInt(), 89 } 90 } else { 91 fmt.Printf("Ignoring invalid %s key: %q (invalid crv/x/y)\n", raw.Kty, raw.Kid) 92 return nil 93 } 94 } 95 default: 96 // TODO log warning properly 97 fmt.Printf("Found unsupported %s key: %q\n", raw.Kty, raw.Kid) 98 return nil 99 } 100 101 *j = *jwk 102 103 return nil 104 } 105 106 // Base64URL encoded 107 108 type base64URLEncodedField struct { 109 data []byte 110 } 111 112 func newBase64URLEncodedField(data []byte) *base64URLEncodedField { 113 return &base64URLEncodedField{ 114 data: data, 115 } 116 } 117 118 func (f *base64URLEncodedField) MarshalJSON() ([]byte, error) { 119 return json.Marshal(base64.RawURLEncoding.EncodeToString(f.data)) 120 } 121 122 func (f *base64URLEncodedField) UnmarshalJSON(data []byte) error { 123 var encoded string 124 err := json.Unmarshal(data, &encoded) 125 if err != nil { 126 return err 127 } 128 129 if encoded == "" { 130 return nil 131 } 132 133 decoded, err := base64.RawURLEncoding.DecodeString(encoded) 134 if err != nil { 135 return err 136 } 137 138 *f = *newBase64URLEncodedField(decoded) 139 140 return nil 141 } 142 143 func (f base64URLEncodedField) toBigInt() *big.Int { 144 return new(big.Int).SetBytes(f.data) 145 } 146 147 func (f base64URLEncodedField) toInt() int { 148 return int(f.toBigInt().Int64()) 149 } 150 151 // Base64 encoded 152 153 type base64EncodedField struct { 154 data []byte 155 } 156 157 func (f *base64EncodedField) UnmarshalJSON(data []byte) error { 158 var encoded string 159 err := json.Unmarshal(data, &encoded) 160 if err != nil { 161 return err 162 } 163 164 if encoded == "" { 165 return nil 166 } 167 168 decoded, err := base64.StdEncoding.DecodeString(encoded) 169 if err != nil { 170 return err 171 } 172 173 *f = base64EncodedField{ 174 data: decoded, 175 } 176 177 return nil 178 } 179 180 func getCurve(name string) (elliptic.Curve, error) { 181 switch name { 182 case "P-256": 183 return elliptic.P256(), nil 184 case "P-384": 185 return elliptic.P384(), nil 186 case "P-521": 187 return elliptic.P521(), nil 188 } 189 return nil, fmt.Errorf("invalid crv: %s", name) 190 } 191 192 func getPublicKeyFromX5c(x5c []*base64EncodedField) (interface{}, error) { 193 if len(x5c) == 0 { 194 return nil, nil 195 } 196 197 certificate, err := x509.ParseCertificate(x5c[0].data) 198 if err != nil { 199 return nil, err 200 } 201 return certificate.PublicKey, nil 202 }