Skip to content

Commit 05daee9

Browse files
authored
Merge pull request #618 from dgarske/optee_pkcs11
Add PKCS11 OP-TEE token support with a PKCS#11 token initialization example
2 parents 219ba67 + 28a6f5b commit 05daee9

6 files changed

Lines changed: 506 additions & 3 deletions

File tree

pkcs11/Makefile

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
CC = gcc
33
WOLFSSL_INSTALL_DIR = /usr/local
44
CFLAGS = -Wall -I$(WOLFSSL_INSTALL_DIR)/include
5-
LIBS = -L$(WOLFSSL_INSTALL_DIR)/lib -lm
5+
# -ldl for pkcs11_inittoken, which dlopen()s the PKCS#11 library. Harmless
6+
# on glibc >= 2.34 where libdl is merged into libc, required on older ones.
7+
LIBS = -L$(WOLFSSL_INSTALL_DIR)/lib -lm -ldl
68

79
# option variables
810
DYN_LIB = -lwolfssl
@@ -11,9 +13,28 @@ DEBUG_FLAGS = -g -DDEBUG
1113
DEBUG_INC_PATHS = -MD
1214
OPTIMIZE = -Os
1315

16+
# WC_ECC_FLAG_DERIVE is an enum member, not a macro, so the preprocessor cannot
17+
# test for it - and a version check cannot either, because wolfSSL master and
18+
# v5.9.2-stable both report LIBWOLFSSL_VERSION_HEX 0x05009002. Probe by
19+
# compiling against the installed headers instead, which is accurate on any
20+
# release, snapshot or git build.
21+
# Skipped for goals that never compile C, so "make clean" does not spawn a
22+
# throwaway compile - which would also fail noisily where wolfSSL is absent.
23+
ifeq ($(filter clean,$(MAKECMDGOALS)),)
24+
HAVE_ECC_FLAG_DERIVE := $(shell printf '%s\n' \
25+
'#include <wolfssl/options.h>' \
26+
'#include <wolfssl/wolfcrypt/ecc.h>' \
27+
'int main(void){return (int)WC_ECC_FLAG_DERIVE;}' \
28+
| $(CC) -I$(WOLFSSL_INSTALL_DIR)/include -x c - -o /dev/null 2>/dev/null \
29+
&& echo yes)
30+
endif
31+
1432
# Options
1533
#CFLAGS+=$(DEBUG_FLAGS)
1634
CFLAGS+=$(OPTIMIZE)
35+
ifeq ($(HAVE_ECC_FLAG_DERIVE),yes)
36+
CFLAGS+=-DHAVE_WC_ECC_FLAG_DERIVE
37+
endif
1738
#LIBS+=$(STATIC_LIB) -ldl -lm
1839
LIBS+=$(DYN_LIB)
1940

