blob: b4707a69febca1bb2b1f0649b7f1de5b6f0146a8 [file] [log] [blame]
..
Copyright 2019 NXP
.. _intro-openssl-engine:
Introduction on OpenSSL engine
==============================
Starting with OpenSSL 0.9.6 an ‘Engine interface’ was added to OpenSSL allowing support
for alternative cryptographic implementations. This Engine interface can be
used to interface with external crypto devices. The key injection process is
secure module specific and is not covered by the Engine interface.
Depending on the capabilities of the attached secure element (e.g. SE050_C, A71CH, ...)
the following functionality can be made available over the OpenSSL Engine interface:
- EC crypto
- EC sign/verify
- ECDH compute key
- Montgomory ECDH
- RSA crypto
- RSA sign/verify
- RSA priv_key_decrypt/pub_key_encrypt
- Fetching random data
General
-------
OpenSSL versions
~~~~~~~~~~~~~~~~
The OpenSSL Engine is compatible with OpenSSL versions 1.0.2 or 1.1.1.
OpenSSL Configuration file
~~~~~~~~~~~~~~~~~~~~~~~~~~
It's possible to add OpenSSL engine specific extensions to the OpenSSL configuration file.
Using these extensions one can control whether the supported crypto functionality is delegated to
the Secure Element or whether it is handled by the OpenSSL SW implementation.
The actual contents of the configuration file depends on the OpenSSL version and the attached
secure element (SE050 or A71CH). The ``demos/linux/common folder`` of this SW package contains
4 reference configuration files covering both SE050 and A71CH for the two supported OpenSSL versions.
The following configuration file fragment (extracted from ``openssl11_sss_se050.cnf``) highlights
the required changes to enable the full functionality of the SE050_C OpenSSL Engine on an iMX Linux system::
...
# System default
openssl_conf = nxp_engine
...
...
[nxp_engine]
engines = engine_section
[engine_section]
e4sss_se050 = e4sss_se050_section
[e4sss_se050_section]
engine_id = e4sss
dynamic_path = /usr/local/lib/libsss_engine.so
init = 1
default_algorithms = RAND,RSA,EC
One overrules the default OpenSSL configuration file by setting the environment variable
``OPENSSL_CONF`` to the path of the custom configuration file.
Platforms
~~~~~~~~~
The OpenSSL engine can be used on iMX boards (running Linux) or on Raspberry Pi (running Raspbian).
Keys
----
Key Management
~~~~~~~~~~~~~~
The cryptographic functionality offered by the OpenSSL engine requires a
reference to a key stored inside the Secure Element (exception is
RAND_Method). These keys are typically inserted into the Secure Element in a
secured environment during production.
OpenSSL requires a key pair, consisting of a private and a public key, to be
loaded before the cryptographic operations can be executed. This creates a
challenge when OpenSSL is used in combination with a secure element as the
private key cannot be extracted out from the Secure Element.
The solution is to populate the OpenSSL Key data structure with only a
reference to the Private Key inside the Secure Element instead of the actual
Private Key. The public key as read from the Secure Element can still be
inserted into the key structure.
OpenSSL crypto API’s are then invoked with these data structure objects as
parameters. When the crypto API is routed to the Engine, the OpenSSL engine
implementation decodes these key references and invokes the SSS API with
correct Key references for a cryptographic operation.
.. _ec-reference-key-format:
EC Reference key format
~~~~~~~~~~~~~~~~~~~~~~~
The following provides an example of an EC reference key. The value reserved
for the private key has been used to contain:
- a pattern of ``0x10..00`` to fill up the datastructure MSB side to the
desired key length
- a 32 bit key identifier (in the example below ``0x7DCCBBAA``)
- a 64 bit magic number (always ``0xA5A6B5B6A5A6B5B6``)
- a byte to describe the key class (``0x10`` for Key pair and ``0x20`` for
Public key)
- a byte to describe the key index (use a reserved value ``0x00``)
.. code:: text
Private-Key: (256 bit)
priv:
10:00:00:00:00:00:00:00:00:00:00:00:00:00:00:
00:00:00:7D:CC:BB:AA:A5:A6:B5:B6:A5:A6:B5:B6:
kk:ii
pub:
04:1C:93:08:8B:26:27:BA:EA:03:D1:BE:DB:1B:DF:
8E:CC:87:EF:95:D2:9D:FC:FC:3A:82:6F:C6:E1:70:
A0:50:D4:B7:1F:F2:A3:EC:F8:92:17:41:60:48:74:
F2:DB:3D:B4:BC:2B:F8:FA:E8:54:72:F6:72:74:8C:
9E:5F:D3:D6:D4
ASN1 OID: prime256v1
.. note::
- The key identifier ``0x7DCCBBAA`` (stored in big-endian convention) is in
front of the magic number ``0xA5A6B5B6A5A6B5B6``
- The padding of the private key value and the magic number make it
unlikely a normal private key value matches a reference key.
- Ensure the value reserved for public key and ASN1 OID contain the values
matching the stored key.
.. note::
- For EC montgomery curves, openssl allows only the private key to be set.
So the reference key created will not have the valid public key.
.. _rsa-reference-key-format:
RSA Reference key format
~~~~~~~~~~~~~~~~~~~~~~~~
The following provides an example of an RSA reference key.
- The value reserved for 'p' (aka 'prime1') is used as a magic number and is
set to '1'
- The value reserved for 'q' (aka 'prime2') is used to store the 32 bit key
identifier (in the example below 0x6DCCBB11)
- The value reserved for '(inverse of q) mod p' (aka 'IQMP' or 'coefficient')
is used to store the magic number 0xA5A6B5B6
.. code:: text
Private-Key: (2048 bit)
modulus:
00:b5:48:67:f8:84:ca:51:ac:a0:fb:d8:e0:c9:a7:
72:2a:bc:cb:bc:93:3a:18:6a:0f:a1:ae:d4:73:e6:
...
publicExponent: 65537 (0x10001)
privateExponent:
58:7a:24:39:90:f4:13:ff:bf:2c:00:11:eb:f5:38:
b1:77:dd:3a:54:3c:f0:d5:27:35:0b:ab:8d:94:93:
...
prime1: 1 (0x1)
prime2: 1842133777(0x6DCCBB11)
exponent1:
00:c1:c9:0a:cc:9f:1a:c5:1c:53:e6:c1:3f:ab:09:
db:fb:20:04:38:2a:26:d5:71:33:cd:17:a0:94:bd:
...
exponent2:
24:95:f0:0b:b0:78:a9:d9:f6:5c:4c:e0:67:d8:89:
c1:eb:df:43:54:74:a0:1c:43:e3:6f:d5:97:88:55:
...
coefficient: 2779166134 (0xA5A6B5B6)
.. note::
- Ensure keylength, the value reserved for (private key) modulus and
public exponent match the stored key.
- The mathematical relation between the different key components is not
preserved.
- Setting prime1 to '1' makes it impossible that a normal private key
matches a reference key.
Building the OpenSSL engine
------------------------------------------------------
The cmake build system will create an OpenSSL engine for supported platforms.
The resulting OpenSSL engine will be copied to the SW tree in directory
``simw-top/sss/plugin/openssl/bin``.
A subsequent ``make install`` will copy the
OpenSSL engine to a standard directory on the file system, in case of iMX Linux e.g.
``/usr/local/lib``.
.. note::
Ensure the following flag is defined when building an application that will be linked against the engine:
``-DOPENSSL_LOAD_CONF``
Sample scripts to demo OpenSSL Engine
------------------------------------------------------
The directory ``simw-top/sss/plugin/openssl/scripts`` contains a set of python
scripts. These scripts use the OpenSSL Engine in the context of standard
OpenSSL utilities. They illustrate using the OpenSSL Engine for fetching
random data, EC or RSA crypto operations. The scripts that illustrate EC or
RSA crypto operations depend on prior provisioning of the secure element.
As an example, the following set of commands first creates and provisions EC key
material. Then it invokes the OpenSSL Engine for ECDSA sign / verify
operations and ECDH calculations. It assumes an SE050 is connected via I2C to
an iMX6UL-EVK board::
python3 openssl_provisionEC.py --key_type prime256v1
python3 openssl_EccSign.py --key_type prime256v1
python3 openssl_Ecdh.py --key_type prime256v1
Further details on using these scripts can be found in the following:
openssl_rnd.py
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. include:: doc/openssl_rnd.rst.txt
openssl_provisionEC.py
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. include:: doc/openssl_provisionEC.rst.txt
openssl_EccSign.py
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. include:: doc/openssl_EccSign.rst.txt
openssl_Ecdh.py
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. include:: doc/openssl_Ecdh.rst.txt
ecc_all.py
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. include:: doc/ecc_all.rst.txt
openssl_provisionRSA.py
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. include:: doc/openssl_provisionRSA.rst.txt
openssl_RSA.py
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. include:: doc/openssl_RSA.rst.txt
rsa_all.py
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. include:: doc/rsa_all.rst.txt
openssl_provisionEC_mont.py
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. include:: doc/openssl_provisionEC_mont.rst.txt
openssl_Ecdh_mont.py
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. include:: doc/openssl_Ecdh_mont.rst.txt
.. only:: nxp
.. warning::
NXP Internal documentation.
Generating the Documentation
---------------------------------
Call this command from within venv::
for %i in ( *.py ) do call python %i --help > doc\%~ni.rst.txt 2>&1
OR
for i in *.py; do python $i --help > doc/$(basename $i .py).rst.txt ; done
Validating the OpenSSL engine
-----------------------------
The directory ``simw-top/sss/plugin/openssl/scripts`` contains validation/test scripts for the OpenSSL
engine on windows and linux platforms. Before executing a validation
script, the secure element must first be provisioned.
The provisioning and validation scripts support multiple interconnects to the Secure Element.
Provisioning
~~~~~~~~~~~~
Assuming a SEO5X is connected on port ``COM1`` execute (from a
Windows cmd prompt, ssscli is used under the hood) ::
-- To provision ECC keys on curve prime256v1
python openssl_provisionEC.py --key_type prime256v1 --connection_data COM1
-- To provision EC montgomory keys on curve x25519
python openssl_provisionEC_mont.py --key_type x25519 --connection_data COM1
-- To provision RSA keys of 1024 bits
python openssl_provisionRSA.py --key_type rsa1024 --connection_data COM1 --- To provision RSA keys
Or, assuming an RJCT server is available on address ``192.168.2.75:8050``
execute (from a cmd prompt, ssscli is used under the hood) ::
python openssl_provisionEC.py --key_type prime256v1 --connection_data 192.168.2.75:8050 jrcpv2
python openssl_provisionEC_mont.py --key_type x25519 --connection_data 192.168.2.75:8050 jrcpv2
python openssl_provisionRSA.py --key_type rsa1024 --connection_data 192.168.2.75:8050 --connection_type jrcpv2
Or, assuming the tests are run on the iMX platform and the SE050 secure element
is connected via I2C ::
python openssl_provisionEC.py --key_type prime256v1
python openssl_provisionEC_mont.py --key_type x25519
python openssl_provisionRSA.py --key_type rsa1024
Validation
~~~~~~~~~~
Run the following scripts for validation (choose an ip_address:port or COM-port argument as appropriate).
To test random number generation ::
python openssl_rnd.py --connection_data COM1
Note: Will also work without first provisioning Secure Element
To test ECC ::
python openssl_EccSign.py --key_type prime256v1 --connection_data COM1
python openssl_Ecdh.py --key_type prime256v1 --connection_data COM1
python openssl_Ecdh_mont.py --key_type x25519 --connection_data COM1
To test RSA ::
python openssl_RSA.py --key_type rsa1024 --connection_data COM1
OR
python openssl_RSA.py --key_type rsa2048 --connection_data COM1
For Negative tests ::
python openssl_EcNegativeTest.py --key_type prime256v1
OpenSSL Engine with Edwards Support
---------------------------------
Refer :numref:`intro-opensslEngine-withEd` for openssl engine with edwards key support.