Parsing new openssh-key-v1 format using openssl libcrypto - ssh

I need to parse an SSH private key ~/.ssh/id_rsa with openssl (libcrypto) into a EVP_PKEY* or RSA* key. Until recently this file would be stored in standard PEM or PKCS1 format which is easy to parse. However openssh has switched to a new format which is more complicated.
The structure is defined here and PEM encoded it looks like this (generated with ssh-keygen)
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABAnG3jyNb
SKSG19wHPhx2U1AAAAEAAAAAEAAAEXAAAAB3NzaC1yc2EAAAADAQABAAABAQDtmnNl2AFg
9faMuZ/U38tY3+pDrOa2yoiOLeXQI3044xNiMiGrRW03wzWsaNCcI8ZnEeSvzr2HUq0YFQ
QQ6MaQp8cZmoGkOSnwhLAscocZOaoZwoj85w2hybuSy9fc99FqKbJ201a0++2BhTw4Syhs
LT3AOs+Z0hHXZEVWAfBsOd4icLnChBdEAsIBzEObdGsZXHiOcVgvcbJ7UOuQCkiJV3RX+P
IvTzivPQ8IGmsgYUj5KSPjZg03/tr3ePItuFQZH2p85dQlbOLyhtMpx6M5ErCAesxuTN6z
kHKtfRNfYXoDOgd5EBIc9hLnmQtpn2EjfIk+yW+yTiv0pwNUhoeFAAAD0BHcM21NrYK7Pu
C4m79CfD3ZRMdKzG+hUqrV6bRC8qK/iTnt/E4GvEOIOqqoQMQp7PLRP5CkeWRp4Y0nmpsP
zoSlVLvpJ1o36pSSpF6ClmsviAXjujB4wqOp+vq9KqfQfJT+khq4u2EaKwzclpfwaUe2lT
t/UdUok4n8BGVZl6Hw3vF+a8XWpM3ZWxFJXNaQ1bklfYraKDR483I2KJX/hT1Y+Shrl7hd
faqfI8A71lV7qYwqyEMBgwsbNzDYUpICwAEGp00pbX7ahBgo3OIL8Ay1LTbVRyZqMZGGSy
Ay4+WD5cgzU1sb7Z7XnKeRdEWyYUezvzDLpwYsx5RjXIDECBOwbRexh0X0taJw9MIS1YtV
dXz+8PRelQSn7jMHTLa1ILhF95KQBBnqN8EAZEXPnX50b6tz1y7/U1PR/+OxaEGX960m25
2WoXfSRraA6lA2b28r4NT2/BWfYg+6RVu9AQOwdZNWs1fU4ZwnN3yf2w+xEJvvnrXFJrIv
Hy6riJOIB9kSFI314vqmipsMpm7eJK7S3TCi8O6npfkhKTsU1rK4MW+gYp3LKTa2/eUy9r
Rfdgg3dZfq4e51th/9g6SCfrLaDhqTVf7AThOSlmqIpW2A1+4WmuSqhplZhZV5QA0Dyg26
mPHMFTIKs6P2dzgqTkfFxpEici6BeTiSBuMjeKau2HI8r6VD8fcpkvcARPHncoZAdQbars
+e9FhyNMY+EVzun95FUjlbSAFCjGUN81/XPAd+PERTtg+Z1h+QEb1jlZO6l+L62SYXZQO7
jZa3euvFTUxh4GAuWMF4SM7HibTrnY3POD4y8pIWWFsS6xbDQPcy1BdgS4A4IeAXNFbFsX
U7xAwiA0QOnF2Qwc6rTIfR8KiDJ2pMPuSF3CsvuX1VuJZ4EvUFXImBAmet5ChXA2Gw2Gkf
vItgB70xjRVJUjqOE1FE8Qb61BWEvH9pQMIHt59ldrcnLycOFmBIvWiCLyEb5s+asMsqui
GoMowxdmaM+tkNsJIWFqKviaqHL51ZxzWfZ5C8RIrC1bBjCPdHd+T6iQifNS1vJhgEPuG/
iI9R2aFMdz69CVnWJzhtTEvJFsBNiM1rKTXXFm00rCZozKM6xVaiDodgL5s3FxVr17WTMH
FaFMCH7JNAJMCR7080IuABHFubE2UyeCV6WxUgDpeGzLGOLXmLlrpyB5DHbkuNa8OohIDm
qW5yZcK4RoN1Foi4+tAs7qCJQAJBKFmwTc+5y6mQnq9s9jHQqBbyweHmK8VTHwiRpHbBv/
BQ3FL3t8pTZxv6msYq0+PUUZ3L8+k=
-----END OPENSSH PRIVATE KEY-----
The first step is to parse the text with PEM_read_bio which will strip off the PEM header and base64-decode the data. But it is unclear how to parse the struct from the spec.
The first 15 bytes are fixed as openssh-key-v1\0 but from there it is unclear.

