summaryrefslogtreecommitdiff
path: root/localmksslcerts
blob: 12198f19883024d8d3c78d112cc77cf0191d718e (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.19 2005-10-18 00:24:33 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. TEMP=`getopt -o f --long help,fqdn:,cn:,state:,loc:,org:,ou:,daemon:,issuer:,cert,cacert:,makeca,force -n "$prg" -- "$@"`
  125. # Check for non-GNU getopt
  126. if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
  127. eval set -- "$TEMP"
  128. while true ; do
  129. case "$1" in
  130. --help) usage;;
  131. --fqdn) fqdn="$2"; shift 2;;
  132. --cn) cn="$2"; shift 2;;
  133. --state) state="$2"; shift 2;;
  134. --loc) loc="$2"; shift 2;;
  135. --org) org="$2"; shift 2;;
  136. --ou) ou="$2"; shift 2;;
  137. --daemon) daemons="$daemons$2 "; shift 2;;
  138. --issuer) issuer="$2"; shift 2;;
  139. --cert) cert=1; shift;;
  140. --cacert) cacert="$2"; shift 2;;
  141. --makeca) makeca=1; shift;;
  142. --force|-f) force=1; shift;;
  143. --) shift; break;;
  144. *) echo "Internal error!" ; exit 1 ;;
  145. esac
  146. done
  147. if [ -z "$issuer" ]; then
  148. DOMAINNAME="`hostname -d`"
  149. ISSUER="postmaster@$DOMAINNAME"
  150. fi
  151. if [ -z "$fqdn" ]; then
  152. if [ $# -gt 0 ]; then
  153. fqdn="`hostname -f`"
  154. else
  155. echo "Too few parameters!"
  156. usage
  157. fi
  158. fi
  159. for val in org ou; do
  160. if eval [ -z "\$$val" ]; then
  161. eval "$val=\"$fqdn\""
  162. fi
  163. done
  164. for val in cn state loc; do
  165. if eval [ -z "\$$val" ]; then
  166. eval "$val=\".\""
  167. fi
  168. done
  169. if [ -n "$cert" ]; then
  170. if [ ! -s "$SSLCERTDIR/$fqdn.pem" ] || [ ! -s "$SSLPRIVDIR/$fqdn.pem" ]; then
  171. echo "WARNING: Host certificate for \"$fqdn\" missing..."
  172. if [ -z "$cacert" ]; then
  173. echo "ERROR: The \"--cacert\" option is required when making a host certificate!"
  174. exit 1
  175. fi
  176. # Cleaning up - if allowed
  177. for file in "$SSLPRIVDIR/$fqdn.pem" "$SSLCERTDIR/$fqdn.csr" "$SSLCERTDIR/$fqdn.pem"; do
  178. if [ -e "$file" ]; then
  179. if [ -n "$force" ]; then
  180. rm -f "$file"
  181. else
  182. echo "ERROR: File \"$file\" already exists!"
  183. exit 1
  184. fi
  185. fi
  186. done
  187. if [ ! -s "$SSLCERTDIR/$cacert.pem" ] || [ ! -s "$SSLPRIVDIR/$cacert.pem" ]; then
  188. echo "WARNING: CAcert (certifying authority certificate) missing..."
  189. if [ -z "$makeca" ]; then
  190. echo "ERROR: The \"--makeca\" option is required when making a CAcert!"
  191. exit 1
  192. fi
  193. # Generate private key for CA certificate
  194. echo "Generating CAcert \"$cacert\"..."
  195. #FIXME: Make strength configurable
  196. openssl genrsa -des3 -out "$SSLPRIVDIR/$cacert.pem" 1024
  197. chown root:root "$SSLPRIVDIR/$cacert.pem"
  198. chmod 0400 "$SSLPRIVDIR/$cacert.pem"
  199. # Generate and pre-fill certification request
  200. #FIXME: Make validity configurable
  201. openssl req -new \
  202. -key "$SSLPRIVDIR/$cacert.pem" \
  203. -x509 -days 1095 \
  204. -out "$SSLCERTDIR/$cacert.pem"
  205. # Add hash to certified public certificate and cleanup
  206. mkcerthash $cacert
  207. fi
  208. echo "Generating host certificate for \"$fqdn\"..."
  209. # Generate private key for host certificate
  210. openssl genrsa -out "$SSLPRIVDIR/$fqdn.pem"
  211. chown root:root "$SSLPRIVDIR/$fqdn.pem"
  212. chmod 0600 "$SSLPRIVDIR/$fqdn.pem"
  213. # Generate and pre-fill certification request
  214. mkcertreq "$fqdn" "$cn" "$state" "$loc" "$org" "$ou" "$fqdn" "$issuer"
  215. # Generate public certificate from certification request
  216. openssl x509 -req \
  217. -days $DAYS2EXPIRE \
  218. -CA "$SSLCERTDIR/$cacert.pem" \
  219. -CAkey "$SSLPRIVDIR/$cacert.pem" \
  220. -CAcreateserial -out "$SSLCERTDIR/$fqdn.pem" -in "$SSLCERTDIR/$fqdn.csr"
  221. # Add hash to certified public certificate and cleanup
  222. mkcerthash $fqdn
  223. rm "$SSLCERTDIR/$fqdn.csr"
  224. fi
  225. fi
  226. for daemon in $daemons $@; do
  227. if [ -f "$SSLCERTDIR/$daemon.pem" ]; then
  228. if [ -n "$force" ]; then
  229. rm -f "$SSLCERTDIR/$(openssl x509 -noout -hash < "$SSLCERTDIR/$daemon.pem").0"
  230. rm -f "$SSLCERTDIR/$daemon.pem"
  231. else
  232. echo "Ignoring certificate (/etc/ssl/certs/$daemon.pem already exists...)"
  233. continue
  234. fi
  235. fi
  236. if [ -n "$cert" ]; then
  237. echo "Attaching $daemon to certified certificate for $fqdn."
  238. ln -sf "$fqdn.pem" "$SSLCERTDIR/$daemon.pem"
  239. ln -sf "$fqdn.pem" "$SSLPRIVDIR/$daemon.pem"
  240. else
  241. echo -n "Generating self-certifying $daemon certificate..."
  242. mkselfcert "$daemon" "$cn" "$state" "$loc" "$org" "$ou" "$fqdn" "$issuer"
  243. echo "Done!"
  244. fi
  245. done