Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for sk- (hardware-backed) ed25519 keys #35

Open
anoadragon453 opened this issue Jul 11, 2023 · 5 comments
Open

Add support for sk- (hardware-backed) ed25519 keys #35

anoadragon453 opened this issue Jul 11, 2023 · 5 comments

Comments

@anoadragon453
Copy link

OpenSSH 8.2 or higher supports hardware-backed variants of ed25519 and ecdsa SSH key types, otherwise known as "secure key" (sk) variants.

I have a Yubikey and use its FIDO2 support to store a sk-ed25519 SSH key on the device. It is not (supposedly) possible to get access to the private keys of this variant, but you can access the public key of course.

I use this key to authenticate to my servers, and I'd like to use it with sops-nix as well. However, it appears that ssh-to-age does not support the -sk variant of ed25519 keys, so I get an error:

$ ssh-to-age -i ~/.ssh/id_ed25519_sk_rk.pub
ssh-to-age: failed to convert '[email protected] AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIGVdcgCRUwCd83w5L+k5yhDHrLDF88GgDWdhvMqYAUiAAAAABHNzaDo= ssh:': failed to parse ssh public key: illegal base64 data at input byte 3

which I believe is due to the check for the "ssh-" prefix here:

ssh-to-age/convert.go

Lines 99 to 103 in 3d775f6

if strings.HasPrefix(string(sshKey), "ssh-") {
pk, _, _, _, err = ssh.ParseAuthorizedKey(sshKey)
} else {
_, _, pk, _, _, err = ssh.ParseKnownHosts(sshKey)
}

If we expand it to:

	if strings.HasPrefix(string(sshKey), "ssh-") || strings.HasPrefix(string(sshKey), "sk-ssh-") {
		pk, _, _, _, err = ssh.ParseAuthorizedKey(sshKey)
	} else {
		_, _, pk, _, _, err = ssh.ParseKnownHosts(sshKey)
	}

then we predictably get:

$ ssh-to-age -i ~/.ssh/id_ed25519_sk_rk.pub  
skipped key: got [email protected] key type, but only ed25519 keys are supported

due to:

ssh-to-age/convert.go

Lines 107 to 110 in 3d775f6

// We only care about ed25519
if pk.Type() != ssh.KeyAlgoED25519 {
return nil, fmt.Errorf("got %s key type, but %w", pk.Type(), UnsupportedKeyType)
}

if we then expand that code to:

	// We only care about ed25519 (and the secure key variant)
	if pk.Type() != ssh.KeyAlgoED25519 && pk.Type() != ssh.KeyAlgoSKED25519 {
		return nil, fmt.Errorf("got %s key type, but %w", pk.Type(), UnsupportedKeyType)
	}

we then get:

$ ssh-to-age -i ~/.ssh/id_ed25519_sk_rk.pub
/nix/store/lngv3dl3yal64xripysv284781qrpxj9-ssh-to-age-1.1.1/bin/ssh-to-age: failed to convert '[email protected] AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIGVdcgCRUwCd83w5L+k5yhDHrLDF88GgDWdhvMqYAUiAAAAABHNzaDo= ssh:': BUG! public key does not implement ssh.CryptoPublicKey

which makes sense. ssh.skEd25519PublicKey does not implement ssh.CryptoPublicKey, while ssh.ed25519PublicKey does.

I'm wondering if it's still possible to get the elliptic curve points out of pk and convert it to an age key regardless? Or am I barking up the wrong tree and should go pester to go devs to implement ssh.CryptoPublicKey on ssh.skEd25519PublicKey? :)

@Mic92
Copy link
Owner

Mic92 commented Jul 12, 2023

The bigger issue here is that sops also needs to support the yubikey for encryption, which is currently not the case: getsops/sops#1103
So yes we could add the conversion here but we would still need support in sops's age implementation to make actually use of it.

@anoadragon453
Copy link
Author

I see, and apologies, I've now found #25, which I missed in an initial search of the repo, asking for the same functionality.

The bigger issue here is that sops also needs to support the yubikey for encryption

I'm confused though - the public key is entirely stored in a file on my computer (~/.ssh/id_ed25519_sk_rk.pub). The yubikey should not be required to be plugged in in order to encrypt content with that public key, is that right?

Or is the issue that the public key types don't match up? Why does the user in getsops/sops#1103 have a age1yubikey type key, rather than just an age type?

Is it an additional problem that sops doesn't engage with the yubikey (or any agent?) in order to decrypt the content?

Or alternatively to all that, do you agree with the way forward laid out in #25 (comment), and we should just use a plugin based approach with sops instead? :)

@Mic92
Copy link
Owner

Mic92 commented Jul 19, 2023

Sops cannot decrypt because it would have to reach out for the yubikey, which is not implemented. I am not sure what you mean by a plugin based approach.

@anoadragon453
Copy link
Author

Right, that part makes sense to me. Thanks for responding.

I'll wait on that front first then. Feel free to leave this issue open in the meantime or close it if you like.

@Mic92
Copy link
Owner

Mic92 commented Jul 20, 2023

I'll keep it open because otherwise someone else will just come again with the same issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants