1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
|
package keys
import (
"bytes"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"math/big"
"github.com/pkg/errors"
"golang.org/x/crypto/ssh"
)
var (
// DefaultKeyType is the default type of a private key.
DefaultKeyType = "EC"
// DefaultKeySize is the default size (in # of bits) of a private key.
DefaultKeySize = 2048
// DefaultKeyCurve is the default curve of a private key.
DefaultKeyCurve = "P-256"
// DefaultSignatureAlgorithm is the default signature algorithm used on a
// certificate with the default key type.
DefaultSignatureAlgorithm = x509.ECDSAWithSHA256
// MinRSAKeyBytes is the minimum acceptable size (in bytes) for RSA keys
// signed by the authority.
MinRSAKeyBytes = 256
)
// PublicKey extracts a public key from a private key.
func PublicKey(priv interface{}) (interface{}, error) {
switch k := priv.(type) {
case *rsa.PrivateKey:
return &k.PublicKey, nil
case *ecdsa.PrivateKey:
return &k.PublicKey, nil
case ed25519.PrivateKey:
return k.Public(), nil
case *rsa.PublicKey, *ecdsa.PublicKey, ed25519.PublicKey:
return k, nil
default:
return nil, errors.Errorf("unrecognized key type: %T", priv)
}
}
// GenerateDefaultKey generates a public/private key pair using sane defaults
// for key type, curve, and size.
func GenerateDefaultKey() (interface{}, error) {
return GenerateKey(DefaultKeyType, DefaultKeyCurve, DefaultKeySize)
}
// GenerateKey generates a key of the given type (kty).
func GenerateKey(kty, crv string, size int) (interface{}, error) {
switch kty {
case "EC":
return generateECKey(crv)
case "RSA":
return generateRSAKey(size)
case "OKP":
return generateOKPKey(crv)
case "oct":
return generateOctKey(size)
default:
return nil, errors.Errorf("unrecognized key type: %s", kty)
}
}
// ExtractKey returns the given public or private key or extracts the public key
// if a x509.Certificate or x509.CertificateRequest is given.
func ExtractKey(in interface{}) (interface{}, error) {
switch k := in.(type) {
case *rsa.PublicKey, *ecdsa.PublicKey, ed25519.PublicKey, *rsa.PrivateKey, *ecdsa.PrivateKey, ed25519.PrivateKey:
return in, nil
case []byte:
return in, nil
case *x509.Certificate:
return k.PublicKey, nil
case *x509.CertificateRequest:
return k.PublicKey, nil
case *ssh.Certificate:
sshCryptoPubKey, ok := k.Key.(ssh.CryptoPublicKey)
if !ok {
return nil, errors.New("ssh public key could not be cast to ssh CryptoPublicKey")
}
return sshCryptoPubKey.CryptoPublicKey(), nil
case ssh.PublicKey:
sshCryptoPubKey, ok := k.(ssh.CryptoPublicKey)
if !ok {
return nil, errors.New("ssh public key could not be cast to ssh CryptoPublicKey")
}
return sshCryptoPubKey.CryptoPublicKey(), nil
default:
return nil, errors.Errorf("cannot extract the key from type '%T'", k)
}
}
// VerifyPair that the public key matches the given private key.
func VerifyPair(pubkey interface{}, key interface{}) error {
switch pub := pubkey.(type) {
case *rsa.PublicKey:
priv, ok := key.(*rsa.PrivateKey)
if !ok {
return errors.New("private key type does not match public key type")
}
if pub.N.Cmp(priv.N) != 0 {
return errors.New("private key does not match public key")
}
case *ecdsa.PublicKey:
priv, ok := key.(*ecdsa.PrivateKey)
if !ok {
return errors.New("private key type does not match public key type")
}
if pub.X.Cmp(priv.X) != 0 || pub.Y.Cmp(priv.Y) != 0 {
return errors.New("private key does not match public key")
}
case ed25519.PublicKey:
priv, ok := key.(ed25519.PrivateKey)
if !ok {
return errors.New("private key type does not match public key type")
}
if !bytes.Equal(priv.Public().(ed25519.PublicKey), pub) {
return errors.New("private key does not match public key")
}
default:
return errors.Errorf("unsupported public key type %T", pub)
}
return nil
}
func generateECKey(crv string) (interface{}, error) {
var c elliptic.Curve
switch crv {
case "P-256":
c = elliptic.P256()
case "P-384":
c = elliptic.P384()
case "P-521":
c = elliptic.P521()
default:
return nil, errors.Errorf("invalid value for argument crv (crv: '%s')", crv)
}
key, err := ecdsa.GenerateKey(c, rand.Reader)
if err != nil {
return nil, errors.Wrap(err, "error generating EC key")
}
return key, nil
}
func generateRSAKey(bits int) (interface{}, error) {
key, err := rsa.GenerateKey(rand.Reader, bits)
if err != nil {
return nil, errors.Wrap(err, "error generating RSA key")
}
return key, nil
}
func generateOKPKey(crv string) (interface{}, error) {
switch crv {
case "Ed25519":
_, key, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
return nil, errors.Wrap(err, "error generating Ed25519 key")
}
return key, nil
default:
return nil, errors.Errorf("missing or invalid value for argument 'crv'. "+
"expected 'Ed25519', but got '%s'", crv)
}
}
func generateOctKey(size int) (interface{}, error) {
const chars = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
result := make([]byte, size)
for i := range result {
num, err := rand.Int(rand.Reader, big.NewInt(int64(len(chars))))
if err != nil {
return nil, err
}
result[i] = chars[num.Int64()]
}
return result, nil
}
|