mkcert.sh 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. #! /bin/bash
  2. #
  3. # Copyright 2016-2023 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 Apache License 2.0 (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 bcon="basicConstraints = critical,CA:true"
  87. local ku="keyUsage = keyCertSign,cRLSign"
  88. local skid="subjectKeyIdentifier = hash"
  89. local akid="authorityKeyIdentifier = keyid"
  90. exts=$(printf "%s\n%s\n%s\n" "$bcon" "$ku" "$skid" "$akid")
  91. for eku in "$@"
  92. do
  93. exts=$(printf "%s\nextendedKeyUsage = %s\n" "$exts" "$eku")
  94. done
  95. csr=$(req "$key" "CN = $cn") || return 1
  96. echo "$csr" |
  97. cert "$cert" "$exts" -signkey "${key}.pem" -set_serial 1 -days "${DAYS}"
  98. }
  99. genca() {
  100. local OPTIND=1
  101. local purpose=
  102. while getopts p:c: o
  103. do
  104. case $o in
  105. p) purpose="$OPTARG";;
  106. c) certpol="$OPTARG";;
  107. *) echo "Usage: $0 genca [-p EKU][-c policyoid] cn keyname certname cakeyname cacertname" >&2
  108. return 1;;
  109. esac
  110. done
  111. shift $((OPTIND - 1))
  112. local cn=$1; shift
  113. local key=$1; shift
  114. local cert=$1; shift
  115. local cakey=$1; shift
  116. local cacert=$1; shift
  117. local bcon="basicConstraints = critical,CA:true"
  118. local ku="keyUsage = keyCertSign,cRLSign"
  119. local skid="subjectKeyIdentifier = hash"
  120. local akid="authorityKeyIdentifier = keyid"
  121. exts=$(printf "%s\n%s\n%s\n" "$bcon" "$ku" "$skid" "$akid")
  122. if [ -n "$purpose" ]; then
  123. exts=$(printf "%s\nextendedKeyUsage = %s\n" "$exts" "$purpose")
  124. fi
  125. if [ -n "$NC" ]; then
  126. exts=$(printf "%s\nnameConstraints = %s\n" "$exts" "$NC")
  127. fi
  128. if [ -n "$certpol" ]; then
  129. exts=$(printf "%s\ncertificatePolicies = %s\n" "$exts" "$certpol")
  130. fi
  131. csr=$(req "$key" "CN = $cn") || return 1
  132. echo "$csr" |
  133. cert "$cert" "$exts" -CA "${cacert}.pem" -CAkey "${cakey}.pem" \
  134. -set_serial 2 -days "${DAYS}" "$@"
  135. }
  136. gen_nonbc_ca() {
  137. local cn=$1; shift
  138. local key=$1; shift
  139. local cert=$1; shift
  140. local cakey=$1; shift
  141. local cacert=$1; shift
  142. local skid="subjectKeyIdentifier = hash"
  143. local akid="authorityKeyIdentifier = keyid"
  144. exts=$(printf "%s\n%s\n%s\n" "$skid" "$akid")
  145. exts=$(printf "%s\nkeyUsage = %s\n" "$exts" "keyCertSign, cRLSign")
  146. for eku in "$@"
  147. do
  148. exts=$(printf "%s\nextendedKeyUsage = %s\n" "$exts" "$eku")
  149. done
  150. csr=$(req "$key" "CN = $cn") || return 1
  151. echo "$csr" |
  152. cert "$cert" "$exts" -CA "${cacert}.pem" -CAkey "${cakey}.pem" \
  153. -set_serial 2 -days "${DAYS}"
  154. }
  155. # Usage: $0 genpc keyname certname eekeyname eecertname pcext1 pcext2 ...
  156. #
  157. # Note: takes csr on stdin, so must be used with $0 req like this:
  158. #
  159. # $0 req keyname dn | $0 genpc keyname certname eekeyname eecertname pcext ...
  160. genpc() {
  161. local key=$1; shift
  162. local cert=$1; shift
  163. local cakey=$1; shift
  164. local ca=$1; shift
  165. exts=$(printf "%s\n%s\n%s\n%s\n" \
  166. "subjectKeyIdentifier = hash" \
  167. "authorityKeyIdentifier = keyid, issuer:always" \
  168. "basicConstraints = CA:false" \
  169. "proxyCertInfo = critical, @pcexts";
  170. echo "[pcexts]";
  171. for x in "$@"; do echo $x; done)
  172. cert "$cert" "$exts" -CA "${ca}.pem" -CAkey "${cakey}.pem" \
  173. -set_serial 2 -days "${DAYS}"
  174. }
  175. geneeconfig() {
  176. local key=$1; shift
  177. local cert=$1; shift
  178. local cakey=$1; shift
  179. local ca=$1; shift
  180. local conf=$1; shift
  181. exts=$(printf "%s\n%s\n%s\n%s\n" \
  182. "subjectKeyIdentifier = hash" \
  183. "authorityKeyIdentifier = keyid" \
  184. "basicConstraints = CA:false"; \
  185. echo "$conf")
  186. cert "$cert" "$exts" -CA "${ca}.pem" -CAkey "${cakey}.pem" \
  187. -set_serial 2 -days "${DAYS}"
  188. }
  189. # Usage: $0 geneealt keyname certname cakeyname cacertname alt1 alt2 ...
  190. #
  191. # Note: takes csr on stdin, so must be used with $0 req like this:
  192. #
  193. # $0 req keyname dn | $0 geneealt keyname certname cakeyname cacertname alt ...
  194. geneealt() {
  195. local key=$1; shift
  196. local cert=$1; shift
  197. local cakey=$1; shift
  198. local ca=$1; shift
  199. conf=$(echo "subjectAltName = @alts"
  200. echo "[alts]";
  201. for x in "$@"; do echo "$x"; done)
  202. geneeconfig $key $cert $cakey $ca "$conf"
  203. }
  204. genee() {
  205. local OPTIND=1
  206. local purpose=serverAuth
  207. local ku=
  208. while getopts p:k: o
  209. do
  210. case $o in
  211. p) purpose="$OPTARG";;
  212. k) ku="keyUsage = $OPTARG";;
  213. *) echo "Usage: $0 genee [-k KU] [-p EKU] cn keyname certname cakeyname cacertname" >&2
  214. return 1;;
  215. esac
  216. done
  217. shift $((OPTIND - 1))
  218. local cn=$1; shift
  219. local key=$1; shift
  220. local cert=$1; shift
  221. local cakey=$1; shift
  222. local ca=$1; shift
  223. exts=$(printf "%s\n%s\n%s\n%s\n%s\n[alts]\n%s\n" \
  224. "subjectKeyIdentifier = hash" \
  225. "authorityKeyIdentifier = keyid, issuer" \
  226. "basicConstraints = CA:false" \
  227. "$ku" \
  228. "extendedKeyUsage = $purpose" \
  229. "subjectAltName = @alts" "DNS=${cn}")
  230. csr=$(req "$key" "CN = $cn") || return 1
  231. echo "$csr" |
  232. cert "$cert" "$exts" -CA "${ca}.pem" -CAkey "${cakey}.pem" \
  233. -set_serial 2 -days "${DAYS}" "$@"
  234. }
  235. geneeextra() {
  236. local OPTIND=1
  237. local purpose=serverAuth
  238. while getopts p: o
  239. do
  240. case $o in
  241. p) purpose="$OPTARG";;
  242. *) echo "Usage: $0 geneeextra [-p EKU] cn keyname certname cakeyname cacertname extraext" >&2
  243. return 1;;
  244. esac
  245. done
  246. shift $((OPTIND - 1))
  247. local cn=$1; shift
  248. local key=$1; shift
  249. local cert=$1; shift
  250. local cakey=$1; shift
  251. local ca=$1; shift
  252. local extraext=$1; shift
  253. exts=$(printf "%s\n%s\n%s\n%s\n%s\n%s\n[alts]\n%s\n" \
  254. "subjectKeyIdentifier = hash" \
  255. "authorityKeyIdentifier = keyid, issuer" \
  256. "basicConstraints = CA:false" \
  257. "extendedKeyUsage = $purpose" \
  258. "subjectAltName = @alts"\
  259. "$extraext" "DNS=${cn}")
  260. csr=$(req "$key" "CN = $cn") || return 1
  261. echo "$csr" |
  262. cert "$cert" "$exts" -CA "${ca}.pem" -CAkey "${cakey}.pem" \
  263. -set_serial 2 -days "${DAYS}" "$@"
  264. }
  265. geneenocsr() {
  266. local OPTIND=1
  267. local purpose=serverAuth
  268. while getopts p: o
  269. do
  270. case $o in
  271. p) purpose="$OPTARG";;
  272. *) echo "Usage: $0 geneenocsr [-p EKU] cn certname cakeyname cacertname" >&2
  273. return 1;;
  274. esac
  275. done
  276. shift $((OPTIND - 1))
  277. local cn=$1; shift
  278. local cert=$1; shift
  279. local cakey=$1; shift
  280. local ca=$1; shift
  281. exts=$(printf "%s\n%s\n%s\n%s\n%s\n[alts]\n%s\n" \
  282. "subjectKeyIdentifier = hash" \
  283. "authorityKeyIdentifier = keyid, issuer" \
  284. "basicConstraints = CA:false" \
  285. "extendedKeyUsage = $purpose" \
  286. "subjectAltName = @alts" "DNS=${cn}")
  287. cert "$cert" "$exts" -CA "${ca}.pem" -CAkey "${cakey}.pem" \
  288. -set_serial 2 -days "${DAYS}" "$@"
  289. }
  290. genss() {
  291. local cn=$1; shift
  292. local key=$1; shift
  293. local cert=$1; shift
  294. exts=$(printf "%s\n%s\n%s\n%s\n%s\n[alts]\n%s\n" \
  295. "subjectKeyIdentifier = hash" \
  296. "authorityKeyIdentifier = keyid, issuer" \
  297. "basicConstraints = CA:false" \
  298. "extendedKeyUsage = serverAuth" \
  299. "subjectAltName = @alts" "DNS=${cn}")
  300. csr=$(req "$key" "CN = $cn") || return 1
  301. echo "$csr" |
  302. cert "$cert" "$exts" -signkey "${key}.pem" \
  303. -set_serial 1 -days "${DAYS}" "$@"
  304. }
  305. gennocn() {
  306. local key=$1; shift
  307. local cert=$1; shift
  308. csr=$(req_nocn "$key") || return 1
  309. echo "$csr" |
  310. cert "$cert" "" -signkey "${key}.pem" -set_serial 1 -days -1 "$@"
  311. }
  312. genct() {
  313. local OPTIND=1
  314. local purpose=serverAuth
  315. while getopts p: o
  316. do
  317. case $o in
  318. p) purpose="$OPTARG";;
  319. *) echo "Usage: $0 genct [-p EKU] cn keyname certname cakeyname cacertname ctlogkey" >&2
  320. return 1;;
  321. esac
  322. done
  323. shift $((OPTIND - 1))
  324. local cn=$1; shift
  325. local key=$1; shift
  326. local cert=$1; shift
  327. local cakey=$1; shift
  328. local ca=$1; shift
  329. local logkey=$1; shift
  330. exts=$(printf "%s\n%s\n%s\n%s\n%s\n%s\n[alts]\n%s\n" \
  331. "subjectKeyIdentifier = hash" \
  332. "authorityKeyIdentifier = keyid, issuer" \
  333. "basicConstraints = CA:false" \
  334. "extendedKeyUsage = $purpose" \
  335. "1.3.6.1.4.1.11129.2.4.3 = critical,ASN1:NULL"\
  336. "subjectAltName = @alts" "DNS=${cn}")
  337. csr=$(req "$key" "CN = $cn") || return 1
  338. echo "$csr" |
  339. cert "$cert" "$exts" -CA "${ca}.pem" -CAkey "${cakey}.pem" \
  340. -set_serial 2 -days "${DAYS}" "$@"
  341. cat ${cert}.pem ${ca}.pem > ${cert}-chain.pem
  342. go run github.com/google/certificate-transparency-go/ctutil/sctgen \
  343. --log_private_key ${logkey}.pem \
  344. --timestamp="2020-01-01T00:00:00Z" \
  345. --cert_chain ${cert}-chain.pem \
  346. --tls_out ${cert}.tlssct
  347. rm ${cert}-chain.pem
  348. filesize=$(wc -c <${cert}.tlssct)
  349. exts=$(printf "%s\n%s\n%s\n%s\n%s%04X%04X%s\n%s\n[alts]\n%s\n" \
  350. "subjectKeyIdentifier = hash" \
  351. "authorityKeyIdentifier = keyid, issuer" \
  352. "basicConstraints = CA:false" \
  353. "extendedKeyUsage = $purpose" \
  354. "1.3.6.1.4.1.11129.2.4.2 = ASN1:FORMAT:HEX,OCT:" $((filesize+2)) $filesize `xxd -p ${cert}.tlssct | tr -d '\n'` \
  355. "subjectAltName = @alts" "DNS=${cn}")
  356. echo "$csr" |
  357. cert "$cert" "$exts" -CA "${ca}.pem" -CAkey "${cakey}.pem" \
  358. -set_serial 2 -days "${DAYS}" "$@"
  359. }
  360. "$@"