Skip to content

Commit 16bf733

Browse files
committed
Benchmark for decoder performance (privkey) #454
pemread.c/pemread gets renamed to pkeyread.c/pkeyread The tool can newly benchmak RSA, DSA, DH, DHX, EC, XKEY. Commit also adds genkey.sh shell script. The script is used by Makefile as regen_key_samples target. Makefile saves generated keys into 'keys.h' header file. The geneated keys.h file is committed to minimize build dependencies which would be otherwise introduced by genkey.sh script. To add new key one should update genkey.sh script. Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from #191)
1 parent 58b7b94 commit 16bf733

File tree

6 files changed

+1021
-162
lines changed

6 files changed

+1021
-162
lines changed

perf/Makefile

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
all: randbytes handshake sslnew newrawkey rsasign x509storeissuer providerdoall pemread rwlocks
1+
all: randbytes handshake sslnew newrawkey rsasign x509storeissuer providerdoall rwlocks pkeyread
22

33
clean:
4-
rm libperf.a *.o randbytes handshake sslnew newrawkey rsasign x509storeissuer providerdoall pemread rwlocks
4+
rm libperf.a *.o randbytes handshake sslnew newrawkey rsasign x509storeissuer providerdoall rwlocks pkeyread
55

66
#-Wl,-rpath,$(TARGET_OSSL_LIBRARY_PATH)
77

@@ -34,8 +34,11 @@ x509storeissuer: x509storeissuer.c libperf.a
3434
providerdoall: providerdoall.c libperf.a
3535
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o providerdoall providerdoall.c -lperf -lcrypto
3636

37-
pemread: pemread.c libperf.a
38-
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o pemread pemread.c -lperf -lcrypto
39-
4037
rwlocks: rwlocks.c libperf.a
41-
gcc $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o rwlocks rwlocks.c -lperf -lcrypto
38+
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o rwlocks rwlocks.c -lperf -lcrypto
39+
40+
regen_key_samples:
41+
./genkeys.sh > keys.h
42+
43+
pkeyread: pkeyread.c keys.h libperf.a
44+
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o pkeyread pkeyread.c -lperf -lcrypto

perf/README

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -110,19 +110,24 @@ It does 100000 repetitions divided evenly among each thread. The number of
110110
threads to use is provided as an argument and the test reports the average time
111111
take to execute a block of 1000 OSSL_PROVIDER_do_all() calls.
112112

113-
pemread
114-
-------------
115-
116-
The pemread test repeatedly calls the PEM_read_bio_PrivateKey() function on
117-
a memory BIO with a private RSA key. It does 100000 repetitions divided evenly
118-
among each thread. The number of threads to use is provided as an argument and
119-
the test reports the average time take to execute a block of 1000
120-
PEM_read_bio_PrivateKey() calls.
121-
122113
rwlocks
123114
-------------
124115
the rwlocks test creates the command line specified number of threads, splitting
125116
them evenly between read and write functions (though this is adjustable via the
126117
LOCK_WRITERS environment variable). Threads then iteratively acquire a shared
127118
rwlock to read or update some shared data. The number of read and write
128119
lock/unlock pairs are reported as a performance measurement
120+
121+
pkeyread
122+
--------
123+
124+
The pkeyread test repeatedly calls the PEM_read_bio_PrivateKey() function on a
125+
memory BIO with a private key of desired type, when it is running in pem mode
126+
(-f pem). If test is running in der mode (-f der) it calls to
127+
d2i_PrivateKey_ex() function to repeatedly read private key of desired type.
128+
It does 100000 repetitions divided evenly among each thread. The number of
129+
threads to use is provided by option -t. The test reports average time per
130+
call. Use option -k to select key type for benchmark. The list of keys for
131+
testing is as follows: dh, dhx, dsa, ec, rsa, xkey. To run bencmark for all
132+
keys and formats using 4 threads run pkeyread as follows:
133+
./pkeyread -f all -k all -t 4

