Tommy
November 18 2020
Key Takeaways
- PGP are replaceable with native OpenSSL RSA public key crypto
and AES-256 keys.
- This approach simplifies crypto operations, and only requires
OpenSSL which is widely available.
- Existing PGP keys stored in GnuPG work with OpenSSL via
gpgsm
.
Introduction
The rabbit hole mission of mine to get rid of PGP continues.
Lately I have been looking into converting PGP keys from GnuPG to
OpenSSL. This way I can send encrypted data to people not using my
OpenSSL-only approach. After all, most people still depend on PGP
and it is the format they publish their public keys in.
Exporting A PGP Public Key for Encryption Using OpenSSL
A PGP key cannot be directly read by OpenSSL, but GPG can natively
export to SSH and ssh-keygen to PKCS8:
gpg --export-ssh-key <key-id>! > /tmp/test.pub
ssh-keygen -f /tmp/test.pub -e -m PKCS8 > /tmp/test.pem
The above pubkey can be used to encrypt data with OpenSSL as shown
on my contact page:
KEY=`openssl rand -hex 32` IV=`openssl rand -hex 16`
ENCRYPTED_KEY_B64=`openssl pkeyutl -encrypt -pubin -inkey /tmp/test.pem -pkeyopt rsa_padding_mode:oaep <<< $KEY|base64`
BLOB=`openssl enc -aes-256-cfb -a -e -K ${KEY} -iv ${IV} -in some-file`
echo "PKCS11-VAULT;aes-256-cfb;rsa_padding_mode:oaep;$ENCRYPTED_KEY_B64:$IV:$BLOB;" > encrypted.txt
The steps of the above are:
- Create an initialization vector [1] and an encryption key
- Encrypt the one-time key to test.pem (our exported PGP-key)
- Encrypt
some-file
using the key and IV using 256 bits AES in CFB-mode
- Format the output in my PV-format.
Store encrypted.txt
for decryption in the next section.
Exporting a PGP Private Key for Decryption Using OpenSSL
This part is a bit more complex. For the sake of an example, let
us say you received an encrypted blob with an IV and encrypted
key, using the approach shown in the former section. You have the
key stored in GnuPG.
gpgsm
can export your private key to p12, which is readable for
OpenSSL [2].
First list your secret keys in the GnuPG store: gpg
--list-secret-keys --with-keygrip
.
Convert the key to X.509 by: gpgsm --gen-key -o
/tmp/temp.crt
. You need to fill the values requested:
- Select “existing key”
- Fill the keygrip from the GPG secret key listing. Make sure you
use the right key, since GPG generates several keys behind the
scenes (the encryption key)
- Fill the cn (this needs to be on the format “cn=…”) and e-mail
- Accept the other values as empty and accept the creation
Now import the certificate into gpgsm
: gpgsm --import
/tmp/temp.crt
. When imported, find the key ID by: gpgsm
--list-keys
.
Using the key ID, you can now export the key in p12-format.
gpgsm -o /tmp/$keyid.p12 --export-secret-key-p12 $keyid
openssl pkcs12 -in /tmp/$key.p12 -nodes -nocerts|tail -n +5 > /tmp/$key.key
You only need to do the conversion once and now have your key in
/tmp/$key.key
. This should be secured accordingly, and have a
password set as is offered in the guidance by gpgsm.
The resulting /tmp/$key.key
is usable for decrypting content
encrypted by the public key. To decrypt the data in encrypted.txt
:
IFS=';' read IDENTIFIER ALGORITHM PADDING_MODE ENCRYPTION_BLOBS SIGNATURE < encrypted.txt
for BLOB in ${ENCRYPTION_BLOBS[@]}; do
IFS=':' read ENCRYPTED_KEY_B64 IV TEXTFILE_ENC <<< $BLOB
ENCRYPTED_KEY=`printf $ENCRYPTED_KEY_B64 | base64 -d`
decrypted=false
DECRYPTED_KEY=`echo $ENCRYPTED_KEY_B64 |base64 -d | openssl pkeyutl -decrypt -inkey /tmp/$key.key -pkeyopt ${PADDING_MODE} 2> /dev/null` && decrypted=true
if [ $decrypted != false ]; then
TEXTFILE_DEC=`printf %s "$TEXTFILE_ENC"|base64 -d|openssl enc -$ALGORITHM -d -K "$DECRYPTED_KEY" -iv "$IV" |base64`
break
fi
done
echo $TEXTFILE_DEC
The above format supports encryption to multiple parties. It:
- Reads the PV-format into variables
- Loops through the encryption blobs (one pass if one recipient)
- Decrypts the key with the private key generated from
gpgsm
- Using the IV and decrypted key, decrypts the content, which is
eventually the same as in the previous section’s
some-file
- Prints the decrypted content
Conclusion
It is possible to convert PGP keys to use with OpenSSL via gpgsm
.
Since OpenSSL is more widely distributed and installed than GnuPG,
it is a method applicable in more environments.
Using OpenSSL instead of GnuPG provides more options, and reduces
the complexity of cryptography (since GnuPG has lots of options).
[1] https://stackoverflow.com/questions/39412760/what-is-an-openssl-iv-and-why-do-i-need-a-key-and-an-iv
[2] https://superuser.com/a/1414277
Tags:
#openssl
#ssh
#gnupg
#encryption
#decryption
#crypto
Read with Gemini
Tommy
October 14 2020
Key Takeaways
- SSH certificates can be used with the Apple T2 chip on
macOS as an alternative to external smart cards,
authenticated with a fingerprint per session.
- The Mac T2 chip serves as an extra security layer by creating
private keys in the secure enclave.
- The CA can be stored on an external smartcard, only
signing for access in a limited period - again limiting
the exposure.
Introduction
Over the past days I have been going down a deep, deep
rabbit hole of SSH proxy jumping and SSH certificates
combined with smart cards.
After playing around with smart cards for SSH, I recognized
that not only external smart cards such as the Yubikey or
Nitrokey is a possible lane to go down.
Mac computers comes with a security chip called T2. This chip is
also known to host something Apple calls Secure Enclave [1]. In
the Secure Enclave you can store keys.
It will probably not serve as an equally secure solution as with
external smart cards, but it is a better balance for usability.
The T2 is permanently stored in hardware on one host only,
so the access needs to be signed on a per-host basis. In
such I would say the T2 and external smart cards complement
each other.
Always having the key available will bring two additional
vulnerabilities:
- If compromised, the key is always available logically
- Separation of equipment and key is not possible e.g. in a
travel situation
With a central pubkey directory tied to an identity
(automated), the T2 can be of better use for an enterprise
setup.
Setting up a Private Key in Secure Enclave
While fiddling around I found sekey on Github [2]. The
project seems abandoned, but it is the secure enclave that
does the heavy lifting.
The short and easy setup are:
$ brew cask install sekey
$ echo "export SSH_AUTH_SOCK=$HOME/.sekey/ssh-agent.ssh" >> ~/.zshrc
$ echo "IdentityAgent ~/.sekey/ssh-agent.ssh" >> ~/.ssh/config
$ source ~/.zshrc
A keypair can now be generated in the secure enclave by:
$ sekey --generate-keypair SSH
$ sekey --list-keys
Now export the public key of the curve generated on-chip:
$ sekey --export-key <id> > id_ecdsa.pub
Using the trick we found in our recent venture into using
smart cards for signing the key, we can used PCKS#11 without
compromising security [3]. In this case I use a Nitrokey:
$ brew cask install opensc
$ PKCS11_MODULE_PATH=/usr/local/lib/opensc-pkcs11.so
$ ssh-keygen -D $PKCS11_MODULE_PATH -e > ca.pub
$ ssh-keygen -D $PKCS11_MODULE_PATH -s ca.pub -I example -n zone-web -V +1h -z 1 id_ecdsa.pub
Enter PIN for 'OpenPGP card (User PIN)':
Signed user key id_ecdsa-cert.pub: id "example" serial 1 for zone-web valid from 2020-10-14T20:26:00 to 2020-10-14T21:27:51
cp id_ecdsa-cert.pub ~/.ssh/
If you now try to ssh into a server using the given
certificate authority as shown in the SSH-CA post [3],
access should be granted with a fingerprint.
A Word of Caution
The T2 has some vulnerabilities shown recently [4]. Make
sure to include these in your risk assessment of using
it. If you won’t go down the smart card route it will still
be better than storing the key on disk.
[1] https://support.apple.com/guide/security/secure-enclave-overview-sec59b0b31ff/web
[2] https://github.com/sekey/sekey
[3] https://secdiary.com/2020–10–13-ssh-ca-proxyjump.html
[4] https://inks.cybsec.network/tag/t2
Tags:
#architecture
#ssh
#apple
#t2
Read with Gemini
Tommy
October 13 2020
Key Takeaways
- SSH has a key-signing concept that in combination with a
smartcard provides a lean, off-disk process
- A SSH-CA provides the possibility of managing access
without a central point of failure
- The use of SSH Jumphost is an easier way to tunnel
sessions end-to-end encrypted, while still maintaining
visibility and control through a central point
Introduction
This post is an all-in-one capture of my recent discoveries with
SSH. It is an introduction for a technical audience.
It turns out that SSH is ready for a zero trust and
microsegmentation approach, which is important for
management of servers. Everything described in this post is
available as open source software, but some parts require a
smartcard or two, such as a Yubikey (or a Nitrokey if you
prefer open source. I describe both).
I also go into detail on how to configure the CA key without
letting the key touch the computer, which is an important
principle.
The end-result should be a more an architecture providing a better
overview of the infrastructure and a second logon-factor
independent of phones and OATH.
SSH-CA
My exploration started when I read a 2016-article by
Facebook engineering [1]. Surprised, but concerned with the
configuration overhead and reliability I set out to test the
SSH-CA concept. Two days later all my servers were on a new
architecture.
SSH-CA works predictably like follows:
[ User generates key on Yubikey ]
|
|
v
[ ssh-keygen generates CA key ] --------> [ signs pubkey of Yubikey ]
| - for a set of security zones
| - for users
| |
| |
| v
v pubkey cert is distributed to user
[ CA cert and zones pushed to servers ] - id_rsa-cert.pub
- auth_principals/root (root-everywhere)
- auth_principals/web (zone-web)
The commands required in a nutshell:
# on client
$ ssh-keygen -t rsa
# on server
$ ssh-keygen -C CA -f ca
$ ssh-keygen -s ca -I <id-for-logs> -n zone-web -V +1w -z 1 id_ecdsa.pub
# on client
cp id_ecdsa-cert.pub ~/.ssh/
Please refer to the next section for a best practice storage
of your private key.
On the SSH server, add the following to the SSHD config:
TrustedUserCAKeys /etc/ssh/ca.pub
AuthorizedPrincipalsFile /etc/ssh/auth_principals/%u
What was conceptually new for me was principals and
authorization files per server. This is how it works:
- Add a security zone, like zone-web, during certificate
signing - “ssh-keygen * -n zone-web *”. Local username does
not matter
- Add a file per user on the SSH server, where zone-web
is added where applicable -
e.g. “/etc/ssh/auth_principals/some-user” contains “zone-web”
- Login with the same user as given in the zone file - “ssh some-user@server”
This is the same as applying a role instead of a name to the
authorization system, while something that IDs the user is
added to certificate and logged when used.
This leaves us with a way better authorization and
authentication scheme than authorized_keys that everyone
uses. Read on to get the details for generating the CA key
securely.
Keeping Private Keys Off-disk
An important principle I have about private keys is to
rather cross-sign and encrypt two keys than to store one on
disk. This was challenged for the SSH-CA design. Luckily I found
an article describing the details of PKCS11 with ssh-keygen
[2]:
If you’re using pkcs11 tokens to hold your ssh key, you
may need to run ssh-keygen -D $PKCS11_MODULE_PATH
~/.ssh/id_rsa.pub so that you have a public key to
sign. If your CA private key is being held in a pkcs11
token, you can use the -D parameter, in this case the -s
parameter has to point to the public key of the CA.
Yubikeys on macOS 11 (Big Sur) requires the yubico-piv-tool
to provide PKCS#11 drivers. It can be installed using
Homebrew:
$ brew install yubico-piv-tool
$ PKCS11_MODULE_PATH=/usr/local/lib/libykcs11.dylib
Similarly the procedure for Nitrokey are:
$ brew cask install opensc
$ PKCS11_MODULE_PATH=/usr/local/lib/opensc-pkcs11.so
Generating a key on-card for Yubikey:
$ yubico-piv-tool -s 9a -a generate -o public.pem
For the Nitrokey:
$ pkcs11-tool -l --login-type so --keypairgen --key-type RSA:2048
Using the exported CA pubkey and the private key on-card a
certificate may now be signed and distributed to the user.
$ ssh-keygen -D $PKCS11_MODULE_PATH -e > ca.pub
$ ssh-keygen -D $PKCS11_MODULE_PATH -s ca.pub -I example -n zone-web -V +1w -z 1 id_rsa.pub
Enter PIN for 'OpenPGP card (User PIN)':
Signed user key .ssh/id_rsa-cert.pub: id "example" serial 1 for zone-web valid from 2020-10-13T15:09:00 to 2020-10-20T15:10:40
The same concept goes for a user smart-card, except that is
a plug and play as long as you have the gpg-agent
running. When the id_rsa-cert.pub (the signed certificate of
e.g. a Yubikey) is located in ~/.ssh, SSH will find the
corresponding private key automatically. The workflow will
be something along these lines:
[ User smartcard ] -----------> [ CA smartcard ]
^ id_rsa.pub |
| | signs
|------------------------------|
sends back id_rsa-cert.pub
A Simple Bastion Host Setup
The other thing I wanted to mention was the -J option of
ssh, ProxyJump.
ProxyJump allows a user to confidentially, without risk of a
man-in-the-middle (MitM), to tunnel the session through a
central bastion host end-to-end encrypted.
Having end-to-end encryption for an SSH proxy may seem
counter-intuitive since it cannot inspect the
content. I believe it is the better option due to:
- It is a usability compromise, but also a security
compromise in case the bastion host is compromised.
- Network access and application authentication (and even
authorization) goes through a hardened point.
- In addition the end-point should also log what happens on
the server to a central syslog server.
- A bastion host should always be positioned in front of the
server segments, not on the infrastructure perimeter.
A simple setup looks like the following:
[ client ] ---> [ bastion host ] ---> [ server ]
Practically speaking a standalone command will look like
follows:
ssh -J jump.example.com dest.example.com
An equivalent .ssh/config will look like:
Host j.example.com
HostName j.example.com
User sshjump
Port 22
Host dest.example.com
HostName dest.example.com
ProxyJump j.example.com
User some-user
Port 22
With the above configuration the user can compress the
ProxyJump SSH-command to “ssh dest.example.com”.
Further Work
The basic design shown above requires one factor which is
probably not acceptable in larger companies: someone needs
to manually sign and rotate certificates. There are some
options mentioned in open sources, where it is normally to
avoid having certificates on clients and having an
authorization gateway with SSO. This does however introduce
a weakness in the chain.
I am also interested in using SSH certificates on iOS, but
that has turned out to be unsupported in all apps I have
tested so far. It is however on the roadmap of Termius,
hopefully in the near-future. Follow updates on this subject
on my Honk thread about it [4].
For a smaller infrastructure like mine, I have found the
manual approach to be sufficient so far.
[1] Scalable and secure access with SSH: https://engineering.fb.com/security/scalable-and-secure-access-with-ssh/
[2] Using a CA with SSH: https://www.lorier.net/docs/ssh-ca.html
[3] Using PIV for SSH through PKCS #11:
https://developers.yubico.com/PIV/Guides/SSH_with_PIV_and_PKCS11.html
[4] https://cybsec.network/u/tommy/h/q1g4YC31q45CT4SPK4
Tags:
#architecture
#ssh
#proxyjump
#smartcard
#pkcs11
#ssh-ca
#certificates
#signing
Read with Gemini