perl-functions.eclass: should 'just work' in EAPI=6
[gentoo.git] / eclass / ssl-cert.eclass
1 # Copyright 1999-2014 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
3 # $Id$
4
5 # @ECLASS: ssl-cert.eclass
6 # @MAINTAINER:
7 # @AUTHOR:
8 # Max Kalika <max@gentoo.org>
9 # @BLURB: Eclass for SSL certificates
10 # @DESCRIPTION:
11 # This eclass implements a standard installation procedure for installing
12 # self-signed SSL certificates.
13 # @EXAMPLE:
14 # "install_cert /foo/bar" installs ${ROOT}/foo/bar.{key,csr,crt,pem}
15
16 # @ECLASS-VARIABLE: SSL_CERT_MANDATORY
17 # @DESCRIPTION:
18 # Set to non zero if ssl-cert is mandatory for ebuild.
19 : ${SSL_CERT_MANDATORY:=0}
20
21 # @ECLASS-VARIABLE: SSL_CERT_USE
22 # @DESCRIPTION:
23 # Use flag to append dependency to.
24 : ${SSL_CERT_USE:=ssl}
25
26 if [[ "${SSL_CERT_MANDATORY}" == "0" ]]; then
27         DEPEND="${SSL_CERT_USE}? ( dev-libs/openssl )"
28         IUSE="${SSL_CERT_USE}"
29 else
30         DEPEND="dev-libs/openssl"
31 fi
32
33 # @FUNCTION: gen_cnf
34 # @USAGE:
35 # @DESCRIPTION:
36 # Initializes variables and generates the needed
37 # OpenSSL configuration file and a CA serial file
38 #
39 # Access: private
40 gen_cnf() {
41         # Location of the config file
42         SSL_CONF="${T}/${$}ssl.cnf"
43         # Location of the CA serial file
44         SSL_SERIAL="${T}/${$}ca.ser"
45         # Location of some random files OpenSSL can use: don't use
46         # /dev/u?random here -- doesn't work properly on all platforms
47         SSL_RANDOM="${T}/environment:${T}/eclass-debug.log:/etc/resolv.conf"
48
49         # These can be overridden in the ebuild
50         SSL_DAYS="${SSL_DAYS:-730}"
51         SSL_BITS="${SSL_BITS:-1024}"
52         SSL_COUNTRY="${SSL_COUNTRY:-US}"
53         SSL_STATE="${SSL_STATE:-California}"
54         SSL_LOCALITY="${SSL_LOCALITY:-Santa Barbara}"
55         SSL_ORGANIZATION="${SSL_ORGANIZATION:-SSL Server}"
56         SSL_UNIT="${SSL_UNIT:-For Testing Purposes Only}"
57         SSL_COMMONNAME="${SSL_COMMONNAME:-localhost}"
58         SSL_EMAIL="${SSL_EMAIL:-root@localhost}"
59
60         # Create the CA serial file
61         echo "01" > "${SSL_SERIAL}"
62
63         # Create the config file
64         ebegin "Generating OpenSSL configuration${1:+ for CA}"
65         cat <<-EOF > "${SSL_CONF}"
66                 [ req ]
67                 prompt             = no
68                 default_bits       = ${SSL_BITS}
69                 distinguished_name = req_dn
70                 [ req_dn ]
71                 C                  = ${SSL_COUNTRY}
72                 ST                 = ${SSL_STATE}
73                 L                  = ${SSL_LOCALITY}
74                 O                  = ${SSL_ORGANIZATION}
75                 OU                 = ${SSL_UNIT}
76                 CN                 = ${SSL_COMMONNAME}${1:+ CA}
77                 emailAddress       = ${SSL_EMAIL}
78         EOF
79         eend $?
80
81         return $?
82 }
83
84 # @FUNCTION: get_base
85 # @USAGE: [if_ca]
86 # @RETURN: <base path>
87 # @DESCRIPTION:
88 # Simple function to determine whether we're creating
89 # a CA (which should only be done once) or final part
90 #
91 # Access: private
92 get_base() {
93         if [ "${1}" ] ; then
94                 echo "${T}/${$}ca"
95         else
96                 echo "${T}/${$}server"
97         fi
98 }
99
100 # @FUNCTION: gen_key
101 # @USAGE: <base path>
102 # @DESCRIPTION:
103 # Generates an RSA key
104 #
105 # Access: private
106 gen_key() {
107         local base=$(get_base "$1")
108         ebegin "Generating ${SSL_BITS} bit RSA key${1:+ for CA}"
109         openssl genrsa -rand "${SSL_RANDOM}" \
110                 -out "${base}.key" "${SSL_BITS}" &> /dev/null
111         eend $?
112
113         return $?
114 }
115
116 # @FUNCTION: gen_csr
117 # @USAGE: <base path>
118 # @DESCRIPTION:
119 # Generates a certificate signing request using
120 # the key made by gen_key()
121 #
122 # Access: private
123 gen_csr() {
124         local base=$(get_base "$1")
125         ebegin "Generating Certificate Signing Request${1:+ for CA}"
126         openssl req -config "${SSL_CONF}" -new \
127                 -key "${base}.key" -out "${base}.csr" &>/dev/null
128         eend $?
129
130         return $?
131 }
132
133 # @FUNCTION: gen_crt
134 # @USAGE: <base path>
135 # @DESCRIPTION:
136 # Generates either a self-signed CA certificate using
137 # the csr and key made by gen_csr() and gen_key() or
138 # a signed server certificate using the CA cert previously
139 # created by gen_crt()
140 #
141 # Access: private
142 gen_crt() {
143         local base=$(get_base "$1")
144         if [ "${1}" ] ; then
145                 ebegin "Generating self-signed X.509 Certificate for CA"
146                 openssl x509 -extfile "${SSL_CONF}" \
147                         -days ${SSL_DAYS} -req -signkey "${base}.key" \
148                         -in "${base}.csr" -out "${base}.crt" &>/dev/null
149         else
150                 local ca=$(get_base 1)
151                 ebegin "Generating authority-signed X.509 Certificate"
152                 openssl x509 -extfile "${SSL_CONF}" \
153                         -days ${SSL_DAYS} -req -CAserial "${SSL_SERIAL}" \
154                         -CAkey "${ca}.key" -CA "${ca}.crt" \
155                         -in "${base}.csr" -out "${base}.crt" &>/dev/null
156         fi
157         eend $?
158
159         return $?
160 }
161
162 # @FUNCTION: gen_pem
163 # @USAGE: <base path>
164 # @DESCRIPTION:
165 # Generates a PEM file by concatinating the key
166 # and cert file created by gen_key() and gen_cert()
167 #
168 # Access: private
169 gen_pem() {
170         local base=$(get_base "$1")
171         ebegin "Generating PEM Certificate"
172         (cat "${base}.key"; echo; cat "${base}.crt") > "${base}.pem"
173         eend $?
174
175         return $?
176 }
177
178 # @FUNCTION: install_cert
179 # @USAGE: <certificates>
180 # @DESCRIPTION:
181 # Uses all the private functions above to generate and install the
182 # requested certificates.
183 # <certificates> are full pathnames relative to ROOT, without extension.
184 #
185 # Example: "install_cert /foo/bar" installs ${ROOT}/foo/bar.{key,csr,crt,pem}
186 #
187 # Access: public
188 install_cert() {
189         if [ $# -lt 1 ] ; then
190                 eerror "At least one argument needed"
191                 return 1;
192         fi
193
194         case ${EBUILD_PHASE} in
195         unpack|prepare|configure|compile|test|install)
196                 die "install_cert cannot be called in ${EBUILD_PHASE}"
197                 ;;
198         esac
199
200         # Generate a CA environment #164601
201         gen_cnf 1 || return 1
202         gen_key 1 || return 1
203         gen_csr 1 || return 1
204         gen_crt 1 || return 1
205         echo
206
207         gen_cnf || return 1
208         echo
209
210         local count=0
211         for cert in "$@" ; do
212                 # Check the requested certificate
213                 if [ -z "${cert##*/}" ] ; then
214                         ewarn "Invalid certification requested, skipping"
215                         continue
216                 fi
217
218                 # Check for previous existence of generated files
219                 for type in key csr crt pem ; do
220                         if [ -e "${ROOT}${cert}.${type}" ] ; then
221                                 ewarn "${ROOT}${cert}.${type}: exists, skipping"
222                                 continue 2
223                         fi
224                 done
225
226                 # Generate the requested files
227                 gen_key || continue
228                 gen_csr || continue
229                 gen_crt || continue
230                 gen_pem || continue
231                 echo
232
233                 # Install the generated files and set sane permissions
234                 local base=$(get_base)
235                 install -d "${ROOT}${cert%/*}"
236                 install -m0400 "${base}.key" "${ROOT}${cert}.key"
237                 install -m0444 "${base}.csr" "${ROOT}${cert}.csr"
238                 install -m0444 "${base}.crt" "${ROOT}${cert}.crt"
239                 install -m0400 "${base}.pem" "${ROOT}${cert}.pem"
240                 : $(( ++count ))
241         done
242
243         # Resulting status
244         if [ ${count} = 0 ] ; then
245                 eerror "No certificates were generated"
246                 return 1
247         elif [ ${count} != ${#} ] ; then
248                 ewarn "Some requested certificates were not generated"
249         fi
250 }