mkcert.sh 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. #! /bin/bash
  2. #
  3. # Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved.
  4. # Copyright (c) 2016 Viktor Dukhovni <openssl-users@dukhovni.org>.
  5. # All rights reserved.
  6. #
  7. # Licensed under the OpenSSL license (the "License"). You may not use
  8. # this file except in compliance with the License. You can obtain a copy
  9. # in the file LICENSE in the source distribution or at
  10. # https://www.openssl.org/source/license.html
  11. # This file is dual-licensed and is also available under other terms.
  12. # Please contact the author.
  13. # 100 years should be enough for now
  14. if [ -z "$DAYS" ]; then
  15. DAYS=36525
  16. fi
  17. if [ -z "$OPENSSL_SIGALG" ]; then
  18. OPENSSL_SIGALG=sha256
  19. fi
  20. if [ -z "$REQMASK" ]; then
  21. REQMASK=utf8only
  22. fi
  23. stderr_onerror() {
  24. (
  25. err=$("$@" >&3 2>&1) || {
  26. printf "%s\n" "$err" >&2
  27. exit 1
  28. }
  29. ) 3>&1
  30. }
  31. key() {
  32. local key=$1; shift
  33. local alg=rsa
  34. if [ -n "$OPENSSL_KEYALG" ]; then
  35. alg=$OPENSSL_KEYALG
  36. fi
  37. local bits=2048
  38. if [ -n "$OPENSSL_KEYBITS" ]; then
  39. bits=$OPENSSL_KEYBITS
  40. fi
  41. if [ ! -f "${key}.pem" ]; then
  42. args=(-algorithm "$alg")
  43. case $alg in
  44. rsa) args=("${args[@]}" -pkeyopt rsa_keygen_bits:$bits );;
  45. ec) args=("${args[@]}" -pkeyopt "ec_paramgen_curve:$bits")
  46. args=("${args[@]}" -pkeyopt ec_param_enc:named_curve);;
  47. dsa) args=(-paramfile "$bits");;
  48. ed25519) ;;
  49. ed448) ;;
  50. *) printf "Unsupported key algorithm: %s\n" "$alg" >&2; return 1;;
  51. esac
  52. stderr_onerror \
  53. openssl genpkey "${args[@]}" -out "${key}.pem"
  54. fi
  55. }
  56. # Usage: $0 req keyname dn1 dn2 ...
  57. req() {
  58. local key=$1; shift
  59. key "$key"
  60. local errs
  61. stderr_onerror \
  62. openssl req -new -"${OPENSSL_SIGALG}" -key "${key}.pem" \
  63. -config <(printf "string_mask=%s\n[req]\n%s\n%s\n[dn]\n" \
  64. "$REQMASK" "prompt = no" "distinguished_name = dn"
  65. for dn in "$@"; do echo "$dn"; done)
  66. }
  67. req_nocn() {
  68. local key=$1; shift
  69. key "$key"
  70. stderr_onerror \
  71. openssl req -new -"${OPENSSL_SIGALG}" -subj / -key "${key}.pem" \
  72. -config <(printf "[req]\n%s\n[dn]\nCN_default =\n" \
  73. "distinguished_name = dn")
  74. }
  75. cert() {
  76. local cert=$1; shift
  77. local exts=$1; shift
  78. stderr_onerror \
  79. openssl x509 -req -"${OPENSSL_SIGALG}" -out "${cert}.pem" \
  80. -extfile <(printf "%s\n" "$exts") "$@"
  81. }
  82. genroot() {
  83. local cn=$1; shift
  84. local key=$1; shift
  85. local cert=$1; shift
  86. local skid="subjectKeyIdentifier = hash"
  87. local akid="authorityKeyIdentifier = keyid"
  88. exts=$(printf "%s\n%s\n%s\n" "$skid" "$akid" "basicConstraints = critical,CA:true")
  89. for eku in "$@"
  90. do
  91. exts=$(printf "%s\nextendedKeyUsage = %s\n" "$exts" "$eku")
  92. done
  93. csr=$(req "$key" "CN = $cn") || return 1
  94. echo "$csr" |
  95. cert "$cert" "$exts" -signkey "${key}.pem" -set_serial 1 -days "${DAYS}"
  96. }
  97. genca() {
  98. local OPTIND=1
  99. local purpose=
  100. while getopts p: o
  101. do
  102. case $o in
  103. p) purpose="$OPTARG";;
  104. *) echo "Usage: $0 genca [-p EKU] cn keyname certname cakeyname cacertname" >&2
  105. return 1;;
  106. esac
  107. done
  108. shift $((OPTIND - 1))
  109. local cn=$1; shift
  110. local key=$1; shift
  111. local cert=$1; shift
  112. local cakey=$1; shift
  113. local cacert=$1; shift
  114. local skid="subjectKeyIdentifier = hash"
  115. local akid="authorityKeyIdentifier = keyid"
  116. exts=$(printf "%s\n%s\n%s\n" "$skid" "$akid" "basicConstraints = critical,CA:true")
  117. if [ -n "$purpose" ]; then
  118. exts=$(printf "%s\nextendedKeyUsage = %s\n" "$exts" "$purpose")
  119. fi
  120. if [ -n "$NC" ]; then
  121. exts=$(printf "%s\nnameConstraints = %s\n" "$exts" "$NC")
  122. fi
  123. csr=$(req "$key" "CN = $cn") || return 1
  124. echo "$csr" |
  125. cert "$cert" "$exts" -CA "${cacert}.pem" -CAkey "${cakey}.pem" \
  126. -set_serial 2 -days "${DAYS}" "$@"
  127. }
  128. gen_nonbc_ca() {
  129. local cn=$1; shift
  130. local key=$1; shift
  131. local cert=$1; shift
  132. local cakey=$1; shift
  133. local cacert=$1; shift
  134. local skid="subjectKeyIdentifier = hash"
  135. local akid="authorityKeyIdentifier = keyid"
  136. exts=$(printf "%s\n%s\n%s\n" "$skid" "$akid")
  137. exts=$(printf "%s\nkeyUsage = %s\n" "$exts" "keyCertSign, cRLSign")
  138. for eku in "$@"
  139. do
  140. exts=$(printf "%s\nextendedKeyUsage = %s\n" "$exts" "$eku")
  141. done
  142. csr=$(req "$key" "CN = $cn") || return 1
  143. echo "$csr" |
  144. cert "$cert" "$exts" -CA "${cacert}.pem" -CAkey "${cakey}.pem" \
  145. -set_serial 2 -days "${DAYS}"
  146. }
  147. # Usage: $0 genpc keyname certname eekeyname eecertname pcext1 pcext2 ...
  148. #
  149. # Note: takes csr on stdin, so must be used with $0 req like this:
  150. #
  151. # $0 req keyname dn | $0 genpc keyname certname eekeyname eecertname pcext ...
  152. genpc() {
  153. local key=$1; shift
  154. local cert=$1; shift
  155. local cakey=$1; shift
  156. local ca=$1; shift
  157. exts=$(printf "%s\n%s\n%s\n%s\n" \
  158. "subjectKeyIdentifier = hash" \
  159. "authorityKeyIdentifier = keyid, issuer:always" \
  160. "basicConstraints = CA:false" \
  161. "proxyCertInfo = critical, @pcexts";
  162. echo "[pcexts]";
  163. for x in "$@"; do echo $x; done)
  164. cert "$cert" "$exts" -CA "${ca}.pem" -CAkey "${cakey}.pem" \
  165. -set_serial 2 -days "${DAYS}"
  166. }
  167. # Usage: $0 geneealt keyname certname eekeyname eecertname alt1 alt2 ...
  168. #
  169. # Note: takes csr on stdin, so must be used with $0 req like this:
  170. #
  171. # $0 req keyname dn | $0 geneealt keyname certname eekeyname eecertname alt ...
  172. geneealt() {
  173. local key=$1; shift
  174. local cert=$1; shift
  175. local cakey=$1; shift
  176. local ca=$1; shift
  177. exts=$(printf "%s\n%s\n%s\n%s\n" \
  178. "subjectKeyIdentifier = hash" \
  179. "authorityKeyIdentifier = keyid" \
  180. "basicConstraints = CA:false" \
  181. "subjectAltName = @alts";
  182. echo "[alts]";
  183. for x in "$@"; do echo $x; done)
  184. cert "$cert" "$exts" -CA "${ca}.pem" -CAkey "${cakey}.pem" \
  185. -set_serial 2 -days "${DAYS}"
  186. }
  187. genee() {
  188. local OPTIND=1
  189. local purpose=serverAuth
  190. while getopts p: o
  191. do
  192. case $o in
  193. p) purpose="$OPTARG";;
  194. *) echo "Usage: $0 genee [-p EKU] cn keyname certname cakeyname cacertname" >&2
  195. return 1;;
  196. esac
  197. done
  198. shift $((OPTIND - 1))
  199. local cn=$1; shift
  200. local key=$1; shift
  201. local cert=$1; shift
  202. local cakey=$1; shift
  203. local ca=$1; shift
  204. exts=$(printf "%s\n%s\n%s\n%s\n%s\n[alts]\n%s\n" \
  205. "subjectKeyIdentifier = hash" \
  206. "authorityKeyIdentifier = keyid, issuer" \
  207. "basicConstraints = CA:false" \
  208. "extendedKeyUsage = $purpose" \
  209. "subjectAltName = @alts" "DNS=${cn}")
  210. csr=$(req "$key" "CN = $cn") || return 1
  211. echo "$csr" |
  212. cert "$cert" "$exts" -CA "${ca}.pem" -CAkey "${cakey}.pem" \
  213. -set_serial 2 -days "${DAYS}" "$@"
  214. }
  215. geneenocsr() {
  216. local OPTIND=1
  217. local purpose=serverAuth
  218. while getopts p: o
  219. do
  220. case $o in
  221. p) purpose="$OPTARG";;
  222. *) echo "Usage: $0 genee [-p EKU] cn certname cakeyname cacertname" >&2
  223. return 1;;
  224. esac
  225. done
  226. shift $((OPTIND - 1))
  227. local cn=$1; shift
  228. local cert=$1; shift
  229. local cakey=$1; shift
  230. local ca=$1; shift
  231. exts=$(printf "%s\n%s\n%s\n%s\n%s\n[alts]\n%s\n" \
  232. "subjectKeyIdentifier = hash" \
  233. "authorityKeyIdentifier = keyid, issuer" \
  234. "basicConstraints = CA:false" \
  235. "extendedKeyUsage = $purpose" \
  236. "subjectAltName = @alts" "DNS=${cn}")
  237. cert "$cert" "$exts" -CA "${ca}.pem" -CAkey "${cakey}.pem" \
  238. -set_serial 2 -days "${DAYS}" "$@"
  239. }
  240. genss() {
  241. local cn=$1; shift
  242. local key=$1; shift
  243. local cert=$1; shift
  244. exts=$(printf "%s\n%s\n%s\n%s\n%s\n[alts]\n%s\n" \
  245. "subjectKeyIdentifier = hash" \
  246. "authorityKeyIdentifier = keyid, issuer" \
  247. "basicConstraints = CA:false" \
  248. "extendedKeyUsage = serverAuth" \
  249. "subjectAltName = @alts" "DNS=${cn}")
  250. csr=$(req "$key" "CN = $cn") || return 1
  251. echo "$csr" |
  252. cert "$cert" "$exts" -signkey "${key}.pem" \
  253. -set_serial 1 -days "${DAYS}" "$@"
  254. }
  255. gennocn() {
  256. local key=$1; shift
  257. local cert=$1; shift
  258. csr=$(req_nocn "$key") || return 1
  259. echo "$csr" |
  260. cert "$cert" "" -signkey "${key}.pem" -set_serial 1 -days -1 "$@"
  261. }
  262. "$@"