pkcs11/README.md

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,114 @@ See [PKCS11.md](./PKCS11.md) in this folder.
159159
It should be noted WOLFSSL_PKCS11_RW_TOKENS is only needed for adding the keys and certs to the store. Once already in the store this is no longer needed.
160160
161161
162+
## Setting up and testing OP-TEE
163+
164+
[OP-TEE](https://optee.readthedocs.io/) provides a PKCS #11 trusted
165+
application, so private keys can be generated and used inside the TrustZone
166+
secure world and never appear in normal-world memory. This has been tested on
167+
an NXP i.MX95 running OP-TEE 4.4, but nothing here is board specific.
168+
169+
1. Build OP-TEE with the PKCS #11 trusted application
170+
171+
The TA is not in every OP-TEE build. Enable it with `CFG_PKCS11_TA=y` and
172+
install the resulting `fd02c9da-306c-48c7-a49c-bbd827ae86ee.ta` where
173+
`tee-supplicant` looks for TAs. You also need the `optee_client` userspace:
174+
`tee-supplicant`, `libteec.so.2` and `libckteec.so.0`.
175+
176+
2. Make sure `tee-supplicant` is running
177+
178+
Every PKCS #11 call fails at `C_Initialize` without it, because the TA
179+
cannot be loaded. If the libraries are not in the default library path,
180+
point the loader at them:
181+
182+
```
183+
export LD_LIBRARY_PATH=/path/to/optee/lib
184+
tee-supplicant -l /path/to/ta/dir &
185+
```
186+
187+
3. Change to wolfssl directory
188+
189+
```
190+
./autogen.sh
191+
./configure --enable-pkcs11 --enable-cryptocb-rsa-pad
192+
make
193+
sudo make install
194+
```
195+
196+
`--enable-cryptocb-rsa-pad` matters. Without it wolfSSL asks the token for
197+
raw RSA (`CKM_RSA_X_509`), which OP-TEE's TA does not implement, and RSA
198+
private key operations fail with `RSA_BUFFER_E` (-131). With it wolfSSL
199+
uses `CKM_RSA_PKCS` and the RSA examples pass. The same applies to any
200+
token that declines raw RSA.
201+
202+
4. Change to wolfssl-examples/pkcs11 directory and build
203+
204+
```
205+
make
206+
```
207+
208+
5. Initialize the token and run the examples
209+
210+
OP-TEE tokens come up uninitialized and OP-TEE ships no equivalent of
211+
`softhsm2-util`, so `pkcs11_inittoken` does it through the PKCS #11 API:
212+
213+
```
214+
./optee-init.sh
215+
```
216+
217+
That initializes slot 0 and then runs the examples. To use a different
218+
slot, label or PIN:
219+
220+
```
221+
OPTEE_TOKEN=myToken OPTEE_PIN=1234 ./optee-init.sh 1
222+
```
223+
224+
Once the token is initialized, run the examples on their own with:
225+
226+
```
227+
./optee.sh
228+
```
229+
230+
Or a single example directly, with the usual argument order:
231+
232+
```
233+
./pkcs11_genecc libckteec.so.0 0 wolfSSL cryptoki
234+
```
235+
236+
### EC keys that both derive and sign
237+
238+
`pkcs11_test` generates a single EC key and then uses it for both ECDH and
239+
ECDSA. PKCS #11 leaves the defaults for `CKA_DERIVE` and `CKA_SIGN` up to the
240+
token: SoftHSM grants both regardless of the template, while OP-TEE grants only
241+
what was asked for.
242+
243+
The examples therefore request both explicitly:
244+
245+
```c
246+
wc_ecc_make_key_ex2(&rng, 32, key, ECC_CURVE_DEF, EC_KEYGEN_FLAGS);
247+
```
248+
249+
`EC_KEYGEN_FLAGS` is `WC_ECC_FLAG_DEC_SIGN | WC_ECC_FLAG_DERIVE` when the
250+
installed wolfSSL has `WC_ECC_FLAG_DERIVE`, and `WC_ECC_FLAG_DEC_SIGN` alone
251+
when it does not. No edit is needed either way: the Makefile probes for the
252+
flag by compiling against the installed headers and defines
253+
`HAVE_WC_ECC_FLAG_DERIVE` when it is present.
254+
255+
The probe exists because neither of the usual tests works here.
256+
`WC_ECC_FLAG_DERIVE` is an enum member rather than a macro, so `#ifdef` cannot
257+
see it, and a version test cannot distinguish the two cases either, because
258+
wolfSSL master and v5.9.2-stable both report `LIBWOLFSSL_VERSION_HEX`
259+
`0x05009002`.
260+
261+
Against a wolfSSL without the flag the key is generated sign-only, which is all
262+
that library can request. `pkcs11_test` then fails on a strict token - the
263+
OP-TEE TA among them - at the first ECDH operation with
264+
`CKR_KEY_FUNCTION_NOT_PERMITTED`, surfacing as `WC_HW_E` (-248). Tokens that
265+
enable `CKA_DERIVE` by default are unaffected.
266+
267+
All the examples pass, including RSA key generation, ECDSA, ECDH, AES-CBC,
268+
AES-GCM, HMAC and RNG.
269+
162270
## TLS Server Example with SoftHSM (RSA)
163271

164272
The example `server-tls-pkcs11` is a server that uses a private key that has been stored on the PKCS #11 device.

pkcs11/optee-init.sh

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#!/bin/sh
2+
3+
# Initialize an OP-TEE PKCS#11 token and then run the examples against it.
4+
#
5+
# OP-TEE tokens come up uninitialized and OP-TEE ships no equivalent of
6+
# softhsm2-util, so pkcs11_inittoken does it through the PKCS#11 API. Re-running
7+
# this is safe: an already-initialized token is left alone.
8+
9+
set -e
10+
11+
cd "$(dirname "$0")"
12+
13+
# Same argument convention as optee.sh: an optional slot id first, then any
14+
# specific examples to run.
15+
# Only treat the first argument as a slot id if it is numeric, so that
16+
# "./optee-init.sh pkcs11_rsa" runs one example against the default slot instead of
17+
# silently consuming the example name as a slot id.
18+
case "${1:-}" in
19+
'' | *[!0-9]* ) ;;
20+
* ) OPTEE_SLOTID=$1; shift ;;
21+
esac
22+
23+
if [ -z "$OPTEE_LIB" ]
24+
then
25+
OPTEE_LIB=libckteec.so.0
26+
fi
27+
if [ -z "$OPTEE_SLOTID" ]
28+
then
29+
OPTEE_SLOTID=0
30+
fi
31+
if [ -z "$OPTEE_TOKEN" ]
32+
then
33+
OPTEE_TOKEN=wolfSSL
34+
fi
35+
if [ -z "$OPTEE_SOPIN" ]
36+
then
37+
OPTEE_SOPIN=cryptoki
38+
fi
39+
if [ -z "$OPTEE_PIN" ]
40+
then
41+
OPTEE_PIN=cryptoki
42+
fi
43+
44+
./pkcs11_inittoken "$OPTEE_LIB" "$OPTEE_SLOTID" "$OPTEE_TOKEN" \
45+
"$OPTEE_SOPIN" "$OPTEE_PIN"
46+
47+
OPTEE_LIB="$OPTEE_LIB" OPTEE_TOKEN="$OPTEE_TOKEN" OPTEE_PIN="$OPTEE_PIN" \
48+
exec ./optee.sh "$OPTEE_SLOTID" "$@"