perf/genkeys.sh

Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,291 @@
1+
#!/bin/sh
2+
3+
#
4+
# Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
5+
#
6+
# Licensed under the Apache License 2.0 (the "License"). You may not use
7+
# this file except in compliance with the License. You can obtain a copy
8+
# in the file LICENSE in the source distribution or at
9+
# https://www.openssl.org/source/license.html
10+
#
11+
12+
#
13+
# Script generates RSA, X25519, DSA, DH, DHX and EC private keys.
14+
# Keys are saved in PEM and DER formats. Script also converts
15+
# the keys to C-friendly definitions. Each key is saved to ASCIIZ
16+
# format. For example RSA key in PEM format is saved as
17+
# PEM_RSA macro which defines ASCIIZ string. DER_RSA macro
18+
# is created for DER representation of RSA key.
19+
#
20+
# Script also constructs convenient arrays:
21+
# const char sample_keys[][2];
22+
# const char sample_key_sizes[][2];
23+
# We also get constants to navigate in those arrays.
24+
# Constants for selecting keys are as follows:
25+
# SAMPLE_RSA
26+
# SAMPLE_DH
27+
# ...
28+
# SAMPLE_ALL
29+
# SAMPLE_INVALID
30+
# Constants to select PEM/DER format are as follows:
31+
# FORMAT_PEM
32+
# FORMAT_DER
33+
# FORMAT_ALL
34+
# FORMAT_INVALID
35+
#
36+
# There are also arrays sample_names, format_names and evp_pkey_tab so one
37+
# can easily resolve name to number/id and EVP_PKEY_* constant. When adding
38+
# a new key, choose -out option in 'openssl genpkey wisely. The script
39+
# uses filename to derive EVP_PKEYs_ constant. The constant is derived
40+
# using those commands:
41+
# NAME=`basename $FILE`;
42+
# NAME=``echo $NAME|tr '[:lower:]' '[:upper:]'`
43+
# EVP_PKEY=`echo "EVP_PKEY_$NAME," ;
44+
# So for RSA key the filename is rsa.pem. The commands above then will
45+
# produce output EVP_PKEYs_RSA.
46+
#
47+
48+
#
49+
# generate private RSA and X25519 keys. They can not
50+
# be generated using -paramfile
51+
#
52+
# The keys are stored in {rsa,xkey}.{pem,der} files
53+
#
54+
for i in PEM DER ; do
55+
SUFFIX=`echo $i|tr '[:upper:]' '[:lower:]'`
56+
openssl genpkey -algorithm X25519 -out x25519.$SUFFIX -outform $i
57+
done
58+
59+
#
60+
# This is fun part with some historical legacy which dates
61+
# back to 1.1.1. Some details can be found here:
62+
# https://github.com/openssl/openssl/issues/16479
63+
#
64+
# to put story short, trying to do something like this:
65+
# openssl genpkey -algorithm RSA -out rsa.der -outform DER
66+
# is kind of futile for us because d2i_PKCS8_PRIV_KEY_INFO_bio(3)
67+
# then fails to read the key. Some details can be found
68+
# at ticket. ASN.1 is fun.
69+
#
70+
# I've figured possible workaround. We use openssl-pkcs8
71+
# command to convert PEM to DER. All the magic happens
72+
# thanks to -topk8 option.
73+
#
74+
openssl genpkey -algorithm RSA -out rsa.pem -outform PEM
75+
openssl pkcs8 -in rsa.pem -inform PEM -nocrypt -out rsa.der -topk8 -outform DER
76+
77+
#
78+
# generate paramfiles for DSA, DH, DHX and EC keys.
79+
#
80+
openssl genpkey -genparam -algorithm DSA -out dsa-param.pem \
81+
-pkeyopt pbits:2048 -pkeyopt qbits:224
82+
83+
openssl genpkey -genparam -algorithm DH -out dh-param.pem \
84+
-pkeyopt group:ffdhe4096
85+
86+
openssl genpkey -genparam -algorithm DHX -out dhx-param.pem \
87+
-pkeyopt dh_rfc5114:2
88+
89+
openssl genpkey -genparam -algorithm EC -out ec-param.pem \
90+
-pkeyopt ec_paramgen_curve:P-384 -pkeyopt ec_param_enc:named_curve
91+
92+
#
93+
# generate PEM and DER variants for DSA, DH, DHX and EC keys
94+
# keys are stored in files keyname.{pem,der}
95+
#
96+
for i in PEM DER ; do
97+
SUFFIX=`echo $i|tr '[:upper:]' '[:lower:]'`
98+
99+
for j in dsa dh dhx ec ; do
100+
openssl genpkey -paramfile $j-param.pem \
101+
-out $j.$SUFFIX -outform $i;
102+
done
103+
done
104+
105+
#
106+
# DSA and EC keys seem to suffer from the same glitch as RSA.
107+
# Let's ask openssl-pkcs8 to do its magic.
108+
#
109+
rm -f dsa.der
110+
openssl pkcs8 -in dsa.pem -inform PEM -nocrypt -out dsa.der -topk8 -outform DER
111+
rm -f ec.der
112+
openssl pkcs8 -in ec.pem -inform PEM -nocrypt -out ec.der -topk8 -outform DER
113+
114+
rm *-param.pem
115+
116+
cat <<EOF
117+
/*
118+
* Copyright `date +%Y` The OpenSSL Project Authors. All Rights Reserved.
119+
* Licensed under the Apache License 2.0 (the "License"). You may not use
120+
* this file except in compliance with the License. You can obtain a copy
121+
* in the file LICENSE in the source distribution or at
122+
* https://www.openssl.org/source/license.html
123+
*
124+
* !!! D O N O T E D I T !!!
125+
* This file is generated by genkeys.sh script.
126+
*/
127+
128+
EOF
129+
130+
#
131+
# create pem_samples. Define them as C macros.
132+
# The macros will be defined as:
133+
# #define PEM_keyname \
134+
# "line 1" \
135+
# "line 2" \
136+
# ...
137+
# "lome m"
138+
#
139+
for i in *.pem ; do
140+
KEY_NAME=`basename $i .pem | tr '[:lower:]' '[:upper:]'`
141+
echo -n "#define PEM_${KEY_NAME} "
142+
while read -r line ; do
143+
echo "\\\\"
144+
echo -n " \"$line\\\\n\""
145+
done < $i;
146+
echo "\n"
147+
done
148+
149+
#
150+
# to write der format in C-friendly form we need sed to
151+
# post process output of od(1). On non-gnu OSes there are
152+
# usually two sed variants available. We need to pick up
153+
# the gnu variant (gsed). gsed should be default one on Liuxes
154+
#
155+
which gsed > /dev/null
156+
if [ $? -eq 0 ] ; then
157+
SED=gsed
158+
else
159+
SED=sed
160+
fi
161+
162+
#
163+
# der samples are defined as C-macros too. They look like this:
164+
# #define DER_keyname \
165+
# "\x41\x42\x43.... \n" \
166+
# "\x41\x42\x43.... \n"
167+
#
168+
for i in *.der ; do
169+
KEY_NAME=`basename $i .der | tr '[:lower:]' '[:upper:]'`
170+
echo -n "#define DER_${KEY_NAME} "
171+
od -t xC $i | while read -r line ; do
172+
echo "\\\\"
173+
LINE=`echo $line | ${SED} -e 's/\([0-9]\+\)\(.*$\)/\2/g'| \
174+
${SED} -e 's/ *\([a-f0-9][a-f0-f9]\) */\\\\x\1/g' \
175+
-e 's/$/"/'`
176+
echo -n " \"$LINE"
177+
done
178+
echo "\n"
179+
done
180+
181+
#
182+
# Generate array with sample keys. The definition of array
183+
# looks as follows:
184+
# {
185+
# {
186+
# PEM_DH, DER_DH,
187+
# },
188+
# {
189+
# PEM_DHX, DER_DHX,
190+
# },
191+
# ..
192+
# {
193+
# NULL, NULL
194+
# },
195+
# }
196+
echo 'static const char *sample_keys[][2] = {'
197+
for i in *.der ; do
198+
echo ' {'
199+
echo -n ' '
200+
for j in PEM DER ; do
201+
KEY_NAME=`basename $i .der | tr '[:lower:]' '[:upper:]'`
202+
echo -n " ${j}_${KEY_NAME},"
203+
done
204+
echo '\n }',
205+
done
206+
echo ' {'
207+
echo ' NULL, NULL'
208+
echo ' }'
209+
echo '};\n'
210+
211+
#
212+
# Generate array which holds sizes of sample keys.
213+
# the array definition looks as follows:
214+
# {
215+
# {
216+
# { sizeof(DH_PEM) - 1 }, { sizeof(DH_DER) - 1 },
217+
# },
218+
# {
219+
# { sizeof(DHX_PEM) - 1 }, { sizeof(DHX_DER) - 1 },
220+
# },
221+
# ...
222+
# }
223+
#
224+
echo 'static const size_t sample_key_sizes[][2] = {'
225+
for i in *.der ; do
226+
echo -n ' { '
227+
for j in PEM DER ; do
228+
KEY_NAME=`basename $i .der | tr '[:lower:]' '[:upper:]'`
229+
echo -n "\tsizeof(${j}_${KEY_NAME}) - 1,"
230+
done
231+
echo ' },'
232+
done
233+
echo '};\n'
234+
235+
#
236+
# genearate SAMPLE_XXX constants
237+
#
238+
echo 'enum {'
239+
for i in *.der ; do
240+
NAME=`basename $i .der`;
241+
NAME=`echo $NAME|tr '[:lower:]' '[:upper:]'`
242+
echo " SAMPLE_$NAME,"
243+
done
244+
echo ' SAMPLE_ALL,'
245+
echo ' SAMPLE_INVALID'
246+
echo '};\n'
247+
248+
#
249+
# generate array of key sample names.
250+
#
251+
echo 'static const char *sample_names[] = {'
252+
for i in *.der ; do
253+
NAME=`basename $i .der`;
254+
echo " \"$NAME\","
255+
done
256+
echo " \"all\","
257+
echo ' NULL'
258+
echo '};'
259+
260+
#
261+
# generate array of EVP_PKEYs to conveniently
262+
# convert sampe id to EVP_PKEY
263+
#
264+
echo 'static const int evp_pkey_tab[] = {'
265+
for i in *.der ; do
266+
NAME=`basename $i .der`;
267+
NAME=`echo $NAME|tr '[:lower:]' '[:upper:]'`
268+
echo " EVP_PKEY_$NAME," ;
269+
done
270+
echo '};'
271+
272+
#
273+
#
274+
# generate constants for key formats.
275+
#
276+
echo 'enum {'
277+
for i in PEM DER ALL INVALID; do echo " FORMAT_${i},"
278+
done
279+
echo '};\n'
280+
281+
#
282+
# generate array with format names
283+
#
284+
echo 'static const char *format_names[] = {'
285+
for i in pem der all ; do
286+
echo " \"$i\","
287+
done
288+
echo " NULL"
289+
echo '};\n'
290+
291+
rm -f *.pem *.der

0 commit comments

Comments
 (0)