...

Source file src/github.com/ory/x/jwksx/generator.go

Documentation: github.com/ory/x/jwksx

     1  /*
     2   * Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   *
    16   * @author		Aeneas Rekkas <aeneas+oss@aeneas.io>
    17   * @copyright 	2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
    18   * @license 	Apache-2.0
    19   */
    20  
    21  package jwksx
    22  
    23  import (
    24  	"crypto"
    25  	"crypto/ecdsa"
    26  	"crypto/elliptic"
    27  	"crypto/rand"
    28  	"crypto/rsa"
    29  	"crypto/x509"
    30  	"io"
    31  
    32  	"github.com/pkg/errors"
    33  
    34  	"github.com/google/uuid"
    35  	"github.com/square/go-jose/v3"
    36  	"golang.org/x/crypto/ed25519"
    37  )
    38  
    39  // GenerateSigningKeys generates a JSON Web Key Set for signing.
    40  func GenerateSigningKeys(id, alg string, bits int) (*jose.JSONWebKeySet, error) {
    41  	if id == "" {
    42  		id = uuid.New().String()
    43  	}
    44  
    45  	key, err := generate(jose.SignatureAlgorithm(alg), bits)
    46  	if err != nil {
    47  		return nil, err
    48  	}
    49  
    50  	return &jose.JSONWebKeySet{
    51  		Keys: []jose.JSONWebKey{
    52  			{
    53  				Algorithm:    alg,
    54  				Use:          "sig",
    55  				Key:          key,
    56  				KeyID:        id,
    57  				Certificates: []*x509.Certificate{},
    58  			},
    59  		},
    60  	}, nil
    61  }
    62  
    63  // GenerateSigningKeysAvailableAlgorithms lists available algorithms that are supported by GenerateSigningKeys.
    64  func GenerateSigningKeysAvailableAlgorithms() []string {
    65  	return []string{
    66  		string(jose.HS256), string(jose.HS384), string(jose.HS512),
    67  		string(jose.ES256), string(jose.ES384), string(jose.ES512), string(jose.EdDSA),
    68  		string(jose.RS256), string(jose.RS384), string(jose.RS512), string(jose.PS256), string(jose.PS384), string(jose.PS512),
    69  	}
    70  }
    71  
    72  // generate generates keypair for corresponding SignatureAlgorithm.
    73  func generate(alg jose.SignatureAlgorithm, bits int) (crypto.PrivateKey, error) {
    74  	switch alg {
    75  	case jose.ES256, jose.ES384, jose.ES512, jose.EdDSA:
    76  		keylen := map[jose.SignatureAlgorithm]int{
    77  			jose.ES256: 256,
    78  			jose.ES384: 384,
    79  			jose.ES512: 521, // sic!
    80  			jose.EdDSA: 256,
    81  		}
    82  		if bits != 0 && bits != keylen[alg] {
    83  			return nil, errors.Errorf(`jwksx: "%s" does not support arbitrary key length`, alg)
    84  		}
    85  	case jose.RS256, jose.RS384, jose.RS512, jose.PS256, jose.PS384, jose.PS512:
    86  		if bits == 0 {
    87  			bits = 2048
    88  		}
    89  		if bits < 2048 {
    90  			return nil, errors.Errorf(`jwksx: key size must be at least 2048 bit for algorithm "%s"`, alg)
    91  		}
    92  	case jose.HS256:
    93  		if bits == 0 {
    94  			bits = 256
    95  		}
    96  		if bits < 256 {
    97  			return nil, errors.Errorf(`jwksx: key size must be at least 256 bit for algorithm "%s"`, alg)
    98  		}
    99  	case jose.HS384:
   100  		if bits == 0 {
   101  			bits = 384
   102  		}
   103  		if bits < 384 {
   104  			return nil, errors.Errorf(`jwksx: key size must be at least 2038448 bit for algorithm "%s"`, alg)
   105  		}
   106  	case jose.HS512:
   107  		if bits == 0 {
   108  			bits = 1024
   109  		}
   110  		if bits < 512 {
   111  			return nil, errors.Errorf(`jwksx: key size must be at least 512 bit for algorithm "%s"`, alg)
   112  		}
   113  	}
   114  
   115  	switch alg {
   116  	case jose.ES256:
   117  		// The cryptographic operations are implemented using constant-time algorithms.
   118  		key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
   119  		return key, errors.Wrapf(err, "jwks: unable to generate key")
   120  	case jose.ES384:
   121  		// NB: The cryptographic operations do not use constant-time algorithms.
   122  		key, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
   123  		return key, errors.Wrapf(err, "jwks: unable to generate key")
   124  	case jose.ES512:
   125  		// NB: The cryptographic operations do not use constant-time algorithms.
   126  		key, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
   127  		return key, errors.Wrapf(err, "jwks: unable to generate key")
   128  	case jose.EdDSA:
   129  		_, key, err := ed25519.GenerateKey(rand.Reader)
   130  		return key, errors.Wrapf(err, "jwks: unable to generate key")
   131  	case jose.RS256, jose.RS384, jose.RS512, jose.PS256, jose.PS384, jose.PS512:
   132  		key, err := rsa.GenerateKey(rand.Reader, bits)
   133  		return key, errors.Wrapf(err, "jwks: unable to generate key")
   134  	case jose.HS256, jose.HS384, jose.HS512:
   135  		if bits%8 != 0 {
   136  			return nil, errors.Errorf(`jwksx: key size must be a multiple of 8 for algorithm "%s" but got: %d`, alg, bits)
   137  		}
   138  
   139  		key := make([]byte, bits/8)
   140  		if _, err := io.ReadFull(rand.Reader, key); err != nil {
   141  			return nil, errors.Wrapf(err, "jwks: unable to generate key")
   142  		}
   143  		return key, nil
   144  	default:
   145  		return nil, errors.Errorf(`jwksx: available algorithms are "%+v" but unknown algorithm was requested: "%s"`, GenerateSigningKeysAvailableAlgorithms(), alg)
   146  	}
   147  }
   148  

View as plain text