Add support for ed25519 (#11780)
* update azure instructions Update instructions in regards to azure AD Authentication and OIDC * Initial pass of ed25519 * Fix typos on marshal function * test wip * typo * fix tests * missef changelog * fix mismatch between signature and algo * added test coverage for ed25519 * remove pkcs1 since does not exist for ed25519 * add ed25519 support to getsigner * pull request feedback Signed-off-by: Anner J. Bonilla <abonilla@hoyosintegrity.com> * typo on key Signed-off-by: Anner J. Bonilla <abonilla@hoyosintegrity.com> * cast mistake Signed-off-by: Anner J. Bonilla <abonilla@hoyosintegrity.com> Co-authored-by: Jim Kalafut <jkalafut@hashicorp.com>
This commit is contained in:
parent
b979b52ed8
commit
8c29f49e1a
|
@ -5,6 +5,7 @@ import (
|
|||
"context"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/ed25519"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
|
@ -211,6 +212,8 @@ func TestBackend_Roles(t *testing.T) {
|
|||
{"RSACSR", &rsaCAKey, &rsaCACert, true},
|
||||
{"EC", &ecCAKey, &ecCACert, false},
|
||||
{"ECCSR", &ecCAKey, &ecCACert, true},
|
||||
{"ED", &edCAKey, &edCACert, false},
|
||||
{"EDCSR", &edCAKey, &edCACert, true},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
|
@ -309,6 +312,13 @@ func checkCertsAndPrivateKey(keyType string, key crypto.Signer, usage x509.KeyUs
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing EC key: %s", err)
|
||||
}
|
||||
case "ed25519":
|
||||
parsedCertBundle.PrivateKeyType = certutil.Ed25519PrivateKey
|
||||
parsedCertBundle.PrivateKey = key
|
||||
parsedCertBundle.PrivateKeyBytes, err = x509.MarshalPKCS8PrivateKey(key.(ed25519.PrivateKey))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing Ed25519 key: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -324,6 +334,8 @@ func checkCertsAndPrivateKey(keyType string, key crypto.Signer, usage x509.KeyUs
|
|||
}
|
||||
|
||||
switch {
|
||||
case parsedCertBundle.PrivateKeyType == certutil.Ed25519PrivateKey && keyType != "ed25519":
|
||||
fallthrough
|
||||
case parsedCertBundle.PrivateKeyType == certutil.RSAPrivateKey && keyType != "rsa":
|
||||
fallthrough
|
||||
case parsedCertBundle.PrivateKeyType == certutil.ECPrivateKey && keyType != "ec":
|
||||
|
@ -707,7 +719,7 @@ func generateRoleSteps(t *testing.T, useCSRs bool) []logicaltest.TestStep {
|
|||
|
||||
generatedRSAKeys := map[int]crypto.Signer{}
|
||||
generatedECKeys := map[int]crypto.Signer{}
|
||||
|
||||
generatedEdKeys := map[int]crypto.Signer{}
|
||||
/*
|
||||
// For the number of tests being run, a seed of 1 has been tested
|
||||
// to hit all of the various values below. However, for normal
|
||||
|
@ -1017,6 +1029,13 @@ func generateRoleSteps(t *testing.T, useCSRs bool) []logicaltest.TestStep {
|
|||
generatedECKeys[keyBits] = privKey
|
||||
}
|
||||
|
||||
case "ed25519":
|
||||
privKey, ok = generatedEdKeys[keyBits]
|
||||
if !ok {
|
||||
_, privKey, _ = ed25519.GenerateKey(rand.Reader)
|
||||
generatedEdKeys[keyBits] = privKey
|
||||
}
|
||||
|
||||
default:
|
||||
panic("invalid key type: " + keyType)
|
||||
}
|
||||
|
@ -3095,6 +3114,36 @@ func setCerts() {
|
|||
Bytes: caBytes,
|
||||
}
|
||||
rsaCACert = strings.TrimSpace(string(pem.EncodeToMemory(caCertPEMBlock)))
|
||||
|
||||
_, edk, err := ed25519.GenerateKey(rand.Reader)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
marshaledKey, err = x509.MarshalPKCS8PrivateKey(edk)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
keyPEMBlock = &pem.Block{
|
||||
Type: "PRIVATE KEY",
|
||||
Bytes: marshaledKey,
|
||||
}
|
||||
edCAKey = strings.TrimSpace(string(pem.EncodeToMemory(keyPEMBlock)))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
subjKeyID, err = certutil.GetSubjKeyID(edk)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
caBytes, err = x509.CreateCertificate(rand.Reader, caCertTemplate, caCertTemplate, edk.Public(), edk)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
caCertPEMBlock = &pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: caBytes,
|
||||
}
|
||||
edCACert = strings.TrimSpace(string(pem.EncodeToMemory(caCertPEMBlock)))
|
||||
}
|
||||
|
||||
func TestBackend_RevokePlusTidy_Intermediate(t *testing.T) {
|
||||
|
@ -3281,4 +3330,6 @@ var (
|
|||
rsaCACert string
|
||||
ecCAKey string
|
||||
ecCACert string
|
||||
edCAKey string
|
||||
edCACert string
|
||||
)
|
||||
|
|
|
@ -3,6 +3,7 @@ package pki
|
|||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"crypto/ed25519"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
|
@ -49,7 +50,7 @@ func TestBackend_CA_Steps(t *testing.T) {
|
|||
client := cluster.Cores[0].Client
|
||||
|
||||
// Set RSA/EC CA certificates
|
||||
var rsaCAKey, rsaCACert, ecCAKey, ecCACert string
|
||||
var rsaCAKey, rsaCACert, ecCAKey, ecCACert, edCAKey, edCACert string
|
||||
{
|
||||
cak, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
|
@ -119,10 +120,40 @@ func TestBackend_CA_Steps(t *testing.T) {
|
|||
Bytes: caBytes,
|
||||
}
|
||||
rsaCACert = strings.TrimSpace(string(pem.EncodeToMemory(caCertPEMBlock)))
|
||||
|
||||
_, edk, err := ed25519.GenerateKey(rand.Reader)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
marshaledKey, err = x509.MarshalPKCS8PrivateKey(edk)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
keyPEMBlock = &pem.Block{
|
||||
Type: "PRIVATE KEY",
|
||||
Bytes: marshaledKey,
|
||||
}
|
||||
edCAKey = strings.TrimSpace(string(pem.EncodeToMemory(keyPEMBlock)))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_, err = certutil.GetSubjKeyID(edk)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
caBytes, err = x509.CreateCertificate(rand.Reader, caCertTemplate, caCertTemplate, edk.Public(), edk)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
caCertPEMBlock = &pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: caBytes,
|
||||
}
|
||||
edCACert = strings.TrimSpace(string(pem.EncodeToMemory(caCertPEMBlock)))
|
||||
}
|
||||
|
||||
// Setup backends
|
||||
var rsaRoot, rsaInt, ecRoot, ecInt *backend
|
||||
var rsaRoot, rsaInt, ecRoot, ecInt, edRoot, edInt *backend
|
||||
{
|
||||
if err := client.Sys().Mount("rsaroot", &api.MountInput{
|
||||
Type: "pki",
|
||||
|
@ -167,6 +198,28 @@ func TestBackend_CA_Steps(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
ecInt = b
|
||||
|
||||
if err := client.Sys().Mount("ed25519root", &api.MountInput{
|
||||
Type: "pki",
|
||||
Config: api.MountConfigInput{
|
||||
DefaultLeaseTTL: "16h",
|
||||
MaxLeaseTTL: "60h",
|
||||
},
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
edRoot = b
|
||||
|
||||
if err := client.Sys().Mount("ed25519int", &api.MountInput{
|
||||
Type: "pki",
|
||||
Config: api.MountConfigInput{
|
||||
DefaultLeaseTTL: "16h",
|
||||
MaxLeaseTTL: "60h",
|
||||
},
|
||||
}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
edInt = b
|
||||
}
|
||||
|
||||
t.Run("teststeps", func(t *testing.T) {
|
||||
|
@ -188,6 +241,15 @@ func TestBackend_CA_Steps(t *testing.T) {
|
|||
subClient.SetToken(client.Token())
|
||||
runSteps(t, ecRoot, ecInt, subClient, "ecroot/", "ecint/", ecCACert, ecCAKey)
|
||||
})
|
||||
t.Run("ed25519", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
subClient, err := client.Clone()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
subClient.SetToken(client.Token())
|
||||
runSteps(t, edRoot, edInt, subClient, "ed25519root/", "ed25519int/", edCACert, edCAKey)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/ed25519"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
|
@ -597,6 +598,18 @@ func signCert(b *backend,
|
|||
pubKey.Params().BitSize)}
|
||||
}
|
||||
|
||||
case "ed25519":
|
||||
// Verify that the key matches the role type
|
||||
if csr.PublicKeyAlgorithm != x509.PublicKeyAlgorithm(x509.Ed25519) {
|
||||
return nil, errutil.UserError{Err: fmt.Sprintf(
|
||||
"role requires keys of type %s",
|
||||
data.role.KeyType)}
|
||||
}
|
||||
_, ok := csr.PublicKey.(ed25519.PublicKey)
|
||||
if !ok {
|
||||
return nil, errutil.UserError{Err: "could not parse CSR's public key"}
|
||||
}
|
||||
|
||||
case "any":
|
||||
// We only care about running RSA < 2048 bit checks, so if not RSA
|
||||
// break out
|
||||
|
|
|
@ -270,8 +270,8 @@ Set to 384 for SHA384 and 512 for SHA512.
|
|||
Type: framework.TypeString,
|
||||
Default: "rsa",
|
||||
Description: `The type of key to use; defaults to RSA. "rsa"
|
||||
and "ec" are the only valid values.`,
|
||||
AllowedValues: []interface{}{"rsa", "ec"},
|
||||
"ec" and "ed25519" are the only valid values.`,
|
||||
AllowedValues: []interface{}{"rsa", "ec", "ed25519"},
|
||||
DisplayAttrs: &framework.DisplayAttributes{
|
||||
Value: "rsa",
|
||||
},
|
||||
|
|
|
@ -193,8 +193,8 @@ protection use. Defaults to false.`,
|
|||
Type: framework.TypeString,
|
||||
Default: "rsa",
|
||||
Description: `The type of key to use; defaults to RSA. "rsa"
|
||||
and "ec" are the only valid values.`,
|
||||
AllowedValues: []interface{}{"rsa", "ec"},
|
||||
"ec" and "ed25519" are the only valid values.`,
|
||||
AllowedValues: []interface{}{"rsa", "ec", "ed25519"},
|
||||
},
|
||||
|
||||
"key_bits": {
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
```release-note:feature
|
||||
pki: Support ed25519 as a key for the pki backend
|
||||
```
|
|
@ -3,6 +3,7 @@ package certutil
|
|||
import (
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"crypto/ed25519"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
|
@ -36,6 +37,8 @@ func TestCertBundleConversion(t *testing.T) {
|
|||
refreshECCertBundleWithChain(),
|
||||
refreshEC8CertBundle(),
|
||||
refreshEC8CertBundleWithChain(),
|
||||
refreshEd255198CertBundle(),
|
||||
refreshEd255198CertBundleWithChain(),
|
||||
}
|
||||
|
||||
for i, cbut := range cbuts {
|
||||
|
@ -75,6 +78,8 @@ func BenchmarkCertBundleParsing(b *testing.B) {
|
|||
refreshECCertBundleWithChain(),
|
||||
refreshEC8CertBundle(),
|
||||
refreshEC8CertBundleWithChain(),
|
||||
refreshEd255198CertBundle(),
|
||||
refreshEd255198CertBundleWithChain(),
|
||||
}
|
||||
|
||||
for i, cbut := range cbuts {
|
||||
|
@ -103,6 +108,8 @@ func TestCertBundleParsing(t *testing.T) {
|
|||
refreshECCertBundleWithChain(),
|
||||
refreshEC8CertBundle(),
|
||||
refreshEC8CertBundleWithChain(),
|
||||
refreshEd255198CertBundle(),
|
||||
refreshEd255198CertBundleWithChain(),
|
||||
}
|
||||
|
||||
for i, cbut := range cbuts {
|
||||
|
@ -179,6 +186,10 @@ func compareCertBundleToParsedCertBundle(cbut *CertBundle, pcbut *ParsedCertBund
|
|||
if pcbut.PrivateKeyType != ECPrivateKey {
|
||||
return fmt.Errorf("parsed bundle has wrong pkcs8 private key type: %v, should be 'ec' (%v)", pcbut.PrivateKeyType, ECPrivateKey)
|
||||
}
|
||||
case privEd255198KeyPem:
|
||||
if pcbut.PrivateKeyType != Ed25519PrivateKey {
|
||||
return fmt.Errorf("parsed bundle has wrong pkcs8 private key type: %v, should be 'ed25519' (%v)", pcbut.PrivateKeyType, ECPrivateKey)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("parsed bundle has unknown private key type")
|
||||
}
|
||||
|
@ -221,6 +232,10 @@ func compareCertBundleToParsedCertBundle(cbut *CertBundle, pcbut *ParsedCertBund
|
|||
if cb.PrivateKey != privECKeyPem && cb.PrivateKey != privEC8KeyPem {
|
||||
return fmt.Errorf("bundle private key does not match")
|
||||
}
|
||||
case Ed25519PrivateKey:
|
||||
if cb.PrivateKey != privEd255198KeyPem {
|
||||
return fmt.Errorf("bundle private key does not match")
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("certBundle has unknown private key type")
|
||||
}
|
||||
|
@ -245,6 +260,7 @@ func TestCSRBundleConversion(t *testing.T) {
|
|||
csrbuts := []*CSRBundle{
|
||||
refreshRSACSRBundle(),
|
||||
refreshECCSRBundle(),
|
||||
refreshEd25519CSRBundle(),
|
||||
}
|
||||
|
||||
for _, csrbut := range csrbuts {
|
||||
|
@ -294,6 +310,10 @@ func compareCSRBundleToParsedCSRBundle(csrbut *CSRBundle, pcsrbut *ParsedCSRBund
|
|||
if pcsrbut.PrivateKeyType != ECPrivateKey {
|
||||
return fmt.Errorf("parsed bundle has wrong private key type")
|
||||
}
|
||||
case privEd255198KeyPem:
|
||||
if pcsrbut.PrivateKeyType != Ed25519PrivateKey {
|
||||
return fmt.Errorf("parsed bundle has wrong private key type")
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("parsed bundle has unknown private key type")
|
||||
}
|
||||
|
@ -325,6 +345,13 @@ func compareCSRBundleToParsedCSRBundle(csrbut *CSRBundle, pcsrbut *ParsedCSRBund
|
|||
if csrb.PrivateKey != privECKeyPem {
|
||||
return fmt.Errorf("bundle ec private key does not match")
|
||||
}
|
||||
case "ed25519":
|
||||
if pcsrbut.PrivateKeyType != Ed25519PrivateKey {
|
||||
return fmt.Errorf("bundle has wrong private key type")
|
||||
}
|
||||
if csrb.PrivateKey != privEd255198KeyPem {
|
||||
return fmt.Errorf("bundle ed25519 private key does not match")
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("bundle has unknown private key type")
|
||||
}
|
||||
|
@ -476,6 +503,30 @@ func refreshECCertBundleWithChain() *CertBundle {
|
|||
return ret
|
||||
}
|
||||
|
||||
func refreshEd255198CertBundle() *CertBundle {
|
||||
initTest.Do(setCerts)
|
||||
return &CertBundle{
|
||||
Certificate: certEd25519Pem,
|
||||
PrivateKey: privEd255198KeyPem,
|
||||
CAChain: []string{issuingCaChainPem[0]},
|
||||
}
|
||||
}
|
||||
|
||||
func refreshEd255198CertBundleWithChain() *CertBundle {
|
||||
initTest.Do(setCerts)
|
||||
ret := refreshEd255198CertBundle()
|
||||
ret.CAChain = issuingCaChainPem
|
||||
return ret
|
||||
}
|
||||
|
||||
func refreshEd25519CSRBundle() *CSRBundle {
|
||||
initTest.Do(setCerts)
|
||||
return &CSRBundle{
|
||||
CSR: csrEd25519Pem,
|
||||
PrivateKey: privEd255198KeyPem,
|
||||
}
|
||||
}
|
||||
|
||||
func refreshRSACSRBundle() *CSRBundle {
|
||||
initTest.Do(setCerts)
|
||||
return &CSRBundle{
|
||||
|
@ -714,18 +765,81 @@ func setCerts() {
|
|||
privRSA8KeyPem = strings.TrimSpace(string(pem.EncodeToMemory(keyPEMBlock)))
|
||||
}
|
||||
|
||||
// Ed25519 generation
|
||||
{
|
||||
pubkey, privkey, err := ed25519.GenerateKey(rand.Reader)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
subjKeyID, err := GetSubjKeyID(privkey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
certTemplate := &x509.Certificate{
|
||||
Subject: pkix.Name{
|
||||
CommonName: "localhost",
|
||||
},
|
||||
SubjectKeyId: subjKeyID,
|
||||
DNSNames: []string{"localhost"},
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{
|
||||
x509.ExtKeyUsageServerAuth,
|
||||
x509.ExtKeyUsageClientAuth,
|
||||
},
|
||||
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageKeyAgreement,
|
||||
SerialNumber: big.NewInt(mathrand.Int63()),
|
||||
NotBefore: time.Now().Add(-30 * time.Second),
|
||||
NotAfter: time.Now().Add(262980 * time.Hour),
|
||||
}
|
||||
csrTemplate := &x509.CertificateRequest{
|
||||
Subject: pkix.Name{
|
||||
CommonName: "localhost",
|
||||
},
|
||||
DNSNames: []string{"localhost"},
|
||||
}
|
||||
csrBytes, err := x509.CreateCertificateRequest(rand.Reader, csrTemplate, privkey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
csrPEMBlock := &pem.Block{
|
||||
Type: "CERTIFICATE REQUEST",
|
||||
Bytes: csrBytes,
|
||||
}
|
||||
csrEd25519Pem = strings.TrimSpace(string(pem.EncodeToMemory(csrPEMBlock)))
|
||||
certBytes, err := x509.CreateCertificate(rand.Reader, certTemplate, intCert, pubkey, intKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
certPEMBlock := &pem.Block{
|
||||
Type: "CERTIFICATE",
|
||||
Bytes: certBytes,
|
||||
}
|
||||
certEd25519Pem = strings.TrimSpace(string(pem.EncodeToMemory(certPEMBlock)))
|
||||
marshaledKey, err := x509.MarshalPKCS8PrivateKey(privkey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
keyPEMBlock := &pem.Block{
|
||||
Type: "PRIVATE KEY",
|
||||
Bytes: marshaledKey,
|
||||
}
|
||||
privEd255198KeyPem = strings.TrimSpace(string(pem.EncodeToMemory(keyPEMBlock)))
|
||||
}
|
||||
|
||||
issuingCaChainPem = []string{intCertPEM, caCertPEM}
|
||||
}
|
||||
|
||||
var (
|
||||
initTest sync.Once
|
||||
privRSA8KeyPem string
|
||||
privRSAKeyPem string
|
||||
csrRSAPem string
|
||||
certRSAPem string
|
||||
privECKeyPem string
|
||||
csrECPem string
|
||||
privEC8KeyPem string
|
||||
certECPem string
|
||||
issuingCaChainPem []string
|
||||
initTest sync.Once
|
||||
privRSA8KeyPem string
|
||||
privRSAKeyPem string
|
||||
csrRSAPem string
|
||||
certRSAPem string
|
||||
privEd255198KeyPem string
|
||||
csrEd25519Pem string
|
||||
certEd25519Pem string
|
||||
privECKeyPem string
|
||||
csrECPem string
|
||||
privEC8KeyPem string
|
||||
certECPem string
|
||||
issuingCaChainPem []string
|
||||
)
|
||||
|
|
|
@ -164,6 +164,10 @@ func ParsePEMBundle(pemBundle string) (*ParsedCertBundle, error) {
|
|||
parsedBundle.PrivateKey = signer
|
||||
parsedBundle.PrivateKeyType = ECPrivateKey
|
||||
parsedBundle.PrivateKeyBytes = pemBlock.Bytes
|
||||
case ed25519.PrivateKey:
|
||||
parsedBundle.PrivateKey = signer
|
||||
parsedBundle.PrivateKeyType = Ed25519PrivateKey
|
||||
parsedBundle.PrivateKeyBytes = pemBlock.Bytes
|
||||
}
|
||||
} else if certificates, err := x509.ParseCertificates(pemBlock.Bytes); err == nil {
|
||||
certPath = append(certPath, &CertBlock{
|
||||
|
@ -246,6 +250,16 @@ func generatePrivateKey(keyType string, keyBits int, container ParsedPrivateKeyC
|
|||
if err != nil {
|
||||
return errutil.InternalError{Err: fmt.Sprintf("error marshalling EC private key: %v", err)}
|
||||
}
|
||||
case "ed25519":
|
||||
privateKeyType = Ed25519PrivateKey
|
||||
_, privateKey, err = ed25519.GenerateKey(randReader)
|
||||
if err != nil {
|
||||
return errutil.InternalError{Err: fmt.Sprintf("error generating ed25519 private key: %v", err)}
|
||||
}
|
||||
privateKeyBytes, err = x509.MarshalPKCS8PrivateKey(privateKey.(ed25519.PrivateKey))
|
||||
if err != nil {
|
||||
return errutil.InternalError{Err: fmt.Sprintf("error marshalling Ed25519 private key: %v", err)}
|
||||
}
|
||||
default:
|
||||
return errutil.UserError{Err: fmt.Sprintf("unknown key type: %s", keyType)}
|
||||
}
|
||||
|
@ -309,7 +323,16 @@ func ComparePublicKeys(key1Iface, key2Iface crypto.PublicKey) (bool, error) {
|
|||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
|
||||
case ed25519.PublicKey:
|
||||
key1 := key1Iface.(ed25519.PublicKey)
|
||||
key2, ok := key2Iface.(ed25519.PublicKey)
|
||||
if !ok {
|
||||
return false, fmt.Errorf("key types do not match: %T and %T", key1Iface, key2Iface)
|
||||
}
|
||||
if !key1.Equal(key2) {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
default:
|
||||
return false, fmt.Errorf("cannot compare key with type %T", key1Iface)
|
||||
}
|
||||
|
@ -521,7 +544,7 @@ func ValidateKeyTypeLength(keyType string, keyBits int) error {
|
|||
default:
|
||||
return fmt.Errorf("unsupported bit length for EC key: %d", keyBits)
|
||||
}
|
||||
case "any":
|
||||
case "any", "ed25519":
|
||||
default:
|
||||
return fmt.Errorf("unknown key type %s", keyType)
|
||||
}
|
||||
|
@ -617,6 +640,8 @@ func createCertificate(data *CreationBundle, randReader io.Reader) (*ParsedCertB
|
|||
case 512:
|
||||
certTemplate.SignatureAlgorithm = x509.SHA512WithRSA
|
||||
}
|
||||
case Ed25519PrivateKey:
|
||||
certTemplate.SignatureAlgorithm = x509.PureEd25519
|
||||
case ECPrivateKey:
|
||||
switch data.Params.SignatureBits {
|
||||
case 256:
|
||||
|
@ -651,6 +676,8 @@ func createCertificate(data *CreationBundle, randReader io.Reader) (*ParsedCertB
|
|||
case 512:
|
||||
certTemplate.SignatureAlgorithm = x509.SHA512WithRSA
|
||||
}
|
||||
case "ed25519":
|
||||
certTemplate.SignatureAlgorithm = x509.PureEd25519
|
||||
case "ec":
|
||||
switch data.Params.SignatureBits {
|
||||
case 256:
|
||||
|
@ -754,6 +781,8 @@ func createCSR(data *CreationBundle, addBasicConstraints bool, randReader io.Rea
|
|||
csrTemplate.SignatureAlgorithm = x509.SHA256WithRSA
|
||||
case "ec":
|
||||
csrTemplate.SignatureAlgorithm = x509.ECDSAWithSHA256
|
||||
case "ed25519":
|
||||
csrTemplate.SignatureAlgorithm = x509.PureEd25519
|
||||
}
|
||||
|
||||
csr, err := x509.CreateCertificateRequest(randReader, csrTemplate, result.PrivateKey)
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"bytes"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/ed25519"
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
|
@ -56,6 +57,7 @@ const (
|
|||
UnknownPrivateKey PrivateKeyType = ""
|
||||
RSAPrivateKey PrivateKeyType = "rsa"
|
||||
ECPrivateKey PrivateKeyType = "ec"
|
||||
Ed25519PrivateKey PrivateKeyType = "ed25519"
|
||||
)
|
||||
|
||||
// TLSUsage controls whether the intended usage of a *tls.Config
|
||||
|
@ -185,6 +187,8 @@ func (c *CertBundle) ToParsedCertBundle() (*ParsedCertBundle, error) {
|
|||
c.PrivateKeyType = ECPrivateKey
|
||||
case RSAPrivateKey:
|
||||
c.PrivateKeyType = RSAPrivateKey
|
||||
case Ed25519PrivateKey:
|
||||
c.PrivateKeyType = Ed25519PrivateKey
|
||||
}
|
||||
default:
|
||||
return nil, errutil.UserError{Err: fmt.Sprintf("Unsupported key block type: %s", pemBlock.Type)}
|
||||
|
@ -290,6 +294,8 @@ func (p *ParsedCertBundle) ToCertBundle() (*CertBundle, error) {
|
|||
block.Type = string(ECBlock)
|
||||
case RSAPrivateKey:
|
||||
block.Type = string(PKCS1Block)
|
||||
case Ed25519PrivateKey:
|
||||
block.Type = string(PKCS8Block)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -380,7 +386,7 @@ func (p *ParsedCertBundle) getSigner() (crypto.Signer, error) {
|
|||
case PKCS8Block:
|
||||
if k, err := x509.ParsePKCS8PrivateKey(p.PrivateKeyBytes); err == nil {
|
||||
switch k := k.(type) {
|
||||
case *rsa.PrivateKey, *ecdsa.PrivateKey:
|
||||
case *rsa.PrivateKey, *ecdsa.PrivateKey, ed25519.PrivateKey:
|
||||
return k.(crypto.Signer), nil
|
||||
default:
|
||||
return nil, errutil.UserError{Err: "Found unknown private key type in pkcs#8 wrapping"}
|
||||
|
@ -411,6 +417,8 @@ func getPKCS8Type(bs []byte) (PrivateKeyType, error) {
|
|||
return ECPrivateKey, nil
|
||||
case *rsa.PrivateKey:
|
||||
return RSAPrivateKey, nil
|
||||
case ed25519.PrivateKey:
|
||||
return Ed25519PrivateKey, nil
|
||||
default:
|
||||
return UnknownPrivateKey, errutil.UserError{Err: "Found unknown private key type in pkcs#8 wrapping"}
|
||||
}
|
||||
|
@ -443,6 +451,9 @@ func (c *CSRBundle) ToParsedCSRBundle() (*ParsedCSRBundle, error) {
|
|||
} else if _, err := x509.ParsePKCS1PrivateKey(pemBlock.Bytes); err == nil {
|
||||
result.PrivateKeyType = RSAPrivateKey
|
||||
c.PrivateKeyType = "rsa"
|
||||
} else if _, err := x509.ParsePKCS8PrivateKey(pemBlock.Bytes); err == nil {
|
||||
result.PrivateKeyType = Ed25519PrivateKey
|
||||
c.PrivateKeyType = "ed25519"
|
||||
} else {
|
||||
return nil, errutil.UserError{Err: fmt.Sprintf("Unknown private key type in bundle: %s", c.PrivateKeyType)}
|
||||
}
|
||||
|
@ -491,6 +502,9 @@ func (p *ParsedCSRBundle) ToCSRBundle() (*CSRBundle, error) {
|
|||
case ECPrivateKey:
|
||||
result.PrivateKeyType = "ec"
|
||||
block.Type = "EC PRIVATE KEY"
|
||||
case Ed25519PrivateKey:
|
||||
result.PrivateKeyType = "ed25519"
|
||||
block.Type = "PRIVATE KEY"
|
||||
default:
|
||||
return nil, errutil.InternalError{Err: "Could not determine private key type when creating block"}
|
||||
}
|
||||
|
@ -525,8 +539,15 @@ func (p *ParsedCSRBundle) getSigner() (crypto.Signer, error) {
|
|||
return nil, errutil.UserError{Err: fmt.Sprintf("Unable to parse CA's private RSA key: %s", err)}
|
||||
}
|
||||
|
||||
case Ed25519PrivateKey:
|
||||
signerd, err := x509.ParsePKCS8PrivateKey(p.PrivateKeyBytes)
|
||||
signer = signerd.(ed25519.PrivateKey)
|
||||
if err != nil {
|
||||
return nil, errutil.UserError{Err: fmt.Sprintf("Unable to parse CA's private Ed25519 key: %s", err)}
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, errutil.UserError{Err: "Unable to determine type of private key; only RSA and EC are supported"}
|
||||
return nil, errutil.UserError{Err: "Unable to determine type of private key; only RSA, Ed25519 and EC are supported"}
|
||||
}
|
||||
return signer, nil
|
||||
}
|
||||
|
|
|
@ -128,7 +128,7 @@ export default Certificate.extend({
|
|||
}),
|
||||
|
||||
keyType: attr('string', {
|
||||
possibleValues: ['rsa', 'ec'],
|
||||
possibleValues: ['rsa', 'ec','ed25519'],
|
||||
defaultValue: 'rsa',
|
||||
}),
|
||||
keyBits: attr('number', {
|
||||
|
|
|
@ -463,7 +463,7 @@ can be set in a CSR are supported.
|
|||
PEM-encoded DER, depending on the value of `format`. The other option is
|
||||
`pkcs8` which will return the key marshalled as PEM-encoded PKCS8.
|
||||
|
||||
- `key_type` `(string: "rsa")` – Specifies the desired key type; must be `rsa`
|
||||
- `key_type` `(string: "rsa")` – Specifies the desired key type; must be `rsa`, `ed25519`
|
||||
or `ec`.
|
||||
|
||||
- `key_bits` `(int: 2048)` – Specifies the number of bits to use. This must be
|
||||
|
@ -1084,7 +1084,7 @@ overwrite the existing cert/key with new values.
|
|||
PEM-encoded DER, depending on the value of `format`. The other option is
|
||||
`pkcs8` which will return the key marshalled as PEM-encoded PKCS8.
|
||||
|
||||
- `key_type` `(string: "rsa")` – Specifies the desired key type; must be `rsa`
|
||||
- `key_type` `(string: "rsa")` – Specifies the desired key type; must be `rsa`, `ed25519`
|
||||
or `ec`.
|
||||
|
||||
- `key_bits` `(int: 2048)` – Specifies the number of bits to use. This must be
|
||||
|
|
Loading…
Reference in New Issue