Closed unreality closed 2 years ago
@unreality hey, thanks for the suggestion! Secretive is mostly about providing easy access to keys backed by secure hardware (ie, the SEP on Macs with Touch ID and security keys, like YubiKeys) – I'm not sure there's a ton of value-add for just accessing certs that already live on disk (unless I'm misunderstanding this request).
I feel like you may have misunderstood what happens with the certificates?
The key is still backed by hardware crypto (SmartCard, secure enclave, etc), but using certificates allows an org to issue credentials that dont require installing public-keys on machines. The authentication flow requires both the certificate and the private key in order to proceed. Check out https://smallstep.com/blog/use-ssh-certificates/ for some details on how it all works.
The additional functionality would be to somehow attach a certificate (or certificates) to a private key, and to support the agent signing requests using those certificates.
Sounds like I might've ;) Lemme read up on it.
Just after reading a bit about it I'm not 100% sure this will be feasible – the SEP doesn't allow import or export of private keys, which my initial reading of this (again, could be wrong here) suggests would be required. This flow probbbbbbably would work with a YubiKey though?
Import or export of private keys isn't required, as long as a public key can be exported. The CA is sent the public key and will send back a signed certificate which includes the public key the cert is valid for.
When authenticating the ssh client presents the certificate. The SSH server checks the validity of the certificate, then asks the connecting client to sign a request using the private key that corresponds to the public key in the cert. If the connecting client returns a valid signature, the connection is allowed.
Having a look at some other agent implementations, it seems that the way this is implemented is essentially 'if a certificate is available, use that instead of the public key.' (https://github.com/golang/crypto/blob/ae814b36b87190c757eede9bc2d32ed77df88551/ssh/agent/keyring.go#L146)
Thanks for the great app.
I think adding support for certificates is feasible: it doesn't matter where the private key is stored.
First I would like to explain a bit on how SSH certificates work.
In the world without SSH certificates, the server trusts the key directly (i.e., the key is put in authorized_keys
).
When logging in, the client offers a list of keys it has, and the server accepts the one that is trusted.
Finally the client signs a message passed by the server to show that it holds the private key.
When SSH certificate come into play, the trust is built in two steps:
authorized_keys
starting like cert-authority <pub_key>
where <pub_key>
is the public key of the CA, see https://man7.org/linux/man-pages/man8/sshd.8.html#AUTHORIZED_KEYS_FILE_FORMAT).ecdsa-sha2-nistp256
key is ecdsa-sha2-nistp256-cert-v01@openssh.com
.In this case, when logging in, instead of presenting the keys directly, the client presents the certificates to the server. The server then accepts the certificate that is issued (i.e., signed) by the trusted CA.
Why the current version of Secretive does not work with certificates? Because the SSH agent returns only the public key instead of the certificate.
Why it doesn't matter where the private key is stored? Because the creation of the certificate does not require the private key. What the CA signs is the public key.
What need to be implemented in order to support certificates? We can add an option to allow users to attach a certificate to a key (it is a string in a format like a public key but longer). Then the SSH agent returns the certificate if available, and fallback to the public key otherwise. I don't think we need to consider the creation of the certificate for now.
Other information that may be useful:
Thank you again for the great app. I would like to help if you plan to support this feature (but I don't have enough knowledge of how the source code is organized).
As a workaround, it's possible to use certificates with Secretive already, by either putting the certificate file in ~/.ssh
with a filename that OpenSSH looks for by default (such as id_ecdsa-cert.pub
), or by putting the file anywhere and adding a CertificateFile
line in .ssh/config
that points to it. I've tried that and it works. But it would be helpful to have a way to load a certificate into Secretive so that the agent can provide it, instead of having to configure OpenSSH separately.
(When OpenSSH looks for the default key files like id_rsa
and id_ecdsa
and their associated .pub
files, it also looks for associated -cert.pub
files, and apparently it loads certificate files even if no corresponding private or .pub
file exists. Then, having loaded the certificate from the file, it's able to recognize that it matches the private key obtained from the agent, so it can use them together. But when using an agent, it's more typical for the agent to provide the certificate along with the key, so OpenSSH doesn't have to load it separately from a file.)
SSH certificates are very useful, btw: they change key distribution from an M*N
problem to an M+N
one. Instead of your authorized_keys
file needing separate lines for each client that you want to log in from (e.g. desktop and laptop), it can have one line for the key that you sign your certificates with, and that'll accept all your certificates from all your client machines.
It's a particularly good fit for Secretive, since you can't copy keys from one machine to another. Without certificates, if you get a new Mac and create a new key, you have to copy it into authorized_keys
on all your remote servers — which is tedious, and you might forget some. If you're using certificates, you just make a certificate for your new key, and you're done: the new machine can log into everywhere that the old one could.
either putting the certificate file in ~/.ssh with a filename that OpenSSH looks for by default (such as id_ecdsa-cert.pub), or by putting the file anywhere and adding a CertificateFile line in .ssh/config that points to it.
Thanks for sharing the workaround. It works when I am using the agent locally. When the agent is forwarded to another server, the certificates does not work because the agent is not aware of the existence of the certificates.
It would be great if secretive supported OpenSSH Certificates
I'm unsure how this would work, perhaps a location on disk where secretive looks for certificates, and adds them to the list of identities if a matching public key is found?
Unless its already supported? I could not find any mention of them in the docs or code...