summaryrefslogtreecommitdiff
path: root/localmksslcerts
blob: 3cf2f2b75953ba0ea6240bf92c5d38c38ce60528 (plain)
  1. #!/bin/sh
  2. #
  3. # /usr/local/sbin/localmksslcerts
  4. # Copyright 2001-2004 Jonas Smedegaard <dr@jones.dk>
  5. #
  6. # $Id: localmksslcerts,v 1.18 2005-10-17 21:16:19 jonas Exp $
  7. #
  8. # Generate certificates for mail (and other) servers
  9. # Based on uw-imapd-ssl post-install script
  10. #
  11. # TODO: Use getopts
  12. # TODO: Add symlink from CA certificate to cacert.pem if non-existing
  13. # TODO: Default CA certificate is cacert.pem if --cacert not set
  14. set -e
  15. prg=$(basename $0)
  16. copyright="(C) 2001-2004 Jonas Smedegaard <dr@jones.dk>"
  17. # Set some defaults
  18. PATH="$PATH:/usr/bin/ssl"
  19. DAYS2EXPIRE="365"
  20. SSLCERTDIR="/etc/ssl/certs"
  21. SSLPRIVDIR="/etc/ssl/private"
  22. usage() {
  23. echo "$prg, $copyright
  24. Usage: $prg [--fqdn <FQDN>] [...] --daemon <daemon> [...] [--force]
  25. or: $prg <daemon> [<daemon>...] [-f]
  26. Options:
  27. --fqdn <FQDN> Fully Qualified Domain Name for this host.
  28. --cn <country> Country Name (2 letter code)
  29. --state <state> State or Province Name (full name)
  30. --loc <locality> Locality Name (eg, city)
  31. --org <organisation> Organisation/company
  32. --ou <department> Organisational unit/department
  33. --daemon <daemon> Daemon(s) in need for a certificate
  34. (certificate is generated for each daemon)
  35. --issuer <issuer> Email address of entity issuing certificate
  36. --cert Use certified host certificate
  37. --cacert <file> Where to store host certificate if missing
  38. --makeca Create CA certificate if missing
  39. -f, --force Force overwriting existing certificate(s)
  40. -h, --help This help text
  41. Examples:
  42. Create certs for UW imapd/popd, bound to default host cert if there:
  43. localmksslcerts imapd pop3d
  44. Create host cert for non-default hostname, overwriting stray files:
  45. localmksslcerts --fqdn mail.jones.dk --cert --force
  46. Create host cert for non-default hostname and bind to UW daemons:
  47. localmksslcerts --fqdn mail.jones.dk --cert --force imapd pop3d
  48. Create CA-signed host cert (and CA cert if not there):
  49. localmksslcerts --cert --cacert IT-guide_dr_Jones_CA
  50. If issuer is not given, \"postmaster@<localdomain>\" is used."
  51. exit 1
  52. }
  53. mkcerthash() {
  54. filebase="$1"
  55. filename="$filebase.pem"
  56. certhash="$(openssl x509 -noout -hash -in "$SSLCERTDIR/$filename")"
  57. hashfile="$certhash.0"
  58. ln -sf "$filename" "$SSLCERTDIR/$hashfile"
  59. }
  60. mkselfcert() {
  61. filebase="$1"
  62. cn="$2"
  63. state="$3"
  64. loc="$4"
  65. org="$5"
  66. ou="$6"
  67. fqdn="$7"
  68. issuer="$8"
  69. filename="$filebase.pem"
  70. openssl req -new -x509 -nodes \
  71. -days "$DAYS2EXPIRE" \
  72. -keyout "$SSLCERTDIR/$filename" \
  73. -out "$SSLCERTDIR/$filename" > /dev/null 2>&1 <<+
  74. $cn
  75. $state
  76. $loc
  77. $org
  78. $ou
  79. $fqdn
  80. $issuer
  81. +
  82. mkcerthash "$filebase"
  83. chown root:root "$SSLCERTDIR/$filename"
  84. chmod 0640 "$SSLCERTDIR/$filename"
  85. }
  86. mkcertreq() {
  87. filebase="$1"
  88. cn="$2"
  89. state="$3"
  90. loc="$4"
  91. org="$5"
  92. ou="$6"
  93. fqdn="$7"
  94. issuer="$8"
  95. filename="$filebase.pem"
  96. openssl req -new \
  97. -key "$SSLPRIVDIR/$filename" \
  98. -out "$SSLCERTDIR/$filename" > /dev/null 2>&1 <<+
  99. $cn
  100. $state
  101. $loc
  102. $org
  103. $ou
  104. $fqdn
  105. $issuer
  106. +
  107. chown root:root "$SSLCERTDIR/$filename"
  108. chmod 0640 "$SSLCERTDIR/$filename"
  109. }
  110. fqdn=''
  111. cn=''
  112. state=''
  113. loc=''
  114. org=''
  115. ou=''
  116. daemon=''
  117. daemons=''
  118. issuer=''
  119. cert=''
  120. cacert=''
  121. makeca=''
  122. force=''
  123. args=''
  124. while [ $# -gt 0 ]; do
  125. doubleshift=''
  126. case $1 in
  127. --fqdn) fqdn="$2"; doubleshift=1;;
  128. --cn) cn="$2"; doubleshift=1;;
  129. --state) state="$2"; doubleshift=1;;
  130. --loc) loc="$2"; doubleshift=1;;
  131. --org) org="$2"; doubleshift=1;;
  132. --ou) ou="$2"; doubleshift=1;;
  133. --daemon) daemons="$daemons$2 "; doubleshift=1;;
  134. --issuer) issuer="$2"; doubleshift=1;;
  135. --cert) cert=1;;
  136. --cacert) cacert="$2"; doubleshift=1;;
  137. --makeca) makeca=1;;
  138. --force|-f) force=1;;
  139. -*) usage;;
  140. *) args="$args$1 ";;
  141. esac
  142. if [ -n "$doubleshift" ];then
  143. if [ $# -gt 1 ]; then
  144. shift
  145. else
  146. echo "ERROR: Parameter for option \"$1\" missing!"
  147. usage
  148. fi
  149. fi
  150. shift
  151. done
  152. set -- $args
  153. if [ -z "$issuer" ]; then
  154. DOMAINNAME="`hostname -d`"
  155. ISSUER="postmaster@$DOMAINNAME"
  156. fi
  157. if [ -z "$fqdn" ]; then
  158. if [ $# -gt 0 ]; then
  159. fqdn="`hostname -f`"
  160. else
  161. echo "Too few parameters!"
  162. usage
  163. fi
  164. fi
  165. for val in org ou; do
  166. if eval [ -z "\$$val" ]; then
  167. eval "$val=\"$fqdn\""
  168. fi
  169. done
  170. for val in cn state loc; do
  171. if eval [ -z "\$$val" ]; then
  172. eval "$val=\".\""
  173. fi
  174. done
  175. if [ -n "$cert" ]; then
  176. if [ ! -s "$SSLCERTDIR/$fqdn.pem" ] || [ ! -s "$SSLPRIVDIR/$fqdn.pem" ]; then
  177. echo "WARNING: Host certificate for \"$fqdn\" missing..."
  178. if [ -z "$cacert" ]; then
  179. echo "ERROR: The \"--cacert\" option is required when making a host certificate!"
  180. exit 1
  181. fi
  182. # Cleaning up - if allowed
  183. for file in "$SSLPRIVDIR/$fqdn.pem" "$SSLCERTDIR/$fqdn.csr" "$SSLCERTDIR/$fqdn.pem"; do
  184. if [ -e "$file" ]; then
  185. if [ -n "$force" ]; then
  186. rm -f "$file"
  187. else
  188. echo "ERROR: File \"$file\" already exists!"
  189. exit 1
  190. fi
  191. fi
  192. done
  193. if [ ! -s "$SSLCERTDIR/$cacert.pem" ] || [ ! -s "$SSLPRIVDIR/$cacert.pem" ]; then
  194. echo "WARNING: CAcert (certifying authority certificate) missing..."
  195. if [ -z "$makeca" ]; then
  196. echo "ERROR: The \"--makeca\" option is required when making a CAcert!"
  197. exit 1
  198. fi
  199. # Generate private key for CA certificate
  200. echo "Generating CAcert \"$cacert\"..."
  201. #FIXME: Make strength configurable
  202. openssl genrsa -des3 -out "$SSLPRIVDIR/$cacert.pem" 1024
  203. chown root:root "$SSLPRIVDIR/$cacert.pem"
  204. chmod 0400 "$SSLPRIVDIR/$cacert.pem"
  205. # Generate and pre-fill certification request
  206. #FIXME: Make validity configurable
  207. openssl req -new \
  208. -key "$SSLPRIVDIR/$cacert.pem" \
  209. -x509 -days 1095 \
  210. -out "$SSLCERTDIR/$cacert.pem"
  211. # Add hash to certified public certificate and cleanup
  212. mkcerthash $cacert
  213. fi
  214. echo "Generating host certificate for \"$fqdn\"..."
  215. # Generate private key for host certificate
  216. openssl genrsa -out "$SSLPRIVDIR/$fqdn.pem"
  217. chown root:root "$SSLPRIVDIR/$fqdn.pem"
  218. chmod 0600 "$SSLPRIVDIR/$fqdn.pem"
  219. # Generate and pre-fill certification request
  220. mkcertreq "$fqdn" "$cn" "$state" "$loc" "$org" "$ou" "$fqdn" "$issuer"
  221. # Generate public certificate from certification request
  222. openssl x509 -req \
  223. -days $DAYS2EXPIRE \
  224. -CA "$SSLCERTDIR/$cacert.pem" \
  225. -CAkey "$SSLPRIVDIR/$cacert.pem" \
  226. -CAcreateserial -out "$SSLCERTDIR/$fqdn.pem" -in "$SSLCERTDIR/$fqdn.csr"
  227. # Add hash to certified public certificate and cleanup
  228. mkcerthash $fqdn
  229. rm "$SSLCERTDIR/$fqdn.csr"
  230. fi
  231. fi
  232. for daemon in $daemons $@; do
  233. if [ -f "$SSLCERTDIR/$daemon.pem" ]; then
  234. if [ -n "$force" ]; then
  235. rm -f "$SSLCERTDIR/$(openssl x509 -noout -hash < "$SSLCERTDIR/$daemon.pem").0"
  236. rm -f "$SSLCERTDIR/$daemon.pem"
  237. else
  238. echo "Ignoring certificate (/etc/ssl/certs/$daemon.pem already exists...)"
  239. continue
  240. fi
  241. fi
  242. if [ -n "$cert" ]; then
  243. echo "Attaching $daemon to certified certificate for $fqdn."
  244. ln -sf "$fqdn.pem" "$SSLCERTDIR/$daemon.pem"
  245. ln -sf "$fqdn.pem" "$SSLPRIVDIR/$daemon.pem"
  246. else
  247. echo -n "Generating self-certifying $daemon certificate..."
  248. mkselfcert "$daemon" "$cn" "$state" "$loc" "$org" "$ou" "$fqdn" "$issuer"
  249. echo "Done!"
  250. fi
  251. done