mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-11-04 04:28:08 +00:00 
			
		
		
		
	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:
		@@ -5,6 +5,7 @@ import (
 | 
				
			|||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"crypto"
 | 
						"crypto"
 | 
				
			||||||
	"crypto/ecdsa"
 | 
						"crypto/ecdsa"
 | 
				
			||||||
 | 
						"crypto/ed25519"
 | 
				
			||||||
	"crypto/elliptic"
 | 
						"crypto/elliptic"
 | 
				
			||||||
	"crypto/rand"
 | 
						"crypto/rand"
 | 
				
			||||||
	"crypto/rsa"
 | 
						"crypto/rsa"
 | 
				
			||||||
@@ -211,6 +212,8 @@ func TestBackend_Roles(t *testing.T) {
 | 
				
			|||||||
		{"RSACSR", &rsaCAKey, &rsaCACert, true},
 | 
							{"RSACSR", &rsaCAKey, &rsaCACert, true},
 | 
				
			||||||
		{"EC", &ecCAKey, &ecCACert, false},
 | 
							{"EC", &ecCAKey, &ecCACert, false},
 | 
				
			||||||
		{"ECCSR", &ecCAKey, &ecCACert, true},
 | 
							{"ECCSR", &ecCAKey, &ecCACert, true},
 | 
				
			||||||
 | 
							{"ED", &edCAKey, &edCACert, false},
 | 
				
			||||||
 | 
							{"EDCSR", &edCAKey, &edCACert, true},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, tc := range cases {
 | 
						for _, tc := range cases {
 | 
				
			||||||
@@ -309,6 +312,13 @@ func checkCertsAndPrivateKey(keyType string, key crypto.Signer, usage x509.KeyUs
 | 
				
			|||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return nil, fmt.Errorf("error parsing EC key: %s", err)
 | 
									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 {
 | 
						switch {
 | 
				
			||||||
 | 
						case parsedCertBundle.PrivateKeyType == certutil.Ed25519PrivateKey && keyType != "ed25519":
 | 
				
			||||||
 | 
							fallthrough
 | 
				
			||||||
	case parsedCertBundle.PrivateKeyType == certutil.RSAPrivateKey && keyType != "rsa":
 | 
						case parsedCertBundle.PrivateKeyType == certutil.RSAPrivateKey && keyType != "rsa":
 | 
				
			||||||
		fallthrough
 | 
							fallthrough
 | 
				
			||||||
	case parsedCertBundle.PrivateKeyType == certutil.ECPrivateKey && keyType != "ec":
 | 
						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{}
 | 
						generatedRSAKeys := map[int]crypto.Signer{}
 | 
				
			||||||
	generatedECKeys := 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
 | 
							// 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
 | 
							// 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
 | 
									generatedECKeys[keyBits] = privKey
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							case "ed25519":
 | 
				
			||||||
 | 
								privKey, ok = generatedEdKeys[keyBits]
 | 
				
			||||||
 | 
								if !ok {
 | 
				
			||||||
 | 
									_, privKey, _ = ed25519.GenerateKey(rand.Reader)
 | 
				
			||||||
 | 
									generatedEdKeys[keyBits] = privKey
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			panic("invalid key type: " + keyType)
 | 
								panic("invalid key type: " + keyType)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -3095,6 +3114,36 @@ func setCerts() {
 | 
				
			|||||||
		Bytes: caBytes,
 | 
							Bytes: caBytes,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	rsaCACert = strings.TrimSpace(string(pem.EncodeToMemory(caCertPEMBlock)))
 | 
						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) {
 | 
					func TestBackend_RevokePlusTidy_Intermediate(t *testing.T) {
 | 
				
			||||||
@@ -3281,4 +3330,6 @@ var (
 | 
				
			|||||||
	rsaCACert string
 | 
						rsaCACert string
 | 
				
			||||||
	ecCAKey   string
 | 
						ecCAKey   string
 | 
				
			||||||
	ecCACert  string
 | 
						ecCACert  string
 | 
				
			||||||
 | 
						edCAKey   string
 | 
				
			||||||
 | 
						edCACert  string
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,7 @@ package pki
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"crypto/ecdsa"
 | 
						"crypto/ecdsa"
 | 
				
			||||||
 | 
						"crypto/ed25519"
 | 
				
			||||||
	"crypto/elliptic"
 | 
						"crypto/elliptic"
 | 
				
			||||||
	"crypto/rand"
 | 
						"crypto/rand"
 | 
				
			||||||
	"crypto/rsa"
 | 
						"crypto/rsa"
 | 
				
			||||||
@@ -49,7 +50,7 @@ func TestBackend_CA_Steps(t *testing.T) {
 | 
				
			|||||||
	client := cluster.Cores[0].Client
 | 
						client := cluster.Cores[0].Client
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Set RSA/EC CA certificates
 | 
						// 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)
 | 
							cak, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
@@ -119,10 +120,40 @@ func TestBackend_CA_Steps(t *testing.T) {
 | 
				
			|||||||
			Bytes: caBytes,
 | 
								Bytes: caBytes,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		rsaCACert = strings.TrimSpace(string(pem.EncodeToMemory(caCertPEMBlock)))
 | 
							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
 | 
						// Setup backends
 | 
				
			||||||
	var rsaRoot, rsaInt, ecRoot, ecInt *backend
 | 
						var rsaRoot, rsaInt, ecRoot, ecInt, edRoot, edInt *backend
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if err := client.Sys().Mount("rsaroot", &api.MountInput{
 | 
							if err := client.Sys().Mount("rsaroot", &api.MountInput{
 | 
				
			||||||
			Type: "pki",
 | 
								Type: "pki",
 | 
				
			||||||
@@ -167,6 +198,28 @@ func TestBackend_CA_Steps(t *testing.T) {
 | 
				
			|||||||
			t.Fatal(err)
 | 
								t.Fatal(err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ecInt = b
 | 
							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) {
 | 
						t.Run("teststeps", func(t *testing.T) {
 | 
				
			||||||
@@ -188,6 +241,15 @@ func TestBackend_CA_Steps(t *testing.T) {
 | 
				
			|||||||
			subClient.SetToken(client.Token())
 | 
								subClient.SetToken(client.Token())
 | 
				
			||||||
			runSteps(t, ecRoot, ecInt, subClient, "ecroot/", "ecint/", ecCACert, ecCAKey)
 | 
								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"
 | 
						"context"
 | 
				
			||||||
	"crypto"
 | 
						"crypto"
 | 
				
			||||||
	"crypto/ecdsa"
 | 
						"crypto/ecdsa"
 | 
				
			||||||
 | 
						"crypto/ed25519"
 | 
				
			||||||
	"crypto/rsa"
 | 
						"crypto/rsa"
 | 
				
			||||||
	"crypto/x509"
 | 
						"crypto/x509"
 | 
				
			||||||
	"crypto/x509/pkix"
 | 
						"crypto/x509/pkix"
 | 
				
			||||||
@@ -597,6 +598,18 @@ func signCert(b *backend,
 | 
				
			|||||||
				pubKey.Params().BitSize)}
 | 
									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":
 | 
						case "any":
 | 
				
			||||||
		// We only care about running RSA < 2048 bit checks, so if not RSA
 | 
							// We only care about running RSA < 2048 bit checks, so if not RSA
 | 
				
			||||||
		// break out
 | 
							// break out
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -270,8 +270,8 @@ Set to 384 for SHA384 and 512 for SHA512.
 | 
				
			|||||||
		Type:    framework.TypeString,
 | 
							Type:    framework.TypeString,
 | 
				
			||||||
		Default: "rsa",
 | 
							Default: "rsa",
 | 
				
			||||||
		Description: `The type of key to use; defaults to RSA. "rsa"
 | 
							Description: `The type of key to use; defaults to RSA. "rsa"
 | 
				
			||||||
and "ec" are the only valid values.`,
 | 
					"ec" and "ed25519" are the only valid values.`,
 | 
				
			||||||
		AllowedValues: []interface{}{"rsa", "ec"},
 | 
							AllowedValues: []interface{}{"rsa", "ec", "ed25519"},
 | 
				
			||||||
		DisplayAttrs: &framework.DisplayAttributes{
 | 
							DisplayAttrs: &framework.DisplayAttributes{
 | 
				
			||||||
			Value: "rsa",
 | 
								Value: "rsa",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -193,8 +193,8 @@ protection use. Defaults to false.`,
 | 
				
			|||||||
				Type:    framework.TypeString,
 | 
									Type:    framework.TypeString,
 | 
				
			||||||
				Default: "rsa",
 | 
									Default: "rsa",
 | 
				
			||||||
				Description: `The type of key to use; defaults to RSA. "rsa"
 | 
									Description: `The type of key to use; defaults to RSA. "rsa"
 | 
				
			||||||
and "ec" are the only valid values.`,
 | 
					"ec" and "ed25519" are the only valid values.`,
 | 
				
			||||||
				AllowedValues: []interface{}{"rsa", "ec"},
 | 
									AllowedValues: []interface{}{"rsa", "ec", "ed25519"},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			"key_bits": {
 | 
								"key_bits": {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										3
									
								
								changelog/11780.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								changelog/11780.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					```release-note:feature
 | 
				
			||||||
 | 
					pki: Support ed25519 as a key for the pki backend
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
@@ -3,6 +3,7 @@ package certutil
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
	"crypto/ecdsa"
 | 
						"crypto/ecdsa"
 | 
				
			||||||
 | 
						"crypto/ed25519"
 | 
				
			||||||
	"crypto/elliptic"
 | 
						"crypto/elliptic"
 | 
				
			||||||
	"crypto/rand"
 | 
						"crypto/rand"
 | 
				
			||||||
	"crypto/rsa"
 | 
						"crypto/rsa"
 | 
				
			||||||
@@ -36,6 +37,8 @@ func TestCertBundleConversion(t *testing.T) {
 | 
				
			|||||||
		refreshECCertBundleWithChain(),
 | 
							refreshECCertBundleWithChain(),
 | 
				
			||||||
		refreshEC8CertBundle(),
 | 
							refreshEC8CertBundle(),
 | 
				
			||||||
		refreshEC8CertBundleWithChain(),
 | 
							refreshEC8CertBundleWithChain(),
 | 
				
			||||||
 | 
							refreshEd255198CertBundle(),
 | 
				
			||||||
 | 
							refreshEd255198CertBundleWithChain(),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for i, cbut := range cbuts {
 | 
						for i, cbut := range cbuts {
 | 
				
			||||||
@@ -75,6 +78,8 @@ func BenchmarkCertBundleParsing(b *testing.B) {
 | 
				
			|||||||
			refreshECCertBundleWithChain(),
 | 
								refreshECCertBundleWithChain(),
 | 
				
			||||||
			refreshEC8CertBundle(),
 | 
								refreshEC8CertBundle(),
 | 
				
			||||||
			refreshEC8CertBundleWithChain(),
 | 
								refreshEC8CertBundleWithChain(),
 | 
				
			||||||
 | 
								refreshEd255198CertBundle(),
 | 
				
			||||||
 | 
								refreshEd255198CertBundleWithChain(),
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for i, cbut := range cbuts {
 | 
							for i, cbut := range cbuts {
 | 
				
			||||||
@@ -103,6 +108,8 @@ func TestCertBundleParsing(t *testing.T) {
 | 
				
			|||||||
		refreshECCertBundleWithChain(),
 | 
							refreshECCertBundleWithChain(),
 | 
				
			||||||
		refreshEC8CertBundle(),
 | 
							refreshEC8CertBundle(),
 | 
				
			||||||
		refreshEC8CertBundleWithChain(),
 | 
							refreshEC8CertBundleWithChain(),
 | 
				
			||||||
 | 
							refreshEd255198CertBundle(),
 | 
				
			||||||
 | 
							refreshEd255198CertBundleWithChain(),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for i, cbut := range cbuts {
 | 
						for i, cbut := range cbuts {
 | 
				
			||||||
@@ -179,6 +186,10 @@ func compareCertBundleToParsedCertBundle(cbut *CertBundle, pcbut *ParsedCertBund
 | 
				
			|||||||
		if pcbut.PrivateKeyType != ECPrivateKey {
 | 
							if pcbut.PrivateKeyType != ECPrivateKey {
 | 
				
			||||||
			return fmt.Errorf("parsed bundle has wrong pkcs8 private key type: %v, should be 'ec' (%v)", 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:
 | 
						default:
 | 
				
			||||||
		return fmt.Errorf("parsed bundle has unknown private key type")
 | 
							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 {
 | 
							if cb.PrivateKey != privECKeyPem && cb.PrivateKey != privEC8KeyPem {
 | 
				
			||||||
			return fmt.Errorf("bundle private key does not match")
 | 
								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:
 | 
						default:
 | 
				
			||||||
		return fmt.Errorf("certBundle has unknown private key type")
 | 
							return fmt.Errorf("certBundle has unknown private key type")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -245,6 +260,7 @@ func TestCSRBundleConversion(t *testing.T) {
 | 
				
			|||||||
	csrbuts := []*CSRBundle{
 | 
						csrbuts := []*CSRBundle{
 | 
				
			||||||
		refreshRSACSRBundle(),
 | 
							refreshRSACSRBundle(),
 | 
				
			||||||
		refreshECCSRBundle(),
 | 
							refreshECCSRBundle(),
 | 
				
			||||||
 | 
							refreshEd25519CSRBundle(),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, csrbut := range csrbuts {
 | 
						for _, csrbut := range csrbuts {
 | 
				
			||||||
@@ -294,6 +310,10 @@ func compareCSRBundleToParsedCSRBundle(csrbut *CSRBundle, pcsrbut *ParsedCSRBund
 | 
				
			|||||||
		if pcsrbut.PrivateKeyType != ECPrivateKey {
 | 
							if pcsrbut.PrivateKeyType != ECPrivateKey {
 | 
				
			||||||
			return fmt.Errorf("parsed bundle has wrong private key type")
 | 
								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:
 | 
						default:
 | 
				
			||||||
		return fmt.Errorf("parsed bundle has unknown private key type")
 | 
							return fmt.Errorf("parsed bundle has unknown private key type")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -325,6 +345,13 @@ func compareCSRBundleToParsedCSRBundle(csrbut *CSRBundle, pcsrbut *ParsedCSRBund
 | 
				
			|||||||
		if csrb.PrivateKey != privECKeyPem {
 | 
							if csrb.PrivateKey != privECKeyPem {
 | 
				
			||||||
			return fmt.Errorf("bundle ec private key does not match")
 | 
								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:
 | 
						default:
 | 
				
			||||||
		return fmt.Errorf("bundle has unknown private key type")
 | 
							return fmt.Errorf("bundle has unknown private key type")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -476,6 +503,30 @@ func refreshECCertBundleWithChain() *CertBundle {
 | 
				
			|||||||
	return ret
 | 
						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 {
 | 
					func refreshRSACSRBundle() *CSRBundle {
 | 
				
			||||||
	initTest.Do(setCerts)
 | 
						initTest.Do(setCerts)
 | 
				
			||||||
	return &CSRBundle{
 | 
						return &CSRBundle{
 | 
				
			||||||
@@ -714,6 +765,66 @@ func setCerts() {
 | 
				
			|||||||
		privRSA8KeyPem = strings.TrimSpace(string(pem.EncodeToMemory(keyPEMBlock)))
 | 
							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}
 | 
						issuingCaChainPem = []string{intCertPEM, caCertPEM}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -723,6 +834,9 @@ var (
 | 
				
			|||||||
	privRSAKeyPem      string
 | 
						privRSAKeyPem      string
 | 
				
			||||||
	csrRSAPem          string
 | 
						csrRSAPem          string
 | 
				
			||||||
	certRSAPem         string
 | 
						certRSAPem         string
 | 
				
			||||||
 | 
						privEd255198KeyPem string
 | 
				
			||||||
 | 
						csrEd25519Pem      string
 | 
				
			||||||
 | 
						certEd25519Pem     string
 | 
				
			||||||
	privECKeyPem       string
 | 
						privECKeyPem       string
 | 
				
			||||||
	csrECPem           string
 | 
						csrECPem           string
 | 
				
			||||||
	privEC8KeyPem      string
 | 
						privEC8KeyPem      string
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -164,6 +164,10 @@ func ParsePEMBundle(pemBundle string) (*ParsedCertBundle, error) {
 | 
				
			|||||||
				parsedBundle.PrivateKey = signer
 | 
									parsedBundle.PrivateKey = signer
 | 
				
			||||||
				parsedBundle.PrivateKeyType = ECPrivateKey
 | 
									parsedBundle.PrivateKeyType = ECPrivateKey
 | 
				
			||||||
				parsedBundle.PrivateKeyBytes = pemBlock.Bytes
 | 
									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 {
 | 
							} else if certificates, err := x509.ParseCertificates(pemBlock.Bytes); err == nil {
 | 
				
			||||||
			certPath = append(certPath, &CertBlock{
 | 
								certPath = append(certPath, &CertBlock{
 | 
				
			||||||
@@ -246,6 +250,16 @@ func generatePrivateKey(keyType string, keyBits int, container ParsedPrivateKeyC
 | 
				
			|||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return errutil.InternalError{Err: fmt.Sprintf("error marshalling EC private key: %v", err)}
 | 
								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:
 | 
						default:
 | 
				
			||||||
		return errutil.UserError{Err: fmt.Sprintf("unknown key type: %s", keyType)}
 | 
							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 false, nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return true, 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:
 | 
						default:
 | 
				
			||||||
		return false, fmt.Errorf("cannot compare key with type %T", key1Iface)
 | 
							return false, fmt.Errorf("cannot compare key with type %T", key1Iface)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -521,7 +544,7 @@ func ValidateKeyTypeLength(keyType string, keyBits int) error {
 | 
				
			|||||||
		default:
 | 
							default:
 | 
				
			||||||
			return fmt.Errorf("unsupported bit length for EC key: %d", keyBits)
 | 
								return fmt.Errorf("unsupported bit length for EC key: %d", keyBits)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	case "any":
 | 
						case "any", "ed25519":
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		return fmt.Errorf("unknown key type %s", keyType)
 | 
							return fmt.Errorf("unknown key type %s", keyType)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -617,6 +640,8 @@ func createCertificate(data *CreationBundle, randReader io.Reader) (*ParsedCertB
 | 
				
			|||||||
			case 512:
 | 
								case 512:
 | 
				
			||||||
				certTemplate.SignatureAlgorithm = x509.SHA512WithRSA
 | 
									certTemplate.SignatureAlgorithm = x509.SHA512WithRSA
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
							case Ed25519PrivateKey:
 | 
				
			||||||
 | 
								certTemplate.SignatureAlgorithm = x509.PureEd25519
 | 
				
			||||||
		case ECPrivateKey:
 | 
							case ECPrivateKey:
 | 
				
			||||||
			switch data.Params.SignatureBits {
 | 
								switch data.Params.SignatureBits {
 | 
				
			||||||
			case 256:
 | 
								case 256:
 | 
				
			||||||
@@ -651,6 +676,8 @@ func createCertificate(data *CreationBundle, randReader io.Reader) (*ParsedCertB
 | 
				
			|||||||
			case 512:
 | 
								case 512:
 | 
				
			||||||
				certTemplate.SignatureAlgorithm = x509.SHA512WithRSA
 | 
									certTemplate.SignatureAlgorithm = x509.SHA512WithRSA
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
							case "ed25519":
 | 
				
			||||||
 | 
								certTemplate.SignatureAlgorithm = x509.PureEd25519
 | 
				
			||||||
		case "ec":
 | 
							case "ec":
 | 
				
			||||||
			switch data.Params.SignatureBits {
 | 
								switch data.Params.SignatureBits {
 | 
				
			||||||
			case 256:
 | 
								case 256:
 | 
				
			||||||
@@ -754,6 +781,8 @@ func createCSR(data *CreationBundle, addBasicConstraints bool, randReader io.Rea
 | 
				
			|||||||
		csrTemplate.SignatureAlgorithm = x509.SHA256WithRSA
 | 
							csrTemplate.SignatureAlgorithm = x509.SHA256WithRSA
 | 
				
			||||||
	case "ec":
 | 
						case "ec":
 | 
				
			||||||
		csrTemplate.SignatureAlgorithm = x509.ECDSAWithSHA256
 | 
							csrTemplate.SignatureAlgorithm = x509.ECDSAWithSHA256
 | 
				
			||||||
 | 
						case "ed25519":
 | 
				
			||||||
 | 
							csrTemplate.SignatureAlgorithm = x509.PureEd25519
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	csr, err := x509.CreateCertificateRequest(randReader, csrTemplate, result.PrivateKey)
 | 
						csr, err := x509.CreateCertificateRequest(randReader, csrTemplate, result.PrivateKey)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,6 +12,7 @@ import (
 | 
				
			|||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
	"crypto"
 | 
						"crypto"
 | 
				
			||||||
	"crypto/ecdsa"
 | 
						"crypto/ecdsa"
 | 
				
			||||||
 | 
						"crypto/ed25519"
 | 
				
			||||||
	"crypto/rsa"
 | 
						"crypto/rsa"
 | 
				
			||||||
	"crypto/tls"
 | 
						"crypto/tls"
 | 
				
			||||||
	"crypto/x509"
 | 
						"crypto/x509"
 | 
				
			||||||
@@ -56,6 +57,7 @@ const (
 | 
				
			|||||||
	UnknownPrivateKey PrivateKeyType = ""
 | 
						UnknownPrivateKey PrivateKeyType = ""
 | 
				
			||||||
	RSAPrivateKey     PrivateKeyType = "rsa"
 | 
						RSAPrivateKey     PrivateKeyType = "rsa"
 | 
				
			||||||
	ECPrivateKey      PrivateKeyType = "ec"
 | 
						ECPrivateKey      PrivateKeyType = "ec"
 | 
				
			||||||
 | 
						Ed25519PrivateKey PrivateKeyType = "ed25519"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TLSUsage controls whether the intended usage of a *tls.Config
 | 
					// TLSUsage controls whether the intended usage of a *tls.Config
 | 
				
			||||||
@@ -185,6 +187,8 @@ func (c *CertBundle) ToParsedCertBundle() (*ParsedCertBundle, error) {
 | 
				
			|||||||
				c.PrivateKeyType = ECPrivateKey
 | 
									c.PrivateKeyType = ECPrivateKey
 | 
				
			||||||
			case RSAPrivateKey:
 | 
								case RSAPrivateKey:
 | 
				
			||||||
				c.PrivateKeyType = RSAPrivateKey
 | 
									c.PrivateKeyType = RSAPrivateKey
 | 
				
			||||||
 | 
								case Ed25519PrivateKey:
 | 
				
			||||||
 | 
									c.PrivateKeyType = Ed25519PrivateKey
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			return nil, errutil.UserError{Err: fmt.Sprintf("Unsupported key block type: %s", pemBlock.Type)}
 | 
								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)
 | 
									block.Type = string(ECBlock)
 | 
				
			||||||
			case RSAPrivateKey:
 | 
								case RSAPrivateKey:
 | 
				
			||||||
				block.Type = string(PKCS1Block)
 | 
									block.Type = string(PKCS1Block)
 | 
				
			||||||
 | 
								case Ed25519PrivateKey:
 | 
				
			||||||
 | 
									block.Type = string(PKCS8Block)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -380,7 +386,7 @@ func (p *ParsedCertBundle) getSigner() (crypto.Signer, error) {
 | 
				
			|||||||
	case PKCS8Block:
 | 
						case PKCS8Block:
 | 
				
			||||||
		if k, err := x509.ParsePKCS8PrivateKey(p.PrivateKeyBytes); err == nil {
 | 
							if k, err := x509.ParsePKCS8PrivateKey(p.PrivateKeyBytes); err == nil {
 | 
				
			||||||
			switch k := k.(type) {
 | 
								switch k := k.(type) {
 | 
				
			||||||
			case *rsa.PrivateKey, *ecdsa.PrivateKey:
 | 
								case *rsa.PrivateKey, *ecdsa.PrivateKey, ed25519.PrivateKey:
 | 
				
			||||||
				return k.(crypto.Signer), nil
 | 
									return k.(crypto.Signer), nil
 | 
				
			||||||
			default:
 | 
								default:
 | 
				
			||||||
				return nil, errutil.UserError{Err: "Found unknown private key type in pkcs#8 wrapping"}
 | 
									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
 | 
							return ECPrivateKey, nil
 | 
				
			||||||
	case *rsa.PrivateKey:
 | 
						case *rsa.PrivateKey:
 | 
				
			||||||
		return RSAPrivateKey, nil
 | 
							return RSAPrivateKey, nil
 | 
				
			||||||
 | 
						case ed25519.PrivateKey:
 | 
				
			||||||
 | 
							return Ed25519PrivateKey, nil
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		return UnknownPrivateKey, errutil.UserError{Err: "Found unknown private key type in pkcs#8 wrapping"}
 | 
							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 {
 | 
								} else if _, err := x509.ParsePKCS1PrivateKey(pemBlock.Bytes); err == nil {
 | 
				
			||||||
				result.PrivateKeyType = RSAPrivateKey
 | 
									result.PrivateKeyType = RSAPrivateKey
 | 
				
			||||||
				c.PrivateKeyType = "rsa"
 | 
									c.PrivateKeyType = "rsa"
 | 
				
			||||||
 | 
								} else if _, err := x509.ParsePKCS8PrivateKey(pemBlock.Bytes); err == nil {
 | 
				
			||||||
 | 
									result.PrivateKeyType = Ed25519PrivateKey
 | 
				
			||||||
 | 
									c.PrivateKeyType = "ed25519"
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				return nil, errutil.UserError{Err: fmt.Sprintf("Unknown private key type in bundle: %s", c.PrivateKeyType)}
 | 
									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:
 | 
							case ECPrivateKey:
 | 
				
			||||||
			result.PrivateKeyType = "ec"
 | 
								result.PrivateKeyType = "ec"
 | 
				
			||||||
			block.Type = "EC PRIVATE KEY"
 | 
								block.Type = "EC PRIVATE KEY"
 | 
				
			||||||
 | 
							case Ed25519PrivateKey:
 | 
				
			||||||
 | 
								result.PrivateKeyType = "ed25519"
 | 
				
			||||||
 | 
								block.Type = "PRIVATE KEY"
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			return nil, errutil.InternalError{Err: "Could not determine private key type when creating block"}
 | 
								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)}
 | 
								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:
 | 
						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
 | 
						return signer, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -128,7 +128,7 @@ export default Certificate.extend({
 | 
				
			|||||||
  }),
 | 
					  }),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  keyType: attr('string', {
 | 
					  keyType: attr('string', {
 | 
				
			||||||
    possibleValues: ['rsa', 'ec'],
 | 
					    possibleValues: ['rsa', 'ec','ed25519'],
 | 
				
			||||||
    defaultValue: 'rsa',
 | 
					    defaultValue: 'rsa',
 | 
				
			||||||
  }),
 | 
					  }),
 | 
				
			||||||
  keyBits: attr('number', {
 | 
					  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
 | 
					  PEM-encoded DER, depending on the value of `format`. The other option is
 | 
				
			||||||
  `pkcs8` which will return the key marshalled as PEM-encoded PKCS8.
 | 
					  `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`.
 | 
					  or `ec`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- `key_bits` `(int: 2048)` – Specifies the number of bits to use. This must be
 | 
					- `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
 | 
					  PEM-encoded DER, depending on the value of `format`. The other option is
 | 
				
			||||||
  `pkcs8` which will return the key marshalled as PEM-encoded PKCS8.
 | 
					  `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`.
 | 
					  or `ec`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- `key_bits` `(int: 2048)` – Specifies the number of bits to use. This must be
 | 
					- `key_bits` `(int: 2048)` – Specifies the number of bits to use. This must be
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user