2

This is related to Converting keys between openssl and openssh .

I have private keys generated by openssl that I want to use with SSH for connection authentication. I have no issue using ssh-keygen to generate a public key. However, I'm now trying to use CA certificate signing as I'm dealing with over 100 machines that need to connect via SSH.

If I try to do ssh-keygen -s ca.key -I dev1 dev1.key on my openssl generated key I get a message saying 'do_ca_sign: unable to open "dev1.key"'. I noticed that my openssl private keys are all 1675 bytes and the private keys generated by ssh-keygen are all 1679 bytes. Do I need to do some sort of conversion on the openssl keys before being able to sign them with the ca.key? Strangely ssh-keygen has no problem reading the same private key to generate a public key so I'm lost as to what to do.

Tim Tisdall
  • 125
  • 1
  • 5

2 Answers2

2

Digital Ocean published a tutorial showing how ssh-keygen can be used to sign a user's public key with a CA certificate. Generate a CA with ssh-keygen (NOT with openssl)

ssh-keygen -f users_ca

/etc/ssh/sshd_config can be amended so that the public keys don't need distribution:

AuthorizedKeysFile /dev/null

As long as the CA certificate is present and configured:

TrustedUserCAKeys /etc/ssh/users_ca.pub

Configure AuthorizedKeysFile to another value to allow exceptions

bbaassssiiee
  • 452
  • 2
  • 16
2

TL/DR: ssh-keygen only signs public keys. However, it tries to recover from being passed a private key by looking for an appropriately named public key automatically and gives no warning messages.

Unfortunately, SSH keys do not implement trusted third party as certificates do. SSH keys are quite basic, they are just "keys" as the name imply, without all the bell and whistles you may find in certificates (certificates being actually a key wrapped in a container adding supplementary information, and the CA signature is part of this container).

Would you need to find a way to handle SSH keys on a large number of hosts, you may be interested in this thread, where a solution is proposed to use MonkeySphere which relies on OpenPGP web of trust to add trusted third party concepts including to OpenSSH.

Edit: As appeared in the discussion below, openSSH added a specific feature implementing signing a public key using a third party CA key.

The command given in the question, "ssh-keygen -s ca.key -I dev1 dev1.key" does not work because, as stated in ssh-keygen manpage, dev1.key must be a public key.

However, when the file given as parameter is not a valid public key, before giving up ssh-keygen will check for the existence of a file named {filename}.pub which may contain the expected public key.

In the case of keys generated using ssh-keygen, this *.pub file is automatically generated, so when giving the private key file as parameter ssh-keygen will transparently fallback on the public key file.

However, key files manually generated from SSL certificates did not respect the same convention (the file dev1.key did not have its dev1.key.pub counterpart), and that's what it was failing in this case.

Edit 2: Checking this behavior is as simple as launching the command below

strace ssh-keygen -s ca.key -I dev1 dev1

The behavior I describe appear here:

# First ssh-keygen try to open the file given as parameter:
...
open("dev1", O_RDONLY)                  = 3
fstat(3, {st_mode=S_IFREG|0600, st_size=1671, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f15ec1c0000

# Then it reads its content:
read(3, "-----BEGIN RSA PRIVATE KEY-----\n"..., 4096) = 1671

# Seeing it is not a public key, it closes it:
close(3)                                = 0
munmap(0x7f15ec1c0000, 4096)            = 0

# Then he checks if a file with extension .pub exists:
open("dev1.pub", O_RDONLY)              = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=405, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f15ec1c0000

# If it exists, it reads it content too to check if it is a valid public key file:
read(3, "ssh-rsa AAAAB3NzaC1yc2EAAAADAQAB"..., 4096) = 405

# Yes it is, so now having read its content, it closes it and proceeds with
# creating the signed version of this public key (file 'dev1-cert.pub'):
close(3)                                = 0
munmap(0x7f15ec1c0000, 4096)            = 0
open("dev1-cert.pub", O_WRONLY|O_CREAT|O_TRUNC, 0644) = 3
...
WhiteWinterWolf
  • 19,292
  • 4
  • 61
  • 110
  • "ssh-keygen -s ca.key -I dev1 dev1.key " creates a private key signed by the CA. You can then use the CA public key on the server for authentication. My problem is just using private keys not generated with ssh-keygen. – Tim Tisdall Jan 24 '15 at 13:15
  • @TimTisdall Indeed feature specific to openSSH added in 2010 (OpenSSH 5.4). I get your error only when dev1.key does not exists or is not valid. Do you confirm it is a public key and not a private one? Would it be possible to get more information about how you generated it? A strace showing the last execution steps (starting from "open("dev1.key", O_RDONLY)") of ssh-keygen might also be usefull (it shows clearly if the file has been found, etc.). – WhiteWinterWolf Jan 24 '15 at 14:14
  • I'm pretty sure it has to be with the private key, that's what works when using a ssh-keygen created key pair. Yes, I noticed that too, the error message is pretty useless. I'll report back when I have a chance to do an strace. – Tim Tisdall Jan 24 '15 at 14:21
  • As specified in the manpage, under the "-s ca_key" option, "Certify (sign) a public key using the specified CA key.", I therefore confirms it signs the public key. Thanks to this, the user keeps the private key secret, and only has to provide the public key to the third party authority to sign it. – WhiteWinterWolf Jan 24 '15 at 14:26
  • strange... I converted the openssl private key into a public key and then was able to sign it properly. However, the program had no complaints signing the private key generated by ssh-keygen. – Tim Tisdall Jan 24 '15 at 21:30
  • It is possible that this functionality may still need a bit of polish: more consistent behavior, more explicit error messages ;). Anyway I suppose it targets signing public keys since it is the ones which will be sent to the remote hosts so they can check their validity. – WhiteWinterWolf Jan 25 '15 at 15:59
  • @TimTisdall: Finally got it :), I edited my answer accordingly, if it correctly answers your question do not forget to flag it as Right Answer! – WhiteWinterWolf Jan 26 '15 at 09:10
  • I tried running "ssh-keygen -s ca.key -I dev1 ..." on both the private key and the public key and it gave different results. It seems like you can actually sign either (the signed private key may not be useful for anything though). – Tim Tisdall Jan 26 '15 at 15:28
  • The result is always different, even when you try to sign several times the same key using the same certificate, I suppose some random data must be included at some point in the signed key. However, if you run ssh-keygen through strace (it is simply launching "strace ssh-keygen -s ca.key -I dev1 dev1"), then you will clearly see what I mean... I cannot add strace output here in the comment, I will update my answer. – WhiteWinterWolf Jan 26 '15 at 15:47
  • oi.. someone needs to make ssh-keygen a little more transparent in what it's doing. Maybe the -v option does that, but the error message you get when feeding it the private key is less than helpful. – Tim Tisdall Jan 26 '15 at 16:14
  • Can confirm that's what's happening. The error message is just missleading and plain atrocious. – user643011 Sep 06 '20 at 04:42