popen.c: fix compiler warnings
[s-mailx.git] / openssl.c
blobc47b6269810dc59d2a7c8750113dca8f4a76c26f
1 /*
2 * Heirloom mailx - a mail user agent derived from Berkeley Mail.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 Steffen "Daode" Nurpmeso.
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 #ifndef lint
41 #ifdef DOSCCS
42 static char sccsid[] = "@(#)openssl.c 1.26 (gritter) 5/26/09";
43 #endif
44 #endif /* not lint */
46 #include "config.h"
48 #ifdef USE_NSS
49 typedef int avoid_empty_file_compiler_warning;
50 #elif defined USE_OPENSSL
52 #include <setjmp.h>
53 #include <termios.h>
54 #include <stdio.h>
56 static int verbose;
57 static int reset_tio;
58 static struct termios otio;
59 static sigjmp_buf ssljmp;
61 #include <openssl/crypto.h>
62 #include <openssl/ssl.h>
63 #include <openssl/err.h>
64 #include <openssl/x509v3.h>
65 #include <openssl/x509.h>
66 #include <openssl/pem.h>
67 #include <openssl/rand.h>
69 #include "rcv.h"
70 #include <errno.h>
71 #include <sys/stat.h>
72 #include <unistd.h>
73 #include <time.h>
75 #include <sys/socket.h>
76 #include <netdb.h>
77 #include <netinet/in.h>
78 #ifdef HAVE_ARPA_INET_H
79 #include <arpa/inet.h>
80 #endif /* HAVE_ARPA_INET_H */
82 #include <dirent.h>
84 #include "extern.h"
87 * Mail -- a mail program
89 * SSL functions
93 * OpenSSL client implementation according to: John Viega, Matt Messier,
94 * Pravir Chandra: Network Security with OpenSSL. Sebastopol, CA 2002.
97 static int initialized;
98 static int rand_init;
99 static int message_number;
100 static int verify_error_found;
102 static void sslcatch(int s);
103 static int ssl_rand_init(void);
104 static void ssl_init(void);
105 static int ssl_verify_cb(int success, X509_STORE_CTX *store);
106 static const SSL_METHOD *ssl_select_method(const char *uhp);
107 static void ssl_load_verifications(struct sock *sp);
108 static void ssl_certificate(struct sock *sp, const char *uhp);
109 static enum okay ssl_check_host(const char *server, struct sock *sp);
110 #ifdef HAVE_STACK_OF
111 static int smime_verify(struct message *m, int n, STACK_OF(X509) *chain,
112 X509_STORE *store);
113 #else
114 static int smime_verify(struct message *m, int n, STACK *chain,
115 X509_STORE *store);
116 #endif
117 static EVP_CIPHER *smime_cipher(const char *name);
118 static int ssl_password_cb(char *buf, int size, int rwflag, void *userdata);
119 static FILE *smime_sign_cert(const char *xname, const char *xname2, int warn);
120 static char *smime_sign_include_certs(char *name);
121 #ifdef HAVE_STACK_OF
122 static int smime_sign_include_chain_creat(STACK_OF(X509) **chain, char *cfiles);
123 #else
124 static int smime_sign_include_chain_creat(STACK **chain, char *cfiles);
125 #endif
126 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
127 static enum okay load_crl1(X509_STORE *store, const char *name);
128 #endif
129 static enum okay load_crls(X509_STORE *store, const char *vfile,
130 const char *vdir);
132 static void
133 sslcatch(int s)
135 if (reset_tio)
136 tcsetattr(0, TCSADRAIN, &otio);
137 siglongjmp(ssljmp, s);
140 static int
141 ssl_rand_init(void)
143 char *cp;
144 int state = 0;
146 if ((cp = value("ssl-rand-egd")) != NULL) {
147 cp = expand(cp);
148 if (RAND_egd(cp) == -1) {
149 fprintf(stderr, catgets(catd, CATSET, 245,
150 "entropy daemon at \"%s\" not available\n"),
151 cp);
152 } else
153 state = 1;
154 } else if ((cp = value("ssl-rand-file")) != NULL) {
155 cp = expand(cp);
156 if (RAND_load_file(cp, 1024) == -1) {
157 fprintf(stderr, catgets(catd, CATSET, 246,
158 "entropy file at \"%s\" not available\n"), cp);
159 } else {
160 struct stat st;
162 if (stat(cp, &st) == 0 && S_ISREG(st.st_mode) &&
163 access(cp, W_OK) == 0) {
164 if (RAND_write_file(cp) == -1) {
165 fprintf(stderr, catgets(catd, CATSET,
166 247,
167 "writing entropy data to \"%s\" failed\n"), cp);
170 state = 1;
173 return state;
176 static void
177 ssl_init(void)
179 verbose = value("verbose") != NULL;
180 if (initialized == 0) {
181 SSL_library_init();
182 initialized = 1;
184 if (rand_init == 0)
185 rand_init = ssl_rand_init();
188 static int
189 ssl_verify_cb(int success, X509_STORE_CTX *store)
191 if (success == 0) {
192 char data[256];
193 X509 *cert = X509_STORE_CTX_get_current_cert(store);
194 int depth = X509_STORE_CTX_get_error_depth(store);
195 int err = X509_STORE_CTX_get_error(store);
197 verify_error_found = 1;
198 if (message_number)
199 fprintf(stderr, "Message %d: ", message_number);
200 fprintf(stderr, catgets(catd, CATSET, 229,
201 "Error with certificate at depth: %i\n"),
202 depth);
203 X509_NAME_oneline(X509_get_issuer_name(cert), data,
204 sizeof data);
205 fprintf(stderr, catgets(catd, CATSET, 230, " issuer = %s\n"),
206 data);
207 X509_NAME_oneline(X509_get_subject_name(cert), data,
208 sizeof data);
209 fprintf(stderr, catgets(catd, CATSET, 231, " subject = %s\n"),
210 data);
211 fprintf(stderr, catgets(catd, CATSET, 232, " err %i: %s\n"),
212 err, X509_verify_cert_error_string(err));
213 if (ssl_vrfy_decide() != OKAY)
214 return 0;
216 return 1;
219 static const SSL_METHOD *
220 ssl_select_method(const char *uhp)
222 const SSL_METHOD *method;
223 char *cp;
225 cp = ssl_method_string(uhp);
226 if (cp != NULL) {
227 #ifndef OPENSSL_NO_SSL2
228 if (equal(cp, "ssl2"))
229 method = SSLv2_client_method();
230 else
231 #endif
232 if (equal(cp, "ssl3"))
233 method = SSLv3_client_method();
234 else if (equal(cp, "tls1"))
235 method = TLSv1_client_method();
236 else {
237 fprintf(stderr, catgets(catd, CATSET, 244,
238 "Invalid SSL method \"%s\"\n"), cp);
239 method = SSLv23_client_method();
241 } else
242 method = SSLv23_client_method();
243 return method;
246 static void
247 ssl_load_verifications(struct sock *sp)
249 char *ca_dir, *ca_file;
250 X509_STORE *store;
252 if (ssl_vrfy_level == VRFY_IGNORE)
253 return;
254 if ((ca_dir = value("ssl-ca-dir")) != NULL)
255 ca_dir = expand(ca_dir);
256 if ((ca_file = value("ssl-ca-file")) != NULL)
257 ca_file = expand(ca_file);
258 if (ca_dir || ca_file) {
259 if (SSL_CTX_load_verify_locations(sp->s_ctx,
260 ca_file, ca_dir) != 1) {
261 fprintf(stderr, catgets(catd, CATSET, 233,
262 "Error loading"));
263 if (ca_dir) {
264 fprintf(stderr, catgets(catd, CATSET, 234,
265 " %s"), ca_dir);
266 if (ca_file)
267 fprintf(stderr, catgets(catd, CATSET,
268 235, " or"));
270 if (ca_file)
271 fprintf(stderr, catgets(catd, CATSET, 236,
272 " %s"), ca_file);
273 fprintf(stderr, catgets(catd, CATSET, 237, "\n"));
276 if (value("ssl-no-default-ca") == NULL) {
277 if (SSL_CTX_set_default_verify_paths(sp->s_ctx) != 1)
278 fprintf(stderr, catgets(catd, CATSET, 243,
279 "Error loading default CA locations\n"));
281 verify_error_found = 0;
282 message_number = 0;
283 SSL_CTX_set_verify(sp->s_ctx, SSL_VERIFY_PEER, ssl_verify_cb);
284 store = SSL_CTX_get_cert_store(sp->s_ctx);
285 load_crls(store, "ssl-crl-file", "ssl-crl-dir");
288 static void
289 ssl_certificate(struct sock *sp, const char *uhp)
291 char *certvar, *keyvar, *cert, *key;
293 certvar = ac_alloc(strlen(uhp) + 10);
294 strcpy(certvar, "ssl-cert-");
295 strcpy(&certvar[9], uhp);
296 if ((cert = value(certvar)) != NULL ||
297 (cert = value("ssl-cert")) != NULL) {
298 cert = expand(cert);
299 if (SSL_CTX_use_certificate_chain_file(sp->s_ctx, cert) == 1) {
300 keyvar = ac_alloc(strlen(uhp) + 9);
301 strcpy(keyvar, "ssl-key-");
302 if ((key = value(keyvar)) == NULL &&
303 (key = value("ssl-key")) == NULL)
304 key = cert;
305 else
306 key = expand(key);
307 if (SSL_CTX_use_PrivateKey_file(sp->s_ctx, key,
308 SSL_FILETYPE_PEM) != 1)
309 fprintf(stderr, catgets(catd, CATSET, 238,
310 "cannot load private key from file %s\n"),
311 key);
312 ac_free(keyvar);
313 } else
314 fprintf(stderr, catgets(catd, CATSET, 239,
315 "cannot load certificate from file %s\n"),
316 cert);
318 ac_free(certvar);
321 static enum okay
322 ssl_check_host(const char *server, struct sock *sp)
324 X509 *cert;
325 X509_NAME *subj;
326 char data[256];
327 #ifdef HAVE_STACK_OF
328 STACK_OF(GENERAL_NAME) *gens;
329 #else
330 /*GENERAL_NAMES*/STACK *gens;
331 #endif
332 GENERAL_NAME *gen;
333 int i;
335 if ((cert = SSL_get_peer_certificate(sp->s_ssl)) == NULL) {
336 fprintf(stderr, catgets(catd, CATSET, 248,
337 "no certificate from \"%s\"\n"), server);
338 return STOP;
340 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
341 if (gens != NULL) {
342 for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
343 gen = sk_GENERAL_NAME_value(gens, i);
344 if (gen->type == GEN_DNS) {
345 if (verbose)
346 fprintf(stderr,
347 "Comparing DNS name: \"%s\"\n",
348 gen->d.ia5->data);
349 if (rfc2595_hostname_match(server,
350 (char *)gen->d.ia5->data)
351 == OKAY)
352 goto found;
356 if ((subj = X509_get_subject_name(cert)) != NULL &&
357 X509_NAME_get_text_by_NID(subj, NID_commonName,
358 data, sizeof data) > 0) {
359 data[sizeof data - 1] = 0;
360 if (verbose)
361 fprintf(stderr, "Comparing common name: \"%s\"\n",
362 data);
363 if (rfc2595_hostname_match(server, data) == OKAY)
364 goto found;
366 X509_free(cert);
367 return STOP;
368 found: X509_free(cert);
369 return OKAY;
372 enum okay
373 ssl_open(const char *server, struct sock *sp, const char *uhp)
375 char *cp;
376 long options;
378 ssl_init();
379 ssl_set_vrfy_level(uhp);
380 if ((sp->s_ctx =
381 SSL_CTX_new((SSL_METHOD *)ssl_select_method(uhp))) == NULL) {
382 ssl_gen_err(catgets(catd, CATSET, 261, "SSL_CTX_new() failed"));
383 return STOP;
385 #ifdef SSL_MODE_AUTO_RETRY
386 /* available with OpenSSL 0.9.6 or later */
387 SSL_CTX_set_mode(sp->s_ctx, SSL_MODE_AUTO_RETRY);
388 #endif /* SSL_MODE_AUTO_RETRY */
389 options = SSL_OP_ALL;
390 if (value("ssl-v2-allow") == NULL)
391 options |= SSL_OP_NO_SSLv2;
392 SSL_CTX_set_options(sp->s_ctx, options);
393 ssl_load_verifications(sp);
394 ssl_certificate(sp, uhp);
395 if ((cp = value("ssl-cipher-list")) != NULL) {
396 if (SSL_CTX_set_cipher_list(sp->s_ctx, cp) != 1)
397 fprintf(stderr, catgets(catd, CATSET, 240,
398 "invalid ciphers: %s\n"), cp);
400 if ((sp->s_ssl = SSL_new(sp->s_ctx)) == NULL) {
401 ssl_gen_err(catgets(catd, CATSET, 262, "SSL_new() failed"));
402 return STOP;
404 SSL_set_fd(sp->s_ssl, sp->s_fd);
405 if (SSL_connect(sp->s_ssl) < 0) {
406 ssl_gen_err(catgets(catd, CATSET, 263,
407 "could not initiate SSL/TLS connection"));
408 return STOP;
410 if (ssl_vrfy_level != VRFY_IGNORE) {
411 if (ssl_check_host(server, sp) != OKAY) {
412 fprintf(stderr, catgets(catd, CATSET, 249,
413 "host certificate does not match \"%s\"\n"),
414 server);
415 if (ssl_vrfy_decide() != OKAY)
416 return STOP;
419 sp->s_use_ssl = 1;
420 return OKAY;
423 void
424 ssl_gen_err(const char *fmt, ...)
426 va_list ap;
428 va_start(ap, fmt);
429 vfprintf(stderr, fmt, ap);
430 va_end(ap);
431 SSL_load_error_strings();
432 fprintf(stderr, ": %s\n",
433 (ERR_error_string(ERR_get_error(), NULL)));
436 FILE *
437 smime_sign(FILE *ip, struct header *headp)
439 FILE *sp, *fp, *bp, *hp;
440 char *cp, *addr;
441 X509 *cert;
442 #ifdef HAVE_STACK_OF
443 STACK_OF(X509) *chain = NULL;
444 #else
445 STACK *chain = NULL;
446 #endif
447 PKCS7 *pkcs7;
448 EVP_PKEY *pkey;
449 BIO *bb, *sb;
451 ssl_init();
452 if ((addr = myorigin(headp)) == NULL) {
453 fprintf(stderr, "No \"from\" address for signing specified\n");
454 return NULL;
456 if ((fp = smime_sign_cert(addr, NULL, 1)) == NULL)
457 return NULL;
458 if ((pkey = PEM_read_PrivateKey(fp, NULL, ssl_password_cb, NULL))
459 == NULL) {
460 ssl_gen_err("Error reading private key from");
461 Fclose(fp);
462 return NULL;
464 rewind(fp);
465 if ((cert = PEM_read_X509(fp, NULL, ssl_password_cb, NULL)) == NULL) {
466 ssl_gen_err("Error reading signer certificate from");
467 Fclose(fp);
468 EVP_PKEY_free(pkey);
469 return NULL;
471 Fclose(fp);
472 if ((cp = smime_sign_include_certs(addr)) != NULL &&
473 !smime_sign_include_chain_creat(&chain, cp)) {
474 X509_free(cert);
475 EVP_PKEY_free(pkey);
476 return NULL;
478 if ((sp = Ftemp(&cp, "Rs", "w+", 0600, 1)) == NULL) {
479 perror("tempfile");
480 if (chain != NULL)
481 sk_X509_pop_free(chain, X509_free);
482 X509_free(cert);
483 EVP_PKEY_free(pkey);
484 return NULL;
486 rm(cp);
487 Ftfree(&cp);
488 rewind(ip);
489 if (smime_split(ip, &hp, &bp, -1, 0) == STOP) {
490 Fclose(sp);
491 if (chain != NULL)
492 sk_X509_pop_free(chain, X509_free);
493 X509_free(cert);
494 EVP_PKEY_free(pkey);
495 return NULL;
497 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
498 (sb = BIO_new_fp(sp, BIO_NOCLOSE)) == NULL) {
499 ssl_gen_err("Error creating BIO signing objects");
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 ((pkcs7 = PKCS7_sign(cert, pkey, chain, bb,
508 PKCS7_DETACHED)) == NULL) {
509 ssl_gen_err("Error creating the PKCS#7 signing object");
510 BIO_free(bb);
511 BIO_free(sb);
512 Fclose(sp);
513 if (chain != NULL)
514 sk_X509_pop_free(chain, X509_free);
515 X509_free(cert);
516 EVP_PKEY_free(pkey);
517 return NULL;
519 if (PEM_write_bio_PKCS7(sb, pkcs7) == 0) {
520 ssl_gen_err("Error writing signed S/MIME data");
521 BIO_free(bb);
522 BIO_free(sb);
523 Fclose(sp);
524 if (chain != NULL)
525 sk_X509_pop_free(chain, X509_free);
526 X509_free(cert);
527 EVP_PKEY_free(pkey);
528 return NULL;
530 BIO_free(bb);
531 BIO_free(sb);
532 if (chain != NULL)
533 sk_X509_pop_free(chain, X509_free);
534 X509_free(cert);
535 EVP_PKEY_free(pkey);
536 rewind(bp);
537 fflush(sp);
538 rewind(sp);
539 return smime_sign_assemble(hp, bp, sp);
542 static int
543 #ifdef HAVE_STACK_OF
544 smime_verify(struct message *m, int n, STACK_OF(X509) *chain, X509_STORE *store)
545 #else
546 smime_verify(struct message *m, int n, STACK *chain, X509_STORE *store)
547 #endif
549 struct message *x;
550 char *cp, *sender, *to, *cc, *cnttype;
551 int c, i, j;
552 FILE *fp, *ip;
553 off_t size;
554 BIO *fb, *pb;
555 PKCS7 *pkcs7;
556 #ifdef HAVE_STACK_OF
557 STACK_OF(X509) *certs;
558 STACK_OF(GENERAL_NAME) *gens;
559 #else
560 STACK *certs, *gens;
561 #endif
562 X509 *cert;
563 X509_NAME *subj;
564 char data[LINESIZE];
565 GENERAL_NAME *gen;
567 verify_error_found = 0;
568 message_number = n;
569 loop: sender = getsender(m);
570 to = hfield("to", m);
571 cc = hfield("cc", m);
572 cnttype = hfield("content-type", m);
573 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
574 return 1;
575 if (cnttype && strncmp(cnttype, "application/x-pkcs7-mime", 24) == 0) {
576 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
577 return 1;
578 if (x != (struct message *)-1) {
579 m = x;
580 goto loop;
583 size = m->m_size;
584 if ((fp = Ftemp(&cp, "Rv", "w+", 0600, 1)) == NULL) {
585 perror("tempfile");
586 return 1;
588 rm(cp);
589 Ftfree(&cp);
590 while (size-- > 0) {
591 c = getc(ip);
592 putc(c, fp);
594 fflush(fp);
595 rewind(fp);
596 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
597 ssl_gen_err("Error creating BIO verification object "
598 "for message %d", n);
599 Fclose(fp);
600 return 1;
602 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
603 ssl_gen_err("Error reading PKCS#7 object for message %d", n);
604 BIO_free(fb);
605 Fclose(fp);
606 return 1;
608 if (PKCS7_verify(pkcs7, chain, store, pb, NULL, 0) != 1) {
609 ssl_gen_err("Error verifying message %d", n);
610 BIO_free(fb);
611 Fclose(fp);
612 return 1;
614 BIO_free(fb);
615 Fclose(fp);
616 if (sender == NULL) {
617 fprintf(stderr,
618 "Warning: Message %d has no sender.\n", n);
619 return 0;
621 certs = PKCS7_get0_signers(pkcs7, chain, 0);
622 if (certs == NULL) {
623 fprintf(stderr, "No certificates found in message %d.\n", n);
624 return 1;
626 for (i = 0; i < sk_X509_num(certs); i++) {
627 cert = sk_X509_value(certs, i);
628 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
629 if (gens != NULL) {
630 for (j = 0; j < sk_GENERAL_NAME_num(gens); j++) {
631 gen = sk_GENERAL_NAME_value(gens, j);
632 if (gen->type == GEN_EMAIL) {
633 if (verbose)
634 fprintf(stderr,
635 "Comparing alt. "
636 "address: %s\"\n",
637 data);
638 if (!asccasecmp((char *)
639 gen->d.ia5->data,
640 sender))
641 goto found;
645 if ((subj = X509_get_subject_name(cert)) != NULL &&
646 X509_NAME_get_text_by_NID(subj,
647 NID_pkcs9_emailAddress,
648 data, sizeof data) > 0) {
649 data[sizeof data - 1] = 0;
650 if (verbose)
651 fprintf(stderr, "Comparing address: \"%s\"\n",
652 data);
653 if (asccasecmp(data, sender) == 0)
654 goto found;
657 fprintf(stderr, "Message %d: certificate does not match <%s>\n",
658 n, sender);
659 return 1;
660 found: if (verify_error_found == 0)
661 printf("Message %d was verified successfully.\n", n);
662 return verify_error_found;
665 int
666 cverify(void *vp)
668 int *msgvec = vp, *ip;
669 int ec = 0;
670 #ifdef HAVE_STACK_OF
671 STACK_OF(X509) *chain = NULL;
672 #else
673 STACK *chain = NULL;
674 #endif
675 X509_STORE *store;
676 char *ca_dir, *ca_file;
678 ssl_init();
679 ssl_vrfy_level = VRFY_STRICT;
680 if ((store = X509_STORE_new()) == NULL) {
681 ssl_gen_err("Error creating X509 store");
682 return 1;
684 X509_STORE_set_verify_cb_func(store, ssl_verify_cb);
685 if ((ca_dir = value("smime-ca-dir")) != NULL)
686 ca_dir = expand(ca_dir);
687 if ((ca_file = value("smime-ca-file")) != NULL)
688 ca_file = expand(ca_file);
689 if (ca_dir || ca_file) {
690 if (X509_STORE_load_locations(store, ca_file, ca_dir) != 1) {
691 ssl_gen_err("Error loading %s",
692 ca_file ? ca_file : ca_dir);
693 return 1;
696 if (value("smime-no-default-ca") == NULL) {
697 if (X509_STORE_set_default_paths(store) != 1) {
698 ssl_gen_err("Error loading default CA locations");
699 return 1;
702 if (load_crls(store, "smime-crl-file", "smime-crl-dir") != OKAY)
703 return 1;
704 for (ip = msgvec; *ip; ip++) {
705 setdot(&message[*ip-1]);
706 ec |= smime_verify(&message[*ip-1], *ip, chain, store);
708 return ec;
711 static EVP_CIPHER *
712 smime_cipher(const char *name)
714 const EVP_CIPHER *cipher;
715 char *vn, *cp;
716 int vs;
718 vn = ac_alloc(vs = strlen(name) + 30);
719 snprintf(vn, vs, "smime-cipher-%s", name);
720 if ((cp = value(vn)) != NULL) {
721 if (strcmp(cp, "rc2-40") == 0)
722 cipher = EVP_rc2_40_cbc();
723 else if (strcmp(cp, "rc2-64") == 0)
724 cipher = EVP_rc2_64_cbc();
725 else if (strcmp(cp, "des") == 0)
726 cipher = EVP_des_cbc();
727 else if (strcmp(cp, "des-ede3") == 0)
728 cipher = EVP_des_ede3_cbc();
729 else {
730 fprintf(stderr, "Invalid cipher \"%s\".\n", cp);
731 cipher = NULL;
733 } else
734 cipher = EVP_des_ede3_cbc();
735 ac_free(vn);
736 return (EVP_CIPHER *)cipher;
739 FILE *
740 smime_encrypt(FILE *ip, const char *certfile, const char *to)
742 FILE *yp, *fp, *bp, *hp;
743 char *cp;
744 X509 *cert;
745 PKCS7 *pkcs7;
746 BIO *bb, *yb;
747 #ifdef HAVE_STACK_OF
748 STACK_OF(X509) *certs;
749 #else
750 STACK *certs;
751 #endif
752 EVP_CIPHER *cipher;
754 certfile = expand((char *)certfile);
755 ssl_init();
756 if ((cipher = smime_cipher(to)) == NULL)
757 return NULL;
758 if ((fp = Fopen(certfile, "r")) == NULL) {
759 perror(certfile);
760 return NULL;
762 if ((cert = PEM_read_X509(fp, NULL, ssl_password_cb, NULL)) == NULL) {
763 ssl_gen_err("Error reading encryption certificate from \"%s\"",
764 certfile);
765 Fclose(fp);
766 return NULL;
768 Fclose(fp);
769 certs = sk_X509_new_null();
770 sk_X509_push(certs, cert);
771 if ((yp = Ftemp(&cp, "Ry", "w+", 0600, 1)) == NULL) {
772 perror("tempfile");
773 return NULL;
775 rm(cp);
776 Ftfree(&cp);
777 rewind(ip);
778 if (smime_split(ip, &hp, &bp, -1, 0) == STOP) {
779 Fclose(yp);
780 return NULL;
782 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
783 (yb = BIO_new_fp(yp, BIO_NOCLOSE)) == NULL) {
784 ssl_gen_err("Error creating BIO encryption objects");
785 Fclose(yp);
786 return NULL;
788 if ((pkcs7 = PKCS7_encrypt(certs, bb, cipher, 0)) == NULL) {
789 ssl_gen_err("Error creating the PKCS#7 encryption object");
790 BIO_free(bb);
791 BIO_free(yb);
792 Fclose(yp);
793 return NULL;
795 if (PEM_write_bio_PKCS7(yb, pkcs7) == 0) {
796 ssl_gen_err("Error writing encrypted S/MIME data");
797 BIO_free(bb);
798 BIO_free(yb);
799 Fclose(yp);
800 return NULL;
802 BIO_free(bb);
803 BIO_free(yb);
804 Fclose(bp);
805 fflush(yp);
806 rewind(yp);
807 return smime_encrypt_assemble(hp, yp);
810 struct message *
811 smime_decrypt(struct message *m, const char *to, const char *cc, int signcall)
813 FILE *fp, *bp, *hp, *op;
814 char *cp;
815 X509 *cert = NULL;
816 PKCS7 *pkcs7;
817 EVP_PKEY *pkey = NULL;
818 BIO *bb, *pb, *ob;
819 long size = m->m_size;
820 FILE *yp;
822 if ((yp = setinput(&mb, m, NEED_BODY)) == NULL)
823 return NULL;
824 ssl_init();
825 if ((fp = smime_sign_cert(to, cc, 0)) != NULL) {
826 if ((pkey = PEM_read_PrivateKey(fp, NULL, ssl_password_cb,
827 NULL)) == NULL) {
828 ssl_gen_err("Error reading private key");
829 Fclose(fp);
830 return NULL;
832 rewind(fp);
833 if ((cert = PEM_read_X509(fp, NULL, ssl_password_cb,
834 NULL)) == NULL) {
835 ssl_gen_err("Error reading decryption certificate");
836 Fclose(fp);
837 EVP_PKEY_free(pkey);
838 return NULL;
840 Fclose(fp);
842 if ((op = Ftemp(&cp, "Rp", "w+", 0600, 1)) == NULL) {
843 perror("tempfile");
844 if (cert)
845 X509_free(cert);
846 if (pkey)
847 EVP_PKEY_free(pkey);
848 return NULL;
850 rm(cp);
851 Ftfree(&cp);
852 if (smime_split(yp, &hp, &bp, size, 1) == STOP) {
853 Fclose(op);
854 if (cert)
855 X509_free(cert);
856 if (pkey)
857 EVP_PKEY_free(pkey);
858 return NULL;
860 if ((ob = BIO_new_fp(op, BIO_NOCLOSE)) == NULL ||
861 (bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL) {
862 ssl_gen_err("Error creating BIO decryption objects");
863 Fclose(op);
864 if (cert)
865 X509_free(cert);
866 if (pkey)
867 EVP_PKEY_free(pkey);
868 return NULL;
870 if ((pkcs7 = SMIME_read_PKCS7(bb, &pb)) == NULL) {
871 ssl_gen_err("Error reading PKCS#7 object");
872 Fclose(op);
873 if (cert)
874 X509_free(cert);
875 if (pkey)
876 EVP_PKEY_free(pkey);
877 return NULL;
879 if (PKCS7_type_is_signed(pkcs7)) {
880 if (signcall) {
881 BIO_free(bb);
882 BIO_free(ob);
883 if (cert)
884 X509_free(cert);
885 if (pkey)
886 EVP_PKEY_free(pkey);
887 Fclose(op);
888 Fclose(bp);
889 Fclose(hp);
890 setinput(&mb, m, NEED_BODY);
891 return (struct message *)-1;
893 if (PKCS7_verify(pkcs7, NULL, NULL, NULL, ob,
894 PKCS7_NOVERIFY|PKCS7_NOSIGS) != 1)
895 goto err;
896 fseek(hp, 0L, SEEK_END);
897 fprintf(hp, "X-Encryption-Cipher: none\n");
898 fflush(hp);
899 rewind(hp);
900 } else if (pkey == NULL) {
901 fprintf(stderr, "No appropriate private key found.\n");
902 goto err2;
903 } else if (cert == NULL) {
904 fprintf(stderr, "No appropriate certificate found.\n");
905 goto err2;
906 } else if (PKCS7_decrypt(pkcs7, pkey, cert, ob, 0) != 1) {
907 err: ssl_gen_err("Error decrypting PKCS#7 object");
908 err2: BIO_free(bb);
909 BIO_free(ob);
910 Fclose(op);
911 Fclose(bp);
912 Fclose(hp);
913 if (cert)
914 X509_free(cert);
915 if (pkey)
916 EVP_PKEY_free(pkey);
917 return NULL;
919 BIO_free(bb);
920 BIO_free(ob);
921 if (cert)
922 X509_free(cert);
923 if (pkey)
924 EVP_PKEY_free(pkey);
925 fflush(op);
926 rewind(op);
927 Fclose(bp);
928 return smime_decrypt_assemble(m, hp, op);
931 /*ARGSUSED4*/
932 static int
933 ssl_password_cb(char *buf, int size, int rwflag, void *userdata)
935 sighandler_type saveint;
936 char *pass = NULL;
937 int len;
938 (void)rwflag;
939 (void)userdata;
941 saveint = safe_signal(SIGINT, SIG_IGN);
942 if (sigsetjmp(ssljmp, 1) == 0) {
943 if (saveint != SIG_IGN)
944 safe_signal(SIGINT, sslcatch);
945 pass = getpassword(&otio, &reset_tio, "PEM pass phrase:");
947 safe_signal(SIGINT, saveint);
948 if (pass == NULL)
949 return 0;
950 len = strlen(pass);
951 if (len > size)
952 len = size;
953 memcpy(buf, pass, len);
954 return len;
957 static FILE *
958 smime_sign_cert(const char *xname, const char *xname2, int warn)
960 char *vn, *cp;
961 int vs;
962 FILE *fp;
963 struct name *np;
964 const char *name = xname, *name2 = xname2;
966 loop: if (name) {
967 np = sextract(savestr(name), GTO|GSKIN);
968 while (np) {
970 * This needs to be more intelligent since it will
971 * currently take the first name for which a private
972 * key is available regardless of whether it is the
973 * right one for the message.
975 vn = ac_alloc(vs = strlen(np->n_name) + 30);
976 snprintf(vn, vs, "smime-sign-cert-%s", np->n_name);
977 if ((cp = value(vn)) != NULL)
978 goto open;
979 np = np->n_flink;
981 if (name2) {
982 name = name2;
983 name2 = NULL;
984 goto loop;
987 if ((cp = value("smime-sign-cert")) != NULL)
988 goto open;
989 if (warn) {
990 fprintf(stderr, "Could not find a certificate for %s", xname);
991 if (xname2)
992 fprintf(stderr, "or %s", xname2);
993 fputc('\n', stderr);
995 return NULL;
996 open: cp = expand(cp);
997 if ((fp = Fopen(cp, "r")) == NULL) {
998 perror(cp);
999 return NULL;
1001 return fp;
1004 static char *
1005 smime_sign_include_certs(char *name)
1007 /* See comments in smime_sign_cert() for algorithm pitfalls */
1008 if (name) {
1009 struct name *np = sextract(savestr(name), GTO|GSKIN);
1010 while (np) {
1011 int vs;
1012 char *vn = ac_alloc(vs = strlen(np->n_name) + 30);
1013 snprintf(vn, vs, "smime-sign-include-certs-%s",
1014 np->n_name);
1015 if ((name = value(vn)) != NULL)
1016 return name;
1017 np = np->n_flink;
1020 return value("smime-sign-include-certs");
1023 static int
1024 smime_sign_include_chain_creat(
1025 #ifdef HAVE_STACK_OF
1026 STACK_OF(X509) **chain,
1027 #else
1028 STACK **chain,
1029 #endif
1030 char *cfiles)
1032 *chain = sk_X509_new_null();
1034 for (;;) {
1035 X509 *tmp;
1036 FILE *fp;
1037 char *exp, *ncf = strchr(cfiles, ',');
1038 if (ncf)
1039 *ncf++ = '\0';
1040 /* This fails for '=,file' constructs, but those are sick */
1041 if (! *cfiles)
1042 break;
1044 if ((exp = expand(cfiles)) != NULL)
1045 cfiles = exp;
1046 if ((fp = Fopen(cfiles, "r")) == NULL) {
1047 perror(cfiles);
1048 goto jerr;
1050 if ((tmp = PEM_read_X509(fp, NULL, ssl_password_cb, NULL)
1051 ) == NULL) {
1052 ssl_gen_err("Error reading certificate from \"%s\"",
1053 cfiles);
1054 Fclose(fp);
1055 goto jerr;
1057 sk_X509_push(*chain, tmp);
1058 Fclose(fp);
1060 if (! ncf)
1061 break;
1062 cfiles = ncf;
1065 if (sk_X509_num(*chain) == 0) {
1066 fprintf(stderr, "smime-sign-include-certs defined but empty\n");
1067 goto jerr;
1070 jleave: return (*chain != NULL);
1072 jerr: sk_X509_pop_free(*chain, X509_free);
1073 *chain = NULL;
1074 goto jleave;
1077 enum okay
1078 smime_certsave(struct message *m, int n, FILE *op)
1080 struct message *x;
1081 char *cp, *to, *cc, *cnttype;
1082 int c, i;
1083 FILE *fp, *ip;
1084 off_t size;
1085 BIO *fb, *pb;
1086 PKCS7 *pkcs7;
1087 #ifdef HAVE_STACK_OF
1088 STACK_OF(X509) *certs;
1089 STACK_OF(X509) *chain = NULL;
1090 #else
1091 STACK *certs;
1092 STACK *chain = NULL;
1093 #endif
1094 X509 *cert;
1095 enum okay ok = OKAY;
1097 message_number = n;
1098 loop: to = hfield("to", m);
1099 cc = hfield("cc", m);
1100 cnttype = hfield("content-type", m);
1101 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
1102 return STOP;
1103 if (cnttype && strncmp(cnttype, "application/x-pkcs7-mime", 24) == 0) {
1104 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
1105 return STOP;
1106 if (x != (struct message *)-1) {
1107 m = x;
1108 goto loop;
1111 size = m->m_size;
1112 if ((fp = Ftemp(&cp, "Rv", "w+", 0600, 1)) == NULL) {
1113 perror("tempfile");
1114 return STOP;
1116 rm(cp);
1117 Ftfree(&cp);
1118 while (size-- > 0) {
1119 c = getc(ip);
1120 putc(c, fp);
1122 fflush(fp);
1123 rewind(fp);
1124 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
1125 ssl_gen_err("Error creating BIO object for message %d", n);
1126 Fclose(fp);
1127 return STOP;
1129 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
1130 ssl_gen_err("Error reading PKCS#7 object for message %d", n);
1131 BIO_free(fb);
1132 Fclose(fp);
1133 return STOP;
1135 BIO_free(fb);
1136 Fclose(fp);
1137 certs = PKCS7_get0_signers(pkcs7, chain, 0);
1138 if (certs == NULL) {
1139 fprintf(stderr, "No certificates found in message %d.\n", n);
1140 return STOP;
1142 for (i = 0; i < sk_X509_num(certs); i++) {
1143 cert = sk_X509_value(certs, i);
1144 if (X509_print_fp(op, cert) == 0 ||
1145 PEM_write_X509(op, cert) == 0) {
1146 ssl_gen_err("Error writing certificate %d from "
1147 "message %d", i, n);
1148 ok = STOP;
1151 return ok;
1154 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1155 static enum okay
1156 load_crl1(X509_STORE *store, const char *name)
1158 X509_LOOKUP *lookup;
1160 if (verbose)
1161 printf("Loading CRL from \"%s\".\n", name);
1162 if ((lookup = X509_STORE_add_lookup(store,
1163 X509_LOOKUP_file())) == NULL) {
1164 ssl_gen_err("Error creating X509 lookup object");
1165 return STOP;
1167 if (X509_load_crl_file(lookup, name, X509_FILETYPE_PEM) != 1) {
1168 ssl_gen_err("Error loading CRL from \"%s\"", name);
1169 return STOP;
1171 return OKAY;
1173 #endif /* new OpenSSL */
1175 static enum okay
1176 load_crls(X509_STORE *store, const char *vfile, const char *vdir)
1178 char *crl_file, *crl_dir;
1179 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1180 DIR *dirfd;
1181 struct dirent *dp;
1182 char *fn = NULL;
1183 int fs = 0, ds, es;
1184 #endif /* new OpenSSL */
1186 if ((crl_file = value(vfile)) != NULL) {
1187 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1188 crl_file = expand(crl_file);
1189 if (load_crl1(store, crl_file) != OKAY)
1190 return STOP;
1191 #else /* old OpenSSL */
1192 fprintf(stderr,
1193 "This OpenSSL version is too old to use CRLs.\n");
1194 return STOP;
1195 #endif /* old OpenSSL */
1197 if ((crl_dir = value(vdir)) != NULL) {
1198 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1199 crl_dir = expand(crl_dir);
1200 ds = strlen(crl_dir);
1201 if ((dirfd = opendir(crl_dir)) == NULL) {
1202 perror(crl_dir);
1203 return STOP;
1205 fn = smalloc(fs = ds + 20);
1206 strcpy(fn, crl_dir);
1207 fn[ds] = '/';
1208 while ((dp = readdir(dirfd)) != NULL) {
1209 if (dp->d_name[0] == '.' &&
1210 (dp->d_name[1] == '\0' ||
1211 (dp->d_name[1] == '.' &&
1212 dp->d_name[2] == '\0')))
1213 continue;
1214 if (dp->d_name[0] == '.')
1215 continue;
1216 if (ds + (es = strlen(dp->d_name)) + 2 < fs)
1217 fn = srealloc(fn, fs = ds + es + 20);
1218 strcpy(&fn[ds+1], dp->d_name);
1219 if (load_crl1(store, fn) != OKAY) {
1220 closedir(dirfd);
1221 free(fn);
1222 return STOP;
1225 closedir(dirfd);
1226 free(fn);
1227 #else /* old OpenSSL */
1228 fprintf(stderr,
1229 "This OpenSSL version is too old to use CRLs.\n");
1230 return STOP;
1231 #endif /* old OpenSSL */
1233 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1234 if (crl_file || crl_dir)
1235 X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK |
1236 X509_V_FLAG_CRL_CHECK_ALL);
1237 #endif /* old OpenSSL */
1238 return OKAY;
1241 #else /* !NSS && !USE_OPENSSL */
1243 #include <stdio.h>
1245 static void
1246 nosmime(void)
1248 fprintf(stderr, "No S/MIME support compiled in.\n");
1251 /*ARGSUSED*/
1252 FILE *
1253 smime_sign(FILE *fp)
1255 (void)fp;
1256 nosmime();
1257 return NULL;
1260 /*ARGSUSED*/
1261 int
1262 cverify(void *vp)
1264 (void)vp;
1265 nosmime();
1266 return 1;
1269 /*ARGSUSED*/
1270 FILE *
1271 smime_encrypt(FILE *fp, const char *certfile, const char *to)
1273 (void)fp;
1274 (void)certfile;
1275 (void)to;
1276 nosmime();
1277 return NULL;
1280 /*ARGSUSED*/
1281 struct message *
1282 smime_decrypt(struct message *m, const char *to, const char *cc, int signcall)
1284 (void)m;
1285 (void)to;
1286 (void)cc;
1287 (void)signcall;
1288 nosmime();
1289 return NULL;
1292 /*ARGSUSED*/
1293 int
1294 ccertsave(void *v)
1296 (void)v;
1297 nosmime();
1298 return 1;
1300 #endif /* !USE_NSS && !USE_OPENSSL */