Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for openssl PKCS#11 engine to openssl_posix.c #1780

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
18 changes: 15 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -65,16 +65,28 @@ set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin )
set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )

if(DEFINED ROOT_CA_CERT_PATH)
string(REPLACE ";" "\\$<SEMICOLON>" ROOT_CA_CERT_PATH "${ROOT_CA_CERT_PATH}")
endif()

if(DEFINED CLIENT_CERT_PATH)
string(REPLACE ";" "\\$<SEMICOLON>" CLIENT_CERT_PATH "${CLIENT_CERT_PATH}")
endif()

if(DEFINED CLIENT_PRIVATE_KEY_PATH)
string(REPLACE ";" "\\$<SEMICOLON>" CLIENT_PRIVATE_KEY_PATH "${CLIENT_PRIVATE_KEY_PATH}")
endif()

# Set prefix to PWD if any path flags are relative.
# PWD is set to the path where you run the cmake command.
if(DEFINED ENV{PWD})
if(ROOT_CA_CERT_PATH AND NOT IS_ABSOLUTE ${ROOT_CA_CERT_PATH})
if(DEFINED ROOT_CA_CERT_PATH AND NOT ROOT_CA_CERT_PATH MATCHES "^pkcs11.+$" AND NOT IS_ABSOLUTE ${ROOT_CA_CERT_PATH})
set(ROOT_CA_CERT_PATH "$ENV{PWD}/${ROOT_CA_CERT_PATH}")
endif()
if(CLIENT_CERT_PATH AND NOT IS_ABSOLUTE ${CLIENT_CERT_PATH})
if(DEFINED CLIENT_CERT_PATH AND NOT CLIENT_CERT_PATH MATCHES "^pkcs11.+$" AND NOT IS_ABSOLUTE ${CLIENT_CERT_PATH})
set(CLIENT_CERT_PATH "$ENV{PWD}/${CLIENT_CERT_PATH}")
endif()
if(CLIENT_PRIVATE_KEY_PATH AND NOT IS_ABSOLUTE ${CLIENT_PRIVATE_KEY_PATH})
if(DEFINED CLIENT_PRIVATE_KEY_PATH AND NOT CLIENT_PRIVATE_KEY_PATH MATCHES "^pkcs11.+$" AND NOT IS_ABSOLUTE ${CLIENT_PRIVATE_KEY_PATH})
set(CLIENT_PRIVATE_KEY_PATH "$ENV{PWD}/${CLIENT_PRIVATE_KEY_PATH}")
endif()
endif()
Expand Down
149 changes: 149 additions & 0 deletions docs/README_openssl_pkcs11.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# Install Prerequisites
Install the prerequisites for using openssl with the libp11 pkcs11 engine:
```
sudo apt install softhsm2 gnutls-bin openssl libengine-pkcs11-openssl libp11-kit0 libp11-kit-dev p11-kit p11-kit-modules
```

