mkcert.sh 11 KB

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