mkcert.sh 11 KB

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