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