pkcs11/optee.sh

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#!/bin/sh
2+
3+
# Run the PKCS#11 examples against OP-TEE's PKCS#11 trusted application.
4+
#
5+
# The token must already be initialized - use ./optee-init.sh for that.
6+
#
7+
# Requires tee-supplicant to be running; without it every call fails at
8+
# C_Initialize because the TA cannot be loaded.
9+
10+
# Only treat the first argument as a slot id if it is numeric, so that
11+
# "./optee.sh pkcs11_rsa" runs one example against the default slot instead of
12+
# silently consuming the example name as a slot id.
13+
case "${1:-}" in
14+
'' | *[!0-9]* ) ;;
15+
* ) OPTEE_SLOTID=$1; shift ;;
16+
esac
17+
18+
# OP-TEE's PKCS#11 client library. It is usually installed as a normal shared
19+
# library, but on an embedded rootfs it is often staged elsewhere, in which
20+
# case set OPTEE_LIB (and LD_LIBRARY_PATH) to point at it.
21+
if [ -z "$OPTEE_LIB" ]
22+
then
23+
OPTEE_LIB=libckteec.so.0
24+
fi
25+
26+
if [ -z "$OPTEE_SLOTID" ]
27+
then
28+
OPTEE_SLOTID=0
29+
fi
30+
if [ -z "$OPTEE_TOKEN" ]
31+
then
32+
OPTEE_TOKEN=wolfSSL
33+
fi
34+
if [ -z "$OPTEE_PIN" ]
35+
then
36+
OPTEE_PIN=cryptoki
37+
fi
38+
39+
rc=0
40+
41+
run_example()
42+
{
43+
name=$1
44+
shift
45+
echo
46+
echo "# $name"
47+
if ! "$@" "$OPTEE_LIB" "$OPTEE_SLOTID" "$OPTEE_TOKEN" "$OPTEE_PIN"
48+
then
49+
echo "# FAILED: $name"
50+
rc=1
51+
fi
52+
}
53+
54+
echo "# Using slot ID: $OPTEE_SLOTID"
55+
echo "# Using library: $OPTEE_LIB"
56+
echo "# Using token: $OPTEE_TOKEN"
57+
58+
if [ $# -gt 0 ]
59+
then
60+
for example in "$@"
61+
do
62+
run_example "$example" "./$example"
63+
done
64+
else
65+
run_example "RSA example" ./pkcs11_rsa
66+
run_example "ECC example" ./pkcs11_ecc
67+
run_example "Generate ECC example" ./pkcs11_genecc
68+
run_example "AES-GCM example" ./pkcs11_aesgcm
69+
run_example "AES-CBC example" ./pkcs11_aescbc
70+
run_example "HMAC example" ./pkcs11_hmac
71+
run_example "Random Number Generation example" ./pkcs11_rand
72+
run_example "PKCS#11 test" ./pkcs11_test
73+
fi
74+
75+
echo
76+
if [ $rc -eq 0 ]
77+
then
78+
echo "# All PKCS#11 examples passed"
79+
else
80+
echo "# One or more PKCS#11 examples FAILED"
81+
fi
82+
83+
exit $rc

0 commit comments

Comments
 (0)