8.1. 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

8.1.1. General

8.1.1.1. OpenSSL versions

The OpenSSL Engine is compatible with OpenSSL versions 1.0.2 or 1.1.1.

8.1.1.2. 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.

8.1.1.3. Platforms

The OpenSSL engine can be used on iMX boards (running Linux) or on Raspberry Pi (running Raspbian).

8.1.2. Keys

8.1.2.1. 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. If the input key is not reference key, execution will roll back to openssl software implementation

8.1.2.2. 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)

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.

8.1.2.3. 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

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.

8.1.3. 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

8.1.4. 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:

8.1.4.1. openssl_rnd.py

usage: openssl_rnd.py [-h] [–connection_data CONNECTION_DATA]

Generate few random numbers from the attached secure element.

optional arguments:
-h, --help

show this help message and exit

--connection_data CONNECTION_DATA

Parameter to connect to SE => eg. COM3, 127.0.0.1:8050, none. Default: none

Example invocation:

python openssl_rnd.py --connection_data 127.0.0.1:8050

8.1.4.2. openssl_provisionEC.py

usage: openssl_provisionEC.py [-h] –key_type KEY_TYPE

[–connection_type CONNECTION_TYPE] [–connection_data CONNECTION_DATA] [–subsystem SUBSYSTEM] [–auth_type AUTH_TYPE] [–scpkey SCPKEY]

Provision attached secure element with EC keys

This example generates a complete set of ECC key files (*.pem) (existing ones overwritten). Performs debug reset the attached secure element. Attached secure element provisioned with EC key. Creates reference key from the injected EC key.

optional arguments:
-h, --help

show this help message and exit

required arguments:
--key_type KEY_TYPE

Supported key types => prime192v1, secp224r1, prime256v1, secp384r1, secp521r1, brainpoolP160r1, brainpoolP192r1, brainpoolP224r1, brainpoolP256r1, brainpoolP320r1, brainpoolP384r1, brainpoolP512r1, secp160k1, secp192k1, secp224k1, secp256k1

optional arguments:
--connection_type CONNECTION_TYPE

Supported connection types => t1oi2c, sci2c, vcom, jrcpv1, jrcpv2, pcsc. Default: t1oi2c

--connection_data CONNECTION_DATA

Parameter to connect to SE => eg. COM3, 127.0.0.1:8050, none. Default: none

--subsystem SUBSYSTEM

Supported subsystem => se050, a71ch, mbedtls. Default: se050

--auth_type AUTH_TYPE

Supported subsystem => None, PlatformSCP, UserID, ECKey, AESKey. Default: None

–scpkey SCPKEY

Example invocation:

python openssl_provisionEC.py --key_type prime256v1
python openssl_provisionEC.py --key_type prime256v1 --connection_data 169.254.0.1:8050
python openssl_provisionEC.py --key_type secp224k1  --connection_type jrcpv2 --connection_data 127.0.0.1:8050
python openssl_provisionEC.py --key_type brainpoolP256r1 --connection_data COM3
python openssl_provisionEC.py --key_type prime256v1 --subsystem a71ch

8.1.4.3. openssl_EccSign.py

usage: openssl_EccSign.py [-h] –key_type KEY_TYPE

[–connection_data CONNECTION_DATA] [–disable_sha1 DISABLE_SHA1]

Validation of Sign Verify with OpenSSL engine using EC Keys

This example showcases sign using reference key, then verify using openssl and vice versa.

Precondition:
  • Inject keys using openssl_provisionEC.py.

optional arguments:
-h, --help

show this help message and exit

required arguments:
--key_type KEY_TYPE

Supported key types => prime192v1, secp224r1, prime256v1, secp384r1, secp521r1, brainpoolP160r1, brainpoolP192r1, brainpoolP224r1, brainpoolP256r1, brainpoolP320r1, brainpoolP384r1, brainpoolP512r1, secp160k1, secp192k1, secp224k1, secp256k1

optional arguments:
--connection_data CONNECTION_DATA

Parameter to connect to SE => eg. COM3, 127.0.0.1:8050, none. Default: none

--disable_sha1 DISABLE_SHA1

Parameter to disable SHA1 => eg. True, False. Default: False

Example invocation:

python openssl_EccSign.py --key_type prime256v1
python openssl_EccSign.py --key_type secp160k1 --connection_data 127.0.0.1:8050

8.1.4.4. openssl_Ecdh.py

usage: openssl_Ecdh.py [-h] –key_type KEY_TYPE

[–connection_data CONNECTION_DATA] [–disable_sha1 DISABLE_SHA1]

Validation of ECDH with OpenSSL engine using EC keys

This example showcases ECDH between openssl engine and openssl.