The simplest way to parse these is to avoid parsing them yourself, and instead use ssh-keygen -p -m PEM -f ~/.ssh/id_rsa to convert the key into PEM format, and then parse that using OpenSSL as per normal.
If you have a serious desire to get your hands dirty, though, the protocol description you linked to does, in fact, give you most of what you need to know. The (crucial) pieces of missing information are:
All integers are network byte order;
int is 32 bits;
Most crucially, the string type is a length-value tuple, where length is a uint32 indicating how many of the next octets make up the string; and
The formats of the various public key types (ssh-dss, ssh-rsa, ecdsa-sha2-*, etc) are documented in various RFCs that you can find referenced in the IANA registry for SSH Public Key Algorithm Names.
Extrapolation of the private key portions of various key types is left as an exercise for the reader, because I haven't figured it out yet. In the (near) future, my openssl-additions gem will have a Ruby-based implementation of SSH private key parsing, because I need to figure it out for my own project, so you could take the parameter ordering from that.

Related

Multiple ssh access types from a given user1/client to the same user2/server

I want to access from one user/client combination (say, user1#cl) to a user/server combination (say, user2#srv) via ssh, with two different types of Access:
Access type #1 would be restricted to interactions with a bazaar repository.
For this, I added a line (#1) in ~user2/.ssh/authorized_keys like
command="bzr serve --inet --directory=/repodir --allow-writes",no-port-forwarding,no-X11-forwarding,no-agent-forwarding ssh-rsa ... user1#cl
Access type #2 would be a login shell.
For this, I added a "usual" line (#2) in ~user2/.ssh/authorized_keys like
ssh-rsa ... user1#cl
As I understand, and as I tested, both lines cannot be used simultaneously.
I.e., if line #1 appears first in ~user2/.ssh/authorized_keys, then I would be able to interact with the bzr repo, but I will not be able to do
[user1#cl]$ ssh user2#srv
If line #2 appears first in ~user2/.ssh/authorized_keys, then I would be able to do ssh, but any bzr operation gives
bzr: ERROR: Not a branch ...
Is there any way to work this out?
I am using RHEL7, but I guess this is not important.
Related posts (but not addressing my case, as I understand):
Best way to use multiple SSH private keys on one client
https://serverfault.com/questions/142997/what-options-can-be-put-into-a-ssh-authorized-keys-file
https://serverfault.com/questions/749474/ssh-authorized-keys-command-option-multiple-commands
https://askubuntu.com/questions/1962/how-can-multiple-private-keys-be-used-with-ssh
I made it work, with two different key pairs (say, pair 1 for bzr and pair 2 for ssh login).
I added the corresponding lines in ~user2/.ssh/authorized_keys.
The private key 1 was stored in file id_rsa (which is read by default),
and the private key 2 was stored in file id_rsa_ssh.
Then, bzr was working normally, and for logging in I use
[user1#cl]$ ssh -i id_rsa_ssh user2#srv
which indicates using an alternative identity.

OpenSSL Sign with Serial Number

I'm trying to get a .crt file with some information, but unfortunately, i can't get a Serial Number generated.
I'd like to have a serial number generated, but not the same as the top one.
My CRT is generated with a PHP and I'd like to know what to put in my openssl.cnf to have the "same" process as the bottom one.
The last parameter of openssl_csr_sign function put the serial into crt

What is an RSA "key ID"?

I've seen key IDs used in several places and would like to use them in my program, but I haven't been able to find a description of them. How are they generated?
Having just done this for my own purposes, I'll write this down while it's all fresh in my head...
The "official" key ID (that is, the content of the "X509v3 Subject Key Identifier" extension in an X509 certificate) is the SHA1 hash of the DER-encoded ASN.1 sequence consisting of the modulus and exponent of an RSA public key. It takes piecing together about three different RFCs and a bit of experimentation to come up with that, but that's how it works.
Some Ruby code to do the encoding looks like this -- feed it an RSA public or private key on stdin:
require 'openssl'
pkey = OpenSSL::PKey::RSA.new($stdin.read).public_key
seq = OpenSSL::ASN1::Sequence([OpenSSL::ASN1::Integer.new(pkey.n),
OpenSSL::ASN1::Integer.new(pkey.e)])
puts Digest::SHA1.hexdigest(seq.to_der).upcase.scan(/../).join(':')
In different formats (PGP, SSH, X.509 certificates) key ID has different meaning. Neither SSH nor X.509 have a "dedicated" concept of key ID, but some people use this term (including their software) - in this case it's usually a hash of the public key or of the certificate in whole.
Update: the comments reminded me that "key identifier" extensions exist in X.509 certifiactes, and they sometimes are being referred to as key IDs. Yet, this is not common - usually the hash (also sometimes called the fingerprint) is referenced as key ID.
In the case of Strongswan one can display what it refers to as the keyid using its command line utilities. The main point of the keyid is that it can be used to identify the actual public key contained within a certificate so that a certificate might change but by checking the keyid one can check whether the key has changed or not.
The pki command will list the keyids of an X.509 cert as follows (where the subjectPublicKeyInfo hash is the keyid):
pki --keyid --in cert.pem --type x509
Or for an RSA private key:
pki --keyid --in key.pem
The second command is ipsec which one can use to list all the certs (and config) installed in the /etc/ipsec.d subdirectories (this command will list the certificates and their corresponding keyid which is the same as their subjectPublicKeyInfo hash listed by the pki command):
ipsec listall
Also one can use openssl to generate Strongswan's idea of a keyid, which is basically the SHA1 of the actual RSA public key (the sed script just strips the '-----BEGIN PUBLIC KEY-----' and END banners) [Corrected after Micah's comment]:
openssl x509 -in cert.pem -noout -pubkey | sed 's/--.*$//g' | base64 --decode | sha1sum
When you decrypt using gpg it provides a "long" keyID hash. To verify which key was used list the keys in long format using:
gpg --list-keys --keyid-format long
To list the keys in a different keyring without updating the default keyring use:
gpg --keyring <path-to-pubring.kbx> --no-default-keyring --list-keys
The "key ID" used for RSA key in GPG/PGP is the last 8 hex digits of the modulus of the key.

How to make password file hashed with SHA1

The <passwordFile> element is used to specify a file which has a set of username and password pairs. The format of username and password in this file is ${username}=${password which has been hashed with SHA1}, with one line per user.
Examples
Suppose the password file is admins.properties, which is located in /home/locker. You want to create two users as Administrators:
one username is nlohchab, the password hashed with SHA1 is ThmbShxAtJepX80c2JY1FzOEmUk=
the other one is james, the password hashed with SHA1 is TfkgShslgJepX80c2JY1trwEskT=
SHA is a hashing algorithm, you can't encrypt anything with it.
your question is not programming-related and ServerFault.com is a better place for it.

How to keep ssh-keygen from using my login and computer name in the public key?

I ran ssh-keygen on OS X and when I displayed the public key generated, I saw that my login and machine name appears in the last part of the key. Is there any way to have it use a different value or not use it at all?
From the manpage ‘ssh-keygen(1)’:
For RSA1 keys, there is also a comment field in the key file that is only for
convenience to the user to help identify the key. The comment can tell what the
key is for, or whatever is useful. The comment is initialized to “user#host”
when the key is created, but can be changed using the -c option.
…
-C comment
Provides a new comment.
-c Requests changing the comment in the private and public key files. This
operation is only supported for RSA1 keys. The program will prompt for
the file containing the private keys, for the passphrase if the key has
one, and for the new comment.
So, when creating the key you use -C "$desiredcommenttext" to provide whatever comment text you like; or for an existing key, use the -c option to change the comment.
Yes! It isn't needed at all, it's just arbitrarily appended to make it easy for you to remember where it came from. If you want to edit it, just open a Terminal session and type:
$ nano ~/.ssh/id_rsa.pub
Remove the end part of the line (after the double-equals).