Fix ed25519 generated SSH key marshalling (#14101)

* Ensure we can issue against generated SSH CA keys

This adds a test to ensure that we can issue leaf SSH certificates using
the newly generated SSH CA keys. Presently this fails because the
ed25519 key private is stored using PKIX's PKCS8 PrivateKey object
format rather than using OpenSSH's desired private key format:

> path_config_ca_test.go:211: bad case 12: err: failed to parse stored CA private key: ssh: invalid openssh private key format, resp: <nil>

Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>

* Add dependency on edkey for OpenSSH ed25519 keys

As mentioned in various terraform-provider-tls discussions, OpenSSH
doesn't understand the standard OpenSSL/PKIX ed25519 key structure (as
generated by PKCS8 marshalling). Instead, we need to place it into the
OpenSSH RFC 8709 format. As mentioned in this dependency's README,
support in golang.org/x/crypto/ssh is presently lacking for this.
When the associated CL is merged, we should be able to remove this dep
and rely on the (extended) standard library, however, no review progress
appears to have been made since the CL was opened by the author.

See also: https://go-review.googlesource.com/c/crypto/+/218620/

Signed-off-by: Alexander Scheel <alex.scheel@hashicorp.com>
This commit is contained in:
Alexander Scheel
2022-02-16 13:28:57 -06:00
committed by GitHub
parent 1cafeeb5d0
commit 42b90ff691
4 changed files with 43 additions and 5 deletions

View File

@@ -191,17 +191,31 @@ func createDeleteHelper(t *testing.T, b logical.Backend, config *logical.Backend
}
resp, err := b.HandleRequest(context.Background(), caReq)
if err != nil || (resp != nil && resp.IsError()) {
t.Fatalf("bad case %v: err: %v, resp:%v", index, err, resp)
t.Fatalf("bad case %v: err: %v, resp: %v", index, err, resp)
}
if !strings.Contains(resp.Data["public_key"].(string), caReq.Data["key_type"].(string)) {
t.Fatalf("bad case %v: expected public key of type %v but was %v", index, caReq.Data["key_type"], resp.Data["public_key"])
}
issueOptions := map[string]interface{}{
"public_key": testCAPublicKeyEd25519,
}
issueReq := &logical.Request{
Path: "sign/ca-issuance",
Operation: logical.UpdateOperation,
Storage: config.StorageView,
Data: issueOptions,
}
resp, err = b.HandleRequest(context.Background(), issueReq)
if err != nil || (resp != nil && resp.IsError()) {
t.Fatalf("bad case %v: err: %v, resp: %v", index, err, resp)
}
// Delete the configured keys
caReq.Operation = logical.DeleteOperation
resp, err = b.HandleRequest(context.Background(), caReq)
if err != nil || (resp != nil && resp.IsError()) {
t.Fatalf("bad case %v: err: %v, resp:%v", index, err, resp)
t.Fatalf("bad case %v: err: %v, resp: %v", index, err, resp)
}
}
@@ -235,6 +249,24 @@ func TestSSH_ConfigCAKeyTypes(t *testing.T) {
{"ed25519", 0},
}
// Create a role for ssh signing.
roleOptions := map[string]interface{}{
"allow_user_certificates": true,
"allowed_users": "*",
"key_type": "ca",
"ttl": "30s",
}
roleReq := &logical.Request{
Operation: logical.UpdateOperation,
Path: "roles/ca-issuance",
Data: roleOptions,
Storage: config.StorageView,
}
_, err = b.HandleRequest(context.Background(), roleReq)
if err != nil {
t.Fatalf("Cannot create role to issue against: %s", err)
}
for index, scenario := range cases {
createDeleteHelper(t, b, config, index, scenario.keyType, scenario.keyBits)
}