mk-conf.sh, mk-mk.in: use variables for *all* utilities
[s-mailx.git] / openssl.c
blob2786fbc9363f84162e8a3aa105bf75e1f453670f
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 memcpy(keyvar, "ssl-key-", 8);
289 memcpy(keyvar + 8, uhp, i + 1);
290 if ((key = value(keyvar)) == NULL &&
291 (key = value("ssl-key")) == NULL)
292 key = cert;
293 else if ((x = key, key = file_expand(key)) == NULL) {
294 key = x;
295 goto jbkey;
297 if (SSL_CTX_use_PrivateKey_file(sp->s_ctx, key,
298 SSL_FILETYPE_PEM) != 1)
299 jbkey: fprintf(stderr, tr(238,
300 "cannot load private key from file "
301 "%s\n"), key);
302 ac_free(keyvar);
303 } else
304 jbcert: fprintf(stderr, tr(239,
305 "cannot load certificate from file %s\n"),
306 cert);
308 ac_free(certvar);
311 static enum okay
312 ssl_check_host(const char *server, struct sock *sp)
314 X509 *cert;
315 X509_NAME *subj;
316 char data[256];
317 #ifdef HAVE_STACK_OF
318 STACK_OF(GENERAL_NAME) *gens;
319 #else
320 /*GENERAL_NAMES*/STACK *gens;
321 #endif
322 GENERAL_NAME *gen;
323 int i;
325 if ((cert = SSL_get_peer_certificate(sp->s_ssl)) == NULL) {
326 fprintf(stderr, tr(248, "no certificate from \"%s\"\n"),
327 server);
328 return STOP;
330 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
331 if (gens != NULL) {
332 for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
333 gen = sk_GENERAL_NAME_value(gens, i);
334 if (gen->type == GEN_DNS) {
335 if (options & OPT_VERBOSE)
336 fprintf(stderr,
337 "Comparing DNS name: \"%s\"\n",
338 gen->d.ia5->data);
339 if (rfc2595_hostname_match(server,
340 (char *)gen->d.ia5->data)
341 == OKAY)
342 goto found;
346 if ((subj = X509_get_subject_name(cert)) != NULL &&
347 X509_NAME_get_text_by_NID(subj, NID_commonName,
348 data, sizeof data) > 0) {
349 data[sizeof data - 1] = 0;
350 if (options & OPT_VERBOSE)
351 fprintf(stderr, "Comparing common name: \"%s\"\n",
352 data);
353 if (rfc2595_hostname_match(server, data) == OKAY)
354 goto found;
356 X509_free(cert);
357 return STOP;
358 found: X509_free(cert);
359 return OKAY;
362 FL enum okay
363 ssl_open(const char *server, struct sock *sp, const char *uhp)
365 char *cp;
366 long opts;
368 ssl_init();
369 ssl_set_vrfy_level(uhp);
370 if ((sp->s_ctx =
371 SSL_CTX_new(UNCONST(ssl_select_method(uhp))))
372 == NULL) {
373 ssl_gen_err(tr(261, "SSL_CTX_new() failed"));
374 return STOP;
376 #ifdef SSL_MODE_AUTO_RETRY
377 /* available with OpenSSL 0.9.6 or later */
378 SSL_CTX_set_mode(sp->s_ctx, SSL_MODE_AUTO_RETRY);
379 #endif /* SSL_MODE_AUTO_RETRY */
380 opts = SSL_OP_ALL;
381 if (value("ssl-v2-allow") == NULL)
382 opts |= SSL_OP_NO_SSLv2;
383 SSL_CTX_set_options(sp->s_ctx, opts);
384 ssl_load_verifications(sp);
385 ssl_certificate(sp, uhp);
386 if ((cp = value("ssl-cipher-list")) != NULL) {
387 if (SSL_CTX_set_cipher_list(sp->s_ctx, cp) != 1)
388 fprintf(stderr, tr(240, "invalid ciphers: %s\n"), cp);
390 if ((sp->s_ssl = SSL_new(sp->s_ctx)) == NULL) {
391 ssl_gen_err(tr(262, "SSL_new() failed"));
392 return STOP;
394 SSL_set_fd(sp->s_ssl, sp->s_fd);
395 if (SSL_connect(sp->s_ssl) < 0) {
396 ssl_gen_err(tr(263, "could not initiate SSL/TLS connection"));
397 return STOP;
399 if (ssl_vrfy_level != VRFY_IGNORE) {
400 if (ssl_check_host(server, sp) != OKAY) {
401 fprintf(stderr, tr(249,
402 "host certificate does not match \"%s\"\n"),
403 server);
404 if (ssl_vrfy_decide() != OKAY)
405 return STOP;
408 sp->s_use_ssl = 1;
409 return OKAY;
412 FL void
413 ssl_gen_err(const char *fmt, ...)
415 va_list ap;
417 va_start(ap, fmt);
418 vfprintf(stderr, fmt, ap);
419 va_end(ap);
420 SSL_load_error_strings();
421 fprintf(stderr, ": %s\n",
422 (ERR_error_string(ERR_get_error(), NULL)));
425 FL FILE *
426 smime_sign(FILE *ip, struct header *headp)
428 FILE *sp, *fp, *bp, *hp;
429 char *cp;
430 char const *addr;
431 X509 *cert;
432 #ifdef HAVE_STACK_OF
433 STACK_OF(X509) *chain = NULL;
434 #else
435 STACK *chain = NULL;
436 #endif
437 PKCS7 *pkcs7;
438 EVP_PKEY *pkey;
439 BIO *bb, *sb;
441 ssl_init();
442 if ((addr = myorigin(headp)) == NULL) {
443 fprintf(stderr, "No \"from\" address for signing specified\n");
444 return NULL;
446 if ((fp = smime_sign_cert(addr, NULL, 1)) == NULL)
447 return NULL;
448 if ((pkey = PEM_read_PrivateKey(fp, NULL, ssl_password_cb, NULL))
449 == NULL) {
450 ssl_gen_err("Error reading private key from");
451 Fclose(fp);
452 return NULL;
454 rewind(fp);
455 if ((cert = PEM_read_X509(fp, NULL, ssl_password_cb, NULL)) == NULL) {
456 ssl_gen_err("Error reading signer certificate from");
457 Fclose(fp);
458 EVP_PKEY_free(pkey);
459 return NULL;
461 Fclose(fp);
462 if ((cp = smime_sign_include_certs(addr)) != NULL &&
463 !smime_sign_include_chain_creat(&chain, cp)) {
464 X509_free(cert);
465 EVP_PKEY_free(pkey);
466 return NULL;
468 if ((sp = Ftemp(&cp, "Rs", "w+", 0600, 1)) == NULL) {
469 perror("tempfile");
470 if (chain != NULL)
471 sk_X509_pop_free(chain, X509_free);
472 X509_free(cert);
473 EVP_PKEY_free(pkey);
474 return NULL;
476 rm(cp);
477 Ftfree(&cp);
478 rewind(ip);
479 if (smime_split(ip, &hp, &bp, -1, 0) == STOP) {
480 Fclose(sp);
481 if (chain != NULL)
482 sk_X509_pop_free(chain, X509_free);
483 X509_free(cert);
484 EVP_PKEY_free(pkey);
485 return NULL;
487 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
488 (sb = BIO_new_fp(sp, BIO_NOCLOSE)) == NULL) {
489 ssl_gen_err("Error creating BIO signing objects");
490 Fclose(sp);
491 if (chain != NULL)
492 sk_X509_pop_free(chain, X509_free);
493 X509_free(cert);
494 EVP_PKEY_free(pkey);
495 return NULL;
497 if ((pkcs7 = PKCS7_sign(cert, pkey, chain, bb,
498 PKCS7_DETACHED)) == NULL) {
499 ssl_gen_err("Error creating the PKCS#7 signing object");
500 BIO_free(bb);
501 BIO_free(sb);
502 Fclose(sp);
503 if (chain != NULL)
504 sk_X509_pop_free(chain, X509_free);
505 X509_free(cert);
506 EVP_PKEY_free(pkey);
507 return NULL;
509 if (PEM_write_bio_PKCS7(sb, pkcs7) == 0) {
510 ssl_gen_err("Error writing signed S/MIME data");
511 BIO_free(bb);
512 BIO_free(sb);
513 Fclose(sp);
514 if (chain != NULL)
515 sk_X509_pop_free(chain, X509_free);
516 X509_free(cert);
517 EVP_PKEY_free(pkey);
518 return NULL;
520 BIO_free(bb);
521 BIO_free(sb);
522 if (chain != NULL)
523 sk_X509_pop_free(chain, X509_free);
524 X509_free(cert);
525 EVP_PKEY_free(pkey);
526 rewind(bp);
527 fflush(sp);
528 rewind(sp);
529 return smime_sign_assemble(hp, bp, sp);
532 static int
533 #ifdef HAVE_STACK_OF
534 smime_verify(struct message *m, int n, STACK_OF(X509) *chain, X509_STORE *store)
535 #else
536 smime_verify(struct message *m, int n, STACK *chain, X509_STORE *store)
537 #endif
539 struct message *x;
540 char *cp, *sender, *to, *cc, *cnttype;
541 int c, i, j;
542 FILE *fp, *ip;
543 off_t size;
544 BIO *fb, *pb;
545 PKCS7 *pkcs7;
546 #ifdef HAVE_STACK_OF
547 STACK_OF(X509) *certs;
548 STACK_OF(GENERAL_NAME) *gens;
549 #else
550 STACK *certs, *gens;
551 #endif
552 X509 *cert;
553 X509_NAME *subj;
554 char data[LINESIZE];
555 GENERAL_NAME *gen;
557 verify_error_found = 0;
558 message_number = n;
559 loop: sender = getsender(m);
560 to = hfield1("to", m);
561 cc = hfield1("cc", m);
562 cnttype = hfield1("content-type", m);
563 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
564 return 1;
565 if (cnttype && strncmp(cnttype, "application/x-pkcs7-mime", 24) == 0) {
566 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
567 return 1;
568 if (x != (struct message *)-1) {
569 m = x;
570 goto loop;
573 size = m->m_size;
574 if ((fp = Ftemp(&cp, "Rv", "w+", 0600, 1)) == NULL) {
575 perror("tempfile");
576 return 1;
578 rm(cp);
579 Ftfree(&cp);
580 while (size-- > 0) {
581 c = getc(ip);
582 putc(c, fp);
584 fflush(fp);
585 rewind(fp);
586 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
587 ssl_gen_err("Error creating BIO verification object "
588 "for message %d", n);
589 Fclose(fp);
590 return 1;
592 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
593 ssl_gen_err("Error reading PKCS#7 object for message %d", n);
594 BIO_free(fb);
595 Fclose(fp);
596 return 1;
598 if (PKCS7_verify(pkcs7, chain, store, pb, NULL, 0) != 1) {
599 ssl_gen_err("Error verifying message %d", n);
600 BIO_free(fb);
601 Fclose(fp);
602 return 1;
604 BIO_free(fb);
605 Fclose(fp);
606 if (sender == NULL) {
607 fprintf(stderr,
608 "Warning: Message %d has no sender.\n", n);
609 return 0;
611 certs = PKCS7_get0_signers(pkcs7, chain, 0);
612 if (certs == NULL) {
613 fprintf(stderr, "No certificates found in message %d.\n", n);
614 return 1;
616 for (i = 0; i < sk_X509_num(certs); i++) {
617 cert = sk_X509_value(certs, i);
618 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
619 if (gens != NULL) {
620 for (j = 0; j < sk_GENERAL_NAME_num(gens); j++) {
621 gen = sk_GENERAL_NAME_value(gens, j);
622 if (gen->type == GEN_EMAIL) {
623 if (options & OPT_VERBOSE)
624 fprintf(stderr,
625 "Comparing alt. "
626 "address: %s\"\n",
627 data);
628 if (!asccasecmp((char *)
629 gen->d.ia5->data,
630 sender))
631 goto found;
635 if ((subj = X509_get_subject_name(cert)) != NULL &&
636 X509_NAME_get_text_by_NID(subj,
637 NID_pkcs9_emailAddress,
638 data, sizeof data) > 0) {
639 data[sizeof data - 1] = 0;
640 if (options & OPT_VERBOSE)
641 fprintf(stderr, "Comparing address: \"%s\"\n",
642 data);
643 if (asccasecmp(data, sender) == 0)
644 goto found;
647 fprintf(stderr, "Message %d: certificate does not match <%s>\n",
648 n, sender);
649 return 1;
650 found: if (verify_error_found == 0)
651 printf("Message %d was verified successfully.\n", n);
652 return verify_error_found;
655 FL int
656 cverify(void *vp)
658 int *msgvec = vp, *ip;
659 int ec = 0;
660 #ifdef HAVE_STACK_OF
661 STACK_OF(X509) *chain = NULL;
662 #else
663 STACK *chain = NULL;
664 #endif
665 X509_STORE *store;
666 char *ca_dir, *ca_file;
668 ssl_init();
669 ssl_vrfy_level = VRFY_STRICT;
670 if ((store = X509_STORE_new()) == NULL) {
671 ssl_gen_err("Error creating X509 store");
672 return 1;
674 X509_STORE_set_verify_cb_func(store, ssl_verify_cb);
675 if ((ca_dir = value("smime-ca-dir")) != NULL)
676 ca_dir = file_expand(ca_dir);
677 if ((ca_file = value("smime-ca-file")) != NULL)
678 ca_file = file_expand(ca_file);
679 if (ca_dir != NULL || ca_file != NULL) {
680 if (X509_STORE_load_locations(store, ca_file, ca_dir) != 1) {
681 ssl_gen_err("Error loading %s",
682 ca_file ? ca_file : ca_dir);
683 return 1;
686 if (value("smime-no-default-ca") == NULL) {
687 if (X509_STORE_set_default_paths(store) != 1) {
688 ssl_gen_err("Error loading default CA locations");
689 return 1;
692 if (load_crls(store, "smime-crl-file", "smime-crl-dir") != OKAY)
693 return 1;
694 for (ip = msgvec; *ip; ip++) {
695 setdot(&message[*ip-1]);
696 ec |= smime_verify(&message[*ip-1], *ip, chain, store);
698 return ec;
701 static EVP_CIPHER *
702 smime_cipher(const char *name)
704 const EVP_CIPHER *cipher;
705 char *vn, *cp;
706 int vs;
708 vn = ac_alloc(vs = strlen(name) + 30);
709 snprintf(vn, vs, "smime-cipher-%s", name);
710 if ((cp = value(vn)) != NULL) {
711 if (strcmp(cp, "rc2-40") == 0)
712 cipher = EVP_rc2_40_cbc();
713 else if (strcmp(cp, "rc2-64") == 0)
714 cipher = EVP_rc2_64_cbc();
715 else if (strcmp(cp, "des") == 0)
716 cipher = EVP_des_cbc();
717 else if (strcmp(cp, "des-ede3") == 0)
718 cipher = EVP_des_ede3_cbc();
719 else {
720 fprintf(stderr, "Invalid cipher \"%s\".\n", cp);
721 cipher = NULL;
723 } else
724 cipher = EVP_des_ede3_cbc();
725 ac_free(vn);
726 return UNCONST(cipher);
729 FL FILE *
730 smime_encrypt(FILE *ip, const char *xcertfile, const char *to)
732 char *certfile = UNCONST(xcertfile), *cp;
733 FILE *yp, *fp, *bp, *hp;
734 X509 *cert;
735 PKCS7 *pkcs7;
736 BIO *bb, *yb;
737 #ifdef HAVE_STACK_OF
738 STACK_OF(X509) *certs;
739 #else
740 STACK *certs;
741 #endif
742 EVP_CIPHER *cipher;
744 if ((certfile = file_expand(certfile)) == NULL)
745 return NULL;
747 ssl_init();
748 if ((cipher = smime_cipher(to)) == NULL)
749 return NULL;
750 if ((fp = Fopen(certfile, "r")) == NULL) {
751 perror(certfile);
752 return NULL;
754 if ((cert = PEM_read_X509(fp, NULL, ssl_password_cb, NULL)) == NULL) {
755 ssl_gen_err("Error reading encryption certificate from \"%s\"",
756 certfile);
757 Fclose(fp);
758 return NULL;
760 Fclose(fp);
761 certs = sk_X509_new_null();
762 sk_X509_push(certs, cert);
763 if ((yp = Ftemp(&cp, "Ry", "w+", 0600, 1)) == NULL) {
764 perror("tempfile");
765 return NULL;
767 rm(cp);
768 Ftfree(&cp);
769 rewind(ip);
770 if (smime_split(ip, &hp, &bp, -1, 0) == STOP) {
771 Fclose(yp);
772 return NULL;
774 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
775 (yb = BIO_new_fp(yp, BIO_NOCLOSE)) == NULL) {
776 ssl_gen_err("Error creating BIO encryption objects");
777 Fclose(yp);
778 return NULL;
780 if ((pkcs7 = PKCS7_encrypt(certs, bb, cipher, 0)) == NULL) {
781 ssl_gen_err("Error creating the PKCS#7 encryption object");
782 BIO_free(bb);
783 BIO_free(yb);
784 Fclose(yp);
785 return NULL;
787 if (PEM_write_bio_PKCS7(yb, pkcs7) == 0) {
788 ssl_gen_err("Error writing encrypted S/MIME data");
789 BIO_free(bb);
790 BIO_free(yb);
791 Fclose(yp);
792 return NULL;
794 BIO_free(bb);
795 BIO_free(yb);
796 Fclose(bp);
797 fflush(yp);
798 rewind(yp);
799 return smime_encrypt_assemble(hp, yp);
802 FL struct message *
803 smime_decrypt(struct message *m, const char *to, const char *cc, int signcall)
805 FILE *fp, *bp, *hp, *op;
806 char *cp;
807 X509 *cert = NULL;
808 PKCS7 *pkcs7;
809 EVP_PKEY *pkey = NULL;
810 BIO *bb, *pb, *ob;
811 long size = m->m_size;
812 FILE *yp;
814 if ((yp = setinput(&mb, m, NEED_BODY)) == NULL)
815 return NULL;
816 ssl_init();
817 if ((fp = smime_sign_cert(to, cc, 0)) != NULL) {
818 if ((pkey = PEM_read_PrivateKey(fp, NULL, ssl_password_cb,
819 NULL)) == NULL) {
820 ssl_gen_err("Error reading private key");
821 Fclose(fp);
822 return NULL;
824 rewind(fp);
825 if ((cert = PEM_read_X509(fp, NULL, ssl_password_cb,
826 NULL)) == NULL) {
827 ssl_gen_err("Error reading decryption certificate");
828 Fclose(fp);
829 EVP_PKEY_free(pkey);
830 return NULL;
832 Fclose(fp);
834 if ((op = Ftemp(&cp, "Rp", "w+", 0600, 1)) == NULL) {
835 perror("tempfile");
836 if (cert)
837 X509_free(cert);
838 if (pkey)
839 EVP_PKEY_free(pkey);
840 return NULL;
842 rm(cp);
843 Ftfree(&cp);
844 if (smime_split(yp, &hp, &bp, size, 1) == STOP) {
845 Fclose(op);
846 if (cert)
847 X509_free(cert);
848 if (pkey)
849 EVP_PKEY_free(pkey);
850 return NULL;
852 if ((ob = BIO_new_fp(op, BIO_NOCLOSE)) == NULL ||
853 (bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL) {
854 ssl_gen_err("Error creating BIO decryption objects");
855 Fclose(op);
856 if (cert)
857 X509_free(cert);
858 if (pkey)
859 EVP_PKEY_free(pkey);
860 return NULL;
862 if ((pkcs7 = SMIME_read_PKCS7(bb, &pb)) == NULL) {
863 ssl_gen_err("Error reading PKCS#7 object");
864 Fclose(op);
865 if (cert)
866 X509_free(cert);
867 if (pkey)
868 EVP_PKEY_free(pkey);
869 return NULL;
871 if (PKCS7_type_is_signed(pkcs7)) {
872 if (signcall) {
873 BIO_free(bb);
874 BIO_free(ob);
875 if (cert)
876 X509_free(cert);
877 if (pkey)
878 EVP_PKEY_free(pkey);
879 Fclose(op);
880 Fclose(bp);
881 Fclose(hp);
882 setinput(&mb, m, NEED_BODY);
883 return (struct message *)-1;
885 if (PKCS7_verify(pkcs7, NULL, NULL, NULL, ob,
886 PKCS7_NOVERIFY|PKCS7_NOSIGS) != 1)
887 goto err;
888 fseek(hp, 0L, SEEK_END);
889 fprintf(hp, "X-Encryption-Cipher: none\n");
890 fflush(hp);
891 rewind(hp);
892 } else if (pkey == NULL) {
893 fprintf(stderr, "No appropriate private key found.\n");
894 goto err2;
895 } else if (cert == NULL) {
896 fprintf(stderr, "No appropriate certificate found.\n");
897 goto err2;
898 } else if (PKCS7_decrypt(pkcs7, pkey, cert, ob, 0) != 1) {
899 err: ssl_gen_err("Error decrypting PKCS#7 object");
900 err2: BIO_free(bb);
901 BIO_free(ob);
902 Fclose(op);
903 Fclose(bp);
904 Fclose(hp);
905 if (cert)
906 X509_free(cert);
907 if (pkey)
908 EVP_PKEY_free(pkey);
909 return NULL;
911 BIO_free(bb);
912 BIO_free(ob);
913 if (cert)
914 X509_free(cert);
915 if (pkey)
916 EVP_PKEY_free(pkey);
917 fflush(op);
918 rewind(op);
919 Fclose(bp);
920 return smime_decrypt_assemble(m, hp, op);
923 /*ARGSUSED4*/
924 static int
925 ssl_password_cb(char *buf, int size, int rwflag, void *userdata)
927 sighandler_type volatile saveint;
928 char *pass = NULL;
929 size_t len;
930 UNUSED(rwflag);
931 UNUSED(userdata);
933 saveint = safe_signal(SIGINT, SIG_IGN);
934 if (sigsetjmp(ssljmp, 1) == 0) {
935 if (saveint != SIG_IGN)
936 safe_signal(SIGINT, sslcatch);
937 pass = getpassword("PEM pass phrase:");
939 safe_signal(SIGINT, saveint);
940 if (pass == NULL)
941 return 0;
942 len = strlen(pass);
943 if (UICMP(z, len, >, size))
944 len = size;
945 memcpy(buf, pass, len);
946 return len;
949 static FILE *
950 smime_sign_cert(const char *xname, const char *xname2, bool_t dowarn)
952 char *vn, *cp;
953 int vs;
954 FILE *fp;
955 struct name *np;
956 const char *name = xname, *name2 = xname2;
958 loop: if (name) {
959 np = lextract(name, GTO|GSKIN);
960 while (np) {
962 * This needs to be more intelligent since it will
963 * currently take the first name for which a private
964 * key is available regardless of whether it is the
965 * right one for the message.
967 vn = ac_alloc(vs = strlen(np->n_name) + 30);
968 snprintf(vn, vs, "smime-sign-cert-%s", np->n_name);
969 cp = value(vn);
970 ac_free(vn);
971 if (cp != 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 (dowarn) {
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:
991 if ((cp = file_expand(cp)) == NULL)
992 return (NULL);
993 if ((fp = Fopen(cp, "r")) == NULL) {
994 perror(cp);
995 return NULL;
997 return fp;
1000 static char *
1001 smime_sign_include_certs(char const *name)
1003 char *ret;
1004 /* See comments in smime_sign_cert() for algorithm pitfalls */
1005 if (name) {
1006 struct name *np = lextract(name, GTO|GSKIN);
1007 while (np) {
1008 int vs;
1009 char *vn = ac_alloc(vs = strlen(np->n_name) + 30);
1010 snprintf(vn, vs, "smime-sign-include-certs-%s",
1011 np->n_name);
1012 ret = value(vn);
1013 ac_free(vn);
1014 if (ret != NULL)
1015 return ret;
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 *x, *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 ((x = file_expand(cfiles)) == NULL ||
1044 (fp = Fopen(cfiles = x, "r")) == NULL) {
1045 perror(cfiles);
1046 goto jerr;
1048 if ((tmp = PEM_read_X509(fp, NULL, ssl_password_cb, NULL)
1049 ) == NULL) {
1050 ssl_gen_err("Error reading certificate from \"%s\"",
1051 cfiles);
1052 Fclose(fp);
1053 goto jerr;
1055 sk_X509_push(*chain, tmp);
1056 Fclose(fp);
1058 if (! ncf)
1059 break;
1060 cfiles = ncf;
1063 if (sk_X509_num(*chain) == 0) {
1064 fprintf(stderr, "smime-sign-include-certs defined but empty\n");
1065 goto jerr;
1068 jleave: return (*chain != NULL);
1070 jerr: sk_X509_pop_free(*chain, X509_free);
1071 *chain = NULL;
1072 goto jleave;
1075 FL enum okay
1076 smime_certsave(struct message *m, int n, FILE *op)
1078 struct message *x;
1079 char *cp, *to, *cc, *cnttype;
1080 int c, i;
1081 FILE *fp, *ip;
1082 off_t size;
1083 BIO *fb, *pb;
1084 PKCS7 *pkcs7;
1085 #ifdef HAVE_STACK_OF
1086 STACK_OF(X509) *certs;
1087 STACK_OF(X509) *chain = NULL;
1088 #else
1089 STACK *certs;
1090 STACK *chain = NULL;
1091 #endif
1092 X509 *cert;
1093 enum okay ok = OKAY;
1095 message_number = n;
1096 loop: to = hfield1("to", m);
1097 cc = hfield1("cc", m);
1098 cnttype = hfield1("content-type", m);
1099 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
1100 return STOP;
1101 if (cnttype && strncmp(cnttype, "application/x-pkcs7-mime", 24) == 0) {
1102 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
1103 return STOP;
1104 if (x != (struct message *)-1) {
1105 m = x;
1106 goto loop;
1109 size = m->m_size;
1110 if ((fp = Ftemp(&cp, "Rv", "w+", 0600, 1)) == NULL) {
1111 perror("tempfile");
1112 return STOP;
1114 rm(cp);
1115 Ftfree(&cp);
1116 while (size-- > 0) {
1117 c = getc(ip);
1118 putc(c, fp);
1120 fflush(fp);
1121 rewind(fp);
1122 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
1123 ssl_gen_err("Error creating BIO object for message %d", n);
1124 Fclose(fp);
1125 return STOP;
1127 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
1128 ssl_gen_err("Error reading PKCS#7 object for message %d", n);
1129 BIO_free(fb);
1130 Fclose(fp);
1131 return STOP;
1133 BIO_free(fb);
1134 Fclose(fp);
1135 certs = PKCS7_get0_signers(pkcs7, chain, 0);
1136 if (certs == NULL) {
1137 fprintf(stderr, "No certificates found in message %d.\n", n);
1138 return STOP;
1140 for (i = 0; i < sk_X509_num(certs); i++) {
1141 cert = sk_X509_value(certs, i);
1142 if (X509_print_fp(op, cert) == 0 ||
1143 PEM_write_X509(op, cert) == 0) {
1144 ssl_gen_err("Error writing certificate %d from "
1145 "message %d", i, n);
1146 ok = STOP;
1149 return ok;
1152 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1153 static enum okay
1154 load_crl1(X509_STORE *store, const char *name)
1156 X509_LOOKUP *lookup;
1158 if (options & OPT_VERBOSE)
1159 printf("Loading CRL from \"%s\".\n", name);
1160 if ((lookup = X509_STORE_add_lookup(store,
1161 X509_LOOKUP_file())) == NULL) {
1162 ssl_gen_err("Error creating X509 lookup object");
1163 return STOP;
1165 if (X509_load_crl_file(lookup, name, X509_FILETYPE_PEM) != 1) {
1166 ssl_gen_err("Error loading CRL from \"%s\"", name);
1167 return STOP;
1169 return OKAY;
1171 #endif /* new OpenSSL */
1173 static enum okay
1174 load_crls(X509_STORE *store, const char *vfile, const char *vdir)
1176 char *crl_file, *crl_dir;
1177 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1178 DIR *dirp;
1179 struct dirent *dp;
1180 char *fn = NULL;
1181 int fs = 0, ds, es;
1182 #endif /* new OpenSSL */
1184 if ((crl_file = value(vfile)) != NULL) {
1185 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1186 if ((crl_file = file_expand(crl_file)) == NULL ||
1187 load_crl1(store, crl_file) != OKAY)
1188 return STOP;
1189 #else /* old OpenSSL */
1190 fprintf(stderr,
1191 "This OpenSSL version is too old to use CRLs.\n");
1192 return STOP;
1193 #endif /* old OpenSSL */
1195 if ((crl_dir = value(vdir)) != NULL) {
1196 #if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
1197 char *x;
1198 if ((x = file_expand(crl_dir)) == NULL ||
1199 (dirp = opendir(crl_dir = x)) == NULL) {
1200 perror(crl_dir);
1201 return STOP;
1203 ds = strlen(crl_dir);
1204 fn = smalloc(fs = ds + 20);
1205 memcpy(fn, crl_dir, ds);
1206 fn[ds] = '/';
1207 while ((dp = readdir(dirp)) != 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 memcpy(fn + ds + 1, dp->d_name, es + 1);
1218 if (load_crl1(store, fn) != OKAY) {
1219 closedir(dirp);
1220 free(fn);
1221 return STOP;
1224 closedir(dirp);
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;
1239 #endif /* HAVE_OPENSSL */