load(): handle NULL arg ourself, do not pass to Fopen()
[s-mailx.git] / openssl.c
blob2f10cc4cfeaa566f094392dbaabb53469997b61d
1 /*
2 * S-nail - 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 #include "config.h"
42 #ifdef USE_NSS
43 typedef int avoid_empty_file_compiler_warning;
44 #elif defined USE_OPENSSL
46 #include <setjmp.h>
47 #include <termios.h>
48 #include <stdio.h>
50 static int verbose;
51 static int reset_tio;
52 static struct termios otio;
53 static sigjmp_buf ssljmp;
55 #include <openssl/crypto.h>
56 #include <openssl/ssl.h>
57 #include <openssl/err.h>
58 #include <openssl/x509v3.h>
59 #include <openssl/x509.h>
60 #include <openssl/pem.h>
61 #include <openssl/rand.h>
63 #include "rcv.h"
64 #include <errno.h>
65 #include <sys/stat.h>
66 #include <unistd.h>
67 #include <time.h>
69 #include <sys/socket.h>
70 #include <netdb.h>
71 #include <netinet/in.h>
72 #ifdef HAVE_ARPA_INET_H
73 #include <arpa/inet.h>
74 #endif /* HAVE_ARPA_INET_H */
76 #include <dirent.h>
78 #include "extern.h"
81 * Mail -- a mail program
83 * SSL functions
87 * OpenSSL client implementation according to: John Viega, Matt Messier,
88 * Pravir Chandra: Network Security with OpenSSL. Sebastopol, CA 2002.
91 static int initialized;
92 static int rand_init;
93 static int message_number;
94 static int verify_error_found;
96 static void sslcatch(int s);
97 static int ssl_rand_init(void);
98 static void ssl_init(void);
99 static int ssl_verify_cb(int success, X509_STORE_CTX *store);
100 static const SSL_METHOD *ssl_select_method(const char *uhp);
101 static void ssl_load_verifications(struct sock *sp);
102 static void ssl_certificate(struct sock *sp, const char *uhp);
103 static enum okay ssl_check_host(const char *server, struct sock *sp);
104 #ifdef HAVE_STACK_OF
105 static int smime_verify(struct message *m, int n, STACK_OF(X509) *chain,
106 X509_STORE *store);
107 #else
108 static int smime_verify(struct message *m, int n, STACK *chain,
109 X509_STORE *store);
110 #endif
111 static EVP_CIPHER *smime_cipher(const char *name);
112 static int ssl_password_cb(char *buf, int size, int rwflag, void *userdata);
113 static FILE *smime_sign_cert(const char *xname, const char *xname2, int warn);
114 static char *smime_sign_include_certs(char *name);
115 #ifdef HAVE_STACK_OF
116 static int smime_sign_include_chain_creat(STACK_OF(X509) **chain, char *cfiles);
117 #else
118 static int smime_sign_include_chain_creat(STACK **chain, char *cfiles);
119 #endif
120 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
121 static enum okay load_crl1(X509_STORE *store, const char *name);
122 #endif
123 static enum okay load_crls(X509_STORE *store, const char *vfile,
124 const char *vdir);
126 static void
127 sslcatch(int s)
129 if (reset_tio)
130 tcsetattr(0, TCSADRAIN, &otio);
131 siglongjmp(ssljmp, s);
134 static int
135 ssl_rand_init(void)
137 char *cp;
138 int state = 0;
140 if ((cp = value("ssl-rand-egd")) != NULL) {
141 if ((cp = file_expand(cp)) == NULL)
143 else if (RAND_egd(cp) == -1)
144 fprintf(stderr, tr(245,
145 "entropy daemon at \"%s\" not available\n"),
146 cp);
147 else
148 state = 1;
149 } else if ((cp = value("ssl-rand-file")) != NULL) {
150 if ((cp = file_expand(cp)) == NULL)
152 else if (RAND_load_file(cp, 1024) == -1)
153 fprintf(stderr, tr(246,
154 "entropy file at \"%s\" not available\n"), cp);
155 else {
156 struct stat st;
158 if (stat(cp, &st) == 0 && S_ISREG(st.st_mode) &&
159 access(cp, W_OK) == 0) {
160 if (RAND_write_file(cp) == -1) {
161 fprintf(stderr, catgets(catd, CATSET,
162 247,
163 "writing entropy data to \"%s\" failed\n"), cp);
166 state = 1;
169 return state;
172 static void
173 ssl_init(void)
175 verbose = value("verbose") != NULL;
176 if (initialized == 0) {
177 SSL_library_init();
178 initialized = 1;
180 if (rand_init == 0)
181 rand_init = ssl_rand_init();
184 static int
185 ssl_verify_cb(int success, X509_STORE_CTX *store)
187 if (success == 0) {
188 char data[256];
189 X509 *cert = X509_STORE_CTX_get_current_cert(store);
190 int depth = X509_STORE_CTX_get_error_depth(store);
191 int err = X509_STORE_CTX_get_error(store);
193 verify_error_found = 1;
194 if (message_number)
195 fprintf(stderr, "Message %d: ", message_number);
196 fprintf(stderr, catgets(catd, CATSET, 229,
197 "Error with certificate at depth: %i\n"),
198 depth);
199 X509_NAME_oneline(X509_get_issuer_name(cert), data,
200 sizeof data);
201 fprintf(stderr, catgets(catd, CATSET, 230, " issuer = %s\n"),
202 data);
203 X509_NAME_oneline(X509_get_subject_name(cert), data,
204 sizeof data);
205 fprintf(stderr, catgets(catd, CATSET, 231, " subject = %s\n"),
206 data);
207 fprintf(stderr, catgets(catd, CATSET, 232, " err %i: %s\n"),
208 err, X509_verify_cert_error_string(err));
209 if (ssl_vrfy_decide() != OKAY)
210 return 0;
212 return 1;
215 static const SSL_METHOD *
216 ssl_select_method(const char *uhp)
218 const SSL_METHOD *method;
219 char *cp;
221 cp = ssl_method_string(uhp);
222 if (cp != NULL) {
223 #ifndef OPENSSL_NO_SSL2
224 if (strcmp(cp, "ssl2") == 0)
225 method = SSLv2_client_method();
226 else
227 #endif
228 if (strcmp(cp, "ssl3") == 0)
229 method = SSLv3_client_method();
230 else if (strcmp(cp, "tls1") == 0)
231 method = TLSv1_client_method();
232 else {
233 fprintf(stderr, tr(244, "Invalid SSL method \"%s\"\n"),
234 cp);
235 method = SSLv23_client_method();
237 } else
238 method = SSLv23_client_method();
239 return method;
242 static void
243 ssl_load_verifications(struct sock *sp)
245 char *ca_dir, *ca_file;
246 X509_STORE *store;
248 if (ssl_vrfy_level == VRFY_IGNORE)
249 return;
250 if ((ca_dir = value("ssl-ca-dir")) != NULL)
251 ca_dir = file_expand(ca_dir);
252 if ((ca_file = value("ssl-ca-file")) != NULL)
253 ca_file = file_expand(ca_file);
254 if (ca_dir || ca_file) {
255 if (SSL_CTX_load_verify_locations(sp->s_ctx,
256 ca_file, ca_dir) != 1) {
257 fprintf(stderr, catgets(catd, CATSET, 233,
258 "Error loading"));
259 if (ca_dir) {
260 fprintf(stderr, catgets(catd, CATSET, 234,
261 " %s"), ca_dir);
262 if (ca_file)
263 fprintf(stderr, catgets(catd, CATSET,
264 235, " or"));
266 if (ca_file)
267 fprintf(stderr, catgets(catd, CATSET, 236,
268 " %s"), ca_file);
269 fprintf(stderr, catgets(catd, CATSET, 237, "\n"));
272 if (value("ssl-no-default-ca") == NULL) {
273 if (SSL_CTX_set_default_verify_paths(sp->s_ctx) != 1)
274 fprintf(stderr, catgets(catd, CATSET, 243,
275 "Error loading default CA locations\n"));
277 verify_error_found = 0;
278 message_number = 0;
279 SSL_CTX_set_verify(sp->s_ctx, SSL_VERIFY_PEER, ssl_verify_cb);
280 store = SSL_CTX_get_cert_store(sp->s_ctx);
281 load_crls(store, "ssl-crl-file", "ssl-crl-dir");
284 static void
285 ssl_certificate(struct sock *sp, const char *uhp)
287 char *certvar, *keyvar, *cert, *key, *x;
289 certvar = ac_alloc(strlen(uhp) + 10);
290 strcpy(certvar, "ssl-cert-");
291 strcpy(&certvar[9], uhp);
292 if ((cert = value(certvar)) != NULL ||
293 (cert = value("ssl-cert")) != NULL) {
294 x = cert;
295 if ((cert = file_expand(cert)) == NULL) {
296 cert = x;
297 goto jbcert;
298 } else if (SSL_CTX_use_certificate_chain_file(sp->s_ctx, cert)
299 == 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 if ((x = key, key = file_expand(key)) == NULL) {
306 key = x;
307 goto jbkey;
309 if (SSL_CTX_use_PrivateKey_file(sp->s_ctx, key,
310 SSL_FILETYPE_PEM) != 1)
311 jbkey: fprintf(stderr, tr(238,
312 "cannot load private key from file "
313 "%s\n"), key);
314 ac_free(keyvar);
315 } else
316 jbcert: fprintf(stderr, tr(239,
317 "cannot load certificate from file %s\n"),
318 cert);
320 ac_free(certvar);
323 static enum okay
324 ssl_check_host(const char *server, struct sock *sp)
326 X509 *cert;
327 X509_NAME *subj;
328 char data[256];
329 #ifdef HAVE_STACK_OF
330 STACK_OF(GENERAL_NAME) *gens;
331 #else
332 /*GENERAL_NAMES*/STACK *gens;
333 #endif
334 GENERAL_NAME *gen;
335 int i;
337 if ((cert = SSL_get_peer_certificate(sp->s_ssl)) == NULL) {
338 fprintf(stderr, catgets(catd, CATSET, 248,
339 "no certificate from \"%s\"\n"), server);
340 return STOP;
342 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
343 if (gens != NULL) {
344 for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
345 gen = sk_GENERAL_NAME_value(gens, i);
346 if (gen->type == GEN_DNS) {
347 if (verbose)
348 fprintf(stderr,
349 "Comparing DNS name: \"%s\"\n",
350 gen->d.ia5->data);
351 if (rfc2595_hostname_match(server,
352 (char *)gen->d.ia5->data)
353 == OKAY)
354 goto found;
358 if ((subj = X509_get_subject_name(cert)) != NULL &&
359 X509_NAME_get_text_by_NID(subj, NID_commonName,
360 data, sizeof data) > 0) {
361 data[sizeof data - 1] = 0;
362 if (verbose)
363 fprintf(stderr, "Comparing common name: \"%s\"\n",
364 data);
365 if (rfc2595_hostname_match(server, data) == OKAY)
366 goto found;
368 X509_free(cert);
369 return STOP;
370 found: X509_free(cert);
371 return OKAY;
374 enum okay
375 ssl_open(const char *server, struct sock *sp, const char *uhp)
377 char *cp;
378 long options;
380 ssl_init();
381 ssl_set_vrfy_level(uhp);
382 if ((sp->s_ctx =
383 SSL_CTX_new((SSL_METHOD *)ssl_select_method(uhp))) == NULL) {
384 ssl_gen_err(catgets(catd, CATSET, 261, "SSL_CTX_new() failed"));
385 return STOP;
387 #ifdef SSL_MODE_AUTO_RETRY
388 /* available with OpenSSL 0.9.6 or later */
389 SSL_CTX_set_mode(sp->s_ctx, SSL_MODE_AUTO_RETRY);
390 #endif /* SSL_MODE_AUTO_RETRY */
391 options = SSL_OP_ALL;
392 if (value("ssl-v2-allow") == NULL)
393 options |= SSL_OP_NO_SSLv2;
394 SSL_CTX_set_options(sp->s_ctx, options);
395 ssl_load_verifications(sp);
396 ssl_certificate(sp, uhp);
397 if ((cp = value("ssl-cipher-list")) != NULL) {
398 if (SSL_CTX_set_cipher_list(sp->s_ctx, cp) != 1)
399 fprintf(stderr, catgets(catd, CATSET, 240,
400 "invalid ciphers: %s\n"), cp);
402 if ((sp->s_ssl = SSL_new(sp->s_ctx)) == NULL) {
403 ssl_gen_err(catgets(catd, CATSET, 262, "SSL_new() failed"));
404 return STOP;
406 SSL_set_fd(sp->s_ssl, sp->s_fd);
407 if (SSL_connect(sp->s_ssl) < 0) {
408 ssl_gen_err(catgets(catd, CATSET, 263,
409 "could not initiate SSL/TLS connection"));
410 return STOP;
412 if (ssl_vrfy_level != VRFY_IGNORE) {
413 if (ssl_check_host(server, sp) != OKAY) {
414 fprintf(stderr, catgets(catd, CATSET, 249,
415 "host certificate does not match \"%s\"\n"),
416 server);
417 if (ssl_vrfy_decide() != OKAY)
418 return STOP;
421 sp->s_use_ssl = 1;
422 return OKAY;
425 void
426 ssl_gen_err(const char *fmt, ...)
428 va_list ap;
430 va_start(ap, fmt);
431 vfprintf(stderr, fmt, ap);
432 va_end(ap);
433 SSL_load_error_strings();
434 fprintf(stderr, ": %s\n",
435 (ERR_error_string(ERR_get_error(), NULL)));
438 FILE *
439 smime_sign(FILE *ip, struct header *headp)
441 FILE *sp, *fp, *bp, *hp;
442 char *cp, *addr;
443 X509 *cert;
444 #ifdef HAVE_STACK_OF
445 STACK_OF(X509) *chain = NULL;
446 #else
447 STACK *chain = NULL;
448 #endif
449 PKCS7 *pkcs7;
450 EVP_PKEY *pkey;
451 BIO *bb, *sb;
453 ssl_init();
454 if ((addr = myorigin(headp)) == NULL) {
455 fprintf(stderr, "No \"from\" address for signing specified\n");
456 return NULL;
458 if ((fp = smime_sign_cert(addr, NULL, 1)) == NULL)
459 return NULL;
460 if ((pkey = PEM_read_PrivateKey(fp, NULL, ssl_password_cb, NULL))
461 == NULL) {
462 ssl_gen_err("Error reading private key from");
463 Fclose(fp);
464 return NULL;
466 rewind(fp);
467 if ((cert = PEM_read_X509(fp, NULL, ssl_password_cb, NULL)) == NULL) {
468 ssl_gen_err("Error reading signer certificate from");
469 Fclose(fp);
470 EVP_PKEY_free(pkey);
471 return NULL;
473 Fclose(fp);
474 if ((cp = smime_sign_include_certs(addr)) != NULL &&
475 !smime_sign_include_chain_creat(&chain, cp)) {
476 X509_free(cert);
477 EVP_PKEY_free(pkey);
478 return NULL;
480 if ((sp = Ftemp(&cp, "Rs", "w+", 0600, 1)) == NULL) {
481 perror("tempfile");
482 if (chain != NULL)
483 sk_X509_pop_free(chain, X509_free);
484 X509_free(cert);
485 EVP_PKEY_free(pkey);
486 return NULL;
488 rm(cp);
489 Ftfree(&cp);
490 rewind(ip);
491 if (smime_split(ip, &hp, &bp, -1, 0) == STOP) {
492 Fclose(sp);
493 if (chain != NULL)
494 sk_X509_pop_free(chain, X509_free);
495 X509_free(cert);
496 EVP_PKEY_free(pkey);
497 return NULL;
499 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
500 (sb = BIO_new_fp(sp, BIO_NOCLOSE)) == NULL) {
501 ssl_gen_err("Error creating BIO signing objects");
502 Fclose(sp);
503 if (chain != NULL)
504 sk_X509_pop_free(chain, X509_free);
505 X509_free(cert);
506 EVP_PKEY_free(pkey);
507 return NULL;
509 if ((pkcs7 = PKCS7_sign(cert, pkey, chain, bb,
510 PKCS7_DETACHED)) == NULL) {
511 ssl_gen_err("Error creating the PKCS#7 signing object");
512 BIO_free(bb);
513 BIO_free(sb);
514 Fclose(sp);
515 if (chain != NULL)
516 sk_X509_pop_free(chain, X509_free);
517 X509_free(cert);
518 EVP_PKEY_free(pkey);
519 return NULL;
521 if (PEM_write_bio_PKCS7(sb, pkcs7) == 0) {
522 ssl_gen_err("Error writing signed S/MIME data");
523 BIO_free(bb);
524 BIO_free(sb);
525 Fclose(sp);
526 if (chain != NULL)
527 sk_X509_pop_free(chain, X509_free);
528 X509_free(cert);
529 EVP_PKEY_free(pkey);
530 return NULL;
532 BIO_free(bb);
533 BIO_free(sb);
534 if (chain != NULL)
535 sk_X509_pop_free(chain, X509_free);
536 X509_free(cert);
537 EVP_PKEY_free(pkey);
538 rewind(bp);
539 fflush(sp);
540 rewind(sp);
541 return smime_sign_assemble(hp, bp, sp);
544 static int
545 #ifdef HAVE_STACK_OF
546 smime_verify(struct message *m, int n, STACK_OF(X509) *chain, X509_STORE *store)
547 #else
548 smime_verify(struct message *m, int n, STACK *chain, X509_STORE *store)
549 #endif
551 struct message *x;
552 char *cp, *sender, *to, *cc, *cnttype;
553 int c, i, j;
554 FILE *fp, *ip;
555 off_t size;
556 BIO *fb, *pb;
557 PKCS7 *pkcs7;
558 #ifdef HAVE_STACK_OF
559 STACK_OF(X509) *certs;
560 STACK_OF(GENERAL_NAME) *gens;
561 #else
562 STACK *certs, *gens;
563 #endif
564 X509 *cert;
565 X509_NAME *subj;
566 char data[LINESIZE];
567 GENERAL_NAME *gen;
569 verify_error_found = 0;
570 message_number = n;
571 loop: sender = getsender(m);
572 to = hfield1("to", m);
573 cc = hfield1("cc", m);
574 cnttype = hfield1("content-type", m);
575 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
576 return 1;
577 if (cnttype && strncmp(cnttype, "application/x-pkcs7-mime", 24) == 0) {
578 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
579 return 1;
580 if (x != (struct message *)-1) {
581 m = x;
582 goto loop;
585 size = m->m_size;
586 if ((fp = Ftemp(&cp, "Rv", "w+", 0600, 1)) == NULL) {
587 perror("tempfile");
588 return 1;
590 rm(cp);
591 Ftfree(&cp);
592 while (size-- > 0) {
593 c = getc(ip);
594 putc(c, fp);
596 fflush(fp);
597 rewind(fp);
598 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
599 ssl_gen_err("Error creating BIO verification object "
600 "for message %d", n);
601 Fclose(fp);
602 return 1;
604 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
605 ssl_gen_err("Error reading PKCS#7 object for message %d", n);
606 BIO_free(fb);
607 Fclose(fp);
608 return 1;
610 if (PKCS7_verify(pkcs7, chain, store, pb, NULL, 0) != 1) {
611 ssl_gen_err("Error verifying message %d", n);
612 BIO_free(fb);
613 Fclose(fp);
614 return 1;
616 BIO_free(fb);
617 Fclose(fp);
618 if (sender == NULL) {
619 fprintf(stderr,
620 "Warning: Message %d has no sender.\n", n);
621 return 0;
623 certs = PKCS7_get0_signers(pkcs7, chain, 0);
624 if (certs == NULL) {
625 fprintf(stderr, "No certificates found in message %d.\n", n);
626 return 1;
628 for (i = 0; i < sk_X509_num(certs); i++) {
629 cert = sk_X509_value(certs, i);
630 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
631 if (gens != NULL) {
632 for (j = 0; j < sk_GENERAL_NAME_num(gens); j++) {
633 gen = sk_GENERAL_NAME_value(gens, j);
634 if (gen->type == GEN_EMAIL) {
635 if (verbose)
636 fprintf(stderr,
637 "Comparing alt. "
638 "address: %s\"\n",
639 data);
640 if (!asccasecmp((char *)
641 gen->d.ia5->data,
642 sender))
643 goto found;
647 if ((subj = X509_get_subject_name(cert)) != NULL &&
648 X509_NAME_get_text_by_NID(subj,
649 NID_pkcs9_emailAddress,
650 data, sizeof data) > 0) {
651 data[sizeof data - 1] = 0;
652 if (verbose)
653 fprintf(stderr, "Comparing address: \"%s\"\n",
654 data);
655 if (asccasecmp(data, sender) == 0)
656 goto found;
659 fprintf(stderr, "Message %d: certificate does not match <%s>\n",
660 n, sender);
661 return 1;
662 found: if (verify_error_found == 0)
663 printf("Message %d was verified successfully.\n", n);
664 return verify_error_found;
667 int
668 cverify(void *vp)
670 int *msgvec = vp, *ip;
671 int ec = 0;
672 #ifdef HAVE_STACK_OF
673 STACK_OF(X509) *chain = NULL;
674 #else
675 STACK *chain = NULL;
676 #endif
677 X509_STORE *store;
678 char *ca_dir, *ca_file;
680 ssl_init();
681 ssl_vrfy_level = VRFY_STRICT;
682 if ((store = X509_STORE_new()) == NULL) {
683 ssl_gen_err("Error creating X509 store");
684 return 1;
686 X509_STORE_set_verify_cb_func(store, ssl_verify_cb);
687 if ((ca_dir = value("smime-ca-dir")) != NULL)
688 ca_dir = file_expand(ca_dir);
689 if ((ca_file = value("smime-ca-file")) != NULL)
690 ca_file = file_expand(ca_file);
691 if (ca_dir || ca_file) {
692 if (X509_STORE_load_locations(store, ca_file, ca_dir) != 1) {
693 ssl_gen_err("Error loading %s",
694 ca_file ? ca_file : ca_dir);
695 return 1;
698 if (value("smime-no-default-ca") == NULL) {
699 if (X509_STORE_set_default_paths(store) != 1) {
700 ssl_gen_err("Error loading default CA locations");
701 return 1;
704 if (load_crls(store, "smime-crl-file", "smime-crl-dir") != OKAY)
705 return 1;
706 for (ip = msgvec; *ip; ip++) {
707 setdot(&message[*ip-1]);
708 ec |= smime_verify(&message[*ip-1], *ip, chain, store);
710 return ec;
713 static EVP_CIPHER *
714 smime_cipher(const char *name)
716 const EVP_CIPHER *cipher;
717 char *vn, *cp;
718 int vs;
720 vn = ac_alloc(vs = strlen(name) + 30);
721 snprintf(vn, vs, "smime-cipher-%s", name);
722 if ((cp = value(vn)) != NULL) {
723 if (strcmp(cp, "rc2-40") == 0)
724 cipher = EVP_rc2_40_cbc();
725 else if (strcmp(cp, "rc2-64") == 0)
726 cipher = EVP_rc2_64_cbc();
727 else if (strcmp(cp, "des") == 0)
728 cipher = EVP_des_cbc();
729 else if (strcmp(cp, "des-ede3") == 0)
730 cipher = EVP_des_ede3_cbc();
731 else {
732 fprintf(stderr, "Invalid cipher \"%s\".\n", cp);
733 cipher = NULL;
735 } else
736 cipher = EVP_des_ede3_cbc();
737 ac_free(vn);
738 return (EVP_CIPHER *)cipher;
741 FILE *
742 smime_encrypt(FILE *ip, const char *xcertfile, const char *to)
744 char *certfile = (char*)xcertfile, *cp;
745 FILE *yp, *fp, *bp, *hp;
746 X509 *cert;
747 PKCS7 *pkcs7;
748 BIO *bb, *yb;
749 #ifdef HAVE_STACK_OF
750 STACK_OF(X509) *certs;
751 #else
752 STACK *certs;
753 #endif
754 EVP_CIPHER *cipher;
756 if ((certfile = file_expand(certfile)) == NULL)
757 return NULL;
759 ssl_init();
760 if ((cipher = smime_cipher(to)) == NULL)
761 return NULL;
762 if ((fp = Fopen(certfile, "r")) == NULL) {
763 perror(certfile);
764 return NULL;
766 if ((cert = PEM_read_X509(fp, NULL, ssl_password_cb, NULL)) == NULL) {
767 ssl_gen_err("Error reading encryption certificate from \"%s\"",
768 certfile);
769 Fclose(fp);
770 return NULL;
772 Fclose(fp);
773 certs = sk_X509_new_null();
774 sk_X509_push(certs, cert);
775 if ((yp = Ftemp(&cp, "Ry", "w+", 0600, 1)) == NULL) {
776 perror("tempfile");
777 return NULL;
779 rm(cp);
780 Ftfree(&cp);
781 rewind(ip);
782 if (smime_split(ip, &hp, &bp, -1, 0) == STOP) {
783 Fclose(yp);
784 return NULL;
786 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
787 (yb = BIO_new_fp(yp, BIO_NOCLOSE)) == NULL) {
788 ssl_gen_err("Error creating BIO encryption objects");
789 Fclose(yp);
790 return NULL;
792 if ((pkcs7 = PKCS7_encrypt(certs, bb, cipher, 0)) == NULL) {
793 ssl_gen_err("Error creating the PKCS#7 encryption object");
794 BIO_free(bb);
795 BIO_free(yb);
796 Fclose(yp);
797 return NULL;
799 if (PEM_write_bio_PKCS7(yb, pkcs7) == 0) {
800 ssl_gen_err("Error writing encrypted S/MIME data");
801 BIO_free(bb);
802 BIO_free(yb);
803 Fclose(yp);
804 return NULL;
806 BIO_free(bb);
807 BIO_free(yb);
808 Fclose(bp);
809 fflush(yp);
810 rewind(yp);
811 return smime_encrypt_assemble(hp, yp);
814 struct message *
815 smime_decrypt(struct message *m, const char *to, const char *cc, int signcall)
817 FILE *fp, *bp, *hp, *op;
818 char *cp;
819 X509 *cert = NULL;
820 PKCS7 *pkcs7;
821 EVP_PKEY *pkey = NULL;
822 BIO *bb, *pb, *ob;
823 long size = m->m_size;
824 FILE *yp;
826 if ((yp = setinput(&mb, m, NEED_BODY)) == NULL)
827 return NULL;
828 ssl_init();
829 if ((fp = smime_sign_cert(to, cc, 0)) != NULL) {
830 if ((pkey = PEM_read_PrivateKey(fp, NULL, ssl_password_cb,
831 NULL)) == NULL) {
832 ssl_gen_err("Error reading private key");
833 Fclose(fp);
834 return NULL;
836 rewind(fp);
837 if ((cert = PEM_read_X509(fp, NULL, ssl_password_cb,
838 NULL)) == NULL) {
839 ssl_gen_err("Error reading decryption certificate");
840 Fclose(fp);
841 EVP_PKEY_free(pkey);
842 return NULL;
844 Fclose(fp);
846 if ((op = Ftemp(&cp, "Rp", "w+", 0600, 1)) == NULL) {
847 perror("tempfile");
848 if (cert)
849 X509_free(cert);
850 if (pkey)
851 EVP_PKEY_free(pkey);
852 return NULL;
854 rm(cp);
855 Ftfree(&cp);
856 if (smime_split(yp, &hp, &bp, size, 1) == STOP) {
857 Fclose(op);
858 if (cert)
859 X509_free(cert);
860 if (pkey)
861 EVP_PKEY_free(pkey);
862 return NULL;
864 if ((ob = BIO_new_fp(op, BIO_NOCLOSE)) == NULL ||
865 (bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL) {
866 ssl_gen_err("Error creating BIO decryption objects");
867 Fclose(op);
868 if (cert)
869 X509_free(cert);
870 if (pkey)
871 EVP_PKEY_free(pkey);
872 return NULL;
874 if ((pkcs7 = SMIME_read_PKCS7(bb, &pb)) == NULL) {
875 ssl_gen_err("Error reading PKCS#7 object");
876 Fclose(op);
877 if (cert)
878 X509_free(cert);
879 if (pkey)
880 EVP_PKEY_free(pkey);
881 return NULL;
883 if (PKCS7_type_is_signed(pkcs7)) {
884 if (signcall) {
885 BIO_free(bb);
886 BIO_free(ob);
887 if (cert)
888 X509_free(cert);
889 if (pkey)
890 EVP_PKEY_free(pkey);
891 Fclose(op);
892 Fclose(bp);
893 Fclose(hp);
894 setinput(&mb, m, NEED_BODY);
895 return (struct message *)-1;
897 if (PKCS7_verify(pkcs7, NULL, NULL, NULL, ob,
898 PKCS7_NOVERIFY|PKCS7_NOSIGS) != 1)
899 goto err;
900 fseek(hp, 0L, SEEK_END);
901 fprintf(hp, "X-Encryption-Cipher: none\n");
902 fflush(hp);
903 rewind(hp);
904 } else if (pkey == NULL) {
905 fprintf(stderr, "No appropriate private key found.\n");
906 goto err2;
907 } else if (cert == NULL) {
908 fprintf(stderr, "No appropriate certificate found.\n");
909 goto err2;
910 } else if (PKCS7_decrypt(pkcs7, pkey, cert, ob, 0) != 1) {
911 err: ssl_gen_err("Error decrypting PKCS#7 object");
912 err2: BIO_free(bb);
913 BIO_free(ob);
914 Fclose(op);
915 Fclose(bp);
916 Fclose(hp);
917 if (cert)
918 X509_free(cert);
919 if (pkey)
920 EVP_PKEY_free(pkey);
921 return NULL;
923 BIO_free(bb);
924 BIO_free(ob);
925 if (cert)
926 X509_free(cert);
927 if (pkey)
928 EVP_PKEY_free(pkey);
929 fflush(op);
930 rewind(op);
931 Fclose(bp);
932 return smime_decrypt_assemble(m, hp, op);
935 /*ARGSUSED4*/
936 static int
937 ssl_password_cb(char *buf, int size, int rwflag, void *userdata)
939 sighandler_type saveint;
940 char *pass = NULL;
941 int len;
942 (void)rwflag;
943 (void)userdata;
945 saveint = safe_signal(SIGINT, SIG_IGN);
946 if (sigsetjmp(ssljmp, 1) == 0) {
947 if (saveint != SIG_IGN)
948 safe_signal(SIGINT, sslcatch);
949 pass = getpassword(&otio, &reset_tio, "PEM pass phrase:");
951 safe_signal(SIGINT, saveint);
952 if (pass == NULL)
953 return 0;
954 len = strlen(pass);
955 if (len > size)
956 len = size;
957 memcpy(buf, pass, len);
958 return len;
961 static FILE *
962 smime_sign_cert(const char *xname, const char *xname2, int warn)
964 char *vn, *cp;
965 int vs;
966 FILE *fp;
967 struct name *np;
968 const char *name = xname, *name2 = xname2;
970 loop: if (name) {
971 np = lextract(name, GTO|GSKIN);
972 while (np) {
974 * This needs to be more intelligent since it will
975 * currently take the first name for which a private
976 * key is available regardless of whether it is the
977 * right one for the message.
979 vn = ac_alloc(vs = strlen(np->n_name) + 30);
980 snprintf(vn, vs, "smime-sign-cert-%s", np->n_name);
981 if ((cp = value(vn)) != NULL)
982 goto open;
983 np = np->n_flink;
985 if (name2) {
986 name = name2;
987 name2 = NULL;
988 goto loop;
991 if ((cp = value("smime-sign-cert")) != NULL)
992 goto open;
993 if (warn) {
994 fprintf(stderr, "Could not find a certificate for %s", xname);
995 if (xname2)
996 fprintf(stderr, "or %s", xname2);
997 fputc('\n', stderr);
999 return NULL;
1000 open: vn = cp;
1001 if ((cp = file_expand(cp)) == NULL)
1002 return (NULL);
1003 if ((fp = Fopen(cp, "r")) == NULL) {
1004 perror(cp);
1005 return NULL;
1007 return fp;
1010 static char *
1011 smime_sign_include_certs(char *name)
1013 /* See comments in smime_sign_cert() for algorithm pitfalls */
1014 if (name) {
1015 struct name *np = lextract(name, GTO|GSKIN);
1016 while (np) {
1017 int vs;
1018 char *vn = ac_alloc(vs = strlen(np->n_name) + 30);
1019 snprintf(vn, vs, "smime-sign-include-certs-%s",
1020 np->n_name);
1021 if ((name = value(vn)) != NULL)
1022 return name;
1023 np = np->n_flink;
1026 return value("smime-sign-include-certs");
1029 static int
1030 smime_sign_include_chain_creat(
1031 #ifdef HAVE_STACK_OF
1032 STACK_OF(X509) **chain,
1033 #else
1034 STACK **chain,
1035 #endif
1036 char *cfiles)
1038 *chain = sk_X509_new_null();
1040 for (;;) {
1041 X509 *tmp;
1042 FILE *fp;
1043 char *ncf = strchr(cfiles, ',');
1044 if (ncf)
1045 *ncf++ = '\0';
1046 /* This fails for '=,file' constructs, but those are sick */
1047 if (! *cfiles)
1048 break;
1050 if ((cfiles = file_expand(cfiles)) != NULL)
1051 goto jerr;
1052 if ((fp = Fopen(cfiles, "r")) == NULL) {
1053 perror(cfiles);
1054 goto jerr;
1056 if ((tmp = PEM_read_X509(fp, NULL, ssl_password_cb, NULL)
1057 ) == NULL) {
1058 ssl_gen_err("Error reading certificate from \"%s\"",
1059 cfiles);
1060 Fclose(fp);
1061 goto jerr;
1063 sk_X509_push(*chain, tmp);
1064 Fclose(fp);
1066 if (! ncf)
1067 break;
1068 cfiles = ncf;
1071 if (sk_X509_num(*chain) == 0) {
1072 fprintf(stderr, "smime-sign-include-certs defined but empty\n");
1073 goto jerr;
1076 jleave: return (*chain != NULL);
1078 jerr: sk_X509_pop_free(*chain, X509_free);
1079 *chain = NULL;
1080 goto jleave;
1083 enum okay
1084 smime_certsave(struct message *m, int n, FILE *op)
1086 struct message *x;
1087 char *cp, *to, *cc, *cnttype;
1088 int c, i;
1089 FILE *fp, *ip;
1090 off_t size;
1091 BIO *fb, *pb;
1092 PKCS7 *pkcs7;
1093 #ifdef HAVE_STACK_OF
1094 STACK_OF(X509) *certs;
1095 STACK_OF(X509) *chain = NULL;
1096 #else
1097 STACK *certs;
1098 STACK *chain = NULL;
1099 #endif
1100 X509 *cert;
1101 enum okay ok = OKAY;
1103 message_number = n;
1104 loop: to = hfield1("to", m);
1105 cc = hfield1("cc", m);
1106 cnttype = hfield1("content-type", m);
1107 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
1108 return STOP;
1109 if (cnttype && strncmp(cnttype, "application/x-pkcs7-mime", 24) == 0) {
1110 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
1111 return STOP;
1112 if (x != (struct message *)-1) {
1113 m = x;
1114 goto loop;
1117 size = m->m_size;
1118 if ((fp = Ftemp(&cp, "Rv", "w+", 0600, 1)) == NULL) {
1119 perror("tempfile");
1120 return STOP;
1122 rm(cp);
1123 Ftfree(&cp);
1124 while (size-- > 0) {
1125 c = getc(ip);
1126 putc(c, fp);
1128 fflush(fp);
1129 rewind(fp);
1130 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
1131 ssl_gen_err("Error creating BIO object for message %d", n);
1132 Fclose(fp);
1133 return STOP;
1135 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
1136 ssl_gen_err("Error reading PKCS#7 object for message %d", n);
1137 BIO_free(fb);
1138 Fclose(fp);
1139 return STOP;
1141 BIO_free(fb);
1142 Fclose(fp);
1143 certs = PKCS7_get0_signers(pkcs7, chain, 0);
1144 if (certs == NULL) {
1145 fprintf(stderr, "No certificates found in message %d.\n", n);
1146 return STOP;
1148 for (i = 0; i < sk_X509_num(certs); i++) {
1149 cert = sk_X509_value(certs, i);
1150 if (X509_print_fp(op, cert) == 0 ||
1151 PEM_write_X509(op, cert) == 0) {
1152 ssl_gen_err("Error writing certificate %d from "
1153 "message %d", i, n);
1154 ok = STOP;
1157 return ok;
1160 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1161 static enum okay
1162 load_crl1(X509_STORE *store, const char *name)
1164 X509_LOOKUP *lookup;
1166 if (verbose)
1167 printf("Loading CRL from \"%s\".\n", name);
1168 if ((lookup = X509_STORE_add_lookup(store,
1169 X509_LOOKUP_file())) == NULL) {
1170 ssl_gen_err("Error creating X509 lookup object");
1171 return STOP;
1173 if (X509_load_crl_file(lookup, name, X509_FILETYPE_PEM) != 1) {
1174 ssl_gen_err("Error loading CRL from \"%s\"", name);
1175 return STOP;
1177 return OKAY;
1179 #endif /* new OpenSSL */
1181 static enum okay
1182 load_crls(X509_STORE *store, const char *vfile, const char *vdir)
1184 char *crl_file, *crl_dir;
1185 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1186 DIR *dirfd;
1187 struct dirent *dp;
1188 char *fn = NULL;
1189 int fs = 0, ds, es;
1190 #endif /* new OpenSSL */
1192 if ((crl_file = value(vfile)) != NULL) {
1193 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1194 if ((crl_file = file_expand(crl_file)) == NULL ||
1195 load_crl1(store, crl_file) != OKAY)
1196 return STOP;
1197 #else /* old OpenSSL */
1198 fprintf(stderr,
1199 "This OpenSSL version is too old to use CRLs.\n");
1200 return STOP;
1201 #endif /* old OpenSSL */
1203 if ((crl_dir = value(vdir)) != NULL) {
1204 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1205 char *x;
1206 if ((x = file_expand(crl_dir)) == NULL ||
1207 (dirfd = opendir(crl_dir = x)) == NULL) {
1208 perror(crl_dir);
1209 return STOP;
1211 ds = strlen(crl_dir);
1212 fn = smalloc(fs = ds + 20);
1213 strcpy(fn, crl_dir);
1214 fn[ds] = '/';
1215 while ((dp = readdir(dirfd)) != NULL) {
1216 if (dp->d_name[0] == '.' &&
1217 (dp->d_name[1] == '\0' ||
1218 (dp->d_name[1] == '.' &&
1219 dp->d_name[2] == '\0')))
1220 continue;
1221 if (dp->d_name[0] == '.')
1222 continue;
1223 if (ds + (es = strlen(dp->d_name)) + 2 < fs)
1224 fn = srealloc(fn, fs = ds + es + 20);
1225 strcpy(&fn[ds+1], dp->d_name);
1226 if (load_crl1(store, fn) != OKAY) {
1227 closedir(dirfd);
1228 free(fn);
1229 return STOP;
1232 closedir(dirfd);
1233 free(fn);
1234 #else /* old OpenSSL */
1235 fprintf(stderr,
1236 "This OpenSSL version is too old to use CRLs.\n");
1237 return STOP;
1238 #endif /* old OpenSSL */
1240 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1241 if (crl_file || crl_dir)
1242 X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK |
1243 X509_V_FLAG_CRL_CHECK_ALL);
1244 #endif /* old OpenSSL */
1245 return OKAY;
1248 #else /* !NSS && !USE_OPENSSL */
1250 #include <stdio.h>
1252 static void
1253 nosmime(void)
1255 fprintf(stderr, "No S/MIME support compiled in.\n");
1258 /*ARGSUSED*/
1259 FILE *
1260 smime_sign(FILE *fp)
1262 (void)fp;
1263 nosmime();
1264 return NULL;
1267 /*ARGSUSED*/
1268 int
1269 cverify(void *vp)
1271 (void)vp;
1272 nosmime();
1273 return 1;
1276 /*ARGSUSED*/
1277 FILE *
1278 smime_encrypt(FILE *fp, const char *certfile, const char *to)
1280 (void)fp;
1281 (void)certfile;
1282 (void)to;
1283 nosmime();
1284 return NULL;
1287 /*ARGSUSED*/
1288 struct message *
1289 smime_decrypt(struct message *m, const char *to, const char *cc, int signcall)
1291 (void)m;
1292 (void)to;
1293 (void)cc;
1294 (void)signcall;
1295 nosmime();
1296 return NULL;
1299 /*ARGSUSED*/
1300 int
1301 ccertsave(void *v)
1303 (void)v;
1304 nosmime();
1305 return 1;
1307 #endif /* !USE_NSS && !USE_OPENSSL */