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