[SoftHSM2](https://github.com/opendnssec/SoftHSMv2) is used as the pkcs11 module in this documentation. It should be replaced with the actual pkcs11 module you plan to use in production.

If running softhsm on a linux system, be sure to add your user to the "softhsm" group and log-out/log-in if required by your distribution.
```
sudo adduser $(whoami) softhsm
```

# Initialize token and list objects
List existing tokens:
```
export GNUTLS_SO_PIN=0000
export GNUTLS_PIN=0000
p11tool --login --list-all
```

## SoftHSM2
SoftHSM2 is used as an example PKCS#11 module for testing purposes. Depending on your device security model, it may or may not be suitable for use in produiction.


Delete any existing tokens if desired:
```
softhsm2-util --delete-token --token default
```
Initalize a new token:
```
softhsm2-util --init-token --free --label default --pin 0000 --so-pin 0000
```

Check that the new token is accessible:
```
softhsm2-util --show-slots
```

When using p11-kit-proxy, SoftHSM should be automatically detected by the openssl pkcs11 engine.

## p11-kit-trust
P11-Kit includes a Turst Policy module which exposes the trusted CA certificates installed on a system via PKCS#11.

Note: By default, this module has the "disable-in: p11-kit-proxy" configuration option set. This will cause p11-kit-proxy to disregard this module altogether. If you plan to use PKCS#11 to access to the system trust store, you may want to disable this confgiuration option to allow access to both the system trust store and the PKCS11 module containing your private key.

## Microchip CryptoAuthLib for ECC608
[cryptoauthlib](https://github.com/MicrochipTech/cryptoauthlib)

## p11-kit-proxy
On linux systems, it is quite common to use the [p11-kit-proxy](https://p11-glue.github.io/p11-glue/p11-kit.html) PKCS#11 module to arbitrate access to one or more other PKCS#11 modules from one or more threads.

p11-kit and other p11-kit aware packages install default "module" configuration files in /usr/share/p11-kit/modules/. p11-kit also searches /etc/pkcs11/modules and ~/.config/pkcs11/modules for additional user-defined module configurations.

The Openssl PKCS#11 module is configured to use p11-kit-proxy by default in most linux distributions.

# Generate a new Key
Generate a new public/private key pair if one has not been pre-provisioned in your hsm.
ECC/ECDSA keys typically have a lower computational overhead, so are preferred on low-resource devices.
Generate either an RSA or ECDSA key.

## Delete any existing key objects
```
yes | p11tool --login --delete "pkcs11:object=aws_iot_pk"
```
## RSA
```
p11tool --login --generate-rsa --bits 2048 --label "aws_iot_pk" pkcs11:token=default
```
## ECC / ECDSA
```
p11tool --login --generate-ecc --curve secp256r1 --label "aws_iot_pk" pkcs11:token=default
```

# Generate and register a certificate
A certificate can be generated in any of the three ways listed in the following sections. Choose the option that best fits your device provisioning strategy.

## Self-Signed Certificate
```
openssl req -new -x509 -subj '/CN=TestIotDevice01/' -days 30 -sha256 -engine pkcs11 -keyform engine -key "pkcs11:object=aws_iot_pk" -outform pem -out aws_iot_pk.crt -passin pass:0000
```
Review the contents of the self-signed certificate:
```
openssl x509 -in aws_iot_pk.crt -noout -text
```
Register the self-signed certificate with AWS IoT Core
```
aws iot register-certificate-without-ca --status=ACTIVE --certificate-pem file://aws_iot_pk.crt
```
## Certificate Signed by a private CA registered with IoT Core
Follow the guides listed below to generate a new Certificate Authority and register that CA with AWS IoT Core.

[Generate a new CA](https://docs.aws.amazon.com/iot/latest/developerguide/create-your-CA-cert.html)

[Register your new CA with AWS IoT Core](https://docs.aws.amazon.com/iot/latest/developerguide/register-CA-cert.html)

Generate a new CSR
```
openssl req -new -subj '/CN=TestIotDevice01/' -sha256 -engine pkcs11 -keyform engine -key "pkcs11:object=aws_iot_pk" -outform pem -out aws_iot_pk.csr -passin pass:0000
```
View the contents of the generated CSR
```
openssl x509 -in aws_iot_pk.csr -noout -text
```
Issue a Certificate from you CA

Follow the instructions for your particular CA managerment software or using something similar to the openssl command below:
```
openssl x509 -req \
-in device_cert_csr_filename \
-CA root_CA_pem_filename \
-CAkey root_CA_key_filename \
-CAcreateserial \
-out device_cert_pem_filename \
-days 500 -sha256
```

## Certificate Signed by AWS IoT Core
Generate a new CSR
```
openssl req -new -subj '/CN=TestIotDevice01/' -sha256 -engine pkcs11 -keyform engine -key "pkcs11:object=aws_iot_pk" -outform pem -out aws_iot_pk.csr -passin pass:0000
```
View the contents of the generated CSR
```
openssl x509 -in aws_iot_pk.csr -noout -text
```
Submit the CSR to IoT Core, receive the new certificate and register it via the aws cli
```
aws iot create-certificate-from-csr --set-as-active --certificate-signing-request file://aws_iot_pk.csr --certificate-pem-outfile aws_iot_pk.crt
```

# Import certificate back into HSM
Next, import the generated certificate back into your HSM / pkcs11 module:
```
p11tool --login --load-certificate=aws_iot_pk.crt --write --label=aws_iot_pk "pkcs11:token=default"
```

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Steps are missing or its not clear how to add/get Amazon Root CA or private rootCA from system trust store.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They're automatically included by the OS.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See https://p11-glue.github.io/p11-glue/p11-kit/manual/trust-module.html for more information.

I'll add a note similar to:

You can confirm this with the follow cli command:

p11tool --list-all-certs pkcs11:token=System%20Trust | grep Amazon\ Root\ CA

# Build the C-SDK demos:

Use a cmake command similar to the one listed below to build the desired demos:

```
cmake -B build2 -DBUILD_DEMOS=1 -DBUILD_TESTS=0 \
-DAWS_IOT_ENDPOINT="XXXXXXXXXXXXXX-ats.iot.XX-XXXX-X.amazonaws.com" \
-DCLIENT_CERT_PATH="pkcs11:token=default;object=aws_iot_pk" \
-DCLIENT_PRIVATE_KEY_PATH="pkcs11:token=default;object=aws_iot_pk?pin-value=0000" \
-DROOT_CA_CERT_PATH="pkcs11:token=System%20Trust;object=Amazon%20Root%20CA%201" \
-DBUILD_CLONE_SUBMODULES=0
```
22 changes: 7 additions & 15 deletions platform/lexicon.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ basedefs
bio
bitmasking
blocksize
blocksize
bool
bootable
bootloader
Expand All @@ -35,7 +34,6 @@ clienthello
cmock
com
config
config
connectsuccessindex
const
corehttp
Expand Down Expand Up @@ -104,7 +102,6 @@ int
io
iot
ip
ip
keytype
lfilecloseresult
linux
Expand Down Expand Up @@ -147,7 +144,6 @@ otaimagestateaccepted
otaimagestateinvalid
otaimagestatependingcommit
otaimagestaterejected
otaimagestaterejected
otaimagestatetesting
otaimagestateunknown
otalastimagestate
Expand All @@ -168,20 +164,12 @@ otapalimagestatependingcommit
otapalimagestateunknown
otapalimagestatevalid
otapalnullfilecontext
otapalnullfilecontext
otapaloutofmemory
otapaloutofmemory
otapalrejectfailed
otapalrejectfailed
otapalrxfilecreatefailed
otapalrxfilecreatefailed
otapalrxfiletoolarge
otapalrxfiletoolarge
otapalsignaturecheckfailed
otapalsignaturecheckfailed
otapalsuccess
otapalsuccess
otapaluninitialized
otapaluninitialized
paddrinfo
palpnprotos
Expand All @@ -191,16 +179,17 @@ pbuffer
pcdata
pcertfilepath
pcertificatecontext
pcerturi
pclientcertlabel
pclientcertpath
pclientcerturi
pcontext
pctx
pdata
pdata
pem
pengine
pfile
pfilecontext
pfilecontext
pfilepath
pformat
phash
Expand All @@ -209,7 +198,6 @@ pkcs
plabelname
plaintext
platformimagestate
platformimagestate
plisthead
pnetworkcontext
png
Expand All @@ -218,10 +206,12 @@ pollpri
popensslcredentials
popensslparams
posix
ppengine
ppkey
pplatformimagestate
pprivatekeylabel
pprivatekeypath
pprivatekeyuri
prandom
pre
pretryparams
Expand All @@ -230,6 +220,7 @@ privkeyinfo
prng
prngcontext
prootcapath
prootcauri
pserverinfo
psig
psiglen
Expand Down Expand Up @@ -300,6 +291,7 @@ ulblockindex
ulblocksize
uloffset
unistd
uri
utest
utils
v1
Expand Down
8 changes: 4 additions & 4 deletions platform/posix/transport/include/openssl_posix.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
* implementation that uses OpenSSL and POSIX sockets.
*
* @note For this transport implementation, the socket descriptor and
* SSL context is used.
* SSL context are kept.
*/
typedef struct OpensslParams
{
Expand Down Expand Up @@ -135,9 +135,9 @@ typedef struct OpensslCredentials
*
* @note These strings must be NULL-terminated because the OpenSSL API requires them to be.
*/
const char * pRootCaPath; /**< @brief Filepath string to the trusted server root CA. */
const char * pClientCertPath; /**< @brief Filepath string to the client certificate. */
const char * pPrivateKeyPath; /**< @brief Filepath string to the client certificate's private key. */
const char * pRootCaPath; /**< @brief File path or PKCS#11 URI to the trusted server root CA certificate. */
const char * pClientCertPath; /**< @brief File path or PKCS#11 URI to the tls client certificate. */
const char * pPrivateKeyPath; /**< @brief File path or PKCS#11 URI to the tls client private key. */
} OpensslCredentials_t;

/**
Expand Down
Loading