md5.c: fix compiler warnings..
[s-mailx.git] / openssl.c
blob30d941fb6ebeaf2ce45ad755d398837012e8b5be
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 #ifndef USE_NSS
49 #ifdef USE_OPENSSL
51 #include <setjmp.h>
52 #include <termios.h>
53 #include <stdio.h>
55 static int verbose;
56 static int reset_tio;
57 static struct termios otio;
58 static sigjmp_buf ssljmp;
60 #include <openssl/crypto.h>
61 #include <openssl/ssl.h>
62 #include <openssl/err.h>
63 #include <openssl/x509v3.h>
64 #include <openssl/x509.h>
65 #include <openssl/pem.h>
66 #include <openssl/rand.h>
68 #include "rcv.h"
69 #include <errno.h>
70 #include <sys/stat.h>
71 #include <unistd.h>
72 #include <time.h>
74 #include <sys/socket.h>
75 #include <netdb.h>
76 #include <netinet/in.h>
77 #ifdef HAVE_ARPA_INET_H
78 #include <arpa/inet.h>
79 #endif /* HAVE_ARPA_INET_H */
81 #include <dirent.h>
83 #include "extern.h"
86 * Mail -- a mail program
88 * SSL functions
92 * OpenSSL client implementation according to: John Viega, Matt Messier,
93 * Pravir Chandra: Network Security with OpenSSL. Sebastopol, CA 2002.
96 static int initialized;
97 static int rand_init;
98 static int message_number;
99 static int verify_error_found;
101 static void sslcatch(int s);
102 static int ssl_rand_init(void);
103 static void ssl_init(void);
104 static int ssl_verify_cb(int success, X509_STORE_CTX *store);
105 static const SSL_METHOD *ssl_select_method(const char *uhp);
106 static void ssl_load_verifications(struct sock *sp);
107 static void ssl_certificate(struct sock *sp, const char *uhp);
108 static enum okay ssl_check_host(const char *server, struct sock *sp);
109 #ifdef HAVE_STACK_OF
110 static int smime_verify(struct message *m, int n, STACK_OF(X509) *chain,
111 X509_STORE *store);
112 #else
113 static int smime_verify(struct message *m, int n, STACK *chain,
114 X509_STORE *store);
115 #endif
116 static EVP_CIPHER *smime_cipher(const char *name);
117 static int ssl_password_cb(char *buf, int size, int rwflag, void *userdata);
118 static FILE *smime_sign_cert(const char *xname, const char *xname2, int warn);
119 static char *smime_sign_include_certs(char *name);
120 #ifdef HAVE_STACK_OF
121 static int smime_sign_include_chain_creat(STACK_OF(X509) **chain, char *cfiles);
122 #else
123 static int smime_sign_include_chain_creat(STACK **chain, char *cfiles);
124 #endif
125 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
126 static enum okay load_crl1(X509_STORE *store, const char *name);
127 #endif
128 static enum okay load_crls(X509_STORE *store, const char *vfile,
129 const char *vdir);
131 static void
132 sslcatch(int s)
134 if (reset_tio)
135 tcsetattr(0, TCSADRAIN, &otio);
136 siglongjmp(ssljmp, s);
139 static int
140 ssl_rand_init(void)
142 char *cp;
143 int state = 0;
145 if ((cp = value("ssl-rand-egd")) != NULL) {
146 cp = expand(cp);
147 if (RAND_egd(cp) == -1) {
148 fprintf(stderr, catgets(catd, CATSET, 245,
149 "entropy daemon at \"%s\" not available\n"),
150 cp);
151 } else
152 state = 1;
153 } else if ((cp = value("ssl-rand-file")) != NULL) {
154 cp = expand(cp);
155 if (RAND_load_file(cp, 1024) == -1) {
156 fprintf(stderr, catgets(catd, CATSET, 246,
157 "entropy file at \"%s\" not available\n"), cp);
158 } else {
159 struct stat st;
161 if (stat(cp, &st) == 0 && S_ISREG(st.st_mode) &&
162 access(cp, W_OK) == 0) {
163 if (RAND_write_file(cp) == -1) {
164 fprintf(stderr, catgets(catd, CATSET,
165 247,
166 "writing entropy data to \"%s\" failed\n"), cp);
169 state = 1;
172 return state;
175 static void
176 ssl_init(void)
178 verbose = value("verbose") != NULL;
179 if (initialized == 0) {
180 SSL_library_init();
181 initialized = 1;
183 if (rand_init == 0)
184 rand_init = ssl_rand_init();
187 static int
188 ssl_verify_cb(int success, X509_STORE_CTX *store)
190 if (success == 0) {
191 char data[256];
192 X509 *cert = X509_STORE_CTX_get_current_cert(store);
193 int depth = X509_STORE_CTX_get_error_depth(store);
194 int err = X509_STORE_CTX_get_error(store);
196 verify_error_found = 1;
197 if (message_number)
198 fprintf(stderr, "Message %d: ", message_number);
199 fprintf(stderr, catgets(catd, CATSET, 229,
200 "Error with certificate at depth: %i\n"),
201 depth);
202 X509_NAME_oneline(X509_get_issuer_name(cert), data,
203 sizeof data);
204 fprintf(stderr, catgets(catd, CATSET, 230, " issuer = %s\n"),
205 data);
206 X509_NAME_oneline(X509_get_subject_name(cert), data,
207 sizeof data);
208 fprintf(stderr, catgets(catd, CATSET, 231, " subject = %s\n"),
209 data);
210 fprintf(stderr, catgets(catd, CATSET, 232, " err %i: %s\n"),
211 err, X509_verify_cert_error_string(err));
212 if (ssl_vrfy_decide() != OKAY)
213 return 0;
215 return 1;
218 static const SSL_METHOD *
219 ssl_select_method(const char *uhp)
221 const SSL_METHOD *method;
222 char *cp;
224 cp = ssl_method_string(uhp);
225 if (cp != NULL) {
226 #ifndef OPENSSL_NO_SSL2
227 if (equal(cp, "ssl2"))
228 method = SSLv2_client_method();
229 else
230 #endif
231 if (equal(cp, "ssl3"))
232 method = SSLv3_client_method();
233 else if (equal(cp, "tls1"))
234 method = TLSv1_client_method();
235 else {
236 fprintf(stderr, catgets(catd, CATSET, 244,
237 "Invalid SSL method \"%s\"\n"), cp);
238 method = SSLv23_client_method();
240 } else
241 method = SSLv23_client_method();
242 return method;
245 static void
246 ssl_load_verifications(struct sock *sp)
248 char *ca_dir, *ca_file;
249 X509_STORE *store;
251 if (ssl_vrfy_level == VRFY_IGNORE)
252 return;
253 if ((ca_dir = value("ssl-ca-dir")) != NULL)
254 ca_dir = expand(ca_dir);
255 if ((ca_file = value("ssl-ca-file")) != NULL)
256 ca_file = expand(ca_file);
257 if (ca_dir || ca_file) {
258 if (SSL_CTX_load_verify_locations(sp->s_ctx,
259 ca_file, ca_dir) != 1) {
260 fprintf(stderr, catgets(catd, CATSET, 233,
261 "Error loading"));
262 if (ca_dir) {
263 fprintf(stderr, catgets(catd, CATSET, 234,
264 " %s"), ca_dir);
265 if (ca_file)
266 fprintf(stderr, catgets(catd, CATSET,
267 235, " or"));
269 if (ca_file)
270 fprintf(stderr, catgets(catd, CATSET, 236,
271 " %s"), ca_file);
272 fprintf(stderr, catgets(catd, CATSET, 237, "\n"));
275 if (value("ssl-no-default-ca") == NULL) {
276 if (SSL_CTX_set_default_verify_paths(sp->s_ctx) != 1)
277 fprintf(stderr, catgets(catd, CATSET, 243,
278 "Error loading default CA locations\n"));
280 verify_error_found = 0;
281 message_number = 0;
282 SSL_CTX_set_verify(sp->s_ctx, SSL_VERIFY_PEER, ssl_verify_cb);
283 store = SSL_CTX_get_cert_store(sp->s_ctx);
284 load_crls(store, "ssl-crl-file", "ssl-crl-dir");
287 static void
288 ssl_certificate(struct sock *sp, const char *uhp)
290 char *certvar, *keyvar, *cert, *key;
292 certvar = ac_alloc(strlen(uhp) + 10);
293 strcpy(certvar, "ssl-cert-");
294 strcpy(&certvar[9], uhp);
295 if ((cert = value(certvar)) != NULL ||
296 (cert = value("ssl-cert")) != NULL) {
297 cert = expand(cert);
298 if (SSL_CTX_use_certificate_chain_file(sp->s_ctx, cert) == 1) {
299 keyvar = ac_alloc(strlen(uhp) + 9);
300 strcpy(keyvar, "ssl-key-");
301 if ((key = value(keyvar)) == NULL &&
302 (key = value("ssl-key")) == NULL)
303 key = cert;
304 else
305 key = expand(key);
306 if (SSL_CTX_use_PrivateKey_file(sp->s_ctx, key,
307 SSL_FILETYPE_PEM) != 1)
308 fprintf(stderr, catgets(catd, CATSET, 238,
309 "cannot load private key from file %s\n"),
310 key);
311 ac_free(keyvar);
312 } else
313 fprintf(stderr, catgets(catd, CATSET, 239,
314 "cannot load certificate from file %s\n"),
315 cert);
317 ac_free(certvar);
320 static enum okay
321 ssl_check_host(const char *server, struct sock *sp)
323 X509 *cert;
324 X509_NAME *subj;
325 char data[256];
326 #ifdef HAVE_STACK_OF
327 STACK_OF(GENERAL_NAME) *gens;
328 #else
329 /*GENERAL_NAMES*/STACK *gens;
330 #endif
331 GENERAL_NAME *gen;
332 int i;
334 if ((cert = SSL_get_peer_certificate(sp->s_ssl)) == NULL) {
335 fprintf(stderr, catgets(catd, CATSET, 248,
336 "no certificate from \"%s\"\n"), server);
337 return STOP;
339 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
340 if (gens != NULL) {
341 for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
342 gen = sk_GENERAL_NAME_value(gens, i);
343 if (gen->type == GEN_DNS) {
344 if (verbose)
345 fprintf(stderr,
346 "Comparing DNS name: \"%s\"\n",
347 gen->d.ia5->data);
348 if (rfc2595_hostname_match(server,
349 (char *)gen->d.ia5->data)
350 == OKAY)
351 goto found;
355 if ((subj = X509_get_subject_name(cert)) != NULL &&
356 X509_NAME_get_text_by_NID(subj, NID_commonName,
357 data, sizeof data) > 0) {
358 data[sizeof data - 1] = 0;
359 if (verbose)
360 fprintf(stderr, "Comparing common name: \"%s\"\n",
361 data);
362 if (rfc2595_hostname_match(server, data) == OKAY)
363 goto found;
365 X509_free(cert);
366 return STOP;
367 found: X509_free(cert);
368 return OKAY;
371 enum okay
372 ssl_open(const char *server, struct sock *sp, const char *uhp)
374 char *cp;
375 long options;
377 ssl_init();
378 ssl_set_vrfy_level(uhp);
379 if ((sp->s_ctx =
380 SSL_CTX_new((SSL_METHOD *)ssl_select_method(uhp))) == NULL) {
381 ssl_gen_err(catgets(catd, CATSET, 261, "SSL_CTX_new() failed"));
382 return STOP;
384 #ifdef SSL_MODE_AUTO_RETRY
385 /* available with OpenSSL 0.9.6 or later */
386 SSL_CTX_set_mode(sp->s_ctx, SSL_MODE_AUTO_RETRY);
387 #endif /* SSL_MODE_AUTO_RETRY */
388 options = SSL_OP_ALL;
389 if (value("ssl-v2-allow") == NULL)
390 options |= SSL_OP_NO_SSLv2;
391 SSL_CTX_set_options(sp->s_ctx, options);
392 ssl_load_verifications(sp);
393 ssl_certificate(sp, uhp);
394 if ((cp = value("ssl-cipher-list")) != NULL) {
395 if (SSL_CTX_set_cipher_list(sp->s_ctx, cp) != 1)
396 fprintf(stderr, catgets(catd, CATSET, 240,
397 "invalid ciphers: %s\n"), cp);
399 if ((sp->s_ssl = SSL_new(sp->s_ctx)) == NULL) {
400 ssl_gen_err(catgets(catd, CATSET, 262, "SSL_new() failed"));
401 return STOP;
403 SSL_set_fd(sp->s_ssl, sp->s_fd);
404 if (SSL_connect(sp->s_ssl) < 0) {
405 ssl_gen_err(catgets(catd, CATSET, 263,
406 "could not initiate SSL/TLS connection"));
407 return STOP;
409 if (ssl_vrfy_level != VRFY_IGNORE) {
410 if (ssl_check_host(server, sp) != OKAY) {
411 fprintf(stderr, catgets(catd, CATSET, 249,
412 "host certificate does not match \"%s\"\n"),
413 server);
414 if (ssl_vrfy_decide() != OKAY)
415 return STOP;
418 sp->s_use_ssl = 1;
419 return OKAY;
422 void
423 ssl_gen_err(const char *fmt, ...)
425 va_list ap;
427 va_start(ap, fmt);
428 vfprintf(stderr, fmt, ap);
429 va_end(ap);
430 SSL_load_error_strings();
431 fprintf(stderr, ": %s\n",
432 (ERR_error_string(ERR_get_error(), NULL)));
435 FILE *
436 smime_sign(FILE *ip, struct header *headp)
438 FILE *sp, *fp, *bp, *hp;
439 char *cp, *addr;
440 X509 *cert;
441 #ifdef HAVE_STACK_OF
442 STACK_OF(X509) *chain = NULL;
443 #else
444 STACK *chain = NULL;
445 #endif
446 PKCS7 *pkcs7;
447 EVP_PKEY *pkey;
448 BIO *bb, *sb;
450 ssl_init();
451 if ((addr = myorigin(headp)) == NULL) {
452 fprintf(stderr, "No \"from\" address for signing specified\n");
453 return NULL;
455 if ((fp = smime_sign_cert(addr, NULL, 1)) == NULL)
456 return NULL;
457 if ((pkey = PEM_read_PrivateKey(fp, NULL, ssl_password_cb, NULL))
458 == NULL) {
459 ssl_gen_err("Error reading private key from");
460 Fclose(fp);
461 return NULL;
463 rewind(fp);
464 if ((cert = PEM_read_X509(fp, NULL, ssl_password_cb, NULL)) == NULL) {
465 ssl_gen_err("Error reading signer certificate from");
466 Fclose(fp);
467 EVP_PKEY_free(pkey);
468 return NULL;
470 Fclose(fp);
471 if ((cp = smime_sign_include_certs(addr)) != NULL &&
472 !smime_sign_include_chain_creat(&chain, cp)) {
473 X509_free(cert);
474 EVP_PKEY_free(pkey);
475 return NULL;
477 if ((sp = Ftemp(&cp, "Rs", "w+", 0600, 1)) == NULL) {
478 perror("tempfile");
479 if (chain != NULL)
480 sk_X509_pop_free(chain, X509_free);
481 X509_free(cert);
482 EVP_PKEY_free(pkey);
483 return NULL;
485 rm(cp);
486 Ftfree(&cp);
487 rewind(ip);
488 if (smime_split(ip, &hp, &bp, -1, 0) == STOP) {
489 Fclose(sp);
490 if (chain != NULL)
491 sk_X509_pop_free(chain, X509_free);
492 X509_free(cert);
493 EVP_PKEY_free(pkey);
494 return NULL;
496 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
497 (sb = BIO_new_fp(sp, BIO_NOCLOSE)) == NULL) {
498 ssl_gen_err("Error creating BIO signing objects");
499 Fclose(sp);
500 if (chain != NULL)
501 sk_X509_pop_free(chain, X509_free);
502 X509_free(cert);
503 EVP_PKEY_free(pkey);
504 return NULL;
506 if ((pkcs7 = PKCS7_sign(cert, pkey, chain, bb,
507 PKCS7_DETACHED)) == NULL) {
508 ssl_gen_err("Error creating the PKCS#7 signing object");
509 BIO_free(bb);
510 BIO_free(sb);
511 Fclose(sp);
512 if (chain != NULL)
513 sk_X509_pop_free(chain, X509_free);
514 X509_free(cert);
515 EVP_PKEY_free(pkey);
516 return NULL;
518 if (PEM_write_bio_PKCS7(sb, pkcs7) == 0) {
519 ssl_gen_err("Error writing signed S/MIME data");
520 BIO_free(bb);
521 BIO_free(sb);
522 Fclose(sp);
523 if (chain != NULL)
524 sk_X509_pop_free(chain, X509_free);
525 X509_free(cert);
526 EVP_PKEY_free(pkey);
527 return NULL;
529 BIO_free(bb);
530 BIO_free(sb);
531 if (chain != NULL)
532 sk_X509_pop_free(chain, X509_free);
533 X509_free(cert);
534 EVP_PKEY_free(pkey);
535 rewind(bp);
536 fflush(sp);
537 rewind(sp);
538 return smime_sign_assemble(hp, bp, sp);
541 static int
542 #ifdef HAVE_STACK_OF
543 smime_verify(struct message *m, int n, STACK_OF(X509) *chain, X509_STORE *store)
544 #else
545 smime_verify(struct message *m, int n, STACK *chain, X509_STORE *store)
546 #endif
548 struct message *x;
549 char *cp, *sender, *to, *cc, *cnttype;
550 int c, i, j;
551 FILE *fp, *ip;
552 off_t size;
553 BIO *fb, *pb;
554 PKCS7 *pkcs7;
555 #ifdef HAVE_STACK_OF
556 STACK_OF(X509) *certs;
557 STACK_OF(GENERAL_NAME) *gens;
558 #else
559 STACK *certs, *gens;
560 #endif
561 X509 *cert;
562 X509_NAME *subj;
563 char data[LINESIZE];
564 GENERAL_NAME *gen;
566 verify_error_found = 0;
567 message_number = n;
568 loop: sender = getsender(m);
569 to = hfield("to", m);
570 cc = hfield("cc", m);
571 cnttype = hfield("content-type", m);
572 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
573 return 1;
574 if (cnttype && strncmp(cnttype, "application/x-pkcs7-mime", 24) == 0) {
575 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
576 return 1;
577 if (x != (struct message *)-1) {
578 m = x;
579 goto loop;
582 size = m->m_size;
583 if ((fp = Ftemp(&cp, "Rv", "w+", 0600, 1)) == NULL) {
584 perror("tempfile");
585 return 1;
587 rm(cp);
588 Ftfree(&cp);
589 while (size-- > 0) {
590 c = getc(ip);
591 putc(c, fp);
593 fflush(fp);
594 rewind(fp);
595 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
596 ssl_gen_err("Error creating BIO verification object "
597 "for message %d", n);
598 Fclose(fp);
599 return 1;
601 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
602 ssl_gen_err("Error reading PKCS#7 object for message %d", n);
603 BIO_free(fb);
604 Fclose(fp);
605 return 1;
607 if (PKCS7_verify(pkcs7, chain, store, pb, NULL, 0) != 1) {
608 ssl_gen_err("Error verifying message %d", n);
609 BIO_free(fb);
610 Fclose(fp);
611 return 1;
613 BIO_free(fb);
614 Fclose(fp);
615 if (sender == NULL) {
616 fprintf(stderr,
617 "Warning: Message %d has no sender.\n", n);
618 return 0;
620 certs = PKCS7_get0_signers(pkcs7, chain, 0);
621 if (certs == NULL) {
622 fprintf(stderr, "No certificates found in message %d.\n", n);
623 return 1;
625 for (i = 0; i < sk_X509_num(certs); i++) {
626 cert = sk_X509_value(certs, i);
627 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
628 if (gens != NULL) {
629 for (j = 0; j < sk_GENERAL_NAME_num(gens); j++) {
630 gen = sk_GENERAL_NAME_value(gens, j);
631 if (gen->type == GEN_EMAIL) {
632 if (verbose)
633 fprintf(stderr,
634 "Comparing alt. "
635 "address: %s\"\n",
636 data);
637 if (!asccasecmp((char *)
638 gen->d.ia5->data,
639 sender))
640 goto found;
644 if ((subj = X509_get_subject_name(cert)) != NULL &&
645 X509_NAME_get_text_by_NID(subj,
646 NID_pkcs9_emailAddress,
647 data, sizeof data) > 0) {
648 data[sizeof data - 1] = 0;
649 if (verbose)
650 fprintf(stderr, "Comparing address: \"%s\"\n",
651 data);
652 if (asccasecmp(data, sender) == 0)
653 goto found;
656 fprintf(stderr, "Message %d: certificate does not match <%s>\n",
657 n, sender);
658 return 1;
659 found: if (verify_error_found == 0)
660 printf("Message %d was verified successfully.\n", n);
661 return verify_error_found;
664 int
665 cverify(void *vp)
667 int *msgvec = vp, *ip;
668 int ec = 0;
669 #ifdef HAVE_STACK_OF
670 STACK_OF(X509) *chain = NULL;
671 #else
672 STACK *chain = NULL;
673 #endif
674 X509_STORE *store;
675 char *ca_dir, *ca_file;
677 ssl_init();
678 ssl_vrfy_level = VRFY_STRICT;
679 if ((store = X509_STORE_new()) == NULL) {
680 ssl_gen_err("Error creating X509 store");
681 return 1;
683 X509_STORE_set_verify_cb_func(store, ssl_verify_cb);
684 if ((ca_dir = value("smime-ca-dir")) != NULL)
685 ca_dir = expand(ca_dir);
686 if ((ca_file = value("smime-ca-file")) != NULL)
687 ca_file = expand(ca_file);
688 if (ca_dir || ca_file) {
689 if (X509_STORE_load_locations(store, ca_file, ca_dir) != 1) {
690 ssl_gen_err("Error loading %s",
691 ca_file ? ca_file : ca_dir);
692 return 1;
695 if (value("smime-no-default-ca") == NULL) {
696 if (X509_STORE_set_default_paths(store) != 1) {
697 ssl_gen_err("Error loading default CA locations");
698 return 1;
701 if (load_crls(store, "smime-crl-file", "smime-crl-dir") != OKAY)
702 return 1;
703 for (ip = msgvec; *ip; ip++) {
704 setdot(&message[*ip-1]);
705 ec |= smime_verify(&message[*ip-1], *ip, chain, store);
707 return ec;
710 static EVP_CIPHER *
711 smime_cipher(const char *name)
713 const EVP_CIPHER *cipher;
714 char *vn, *cp;
715 int vs;
717 vn = ac_alloc(vs = strlen(name) + 30);
718 snprintf(vn, vs, "smime-cipher-%s", name);
719 if ((cp = value(vn)) != NULL) {
720 if (strcmp(cp, "rc2-40") == 0)
721 cipher = EVP_rc2_40_cbc();
722 else if (strcmp(cp, "rc2-64") == 0)
723 cipher = EVP_rc2_64_cbc();
724 else if (strcmp(cp, "des") == 0)
725 cipher = EVP_des_cbc();
726 else if (strcmp(cp, "des-ede3") == 0)
727 cipher = EVP_des_ede3_cbc();
728 else {
729 fprintf(stderr, "Invalid cipher \"%s\".\n", cp);
730 cipher = NULL;
732 } else
733 cipher = EVP_des_ede3_cbc();
734 ac_free(vn);
735 return (EVP_CIPHER *)cipher;
738 FILE *
739 smime_encrypt(FILE *ip, const char *certfile, const char *to)
741 FILE *yp, *fp, *bp, *hp;
742 char *cp;
743 X509 *cert;
744 PKCS7 *pkcs7;
745 BIO *bb, *yb;
746 #ifdef HAVE_STACK_OF
747 STACK_OF(X509) *certs;
748 #else
749 STACK *certs;
750 #endif
751 EVP_CIPHER *cipher;
753 certfile = expand((char *)certfile);
754 ssl_init();
755 if ((cipher = smime_cipher(to)) == NULL)
756 return NULL;
757 if ((fp = Fopen(certfile, "r")) == NULL) {
758 perror(certfile);
759 return NULL;
761 if ((cert = PEM_read_X509(fp, NULL, ssl_password_cb, NULL)) == NULL) {
762 ssl_gen_err("Error reading encryption certificate from \"%s\"",
763 certfile);
764 Fclose(fp);
765 return NULL;
767 Fclose(fp);
768 certs = sk_X509_new_null();
769 sk_X509_push(certs, cert);
770 if ((yp = Ftemp(&cp, "Ry", "w+", 0600, 1)) == NULL) {
771 perror("tempfile");
772 return NULL;
774 rm(cp);
775 Ftfree(&cp);
776 rewind(ip);
777 if (smime_split(ip, &hp, &bp, -1, 0) == STOP) {
778 Fclose(yp);
779 return NULL;
781 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
782 (yb = BIO_new_fp(yp, BIO_NOCLOSE)) == NULL) {
783 ssl_gen_err("Error creating BIO encryption objects");
784 Fclose(yp);
785 return NULL;
787 if ((pkcs7 = PKCS7_encrypt(certs, bb, cipher, 0)) == NULL) {
788 ssl_gen_err("Error creating the PKCS#7 encryption object");
789 BIO_free(bb);
790 BIO_free(yb);
791 Fclose(yp);
792 return NULL;
794 if (PEM_write_bio_PKCS7(yb, pkcs7) == 0) {
795 ssl_gen_err("Error writing encrypted S/MIME data");
796 BIO_free(bb);
797 BIO_free(yb);
798 Fclose(yp);
799 return NULL;
801 BIO_free(bb);
802 BIO_free(yb);
803 Fclose(bp);
804 fflush(yp);
805 rewind(yp);
806 return smime_encrypt_assemble(hp, yp);
809 struct message *
810 smime_decrypt(struct message *m, const char *to, const char *cc, int signcall)
812 FILE *fp, *bp, *hp, *op;
813 char *cp;
814 X509 *cert = NULL;
815 PKCS7 *pkcs7;
816 EVP_PKEY *pkey = NULL;
817 BIO *bb, *pb, *ob;
818 long size = m->m_size;
819 FILE *yp;
821 if ((yp = setinput(&mb, m, NEED_BODY)) == NULL)
822 return NULL;
823 ssl_init();
824 if ((fp = smime_sign_cert(to, cc, 0)) != NULL) {
825 if ((pkey = PEM_read_PrivateKey(fp, NULL, ssl_password_cb,
826 NULL)) == NULL) {
827 ssl_gen_err("Error reading private key");
828 Fclose(fp);
829 return NULL;
831 rewind(fp);
832 if ((cert = PEM_read_X509(fp, NULL, ssl_password_cb,
833 NULL)) == NULL) {
834 ssl_gen_err("Error reading decryption certificate");
835 Fclose(fp);
836 EVP_PKEY_free(pkey);
837 return NULL;
839 Fclose(fp);
841 if ((op = Ftemp(&cp, "Rp", "w+", 0600, 1)) == NULL) {
842 perror("tempfile");
843 if (cert)
844 X509_free(cert);
845 if (pkey)
846 EVP_PKEY_free(pkey);
847 return NULL;
849 rm(cp);
850 Ftfree(&cp);
851 if (smime_split(yp, &hp, &bp, size, 1) == STOP) {
852 Fclose(op);
853 if (cert)
854 X509_free(cert);
855 if (pkey)
856 EVP_PKEY_free(pkey);
857 return NULL;
859 if ((ob = BIO_new_fp(op, BIO_NOCLOSE)) == NULL ||
860 (bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL) {
861 ssl_gen_err("Error creating BIO decryption objects");
862 Fclose(op);
863 if (cert)
864 X509_free(cert);
865 if (pkey)
866 EVP_PKEY_free(pkey);
867 return NULL;
869 if ((pkcs7 = SMIME_read_PKCS7(bb, &pb)) == NULL) {
870 ssl_gen_err("Error reading PKCS#7 object");
871 Fclose(op);
872 if (cert)
873 X509_free(cert);
874 if (pkey)
875 EVP_PKEY_free(pkey);
876 return NULL;
878 if (PKCS7_type_is_signed(pkcs7)) {
879 if (signcall) {
880 BIO_free(bb);
881 BIO_free(ob);
882 if (cert)
883 X509_free(cert);
884 if (pkey)
885 EVP_PKEY_free(pkey);
886 Fclose(op);
887 Fclose(bp);
888 Fclose(hp);
889 setinput(&mb, m, NEED_BODY);
890 return (struct message *)-1;
892 if (PKCS7_verify(pkcs7, NULL, NULL, NULL, ob,
893 PKCS7_NOVERIFY|PKCS7_NOSIGS) != 1)
894 goto err;
895 fseek(hp, 0L, SEEK_END);
896 fprintf(hp, "X-Encryption-Cipher: none\n");
897 fflush(hp);
898 rewind(hp);
899 } else if (pkey == NULL) {
900 fprintf(stderr, "No appropriate private key found.\n");
901 goto err2;
902 } else if (cert == NULL) {
903 fprintf(stderr, "No appropriate certificate found.\n");
904 goto err2;
905 } else if (PKCS7_decrypt(pkcs7, pkey, cert, ob, 0) != 1) {
906 err: ssl_gen_err("Error decrypting PKCS#7 object");
907 err2: BIO_free(bb);
908 BIO_free(ob);
909 Fclose(op);
910 Fclose(bp);
911 Fclose(hp);
912 if (cert)
913 X509_free(cert);
914 if (pkey)
915 EVP_PKEY_free(pkey);
916 return NULL;
918 BIO_free(bb);
919 BIO_free(ob);
920 if (cert)
921 X509_free(cert);
922 if (pkey)
923 EVP_PKEY_free(pkey);
924 fflush(op);
925 rewind(op);
926 Fclose(bp);
927 return smime_decrypt_assemble(m, hp, op);
930 /*ARGSUSED4*/
931 static int
932 ssl_password_cb(char *buf, int size, int rwflag, void *userdata)
934 sighandler_type saveint;
935 char *pass = NULL;
936 int len;
938 (void)&saveint;
939 (void)&pass;
940 saveint = safe_signal(SIGINT, SIG_IGN);
941 if (sigsetjmp(ssljmp, 1) == 0) {
942 if (saveint != SIG_IGN)
943 safe_signal(SIGINT, sslcatch);
944 pass = getpassword(&otio, &reset_tio, "PEM pass phrase:");
946 safe_signal(SIGINT, saveint);
947 if (pass == NULL)
948 return 0;
949 len = strlen(pass);
950 if (len > size)
951 len = size;
952 memcpy(buf, pass, len);
953 return len;
956 static FILE *
957 smime_sign_cert(const char *xname, const char *xname2, int warn)
959 char *vn, *cp;
960 int vs;
961 FILE *fp;
962 struct name *np;
963 const char *name = xname, *name2 = xname2;
965 loop: if (name) {
966 np = sextract(savestr(name), GTO|GSKIN);
967 while (np) {
969 * This needs to be more intelligent since it will
970 * currently take the first name for which a private
971 * key is available regardless of whether it is the
972 * right one for the message.
974 vn = ac_alloc(vs = strlen(np->n_name) + 30);
975 snprintf(vn, vs, "smime-sign-cert-%s", np->n_name);
976 if ((cp = value(vn)) != NULL)
977 goto open;
978 np = np->n_flink;
980 if (name2) {
981 name = name2;
982 name2 = NULL;
983 goto loop;
986 if ((cp = value("smime-sign-cert")) != NULL)
987 goto open;
988 if (warn) {
989 fprintf(stderr, "Could not find a certificate for %s", xname);
990 if (xname2)
991 fprintf(stderr, "or %s", xname2);
992 fputc('\n', stderr);
994 return NULL;
995 open: cp = expand(cp);
996 if ((fp = Fopen(cp, "r")) == NULL) {
997 perror(cp);
998 return NULL;
1000 return fp;
1003 static char *
1004 smime_sign_include_certs(char *name)
1006 /* See comments in smime_sign_cert() for algorithm pitfalls */
1007 if (name) {
1008 struct name *np = sextract(savestr(name), GTO|GSKIN);
1009 while (np) {
1010 int vs;
1011 char *vn = ac_alloc(vs = strlen(np->n_name) + 30);
1012 snprintf(vn, vs, "smime-sign-include-certs-%s",
1013 np->n_name);
1014 if ((name = value(vn)) != NULL)
1015 return name;
1016 np = np->n_flink;
1019 return value("smime-sign-include-certs");
1022 static int
1023 smime_sign_include_chain_creat(
1024 #ifdef HAVE_STACK_OF
1025 STACK_OF(X509) **chain,
1026 #else
1027 STACK **chain,
1028 #endif
1029 char *cfiles)
1031 *chain = sk_X509_new_null();
1033 for (;;) {
1034 X509 *tmp;
1035 FILE *fp;
1036 char *exp, *ncf = strchr(cfiles, ',');
1037 if (ncf)
1038 *ncf++ = '\0';
1039 /* This fails for '=,file' constructs, but those are sick */
1040 if (! *cfiles)
1041 break;
1043 if ((exp = expand(cfiles)) != NULL)
1044 cfiles = exp;
1045 if ((fp = Fopen(cfiles, "r")) == NULL) {
1046 perror(cfiles);
1047 goto jerr;
1049 if ((tmp = PEM_read_X509(fp, NULL, ssl_password_cb, NULL)
1050 ) == NULL) {
1051 ssl_gen_err("Error reading certificate from \"%s\"",
1052 cfiles);
1053 Fclose(fp);
1054 goto jerr;
1056 sk_X509_push(*chain, tmp);
1057 Fclose(fp);
1059 if (! ncf)
1060 break;
1061 cfiles = ncf;
1064 if (sk_X509_num(*chain) == 0) {
1065 fprintf(stderr, "smime-sign-include-certs defined but empty\n");
1066 goto jerr;
1069 jleave: return (*chain != NULL);
1071 jerr: sk_X509_pop_free(*chain, X509_free);
1072 *chain = NULL;
1073 goto jleave;
1076 enum okay
1077 smime_certsave(struct message *m, int n, FILE *op)
1079 struct message *x;
1080 char *cp, *to, *cc, *cnttype;
1081 int c, i;
1082 FILE *fp, *ip;
1083 off_t size;
1084 BIO *fb, *pb;
1085 PKCS7 *pkcs7;
1086 #ifdef HAVE_STACK_OF
1087 STACK_OF(X509) *certs;
1088 STACK_OF(X509) *chain = NULL;
1089 #else
1090 STACK *certs;
1091 STACK *chain = NULL;
1092 #endif
1093 X509 *cert;
1094 enum okay ok = OKAY;
1096 message_number = n;
1097 loop: to = hfield("to", m);
1098 cc = hfield("cc", m);
1099 cnttype = hfield("content-type", m);
1100 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
1101 return STOP;
1102 if (cnttype && strncmp(cnttype, "application/x-pkcs7-mime", 24) == 0) {
1103 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
1104 return STOP;
1105 if (x != (struct message *)-1) {
1106 m = x;
1107 goto loop;
1110 size = m->m_size;
1111 if ((fp = Ftemp(&cp, "Rv", "w+", 0600, 1)) == NULL) {
1112 perror("tempfile");
1113 return STOP;
1115 rm(cp);
1116 Ftfree(&cp);
1117 while (size-- > 0) {
1118 c = getc(ip);
1119 putc(c, fp);
1121 fflush(fp);
1122 rewind(fp);
1123 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
1124 ssl_gen_err("Error creating BIO object for message %d", n);
1125 Fclose(fp);
1126 return STOP;
1128 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
1129 ssl_gen_err("Error reading PKCS#7 object for message %d", n);
1130 BIO_free(fb);
1131 Fclose(fp);
1132 return STOP;
1134 BIO_free(fb);
1135 Fclose(fp);
1136 certs = PKCS7_get0_signers(pkcs7, chain, 0);
1137 if (certs == NULL) {
1138 fprintf(stderr, "No certificates found in message %d.\n", n);
1139 return STOP;
1141 for (i = 0; i < sk_X509_num(certs); i++) {
1142 cert = sk_X509_value(certs, i);
1143 if (X509_print_fp(op, cert) == 0 ||
1144 PEM_write_X509(op, cert) == 0) {
1145 ssl_gen_err("Error writing certificate %d from "
1146 "message %d", i, n);
1147 ok = STOP;
1150 return ok;
1153 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1154 static enum okay
1155 load_crl1(X509_STORE *store, const char *name)
1157 X509_LOOKUP *lookup;
1159 if (verbose)
1160 printf("Loading CRL from \"%s\".\n", name);
1161 if ((lookup = X509_STORE_add_lookup(store,
1162 X509_LOOKUP_file())) == NULL) {
1163 ssl_gen_err("Error creating X509 lookup object");
1164 return STOP;
1166 if (X509_load_crl_file(lookup, name, X509_FILETYPE_PEM) != 1) {
1167 ssl_gen_err("Error loading CRL from \"%s\"", name);
1168 return STOP;
1170 return OKAY;
1172 #endif /* new OpenSSL */
1174 static enum okay
1175 load_crls(X509_STORE *store, const char *vfile, const char *vdir)
1177 char *crl_file, *crl_dir;
1178 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1179 DIR *dirfd;
1180 struct dirent *dp;
1181 char *fn = NULL;
1182 int fs = 0, ds, es;
1183 #endif /* new OpenSSL */
1185 if ((crl_file = value(vfile)) != NULL) {
1186 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1187 crl_file = expand(crl_file);
1188 if (load_crl1(store, crl_file) != OKAY)
1189 return STOP;
1190 #else /* old OpenSSL */
1191 fprintf(stderr,
1192 "This OpenSSL version is too old to use CRLs.\n");
1193 return STOP;
1194 #endif /* old OpenSSL */
1196 if ((crl_dir = value(vdir)) != NULL) {
1197 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1198 crl_dir = expand(crl_dir);
1199 ds = strlen(crl_dir);
1200 if ((dirfd = opendir(crl_dir)) == NULL) {
1201 perror(crl_dir);
1202 return STOP;
1204 fn = smalloc(fs = ds + 20);
1205 strcpy(fn, crl_dir);
1206 fn[ds] = '/';
1207 while ((dp = readdir(dirfd)) != NULL) {
1208 if (dp->d_name[0] == '.' &&
1209 (dp->d_name[1] == '\0' ||
1210 (dp->d_name[1] == '.' &&
1211 dp->d_name[2] == '\0')))
1212 continue;
1213 if (dp->d_name[0] == '.')
1214 continue;
1215 if (ds + (es = strlen(dp->d_name)) + 2 < fs)
1216 fn = srealloc(fn, fs = ds + es + 20);
1217 strcpy(&fn[ds+1], dp->d_name);
1218 if (load_crl1(store, fn) != OKAY) {
1219 closedir(dirfd);
1220 free(fn);
1221 return STOP;
1224 closedir(dirfd);
1225 free(fn);
1226 #else /* old OpenSSL */
1227 fprintf(stderr,
1228 "This OpenSSL version is too old to use CRLs.\n");
1229 return STOP;
1230 #endif /* old OpenSSL */
1232 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1233 if (crl_file || crl_dir)
1234 X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK |
1235 X509_V_FLAG_CRL_CHECK_ALL);
1236 #endif /* old OpenSSL */
1237 return OKAY;
1240 #else /* !USE_OPENSSL */
1242 #include <stdio.h>
1244 static void
1245 nosmime(void)
1247 fprintf(stderr, "No S/MIME support compiled in.\n");
1250 /*ARGSUSED*/
1251 FILE *
1252 smime_sign(FILE *fp)
1254 nosmime();
1255 return NULL;
1258 /*ARGSUSED*/
1259 int
1260 cverify(void *vp)
1262 nosmime();
1263 return 1;
1266 /*ARGSUSED*/
1267 FILE *
1268 smime_encrypt(FILE *fp, const char *certfile, const char *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 nosmime();
1279 return NULL;
1282 /*ARGSUSED*/
1283 int
1284 ccertsave(void *v)
1286 nosmime();
1287 return 1;
1289 #endif /* !USE_OPENSSL */
1290 #endif /* !USE_NSS */