Precondition:
  • Inject keys using openssl_provisionEC.py.

optional arguments:
-h, --help

show this help message and exit

required arguments:
--key_type KEY_TYPE

Supported key types => prime192v1, secp224r1, prime256v1, secp384r1, secp521r1, brainpoolP160r1, brainpoolP192r1, brainpoolP224r1, brainpoolP256r1, brainpoolP320r1, brainpoolP384r1, brainpoolP512r1, secp160k1, secp192k1, secp224k1, secp256k1

optional arguments:
--connection_data CONNECTION_DATA

Parameter to connect to SE => eg. COM3, 127.0.0.1:8050, none. Default: none

--disable_sha1 DISABLE_SHA1

Parameter to disable SHA1 => eg. True, False. Default: False

Example invocation:

python openssl_Ecdh.py --key_type prime256v1
python openssl_Ecdh.py --key_type secp160k1 --connection_data 127.0.0.1:8050

8.1.4.5. ecc_all.py

usage: ecc_all.py [-h] [–connection_type CONNECTION_TYPE]

[–connection_data CONNECTION_DATA] [–subsystem SUBSYSTEM] [–auth_type AUTH_TYPE] [–scpkey SCPKEY] [–disable_sha1 DISABLE_SHA1] [–fips FIPS]

Validation of OpenSSL Engine using EC keys

This example injects keys with different supported EC Curves, then showcases ECDH & ECDSA using those keys.

optional arguments:
-h, --help

show this help message and exit

--connection_type CONNECTION_TYPE

Supported connection types => t1oi2c, sci2c, vcom, jrcpv1, jrcpv2, pcsc. Default: t1oi2c

--connection_data CONNECTION_DATA

Parameter to connect to SE => eg. COM3, 127.0.0.1:8050, none. Default: none

--subsystem SUBSYSTEM

Supported subsystem => se051, se050, a71ch. Default: se050

--auth_type AUTH_TYPE

Supported subsystem => None, PlatformSCP, UserID, ECKey, AESKey. Default: None

–scpkey SCPKEY –disable_sha1 DISABLE_SHA1

Parameter to disable SHA1 => eg. True, False. Default: False

--fips FIPS

FIPS Testing => eg. True, False. Default: False

Example invocation:

python ecc_all.py
python ecc_all.py --connection_data 169.254.0.1:8050
python ecc_all.py --connection_data 127.0.0.1:8050 --connection_type jrcpv2
python ecc_all.py --connection_data COM3

8.1.4.6. openssl_provisionRSA.py

usage: openssl_provisionRSA.py [-h] –key_type KEY_TYPE

[–connection_type CONNECTION_TYPE] [–connection_data CONNECTION_DATA] [–subsystem SUBSYSTEM] [–auth_type AUTH_TYPE] [–scpkey SCPKEY]

Provision attached secure element with RSA keys

This example generates a complete set of RSA key files (*.pem) (existing ones overwritten). Performs debug reset the attached secure element. Attached secure element provisioned with RSA key. Creates reference key from the injected RSA key.

optional arguments:
-h, --help

show this help message and exit

required arguments:
--key_type KEY_TYPE

Supported key types => rsa1024, rsa2048, rsa3072, rsa4096

optional arguments:
--connection_type CONNECTION_TYPE

Supported connection types => t1oi2c, sci2c, vcom, jrcpv1, jrcpv2, pcsc. Default: t1oi2c

--connection_data CONNECTION_DATA

Parameter to connect to SE => eg. COM3, 127.0.0.1:8050, none. Default: none

--subsystem SUBSYSTEM

Supported subsystem => se050, mbedtls. Default: se050

--auth_type AUTH_TYPE

Supported subsystem => None, PlatformSCP, UserID, ECKey, AESKey. Default: None

–scpkey SCPKEY

Example invocation:

python openssl_provisionRSA.py --key_type rsa1024
python openssl_provisionRSA.py --key_type rsa2048 --connection_data 169.254.0.1:8050
python openssl_provisionRSA.py --key_type rsa2048 --connection_data 127.0.0.1:8050 --connection_type jrcpv2
python openssl_provisionRSA.py --key_type rsa2048 --connection_data COM3

8.1.4.7. openssl_RSA.py

usage: openssl_RSA.py [-h] –key_type KEY_TYPE

[–connection_data CONNECTION_DATA] [–disable_sha1 DISABLE_SHA1]

Validation of OpenSSL Engine using RSA keys

This example showcases crypto operations and sign verify operations using RSA keys.

optional arguments:
-h, --help

show this help message and exit

required arguments:
--key_type KEY_TYPE

Supported key types => rsa1024, rsa2048, rsa3072, rsa4096

optional arguments:
--connection_data CONNECTION_DATA

