Skip to content

Commit

Permalink
Add secure messaging in readme + sample pki
Browse files Browse the repository at this point in the history
  • Loading branch information
af-anssi committed Nov 30, 2020
1 parent daa583b commit a180b17
Show file tree
Hide file tree
Showing 4 changed files with 303 additions and 4 deletions.
145 changes: 141 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
SmartPGP is a free and open source implementation of the [OpenPGP card
3.4 specification](https://gnupg.org/ftp/specs/OpenPGP-smart-card-application-3.4.pdf) in JavaCard.

The main improvement introduced in OpenPGP card 3.x specification from
previous version is the support of elliptic curve cryptography with
several existing curves (NIST P-256, NIST P-384, NIST P-521, brainpool
p256r1, brainpool p384r1 and brainpool p512r1).


## Features

Expand All @@ -26,6 +31,8 @@ of them depend on underlying hardware support and available

- AES 128/256 bits deciphering primitive;

- Secure messaging (see below).


## Default values

Expand All @@ -39,18 +46,47 @@ The SmartPGP applet is configured with the following default values:

- RSA 2048 bits for PGP keys;

- NIST P-256 for the secure messaging key.

These values can be changed by modifying default values in the code
(see the [Constants](src/fr/anssi/smartpgp/Constants.java)
class).

When the applet is installed, one can use the `smartpgp-cli` utility
given in the `bin` directory to change these values. Keep in mind that
when you change the algorithm attributes of a PGP key, the key and the
corresponding certificate are
when you change the algorithm attributes of a PGP key or of the secure
messaging key, the key and the corresponding certificate are
erased. Also note that hard coded default values will be restored upon
a factory reset.


## Compliance with OpenPGP card 3.4 specification

The SmartPGP applet implements the complete OpenPGP card 3.4
specification, except the secure messaging related features:

- Commands and responses protection is not implemented as described in
the specification. Motivation and implementation details are
explained in the
[secure messaging document](secure_messaging/smartpgp_sm.pdf);

- A command protected by secure messaging is not granted admin
rights. Secure messaging can thus be used to protect communications
only, especially when the token is used contactless;

- If and only if secure messaging static key and certificate have been
provisioned, all commands containing sensitive data (e.g. PIN code,
decrypted data, private key, ...) emitted through a contactless
interface must be protected by secure messaging or they will be
refused;

- The `ACTIVATE FILE` with P1 = P2 = 0, as described in the
specification, resets everything except the secure messaging static
key and certificate. Complete reset, including these elements, can
be performed with `ACTIVATE FILE` with P1 = 0 and P2 = 1.



# Application support

Tokens following the OpenPGP card 3.4 specification are not yet fully
Expand All @@ -61,18 +97,28 @@ supported by most PGP applications.
OpenPGP card 3.x is supported by [GnuPG](https://www.gnupg.org/)
starting from version 2.1.16.

The specific secure messaging of the SmartPGP applet is **not**
supported at is not part of the OpenPGP card specification.

## OpenKeychain

OpenPGP card 3.x is supported by [OpenKeychain](https://www.openkeychain.org/)
starting from version 4.2.

The secure messaging of the SmartPGP applet is fully supported in
OpenKeychain. See the section below for more information on the setup process.


# Content of the repository

The repository contains several directories:

- `bin` contains a Python library and command line tool called
`smartpgp-cli` to interact with an OpenPGP card 3.x;
`smartpgp-cli` to interact with an OpenPGP card 3.x but also to deal
with the specific secure messaging feature of the SmartPGP applet;

- `secure_messaging` contains documentation and example scripts to
play with the secure messaging feature of SmartPGP;

- `src` contains the JavaCard source code of the SmartPGP applet;

Expand Down Expand Up @@ -128,7 +174,8 @@ resource consumption by tweaking the following variables:
- `Constants.EXTENDED_CAPABILITIES`, bytes 5 and 6: the maximal size
in bytes of a certificate associated to a key. Following the OpenPGP
card specification, a certificate can be stored for each of the
three keys.
three keys. In SmartPGP, a fourth certificate is stored for secure
messaging.


## Building the CAP file
Expand All @@ -155,3 +202,93 @@ Be careful to use a valid AID according to the OpenPGP card
specification (see section 4.2.1) for each card (`-create <AID>` with
GlobalPlatformPro)



# Setting up secure messaging with OpenKeychain

## Secure messaging without token authentication

Without token authentication, you are not protected against
man-in-the-middle attack as your device cannot ensure it is
communicating directly with a trusted token. Nevertheless, the
communications with the token are still protected in confidentiality
against passive attacks (i.e. trafic capture).

If you want to test secure messaging without token authentication, you
can use the following command to order the token to generate its
secure messaging key on-board.

`./smartpgp-cli -r X -I generate-sm-key -o pubkey.raw`

In this case, you have to deactivate the certificate verification in
OpenKeychain: go to "Parameters" > "Experimental features" and
deactivate the option called "SmartPGP verify certificate".


## Secure messaging with token authentication

The `secure_messaging` directory contains a subdirectory called `pki`
which contains two sample scripts to generate a certificate
authority and token certificates.

The sample scripts are given **only** for test purposes of the secure
messaging feature with certificate verification. They require
`openssl` to be installed on your system.

If you want to use your own PKI, you have to generate a specific
intermediate certificate authority to sign the certificates of your
token(s). Then, you have to provision the complete certificate chain
from this new intermediate CA to your root CA in OpenKeychain because
the certificate verification implemented in the given patch does not
rely on the system keystore.

### Generate a sample CA key and certificate

Change your current directory to the `pki` directory and execute the
script `./generate_ca.sh`. It will produce a sample CA key in
`PKI/private/ca.key.pem` and the corresponding certificate in
`PKI/certs/ca.cert.pem`.

### Generate a sample token key and certificate

Change your current directory to the `pki` directory and execute the
script

`./generate_token.sh mycard1`

where `mycard1` is some unique identifier for the token. It will
produce a sample token key in `PKI/private/mycard1.key.pem` and the
corresponding certificate in `PKI/certs/mycard1.cert.pem`.

### Provision the token with its sample key and certificate

Change your current directory to the `bin` directory and execute the
following commands after replacing the reader number `X` by the number
of the reader that contains your token, and the path to the `pki`
directory used in previous sections.

The following command imports the token key in the token.

`./smartpgp-cli -r X -I -i path_to_the_pki_dir/PKI/private/mycard1.key.der put-sm-key`

The following command imports the token certificate in the token.

`./smartpgp-cli -r X -I -i path_to_the_pki_dir/PKI/certs/mycard1.cert.der put-sm-certificate`

These commands have to be executed in this order because the key
import clears any previously stored certificate.

Once the token key is imported, you should remove the token private
key from you system as there is no need to keep it outside of your
token.

### Install the CA in OpenKeychain

- Upload the CA certificate `PKI/certs/ca.cert.pem` to your phone;

- Go to "Parameters" > "Experimental features" and activate the option called "SmartPGP verify certificate`;

- Click on "SmartPGP trusted authorities", and then on "+" at the top left;

- Set a name for this authority and select the file you uploaded.

29 changes: 29 additions & 0 deletions secure_messaging/pki/generate_ca.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/bin/bash

CURVE=secp521r1
DAYS=1825

######

DIR=PKI

######

set -e -u

if [[ -e "$DIR/private/ca.key.pem" ]] ; then
echo "CA already exists, please remove it manually if you want to generate a new one" 1>&2
exit 2
fi

mkdir -p "$DIR/private" "$DIR/certs"

openssl ecparam -name "$CURVE" -genkey -check -noout -outform pem -out "$DIR/private/ca.key.pem"

openssl req -config openssl.cnf -extensions v3_ca -days $DAYS -new -x509 -sha256 -keyform pem -key "$DIR/private/ca.key.pem" -outform pem -out "$DIR/certs/ca.cert.pem"

touch $DIR/index.txt

echo 1000 > $DIR/serial

echo 1000 > $DIR/crlnumber
42 changes: 42 additions & 0 deletions secure_messaging/pki/generate_token.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/bin/bash

CURVE=secp256r1
DAYS=730

######

DIR=PKI

######

set -e -u

if [[ $# -lt 1 ]] ; then
echo "Missing card certificate identifier" 1>&2
exit 1
fi
if [[ $# -gt 1 ]] ; then
echo "Too many parameters" 1>&2
exit 2
fi

if [[ ! -e "$DIR/private/ca.key.pem" ]] ; then
echo "Missing CA (please execute generate_ca.sh)" 1>&2
exit 2
fi


NAME="$1"

mkdir -p "$DIR/csr"

openssl ecparam -name "$CURVE" -genkey -check -noout -outform der -out "$DIR/private/$NAME.key.der"

openssl req -config openssl.cnf -new -sha256 -keyform der -key "$DIR/private/$NAME.key.der" -outform pem -out "$DIR/csr/$NAME.csr.pem"

openssl ca -config openssl.cnf -extensions card_cert -days $DAYS -md sha256 -in "$DIR/csr/$NAME.csr.pem" -out "$DIR/certs/$NAME.cert.pem"

openssl x509 -inform pem -in "$DIR/certs/$NAME.cert.pem" -outform der -out "$DIR/certs/$NAME.cert.der"

rm "$DIR/certs/$NAME.cert.pem"

91 changes: 91 additions & 0 deletions secure_messaging/pki/openssl.cnf
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@

[ ca ]
default_ca = CA_default

[ CA_default ]
# Directory and file locations.
dir = ./PKI/
certs = $dir/certs
crl_dir = $dir/crl
new_certs_dir = $dir/certs
database = $dir/index.txt
serial = $dir/serial
RANDFILE = $dir/private/.rand

# The root key and root certificate.
private_key = $dir/private/ca.key.pem
certificate = $dir/certs/ca.cert.pem

# For certificate revocation lists.
crlnumber = $dir/crlnumber
crl = $dir/crl/ca.crl.pem
crl_extensions = crl_ext
default_crl_days = 30

# SHA-1 is deprecated, so use SHA-2 instead.
default_md = sha256

name_opt = ca_default
cert_opt = ca_default
default_days = 730
preserve = no
policy = policy_loose

[ policy_loose ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional

[ req ]
# Options for the `req` tool (`man req`).
default_bits = 2048
distinguished_name = req_distinguished_name
string_mask = utf8only

# SHA-1 is deprecated, so use SHA-2 instead.
default_md = sha256

# Extension to add when the -x509 option is used.
x509_extensions = v3_ca

[ req_distinguished_name ]
# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
countryName = Country Name (2 letter code)
stateOrProvinceName = State or Province Name
localityName = Locality Name
0.organizationName = Organization Name
organizationalUnitName = Organizational Unit Name
commonName = Common Name
emailAddress = Email Address

# Optionally, specify some defaults.
countryName_default =
stateOrProvinceName_default =
localityName_default =
0.organizationName_default =
organizationalUnitName_default =
emailAddress_default =

[ v3_ca ]
# Extensions for a typical CA (`man x509v3_config`).
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:1
keyUsage = critical, digitalSignature, cRLSign, keyCertSign

[ card_cert ]
# Extensions for client certificates (`man x509v3_config`).
basicConstraints = CA:FALSE
nsCertType = client
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, nonRepudiation

[ crl_ext ]
# Extension for CRLs (`man x509v3_config`).
authorityKeyIdentifier=keyid:always

0 comments on commit a180b17

Please sign in to comment.