1 /* $Id$ */
2
3 /*
4 *
5 * Copyright (C) 2005 David Mazieres (dm@uun.org)
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2, or (at
10 * your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 * USA
21 *
22 */
23
24 #include "asmtpd.h"
25 #include "async_ssl.h"
26
27 static bool ssl_initialized;
28 static u_int64_t ssl_initno;
29 static SSL_CTX *ctx;
30 static bssstr ssl_randfile;
31
32 static void
ssl_shutdown()33 ssl_shutdown ()
34 {
35 if (ssl_randfile) {
36 RAND_write_file (ssl_randfile);
37 ssl_randfile = NULL;
38 }
39 }
40
41 static u_int64_t ssl_tmpkey_initno;
42 static RSA *ssl_tmpkey_key;
43 timecb_t *ssl_tmpkey_tmo;
44 static void
45 ssl_tmpkey_erase (bool timedout = false)
46 {
47 if (!timedout && ssl_tmpkey_tmo)
48 timecb_remove (ssl_tmpkey_tmo);
49 ssl_tmpkey_tmo = NULL;
50 RSA_free (ssl_tmpkey_key);
51 ssl_tmpkey_key = NULL;
52 }
53 static RSA *
ssl_tmpkey(SSL * ssl,int exp,int keylen)54 ssl_tmpkey (SSL *ssl, int exp, int keylen)
55 {
56 if (ssl_tmpkey_initno != opt->configno)
57 ssl_tmpkey_erase ();
58
59 if (ssl_tmpkey_key)
60 return ssl_tmpkey_key;
61
62 BIGNUM *bne = BN_new ();
63 BN_set_word (bne, 17);
64 RSA_generate_key_ex (ssl_tmpkey_key, keylen, bne, NULL);
65 BN_free (bne);
66
67 if (!ssl_tmpkey_tmo)
68 ssl_tmpkey_tmo = delaycb (3600, wrap (ssl_tmpkey_erase, true));
69 return ssl_tmpkey_key;
70 }
71
72 static DH *
ssl_dhparm(SSL *,int exp,int len)73 ssl_dhparm (SSL *, int exp, int len)
74 {
75 static qhash<int, DH *> parmtab;
76 if (DH **dhp = parmtab[len])
77 return *dhp;
78
79 DH *dh = NULL;
80 str cachefile = strbuf ("%s/dh%d.pem", opt->etcdir.cstr (), len);
81 if (FILE *fp = fopen (cachefile, "r")) {
82 dh = PEM_read_DHparams(fp, NULL, NULL, NULL);
83 fclose (fp);
84 }
85
86 if (!dh) {
87 warn << "Generating " << len << "-bit DH parameters... ";
88 err_flush ();
89 dh = DH_new ();
90 DH_generate_parameters_ex (dh, len, 2, NULL);
91 if (!dh) {
92 warn << "failed: " << ssl_err () << "\n";
93 DH_free (dh);
94 return NULL;
95 }
96 warnx << "done\n";
97
98 int fd = open (cachefile, O_CREAT|O_EXCL|O_WRONLY, 0644);
99 if (fd >= 0) {
100 if (FILE *fp = fdopen (fd, "w")) {
101 PEM_write_DHparams (fp, dh);
102 fclose (fp);
103 }
104 else
105 close (fd);
106 }
107 }
108
109 parmtab.insert (len, dh);
110 return dh;
111 }
112
113 static int
verify_cb(int,X509_STORE_CTX *)114 verify_cb (int, X509_STORE_CTX *)
115 {
116 return 1;
117 }
118
119 bool
ssl_init()120 ssl_init ()
121 {
122 if (ssl_initno == opt->configno)
123 return opt->ssl_status > 0;
124 opt->ssl_status = -1;
125 ssl_initno = opt->configno;
126
127 ssl_tmpkey_erase ();
128
129 if (!opt->ssl)
130 return false;
131
132 struct stat sb;
133 if (stat (opt->ssl_key, &sb) < 0) {
134 if (errno == ENOENT)
135 warn << "STARTTLS disabled (no file " << opt->ssl_key << ")\n";
136 else
137 warn << opt->ssl_key << ": " << strerror (errno) << "\n";
138 return false;
139 }
140 if (sb.st_mode & 044)
141 warn << "DANGER: " << opt->ssl_key << " should be read-protected\n";
142
143 if (!ssl_initialized) {
144 ssl_initialized = true;
145 SSL_load_error_strings ();
146 SSL_library_init ();
147 #ifdef SFS_DEV_RANDOM
148 if (RAND_load_file (SFS_DEV_RANDOM, 1024) <= 0)
149 warn << "DANGER: " << SFS_DEV_RANDOM ": " << ssl_err () << "\n";
150 #else /* !SFS_DEV_RANDOM */
151 ssl_randfile = opt->etcdir << "/.rnd";
152 if (RAND_load_file (ssl_randfile, 1024) <= 0)
153 warn << "DANGER: " << ssl_randfile << ": " << ssl_err () << "\n";
154 #endif /* !SFS_DEV_RANDOM */
155 atexit (ssl_shutdown);
156 }
157 else if (ssl_randfile)
158 RAND_write_file (ssl_randfile);
159
160 if (ctx)
161 SSL_CTX_free (ctx);
162 ctx = SSL_CTX_new (SSLv23_server_method ());
163 if (!ctx) {
164 warn << "SSL_CTX_new: " << ssl_err () << "\n";
165 return false;
166 }
167
168 bool verify = true;
169 if (SSL_CTX_load_verify_locations (ctx, opt->ssl_ca, NULL) <= 0) {
170 warn << opt->ssl_ca << ": " << ssl_err () << "\n";
171 verify = false;
172 }
173 if (verify)
174 SSL_CTX_set_verify (ctx, SSL_VERIFY_PEER, verify_cb);
175
176 if (!access (opt->ssl_crl, 0)) {
177 X509_STORE *store = SSL_CTX_get_cert_store (ctx);
178 X509_LOOKUP *lookup;
179 if ((lookup = X509_STORE_add_lookup (store, X509_LOOKUP_file ()))
180 && (X509_load_crl_file(lookup, opt->ssl_crl, X509_FILETYPE_PEM) == 1))
181 X509_STORE_set_flags(store, (X509_V_FLAG_CRL_CHECK |
182 X509_V_FLAG_CRL_CHECK_ALL));
183 }
184
185 if (SSL_CTX_use_certificate_file (ctx, opt->ssl_cert,
186 SSL_FILETYPE_PEM) <= 0) {
187 warn << opt->ssl_cert << ": " << ssl_err () << "\n";
188 return false;
189 }
190
191 if (SSL_CTX_use_PrivateKey_file (ctx, opt->ssl_key, SSL_FILETYPE_PEM) <= 0) {
192 warn << opt->ssl_key << ": " << ssl_err () << "\n";
193 return false;
194 }
195
196 if (SSL_CTX_check_private_key (ctx) <= 0) {
197 warn << opt->ssl_key << ": " << ssl_err () << "\n";
198 return false;
199 }
200
201 SSL_CTX_set_options (ctx, SSL_OP_ALL|SSL_OP_NO_SSLv2);
202 if (opt->ssl_ciphers
203 && SSL_CTX_set_cipher_list (ctx, opt->ssl_ciphers) <= 0) {
204 warn << "Cipher list " << opt->ssl_ciphers << ": " << ssl_err () << "\n";
205 return false;
206 }
207
208 SSL_CTX_set_tmp_rsa_callback (ctx, ssl_tmpkey);
209 SSL_CTX_set_tmp_dh_callback (ctx, ssl_dhparm);
210
211 u_char sessid[SSL_MAX_SSL_SESSION_ID_LENGTH];
212 if (RAND_bytes (sessid, sizeof (sessid)) >= 0)
213 SSL_CTX_set_session_id_context (ctx, sessid, sizeof (sessid));
214
215 opt->ssl_status = 1;
216 return true;
217 }
218
219
220 str
helo_starttls()221 smtpd::helo_starttls ()
222 {
223 if (!encrypted && !auth_user && opt->ssl_status > 0)
224 return "250-STARTTLS\r\n";
225 return "";
226 }
227
228 void
cmd_starttls(str cmd,str arg)229 smtpd::cmd_starttls (str cmd, str arg)
230 {
231 aiossl *ssl;
232 if (encrypted || auth_user || opt->ssl_status <= 0
233 || !(ssl = dynamic_cast<aiossl *> (aio.get ()))) {
234 respond ("502 command not implemented\r\n");
235 return;
236 }
237
238 reset ();
239 aio << "220 Starting TLS\r\n";
240 ssl->startssl (ctx, true);
241 encrypted = true;
242
243 ssl->verify_cb (wrap (this, &smtpd::set_quota_user));
244
245 cmdwait = true;
246 aio->readline (wrap (this, &smtpd::getcmd));
247 }
248
249 void
set_quota_user()250 smtpd::set_quota_user ()
251 {
252 if (!encrypted)
253 return;
254 aiossl *ssl = dynamic_cast<aiossl *> (aio.get ());
255 if (ssl && ssl->subject) {
256 quota_user = ssl->subject;
257 if (opt->ssl >= 2 && trust < TRUST_AUTH)
258 trust = TRUST_AUTH;
259 }
260 }
261
262 void
received_starttls(strbuf r)263 smtpd::received_starttls (strbuf r) const
264 {
265 if (!encrypted)
266 return;
267 aiossl *ssl = dynamic_cast<aiossl *> (aio.get ());
268 if (!ssl || !ssl->cipher)
269 return;
270
271 r << " (";
272 if (const char *vers = SSL_get_cipher_version (ssl->get_ssl ()))
273 r << vers;
274 else
275 r << "SSL";
276 int cipher_bits, alg_bits = 0;
277 cipher_bits = SSL_get_cipher_bits (ssl->get_ssl (), &alg_bits);
278 r << " " << ssl->cipher << " " << cipher_bits << "/" << alg_bits;
279
280 if (ssl->subject) {
281 r << ",\n ";
282 if (ssl->issuer)
283 r << " issuer=" << ssl->issuer << ",";
284 r << " subject=" << ssl->subject << ")\n";
285 }
286 else
287 r << ")\n";
288
289 }
290
291 void
env_starttls(vec<str> * envp)292 smtpd::env_starttls (vec<str> *envp) const
293 {
294 if (!encrypted)
295 return;
296 aiossl *ssl = dynamic_cast<aiossl *> (aio.get ());
297 if (!ssl || !ssl->cipher)
298 return;
299
300 envp->push_back (strbuf () << "SSL_CIPHER=" << ssl->cipher);
301
302 int cipher_bits, alg_bits = 0;
303 cipher_bits = SSL_get_cipher_bits (ssl->get_ssl (), &alg_bits);
304 envp->push_back (strbuf ("SSL_CIPHER_BITS=%d", cipher_bits));
305 envp->push_back (strbuf ("SSL_ALG_BITS=%d", alg_bits));
306
307 if (const char *vers = SSL_get_cipher_version (ssl->get_ssl ()))
308 envp->push_back (strbuf () << "SSL_VERSION=" << vers);
309
310 if (ssl->issuer)
311 envp->push_back (strbuf () << "SSL_ISSUER=" << ssl->issuer);
312 if (ssl->issuer_dn)
313 envp->push_back (strbuf () << "SSL_ISSUER_DN=" << ssl->issuer_dn);
314 if (ssl->subject)
315 envp->push_back (strbuf () << "SSL_SUBJECT=" << ssl->subject);
316 if (ssl->subject_dn)
317 envp->push_back (strbuf () << "SSL_SUBJECT_DN=" << ssl->subject_dn);
318 }
319