From 4fd026f5a76af7e5ea6037c973d87e3527f7107c Mon Sep 17 00:00:00 2001 From: "Anner J. Bonilla" Date: Mon, 10 Jun 2019 12:23:27 -0400 Subject: [PATCH 01/14] update azure instructions Update instructions in regards to azure AD Authentication and OIDC --- .../docs/auth/jwt_oidc_providers.html.md | 38 +++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/website/source/docs/auth/jwt_oidc_providers.html.md b/website/source/docs/auth/jwt_oidc_providers.html.md index c45302e1ea3b5..ebd03147b70ce 100644 --- a/website/source/docs/auth/jwt_oidc_providers.html.md +++ b/website/source/docs/auth/jwt_oidc_providers.html.md @@ -20,12 +20,44 @@ Reference: [Azure Active Directory v2.0 and the OpenID Connect protocol](https:/ 1. Register or select an AAD application. Visit Overview page. 1. Configure Redirect URIs ("Web" type). -1. Record "Application (client) ID". + * you must include two redirect URIs here one for CLI access another one for web access + * http://localhost:8250/oidc/callback + * https://hostname:port_number/ui/vault/auth/oidc/oidc/callback +1. Record "Application (client) ID" you will need it as the oidc_client_id +1. Under API Permissions grant the following permission: + * Microsoft Graph API permission [Group.Read.All](https://docs.microsoft.com/en-us/graph/permissions-reference#application-permissions-10) 1. Under "Endpoints", copy the OpenID Connect metadata document URL, omitting the `/well-known...` portion. + * endpoint url (oidc_discovery_url) should look as: https://login.microsoftonline.com/tenant-guid-dead-beef-aaaa-aaaa/v2.0 1. Switch to Certificates & Secrets. Create a new client secret and record the generated value as it will not be accessible after you leave the page. -Please note [Azure AD v2.0 endpoints](https://docs.microsoft.com/en-gb/azure/active-directory/develop/azure-ad-endpoint-comparison) are required for [external groups](https://www.vaultproject.io/docs/secrets/identity/index.html#external-vs-internal-groups) to work. Further, the App Registration needs the [Group.Read.All](https://docs.microsoft.com/en-us/graph/permissions-reference#application-permissions-10) Microsoft Graph API Permission, and `groupMembershipClaims` should be changed from `none` in the [App registration manifest](https://docs.microsoft.com/en-us/azure/active-directory/develop/reference-app-manifest). In the [OIDC Role config](https://www.vaultproject.io/api/auth/jwt/index.html#create-role) the scope `"https://graph.microsoft.com/.default"` should be added to add groups to the jwt token and `groups_claim` should be set to `groups`. Finally Azure AD group can be referenced by using the groups `objectId` as the [group alias name](https://www.vaultproject.io/api/secret/identity/group-alias.html) for the external group. +Please note [Azure AD v2.0 endpoints](https://docs.microsoft.com/en-gb/azure/active-directory/develop/azure-ad-endpoint-comparison) are required for [external groups](https://www.vaultproject.io/docs/secrets/identity/index.html#external-vs-internal-groups) to work. +* `groupMembershipClaims` should be changed from `none` in the [App registration manifest](https://docs.microsoft.com/en-us/azure/active-directory/develop/reference-app-manifest). Options are "All" or "Security" + +* In the [OIDC Role config](https://www.vaultproject.io/api/auth/jwt/index.html#create-role) the scope `"https://graph.microsoft.com/.default"` should be added to add groups to the jwt token and `groups_claim` should be set to `groups`. + +* Finally Azure AD group can be referenced by using the groups `objectId` as the [group alias name](https://www.vaultproject.io/api/secret/identity/group-alias.html) for the external group. +### CLI setup instructions: +You have to fill in the following values make sure to use the correct vault secret patch that matches the name of the authentication method such as /oidc/ + * oidc_client_id = Application Client ID + * oidc_client_secret = Secret obtained from the Certificates & Secrets Section + * default_role = default role the user will be using when connecting. (see the second command) + * oidc_discovery_url = Open ID endpoint retrieved from the App Registration wections. +``` + vault write auth/oidc/config \ + oidc_client_id="your_client_id" \ + oidc_client_secret="your_client_secret" \ + default_role=“your_default_role” \ + oidc_discovery_url="https://login.microsoftonline.com/tenant_id/v2.0” + +``` + +``` +vault write auth/oidc/role/demo user_claim="email" \ +allowed_redirect_uris="http://localhost:8250/oidc/callback,https://online_version_hostname:port_number/ui/vault/auth/oidc/oidc/callback" \ +groups_claim="groups" \ +policies=default +``` ## Auth0 1. Select Create Application (Regular Web App). @@ -66,4 +98,4 @@ Main reference: [Using OAuth 2.0 to Access Google APIs](https://developers.googl 1. Configure Login redirect URIs. Save. 1. Save client ID and secret. -Note your policy will need `oidc_scopes` to include `profile` to get a full profile ("[Fat Token](https://support.okta.com/help/s/article/Okta-Groups-or-Attribute-Missing-from-Id-Token)"). You will also need to configure bound audience along the lines of `"bound_audiences": ["api://default", "0a4........."]` if you are using the default authorization server. \ No newline at end of file +Note your policy will need `oidc_scopes` to include `profile` to get a full profile ("[Fat Token](https://support.okta.com/help/s/article/Okta-Groups-or-Attribute-Missing-from-Id-Token)"). You will also need to configure bound audience along the lines of `"bound_audiences": ["api://default", "0a4........."]` if you are using the default authorization server. From fdc72bc32bedc94dda8d18107a871f5acab09bfa Mon Sep 17 00:00:00 2001 From: "Anner J. Bonilla" Date: Mon, 7 Jun 2021 08:57:06 -0400 Subject: [PATCH 02/14] Initial pass of ed25519 --- builtin/logical/pki/fields.go | 2 +- builtin/logical/pki/path_roles.go | 2 +- sdk/helper/certutil/helpers.go | 7 +++++++ sdk/helper/certutil/types.go | 1 + website/content/api-docs/secret/pki.mdx | 4 ++-- 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/builtin/logical/pki/fields.go b/builtin/logical/pki/fields.go index c67e39eaac20b..8f0d897ad00e5 100644 --- a/builtin/logical/pki/fields.go +++ b/builtin/logical/pki/fields.go @@ -259,7 +259,7 @@ the key_type.`, Default: "rsa", Description: `The type of key to use; defaults to RSA. "rsa" and "ec" are the only valid values.`, - AllowedValues: []interface{}{"rsa", "ec"}, + AllowedValues: []interface{}{"rsa", "ec","ed25519"}, DisplayAttrs: &framework.DisplayAttributes{ Value: "rsa", }, diff --git a/builtin/logical/pki/path_roles.go b/builtin/logical/pki/path_roles.go index 000d95e5c84be..ebd68adf0bbb9 100644 --- a/builtin/logical/pki/path_roles.go +++ b/builtin/logical/pki/path_roles.go @@ -194,7 +194,7 @@ protection use. Defaults to false.`, Default: "rsa", Description: `The type of key to use; defaults to RSA. "rsa" and "ec" are the only valid values.`, - AllowedValues: []interface{}{"rsa", "ec"}, + AllowedValues: []interface{}{"rsa", "ec","ed25519"}, }, "key_bits": { diff --git a/sdk/helper/certutil/helpers.go b/sdk/helper/certutil/helpers.go index c23cca994c089..416f830be089e 100644 --- a/sdk/helper/certutil/helpers.go +++ b/sdk/helper/certutil/helpers.go @@ -246,6 +246,13 @@ 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 = x509.MarshalPkcs1PrivateKey(privateKey.(ed25519.PrivateKey)) default: return errutil.UserError{Err: fmt.Sprintf("unknown key type: %s", keyType)} } diff --git a/sdk/helper/certutil/types.go b/sdk/helper/certutil/types.go index 8a1a1d5fa9290..d12a23e571a8a 100644 --- a/sdk/helper/certutil/types.go +++ b/sdk/helper/certutil/types.go @@ -56,6 +56,7 @@ const ( UnknownPrivateKey PrivateKeyType = "" RSAPrivateKey PrivateKeyType = "rsa" ECPrivateKey PrivateKeyType = "ec" + Ed25519PrivateKey PrivateKeyType = "ed25519" ) // TLSUsage controls whether the intended usage of a *tls.Config diff --git a/website/content/api-docs/secret/pki.mdx b/website/content/api-docs/secret/pki.mdx index d5a3921d6b5d3..e3d19a3b21058 100644 --- a/website/content/api-docs/secret/pki.mdx +++ b/website/content/api-docs/secret/pki.mdx @@ -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 From a58ce66f3374121f83397ecd8b40c8c787fdc2e8 Mon Sep 17 00:00:00 2001 From: "Anner J. Bonilla" Date: Thu, 17 Jun 2021 18:55:51 -0400 Subject: [PATCH 03/14] Fix typos on marshal function --- sdk/helper/certutil/helpers.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sdk/helper/certutil/helpers.go b/sdk/helper/certutil/helpers.go index 416f830be089e..9d77ff438be8a 100644 --- a/sdk/helper/certutil/helpers.go +++ b/sdk/helper/certutil/helpers.go @@ -248,11 +248,14 @@ func generatePrivateKey(keyType string, keyBits int, container ParsedPrivateKeyC } case "ed25519": privateKeyType = Ed25519PrivateKey - privateKey, err = ed25519.GenerateKey(randReader) + _, privateKey, err = ed25519.GenerateKey(randReader) if err != nil { - return errutil.InternalError{Err: fmt.Sprintf("error generating ed25519 private key: %v",err)} + 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)} } - privateKeyBytes = x509.MarshalPkcs1PrivateKey(privateKey.(ed25519.PrivateKey)) default: return errutil.UserError{Err: fmt.Sprintf("unknown key type: %s", keyType)} } From 4900ea20a1f06482867fa72316eb4ad1776c4bf9 Mon Sep 17 00:00:00 2001 From: "Anner J. Bonilla" Date: Thu, 17 Jun 2021 20:06:16 -0400 Subject: [PATCH 04/14] test wip --- builtin/logical/pki/backend_test.go | 2 ++ builtin/logical/pki/fields.go | 4 ++-- builtin/logical/pki/path_roles.go | 4 ++-- sdk/helper/certutil/certutil_test.go | 28 ++++++++++++++++++---------- sdk/helper/certutil/helpers.go | 8 ++++++++ 5 files changed, 32 insertions(+), 14 deletions(-) diff --git a/builtin/logical/pki/backend_test.go b/builtin/logical/pki/backend_test.go index a4329633ebdb5..f78acafe01152 100644 --- a/builtin/logical/pki/backend_test.go +++ b/builtin/logical/pki/backend_test.go @@ -318,6 +318,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": diff --git a/builtin/logical/pki/fields.go b/builtin/logical/pki/fields.go index 8f0d897ad00e5..0b8d808765e17 100644 --- a/builtin/logical/pki/fields.go +++ b/builtin/logical/pki/fields.go @@ -258,8 +258,8 @@ the key_type.`, 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","ed25519"}, +"ec" and "ed25519" are the only valid values.`, + AllowedValues: []interface{}{"rsa", "ec", "ed25519"}, DisplayAttrs: &framework.DisplayAttributes{ Value: "rsa", }, diff --git a/builtin/logical/pki/path_roles.go b/builtin/logical/pki/path_roles.go index ebd68adf0bbb9..5d56bb0452b01 100644 --- a/builtin/logical/pki/path_roles.go +++ b/builtin/logical/pki/path_roles.go @@ -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","ed25519"}, +"ec" and "ed25519" are the only valid values.`, + AllowedValues: []interface{}{"rsa", "ec", "ed25519"}, }, "key_bits": { diff --git a/sdk/helper/certutil/certutil_test.go b/sdk/helper/certutil/certutil_test.go index b428372141258..419fbf145ff7e 100644 --- a/sdk/helper/certutil/certutil_test.go +++ b/sdk/helper/certutil/certutil_test.go @@ -325,6 +325,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 != privEd25519KeyPem { + return fmt.Errorf("bundle ec private key does not match") + } default: return fmt.Errorf("bundle has unknown private key type") } @@ -718,14 +725,15 @@ func setCerts() { } 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 + privECKeyPem string + privEd255119KeyPem string + csrECPem string + privEC8KeyPem string + certECPem string + issuingCaChainPem []string ) diff --git a/sdk/helper/certutil/helpers.go b/sdk/helper/certutil/helpers.go index 9d77ff438be8a..328b2090885a9 100644 --- a/sdk/helper/certutil/helpers.go +++ b/sdk/helper/certutil/helpers.go @@ -520,6 +520,8 @@ func ValidateKeyTypeLength(keyType string, keyBits int) error { default: return fmt.Errorf("unsupported bit length for EC key: %d", keyBits) } + case "ed25519": + return nil case "any": default: return fmt.Errorf("unknown key type %s", keyType) @@ -611,6 +613,8 @@ func createCertificate(data *CreationBundle, randReader io.Reader) (*ParsedCertB certTemplate.SignatureAlgorithm = x509.SHA256WithRSA case ECPrivateKey: certTemplate.SignatureAlgorithm = x509.ECDSAWithSHA256 + case ED25519: + certTemplate.SignatureAlgorithm = x509.Ed25519 } caCert := data.SigningBundle.Certificate @@ -631,6 +635,8 @@ func createCertificate(data *CreationBundle, randReader io.Reader) (*ParsedCertB certTemplate.SignatureAlgorithm = x509.SHA256WithRSA case "ec": certTemplate.SignatureAlgorithm = x509.ECDSAWithSHA256 + case "ed25519": + certTemplate.SignatureAlgorithm = x509.PureEd25519 } certTemplate.AuthorityKeyId = subjKeyID @@ -725,6 +731,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) From 06b3d680c49ebba4698ecaf3aedc840d2ee710fa Mon Sep 17 00:00:00 2001 From: "Anner J. Bonilla" Date: Thu, 17 Jun 2021 21:08:28 -0400 Subject: [PATCH 05/14] typo --- sdk/helper/certutil/helpers.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/helper/certutil/helpers.go b/sdk/helper/certutil/helpers.go index 328b2090885a9..003f55fe9a2a4 100644 --- a/sdk/helper/certutil/helpers.go +++ b/sdk/helper/certutil/helpers.go @@ -613,8 +613,8 @@ func createCertificate(data *CreationBundle, randReader io.Reader) (*ParsedCertB certTemplate.SignatureAlgorithm = x509.SHA256WithRSA case ECPrivateKey: certTemplate.SignatureAlgorithm = x509.ECDSAWithSHA256 - case ED25519: - certTemplate.SignatureAlgorithm = x509.Ed25519 + case Ed25519PrivateKey: + certTemplate.SignatureAlgorithm = x509.PureEd25519 } caCert := data.SigningBundle.Certificate From 8a8cd36d5e99288f236fcc326f04b9f92c54761f Mon Sep 17 00:00:00 2001 From: "Anner J. Bonilla" Date: Thu, 17 Jun 2021 23:42:35 -0400 Subject: [PATCH 06/14] fix tests --- builtin/logical/pki/backend_test.go | 51 ++++++++++++++++++++- builtin/logical/pki/ca_test.go | 66 +++++++++++++++++++++++++++- builtin/logical/pki/cert_util.go | 13 ++++++ sdk/helper/certutil/certutil_test.go | 21 ++++++++- sdk/helper/certutil/helpers.go | 15 ++++++- sdk/helper/certutil/types.go | 21 ++++++++- ui/app/models/pki-ca-certificate.js | 2 +- 7 files changed, 182 insertions(+), 7 deletions(-) diff --git a/builtin/logical/pki/backend_test.go b/builtin/logical/pki/backend_test.go index f78acafe01152..daabab6b7b729 100644 --- a/builtin/logical/pki/backend_test.go +++ b/builtin/logical/pki/backend_test.go @@ -5,6 +5,7 @@ import ( "context" "crypto" "crypto/ecdsa" + "crypto/ed25519" "crypto/elliptic" "crypto/rand" "crypto/rsa" @@ -205,6 +206,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 { @@ -303,6 +306,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) + } } } @@ -702,7 +712,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 @@ -1012,6 +1022,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) } @@ -2924,6 +2941,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) { @@ -3107,4 +3154,6 @@ var ( rsaCACert string ecCAKey string ecCACert string + edCAKey string + edCACert string ) diff --git a/builtin/logical/pki/ca_test.go b/builtin/logical/pki/ca_test.go index 9d4e6b6c0b363..f4c4d12ea05fc 100644 --- a/builtin/logical/pki/ca_test.go +++ b/builtin/logical/pki/ca_test.go @@ -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) + }) }) } diff --git a/builtin/logical/pki/cert_util.go b/builtin/logical/pki/cert_util.go index 9a944dc1aa79a..a7e6e07c73d04 100644 --- a/builtin/logical/pki/cert_util.go +++ b/builtin/logical/pki/cert_util.go @@ -4,6 +4,7 @@ import ( "context" "crypto" "crypto/ecdsa" + "crypto/ed25519" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" @@ -593,6 +594,18 @@ func signCert(b *backend, pubKey.Params().BitSize)} } + case "ed25519": + // Verify that the key matches the role type + if csr.PublicKeyAlgorithm != x509.PublicKeyAlgorithm(x509.PureEd25519) { + 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 diff --git a/sdk/helper/certutil/certutil_test.go b/sdk/helper/certutil/certutil_test.go index 419fbf145ff7e..f3b2af39a61d1 100644 --- a/sdk/helper/certutil/certutil_test.go +++ b/sdk/helper/certutil/certutil_test.go @@ -179,6 +179,14 @@ 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 privEd25519KeyPem: + if pcbut.PrivateKeyType != Ed25519PrivateKey { + return fmt.Errorf("parsed bundle has wrong 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 'ec' (%v)", pcbut.PrivateKeyType, ECPrivateKey) + } default: return fmt.Errorf("parsed bundle has unknown private key type") } @@ -221,6 +229,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 != privEd25519KeyPem && cb.PrivateKey != privEC8KeyPem { + return fmt.Errorf("bundle private key does not match") + } default: return fmt.Errorf("certBundle has unknown private key type") } @@ -294,6 +306,10 @@ func compareCSRBundleToParsedCSRBundle(csrbut *CSRBundle, pcsrbut *ParsedCSRBund if pcsrbut.PrivateKeyType != ECPrivateKey { return fmt.Errorf("parsed bundle has wrong private key type") } + case privEd25519KeyPem: + 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") } @@ -730,8 +746,11 @@ var ( privRSAKeyPem string csrRSAPem string certRSAPem string + privEd255198KeyPem string + privEd25519KeyPem string + csrEd25519Pem string + certEd25519Pem string privECKeyPem string - privEd255119KeyPem string csrECPem string privEC8KeyPem string certECPem string diff --git a/sdk/helper/certutil/helpers.go b/sdk/helper/certutil/helpers.go index 003f55fe9a2a4..f704361cd22a3 100644 --- a/sdk/helper/certutil/helpers.go +++ b/sdk/helper/certutil/helpers.go @@ -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{ @@ -319,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) } diff --git a/sdk/helper/certutil/types.go b/sdk/helper/certutil/types.go index d12a23e571a8a..2f29188218cbe 100644 --- a/sdk/helper/certutil/types.go +++ b/sdk/helper/certutil/types.go @@ -12,6 +12,7 @@ import ( "bytes" "crypto" "crypto/ecdsa" + "crypto/ed25519" "crypto/rsa" "crypto/tls" "crypto/x509" @@ -186,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)} @@ -291,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) } } @@ -381,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"} @@ -412,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"} } @@ -444,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)} } @@ -492,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"} } @@ -526,6 +539,12 @@ 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: + // signer, err = x509.ParsePKCS8PrivateKey(p.PrivateKeyBytes) + // 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"} } diff --git a/ui/app/models/pki-ca-certificate.js b/ui/app/models/pki-ca-certificate.js index 255df6f02c2ce..ab10e335df1a4 100644 --- a/ui/app/models/pki-ca-certificate.js +++ b/ui/app/models/pki-ca-certificate.js @@ -123,7 +123,7 @@ export default Certificate.extend({ }), keyType: attr('string', { - possibleValues: ['rsa', 'ec'], + possibleValues: ['rsa', 'ec','ed25519'], defaultValue: 'rsa', }), keyBits: attr('number', { From 0e989f297a986ca053b74fe8aa6f268529c3e0bb Mon Sep 17 00:00:00 2001 From: "Anner J. Bonilla" Date: Thu, 17 Jun 2021 23:59:24 -0400 Subject: [PATCH 07/14] missef changelog --- changelog/11780.txt | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changelog/11780.txt diff --git a/changelog/11780.txt b/changelog/11780.txt new file mode 100644 index 0000000000000..2a33abb32bb78 --- /dev/null +++ b/changelog/11780.txt @@ -0,0 +1,5 @@ +```` +```release-note:feature +pki: Support ed25519 as a key for the pki backend +``` +```` \ No newline at end of file From 1aeccbe0481080726f380ea633b51926e2f82c53 Mon Sep 17 00:00:00 2001 From: "Anner J. Bonilla" Date: Sat, 19 Jun 2021 19:59:54 -0400 Subject: [PATCH 08/14] fix mismatch between signature and algo --- builtin/logical/pki/cert_util.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/logical/pki/cert_util.go b/builtin/logical/pki/cert_util.go index a7e6e07c73d04..aacd695e0e600 100644 --- a/builtin/logical/pki/cert_util.go +++ b/builtin/logical/pki/cert_util.go @@ -596,7 +596,7 @@ func signCert(b *backend, case "ed25519": // Verify that the key matches the role type - if csr.PublicKeyAlgorithm != x509.PublicKeyAlgorithm(x509.PureEd25519) { + if csr.PublicKeyAlgorithm != x509.PublicKeyAlgorithm(x509.Ed25519) { return nil, errutil.UserError{Err: fmt.Sprintf( "role requires keys of type %s", data.role.KeyType)} From 4e962237d6f400758969b21428ec9e2beffe5418 Mon Sep 17 00:00:00 2001 From: "Anner J. Bonilla" Date: Sun, 27 Jun 2021 17:29:48 -0400 Subject: [PATCH 09/14] added test coverage for ed25519 --- changelog/11780.txt | 8 ++--- sdk/helper/certutil/certutil_test.go | 53 +++++++++++++++++++++++++--- 2 files changed, 52 insertions(+), 9 deletions(-) diff --git a/changelog/11780.txt b/changelog/11780.txt index 2a33abb32bb78..e424054af57de 100644 --- a/changelog/11780.txt +++ b/changelog/11780.txt @@ -1,5 +1,3 @@ -```` -```release-note:feature -pki: Support ed25519 as a key for the pki backend -``` -```` \ No newline at end of file +```release-note:feature +pki: Support ed25519 as a key for the pki backend +``` diff --git a/sdk/helper/certutil/certutil_test.go b/sdk/helper/certutil/certutil_test.go index f3b2af39a61d1..392d6b9ab60ad 100644 --- a/sdk/helper/certutil/certutil_test.go +++ b/sdk/helper/certutil/certutil_test.go @@ -36,6 +36,10 @@ func TestCertBundleConversion(t *testing.T) { refreshECCertBundleWithChain(), refreshEC8CertBundle(), refreshEC8CertBundleWithChain(), + refreshEd25519CertBundle(), + refreshEd25519CertBundleWithChain(), + refreshEd255198CertBundle(), + refreshEd255198CertBundleWithChain(), } for i, cbut := range cbuts { @@ -181,11 +185,11 @@ func compareCertBundleToParsedCertBundle(cbut *CertBundle, pcbut *ParsedCertBund } case privEd25519KeyPem: if pcbut.PrivateKeyType != Ed25519PrivateKey { - return fmt.Errorf("parsed bundle has wrong private key type: %v, should be 'ec' (%v)", pcbut.PrivateKeyType, ECPrivateKey) + return fmt.Errorf("parsed bundle has wrong private key type: %v, should be 'ed25519' (%v)", pcbut.PrivateKeyType, ECPrivateKey) } case privEd255198KeyPem: if pcbut.PrivateKeyType != Ed25519PrivateKey { - 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 'ed25519' (%v)", pcbut.PrivateKeyType, ECPrivateKey) } default: return fmt.Errorf("parsed bundle has unknown private key type") @@ -230,7 +234,7 @@ func compareCertBundleToParsedCertBundle(cbut *CertBundle, pcbut *ParsedCertBund return fmt.Errorf("bundle private key does not match") } case Ed25519PrivateKey: - if cb.PrivateKey != privEd25519KeyPem && cb.PrivateKey != privEC8KeyPem { + if cb.PrivateKey != privEd25519KeyPem && cb.PrivateKey != privEd255198KeyPem { return fmt.Errorf("bundle private key does not match") } default: @@ -257,6 +261,7 @@ func TestCSRBundleConversion(t *testing.T) { csrbuts := []*CSRBundle{ refreshRSACSRBundle(), refreshECCSRBundle(), + refreshEd25519CSRBundle(), } for _, csrbut := range csrbuts { @@ -346,7 +351,7 @@ func compareCSRBundleToParsedCSRBundle(csrbut *CSRBundle, pcsrbut *ParsedCSRBund return fmt.Errorf("bundle has wrong private key type") } if csrb.PrivateKey != privEd25519KeyPem { - return fmt.Errorf("bundle ec private key does not match") + return fmt.Errorf("bundle ed25519 private key does not match") } default: return fmt.Errorf("bundle has unknown private key type") @@ -499,6 +504,46 @@ func refreshECCertBundleWithChain() *CertBundle { return ret } +func refreshEd25519CertBundle() *CertBundle { + initTest.Do(setCerts) + return &CertBundle{ + Certificate: certEd25519Pem, + PrivateKey: privEd25519KeyPem, + CAChain: []string{issuingCaChainPem[0]}, + } +} + +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 refreshEd25519CertBundleWithChain() *CertBundle { + initTest.Do(setCerts) + ret := refreshEd25519CertBundle() + ret.CAChain = issuingCaChainPem + return ret +} + +func refreshEd25519CSRBundle() *CSRBundle { + initTest.Do(setCerts) + return &CSRBundle{ + CSR: csrEd25519Pem, + PrivateKey: privEd25519KeyPem, + } +} + func refreshRSACSRBundle() *CSRBundle { initTest.Do(setCerts) return &CSRBundle{ From d3d17e4719cbc44ea20f4a13280ea15eb5344896 Mon Sep 17 00:00:00 2001 From: "Anner J. Bonilla" Date: Sun, 27 Jun 2021 22:09:59 -0400 Subject: [PATCH 10/14] remove pkcs1 since does not exist for ed25519 --- sdk/helper/certutil/certutil_test.go | 103 ++++++++++++++++++++------- 1 file changed, 77 insertions(+), 26 deletions(-) diff --git a/sdk/helper/certutil/certutil_test.go b/sdk/helper/certutil/certutil_test.go index 392d6b9ab60ad..c2cd0ec5c7680 100644 --- a/sdk/helper/certutil/certutil_test.go +++ b/sdk/helper/certutil/certutil_test.go @@ -3,6 +3,7 @@ package certutil import ( "bytes" "crypto/ecdsa" + "crypto/ed25519" "crypto/elliptic" "crypto/rand" "crypto/rsa" @@ -36,8 +37,6 @@ func TestCertBundleConversion(t *testing.T) { refreshECCertBundleWithChain(), refreshEC8CertBundle(), refreshEC8CertBundleWithChain(), - refreshEd25519CertBundle(), - refreshEd25519CertBundleWithChain(), refreshEd255198CertBundle(), refreshEd255198CertBundleWithChain(), } @@ -79,6 +78,8 @@ func BenchmarkCertBundleParsing(b *testing.B) { refreshECCertBundleWithChain(), refreshEC8CertBundle(), refreshEC8CertBundleWithChain(), + refreshEd255198CertBundle(), + refreshEd255198CertBundleWithChain(), } for i, cbut := range cbuts { @@ -107,6 +108,8 @@ func TestCertBundleParsing(t *testing.T) { refreshECCertBundleWithChain(), refreshEC8CertBundle(), refreshEC8CertBundleWithChain(), + refreshEd255198CertBundle(), + refreshEd255198CertBundleWithChain(), } for i, cbut := range cbuts { @@ -183,10 +186,6 @@ 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 privEd25519KeyPem: - if pcbut.PrivateKeyType != Ed25519PrivateKey { - return fmt.Errorf("parsed bundle has wrong private key type: %v, should be 'ed25519' (%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) @@ -234,7 +233,7 @@ func compareCertBundleToParsedCertBundle(cbut *CertBundle, pcbut *ParsedCertBund return fmt.Errorf("bundle private key does not match") } case Ed25519PrivateKey: - if cb.PrivateKey != privEd25519KeyPem && cb.PrivateKey != privEd255198KeyPem { + if cb.PrivateKey != privEd255198KeyPem { return fmt.Errorf("bundle private key does not match") } default: @@ -311,7 +310,7 @@ func compareCSRBundleToParsedCSRBundle(csrbut *CSRBundle, pcsrbut *ParsedCSRBund if pcsrbut.PrivateKeyType != ECPrivateKey { return fmt.Errorf("parsed bundle has wrong private key type") } - case privEd25519KeyPem: + case privEd255198KeyPem: if pcsrbut.PrivateKeyType != Ed25519PrivateKey { return fmt.Errorf("parsed bundle has wrong private key type") } @@ -350,7 +349,7 @@ func compareCSRBundleToParsedCSRBundle(csrbut *CSRBundle, pcsrbut *ParsedCSRBund if pcsrbut.PrivateKeyType != Ed25519PrivateKey { return fmt.Errorf("bundle has wrong private key type") } - if csrb.PrivateKey != privEd25519KeyPem { + if csrb.PrivateKey != privEd255198KeyPem { return fmt.Errorf("bundle ed25519 private key does not match") } default: @@ -504,14 +503,14 @@ func refreshECCertBundleWithChain() *CertBundle { return ret } -func refreshEd25519CertBundle() *CertBundle { - initTest.Do(setCerts) - return &CertBundle{ - Certificate: certEd25519Pem, - PrivateKey: privEd25519KeyPem, - CAChain: []string{issuingCaChainPem[0]}, - } -} +// func refreshEd25519CertBundle() *CertBundle { +// initTest.Do(setCerts) +// return &CertBundle{ +// Certificate: certEd25519Pem, +// PrivateKey: privEd25519KeyPem, +// CAChain: []string{issuingCaChainPem[0]}, +// } +// } func refreshEd255198CertBundle() *CertBundle { initTest.Do(setCerts) @@ -529,18 +528,11 @@ func refreshEd255198CertBundleWithChain() *CertBundle { return ret } -func refreshEd25519CertBundleWithChain() *CertBundle { - initTest.Do(setCerts) - ret := refreshEd25519CertBundle() - ret.CAChain = issuingCaChainPem - return ret -} - func refreshEd25519CSRBundle() *CSRBundle { initTest.Do(setCerts) return &CSRBundle{ CSR: csrEd25519Pem, - PrivateKey: privEd25519KeyPem, + PrivateKey: privEd255198KeyPem, } } @@ -782,6 +774,66 @@ 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} } @@ -792,7 +844,6 @@ var ( csrRSAPem string certRSAPem string privEd255198KeyPem string - privEd25519KeyPem string csrEd25519Pem string certEd25519Pem string privECKeyPem string From 487e824e636b5788849a02fd0a11ae4f51f568d2 Mon Sep 17 00:00:00 2001 From: "Anner J. Bonilla" Date: Fri, 1 Oct 2021 12:27:36 -0400 Subject: [PATCH 11/14] add ed25519 support to getsigner --- sdk/helper/certutil/types.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/sdk/helper/certutil/types.go b/sdk/helper/certutil/types.go index 2f29188218cbe..cc7205f36d874 100644 --- a/sdk/helper/certutil/types.go +++ b/sdk/helper/certutil/types.go @@ -539,14 +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: - // signer, err = x509.ParsePKCS8PrivateKey(p.PrivateKeyBytes) - // if err != nil { - // return nil, errutil.UserError{Err: fmt.Sprintf("Unable to parse CA's private Ed25519 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 } From 088a8b6b355263bdca09418d895d445073105465 Mon Sep 17 00:00:00 2001 From: "Anner J. Bonilla" Date: Fri, 1 Oct 2021 14:20:03 -0400 Subject: [PATCH 12/14] pull request feedback Signed-off-by: Anner J. Bonilla --- sdk/helper/certutil/certutil_test.go | 9 --------- sdk/helper/certutil/helpers.go | 4 +--- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/sdk/helper/certutil/certutil_test.go b/sdk/helper/certutil/certutil_test.go index c2cd0ec5c7680..cedb48fec3c29 100644 --- a/sdk/helper/certutil/certutil_test.go +++ b/sdk/helper/certutil/certutil_test.go @@ -503,15 +503,6 @@ func refreshECCertBundleWithChain() *CertBundle { return ret } -// func refreshEd25519CertBundle() *CertBundle { -// initTest.Do(setCerts) -// return &CertBundle{ -// Certificate: certEd25519Pem, -// PrivateKey: privEd25519KeyPem, -// CAChain: []string{issuingCaChainPem[0]}, -// } -// } - func refreshEd255198CertBundle() *CertBundle { initTest.Do(setCerts) return &CertBundle{ diff --git a/sdk/helper/certutil/helpers.go b/sdk/helper/certutil/helpers.go index 547771950b6b5..8f0b57f32d03c 100644 --- a/sdk/helper/certutil/helpers.go +++ b/sdk/helper/certutil/helpers.go @@ -544,9 +544,7 @@ func ValidateKeyTypeLength(keyType string, keyBits int) error { default: return fmt.Errorf("unsupported bit length for EC key: %d", keyBits) } - case "ed25519": - return nil - case "any": + case "any", "ed25519": default: return fmt.Errorf("unknown key type %s", keyType) } From 16e62d9e9a7cfd9b5077fb4193b208985fb8f912 Mon Sep 17 00:00:00 2001 From: "Anner J. Bonilla" Date: Fri, 1 Oct 2021 14:34:06 -0400 Subject: [PATCH 13/14] typo on key Signed-off-by: Anner J. Bonilla --- sdk/helper/certutil/helpers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/helper/certutil/helpers.go b/sdk/helper/certutil/helpers.go index 8f0b57f32d03c..a88e39723002d 100644 --- a/sdk/helper/certutil/helpers.go +++ b/sdk/helper/certutil/helpers.go @@ -642,7 +642,7 @@ func createCertificate(data *CreationBundle, randReader io.Reader) (*ParsedCertB } case Ed25519PrivateKey: certTemplate.SignatureAlgorithm = x509.PureEd25519 - case EcPrivateKey: + case ECPrivateKey: switch data.Params.SignatureBits { case 256: certTemplate.SignatureAlgorithm = x509.ECDSAWithSHA256 From d40189b3440fca8c8b860f67ceaaa24029ca8fa9 Mon Sep 17 00:00:00 2001 From: "Anner J. Bonilla" Date: Sat, 2 Oct 2021 03:43:57 +0000 Subject: [PATCH 14/14] cast mistake Signed-off-by: Anner J. Bonilla --- sdk/helper/certutil/types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/helper/certutil/types.go b/sdk/helper/certutil/types.go index b2f554bffaa1f..a557b5d73db5e 100644 --- a/sdk/helper/certutil/types.go +++ b/sdk/helper/certutil/types.go @@ -541,7 +541,7 @@ func (p *ParsedCSRBundle) getSigner() (crypto.Signer, error) { case Ed25519PrivateKey: signerd, err := x509.ParsePKCS8PrivateKey(p.PrivateKeyBytes) - signer = signerd.(*ed25519.PrivateKey) + signer = signerd.(ed25519.PrivateKey) if err != nil { return nil, errutil.UserError{Err: fmt.Sprintf("Unable to parse CA's private Ed25519 key: %s", err)} }