mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-09-12 12:48:51 +00:00
Merge pull request #76390 from rojkov/ecdsa-v2
kubeadm: add support for ECDSA keys
This commit is contained in:
@@ -17,6 +17,7 @@ limitations under the License.
|
||||
package certs
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"net"
|
||||
@@ -30,7 +31,7 @@ import (
|
||||
|
||||
// SetupCertificateAuthorithy is a utility function for kubeadm testing that creates a
|
||||
// CertificateAuthorithy cert/key pair
|
||||
func SetupCertificateAuthorithy(t *testing.T) (*x509.Certificate, *rsa.PrivateKey) {
|
||||
func SetupCertificateAuthorithy(t *testing.T) (*x509.Certificate, crypto.Signer) {
|
||||
caCert, caKey, err := pkiutil.NewCertificateAuthority(&certutil.Config{CommonName: "kubernetes"})
|
||||
if err != nil {
|
||||
t.Fatalf("failure while generating CA certificate and key: %v", err)
|
||||
@@ -130,7 +131,7 @@ func AssertCertificateHasIPAddresses(t *testing.T, cert *x509.Certificate, IPAdd
|
||||
}
|
||||
|
||||
// CreateCACert creates a generic CA cert.
|
||||
func CreateCACert(t *testing.T) (*x509.Certificate, *rsa.PrivateKey) {
|
||||
func CreateCACert(t *testing.T) (*x509.Certificate, crypto.Signer) {
|
||||
certCfg := &certutil.Config{CommonName: "kubernetes"}
|
||||
cert, key, err := pkiutil.NewCertificateAuthority(certCfg)
|
||||
if err != nil {
|
||||
@@ -140,7 +141,7 @@ func CreateCACert(t *testing.T) (*x509.Certificate, *rsa.PrivateKey) {
|
||||
}
|
||||
|
||||
// CreateTestCert makes a generic certificate with the given CA and alternative names.
|
||||
func CreateTestCert(t *testing.T, caCert *x509.Certificate, caKey *rsa.PrivateKey, altNames certutil.AltNames) (*x509.Certificate, *rsa.PrivateKey, *certutil.Config) {
|
||||
func CreateTestCert(t *testing.T, caCert *x509.Certificate, caKey crypto.Signer, altNames certutil.AltNames) (*x509.Certificate, crypto.Signer, *certutil.Config) {
|
||||
config := &certutil.Config{
|
||||
CommonName: "testCert",
|
||||
Usages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
|
||||
|
@@ -18,6 +18,7 @@ package pkiutil
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/rand"
|
||||
cryptorand "crypto/rand"
|
||||
"crypto/rsa"
|
||||
@@ -58,7 +59,7 @@ const (
|
||||
)
|
||||
|
||||
// NewCertificateAuthority creates new certificate and private key for the certificate authority
|
||||
func NewCertificateAuthority(config *certutil.Config) (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||
func NewCertificateAuthority(config *certutil.Config) (*x509.Certificate, crypto.Signer, error) {
|
||||
key, err := NewPrivateKey()
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "unable to create private key while generating CA certificate")
|
||||
@@ -73,7 +74,7 @@ func NewCertificateAuthority(config *certutil.Config) (*x509.Certificate, *rsa.P
|
||||
}
|
||||
|
||||
// NewCertAndKey creates new certificate and key by passing the certificate authority certificate and key
|
||||
func NewCertAndKey(caCert *x509.Certificate, caKey *rsa.PrivateKey, config *certutil.Config) (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||
func NewCertAndKey(caCert *x509.Certificate, caKey crypto.Signer, config *certutil.Config) (*x509.Certificate, crypto.Signer, error) {
|
||||
key, err := NewPrivateKey()
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "unable to create private key")
|
||||
@@ -88,7 +89,7 @@ func NewCertAndKey(caCert *x509.Certificate, caKey *rsa.PrivateKey, config *cert
|
||||
}
|
||||
|
||||
// NewCSRAndKey generates a new key and CSR and that could be signed to create the given certificate
|
||||
func NewCSRAndKey(config *certutil.Config) (*x509.CertificateRequest, *rsa.PrivateKey, error) {
|
||||
func NewCSRAndKey(config *certutil.Config) (*x509.CertificateRequest, crypto.Signer, error) {
|
||||
key, err := NewPrivateKey()
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "unable to create private key")
|
||||
@@ -113,7 +114,7 @@ func HasServerAuth(cert *x509.Certificate) bool {
|
||||
}
|
||||
|
||||
// WriteCertAndKey stores certificate and key at the specified location
|
||||
func WriteCertAndKey(pkiPath string, name string, cert *x509.Certificate, key *rsa.PrivateKey) error {
|
||||
func WriteCertAndKey(pkiPath string, name string, cert *x509.Certificate, key crypto.Signer) error {
|
||||
if err := WriteKey(pkiPath, name, key); err != nil {
|
||||
return errors.Wrap(err, "couldn't write key")
|
||||
}
|
||||
@@ -136,7 +137,7 @@ func WriteCert(pkiPath, name string, cert *x509.Certificate) error {
|
||||
}
|
||||
|
||||
// WriteKey stores the given key at the given location
|
||||
func WriteKey(pkiPath, name string, key *rsa.PrivateKey) error {
|
||||
func WriteKey(pkiPath, name string, key crypto.Signer) error {
|
||||
if key == nil {
|
||||
return errors.New("private key cannot be nil when writing to file")
|
||||
}
|
||||
@@ -175,7 +176,7 @@ func WriteCSR(csrDir, name string, csr *x509.CertificateRequest) error {
|
||||
}
|
||||
|
||||
// WritePublicKey stores the given public key at the given location
|
||||
func WritePublicKey(pkiPath, name string, key *rsa.PublicKey) error {
|
||||
func WritePublicKey(pkiPath, name string, key crypto.PublicKey) error {
|
||||
if key == nil {
|
||||
return errors.New("public key cannot be nil when writing to file")
|
||||
}
|
||||
@@ -219,7 +220,7 @@ func CSROrKeyExist(csrDir, name string) bool {
|
||||
}
|
||||
|
||||
// TryLoadCertAndKeyFromDisk tries to load a cert and a key from the disk and validates that they are valid
|
||||
func TryLoadCertAndKeyFromDisk(pkiPath, name string) (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||
func TryLoadCertAndKeyFromDisk(pkiPath, name string) (*x509.Certificate, crypto.Signer, error) {
|
||||
cert, err := TryLoadCertFromDisk(pkiPath, name)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "failed to load certificate")
|
||||
@@ -259,7 +260,7 @@ func TryLoadCertFromDisk(pkiPath, name string) (*x509.Certificate, error) {
|
||||
}
|
||||
|
||||
// TryLoadKeyFromDisk tries to load the key from the disk and validates that it is valid
|
||||
func TryLoadKeyFromDisk(pkiPath, name string) (*rsa.PrivateKey, error) {
|
||||
func TryLoadKeyFromDisk(pkiPath, name string) (crypto.Signer, error) {
|
||||
privateKeyPath := pathForKey(pkiPath, name)
|
||||
|
||||
// Parse the private key from a file
|
||||
@@ -268,20 +269,22 @@ func TryLoadKeyFromDisk(pkiPath, name string) (*rsa.PrivateKey, error) {
|
||||
return nil, errors.Wrapf(err, "couldn't load the private key file %s", privateKeyPath)
|
||||
}
|
||||
|
||||
// Allow RSA format only
|
||||
var key *rsa.PrivateKey
|
||||
// Allow RSA and ECDSA formats only
|
||||
var key crypto.Signer
|
||||
switch k := privKey.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
key = k
|
||||
case *ecdsa.PrivateKey:
|
||||
key = k
|
||||
default:
|
||||
return nil, errors.Errorf("the private key file %s isn't in RSA format", privateKeyPath)
|
||||
return nil, errors.Errorf("the private key file %s is neither in RSA nor ECDSA format", privateKeyPath)
|
||||
}
|
||||
|
||||
return key, nil
|
||||
}
|
||||
|
||||
// TryLoadCSRAndKeyFromDisk tries to load the CSR and key from the disk
|
||||
func TryLoadCSRAndKeyFromDisk(pkiPath, name string) (*x509.CertificateRequest, *rsa.PrivateKey, error) {
|
||||
func TryLoadCSRAndKeyFromDisk(pkiPath, name string) (*x509.CertificateRequest, crypto.Signer, error) {
|
||||
csrPath := pathForCSR(pkiPath, name)
|
||||
|
||||
csr, err := CertificateRequestFromFile(csrPath)
|
||||
@@ -528,7 +531,7 @@ func EncodeCertPEM(cert *x509.Certificate) []byte {
|
||||
}
|
||||
|
||||
// EncodePublicKeyPEM returns PEM-encoded public data
|
||||
func EncodePublicKeyPEM(key *rsa.PublicKey) ([]byte, error) {
|
||||
func EncodePublicKeyPEM(key crypto.PublicKey) ([]byte, error) {
|
||||
der, err := x509.MarshalPKIXPublicKey(key)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
@@ -541,7 +544,7 @@ func EncodePublicKeyPEM(key *rsa.PublicKey) ([]byte, error) {
|
||||
}
|
||||
|
||||
// NewPrivateKey creates an RSA private key
|
||||
func NewPrivateKey() (*rsa.PrivateKey, error) {
|
||||
func NewPrivateKey() (crypto.Signer, error) {
|
||||
return rsa.GenerateKey(cryptorand.Reader, rsaKeySize)
|
||||
}
|
||||
|
||||
|
@@ -17,6 +17,9 @@ limitations under the License.
|
||||
package pkiutil
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
@@ -49,27 +52,38 @@ func TestNewCertificateAuthority(t *testing.T) {
|
||||
|
||||
func TestNewCertAndKey(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name string
|
||||
caKeySize int
|
||||
expected bool
|
||||
name string
|
||||
keyGenFunc func() (crypto.Signer, error)
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "RSA key too small",
|
||||
caKeySize: 128,
|
||||
expected: false,
|
||||
name: "RSA key too small",
|
||||
keyGenFunc: func() (crypto.Signer, error) {
|
||||
return rsa.GenerateKey(rand.Reader, 128)
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "Should succeed",
|
||||
caKeySize: 2048,
|
||||
expected: true,
|
||||
name: "RSA should succeed",
|
||||
keyGenFunc: func() (crypto.Signer, error) {
|
||||
return rsa.GenerateKey(rand.Reader, 2048)
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "ECDSA should succeed",
|
||||
keyGenFunc: func() (crypto.Signer, error) {
|
||||
return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, rt := range tests {
|
||||
t.Run(rt.name, func(t *testing.T) {
|
||||
caKey, err := rsa.GenerateKey(rand.Reader, rt.caKeySize)
|
||||
caKey, err := rt.keyGenFunc()
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create rsa Private Key")
|
||||
t.Fatalf("Couldn't create Private Key")
|
||||
}
|
||||
caCert := &x509.Certificate{}
|
||||
config := &certutil.Config{
|
||||
@@ -375,49 +389,66 @@ func TestTryLoadCertFromDisk(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestTryLoadKeyFromDisk(t *testing.T) {
|
||||
tmpdir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create tmpdir")
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
_, caKey, err := NewCertificateAuthority(&certutil.Config{CommonName: "kubernetes"})
|
||||
if err != nil {
|
||||
t.Errorf(
|
||||
"failed to create cert and key with an error: %v",
|
||||
err,
|
||||
)
|
||||
}
|
||||
err = WriteKey(tmpdir, "foo", caKey)
|
||||
if err != nil {
|
||||
t.Errorf(
|
||||
"failed to write cert and key with an error: %v",
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
var tests = []struct {
|
||||
desc string
|
||||
path string
|
||||
name string
|
||||
expected bool
|
||||
desc string
|
||||
pathSuffix string
|
||||
name string
|
||||
keyGenFunc func() (crypto.Signer, error)
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
desc: "empty path and name",
|
||||
path: "",
|
||||
name: "",
|
||||
desc: "empty path and name",
|
||||
pathSuffix: "somegarbage",
|
||||
name: "",
|
||||
keyGenFunc: func() (crypto.Signer, error) {
|
||||
return rsa.GenerateKey(rand.Reader, 2048)
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
desc: "valid path and name",
|
||||
path: tmpdir,
|
||||
name: "foo",
|
||||
desc: "RSA valid path and name",
|
||||
pathSuffix: "",
|
||||
name: "foo",
|
||||
keyGenFunc: func() (crypto.Signer, error) {
|
||||
return rsa.GenerateKey(rand.Reader, 2048)
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "ECDSA valid path and name",
|
||||
pathSuffix: "",
|
||||
name: "foo",
|
||||
keyGenFunc: func() (crypto.Signer, error) {
|
||||
return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
for _, rt := range tests {
|
||||
t.Run(rt.desc, func(t *testing.T) {
|
||||
_, actual := TryLoadKeyFromDisk(rt.path, rt.name)
|
||||
tmpdir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create tmpdir")
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
caKey, err := rt.keyGenFunc()
|
||||
if err != nil {
|
||||
t.Errorf(
|
||||
"failed to create key with an error: %v",
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
err = WriteKey(tmpdir, "foo", caKey)
|
||||
if err != nil {
|
||||
t.Errorf(
|
||||
"failed to write key with an error: %v",
|
||||
err,
|
||||
)
|
||||
}
|
||||
_, actual := TryLoadKeyFromDisk(tmpdir+rt.pathSuffix, rt.name)
|
||||
if (actual == nil) != rt.expected {
|
||||
t.Errorf(
|
||||
"failed TryLoadCertAndKeyFromDisk:\n\texpected: %t\n\t actual: %t",
|
||||
|
Reference in New Issue
Block a user