prefixwrite(), TODO: change file tracking..
[s-mailx.git] / openssl.c
blobcf6905855226d8bf6cd18bfe4bd15ce7e9c5d445
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 cp = expand(cp);
142 if (RAND_egd(cp) == -1) {
143 fprintf(stderr, catgets(catd, CATSET, 245,
144 "entropy daemon at \"%s\" not available\n"),
145 cp);
146 } else
147 state = 1;
148 } else if ((cp = value("ssl-rand-file")) != NULL) {
149 cp = expand(cp);
150 if (RAND_load_file(cp, 1024) == -1) {
151 fprintf(stderr, catgets(catd, CATSET, 246,
152 "entropy file at \"%s\" not available\n"), cp);
153 } else {
154 struct stat st;
156 if (stat(cp, &st) == 0 && S_ISREG(st.st_mode) &&
157 access(cp, W_OK) == 0) {
158 if (RAND_write_file(cp) == -1) {
159 fprintf(stderr, catgets(catd, CATSET,
160 247,
161 "writing entropy data to \"%s\" failed\n"), cp);
164 state = 1;
167 return state;
170 static void
171 ssl_init(void)
173 verbose = value("verbose") != NULL;
174 if (initialized == 0) {
175 SSL_library_init();
176 initialized = 1;
178 if (rand_init == 0)
179 rand_init = ssl_rand_init();
182 static int
183 ssl_verify_cb(int success, X509_STORE_CTX *store)
185 if (success == 0) {
186 char data[256];
187 X509 *cert = X509_STORE_CTX_get_current_cert(store);
188 int depth = X509_STORE_CTX_get_error_depth(store);
189 int err = X509_STORE_CTX_get_error(store);
191 verify_error_found = 1;
192 if (message_number)
193 fprintf(stderr, "Message %d: ", message_number);
194 fprintf(stderr, catgets(catd, CATSET, 229,
195 "Error with certificate at depth: %i\n"),
196 depth);
197 X509_NAME_oneline(X509_get_issuer_name(cert), data,
198 sizeof data);
199 fprintf(stderr, catgets(catd, CATSET, 230, " issuer = %s\n"),
200 data);
201 X509_NAME_oneline(X509_get_subject_name(cert), data,
202 sizeof data);
203 fprintf(stderr, catgets(catd, CATSET, 231, " subject = %s\n"),
204 data);
205 fprintf(stderr, catgets(catd, CATSET, 232, " err %i: %s\n"),
206 err, X509_verify_cert_error_string(err));
207 if (ssl_vrfy_decide() != OKAY)
208 return 0;
210 return 1;
213 static const SSL_METHOD *
214 ssl_select_method(const char *uhp)
216 const SSL_METHOD *method;
217 char *cp;
219 cp = ssl_method_string(uhp);
220 if (cp != NULL) {
221 #ifndef OPENSSL_NO_SSL2
222 if (strcmp(cp, "ssl2") == 0)
223 method = SSLv2_client_method();
224 else
225 #endif
226 if (strcmp(cp, "ssl3") == 0)
227 method = SSLv3_client_method();
228 else if (strcmp(cp, "tls1") == 0)
229 method = TLSv1_client_method();
230 else {
231 fprintf(stderr, tr(244, "Invalid SSL method \"%s\"\n"),
232 cp);
233 method = SSLv23_client_method();
235 } else
236 method = SSLv23_client_method();
237 return method;
240 static void
241 ssl_load_verifications(struct sock *sp)
243 char *ca_dir, *ca_file;
244 X509_STORE *store;
246 if (ssl_vrfy_level == VRFY_IGNORE)
247 return;
248 if ((ca_dir = value("ssl-ca-dir")) != NULL)
249 ca_dir = expand(ca_dir);
250 if ((ca_file = value("ssl-ca-file")) != NULL)
251 ca_file = expand(ca_file);
252 if (ca_dir || ca_file) {
253 if (SSL_CTX_load_verify_locations(sp->s_ctx,
254 ca_file, ca_dir) != 1) {
255 fprintf(stderr, catgets(catd, CATSET, 233,
256 "Error loading"));
257 if (ca_dir) {
258 fprintf(stderr, catgets(catd, CATSET, 234,
259 " %s"), ca_dir);
260 if (ca_file)
261 fprintf(stderr, catgets(catd, CATSET,
262 235, " or"));
264 if (ca_file)
265 fprintf(stderr, catgets(catd, CATSET, 236,
266 " %s"), ca_file);
267 fprintf(stderr, catgets(catd, CATSET, 237, "\n"));
270 if (value("ssl-no-default-ca") == NULL) {
271 if (SSL_CTX_set_default_verify_paths(sp->s_ctx) != 1)
272 fprintf(stderr, catgets(catd, CATSET, 243,
273 "Error loading default CA locations\n"));
275 verify_error_found = 0;
276 message_number = 0;
277 SSL_CTX_set_verify(sp->s_ctx, SSL_VERIFY_PEER, ssl_verify_cb);
278 store = SSL_CTX_get_cert_store(sp->s_ctx);
279 load_crls(store, "ssl-crl-file", "ssl-crl-dir");
282 static void
283 ssl_certificate(struct sock *sp, const char *uhp)
285 char *certvar, *keyvar, *cert, *key;
287 certvar = ac_alloc(strlen(uhp) + 10);
288 strcpy(certvar, "ssl-cert-");
289 strcpy(&certvar[9], uhp);
290 if ((cert = value(certvar)) != NULL ||
291 (cert = value("ssl-cert")) != NULL) {
292 cert = expand(cert);
293 if (SSL_CTX_use_certificate_chain_file(sp->s_ctx, cert) == 1) {
294 keyvar = ac_alloc(strlen(uhp) + 9);
295 strcpy(keyvar, "ssl-key-");
296 if ((key = value(keyvar)) == NULL &&
297 (key = value("ssl-key")) == NULL)
298 key = cert;
299 else
300 key = expand(key);
301 if (SSL_CTX_use_PrivateKey_file(sp->s_ctx, key,
302 SSL_FILETYPE_PEM) != 1)
303 fprintf(stderr, catgets(catd, CATSET, 238,
304 "cannot load private key from file %s\n"),
305 key);
306 ac_free(keyvar);
307 } else
308 fprintf(stderr, catgets(catd, CATSET, 239,
309 "cannot load certificate from file %s\n"),
310 cert);
312 ac_free(certvar);
315 static enum okay
316 ssl_check_host(const char *server, struct sock *sp)
318 X509 *cert;
319 X509_NAME *subj;
320 char data[256];
321 #ifdef HAVE_STACK_OF
322 STACK_OF(GENERAL_NAME) *gens;
323 #else
324 /*GENERAL_NAMES*/STACK *gens;
325 #endif
326 GENERAL_NAME *gen;
327 int i;
329 if ((cert = SSL_get_peer_certificate(sp->s_ssl)) == NULL) {
330 fprintf(stderr, catgets(catd, CATSET, 248,
331 "no certificate from \"%s\"\n"), server);
332 return STOP;
334 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
335 if (gens != NULL) {
336 for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
337 gen = sk_GENERAL_NAME_value(gens, i);
338 if (gen->type == GEN_DNS) {
339 if (verbose)
340 fprintf(stderr,
341 "Comparing DNS name: \"%s\"\n",
342 gen->d.ia5->data);
343 if (rfc2595_hostname_match(server,
344 (char *)gen->d.ia5->data)
345 == OKAY)
346 goto found;
350 if ((subj = X509_get_subject_name(cert)) != NULL &&
351 X509_NAME_get_text_by_NID(subj, NID_commonName,
352 data, sizeof data) > 0) {
353 data[sizeof data - 1] = 0;
354 if (verbose)
355 fprintf(stderr, "Comparing common name: \"%s\"\n",
356 data);
357 if (rfc2595_hostname_match(server, data) == OKAY)
358 goto found;
360 X509_free(cert);
361 return STOP;
362 found: X509_free(cert);
363 return OKAY;
366 enum okay
367 ssl_open(const char *server, struct sock *sp, const char *uhp)
369 char *cp;
370 long options;
372 ssl_init();
373 ssl_set_vrfy_level(uhp);
374 if ((sp->s_ctx =
375 SSL_CTX_new((SSL_METHOD *)ssl_select_method(uhp))) == NULL) {
376 ssl_gen_err(catgets(catd, CATSET, 261, "SSL_CTX_new() failed"));
377 return STOP;
379 #ifdef SSL_MODE_AUTO_RETRY
380 /* available with OpenSSL 0.9.6 or later */
381 SSL_CTX_set_mode(sp->s_ctx, SSL_MODE_AUTO_RETRY);
382 #endif /* SSL_MODE_AUTO_RETRY */
383 options = SSL_OP_ALL;
384 if (value("ssl-v2-allow") == NULL)
385 options |= SSL_OP_NO_SSLv2;
386 SSL_CTX_set_options(sp->s_ctx, options);
387 ssl_load_verifications(sp);
388 ssl_certificate(sp, uhp);
389 if ((cp = value("ssl-cipher-list")) != NULL) {
390 if (SSL_CTX_set_cipher_list(sp->s_ctx, cp) != 1)
391 fprintf(stderr, catgets(catd, CATSET, 240,
392 "invalid ciphers: %s\n"), cp);
394 if ((sp->s_ssl = SSL_new(sp->s_ctx)) == NULL) {
395 ssl_gen_err(catgets(catd, CATSET, 262, "SSL_new() failed"));
396 return STOP;
398 SSL_set_fd(sp->s_ssl, sp->s_fd);
399 if (SSL_connect(sp->s_ssl) < 0) {
400 ssl_gen_err(catgets(catd, CATSET, 263,
401 "could not initiate SSL/TLS connection"));
402 return STOP;
404 if (ssl_vrfy_level != VRFY_IGNORE) {
405 if (ssl_check_host(server, sp) != OKAY) {
406 fprintf(stderr, catgets(catd, CATSET, 249,
407 "host certificate does not match \"%s\"\n"),
408 server);
409 if (ssl_vrfy_decide() != OKAY)
410 return STOP;
413 sp->s_use_ssl = 1;
414 return OKAY;
417 void
418 ssl_gen_err(const char *fmt, ...)
420 va_list ap;
422 va_start(ap, fmt);
423 vfprintf(stderr, fmt, ap);
424 va_end(ap);
425 SSL_load_error_strings();
426 fprintf(stderr, ": %s\n",
427 (ERR_error_string(ERR_get_error(), NULL)));
430 FILE *
431 smime_sign(FILE *ip, struct header *headp)
433 FILE *sp, *fp, *bp, *hp;
434 char *cp, *addr;
435 X509 *cert;
436 #ifdef HAVE_STACK_OF
437 STACK_OF(X509) *chain = NULL;
438 #else
439 STACK *chain = NULL;
440 #endif
441 PKCS7 *pkcs7;
442 EVP_PKEY *pkey;
443 BIO *bb, *sb;
445 ssl_init();
446 if ((addr = myorigin(headp)) == NULL) {
447 fprintf(stderr, "No \"from\" address for signing specified\n");
448 return NULL;
450 if ((fp = smime_sign_cert(addr, NULL, 1)) == NULL)
451 return NULL;
452 if ((pkey = PEM_read_PrivateKey(fp, NULL, ssl_password_cb, NULL))
453 == NULL) {
454 ssl_gen_err("Error reading private key from");
455 Fclose(fp);
456 return NULL;
458 rewind(fp);
459 if ((cert = PEM_read_X509(fp, NULL, ssl_password_cb, NULL)) == NULL) {
460 ssl_gen_err("Error reading signer certificate from");
461 Fclose(fp);
462 EVP_PKEY_free(pkey);
463 return NULL;
465 Fclose(fp);
466 if ((cp = smime_sign_include_certs(addr)) != NULL &&
467 !smime_sign_include_chain_creat(&chain, cp)) {
468 X509_free(cert);
469 EVP_PKEY_free(pkey);
470 return NULL;
472 if ((sp = Ftemp(&cp, "Rs", "w+", 0600, 1)) == NULL) {
473 perror("tempfile");
474 if (chain != NULL)
475 sk_X509_pop_free(chain, X509_free);
476 X509_free(cert);
477 EVP_PKEY_free(pkey);
478 return NULL;
480 rm(cp);
481 Ftfree(&cp);
482 rewind(ip);
483 if (smime_split(ip, &hp, &bp, -1, 0) == STOP) {
484 Fclose(sp);
485 if (chain != NULL)
486 sk_X509_pop_free(chain, X509_free);
487 X509_free(cert);
488 EVP_PKEY_free(pkey);
489 return NULL;
491 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
492 (sb = BIO_new_fp(sp, BIO_NOCLOSE)) == NULL) {
493 ssl_gen_err("Error creating BIO signing objects");
494 Fclose(sp);
495 if (chain != NULL)
496 sk_X509_pop_free(chain, X509_free);
497 X509_free(cert);
498 EVP_PKEY_free(pkey);
499 return NULL;
501 if ((pkcs7 = PKCS7_sign(cert, pkey, chain, bb,
502 PKCS7_DETACHED)) == NULL) {
503 ssl_gen_err("Error creating the PKCS#7 signing object");
504 BIO_free(bb);
505 BIO_free(sb);
506 Fclose(sp);
507 if (chain != NULL)
508 sk_X509_pop_free(chain, X509_free);
509 X509_free(cert);
510 EVP_PKEY_free(pkey);
511 return NULL;
513 if (PEM_write_bio_PKCS7(sb, pkcs7) == 0) {
514 ssl_gen_err("Error writing signed S/MIME data");
515 BIO_free(bb);
516 BIO_free(sb);
517 Fclose(sp);
518 if (chain != NULL)
519 sk_X509_pop_free(chain, X509_free);
520 X509_free(cert);
521 EVP_PKEY_free(pkey);
522 return NULL;
524 BIO_free(bb);
525 BIO_free(sb);
526 if (chain != NULL)
527 sk_X509_pop_free(chain, X509_free);
528 X509_free(cert);
529 EVP_PKEY_free(pkey);
530 rewind(bp);
531 fflush(sp);
532 rewind(sp);
533 return smime_sign_assemble(hp, bp, sp);
536 static int
537 #ifdef HAVE_STACK_OF
538 smime_verify(struct message *m, int n, STACK_OF(X509) *chain, X509_STORE *store)
539 #else
540 smime_verify(struct message *m, int n, STACK *chain, X509_STORE *store)
541 #endif
543 struct message *x;
544 char *cp, *sender, *to, *cc, *cnttype;
545 int c, i, j;
546 FILE *fp, *ip;
547 off_t size;
548 BIO *fb, *pb;
549 PKCS7 *pkcs7;
550 #ifdef HAVE_STACK_OF
551 STACK_OF(X509) *certs;
552 STACK_OF(GENERAL_NAME) *gens;
553 #else
554 STACK *certs, *gens;
555 #endif
556 X509 *cert;
557 X509_NAME *subj;
558 char data[LINESIZE];
559 GENERAL_NAME *gen;
561 verify_error_found = 0;
562 message_number = n;
563 loop: sender = getsender(m);
564 to = hfield1("to", m);
565 cc = hfield1("cc", m);
566 cnttype = hfield1("content-type", m);
567 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
568 return 1;
569 if (cnttype && strncmp(cnttype, "application/x-pkcs7-mime", 24) == 0) {
570 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
571 return 1;
572 if (x != (struct message *)-1) {
573 m = x;
574 goto loop;
577 size = m->m_size;
578 if ((fp = Ftemp(&cp, "Rv", "w+", 0600, 1)) == NULL) {
579 perror("tempfile");
580 return 1;
582 rm(cp);
583 Ftfree(&cp);
584 while (size-- > 0) {
585 c = getc(ip);
586 putc(c, fp);
588 fflush(fp);
589 rewind(fp);
590 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
591 ssl_gen_err("Error creating BIO verification object "
592 "for message %d", n);
593 Fclose(fp);
594 return 1;
596 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
597 ssl_gen_err("Error reading PKCS#7 object for message %d", n);
598 BIO_free(fb);
599 Fclose(fp);
600 return 1;
602 if (PKCS7_verify(pkcs7, chain, store, pb, NULL, 0) != 1) {
603 ssl_gen_err("Error verifying message %d", n);
604 BIO_free(fb);
605 Fclose(fp);
606 return 1;
608 BIO_free(fb);
609 Fclose(fp);
610 if (sender == NULL) {
611 fprintf(stderr,
612 "Warning: Message %d has no sender.\n", n);
613 return 0;
615 certs = PKCS7_get0_signers(pkcs7, chain, 0);
616 if (certs == NULL) {
617 fprintf(stderr, "No certificates found in message %d.\n", n);
618 return 1;
620 for (i = 0; i < sk_X509_num(certs); i++) {
621 cert = sk_X509_value(certs, i);
622 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
623 if (gens != NULL) {
624 for (j = 0; j < sk_GENERAL_NAME_num(gens); j++) {
625 gen = sk_GENERAL_NAME_value(gens, j);
626 if (gen->type == GEN_EMAIL) {
627 if (verbose)
628 fprintf(stderr,
629 "Comparing alt. "
630 "address: %s\"\n",
631 data);
632 if (!asccasecmp((char *)
633 gen->d.ia5->data,
634 sender))
635 goto found;
639 if ((subj = X509_get_subject_name(cert)) != NULL &&
640 X509_NAME_get_text_by_NID(subj,
641 NID_pkcs9_emailAddress,
642 data, sizeof data) > 0) {
643 data[sizeof data - 1] = 0;
644 if (verbose)
645 fprintf(stderr, "Comparing address: \"%s\"\n",
646 data);
647 if (asccasecmp(data, sender) == 0)
648 goto found;
651 fprintf(stderr, "Message %d: certificate does not match <%s>\n",
652 n, sender);
653 return 1;
654 found: if (verify_error_found == 0)
655 printf("Message %d was verified successfully.\n", n);
656 return verify_error_found;
659 int
660 cverify(void *vp)
662 int *msgvec = vp, *ip;
663 int ec = 0;
664 #ifdef HAVE_STACK_OF
665 STACK_OF(X509) *chain = NULL;
666 #else
667 STACK *chain = NULL;
668 #endif
669 X509_STORE *store;
670 char *ca_dir, *ca_file;
672 ssl_init();
673 ssl_vrfy_level = VRFY_STRICT;
674 if ((store = X509_STORE_new()) == NULL) {
675 ssl_gen_err("Error creating X509 store");
676 return 1;
678 X509_STORE_set_verify_cb_func(store, ssl_verify_cb);
679 if ((ca_dir = value("smime-ca-dir")) != NULL)
680 ca_dir = expand(ca_dir);
681 if ((ca_file = value("smime-ca-file")) != NULL)
682 ca_file = expand(ca_file);
683 if (ca_dir || ca_file) {
684 if (X509_STORE_load_locations(store, ca_file, ca_dir) != 1) {
685 ssl_gen_err("Error loading %s",
686 ca_file ? ca_file : ca_dir);
687 return 1;
690 if (value("smime-no-default-ca") == NULL) {
691 if (X509_STORE_set_default_paths(store) != 1) {
692 ssl_gen_err("Error loading default CA locations");
693 return 1;
696 if (load_crls(store, "smime-crl-file", "smime-crl-dir") != OKAY)
697 return 1;
698 for (ip = msgvec; *ip; ip++) {
699 setdot(&message[*ip-1]);
700 ec |= smime_verify(&message[*ip-1], *ip, chain, store);
702 return ec;
705 static EVP_CIPHER *
706 smime_cipher(const char *name)
708 const EVP_CIPHER *cipher;
709 char *vn, *cp;
710 int vs;
712 vn = ac_alloc(vs = strlen(name) + 30);
713 snprintf(vn, vs, "smime-cipher-%s", name);
714 if ((cp = value(vn)) != NULL) {
715 if (strcmp(cp, "rc2-40") == 0)
716 cipher = EVP_rc2_40_cbc();
717 else if (strcmp(cp, "rc2-64") == 0)
718 cipher = EVP_rc2_64_cbc();
719 else if (strcmp(cp, "des") == 0)
720 cipher = EVP_des_cbc();
721 else if (strcmp(cp, "des-ede3") == 0)
722 cipher = EVP_des_ede3_cbc();
723 else {
724 fprintf(stderr, "Invalid cipher \"%s\".\n", cp);
725 cipher = NULL;
727 } else
728 cipher = EVP_des_ede3_cbc();
729 ac_free(vn);
730 return (EVP_CIPHER *)cipher;
733 FILE *
734 smime_encrypt(FILE *ip, const char *certfile, const char *to)
736 FILE *yp, *fp, *bp, *hp;
737 char *cp;
738 X509 *cert;
739 PKCS7 *pkcs7;
740 BIO *bb, *yb;
741 #ifdef HAVE_STACK_OF
742 STACK_OF(X509) *certs;
743 #else
744 STACK *certs;
745 #endif
746 EVP_CIPHER *cipher;
748 certfile = expand((char *)certfile);
749 ssl_init();
750 if ((cipher = smime_cipher(to)) == NULL)
751 return NULL;
752 if ((fp = Fopen(certfile, "r")) == NULL) {
753 perror(certfile);
754 return NULL;
756 if ((cert = PEM_read_X509(fp, NULL, ssl_password_cb, NULL)) == NULL) {
757 ssl_gen_err("Error reading encryption certificate from \"%s\"",
758 certfile);
759 Fclose(fp);
760 return NULL;
762 Fclose(fp);
763 certs = sk_X509_new_null();
764 sk_X509_push(certs, cert);
765 if ((yp = Ftemp(&cp, "Ry", "w+", 0600, 1)) == NULL) {
766 perror("tempfile");
767 return NULL;
769 rm(cp);
770 Ftfree(&cp);
771 rewind(ip);
772 if (smime_split(ip, &hp, &bp, -1, 0) == STOP) {
773 Fclose(yp);
774 return NULL;
776 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
777 (yb = BIO_new_fp(yp, BIO_NOCLOSE)) == NULL) {
778 ssl_gen_err("Error creating BIO encryption objects");
779 Fclose(yp);
780 return NULL;
782 if ((pkcs7 = PKCS7_encrypt(certs, bb, cipher, 0)) == NULL) {
783 ssl_gen_err("Error creating the PKCS#7 encryption object");
784 BIO_free(bb);
785 BIO_free(yb);
786 Fclose(yp);
787 return NULL;
789 if (PEM_write_bio_PKCS7(yb, pkcs7) == 0) {
790 ssl_gen_err("Error writing encrypted S/MIME data");
791 BIO_free(bb);
792 BIO_free(yb);
793 Fclose(yp);
794 return NULL;
796 BIO_free(bb);
797 BIO_free(yb);
798 Fclose(bp);
799 fflush(yp);
800 rewind(yp);
801 return smime_encrypt_assemble(hp, yp);
804 struct message *
805 smime_decrypt(struct message *m, const char *to, const char *cc, int signcall)
807 FILE *fp, *bp, *hp, *op;
808 char *cp;
809 X509 *cert = NULL;
810 PKCS7 *pkcs7;
811 EVP_PKEY *pkey = NULL;
812 BIO *bb, *pb, *ob;
813 long size = m->m_size;
814 FILE *yp;
816 if ((yp = setinput(&mb, m, NEED_BODY)) == NULL)
817 return NULL;
818 ssl_init();
819 if ((fp = smime_sign_cert(to, cc, 0)) != NULL) {
820 if ((pkey = PEM_read_PrivateKey(fp, NULL, ssl_password_cb,
821 NULL)) == NULL) {
822 ssl_gen_err("Error reading private key");
823 Fclose(fp);
824 return NULL;
826 rewind(fp);
827 if ((cert = PEM_read_X509(fp, NULL, ssl_password_cb,
828 NULL)) == NULL) {
829 ssl_gen_err("Error reading decryption certificate");
830 Fclose(fp);
831 EVP_PKEY_free(pkey);
832 return NULL;
834 Fclose(fp);
836 if ((op = Ftemp(&cp, "Rp", "w+", 0600, 1)) == NULL) {
837 perror("tempfile");
838 if (cert)
839 X509_free(cert);
840 if (pkey)
841 EVP_PKEY_free(pkey);
842 return NULL;
844 rm(cp);
845 Ftfree(&cp);
846 if (smime_split(yp, &hp, &bp, size, 1) == STOP) {
847 Fclose(op);
848 if (cert)
849 X509_free(cert);
850 if (pkey)
851 EVP_PKEY_free(pkey);
852 return NULL;
854 if ((ob = BIO_new_fp(op, BIO_NOCLOSE)) == NULL ||
855 (bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL) {
856 ssl_gen_err("Error creating BIO decryption objects");
857 Fclose(op);
858 if (cert)
859 X509_free(cert);
860 if (pkey)
861 EVP_PKEY_free(pkey);
862 return NULL;
864 if ((pkcs7 = SMIME_read_PKCS7(bb, &pb)) == NULL) {
865 ssl_gen_err("Error reading PKCS#7 object");
866 Fclose(op);
867 if (cert)
868 X509_free(cert);
869 if (pkey)
870 EVP_PKEY_free(pkey);
871 return NULL;
873 if (PKCS7_type_is_signed(pkcs7)) {
874 if (signcall) {
875 BIO_free(bb);
876 BIO_free(ob);
877 if (cert)
878 X509_free(cert);
879 if (pkey)
880 EVP_PKEY_free(pkey);
881 Fclose(op);
882 Fclose(bp);
883 Fclose(hp);
884 setinput(&mb, m, NEED_BODY);
885 return (struct message *)-1;
887 if (PKCS7_verify(pkcs7, NULL, NULL, NULL, ob,
888 PKCS7_NOVERIFY|PKCS7_NOSIGS) != 1)
889 goto err;
890 fseek(hp, 0L, SEEK_END);
891 fprintf(hp, "X-Encryption-Cipher: none\n");
892 fflush(hp);
893 rewind(hp);
894 } else if (pkey == NULL) {
895 fprintf(stderr, "No appropriate private key found.\n");
896 goto err2;
897 } else if (cert == NULL) {
898 fprintf(stderr, "No appropriate certificate found.\n");
899 goto err2;
900 } else if (PKCS7_decrypt(pkcs7, pkey, cert, ob, 0) != 1) {
901 err: ssl_gen_err("Error decrypting PKCS#7 object");
902 err2: BIO_free(bb);
903 BIO_free(ob);
904 Fclose(op);
905 Fclose(bp);
906 Fclose(hp);
907 if (cert)
908 X509_free(cert);
909 if (pkey)
910 EVP_PKEY_free(pkey);
911 return NULL;
913 BIO_free(bb);
914 BIO_free(ob);
915 if (cert)
916 X509_free(cert);
917 if (pkey)
918 EVP_PKEY_free(pkey);
919 fflush(op);
920 rewind(op);
921 Fclose(bp);
922 return smime_decrypt_assemble(m, hp, op);
925 /*ARGSUSED4*/
926 static int
927 ssl_password_cb(char *buf, int size, int rwflag, void *userdata)
929 sighandler_type saveint;
930 char *pass = NULL;
931 int len;
932 (void)rwflag;
933 (void)userdata;
935 saveint = safe_signal(SIGINT, SIG_IGN);
936 if (sigsetjmp(ssljmp, 1) == 0) {
937 if (saveint != SIG_IGN)
938 safe_signal(SIGINT, sslcatch);
939 pass = getpassword(&otio, &reset_tio, "PEM pass phrase:");
941 safe_signal(SIGINT, saveint);
942 if (pass == NULL)
943 return 0;
944 len = strlen(pass);
945 if (len > size)
946 len = size;
947 memcpy(buf, pass, len);
948 return len;
951 static FILE *
952 smime_sign_cert(const char *xname, const char *xname2, int warn)
954 char *vn, *cp;
955 int vs;
956 FILE *fp;
957 struct name *np;
958 const char *name = xname, *name2 = xname2;
960 loop: if (name) {
961 np = sextract(savestr(name), GTO|GSKIN);
962 while (np) {
964 * This needs to be more intelligent since it will
965 * currently take the first name for which a private
966 * key is available regardless of whether it is the
967 * right one for the message.
969 vn = ac_alloc(vs = strlen(np->n_name) + 30);
970 snprintf(vn, vs, "smime-sign-cert-%s", np->n_name);
971 if ((cp = value(vn)) != NULL)
972 goto open;
973 np = np->n_flink;
975 if (name2) {
976 name = name2;
977 name2 = NULL;
978 goto loop;
981 if ((cp = value("smime-sign-cert")) != NULL)
982 goto open;
983 if (warn) {
984 fprintf(stderr, "Could not find a certificate for %s", xname);
985 if (xname2)
986 fprintf(stderr, "or %s", xname2);
987 fputc('\n', stderr);
989 return NULL;
990 open: cp = expand(cp);
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 *name)
1001 /* See comments in smime_sign_cert() for algorithm pitfalls */
1002 if (name) {
1003 struct name *np = sextract(savestr(name), GTO|GSKIN);
1004 while (np) {
1005 int vs;
1006 char *vn = ac_alloc(vs = strlen(np->n_name) + 30);
1007 snprintf(vn, vs, "smime-sign-include-certs-%s",
1008 np->n_name);
1009 if ((name = value(vn)) != NULL)
1010 return name;
1011 np = np->n_flink;
1014 return value("smime-sign-include-certs");
1017 static int
1018 smime_sign_include_chain_creat(
1019 #ifdef HAVE_STACK_OF
1020 STACK_OF(X509) **chain,
1021 #else
1022 STACK **chain,
1023 #endif
1024 char *cfiles)
1026 *chain = sk_X509_new_null();
1028 for (;;) {
1029 X509 *tmp;
1030 FILE *fp;
1031 char *exp, *ncf = strchr(cfiles, ',');
1032 if (ncf)
1033 *ncf++ = '\0';
1034 /* This fails for '=,file' constructs, but those are sick */
1035 if (! *cfiles)
1036 break;
1038 if ((exp = expand(cfiles)) != NULL)
1039 cfiles = exp;
1040 if ((fp = Fopen(cfiles, "r")) == NULL) {
1041 perror(cfiles);
1042 goto jerr;
1044 if ((tmp = PEM_read_X509(fp, NULL, ssl_password_cb, NULL)
1045 ) == NULL) {
1046 ssl_gen_err("Error reading certificate from \"%s\"",
1047 cfiles);
1048 Fclose(fp);
1049 goto jerr;
1051 sk_X509_push(*chain, tmp);
1052 Fclose(fp);
1054 if (! ncf)
1055 break;
1056 cfiles = ncf;
1059 if (sk_X509_num(*chain) == 0) {
1060 fprintf(stderr, "smime-sign-include-certs defined but empty\n");
1061 goto jerr;
1064 jleave: return (*chain != NULL);
1066 jerr: sk_X509_pop_free(*chain, X509_free);
1067 *chain = NULL;
1068 goto jleave;
1071 enum okay
1072 smime_certsave(struct message *m, int n, FILE *op)
1074 struct message *x;
1075 char *cp, *to, *cc, *cnttype;
1076 int c, i;
1077 FILE *fp, *ip;
1078 off_t size;
1079 BIO *fb, *pb;
1080 PKCS7 *pkcs7;
1081 #ifdef HAVE_STACK_OF
1082 STACK_OF(X509) *certs;
1083 STACK_OF(X509) *chain = NULL;
1084 #else
1085 STACK *certs;
1086 STACK *chain = NULL;
1087 #endif
1088 X509 *cert;
1089 enum okay ok = OKAY;
1091 message_number = n;
1092 loop: to = hfield1("to", m);
1093 cc = hfield1("cc", m);
1094 cnttype = hfield1("content-type", m);
1095 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
1096 return STOP;
1097 if (cnttype && strncmp(cnttype, "application/x-pkcs7-mime", 24) == 0) {
1098 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
1099 return STOP;
1100 if (x != (struct message *)-1) {
1101 m = x;
1102 goto loop;
1105 size = m->m_size;
1106 if ((fp = Ftemp(&cp, "Rv", "w+", 0600, 1)) == NULL) {
1107 perror("tempfile");
1108 return STOP;
1110 rm(cp);
1111 Ftfree(&cp);
1112 while (size-- > 0) {
1113 c = getc(ip);
1114 putc(c, fp);
1116 fflush(fp);
1117 rewind(fp);
1118 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
1119 ssl_gen_err("Error creating BIO object for message %d", n);
1120 Fclose(fp);
1121 return STOP;
1123 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
1124 ssl_gen_err("Error reading PKCS#7 object for message %d", n);
1125 BIO_free(fb);
1126 Fclose(fp);
1127 return STOP;
1129 BIO_free(fb);
1130 Fclose(fp);
1131 certs = PKCS7_get0_signers(pkcs7, chain, 0);
1132 if (certs == NULL) {
1133 fprintf(stderr, "No certificates found in message %d.\n", n);
1134 return STOP;
1136 for (i = 0; i < sk_X509_num(certs); i++) {
1137 cert = sk_X509_value(certs, i);
1138 if (X509_print_fp(op, cert) == 0 ||
1139 PEM_write_X509(op, cert) == 0) {
1140 ssl_gen_err("Error writing certificate %d from "
1141 "message %d", i, n);
1142 ok = STOP;
1145 return ok;
1148 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1149 static enum okay
1150 load_crl1(X509_STORE *store, const char *name)
1152 X509_LOOKUP *lookup;
1154 if (verbose)
1155 printf("Loading CRL from \"%s\".\n", name);
1156 if ((lookup = X509_STORE_add_lookup(store,
1157 X509_LOOKUP_file())) == NULL) {
1158 ssl_gen_err("Error creating X509 lookup object");
1159 return STOP;
1161 if (X509_load_crl_file(lookup, name, X509_FILETYPE_PEM) != 1) {
1162 ssl_gen_err("Error loading CRL from \"%s\"", name);
1163 return STOP;
1165 return OKAY;
1167 #endif /* new OpenSSL */
1169 static enum okay
1170 load_crls(X509_STORE *store, const char *vfile, const char *vdir)
1172 char *crl_file, *crl_dir;
1173 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1174 DIR *dirfd;
1175 struct dirent *dp;
1176 char *fn = NULL;
1177 int fs = 0, ds, es;
1178 #endif /* new OpenSSL */
1180 if ((crl_file = value(vfile)) != NULL) {
1181 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1182 crl_file = expand(crl_file);
1183 if (load_crl1(store, crl_file) != OKAY)
1184 return STOP;
1185 #else /* old OpenSSL */
1186 fprintf(stderr,
1187 "This OpenSSL version is too old to use CRLs.\n");
1188 return STOP;
1189 #endif /* old OpenSSL */
1191 if ((crl_dir = value(vdir)) != NULL) {
1192 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1193 crl_dir = expand(crl_dir);
1194 ds = strlen(crl_dir);
1195 if ((dirfd = opendir(crl_dir)) == NULL) {
1196 perror(crl_dir);
1197 return STOP;
1199 fn = smalloc(fs = ds + 20);
1200 strcpy(fn, crl_dir);
1201 fn[ds] = '/';
1202 while ((dp = readdir(dirfd)) != NULL) {
1203 if (dp->d_name[0] == '.' &&
1204 (dp->d_name[1] == '\0' ||
1205 (dp->d_name[1] == '.' &&
1206 dp->d_name[2] == '\0')))
1207 continue;
1208 if (dp->d_name[0] == '.')
1209 continue;
1210 if (ds + (es = strlen(dp->d_name)) + 2 < fs)
1211 fn = srealloc(fn, fs = ds + es + 20);
1212 strcpy(&fn[ds+1], dp->d_name);
1213 if (load_crl1(store, fn) != OKAY) {
1214 closedir(dirfd);
1215 free(fn);
1216 return STOP;
1219 closedir(dirfd);
1220 free(fn);
1221 #else /* old OpenSSL */
1222 fprintf(stderr,
1223 "This OpenSSL version is too old to use CRLs.\n");
1224 return STOP;
1225 #endif /* old OpenSSL */
1227 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1228 if (crl_file || crl_dir)
1229 X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK |
1230 X509_V_FLAG_CRL_CHECK_ALL);
1231 #endif /* old OpenSSL */
1232 return OKAY;
1235 #else /* !NSS && !USE_OPENSSL */
1237 #include <stdio.h>
1239 static void
1240 nosmime(void)
1242 fprintf(stderr, "No S/MIME support compiled in.\n");
1245 /*ARGSUSED*/
1246 FILE *
1247 smime_sign(FILE *fp)
1249 (void)fp;
1250 nosmime();
1251 return NULL;
1254 /*ARGSUSED*/
1255 int
1256 cverify(void *vp)
1258 (void)vp;
1259 nosmime();
1260 return 1;
1263 /*ARGSUSED*/
1264 FILE *
1265 smime_encrypt(FILE *fp, const char *certfile, const char *to)
1267 (void)fp;
1268 (void)certfile;
1269 (void)to;
1270 nosmime();
1271 return NULL;
1274 /*ARGSUSED*/
1275 struct message *
1276 smime_decrypt(struct message *m, const char *to, const char *cc, int signcall)
1278 (void)m;
1279 (void)to;
1280 (void)cc;
1281 (void)signcall;
1282 nosmime();
1283 return NULL;
1286 /*ARGSUSED*/
1287 int
1288 ccertsave(void *v)
1290 (void)v;
1291 nosmime();
1292 return 1;
1294 #endif /* !USE_NSS && !USE_OPENSSL */