Fix quotflt output channel (Gavin Troy)..
[s-mailx.git] / openssl.c
blob41575d87d8cfa5e2ca93a6ef5950581a737a8f75
1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ OpenSSL functions.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 - 2013 Steffen "Daode" Nurpmeso <sdaoden@users.sf.net>.
6 */
7 /*
8 * Copyright (c) 2002
9 * Gunnar Ritter. All rights reserved.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by Gunnar Ritter
22 * and his contributors.
23 * 4. Neither the name of Gunnar Ritter nor the names of his contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY GUNNAR RITTER AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL GUNNAR RITTER OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
40 #include "config.h"
42 #ifndef HAVE_OPENSSL
43 typedef int avoid_empty_file_compiler_warning;
44 #else
45 #include "rcv.h"
47 #include <sys/socket.h>
48 #include <sys/stat.h>
49 #include <dirent.h>
50 #include <errno.h>
51 #include <netdb.h>
52 #include <netinet/in.h>
53 #include <openssl/crypto.h>
54 #include <openssl/ssl.h>
55 #include <openssl/err.h>
56 #include <openssl/x509v3.h>
57 #include <openssl/x509.h>
58 #include <openssl/pem.h>
59 #include <openssl/rand.h>
60 #include <stdio.h>
61 #include <setjmp.h>
62 #include <termios.h>
63 #include <time.h>
64 #include <unistd.h>
65 #ifdef HAVE_ARPA_INET_H
66 # include <arpa/inet.h>
67 #endif
69 #include "extern.h"
72 * OpenSSL client implementation according to: John Viega, Matt Messier,
73 * Pravir Chandra: Network Security with OpenSSL. Sebastopol, CA 2002.
76 static sigjmp_buf ssljmp;
78 static int initialized;
79 static int rand_init;
80 static int message_number;
81 static int verify_error_found;
83 static void sslcatch(int s);
84 static int ssl_rand_init(void);
85 static void ssl_init(void);
86 static int ssl_verify_cb(int success, X509_STORE_CTX *store);
87 static const SSL_METHOD *ssl_select_method(const char *uhp);
88 static void ssl_load_verifications(struct sock *sp);
89 static void ssl_certificate(struct sock *sp, const char *uhp);
90 static enum okay ssl_check_host(const char *server, struct sock *sp);
91 #ifdef HAVE_STACK_OF
92 static int smime_verify(struct message *m, int n, STACK_OF(X509) *chain,
93 X509_STORE *store);
94 #else
95 static int smime_verify(struct message *m, int n, STACK *chain,
96 X509_STORE *store);
97 #endif
98 static EVP_CIPHER *smime_cipher(const char *name);
99 static int ssl_password_cb(char *buf, int size, int rwflag, void *userdata);
100 static FILE *smime_sign_cert(const char *xname, const char *xname2, int warn);
101 static char *smime_sign_include_certs(char const *name);
102 #ifdef HAVE_STACK_OF
103 static int smime_sign_include_chain_creat(STACK_OF(X509) **chain, char *cfiles);
104 #else
105 static int smime_sign_include_chain_creat(STACK **chain, char *cfiles);
106 #endif
107 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
108 static enum okay load_crl1(X509_STORE *store, const char *name);
109 #endif
110 static enum okay load_crls(X509_STORE *store, const char *vfile,
111 const char *vdir);
113 static void
114 sslcatch(int s)
116 termios_state_reset();
117 siglongjmp(ssljmp, s);
120 static int
121 ssl_rand_init(void)
123 char *cp, *x;
124 int state = 0;
126 if ((cp = value("ssl-rand-egd")) != NULL) {
127 if ((x = file_expand(cp)) == NULL || RAND_egd(cp = x) == -1)
128 fprintf(stderr, tr(245,
129 "entropy daemon at \"%s\" not available\n"),
130 cp);
131 else
132 state = 1;
133 } else if ((cp = value("ssl-rand-file")) != NULL) {
134 if ((x = file_expand(cp)) == NULL ||
135 RAND_load_file(cp = x, 1024) == -1)
136 fprintf(stderr, tr(246,
137 "entropy file at \"%s\" not available\n"), cp);
138 else {
139 struct stat st;
141 if (stat(cp, &st) == 0 && S_ISREG(st.st_mode) &&
142 access(cp, W_OK) == 0) {
143 if (RAND_write_file(cp) == -1) {
144 fprintf(stderr, catgets(catd, CATSET,
145 247,
146 "writing entropy data to \"%s\" failed\n"), cp);
149 state = 1;
152 return state;
155 static void
156 ssl_init(void)
158 if (initialized == 0) {
159 SSL_library_init();
160 initialized = 1;
162 if (rand_init == 0)
163 rand_init = ssl_rand_init();
166 static int
167 ssl_verify_cb(int success, X509_STORE_CTX *store)
169 if (success == 0) {
170 char data[256];
171 X509 *cert = X509_STORE_CTX_get_current_cert(store);
172 int depth = X509_STORE_CTX_get_error_depth(store);
173 int err = X509_STORE_CTX_get_error(store);
175 verify_error_found = 1;
176 if (message_number)
177 fprintf(stderr, "Message %d: ", message_number);
178 fprintf(stderr, catgets(catd, CATSET, 229,
179 "Error with certificate at depth: %i\n"),
180 depth);
181 X509_NAME_oneline(X509_get_issuer_name(cert), data,
182 sizeof data);
183 fprintf(stderr, catgets(catd, CATSET, 230, " issuer = %s\n"),
184 data);
185 X509_NAME_oneline(X509_get_subject_name(cert), data,
186 sizeof data);
187 fprintf(stderr, catgets(catd, CATSET, 231, " subject = %s\n"),
188 data);
189 fprintf(stderr, catgets(catd, CATSET, 232, " err %i: %s\n"),
190 err, X509_verify_cert_error_string(err));
191 if (ssl_vrfy_decide() != OKAY)
192 return 0;
194 return 1;
197 static const SSL_METHOD *
198 ssl_select_method(const char *uhp)
200 const SSL_METHOD *method;
201 char *cp;
203 cp = ssl_method_string(uhp);
204 if (cp != NULL) {
205 #ifndef OPENSSL_NO_SSL2
206 if (strcmp(cp, "ssl2") == 0)
207 method = SSLv2_client_method();
208 else
209 #endif
210 if (strcmp(cp, "ssl3") == 0)
211 method = SSLv3_client_method();
212 else if (strcmp(cp, "tls1") == 0)
213 method = TLSv1_client_method();
214 else {
215 fprintf(stderr, tr(244, "Invalid SSL method \"%s\"\n"),
216 cp);
217 method = SSLv23_client_method();
219 } else
220 method = SSLv23_client_method();
221 return method;
224 static void
225 ssl_load_verifications(struct sock *sp)
227 char *ca_dir, *ca_file;
228 X509_STORE *store;
230 if (ssl_vrfy_level == VRFY_IGNORE)
231 return;
232 if ((ca_dir = value("ssl-ca-dir")) != NULL)
233 ca_dir = file_expand(ca_dir);
234 if ((ca_file = value("ssl-ca-file")) != NULL)
235 ca_file = file_expand(ca_file);
236 if (ca_dir != NULL || ca_file != NULL) {
237 if (SSL_CTX_load_verify_locations(sp->s_ctx,
238 ca_file, ca_dir) != 1) {
239 fprintf(stderr, catgets(catd, CATSET, 233,
240 "Error loading"));
241 if (ca_dir) {
242 fprintf(stderr, catgets(catd, CATSET, 234,
243 " %s"), ca_dir);
244 if (ca_file)
245 fprintf(stderr, catgets(catd, CATSET,
246 235, " or"));
248 if (ca_file)
249 fprintf(stderr, catgets(catd, CATSET, 236,
250 " %s"), ca_file);
251 fprintf(stderr, catgets(catd, CATSET, 237, "\n"));
254 if (value("ssl-no-default-ca") == NULL) {
255 if (SSL_CTX_set_default_verify_paths(sp->s_ctx) != 1)
256 fprintf(stderr, catgets(catd, CATSET, 243,
257 "Error loading default CA locations\n"));
259 verify_error_found = 0;
260 message_number = 0;
261 SSL_CTX_set_verify(sp->s_ctx, SSL_VERIFY_PEER, ssl_verify_cb);
262 store = SSL_CTX_get_cert_store(sp->s_ctx);
263 load_crls(store, "ssl-crl-file", "ssl-crl-dir");
266 static void
267 ssl_certificate(struct sock *sp, const char *uhp)
269 size_t i;
270 char *certvar, *keyvar, *cert, *key, *x;
272 i = strlen(uhp);
273 certvar = ac_alloc(i + 9 + 1);
274 memcpy(certvar, "ssl-cert-", 9);
275 memcpy(certvar + 9, uhp, i + 1);
276 if ((cert = value(certvar)) != NULL ||
277 (cert = value("ssl-cert")) != NULL) {
278 x = cert;
279 if ((cert = file_expand(cert)) == NULL) {
280 cert = x;
281 goto jbcert;
282 } else if (SSL_CTX_use_certificate_chain_file(sp->s_ctx, cert)
283 == 1) {
284 keyvar = ac_alloc(strlen(uhp) + 9);
285 strcpy(keyvar, "ssl-key-");
286 if ((key = value(keyvar)) == NULL &&
287 (key = value("ssl-key")) == NULL)
288 key = cert;
289 else if ((x = key, key = file_expand(key)) == NULL) {
290 key = x;
291 goto jbkey;
293 if (SSL_CTX_use_PrivateKey_file(sp->s_ctx, key,
294 SSL_FILETYPE_PEM) != 1)
295 jbkey: fprintf(stderr, tr(238,
296 "cannot load private key from file "
297 "%s\n"), key);
298 ac_free(keyvar);
299 } else
300 jbcert: fprintf(stderr, tr(239,
301 "cannot load certificate from file %s\n"),
302 cert);
304 ac_free(certvar);
307 static enum okay
308 ssl_check_host(const char *server, struct sock *sp)
310 X509 *cert;
311 X509_NAME *subj;
312 char data[256];
313 #ifdef HAVE_STACK_OF
314 STACK_OF(GENERAL_NAME) *gens;
315 #else
316 /*GENERAL_NAMES*/STACK *gens;
317 #endif
318 GENERAL_NAME *gen;
319 int i;
321 if ((cert = SSL_get_peer_certificate(sp->s_ssl)) == NULL) {
322 fprintf(stderr, catgets(catd, CATSET, 248,
323 "no certificate from \"%s\"\n"), server);
324 return STOP;
326 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
327 if (gens != NULL) {
328 for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
329 gen = sk_GENERAL_NAME_value(gens, i);
330 if (gen->type == GEN_DNS) {
331 if (options & OPT_VERBOSE)
332 fprintf(stderr,
333 "Comparing DNS name: \"%s\"\n",
334 gen->d.ia5->data);
335 if (rfc2595_hostname_match(server,
336 (char *)gen->d.ia5->data)
337 == OKAY)
338 goto found;
342 if ((subj = X509_get_subject_name(cert)) != NULL &&
343 X509_NAME_get_text_by_NID(subj, NID_commonName,
344 data, sizeof data) > 0) {
345 data[sizeof data - 1] = 0;
346 if (options & OPT_VERBOSE)
347 fprintf(stderr, "Comparing common name: \"%s\"\n",
348 data);
349 if (rfc2595_hostname_match(server, data) == OKAY)
350 goto found;
352 X509_free(cert);
353 return STOP;
354 found: X509_free(cert);
355 return OKAY;
358 enum okay
359 ssl_open(const char *server, struct sock *sp, const char *uhp)
361 char *cp;
362 long opts;
364 ssl_init();
365 ssl_set_vrfy_level(uhp);
366 if ((sp->s_ctx =
367 SSL_CTX_new(UNCONST(ssl_select_method(uhp))))
368 == NULL) {
369 ssl_gen_err(catgets(catd, CATSET, 261, "SSL_CTX_new() failed"));
370 return STOP;
372 #ifdef SSL_MODE_AUTO_RETRY
373 /* available with OpenSSL 0.9.6 or later */
374 SSL_CTX_set_mode(sp->s_ctx, SSL_MODE_AUTO_RETRY);
375 #endif /* SSL_MODE_AUTO_RETRY */
376 opts = SSL_OP_ALL;
377 if (value("ssl-v2-allow") == NULL)
378 opts |= SSL_OP_NO_SSLv2;
379 SSL_CTX_set_options(sp->s_ctx, opts);
380 ssl_load_verifications(sp);
381 ssl_certificate(sp, uhp);
382 if ((cp = value("ssl-cipher-list")) != NULL) {
383 if (SSL_CTX_set_cipher_list(sp->s_ctx, cp) != 1)
384 fprintf(stderr, catgets(catd, CATSET, 240,
385 "invalid ciphers: %s\n"), cp);
387 if ((sp->s_ssl = SSL_new(sp->s_ctx)) == NULL) {
388 ssl_gen_err(catgets(catd, CATSET, 262, "SSL_new() failed"));
389 return STOP;
391 SSL_set_fd(sp->s_ssl, sp->s_fd);
392 if (SSL_connect(sp->s_ssl) < 0) {
393 ssl_gen_err(catgets(catd, CATSET, 263,
394 "could not initiate SSL/TLS connection"));
395 return STOP;
397 if (ssl_vrfy_level != VRFY_IGNORE) {
398 if (ssl_check_host(server, sp) != OKAY) {
399 fprintf(stderr, catgets(catd, CATSET, 249,
400 "host certificate does not match \"%s\"\n"),
401 server);
402 if (ssl_vrfy_decide() != OKAY)
403 return STOP;
406 sp->s_use_ssl = 1;
407 return OKAY;
410 void
411 ssl_gen_err(const char *fmt, ...)
413 va_list ap;
415 va_start(ap, fmt);
416 vfprintf(stderr, fmt, ap);
417 va_end(ap);
418 SSL_load_error_strings();
419 fprintf(stderr, ": %s\n",
420 (ERR_error_string(ERR_get_error(), NULL)));
423 FILE *
424 smime_sign(FILE *ip, struct header *headp)
426 FILE *sp, *fp, *bp, *hp;
427 char *cp;
428 char const *addr;
429 X509 *cert;
430 #ifdef HAVE_STACK_OF
431 STACK_OF(X509) *chain = NULL;
432 #else
433 STACK *chain = NULL;
434 #endif
435 PKCS7 *pkcs7;
436 EVP_PKEY *pkey;
437 BIO *bb, *sb;
439 ssl_init();
440 if ((addr = myorigin(headp)) == NULL) {
441 fprintf(stderr, "No \"from\" address for signing specified\n");
442 return NULL;
444 if ((fp = smime_sign_cert(addr, NULL, 1)) == NULL)
445 return NULL;
446 if ((pkey = PEM_read_PrivateKey(fp, NULL, ssl_password_cb, NULL))
447 == NULL) {
448 ssl_gen_err("Error reading private key from");
449 Fclose(fp);
450 return NULL;
452 rewind(fp);
453 if ((cert = PEM_read_X509(fp, NULL, ssl_password_cb, NULL)) == NULL) {
454 ssl_gen_err("Error reading signer certificate from");
455 Fclose(fp);
456 EVP_PKEY_free(pkey);
457 return NULL;
459 Fclose(fp);
460 if ((cp = smime_sign_include_certs(addr)) != NULL &&
461 !smime_sign_include_chain_creat(&chain, cp)) {
462 X509_free(cert);
463 EVP_PKEY_free(pkey);
464 return NULL;
466 if ((sp = Ftemp(&cp, "Rs", "w+", 0600, 1)) == NULL) {
467 perror("tempfile");
468 if (chain != NULL)
469 sk_X509_pop_free(chain, X509_free);
470 X509_free(cert);
471 EVP_PKEY_free(pkey);
472 return NULL;
474 rm(cp);
475 Ftfree(&cp);
476 rewind(ip);
477 if (smime_split(ip, &hp, &bp, -1, 0) == STOP) {
478 Fclose(sp);
479 if (chain != NULL)
480 sk_X509_pop_free(chain, X509_free);
481 X509_free(cert);
482 EVP_PKEY_free(pkey);
483 return NULL;
485 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
486 (sb = BIO_new_fp(sp, BIO_NOCLOSE)) == NULL) {
487 ssl_gen_err("Error creating BIO signing objects");
488 Fclose(sp);
489 if (chain != NULL)
490 sk_X509_pop_free(chain, X509_free);
491 X509_free(cert);
492 EVP_PKEY_free(pkey);
493 return NULL;
495 if ((pkcs7 = PKCS7_sign(cert, pkey, chain, bb,
496 PKCS7_DETACHED)) == NULL) {
497 ssl_gen_err("Error creating the PKCS#7 signing object");
498 BIO_free(bb);
499 BIO_free(sb);
500 Fclose(sp);
501 if (chain != NULL)
502 sk_X509_pop_free(chain, X509_free);
503 X509_free(cert);
504 EVP_PKEY_free(pkey);
505 return NULL;
507 if (PEM_write_bio_PKCS7(sb, pkcs7) == 0) {
508 ssl_gen_err("Error writing signed S/MIME data");
509 BIO_free(bb);
510 BIO_free(sb);
511 Fclose(sp);
512 if (chain != NULL)
513 sk_X509_pop_free(chain, X509_free);
514 X509_free(cert);
515 EVP_PKEY_free(pkey);
516 return NULL;
518 BIO_free(bb);
519 BIO_free(sb);
520 if (chain != NULL)
521 sk_X509_pop_free(chain, X509_free);
522 X509_free(cert);
523 EVP_PKEY_free(pkey);
524 rewind(bp);
525 fflush(sp);
526 rewind(sp);
527 return smime_sign_assemble(hp, bp, sp);
530 static int
531 #ifdef HAVE_STACK_OF
532 smime_verify(struct message *m, int n, STACK_OF(X509) *chain, X509_STORE *store)
533 #else
534 smime_verify(struct message *m, int n, STACK *chain, X509_STORE *store)
535 #endif
537 struct message *x;
538 char *cp, *sender, *to, *cc, *cnttype;
539 int c, i, j;
540 FILE *fp, *ip;
541 off_t size;
542 BIO *fb, *pb;
543 PKCS7 *pkcs7;
544 #ifdef HAVE_STACK_OF
545 STACK_OF(X509) *certs;
546 STACK_OF(GENERAL_NAME) *gens;
547 #else
548 STACK *certs, *gens;
549 #endif
550 X509 *cert;
551 X509_NAME *subj;
552 char data[LINESIZE];
553 GENERAL_NAME *gen;
555 verify_error_found = 0;
556 message_number = n;
557 loop: sender = getsender(m);
558 to = hfield1("to", m);
559 cc = hfield1("cc", m);
560 cnttype = hfield1("content-type", m);
561 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
562 return 1;
563 if (cnttype && strncmp(cnttype, "application/x-pkcs7-mime", 24) == 0) {
564 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
565 return 1;
566 if (x != (struct message *)-1) {
567 m = x;
568 goto loop;
571 size = m->m_size;
572 if ((fp = Ftemp(&cp, "Rv", "w+", 0600, 1)) == NULL) {
573 perror("tempfile");
574 return 1;
576 rm(cp);
577 Ftfree(&cp);
578 while (size-- > 0) {
579 c = getc(ip);
580 putc(c, fp);
582 fflush(fp);
583 rewind(fp);
584 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
585 ssl_gen_err("Error creating BIO verification object "
586 "for message %d", n);
587 Fclose(fp);
588 return 1;
590 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
591 ssl_gen_err("Error reading PKCS#7 object for message %d", n);
592 BIO_free(fb);
593 Fclose(fp);
594 return 1;
596 if (PKCS7_verify(pkcs7, chain, store, pb, NULL, 0) != 1) {
597 ssl_gen_err("Error verifying message %d", n);
598 BIO_free(fb);
599 Fclose(fp);
600 return 1;
602 BIO_free(fb);
603 Fclose(fp);
604 if (sender == NULL) {
605 fprintf(stderr,
606 "Warning: Message %d has no sender.\n", n);
607 return 0;
609 certs = PKCS7_get0_signers(pkcs7, chain, 0);
610 if (certs == NULL) {
611 fprintf(stderr, "No certificates found in message %d.\n", n);
612 return 1;
614 for (i = 0; i < sk_X509_num(certs); i++) {
615 cert = sk_X509_value(certs, i);
616 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
617 if (gens != NULL) {
618 for (j = 0; j < sk_GENERAL_NAME_num(gens); j++) {
619 gen = sk_GENERAL_NAME_value(gens, j);
620 if (gen->type == GEN_EMAIL) {
621 if (options & OPT_VERBOSE)
622 fprintf(stderr,
623 "Comparing alt. "
624 "address: %s\"\n",
625 data);
626 if (!asccasecmp((char *)
627 gen->d.ia5->data,
628 sender))
629 goto found;
633 if ((subj = X509_get_subject_name(cert)) != NULL &&
634 X509_NAME_get_text_by_NID(subj,
635 NID_pkcs9_emailAddress,
636 data, sizeof data) > 0) {
637 data[sizeof data - 1] = 0;
638 if (options & OPT_VERBOSE)
639 fprintf(stderr, "Comparing address: \"%s\"\n",
640 data);
641 if (asccasecmp(data, sender) == 0)
642 goto found;
645 fprintf(stderr, "Message %d: certificate does not match <%s>\n",
646 n, sender);
647 return 1;
648 found: if (verify_error_found == 0)
649 printf("Message %d was verified successfully.\n", n);
650 return verify_error_found;
653 int
654 cverify(void *vp)
656 int *msgvec = vp, *ip;
657 int ec = 0;
658 #ifdef HAVE_STACK_OF
659 STACK_OF(X509) *chain = NULL;
660 #else
661 STACK *chain = NULL;
662 #endif
663 X509_STORE *store;
664 char *ca_dir, *ca_file;
666 ssl_init();
667 ssl_vrfy_level = VRFY_STRICT;
668 if ((store = X509_STORE_new()) == NULL) {
669 ssl_gen_err("Error creating X509 store");
670 return 1;
672 X509_STORE_set_verify_cb_func(store, ssl_verify_cb);
673 if ((ca_dir = value("smime-ca-dir")) != NULL)
674 ca_dir = file_expand(ca_dir);
675 if ((ca_file = value("smime-ca-file")) != NULL)
676 ca_file = file_expand(ca_file);
677 if (ca_dir != NULL || ca_file != NULL) {
678 if (X509_STORE_load_locations(store, ca_file, ca_dir) != 1) {
679 ssl_gen_err("Error loading %s",
680 ca_file ? ca_file : ca_dir);
681 return 1;
684 if (value("smime-no-default-ca") == NULL) {
685 if (X509_STORE_set_default_paths(store) != 1) {
686 ssl_gen_err("Error loading default CA locations");
687 return 1;
690 if (load_crls(store, "smime-crl-file", "smime-crl-dir") != OKAY)
691 return 1;
692 for (ip = msgvec; *ip; ip++) {
693 setdot(&message[*ip-1]);
694 ec |= smime_verify(&message[*ip-1], *ip, chain, store);
696 return ec;
699 static EVP_CIPHER *
700 smime_cipher(const char *name)
702 const EVP_CIPHER *cipher;
703 char *vn, *cp;
704 int vs;
706 vn = ac_alloc(vs = strlen(name) + 30);
707 snprintf(vn, vs, "smime-cipher-%s", name);
708 if ((cp = value(vn)) != NULL) {
709 if (strcmp(cp, "rc2-40") == 0)
710 cipher = EVP_rc2_40_cbc();
711 else if (strcmp(cp, "rc2-64") == 0)
712 cipher = EVP_rc2_64_cbc();
713 else if (strcmp(cp, "des") == 0)
714 cipher = EVP_des_cbc();
715 else if (strcmp(cp, "des-ede3") == 0)
716 cipher = EVP_des_ede3_cbc();
717 else {
718 fprintf(stderr, "Invalid cipher \"%s\".\n", cp);
719 cipher = NULL;
721 } else
722 cipher = EVP_des_ede3_cbc();
723 ac_free(vn);
724 return UNCONST(cipher);
727 FILE *
728 smime_encrypt(FILE *ip, const char *xcertfile, const char *to)
730 char *certfile = UNCONST(xcertfile), *cp;
731 FILE *yp, *fp, *bp, *hp;
732 X509 *cert;
733 PKCS7 *pkcs7;
734 BIO *bb, *yb;
735 #ifdef HAVE_STACK_OF
736 STACK_OF(X509) *certs;
737 #else
738 STACK *certs;
739 #endif
740 EVP_CIPHER *cipher;
742 if ((certfile = file_expand(certfile)) == NULL)
743 return NULL;
745 ssl_init();
746 if ((cipher = smime_cipher(to)) == NULL)
747 return NULL;
748 if ((fp = Fopen(certfile, "r")) == NULL) {
749 perror(certfile);
750 return NULL;
752 if ((cert = PEM_read_X509(fp, NULL, ssl_password_cb, NULL)) == NULL) {
753 ssl_gen_err("Error reading encryption certificate from \"%s\"",
754 certfile);
755 Fclose(fp);
756 return NULL;
758 Fclose(fp);
759 certs = sk_X509_new_null();
760 sk_X509_push(certs, cert);
761 if ((yp = Ftemp(&cp, "Ry", "w+", 0600, 1)) == NULL) {
762 perror("tempfile");
763 return NULL;
765 rm(cp);
766 Ftfree(&cp);
767 rewind(ip);
768 if (smime_split(ip, &hp, &bp, -1, 0) == STOP) {
769 Fclose(yp);
770 return NULL;
772 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
773 (yb = BIO_new_fp(yp, BIO_NOCLOSE)) == NULL) {
774 ssl_gen_err("Error creating BIO encryption objects");
775 Fclose(yp);
776 return NULL;
778 if ((pkcs7 = PKCS7_encrypt(certs, bb, cipher, 0)) == NULL) {
779 ssl_gen_err("Error creating the PKCS#7 encryption object");
780 BIO_free(bb);
781 BIO_free(yb);
782 Fclose(yp);
783 return NULL;
785 if (PEM_write_bio_PKCS7(yb, pkcs7) == 0) {
786 ssl_gen_err("Error writing encrypted S/MIME data");
787 BIO_free(bb);
788 BIO_free(yb);
789 Fclose(yp);
790 return NULL;
792 BIO_free(bb);
793 BIO_free(yb);
794 Fclose(bp);
795 fflush(yp);
796 rewind(yp);
797 return smime_encrypt_assemble(hp, yp);
800 struct message *
801 smime_decrypt(struct message *m, const char *to, const char *cc, int signcall)
803 FILE *fp, *bp, *hp, *op;
804 char *cp;
805 X509 *cert = NULL;
806 PKCS7 *pkcs7;
807 EVP_PKEY *pkey = NULL;
808 BIO *bb, *pb, *ob;
809 long size = m->m_size;
810 FILE *yp;
812 if ((yp = setinput(&mb, m, NEED_BODY)) == NULL)
813 return NULL;
814 ssl_init();
815 if ((fp = smime_sign_cert(to, cc, 0)) != NULL) {
816 if ((pkey = PEM_read_PrivateKey(fp, NULL, ssl_password_cb,
817 NULL)) == NULL) {
818 ssl_gen_err("Error reading private key");
819 Fclose(fp);
820 return NULL;
822 rewind(fp);
823 if ((cert = PEM_read_X509(fp, NULL, ssl_password_cb,
824 NULL)) == NULL) {
825 ssl_gen_err("Error reading decryption certificate");
826 Fclose(fp);
827 EVP_PKEY_free(pkey);
828 return NULL;
830 Fclose(fp);
832 if ((op = Ftemp(&cp, "Rp", "w+", 0600, 1)) == NULL) {
833 perror("tempfile");
834 if (cert)
835 X509_free(cert);
836 if (pkey)
837 EVP_PKEY_free(pkey);
838 return NULL;
840 rm(cp);
841 Ftfree(&cp);
842 if (smime_split(yp, &hp, &bp, size, 1) == STOP) {
843 Fclose(op);
844 if (cert)
845 X509_free(cert);
846 if (pkey)
847 EVP_PKEY_free(pkey);
848 return NULL;
850 if ((ob = BIO_new_fp(op, BIO_NOCLOSE)) == NULL ||
851 (bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL) {
852 ssl_gen_err("Error creating BIO decryption objects");
853 Fclose(op);
854 if (cert)
855 X509_free(cert);
856 if (pkey)
857 EVP_PKEY_free(pkey);
858 return NULL;
860 if ((pkcs7 = SMIME_read_PKCS7(bb, &pb)) == NULL) {
861 ssl_gen_err("Error reading PKCS#7 object");
862 Fclose(op);
863 if (cert)
864 X509_free(cert);
865 if (pkey)
866 EVP_PKEY_free(pkey);
867 return NULL;
869 if (PKCS7_type_is_signed(pkcs7)) {
870 if (signcall) {
871 BIO_free(bb);
872 BIO_free(ob);
873 if (cert)
874 X509_free(cert);
875 if (pkey)
876 EVP_PKEY_free(pkey);
877 Fclose(op);
878 Fclose(bp);
879 Fclose(hp);
880 setinput(&mb, m, NEED_BODY);
881 return (struct message *)-1;
883 if (PKCS7_verify(pkcs7, NULL, NULL, NULL, ob,
884 PKCS7_NOVERIFY|PKCS7_NOSIGS) != 1)
885 goto err;
886 fseek(hp, 0L, SEEK_END);
887 fprintf(hp, "X-Encryption-Cipher: none\n");
888 fflush(hp);
889 rewind(hp);
890 } else if (pkey == NULL) {
891 fprintf(stderr, "No appropriate private key found.\n");
892 goto err2;
893 } else if (cert == NULL) {
894 fprintf(stderr, "No appropriate certificate found.\n");
895 goto err2;
896 } else if (PKCS7_decrypt(pkcs7, pkey, cert, ob, 0) != 1) {
897 err: ssl_gen_err("Error decrypting PKCS#7 object");
898 err2: BIO_free(bb);
899 BIO_free(ob);
900 Fclose(op);
901 Fclose(bp);
902 Fclose(hp);
903 if (cert)
904 X509_free(cert);
905 if (pkey)
906 EVP_PKEY_free(pkey);
907 return NULL;
909 BIO_free(bb);
910 BIO_free(ob);
911 if (cert)
912 X509_free(cert);
913 if (pkey)
914 EVP_PKEY_free(pkey);
915 fflush(op);
916 rewind(op);
917 Fclose(bp);
918 return smime_decrypt_assemble(m, hp, op);
921 /*ARGSUSED4*/
922 static int
923 ssl_password_cb(char *buf, int size, int rwflag, void *userdata)
925 sighandler_type saveint;
926 char *pass = NULL;
927 int len;
928 (void)rwflag;
929 (void)userdata;
931 saveint = safe_signal(SIGINT, SIG_IGN);
932 if (sigsetjmp(ssljmp, 1) == 0) {
933 if (saveint != SIG_IGN)
934 safe_signal(SIGINT, sslcatch);
935 pass = getpassword("PEM pass phrase:");
937 safe_signal(SIGINT, saveint);
938 if (pass == NULL)
939 return 0;
940 len = strlen(pass);
941 if (len > size)
942 len = size;
943 memcpy(buf, pass, len);
944 return len;
947 static FILE *
948 smime_sign_cert(const char *xname, const char *xname2, int warn)
950 char *vn, *cp;
951 int vs;
952 FILE *fp;
953 struct name *np;
954 const char *name = xname, *name2 = xname2;
956 loop: if (name) {
957 np = lextract(name, GTO|GSKIN);
958 while (np) {
960 * This needs to be more intelligent since it will
961 * currently take the first name for which a private
962 * key is available regardless of whether it is the
963 * right one for the message.
965 vn = ac_alloc(vs = strlen(np->n_name) + 30);
966 snprintf(vn, vs, "smime-sign-cert-%s", np->n_name);
967 cp = value(vn);
968 ac_free(vn);
969 if (cp != NULL)
970 goto open;
971 np = np->n_flink;
973 if (name2) {
974 name = name2;
975 name2 = NULL;
976 goto loop;
979 if ((cp = value("smime-sign-cert")) != NULL)
980 goto open;
981 if (warn) {
982 fprintf(stderr, "Could not find a certificate for %s", xname);
983 if (xname2)
984 fprintf(stderr, "or %s", xname2);
985 fputc('\n', stderr);
987 return NULL;
988 open:
989 if ((cp = file_expand(cp)) == NULL)
990 return (NULL);
991 if ((fp = Fopen(cp, "r")) == NULL) {
992 perror(cp);
993 return NULL;
995 return fp;
998 static char *
999 smime_sign_include_certs(char const *name)
1001 char *ret;
1002 /* See comments in smime_sign_cert() for algorithm pitfalls */
1003 if (name) {
1004 struct name *np = lextract(name, GTO|GSKIN);
1005 while (np) {
1006 int vs;
1007 char *vn = ac_alloc(vs = strlen(np->n_name) + 30);
1008 snprintf(vn, vs, "smime-sign-include-certs-%s",
1009 np->n_name);
1010 ret = value(vn);
1011 ac_free(vn);
1012 if (ret != NULL)
1013 return ret;
1014 np = np->n_flink;
1017 return value("smime-sign-include-certs");
1020 static int
1021 smime_sign_include_chain_creat(
1022 #ifdef HAVE_STACK_OF
1023 STACK_OF(X509) **chain,
1024 #else
1025 STACK **chain,
1026 #endif
1027 char *cfiles)
1029 *chain = sk_X509_new_null();
1031 for (;;) {
1032 X509 *tmp;
1033 FILE *fp;
1034 char *x, *ncf = strchr(cfiles, ',');
1035 if (ncf)
1036 *ncf++ = '\0';
1037 /* This fails for '=,file' constructs, but those are sick */
1038 if (! *cfiles)
1039 break;
1041 if ((x = file_expand(cfiles)) == NULL ||
1042 (fp = Fopen(cfiles = x, "r")) == NULL) {
1043 perror(cfiles);
1044 goto jerr;
1046 if ((tmp = PEM_read_X509(fp, NULL, ssl_password_cb, NULL)
1047 ) == NULL) {
1048 ssl_gen_err("Error reading certificate from \"%s\"",
1049 cfiles);
1050 Fclose(fp);
1051 goto jerr;
1053 sk_X509_push(*chain, tmp);
1054 Fclose(fp);
1056 if (! ncf)
1057 break;
1058 cfiles = ncf;
1061 if (sk_X509_num(*chain) == 0) {
1062 fprintf(stderr, "smime-sign-include-certs defined but empty\n");
1063 goto jerr;
1066 jleave: return (*chain != NULL);
1068 jerr: sk_X509_pop_free(*chain, X509_free);
1069 *chain = NULL;
1070 goto jleave;
1073 enum okay
1074 smime_certsave(struct message *m, int n, FILE *op)
1076 struct message *x;
1077 char *cp, *to, *cc, *cnttype;
1078 int c, i;
1079 FILE *fp, *ip;
1080 off_t size;
1081 BIO *fb, *pb;
1082 PKCS7 *pkcs7;
1083 #ifdef HAVE_STACK_OF
1084 STACK_OF(X509) *certs;
1085 STACK_OF(X509) *chain = NULL;
1086 #else
1087 STACK *certs;
1088 STACK *chain = NULL;
1089 #endif
1090 X509 *cert;
1091 enum okay ok = OKAY;
1093 message_number = n;
1094 loop: to = hfield1("to", m);
1095 cc = hfield1("cc", m);
1096 cnttype = hfield1("content-type", m);
1097 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
1098 return STOP;
1099 if (cnttype && strncmp(cnttype, "application/x-pkcs7-mime", 24) == 0) {
1100 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
1101 return STOP;
1102 if (x != (struct message *)-1) {
1103 m = x;
1104 goto loop;
1107 size = m->m_size;
1108 if ((fp = Ftemp(&cp, "Rv", "w+", 0600, 1)) == NULL) {
1109 perror("tempfile");
1110 return STOP;
1112 rm(cp);
1113 Ftfree(&cp);
1114 while (size-- > 0) {
1115 c = getc(ip);
1116 putc(c, fp);
1118 fflush(fp);
1119 rewind(fp);
1120 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
1121 ssl_gen_err("Error creating BIO object for message %d", n);
1122 Fclose(fp);
1123 return STOP;
1125 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
1126 ssl_gen_err("Error reading PKCS#7 object for message %d", n);
1127 BIO_free(fb);
1128 Fclose(fp);
1129 return STOP;
1131 BIO_free(fb);
1132 Fclose(fp);
1133 certs = PKCS7_get0_signers(pkcs7, chain, 0);
1134 if (certs == NULL) {
1135 fprintf(stderr, "No certificates found in message %d.\n", n);
1136 return STOP;
1138 for (i = 0; i < sk_X509_num(certs); i++) {
1139 cert = sk_X509_value(certs, i);
1140 if (X509_print_fp(op, cert) == 0 ||
1141 PEM_write_X509(op, cert) == 0) {
1142 ssl_gen_err("Error writing certificate %d from "
1143 "message %d", i, n);
1144 ok = STOP;
1147 return ok;
1150 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1151 static enum okay
1152 load_crl1(X509_STORE *store, const char *name)
1154 X509_LOOKUP *lookup;
1156 if (options & OPT_VERBOSE)
1157 printf("Loading CRL from \"%s\".\n", name);
1158 if ((lookup = X509_STORE_add_lookup(store,
1159 X509_LOOKUP_file())) == NULL) {
1160 ssl_gen_err("Error creating X509 lookup object");
1161 return STOP;
1163 if (X509_load_crl_file(lookup, name, X509_FILETYPE_PEM) != 1) {
1164 ssl_gen_err("Error loading CRL from \"%s\"", name);
1165 return STOP;
1167 return OKAY;
1169 #endif /* new OpenSSL */
1171 static enum okay
1172 load_crls(X509_STORE *store, const char *vfile, const char *vdir)
1174 char *crl_file, *crl_dir;
1175 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1176 DIR *dirp;
1177 struct dirent *dp;
1178 char *fn = NULL;
1179 int fs = 0, ds, es;
1180 #endif /* new OpenSSL */
1182 if ((crl_file = value(vfile)) != NULL) {
1183 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1184 if ((crl_file = file_expand(crl_file)) == NULL ||
1185 load_crl1(store, crl_file) != OKAY)
1186 return STOP;
1187 #else /* old OpenSSL */
1188 fprintf(stderr,
1189 "This OpenSSL version is too old to use CRLs.\n");
1190 return STOP;
1191 #endif /* old OpenSSL */
1193 if ((crl_dir = value(vdir)) != NULL) {
1194 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1195 char *x;
1196 if ((x = file_expand(crl_dir)) == NULL ||
1197 (dirp = opendir(crl_dir = x)) == NULL) {
1198 perror(crl_dir);
1199 return STOP;
1201 ds = strlen(crl_dir);
1202 fn = smalloc(fs = ds + 20);
1203 memcpy(fn, crl_dir, ds);
1204 fn[ds] = '/';
1205 while ((dp = readdir(dirp)) != NULL) {
1206 if (dp->d_name[0] == '.' &&
1207 (dp->d_name[1] == '\0' ||
1208 (dp->d_name[1] == '.' &&
1209 dp->d_name[2] == '\0')))
1210 continue;
1211 if (dp->d_name[0] == '.')
1212 continue;
1213 if (ds + (es = strlen(dp->d_name)) + 2 < fs)
1214 fn = srealloc(fn, fs = ds + es + 20);
1215 memcpy(fn + ds + 1, dp->d_name, es + 1);
1216 if (load_crl1(store, fn) != OKAY) {
1217 closedir(dirp);
1218 free(fn);
1219 return STOP;
1222 closedir(dirp);
1223 free(fn);
1224 #else /* old OpenSSL */
1225 fprintf(stderr,
1226 "This OpenSSL version is too old to use CRLs.\n");
1227 return STOP;
1228 #endif /* old OpenSSL */
1230 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1231 if (crl_file || crl_dir)
1232 X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK |
1233 X509_V_FLAG_CRL_CHECK_ALL);
1234 #endif /* old OpenSSL */
1235 return OKAY;
1237 #endif /* HAVE_OPENSSL */