Parameter to connect to SE => eg. COM3, 127.0.0.1:8050, none. Default: none

--disable_sha1 DISABLE_SHA1

Parameter to disable SHA1 => eg. True, False. Default: False

Example invocation:

python openssl_RSA.py --key_type rsa2048
python openssl_RSA.py --key_type rsa4096 --connection_data 127.0.0.1:8050

8.1.4.8. rsa_all.py

usage: rsa_all.py [-h] [–connection_data CONNECTION_DATA]

[–connection_type CONNECTION_TYPE] [–subsystem SUBSYSTEM] [–auth_type AUTH_TYPE] [–scpkey SCPKEY] [–disable_sha1 DISABLE_SHA1] [–fips FIPS]

Validation of OpenSSL Engine using RSA keys

This example injects keys with different supported RSA keys, then showcases Crypto & sign verify operations using those keys.

optional arguments:
-h, --help

show this help message and exit

--connection_data CONNECTION_DATA

Parameter to connect to SE => eg. COM3, 127.0.0.1:8050, none. Default: none

--connection_type CONNECTION_TYPE

Supported connection types => t1oi2c, sci2c, vcom, jrcpv1, jrcpv2, pcsc. Default: t1oi2c

--subsystem SUBSYSTEM

Supported subsystem => se050. Default: se050

--auth_type AUTH_TYPE

Supported subsystem => None, PlatformSCP, UserID, ECKey, AESKey. Default: None

–scpkey SCPKEY –disable_sha1 DISABLE_SHA1

Parameter to disable SHA1 => eg. True, False. Default: False

--fips FIPS

FIPS Testing => eg. True, False. Default: False

Example invocation:

python rsa_all.py
python rsa_all.py --connection_data 169.254.0.1:8050
python rsa_all.py --connection_data 127.0.0.1:8050 --connection_type jrcpv2
python rsa_all.py --connection_data COM3

8.1.4.9. openssl_provisionEC_mont.py

usage: openssl_provisionEC_mont.py [-h] –key_type KEY_TYPE

[–connection_type CONNECTION_TYPE] [–connection_data CONNECTION_DATA] [–subsystem SUBSYSTEM] [–auth_type AUTH_TYPE] [–scpkey SCPKEY]

Provision attached secure element with EC montogomery keys

This example generates EC montogomery key files (*.pem) (existing ones overwritten). Performs debug reset the attached secure element. Attached secure element provisioned with EC montogomery key. Creates reference key from the injected EC montogomery key.

optional arguments:
-h, --help

show this help message and exit

required arguments:
--key_type KEY_TYPE

Supported key types => x25519, x448

optional arguments:
--connection_type CONNECTION_TYPE

Supported connection types => t1oi2c, sci2c, vcom, jrcpv1, jrcpv2, pcsc. Default: t1oi2c

--connection_data CONNECTION_DATA

Parameter to connect to SE => eg. COM3, 127.0.0.1:8050, none. Default: none

--subsystem SUBSYSTEM

Supported subsystem => se050, a71ch, mbedtls. Default: se050

--auth_type AUTH_TYPE

Supported subsystem => None, PlatformSCP, UserID, ECKey, AESKey. Default: None

–scpkey SCPKEY

Example invocation:

python openssl_provisionEC_mont.py --key_type x25519
python openssl_provisionEC_mont.py --key_type x25519 --connection_data 169.254.0.1:8050
python openssl_provisionEC_mont.py --key_type x448  --connection_type jrcpv2 --connection_data 127.0.0.1:8050
python openssl_provisionEC_mont.py --key_type x448 --connection_data COM3

8.1.4.10. openssl_Ecdh_mont.py

usage: openssl_Ecdh_mont.py [-h] –key_type KEY_TYPE

[–connection_type CONNECTION_TYPE] [–connection_data CONNECTION_DATA]

Validation of Montgomery ECDH with OpenSSL engine using EC mont keys

This example showcases montogomery ECDH between openssl engine and openssl.

Precondition:
  • Inject keys using openssl_provisionEC_mont.py.

optional arguments:
-h, --help

show this help message and exit

required arguments:
--key_type KEY_TYPE

Supported key types => x25519, x448

optional arguments:
--connection_type CONNECTION_TYPE

Supported connection types => t1oi2c, sci2c, vcom, jrcpv1, jrcpv2, pcsc. Default: t1oi2c

--connection_data CONNECTION_DATA

Parameter to connect to SE => eg. COM3, 127.0.0.1:8050, none. Default: none

Example invocation:

python openssl_Ecdh_mont.py --key_type x448
python openssl_Ecdh_mont.py --key_type x25519 --connection_type jrcpv2 --connection_data 127.0.0.1:8050