github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/internal/config/identity/openid/jwks.go (about)

     1  // Copyright (c) 2015-2021 MinIO, Inc.
     2  //
     3  // This file is part of MinIO Object Storage stack
     4  //
     5  // This program is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Affero General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // This program is distributed in the hope that it will be useful
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU Affero General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Affero General Public License
    16  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package openid
    19  
    20  import (
    21  	"crypto"
    22  	"crypto/ecdsa"
    23  	"crypto/elliptic"
    24  	"crypto/rsa"
    25  	"encoding/base64"
    26  	"errors"
    27  	"fmt"
    28  	"math/big"
    29  )
    30  
    31  // JWKS - https://tools.ietf.org/html/rfc7517
    32  type JWKS struct {
    33  	Keys []*JWKS `json:"keys,omitempty"`
    34  
    35  	Kty string `json:"kty"`
    36  	Use string `json:"use,omitempty"`
    37  	Kid string `json:"kid,omitempty"`
    38  	Alg string `json:"alg,omitempty"`
    39  
    40  	Crv string `json:"crv,omitempty"`
    41  	X   string `json:"x,omitempty"`
    42  	Y   string `json:"y,omitempty"`
    43  	D   string `json:"d,omitempty"`
    44  	N   string `json:"n,omitempty"`
    45  	E   string `json:"e,omitempty"`
    46  	K   string `json:"k,omitempty"`
    47  }
    48  
    49  var (
    50  	errMalformedJWKRSAKey = errors.New("malformed JWK RSA key")
    51  	errMalformedJWKECKey  = errors.New("malformed JWK EC key")
    52  )
    53  
    54  // DecodePublicKey - decodes JSON Web Key (JWK) as public key
    55  func (key *JWKS) DecodePublicKey() (crypto.PublicKey, error) {
    56  	switch key.Kty {
    57  	case "RSA":
    58  		if key.N == "" || key.E == "" {
    59  			return nil, errMalformedJWKRSAKey
    60  		}
    61  
    62  		// decode exponent
    63  		ebuf, err := base64.RawURLEncoding.DecodeString(key.E)
    64  		if err != nil {
    65  			return nil, errMalformedJWKRSAKey
    66  		}
    67  
    68  		nbuf, err := base64.RawURLEncoding.DecodeString(key.N)
    69  		if err != nil {
    70  			return nil, errMalformedJWKRSAKey
    71  		}
    72  
    73  		var n, e big.Int
    74  		n.SetBytes(nbuf)
    75  		e.SetBytes(ebuf)
    76  
    77  		return &rsa.PublicKey{
    78  			E: int(e.Int64()),
    79  			N: &n,
    80  		}, nil
    81  	case "EC":
    82  		if key.Crv == "" || key.X == "" || key.Y == "" {
    83  			return nil, errMalformedJWKECKey
    84  		}
    85  
    86  		var curve elliptic.Curve
    87  		switch key.Crv {
    88  		case "P-224":
    89  			curve = elliptic.P224()
    90  		case "P-256":
    91  			curve = elliptic.P256()
    92  		case "P-384":
    93  			curve = elliptic.P384()
    94  		case "P-521":
    95  			curve = elliptic.P521()
    96  		default:
    97  			return nil, fmt.Errorf("Unknown curve type: %s", key.Crv)
    98  		}
    99  
   100  		xbuf, err := base64.RawURLEncoding.DecodeString(key.X)
   101  		if err != nil {
   102  			return nil, errMalformedJWKECKey
   103  		}
   104  
   105  		ybuf, err := base64.RawURLEncoding.DecodeString(key.Y)
   106  		if err != nil {
   107  			return nil, errMalformedJWKECKey
   108  		}
   109  
   110  		var x, y big.Int
   111  		x.SetBytes(xbuf)
   112  		y.SetBytes(ybuf)
   113  
   114  		return &ecdsa.PublicKey{
   115  			Curve: curve,
   116  			X:     &x,
   117  			Y:     &y,
   118  		}, nil
   119  	default:
   120  		return nil, fmt.Errorf("Unknown JWK key type %s", key.Kty)
   121  	}
   122  }