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