Review: auxlily.c
[s-mailx.git] / openssl.c
blobd7e8c3c573fec7dec92a62b9b7be798df8be328e
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 - 2014 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 #ifdef HAVE_STACK_OF
71 # define _STACKOF(X) STACK_OF(X)
72 #else
73 # define _STACKOF(X) /*X*/STACK
74 #endif
76 struct ssl_method {
77 char const sm_name[8];
78 SSL_METHOD const * (*sm_fun)(void);
81 struct smime_cipher {
82 char const sc_name[8];
83 EVP_CIPHER const * (*sc_fun)(void);
86 /* Supported SSL/TLS methods: update manual on change! */
87 static struct ssl_method const _ssl_methods[] = {
88 {"auto", &SSLv23_client_method},
89 #define _SSL_DEFAULT_METHOD SSLv23_client_method
90 #ifndef OPENSSL_NO_TLS1
91 # ifdef TLS1_2_VERSION
92 {"tls1.2", &TLSv1_2_client_method},
93 # endif
94 # ifdef TLS1_1_VERSION
95 {"tls1.1", &TLSv1_1_client_method},
96 # endif
97 {"tls1", &TLSv1_client_method},
98 #endif
99 #ifndef OPENSSL_NO_SSL3
100 {"ssl3", &SSLv3_client_method},
101 #endif
102 #ifndef OPENSSL_NO_SSL2
103 {"ssl2", &SSLv2_client_method}
104 #endif
107 /* Supported S/MIME cipher algorithms: update manual on change! */
108 static struct smime_cipher const _smime_ciphers[] = {
109 #ifndef OPENSSL_NO_AES
110 # define _SMIME_DEFAULT_CIPHER EVP_aes_128_cbc /* According to RFC 5751 */
111 {"aes-128", &EVP_aes_128_cbc},
112 {"aes-256", &EVP_aes_256_cbc},
113 {"aes-192", &EVP_aes_192_cbc},
114 #endif
115 #ifndef OPENSSL_NO_DES
116 # ifndef _SMIME_DEFAULT_CIPHER
117 # define _SMIME_DEFAULT_CIPHER EVP_des_ede3_cbc
118 # endif
119 {"des3", &EVP_des_ede3_cbc},
120 {"des", &EVP_des_cbc},
121 #endif
122 #ifndef OPENSSL_NO_RC2
123 {"rc2-40", &EVP_rc2_40_cbc},
124 {"rc2-64", &EVP_rc2_64_cbc},
125 #endif
127 #ifndef _SMIME_DEFAULT_CIPHER
128 # error Your OpenSSL library does not include the necessary
129 # error cipher algorithms that are required to support S/MIME
130 #endif
132 static sigjmp_buf ssljmp;
133 static int initialized;
134 static int rand_init;
135 static int message_number;
136 static int verify_error_found;
138 static void sslcatch(int s);
139 static int ssl_rand_init(void);
140 static void ssl_init(void);
141 static int ssl_verify_cb(int success, X509_STORE_CTX *store);
142 static const SSL_METHOD *ssl_select_method(char const *uhp);
143 static void ssl_load_verifications(struct sock *sp);
144 static void ssl_certificate(struct sock *sp, char const *uhp);
145 static enum okay ssl_check_host(char const *server, struct sock *sp);
146 static int smime_verify(struct message *m, int n, _STACKOF(X509) *chain,
147 X509_STORE *store);
148 static EVP_CIPHER const * _smime_cipher(char const *name);
149 static int ssl_password_cb(char *buf, int size, int rwflag,
150 void *userdata);
151 static FILE * smime_sign_cert(char const *xname, char const *xname2,
152 bool_t dowarn);
153 static char * smime_sign_include_certs(char const *name);
154 static int smime_sign_include_chain_creat(_STACKOF(X509) **chain,
155 char const *cfiles);
156 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
157 static enum okay load_crl1(X509_STORE *store, char const *name);
158 #endif
159 static enum okay load_crls(X509_STORE *store, enum okeys fok, enum okeys dok);
161 static void
162 sslcatch(int s)
164 NYD_X; /* Signal handler */
165 termios_state_reset();
166 siglongjmp(ssljmp, s);
169 static int
170 ssl_rand_init(void)
172 char *cp, *x;
173 int state = 0;
174 NYD_ENTER;
176 if ((cp = ok_vlook(ssl_rand_egd)) != NULL) {
177 if ((x = file_expand(cp)) == NULL || RAND_egd(cp = x) == -1)
178 fprintf(stderr, tr(245, "entropy daemon at \"%s\" not available\n"),
179 cp);
180 else
181 state = 1;
182 } else if ((cp = ok_vlook(ssl_rand_file)) != NULL) {
183 if ((x = file_expand(cp)) == NULL || RAND_load_file(cp = x, 1024) == -1)
184 fprintf(stderr, tr(246, "entropy file at \"%s\" not available\n"), cp);
185 else {
186 struct stat st;
188 if (stat(cp, &st) == 0 && S_ISREG(st.st_mode) && !access(cp, W_OK)) {
189 if (RAND_write_file(cp) == -1) {
190 fprintf(stderr, tr(247,
191 "writing entropy data to \"%s\" failed\n"), cp);
194 state = 1;
197 NYD_LEAVE;
198 return state;
201 static void
202 ssl_init(void)
204 NYD_ENTER;
205 if (initialized == 0) {
206 SSL_library_init();
207 initialized = 1;
209 if (rand_init == 0)
210 rand_init = ssl_rand_init();
211 NYD_LEAVE;
214 static int
215 ssl_verify_cb(int success, X509_STORE_CTX *store)
217 int rv = TRU1;
218 NYD_ENTER;
220 if (success == 0) {
221 char data[256];
222 X509 *cert = X509_STORE_CTX_get_current_cert(store);
223 int depth = X509_STORE_CTX_get_error_depth(store);
224 int err = X509_STORE_CTX_get_error(store);
226 verify_error_found = 1;
227 if (message_number)
228 fprintf(stderr, "Message %d: ", message_number);
229 fprintf(stderr, tr(229, "Error with certificate at depth: %i\n"), depth);
230 X509_NAME_oneline(X509_get_issuer_name(cert), data, sizeof data);
231 fprintf(stderr, tr(230, " issuer = %s\n"), data);
232 X509_NAME_oneline(X509_get_subject_name(cert), data, sizeof data);
233 fprintf(stderr, tr(231, " subject = %s\n"), data);
234 fprintf(stderr, tr(232, " err %i: %s\n"),
235 err, X509_verify_cert_error_string(err));
236 if (ssl_verify_decide() != OKAY)
237 rv = FAL0;
239 NYD_LEAVE;
240 return rv;
243 static SSL_METHOD const *
244 ssl_select_method(char const *uhp)
246 SSL_METHOD const *method;
247 char *cp;
248 size_t i;
249 NYD_ENTER;
251 if ((cp = ssl_method_string(uhp)) != NULL) {
252 method = NULL;
253 for (i = 0; i < NELEM(_ssl_methods); ++i)
254 if (!strcmp(_ssl_methods[i].sm_name, cp)) {
255 method = (*_ssl_methods[i].sm_fun)();
256 goto jleave;
258 fprintf(stderr, tr(244, "Invalid SSL method \"%s\"\n"), cp);
260 method = _SSL_DEFAULT_METHOD();
261 jleave:
262 NYD_LEAVE;
263 return method;
266 static void
267 ssl_load_verifications(struct sock *sp)
269 char *ca_dir, *ca_file;
270 X509_STORE *store;
271 NYD_ENTER;
273 if (ssl_verify_level == SSL_VERIFY_IGNORE)
274 goto jleave;
276 if ((ca_dir = ok_vlook(ssl_ca_dir)) != NULL)
277 ca_dir = file_expand(ca_dir);
278 if ((ca_file = ok_vlook(ssl_ca_file)) != NULL)
279 ca_file = file_expand(ca_file);
281 if (ca_dir != NULL || ca_file != NULL) {
282 if (SSL_CTX_load_verify_locations(sp->s_ctx, ca_file, ca_dir) != 1) {
283 fprintf(stderr, tr(233, "Error loading "));
284 if (ca_dir) {
285 fputs(ca_dir, stderr);
286 if (ca_file)
287 fputs(tr(234, " or "), stderr);
289 if (ca_file)
290 fputs(ca_file, stderr);
291 fputs("\n", stderr);
295 if (!ok_blook(ssl_no_default_ca)) {
296 if (SSL_CTX_set_default_verify_paths(sp->s_ctx) != 1)
297 fprintf(stderr, tr(243, "Error loading default CA locations\n"));
300 verify_error_found = 0;
301 message_number = 0;
302 SSL_CTX_set_verify(sp->s_ctx, SSL_VERIFY_PEER, ssl_verify_cb);
303 store = SSL_CTX_get_cert_store(sp->s_ctx);
304 load_crls(store, ok_v_ssl_crl_file, ok_v_ssl_crl_dir);
305 jleave:
306 NYD_LEAVE;
309 static void
310 ssl_certificate(struct sock *sp, char const *uhp)
312 size_t i;
313 char *certvar, *keyvar, *cert, *key, *x;
314 NYD_ENTER;
316 i = strlen(uhp);
317 certvar = ac_alloc(i + 9 + 1);
318 memcpy(certvar, "ssl-cert-", 9);
319 memcpy(certvar + 9, uhp, i + 1);
321 if ((cert = vok_vlook(certvar)) != NULL ||
322 (cert = ok_vlook(ssl_cert)) != NULL) {
323 x = cert;
324 if ((cert = file_expand(cert)) == NULL) {
325 cert = x;
326 goto jbcert;
327 } else if (SSL_CTX_use_certificate_chain_file(sp->s_ctx, cert) == 1) {
328 keyvar = ac_alloc(strlen(uhp) + 9);
329 memcpy(keyvar, "ssl-key-", 8);
330 memcpy(keyvar + 8, uhp, i + 1);
331 if ((key = vok_vlook(keyvar)) == NULL &&
332 (key = ok_vlook(ssl_key)) == NULL)
333 key = cert;
334 else if ((x = key, key = file_expand(key)) == NULL) {
335 key = x;
336 goto jbkey;
338 if (SSL_CTX_use_PrivateKey_file(sp->s_ctx, key, SSL_FILETYPE_PEM) != 1)
339 jbkey:
340 fprintf(stderr, tr(238, "cannot load private key from file %s\n"),
341 key);
342 ac_free(keyvar);
343 } else
344 jbcert:
345 fprintf(stderr, tr(239, "cannot load certificate from file %s\n"),
346 cert);
348 ac_free(certvar);
349 NYD_LEAVE;
352 static enum okay
353 ssl_check_host(char const *server, struct sock *sp)
355 char data[256];
356 X509 *cert;
357 X509_NAME *subj;
358 _STACKOF(GENERAL_NAME) *gens;
359 GENERAL_NAME *gen;
360 int i;
361 enum okay rv = STOP;
362 NYD_ENTER;
364 if ((cert = SSL_get_peer_certificate(sp->s_ssl)) == NULL) {
365 fprintf(stderr, tr(248, "no certificate from \"%s\"\n"), server);
366 goto jleave;
369 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
370 if (gens != NULL) {
371 for (i = 0; i < sk_GENERAL_NAME_num(gens); ++i) {
372 gen = sk_GENERAL_NAME_value(gens, i);
373 if (gen->type == GEN_DNS) {
374 if (options & OPT_VERBOSE)
375 fprintf(stderr, "Comparing DNS name: \"%s\"\n",
376 gen->d.ia5->data);
377 rv = rfc2595_hostname_match(server, (char*)gen->d.ia5->data);
378 if (rv == OKAY)
379 goto jdone;
384 if ((subj = X509_get_subject_name(cert)) != NULL &&
385 X509_NAME_get_text_by_NID(subj, NID_commonName, data, sizeof data)
386 > 0) {
387 data[sizeof data - 1] = '\0';
388 if (options & OPT_VERBOSE)
389 fprintf(stderr, "Comparing common name: \"%s\"\n", data);
390 rv = rfc2595_hostname_match(server, data);
392 jdone:
393 X509_free(cert);
394 jleave:
395 NYD_LEAVE;
396 return rv;
399 static int
400 smime_verify(struct message *m, int n, _STACKOF(X509) *chain,
401 X509_STORE *store)
403 char data[LINESIZE], *sender, *to, *cc, *cnttype;
404 int rv, c, i, j;
405 struct message *x;
406 FILE *fp, *ip;
407 off_t size;
408 BIO *fb, *pb;
409 PKCS7 *pkcs7;
410 _STACKOF(X509) *certs;
411 _STACKOF(GENERAL_NAME) *gens;
412 X509 *cert;
413 X509_NAME *subj;
414 GENERAL_NAME *gen;
415 NYD_ENTER;
417 rv = 1;
418 fp = NULL;
419 fb = NULL;
420 verify_error_found = 0;
421 message_number = n;
423 for (;;) {
424 sender = getsender(m);
425 to = hfield1("to", m);
426 cc = hfield1("cc", m);
427 cnttype = hfield1("content-type", m);
428 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
429 goto jleave;
430 if (cnttype && !strncmp(cnttype, "application/x-pkcs7-mime", 24)) {
431 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
432 goto jleave;
433 if (x != (struct message*)-1) {
434 m = x;
435 continue;
438 size = m->m_size;
439 break;
442 if ((fp = Ftmp(NULL, "smimever", OF_RDWR | OF_UNLINK | OF_REGISTER, 0600)) ==
443 NULL) {
444 perror("tempfile");
445 goto jleave;
447 while (size-- > 0) {
448 c = getc(ip);
449 putc(c, fp);
451 fflush_rewind(fp);
453 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
454 ssl_gen_err(tr(537,
455 "Error creating BIO verification object for message %d"), n);
456 goto jleave;
459 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
460 ssl_gen_err(tr(538, "Error reading PKCS#7 object for message %d"), n);
461 goto jleave;
463 if (PKCS7_verify(pkcs7, chain, store, pb, NULL, 0) != 1) {
464 ssl_gen_err(tr(539, "Error verifying message %d"), n);
465 goto jleave;
468 if (sender == NULL) {
469 fprintf(stderr, tr(540, "Warning: Message %d has no sender.\n"), n);
470 rv = 0;
471 goto jleave;
474 certs = PKCS7_get0_signers(pkcs7, chain, 0);
475 if (certs == NULL) {
476 fprintf(stderr, tr(541, "No certificates found in message %d.\n"), n);
477 goto jleave;
480 for (i = 0; i < sk_X509_num(certs); i++) {
481 cert = sk_X509_value(certs, i);
482 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
483 if (gens != NULL) {
484 for (j = 0; j < sk_GENERAL_NAME_num(gens); ++j) {
485 gen = sk_GENERAL_NAME_value(gens, j);
486 if (gen->type == GEN_EMAIL) {
487 if (options & OPT_VERBOSE)
488 fprintf(stderr, "Comparing alt. address: %s\"\n", data);
489 if (!asccasecmp((char*)gen->d.ia5->data, sender))
490 goto jfound;
495 if ((subj = X509_get_subject_name(cert)) != NULL &&
496 X509_NAME_get_text_by_NID(subj, NID_pkcs9_emailAddress,
497 data, sizeof data) > 0) {
498 data[sizeof data - 1] = 0;
499 if (options & OPT_VERBOSE)
500 fprintf(stderr, "Comparing address: \"%s\"\n", data);
501 if (!asccasecmp(data, sender))
502 goto jfound;
505 fprintf(stderr, tr(542, "Message %d: certificate does not match <%s>\n"),
506 n, sender);
507 goto jleave;
508 jfound:
509 if (verify_error_found == 0)
510 printf(tr(543, "Message %d was verified successfully.\n"), n);
511 rv = verify_error_found;
512 jleave:
513 if (fb != NULL)
514 BIO_free(fb);
515 if (fp != NULL)
516 Fclose(fp);
517 NYD_LEAVE;
518 return rv;
521 static EVP_CIPHER const *
522 _smime_cipher(char const *name)
524 EVP_CIPHER const *cipher;
525 char *vn, *cp;
526 size_t i;
527 NYD_ENTER;
529 vn = ac_alloc(i = strlen(name) + 13 +1);
530 snprintf(vn, (int)i, "smime-cipher-%s", name);
531 cp = vok_vlook(vn);
532 ac_free(vn);
534 if (cp != NULL) {
535 cipher = NULL;
536 for (i = 0; i < NELEM(_smime_ciphers); ++i)
537 if (!strcmp(_smime_ciphers[i].sc_name, cp)) {
538 cipher = (*_smime_ciphers[i].sc_fun)();
539 goto jleave;
541 fprintf(stderr, tr(240, "Invalid cipher(s): %s\n"), cp);
542 } else
543 cipher = _SMIME_DEFAULT_CIPHER();
544 jleave:
545 NYD_LEAVE;
546 return cipher;
549 static int
550 ssl_password_cb(char *buf, int size, int rwflag, void *userdata)
552 sighandler_type volatile saveint;
553 char *pass = NULL;
554 size_t len;
555 NYD_ENTER;
556 UNUSED(rwflag);
557 UNUSED(userdata);
559 saveint = safe_signal(SIGINT, SIG_IGN);
560 if (sigsetjmp(ssljmp, 1) == 0) {
561 if (saveint != SIG_IGN)
562 safe_signal(SIGINT, sslcatch);
563 pass = getpassword("PEM pass phrase:");
565 safe_signal(SIGINT, saveint);
567 if (pass == NULL) {
568 len = 0;
569 goto jleave;
571 len = strlen(pass);
572 if (UICMP(z, len, >, size))
573 len = size;
574 memcpy(buf, pass, len);
575 jleave:
576 NYD_LEAVE;
577 return (int)len;
580 static FILE *
581 smime_sign_cert(char const *xname, char const *xname2, bool_t dowarn)
583 char *vn, *cp;
584 int vs;
585 struct name *np;
586 char const *name = xname, *name2 = xname2;
587 FILE *fp = NULL;
588 NYD_ENTER;
590 jloop:
591 if (name) {
592 np = lextract(name, GTO|GSKIN);
593 while (np) {
594 /* This needs to be more intelligent since it will currently take the
595 * first name for which a private key is available regardless of
596 * whether it is the right one for the message */
597 vn = ac_alloc(vs = strlen(np->n_name) + 30);
598 snprintf(vn, vs, "smime-sign-cert-%s", np->n_name);
599 cp = vok_vlook(vn);
600 ac_free(vn);
601 if (cp != NULL)
602 goto jopen;
603 np = np->n_flink;
605 if (name2) {
606 name = name2;
607 name2 = NULL;
608 goto jloop;
612 if ((cp = ok_vlook(smime_sign_cert)) != NULL)
613 goto jopen;
614 if (dowarn) {
615 fprintf(stderr, tr(558, "Could not find a certificate for %s"), xname);
616 if (xname2)
617 fprintf(stderr, tr(559, "or %s"), xname2);
618 fputc('\n', stderr);
620 jleave:
621 NYD_LEAVE;
622 return fp;
623 jopen:
624 if ((cp = file_expand(cp)) == NULL)
625 goto jleave;
626 if ((fp = Fopen(cp, "r")) == NULL)
627 perror(cp);
628 goto jleave;
631 static char *
632 smime_sign_include_certs(char const *name)
634 char *rv;
635 NYD_ENTER;
637 /* See comments in smime_sign_cert() for algorithm pitfalls */
638 if (name != NULL) {
639 struct name *np;
641 for (np = lextract(name, GTO | GSKIN); np != NULL; np = np->n_flink) {
642 int vs;
643 char *vn = ac_alloc(vs = strlen(np->n_name) + 30);
644 snprintf(vn, vs, "smime-sign-include-certs-%s", np->n_name);
645 rv = vok_vlook(vn);
646 ac_free(vn);
647 if (rv != NULL)
648 goto jleave;
651 rv = ok_vlook(smime_sign_include_certs);
652 jleave:
653 NYD_LEAVE;
654 return rv;
657 static int
658 smime_sign_include_chain_creat(_STACKOF(X509) **chain, char const *cfiles)
660 X509 *tmp;
661 FILE *fp;
662 char *rest, *x, *ncf;
663 NYD_ENTER;
665 *chain = sk_X509_new_null();
667 for (rest = savestr(cfiles);;) {
668 ncf = strchr(rest, ',');
669 if (ncf != NULL)
670 *ncf++ = '\0';
671 /* This fails for '=,file' constructs, but those are sick */
672 if (*rest == '\0')
673 break;
675 if ((x = file_expand(rest)) == NULL ||
676 (fp = Fopen(rest = x, "r")) == NULL) {
677 perror(cfiles);
678 goto jerr;
680 if ((tmp = PEM_read_X509(fp, NULL, ssl_password_cb, NULL)) == NULL) {
681 ssl_gen_err(tr(560, "Error reading certificate from \"%s\""), rest);
682 Fclose(fp);
683 goto jerr;
685 sk_X509_push(*chain, tmp);
686 Fclose(fp);
688 if (ncf == NULL)
689 break;
690 rest = ncf;
693 if (sk_X509_num(*chain) == 0) {
694 fprintf(stderr, tr(561, "smime-sign-include-certs defined but empty\n"));
695 goto jerr;
697 jleave:
698 NYD_LEAVE;
699 return (*chain != NULL);
700 jerr:
701 sk_X509_pop_free(*chain, X509_free);
702 *chain = NULL;
703 goto jleave;
706 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
707 static enum okay
708 load_crl1(X509_STORE *store, char const *name)
710 X509_LOOKUP *lookup;
711 enum okay rv = STOP;
712 NYD_ENTER;
714 if (options & OPT_VERBOSE)
715 printf("Loading CRL from \"%s\".\n", name);
716 if ((lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) == NULL) {
717 ssl_gen_err(tr(565, "Error creating X509 lookup object"));
718 goto jleave;
720 if (X509_load_crl_file(lookup, name, X509_FILETYPE_PEM) != 1) {
721 ssl_gen_err(tr(566, "Error loading CRL from \"%s\""), name);
722 goto jleave;
724 rv = OKAY;
725 jleave:
726 NYD_LEAVE;
727 return rv;
729 #endif /* new OpenSSL */
731 static enum okay
732 load_crls(X509_STORE *store, enum okeys fok, enum okeys dok)
734 char *crl_file, *crl_dir;
735 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
736 DIR *dirp;
737 struct dirent *dp;
738 char *fn = NULL;
739 int fs = 0, ds, es;
740 #endif
741 enum okay rv = STOP;
742 NYD_ENTER;
744 if ((crl_file = _var_oklook(fok)) != NULL) {
745 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
746 if ((crl_file = file_expand(crl_file)) == NULL ||
747 load_crl1(store, crl_file) != OKAY)
748 goto jleave;
749 #else
750 fprintf(stderr, tr(567,
751 "This OpenSSL version is too old to use CRLs.\n"));
752 goto jleave;
753 #endif
756 if ((crl_dir = _var_oklook(dok)) != NULL) {
757 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
758 char *x;
759 if ((x = file_expand(crl_dir)) == NULL ||
760 (dirp = opendir(crl_dir = x)) == NULL) {
761 perror(crl_dir);
762 goto jleave;
765 ds = strlen(crl_dir);
766 fn = smalloc(fs = ds + 20);
767 memcpy(fn, crl_dir, ds);
768 fn[ds] = '/';
769 while ((dp = readdir(dirp)) != NULL) {
770 if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
771 (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
772 continue;
773 if (dp->d_name[0] == '.')
774 continue;
775 if (ds + (es = strlen(dp->d_name)) + 2 < fs)
776 fn = srealloc(fn, fs = ds + es + 20);
777 memcpy(fn + ds + 1, dp->d_name, es + 1);
778 if (load_crl1(store, fn) != OKAY) {
779 closedir(dirp);
780 free(fn);
781 goto jleave;
784 closedir(dirp);
785 free(fn);
786 #else /* old OpenSSL */
787 fprintf(stderr, tr(567,
788 "This OpenSSL version is too old to use CRLs.\n"));
789 goto jleave;
790 #endif
792 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
793 if (crl_file || crl_dir)
794 X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK |
795 X509_V_FLAG_CRL_CHECK_ALL);
796 #endif
797 rv = OKAY;
798 jleave:
799 NYD_LEAVE;
800 return rv;
803 FL enum okay
804 ssl_open(char const *server, struct sock *sp, char const *uhp)
806 char *cp;
807 long opts;
808 enum okay rv = STOP;
809 NYD_ENTER;
811 ssl_init();
812 ssl_set_verify_level(uhp);
813 if ((sp->s_ctx = SSL_CTX_new(UNCONST(ssl_select_method(uhp)))) == NULL) {
814 ssl_gen_err(tr(261, "SSL_CTX_new() failed"));
815 goto jleave;
818 #ifdef SSL_MODE_AUTO_RETRY
819 /* available with OpenSSL 0.9.6 or later */
820 SSL_CTX_set_mode(sp->s_ctx, SSL_MODE_AUTO_RETRY);
821 #endif /* SSL_MODE_AUTO_RETRY */
822 opts = SSL_OP_ALL;
823 if (!ok_blook(ssl_v2_allow))
824 opts |= SSL_OP_NO_SSLv2;
825 SSL_CTX_set_options(sp->s_ctx, opts);
826 ssl_load_verifications(sp);
827 ssl_certificate(sp, uhp);
828 if ((cp = ok_vlook(ssl_cipher_list)) != NULL) {
829 if (SSL_CTX_set_cipher_list(sp->s_ctx, cp) != 1)
830 fprintf(stderr, tr(240, "Invalid cipher(s): %s\n"), cp);
833 if ((sp->s_ssl = SSL_new(sp->s_ctx)) == NULL) {
834 ssl_gen_err(tr(262, "SSL_new() failed"));
835 goto jleave;
837 SSL_set_fd(sp->s_ssl, sp->s_fd);
838 if (SSL_connect(sp->s_ssl) < 0) {
839 ssl_gen_err(tr(263, "could not initiate SSL/TLS connection"));
840 goto jleave;
842 if (ssl_verify_level != SSL_VERIFY_IGNORE) {
843 if (ssl_check_host(server, sp) != OKAY) {
844 fprintf(stderr, tr(249, "host certificate does not match \"%s\"\n"),
845 server);
846 if (ssl_verify_decide() != OKAY)
847 goto jleave;
850 sp->s_use_ssl = 1;
851 rv = OKAY;
852 jleave:
853 NYD_LEAVE;
854 return rv;
857 FL void
858 ssl_gen_err(char const *fmt, ...)
860 va_list ap;
861 NYD_ENTER;
863 va_start(ap, fmt);
864 vfprintf(stderr, fmt, ap);
865 va_end(ap);
866 SSL_load_error_strings();
867 fprintf(stderr, ": %s\n", ERR_error_string(ERR_get_error(), NULL));
868 NYD_LEAVE;
871 FL int
872 c_verify(void *vp)
874 int *msgvec = vp, *ip, ec = 0, rv = 1;
875 _STACKOF(X509) *chain = NULL;
876 X509_STORE *store;
877 char *ca_dir, *ca_file;
878 NYD_ENTER;
880 ssl_init();
882 ssl_verify_level = SSL_VERIFY_STRICT;
883 if ((store = X509_STORE_new()) == NULL) {
884 ssl_gen_err(tr(544, "Error creating X509 store"));
885 goto jleave;
887 X509_STORE_set_verify_cb_func(store, ssl_verify_cb);
889 if ((ca_dir = ok_vlook(smime_ca_dir)) != NULL)
890 ca_dir = file_expand(ca_dir);
891 if ((ca_file = ok_vlook(smime_ca_file)) != NULL)
892 ca_file = file_expand(ca_file);
894 if (ca_dir != NULL || ca_file != NULL) {
895 if (X509_STORE_load_locations(store, ca_file, ca_dir) != 1) {
896 ssl_gen_err(tr(545, "Error loading %s"),
897 (ca_file != NULL) ? ca_file : ca_dir);
898 goto jleave;
901 if (!ok_blook(smime_no_default_ca)) {
902 if (X509_STORE_set_default_paths(store) != 1) {
903 ssl_gen_err(tr(546, "Error loading default CA locations"));
904 goto jleave;
908 if (load_crls(store, ok_v_smime_crl_file, ok_v_smime_crl_dir) != OKAY)
909 goto jleave;
910 for (ip = msgvec; *ip; ip++) {
911 setdot(&message[*ip-1]);
912 ec |= smime_verify(message + *ip - 1, *ip, chain, store);
914 rv = ec;
915 jleave:
916 NYD_LEAVE;
917 return rv;
920 FL FILE *
921 smime_sign(FILE *ip, struct header *headp)
923 FILE *rv = NULL, *sp, *fp, *bp, *hp;
924 char const *addr;
925 X509 *cert;
926 _STACKOF(X509) *chain = NULL;
927 PKCS7 *pkcs7;
928 EVP_PKEY *pkey;
929 BIO *bb, *sb;
930 NYD_ENTER;
932 ssl_init();
934 if ((addr = myorigin(headp)) == NULL) {
935 fprintf(stderr, tr(531, "No \"from\" address for signing specified\n"));
936 goto jleave;
938 if ((fp = smime_sign_cert(addr, NULL, 1)) == NULL)
939 goto jleave;
941 if ((pkey = PEM_read_PrivateKey(fp, NULL, ssl_password_cb, NULL)) == NULL) {
942 ssl_gen_err(tr(532, "Error reading private key from"));
943 Fclose(fp);
944 goto jleave;
946 rewind(fp);
947 if ((cert = PEM_read_X509(fp, NULL, ssl_password_cb, NULL)) == NULL) {
948 ssl_gen_err(tr(533, "Error reading signer certificate from"));
949 EVP_PKEY_free(pkey);
950 Fclose(fp);
951 goto jleave;
954 Fclose(fp);
956 if ((addr = smime_sign_include_certs(addr)) != NULL &&
957 !smime_sign_include_chain_creat(&chain, addr)) {
958 X509_free(cert);
959 EVP_PKEY_free(pkey);
960 goto jleave;
963 if ((sp = Ftmp(NULL, "smimesign", OF_RDWR | OF_UNLINK | OF_REGISTER, 0600))
964 == NULL) {
965 perror("tempfile");
966 if (chain != NULL)
967 sk_X509_pop_free(chain, X509_free);
968 X509_free(cert);
969 EVP_PKEY_free(pkey);
970 goto jleave;
973 rewind(ip);
974 if (smime_split(ip, &hp, &bp, -1, 0) == STOP) {
975 Fclose(sp);
976 if (chain != NULL)
977 sk_X509_pop_free(chain, X509_free);
978 X509_free(cert);
979 EVP_PKEY_free(pkey);
980 goto jleave;
983 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
984 (sb = BIO_new_fp(sp, BIO_NOCLOSE)) == NULL) {
985 ssl_gen_err(tr(534, "Error creating BIO signing objects"));
986 Fclose(sp);
987 if (chain != NULL)
988 sk_X509_pop_free(chain, X509_free);
989 X509_free(cert);
990 EVP_PKEY_free(pkey);
991 goto jleave;
994 if ((pkcs7 = PKCS7_sign(cert, pkey, chain, bb,
995 PKCS7_DETACHED)) == NULL) {
996 ssl_gen_err(tr(535, "Error creating the PKCS#7 signing object"));
997 goto jerr;
999 if (PEM_write_bio_PKCS7(sb, pkcs7) == 0) {
1000 ssl_gen_err(tr(536, "Error writing signed S/MIME data"));
1001 jerr:
1002 BIO_free(bb);
1003 BIO_free(sb);
1004 Fclose(sp);
1005 if (chain != NULL)
1006 sk_X509_pop_free(chain, X509_free);
1007 X509_free(cert);
1008 EVP_PKEY_free(pkey);
1009 goto jleave;
1011 BIO_free(bb);
1012 BIO_free(sb);
1013 if (chain != NULL)
1014 sk_X509_pop_free(chain, X509_free);
1015 X509_free(cert);
1016 EVP_PKEY_free(pkey);
1018 rewind(bp);
1019 fflush(sp);
1020 rewind(sp);
1021 rv = smime_sign_assemble(hp, bp, sp);
1022 jleave:
1023 NYD_LEAVE;
1024 return rv;
1027 FL FILE *
1028 smime_encrypt(FILE *ip, char const *xcertfile, char const *to)
1030 char *certfile = UNCONST(xcertfile);
1031 FILE *rv = NULL, *yp, *fp, *bp, *hp;
1032 X509 *cert;
1033 PKCS7 *pkcs7;
1034 BIO *bb, *yb;
1035 _STACKOF(X509) *certs;
1036 EVP_CIPHER const *cipher;
1037 NYD_ENTER;
1039 if ((certfile = file_expand(certfile)) == NULL)
1040 goto jleave;
1042 ssl_init();
1043 if ((cipher = _smime_cipher(to)) == NULL)
1044 goto jleave;
1045 if ((fp = Fopen(certfile, "r")) == NULL) {
1046 perror(certfile);
1047 goto jleave;
1050 if ((cert = PEM_read_X509(fp, NULL, ssl_password_cb, NULL)) == NULL) {
1051 ssl_gen_err(tr(547, "Error reading encryption certificate from \"%s\""),
1052 certfile);
1053 Fclose(fp);
1054 goto jleave;
1056 Fclose(fp);
1058 certs = sk_X509_new_null();
1059 sk_X509_push(certs, cert);
1061 if ((yp = Ftmp(NULL, "smimeenc", OF_RDWR | OF_UNLINK | OF_REGISTER, 0600)) ==
1062 NULL) {
1063 perror("tempfile");
1064 goto jleave;
1067 rewind(ip);
1068 if (smime_split(ip, &hp, &bp, -1, 0) == STOP) {
1069 Fclose(yp);
1070 goto jleave;
1073 yb = NULL;
1074 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
1075 (yb = BIO_new_fp(yp, BIO_NOCLOSE)) == NULL) {
1076 ssl_gen_err(tr(548, "Error creating BIO encryption objects"));
1077 goto jerrall;
1079 if ((pkcs7 = PKCS7_encrypt(certs, bb, cipher, 0)) == NULL) {
1080 ssl_gen_err(tr(549, "Error creating the PKCS#7 encryption object"));
1081 goto jerrall;
1083 if (PEM_write_bio_PKCS7(yb, pkcs7) == 0) {
1084 ssl_gen_err(tr(550, "Error writing encrypted S/MIME data"));
1085 jerrall:
1086 /* TODO better code flow */
1087 if (bb != NULL)
1088 BIO_free(bb);
1089 if (yb != NULL)
1090 BIO_free(yb);
1091 Fclose(bp);
1092 Fclose(yp);
1093 goto jleave;
1095 BIO_free(bb);
1096 BIO_free(yb);
1097 Fclose(bp);
1098 fflush(yp);
1099 rewind(yp);
1101 rv = smime_encrypt_assemble(hp, yp);
1102 jleave:
1103 NYD_LEAVE;
1104 return rv;
1107 FL struct message *
1108 smime_decrypt(struct message *m, char const *to, char const *cc, int signcall)
1110 struct message *rv;
1111 FILE *fp, *bp, *hp, *op;
1112 X509 *cert;
1113 PKCS7 *pkcs7;
1114 EVP_PKEY *pkey;
1115 BIO *bb, *pb, *ob;
1116 long size;
1117 FILE *yp;
1118 NYD_ENTER;
1120 rv = NULL;
1121 cert = NULL;
1122 pkey = NULL;
1123 size = m->m_size;
1125 if ((yp = setinput(&mb, m, NEED_BODY)) == NULL)
1126 goto jleave;
1128 ssl_init();
1129 if ((fp = smime_sign_cert(to, cc, 0)) != NULL) {
1130 pkey = PEM_read_PrivateKey(fp, NULL, ssl_password_cb, NULL);
1131 if (pkey == NULL) {
1132 ssl_gen_err(tr(551, "Error reading private key"));
1133 Fclose(fp);
1134 goto jleave;
1136 rewind(fp);
1138 if ((cert = PEM_read_X509(fp, NULL, ssl_password_cb, NULL)) == NULL) {
1139 ssl_gen_err(tr(552, "Error reading decryption certificate"));
1140 Fclose(fp);
1141 EVP_PKEY_free(pkey);
1142 goto jleave;
1144 Fclose(fp);
1147 if ((op = Ftmp(NULL, "smimedec", OF_RDWR | OF_UNLINK | OF_REGISTER, 0600)) ==
1148 NULL) {
1149 perror("tempfile");
1150 goto j_ferr;
1153 if (smime_split(yp, &hp, &bp, size, 1) == STOP)
1154 goto jferr;
1156 if ((ob = BIO_new_fp(op, BIO_NOCLOSE)) == NULL ||
1157 (bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL) {
1158 ssl_gen_err(tr(553, "Error creating BIO decryption objects"));
1159 goto jferr;
1161 if ((pkcs7 = SMIME_read_PKCS7(bb, &pb)) == NULL) {
1162 ssl_gen_err(tr(554, "Error reading PKCS#7 object"));
1163 jferr:
1164 Fclose(op);
1165 j_ferr:
1166 if (cert)
1167 X509_free(cert);
1168 if (pkey)
1169 EVP_PKEY_free(pkey);
1170 goto jleave;
1173 if (PKCS7_type_is_signed(pkcs7)) {
1174 if (signcall) {
1175 setinput(&mb, m, NEED_BODY);
1176 rv = (struct message*)-1;
1177 goto jerr2;
1179 if (PKCS7_verify(pkcs7, NULL, NULL, NULL, ob,
1180 PKCS7_NOVERIFY | PKCS7_NOSIGS) != 1)
1181 goto jerr;
1182 fseek(hp, 0L, SEEK_END);
1183 fprintf(hp, "X-Encryption-Cipher: none\n");
1184 fflush(hp);
1185 rewind(hp);
1186 } else if (pkey == NULL) {
1187 fprintf(stderr, tr(555, "No appropriate private key found.\n"));
1188 goto jerr2;
1189 } else if (cert == NULL) {
1190 fprintf(stderr, tr(556, "No appropriate certificate found.\n"));
1191 goto jerr2;
1192 } else if (PKCS7_decrypt(pkcs7, pkey, cert, ob, 0) != 1) {
1193 jerr:
1194 ssl_gen_err(tr(557, "Error decrypting PKCS#7 object"));
1195 jerr2:
1196 BIO_free(bb);
1197 BIO_free(ob);
1198 Fclose(op);
1199 Fclose(bp);
1200 Fclose(hp);
1201 if (cert != NULL)
1202 X509_free(cert);
1203 if (pkey != NULL)
1204 EVP_PKEY_free(pkey);
1205 goto jleave;
1207 BIO_free(bb);
1208 BIO_free(ob);
1209 if (cert)
1210 X509_free(cert);
1211 if (pkey)
1212 EVP_PKEY_free(pkey);
1213 fflush_rewind(op);
1214 Fclose(bp);
1216 rv = smime_decrypt_assemble(m, hp, op);
1217 jleave:
1218 NYD_LEAVE;
1219 return rv;
1222 FL enum okay
1223 smime_certsave(struct message *m, int n, FILE *op)
1225 struct message *x;
1226 char *to, *cc, *cnttype;
1227 int c, i;
1228 FILE *fp, *ip;
1229 off_t size;
1230 BIO *fb, *pb;
1231 PKCS7 *pkcs7;
1232 _STACKOF(X509) *certs, *chain = NULL;
1233 X509 *cert;
1234 enum okay rv = STOP;
1235 NYD_ENTER;
1237 message_number = n;
1238 jloop:
1239 to = hfield1("to", m);
1240 cc = hfield1("cc", m);
1241 cnttype = hfield1("content-type", m);
1242 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
1243 goto jleave;
1244 if (cnttype && !strncmp(cnttype, "application/x-pkcs7-mime", 24)) {
1245 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
1246 goto jleave;
1247 if (x != (struct message*)-1) {
1248 m = x;
1249 goto jloop;
1252 size = m->m_size;
1254 if ((fp = Ftmp(NULL, "smimecert", OF_RDWR | OF_UNLINK | OF_REGISTER, 0600))
1255 == NULL) {
1256 perror("tempfile");
1257 goto jleave;
1260 while (size-- > 0) {
1261 c = getc(ip);
1262 putc(c, fp);
1264 fflush(fp);
1266 rewind(fp);
1267 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
1268 ssl_gen_err("Error creating BIO object for message %d", n);
1269 Fclose(fp);
1270 goto jleave;
1273 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
1274 ssl_gen_err(tr(562, "Error reading PKCS#7 object for message %d"), n);
1275 BIO_free(fb);
1276 Fclose(fp);
1277 goto jleave;
1279 BIO_free(fb);
1280 Fclose(fp);
1281 certs = PKCS7_get0_signers(pkcs7, chain, 0);
1282 if (certs == NULL) {
1283 fprintf(stderr, tr(563, "No certificates found in message %d\n"), n);
1284 goto jleave;
1287 for (i = 0; i < sk_X509_num(certs); ++i) {
1288 cert = sk_X509_value(certs, i);
1289 if (X509_print_fp(op, cert) == 0 || PEM_write_X509(op, cert) == 0) {
1290 ssl_gen_err(tr(564, "Error writing certificate %d from message %d"),
1291 i, n);
1292 goto jleave;
1295 rv = OKAY;
1296 jleave:
1297 NYD_LEAVE;
1298 return rv;
1300 #endif /* HAVE_OPENSSL */
1302 /* vim:set fenc=utf-8:s-it-mode */