tty.c, NCL: let ^O mean `dp'
[s-mailx.git] / openssl.c
blob17cd5788732c1dc5155591eeae96113bd526b5a9
1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ OpenSSL functions. TODO this needs an overhaul -- there _are_ stack leaks!?
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 int _ssl_isinit;
133 static int _ssl_rand_isinit;
134 static int _ssl_msgno;
135 static int _ssl_verify_error;
137 static int _ssl_rand_init(void);
138 static void _ssl_init(void);
139 static bool_t _ssl_parse_asn1_time(ASN1_TIME *atp,
140 char *bdat, size_t blen);
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 bool_t _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 int
162 _ssl_rand_init(void)
164 char *cp, *x;
165 int state = 0;
166 NYD_ENTER;
168 if ((cp = ok_vlook(ssl_rand_egd)) != NULL) {
169 if ((x = file_expand(cp)) == NULL || RAND_egd(cp = x) == -1)
170 fprintf(stderr, tr(245, "entropy daemon at \"%s\" not available\n"),
171 cp);
172 else
173 state = 1;
174 } else if ((cp = ok_vlook(ssl_rand_file)) != NULL) {
175 if ((x = file_expand(cp)) == NULL || RAND_load_file(cp = x, 1024) == -1)
176 fprintf(stderr, tr(246, "entropy file at \"%s\" not available\n"), cp);
177 else {
178 struct stat st;
180 if (!stat(cp, &st) && S_ISREG(st.st_mode) && !access(cp, W_OK)) {
181 if (RAND_write_file(cp) == -1) {
182 fprintf(stderr, tr(247,
183 "writing entropy data to \"%s\" failed\n"), cp);
186 state = 1;
189 NYD_LEAVE;
190 return state;
193 static void
194 _ssl_init(void)
196 NYD_ENTER;
197 if (_ssl_isinit == 0) {
198 SSL_library_init();
199 _ssl_isinit = 1;
201 if (_ssl_rand_isinit == 0)
202 _ssl_rand_isinit = _ssl_rand_init();
203 NYD_LEAVE;
206 static bool_t
207 _ssl_parse_asn1_time(ASN1_TIME *atp, char *bdat, size_t blen)
209 /* Shamelessly stolen from CURL */
210 char const *db, *gm;
211 int Y, M, d, h, m, s;
212 bool_t rv;
213 NYD_ENTER;
215 db = (char const*)atp->data;
216 if (atp->length < 10)
217 goto jerr;
219 for (s = 0; s < 10; ++s)
220 if (!digitchar(db[s]))
221 goto jerr;
223 gm = (db[atp->length - 1] == 'Z') ? "GMT" : "";
225 Y = (db[0] - '0') * 10 + (db[1] - '0');
226 if (Y < 50)
227 Y += 100;
228 Y += 1900;
230 M = (db[2] - '0') * 10 + (db[3] - '0');
231 if (M > 12 || M < 1)
232 goto jerr;
234 d = (db[4] - '0') * 10 + (db[5] - '0');
235 h = (db[6] - '0') * 10 + (db[7] - '0');
236 m = (db[8] - '0') * 10 + (db[9] - '0');
237 s = (db[10] >= '0' && db[10] <= '9' && db[11] >= '0' && db[11] <= '9')
238 ? ((db[10] - '0') * 10 + (db[11] - '0')) : 0;
240 snprintf(bdat, blen, "%04d-%02d-%02d %02d:%02d:%02d %s",
241 Y, M, d, h, m, s, gm);
242 rv = TRU1;
243 jleave:
244 NYD_LEAVE;
245 return rv;
246 jerr:
247 snprintf(bdat, blen, tr(576, "Bogus certificate date: %.*s\n"),
248 atp->length, db);
249 rv = FAL0;
250 goto jleave;
253 static int
254 _ssl_verify_cb(int success, X509_STORE_CTX *store)
256 char data[256];
257 X509 *cert;
258 int rv = TRU1;
259 NYD_ENTER;
261 if (success && !(options & OPT_VERB))
262 goto jleave;
264 if (_ssl_msgno != 0) {
265 fprintf(stderr, "Message %d:\n", _ssl_msgno);
266 _ssl_msgno = 0;
268 fprintf(stderr, tr(229, " Certificate depth %d %s\n"),
269 X509_STORE_CTX_get_error_depth(store), (success ? "" : tr(579, "ERROR")));
271 cert = X509_STORE_CTX_get_current_cert(store);
273 X509_NAME_oneline(X509_get_subject_name(cert), data, sizeof data);
274 fprintf(stderr, tr(231, " subject = %s\n"), data);
276 _ssl_parse_asn1_time(X509_get_notBefore(cert), data, sizeof data);
277 fprintf(stderr, tr(577, " notBefore = %s\n"), data);
279 _ssl_parse_asn1_time(X509_get_notAfter(cert), data, sizeof data);
280 fprintf(stderr, tr(578, " notAfter = %s\n"), data);
282 if (!success) {
283 int err = X509_STORE_CTX_get_error(store);
284 fprintf(stderr, tr(232, " err %i: %s\n"),
285 err, X509_verify_cert_error_string(err));
286 _ssl_verify_error = 1;
289 X509_NAME_oneline(X509_get_issuer_name(cert), data, sizeof data);
290 fprintf(stderr, tr(230, " issuer = %s\n"), data);
292 if (!success && ssl_verify_decide() != OKAY)
293 rv = FAL0;
294 jleave:
295 NYD_LEAVE;
296 return rv;
299 static SSL_METHOD const *
300 ssl_select_method(char const *uhp)
302 SSL_METHOD const *method;
303 char *cp;
304 size_t i;
305 NYD_ENTER;
307 if ((cp = ssl_method_string(uhp)) != NULL) {
308 method = NULL;
309 for (i = 0; i < NELEM(_ssl_methods); ++i)
310 if (!strcmp(_ssl_methods[i].sm_name, cp)) {
311 method = (*_ssl_methods[i].sm_fun)();
312 goto jleave;
314 fprintf(stderr, tr(244, "Invalid SSL method \"%s\"\n"), cp);
316 method = _SSL_DEFAULT_METHOD();
317 jleave:
318 NYD_LEAVE;
319 return method;
322 static void
323 ssl_load_verifications(struct sock *sp)
325 char *ca_dir, *ca_file;
326 X509_STORE *store;
327 NYD_ENTER;
329 if (ssl_verify_level == SSL_VERIFY_IGNORE)
330 goto jleave;
332 if ((ca_dir = ok_vlook(ssl_ca_dir)) != NULL)
333 ca_dir = file_expand(ca_dir);
334 if ((ca_file = ok_vlook(ssl_ca_file)) != NULL)
335 ca_file = file_expand(ca_file);
337 if (ca_dir != NULL || ca_file != NULL) {
338 if (SSL_CTX_load_verify_locations(sp->s_ctx, ca_file, ca_dir) != 1) {
339 fprintf(stderr, tr(233, "Error loading "));
340 if (ca_dir) {
341 fputs(ca_dir, stderr);
342 if (ca_file)
343 fputs(tr(234, " or "), stderr);
345 if (ca_file)
346 fputs(ca_file, stderr);
347 fputs("\n", stderr);
351 if (!ok_blook(ssl_no_default_ca)) {
352 if (SSL_CTX_set_default_verify_paths(sp->s_ctx) != 1)
353 fprintf(stderr, tr(243, "Error loading default CA locations\n"));
356 _ssl_verify_error = 0;
357 _ssl_msgno = 0;
358 SSL_CTX_set_verify(sp->s_ctx, SSL_VERIFY_PEER, &_ssl_verify_cb);
359 store = SSL_CTX_get_cert_store(sp->s_ctx);
360 load_crls(store, ok_v_ssl_crl_file, ok_v_ssl_crl_dir);
361 jleave:
362 NYD_LEAVE;
365 static void
366 ssl_certificate(struct sock *sp, char const *uhp)
368 size_t i;
369 char *certvar, *keyvar, *cert, *key, *x;
370 NYD_ENTER;
372 i = strlen(uhp);
373 certvar = ac_alloc(i + 9 +1);
374 memcpy(certvar, "ssl-cert-", 9);
375 memcpy(certvar + 9, uhp, i +1);
377 if ((cert = vok_vlook(certvar)) != NULL ||
378 (cert = ok_vlook(ssl_cert)) != NULL) {
379 x = cert;
380 if ((cert = file_expand(cert)) == NULL) {
381 cert = x;
382 goto jbcert;
383 } else if (SSL_CTX_use_certificate_chain_file(sp->s_ctx, cert) == 1) {
384 keyvar = ac_alloc(strlen(uhp) + 8 +1);
385 memcpy(keyvar, "ssl-key-", 8);
386 memcpy(keyvar + 8, uhp, i +1);
387 if ((key = vok_vlook(keyvar)) == NULL &&
388 (key = ok_vlook(ssl_key)) == NULL)
389 key = cert;
390 else if ((x = key, key = file_expand(key)) == NULL) {
391 key = x;
392 goto jbkey;
394 if (SSL_CTX_use_PrivateKey_file(sp->s_ctx, key, SSL_FILETYPE_PEM) != 1)
395 jbkey:
396 fprintf(stderr, tr(238, "cannot load private key from file %s\n"),
397 key);
398 ac_free(keyvar);
399 } else
400 jbcert:
401 fprintf(stderr, tr(239, "cannot load certificate from file %s\n"),
402 cert);
404 ac_free(certvar);
405 NYD_LEAVE;
408 static enum okay
409 ssl_check_host(char const *server, struct sock *sp)
411 char data[256];
412 X509 *cert;
413 X509_NAME *subj;
414 _STACKOF(GENERAL_NAME) *gens;
415 GENERAL_NAME *gen;
416 int i;
417 enum okay rv = STOP;
418 NYD_ENTER;
420 if ((cert = SSL_get_peer_certificate(sp->s_ssl)) == NULL) {
421 fprintf(stderr, tr(248, "no certificate from \"%s\"\n"), server);
422 goto jleave;
425 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
426 if (gens != NULL) {
427 for (i = 0; i < sk_GENERAL_NAME_num(gens); ++i) {
428 gen = sk_GENERAL_NAME_value(gens, i);
429 if (gen->type == GEN_DNS) {
430 if (options & OPT_VERB)
431 fprintf(stderr, "Comparing DNS: <%s>; should <%s>\n",
432 server, (char*)gen->d.ia5->data);
433 rv = rfc2595_hostname_match(server, (char*)gen->d.ia5->data);
434 if (rv == OKAY)
435 goto jdone;
440 if ((subj = X509_get_subject_name(cert)) != NULL &&
441 X509_NAME_get_text_by_NID(subj, NID_commonName, data, sizeof data)
442 > 0) {
443 data[sizeof data - 1] = '\0';
444 if (options & OPT_VERB)
445 fprintf(stderr, "Comparing commonName: <%s>; should <%s>\n",
446 server, data);
447 rv = rfc2595_hostname_match(server, data);
449 jdone:
450 X509_free(cert);
451 jleave:
452 NYD_LEAVE;
453 return rv;
456 static int
457 smime_verify(struct message *m, int n, _STACKOF(X509) *chain, X509_STORE *store)
459 char data[LINESIZE], *sender, *to, *cc, *cnttype;
460 int rv, c, i, j;
461 struct message *x;
462 FILE *fp, *ip;
463 off_t size;
464 BIO *fb, *pb;
465 PKCS7 *pkcs7;
466 _STACKOF(X509) *certs;
467 _STACKOF(GENERAL_NAME) *gens;
468 X509 *cert;
469 X509_NAME *subj;
470 GENERAL_NAME *gen;
471 NYD_ENTER;
473 rv = 1;
474 fp = NULL;
475 fb = NULL;
476 _ssl_verify_error = 0;
477 _ssl_msgno = n;
479 for (;;) {
480 sender = getsender(m);
481 to = hfield1("to", m);
482 cc = hfield1("cc", m);
483 cnttype = hfield1("content-type", m);
484 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
485 goto jleave;
486 if (cnttype && !ascncasecmp(cnttype, "application/x-pkcs7-mime", 24)) {
487 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
488 goto jleave;
489 if (x != (struct message*)-1) {
490 m = x;
491 continue;
494 size = m->m_size;
495 break;
498 if ((fp = Ftmp(NULL, "smimever", OF_RDWR | OF_UNLINK | OF_REGISTER, 0600)) ==
499 NULL) {
500 perror("tempfile");
501 goto jleave;
503 while (size-- > 0) {
504 c = getc(ip);
505 putc(c, fp);
507 fflush_rewind(fp);
509 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
510 ssl_gen_err(tr(537,
511 "Error creating BIO verification object for message %d"), n);
512 goto jleave;
515 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
516 ssl_gen_err(tr(538, "Error reading PKCS#7 object for message %d"), n);
517 goto jleave;
519 if (PKCS7_verify(pkcs7, chain, store, pb, NULL, 0) != 1) {
520 ssl_gen_err(tr(539, "Error verifying message %d"), n);
521 goto jleave;
524 if (sender == NULL) {
525 fprintf(stderr, tr(540, "Warning: Message %d has no sender.\n"), n);
526 rv = 0;
527 goto jleave;
530 certs = PKCS7_get0_signers(pkcs7, chain, 0);
531 if (certs == NULL) {
532 fprintf(stderr, tr(541, "No certificates found in message %d.\n"), n);
533 goto jleave;
536 for (i = 0; i < sk_X509_num(certs); ++i) {
537 cert = sk_X509_value(certs, i);
538 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
539 if (gens != NULL) {
540 for (j = 0; j < sk_GENERAL_NAME_num(gens); ++j) {
541 gen = sk_GENERAL_NAME_value(gens, j);
542 if (gen->type == GEN_EMAIL) {
543 if (options & OPT_VERB)
544 fprintf(stderr,
545 "Comparing subject_alt_name: <%s>; should <%s>\n",
546 sender, (char*)gen->d.ia5->data);
547 if (!asccasecmp((char*)gen->d.ia5->data, sender))
548 goto jfound;
553 if ((subj = X509_get_subject_name(cert)) != NULL &&
554 X509_NAME_get_text_by_NID(subj, NID_pkcs9_emailAddress,
555 data, sizeof data) > 0) {
556 data[sizeof data -1] = '\0';
557 if (options & OPT_VERB)
558 fprintf(stderr, "Comparing emailAddress: <%s>; should <%s>\n",
559 sender, data);
560 if (!asccasecmp(data, sender))
561 goto jfound;
564 fprintf(stderr, tr(542, "Message %d: certificate does not match <%s>\n"),
565 n, sender);
566 goto jleave;
567 jfound:
568 if (_ssl_verify_error == 0)
569 printf(tr(543, "Message %d was verified successfully.\n"), n);
570 rv = _ssl_verify_error;
571 jleave:
572 if (fb != NULL)
573 BIO_free(fb);
574 if (fp != NULL)
575 Fclose(fp);
576 NYD_LEAVE;
577 return rv;
580 static EVP_CIPHER const *
581 _smime_cipher(char const *name)
583 EVP_CIPHER const *cipher;
584 char *vn, *cp;
585 size_t i;
586 NYD_ENTER;
588 vn = ac_alloc(i = strlen(name) + 13 +1);
589 snprintf(vn, (int)i, "smime-cipher-%s", name);
590 cp = vok_vlook(vn);
591 ac_free(vn);
593 if (cp != NULL) {
594 cipher = NULL;
595 for (i = 0; i < NELEM(_smime_ciphers); ++i)
596 if (!strcmp(_smime_ciphers[i].sc_name, cp)) {
597 cipher = (*_smime_ciphers[i].sc_fun)();
598 goto jleave;
600 fprintf(stderr, tr(240, "Invalid cipher(s): %s\n"), cp);
601 } else
602 cipher = _SMIME_DEFAULT_CIPHER();
603 jleave:
604 NYD_LEAVE;
605 return cipher;
608 static int
609 ssl_password_cb(char *buf, int size, int rwflag, void *userdata)
611 char *pass;
612 size_t len;
613 NYD_ENTER;
614 UNUSED(rwflag);
615 UNUSED(userdata);
617 if ((pass = getpassword("PEM pass phrase:")) != NULL) {
618 len = strlen(pass);
619 if (UICMP(z, len, >=, size))
620 len = size -1;
621 memcpy(buf, pass, len);
622 buf[len] = '\0';
623 } else
624 len = 0;
625 NYD_LEAVE;
626 return (int)len;
629 static FILE *
630 smime_sign_cert(char const *xname, char const *xname2, bool_t dowarn)
632 char *vn, *cp;
633 int vs;
634 struct name *np;
635 char const *name = xname, *name2 = xname2;
636 FILE *fp = NULL;
637 NYD_ENTER;
639 jloop:
640 if (name) {
641 np = lextract(name, GTO | GSKIN);
642 while (np != NULL) {
643 /* This needs to be more intelligent since it will currently take the
644 * first name for which a private key is available regardless of
645 * whether it is the right one for the message */
646 vn = ac_alloc(vs = strlen(np->n_name) + 30);
647 snprintf(vn, vs, "smime-sign-cert-%s", np->n_name);
648 cp = vok_vlook(vn);
649 ac_free(vn);
650 if (cp != NULL)
651 goto jopen;
652 np = np->n_flink;
654 if (name2 != NULL) {
655 name = name2;
656 name2 = NULL;
657 goto jloop;
661 if ((cp = ok_vlook(smime_sign_cert)) == NULL)
662 goto jerr;
663 jopen:
664 if ((cp = file_expand(cp)) == NULL)
665 goto jleave;
666 if ((fp = Fopen(cp, "r")) == NULL)
667 perror(cp);
668 jleave:
669 NYD_LEAVE;
670 return fp;
671 jerr:
672 if (dowarn) {
673 fprintf(stderr, tr(558, "Could not find a certificate for %s"), xname);
674 if (xname2)
675 fprintf(stderr, tr(559, "or %s"), xname2);
676 fputc('\n', stderr);
678 goto jleave;
681 static char *
682 _smime_sign_include_certs(char const *name)
684 char *rv;
685 NYD_ENTER;
687 /* See comments in smime_sign_cert() for algorithm pitfalls */
688 if (name != NULL) {
689 struct name *np;
691 for (np = lextract(name, GTO | GSKIN); np != NULL; np = np->n_flink) {
692 int vs;
693 char *vn = ac_alloc(vs = strlen(np->n_name) + 30);
694 snprintf(vn, vs, "smime-sign-include-certs-%s", np->n_name);
695 rv = vok_vlook(vn);
696 ac_free(vn);
697 if (rv != NULL)
698 goto jleave;
701 rv = ok_vlook(smime_sign_include_certs);
702 jleave:
703 NYD_LEAVE;
704 return rv;
707 static bool_t
708 _smime_sign_include_chain_creat(_STACKOF(X509) **chain, char const *cfiles)
710 X509 *tmp;
711 FILE *fp;
712 char *nfield, *cfield, *x;
713 NYD_ENTER;
715 *chain = sk_X509_new_null();
717 for (nfield = savestr(cfiles);
718 (cfield = n_strsep(&nfield, ',', TRU1)) != NULL;) {
719 if ((x = file_expand(cfield)) == NULL ||
720 (fp = Fopen(cfield = x, "r")) == NULL) {
721 perror(cfiles);
722 goto jerr;
724 if ((tmp = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
725 ssl_gen_err(tr(560, "Error reading certificate from \"%s\""), cfield);
726 Fclose(fp);
727 goto jerr;
729 sk_X509_push(*chain, tmp);
730 Fclose(fp);
733 if (sk_X509_num(*chain) == 0) {
734 fprintf(stderr, tr(561, "smime-sign-include-certs defined but empty\n"));
735 goto jerr;
737 jleave:
738 NYD_LEAVE;
739 return (*chain != NULL);
740 jerr:
741 sk_X509_pop_free(*chain, X509_free);
742 *chain = NULL;
743 goto jleave;
746 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
747 static enum okay
748 load_crl1(X509_STORE *store, char const *name)
750 X509_LOOKUP *lookup;
751 enum okay rv = STOP;
752 NYD_ENTER;
754 if (options & OPT_VERB)
755 printf("Loading CRL from \"%s\".\n", name);
756 if ((lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) == NULL) {
757 ssl_gen_err(tr(565, "Error creating X509 lookup object"));
758 goto jleave;
760 if (X509_load_crl_file(lookup, name, X509_FILETYPE_PEM) != 1) {
761 ssl_gen_err(tr(566, "Error loading CRL from \"%s\""), name);
762 goto jleave;
764 rv = OKAY;
765 jleave:
766 NYD_LEAVE;
767 return rv;
769 #endif /* new OpenSSL */
771 static enum okay
772 load_crls(X509_STORE *store, enum okeys fok, enum okeys dok)
774 char *crl_file, *crl_dir;
775 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
776 DIR *dirp;
777 struct dirent *dp;
778 char *fn = NULL;
779 int fs = 0, ds, es;
780 #endif
781 enum okay rv = STOP;
782 NYD_ENTER;
784 if ((crl_file = _var_oklook(fok)) != NULL) {
785 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
786 if ((crl_file = file_expand(crl_file)) == NULL ||
787 load_crl1(store, crl_file) != OKAY)
788 goto jleave;
789 #else
790 fprintf(stderr, tr(567,
791 "This OpenSSL version is too old to use CRLs.\n"));
792 goto jleave;
793 #endif
796 if ((crl_dir = _var_oklook(dok)) != NULL) {
797 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
798 char *x;
799 if ((x = file_expand(crl_dir)) == NULL ||
800 (dirp = opendir(crl_dir = x)) == NULL) {
801 perror(crl_dir);
802 goto jleave;
805 ds = strlen(crl_dir);
806 fn = smalloc(fs = ds + 20);
807 memcpy(fn, crl_dir, ds);
808 fn[ds] = '/';
809 while ((dp = readdir(dirp)) != NULL) {
810 if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
811 (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
812 continue;
813 if (dp->d_name[0] == '.')
814 continue;
815 if (ds + (es = strlen(dp->d_name)) + 2 < fs)
816 fn = srealloc(fn, fs = ds + es + 20);
817 memcpy(fn + ds + 1, dp->d_name, es + 1);
818 if (load_crl1(store, fn) != OKAY) {
819 closedir(dirp);
820 free(fn);
821 goto jleave;
824 closedir(dirp);
825 free(fn);
826 #else /* old OpenSSL */
827 fprintf(stderr, tr(567,
828 "This OpenSSL version is too old to use CRLs.\n"));
829 goto jleave;
830 #endif
832 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
833 if (crl_file || crl_dir)
834 X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK |
835 X509_V_FLAG_CRL_CHECK_ALL);
836 #endif
837 rv = OKAY;
838 jleave:
839 NYD_LEAVE;
840 return rv;
843 FL enum okay
844 ssl_open(char const *server, struct sock *sp, char const *uhp)
846 char *cp;
847 long opts;
848 enum okay rv = STOP;
849 NYD_ENTER;
851 _ssl_init();
852 ssl_set_verify_level(uhp);
853 if ((sp->s_ctx = SSL_CTX_new(UNCONST(ssl_select_method(uhp)))) == NULL) {
854 ssl_gen_err(tr(261, "SSL_CTX_new() failed"));
855 goto jleave;
858 #ifdef SSL_MODE_AUTO_RETRY
859 /* available with OpenSSL 0.9.6 or later */
860 SSL_CTX_set_mode(sp->s_ctx, SSL_MODE_AUTO_RETRY);
861 #endif /* SSL_MODE_AUTO_RETRY */
862 opts = SSL_OP_ALL;
863 if (!ok_blook(ssl_v2_allow))
864 opts |= SSL_OP_NO_SSLv2;
865 SSL_CTX_set_options(sp->s_ctx, opts);
866 ssl_load_verifications(sp);
867 ssl_certificate(sp, uhp);
868 if ((cp = ok_vlook(ssl_cipher_list)) != NULL) {
869 if (SSL_CTX_set_cipher_list(sp->s_ctx, cp) != 1)
870 fprintf(stderr, tr(240, "Invalid cipher(s): %s\n"), cp);
873 if ((sp->s_ssl = SSL_new(sp->s_ctx)) == NULL) {
874 ssl_gen_err(tr(262, "SSL_new() failed"));
875 goto jleave;
877 SSL_set_fd(sp->s_ssl, sp->s_fd);
878 if (SSL_connect(sp->s_ssl) < 0) {
879 ssl_gen_err(tr(263, "could not initiate SSL/TLS connection"));
880 goto jleave;
882 if (ssl_verify_level != SSL_VERIFY_IGNORE) {
883 if (ssl_check_host(server, sp) != OKAY) {
884 fprintf(stderr, tr(249, "host certificate does not match \"%s\"\n"),
885 server);
886 if (ssl_verify_decide() != OKAY)
887 goto jleave;
890 sp->s_use_ssl = 1;
891 rv = OKAY;
892 jleave:
893 NYD_LEAVE;
894 return rv;
897 FL void
898 ssl_gen_err(char const *fmt, ...)
900 va_list ap;
901 NYD_ENTER;
903 va_start(ap, fmt);
904 vfprintf(stderr, fmt, ap);
905 va_end(ap);
906 SSL_load_error_strings();
907 fprintf(stderr, ": %s\n", ERR_error_string(ERR_get_error(), NULL));
908 NYD_LEAVE;
911 FL int
912 c_verify(void *vp)
914 int *msgvec = vp, *ip, ec = 0, rv = 1;
915 _STACKOF(X509) *chain = NULL;
916 X509_STORE *store;
917 char *ca_dir, *ca_file;
918 NYD_ENTER;
920 _ssl_init();
922 ssl_verify_level = SSL_VERIFY_STRICT;
923 if ((store = X509_STORE_new()) == NULL) {
924 ssl_gen_err(tr(544, "Error creating X509 store"));
925 goto jleave;
927 X509_STORE_set_verify_cb_func(store, &_ssl_verify_cb);
929 if ((ca_dir = ok_vlook(smime_ca_dir)) != NULL)
930 ca_dir = file_expand(ca_dir);
931 if ((ca_file = ok_vlook(smime_ca_file)) != NULL)
932 ca_file = file_expand(ca_file);
934 if (ca_dir != NULL || ca_file != NULL) {
935 if (X509_STORE_load_locations(store, ca_file, ca_dir) != 1) {
936 ssl_gen_err(tr(545, "Error loading %s"),
937 (ca_file != NULL) ? ca_file : ca_dir);
938 goto jleave;
941 if (!ok_blook(smime_no_default_ca)) {
942 if (X509_STORE_set_default_paths(store) != 1) {
943 ssl_gen_err(tr(546, "Error loading default CA locations"));
944 goto jleave;
948 if (load_crls(store, ok_v_smime_crl_file, ok_v_smime_crl_dir) != OKAY)
949 goto jleave;
950 for (ip = msgvec; *ip != 0; ++ip) {
951 struct message *mp = message + *ip - 1;
952 setdot(mp);
953 ec |= smime_verify(mp, *ip, chain, store);
955 if ((rv = ec) != 0)
956 exit_status |= EXIT_ERR;
957 jleave:
958 NYD_LEAVE;
959 return rv;
962 FL FILE *
963 smime_sign(FILE *ip, char const *addr)
965 FILE *rv = NULL, *sp = NULL, *fp = NULL, *bp, *hp;
966 X509 *cert = NULL;
967 _STACKOF(X509) *chain = NULL;
968 PKCS7 *pkcs7;
969 EVP_PKEY *pkey = NULL;
970 BIO *bb, *sb;
971 bool_t bail = FAL0;
972 NYD_ENTER;
974 _ssl_init();
976 if (addr == NULL) {
977 fprintf(stderr, tr(531, "No \"from\" address for signing specified\n"));
978 goto jleave;
980 if ((fp = smime_sign_cert(addr, NULL, 1)) == NULL)
981 goto jleave;
983 if ((pkey = PEM_read_PrivateKey(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
984 ssl_gen_err(tr(532, "Error reading private key from"));
985 goto jleave;
988 rewind(fp);
989 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
990 ssl_gen_err(tr(533, "Error reading signer certificate from"));
991 goto jleave;
993 Fclose(fp);
994 fp = NULL;
996 if ((addr = _smime_sign_include_certs(addr)) != NULL &&
997 !_smime_sign_include_chain_creat(&chain, addr))
998 goto jleave;
1000 if ((sp = Ftmp(NULL, "smimesign", OF_RDWR | OF_UNLINK | OF_REGISTER, 0600))
1001 == NULL) {
1002 perror("tempfile");
1003 goto jleave;
1006 rewind(ip);
1007 if (smime_split(ip, &hp, &bp, -1, 0) == STOP) {
1008 bail = TRU1;
1009 goto jerr1;
1012 sb = NULL;
1013 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
1014 (sb = BIO_new_fp(sp, BIO_NOCLOSE)) == NULL) {
1015 ssl_gen_err(tr(534, "Error creating BIO signing objects"));
1016 bail = TRU1;
1017 goto jerr;
1020 if ((pkcs7 = PKCS7_sign(cert, pkey, chain, bb, PKCS7_DETACHED)) == NULL) {
1021 ssl_gen_err(tr(535, "Error creating the PKCS#7 signing object"));
1022 bail = TRU1;
1023 goto jerr;
1025 if (PEM_write_bio_PKCS7(sb, pkcs7) == 0) {
1026 ssl_gen_err(tr(536, "Error writing signed S/MIME data"));
1027 bail = TRU1;
1028 /*goto jerr*/
1030 jerr:
1031 if (sb != NULL)
1032 BIO_free(sb);
1033 if (bb != NULL)
1034 BIO_free(bb);
1035 if (!bail) {
1036 rewind(bp);
1037 fflush_rewind(sp);
1038 rv = smime_sign_assemble(hp, bp, sp);
1039 } else
1040 jerr1:
1041 Fclose(sp);
1043 jleave:
1044 if (chain != NULL)
1045 sk_X509_pop_free(chain, X509_free);
1046 if (cert != NULL)
1047 X509_free(cert);
1048 if (pkey != NULL)
1049 EVP_PKEY_free(pkey);
1050 if (fp != NULL)
1051 Fclose(fp);
1052 NYD_LEAVE;
1053 return rv;
1056 FL FILE *
1057 smime_encrypt(FILE *ip, char const *xcertfile, char const *to)
1059 char *certfile = UNCONST(xcertfile);
1060 FILE *rv = NULL, *yp, *fp, *bp, *hp;
1061 X509 *cert;
1062 PKCS7 *pkcs7;
1063 BIO *bb, *yb;
1064 _STACKOF(X509) *certs;
1065 EVP_CIPHER const *cipher;
1066 bool_t bail = FAL0;
1067 NYD_ENTER;
1069 if ((certfile = file_expand(certfile)) == NULL)
1070 goto jleave;
1072 _ssl_init();
1074 if ((cipher = _smime_cipher(to)) == NULL)
1075 goto jleave;
1076 if ((fp = Fopen(certfile, "r")) == NULL) {
1077 perror(certfile);
1078 goto jleave;
1081 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
1082 ssl_gen_err(tr(547, "Error reading encryption certificate from \"%s\""),
1083 certfile);
1084 bail = TRU1;
1086 Fclose(fp);
1087 if (bail)
1088 goto jleave;
1089 bail = FAL0;
1091 certs = sk_X509_new_null();
1092 sk_X509_push(certs, cert);
1094 if ((yp = Ftmp(NULL, "smimeenc", OF_RDWR | OF_UNLINK | OF_REGISTER, 0600)) ==
1095 NULL) {
1096 perror("tempfile");
1097 goto jleave;
1100 rewind(ip);
1101 if (smime_split(ip, &hp, &bp, -1, 0) == STOP) {
1102 Fclose(yp);
1103 goto jleave;
1106 yb = NULL;
1107 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
1108 (yb = BIO_new_fp(yp, BIO_NOCLOSE)) == NULL) {
1109 ssl_gen_err(tr(548, "Error creating BIO encryption objects"));
1110 bail = TRU1;
1111 goto jerr;
1113 if ((pkcs7 = PKCS7_encrypt(certs, bb, cipher, 0)) == NULL) {
1114 ssl_gen_err(tr(549, "Error creating the PKCS#7 encryption object"));
1115 bail = TRU1;
1116 goto jerr;
1118 if (PEM_write_bio_PKCS7(yb, pkcs7) == 0) {
1119 ssl_gen_err(tr(550, "Error writing encrypted S/MIME data"));
1120 bail = TRU1;
1121 /* goto jerr */
1123 jerr:
1124 if (bb != NULL)
1125 BIO_free(bb);
1126 if (yb != NULL)
1127 BIO_free(yb);
1128 Fclose(bp);
1129 if (bail)
1130 Fclose(yp);
1131 else {
1132 fflush_rewind(yp);
1133 rv = smime_encrypt_assemble(hp, yp);
1135 jleave:
1136 NYD_LEAVE;
1137 return rv;
1140 FL struct message *
1141 smime_decrypt(struct message *m, char const *to, char const *cc, int signcall)
1143 struct message *rv;
1144 FILE *fp, *bp, *hp, *op;
1145 X509 *cert;
1146 PKCS7 *pkcs7;
1147 EVP_PKEY *pkey;
1148 BIO *bb, *pb, *ob;
1149 long size;
1150 FILE *yp;
1151 NYD_ENTER;
1153 rv = NULL;
1154 cert = NULL;
1155 pkey = NULL;
1156 size = m->m_size;
1158 if ((yp = setinput(&mb, m, NEED_BODY)) == NULL)
1159 goto jleave;
1161 _ssl_init();
1163 if ((fp = smime_sign_cert(to, cc, 0)) != NULL) {
1164 pkey = PEM_read_PrivateKey(fp, NULL, &ssl_password_cb, NULL);
1165 if (pkey == NULL) {
1166 ssl_gen_err(tr(551, "Error reading private key"));
1167 Fclose(fp);
1168 goto jleave;
1170 rewind(fp);
1172 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
1173 ssl_gen_err(tr(552, "Error reading decryption certificate"));
1174 Fclose(fp);
1175 EVP_PKEY_free(pkey);
1176 goto jleave;
1178 Fclose(fp);
1181 if ((op = Ftmp(NULL, "smimedec", OF_RDWR | OF_UNLINK | OF_REGISTER, 0600)) ==
1182 NULL) {
1183 perror("tempfile");
1184 goto j_ferr;
1187 if (smime_split(yp, &hp, &bp, size, 1) == STOP)
1188 goto jferr;
1190 if ((ob = BIO_new_fp(op, BIO_NOCLOSE)) == NULL ||
1191 (bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL) {
1192 ssl_gen_err(tr(553, "Error creating BIO decryption objects"));
1193 goto jferr;
1195 if ((pkcs7 = SMIME_read_PKCS7(bb, &pb)) == NULL) {
1196 ssl_gen_err(tr(554, "Error reading PKCS#7 object"));
1197 jferr:
1198 Fclose(op);
1199 j_ferr:
1200 if (cert)
1201 X509_free(cert);
1202 if (pkey)
1203 EVP_PKEY_free(pkey);
1204 goto jleave;
1207 if (PKCS7_type_is_signed(pkcs7)) {
1208 if (signcall) {
1209 setinput(&mb, m, NEED_BODY);
1210 rv = (struct message*)-1;
1211 goto jerr2;
1213 if (PKCS7_verify(pkcs7, NULL, NULL, NULL, ob,
1214 PKCS7_NOVERIFY | PKCS7_NOSIGS) != 1)
1215 goto jerr;
1216 fseek(hp, 0L, SEEK_END);
1217 fprintf(hp, "X-Encryption-Cipher: none\n");
1218 fflush(hp);
1219 rewind(hp);
1220 } else if (pkey == NULL) {
1221 fprintf(stderr, tr(555, "No appropriate private key found.\n"));
1222 goto jerr2;
1223 } else if (cert == NULL) {
1224 fprintf(stderr, tr(556, "No appropriate certificate found.\n"));
1225 goto jerr2;
1226 } else if (PKCS7_decrypt(pkcs7, pkey, cert, ob, 0) != 1) {
1227 jerr:
1228 ssl_gen_err(tr(557, "Error decrypting PKCS#7 object"));
1229 jerr2:
1230 BIO_free(bb);
1231 BIO_free(ob);
1232 Fclose(op);
1233 Fclose(bp);
1234 Fclose(hp);
1235 if (cert != NULL)
1236 X509_free(cert);
1237 if (pkey != NULL)
1238 EVP_PKEY_free(pkey);
1239 goto jleave;
1241 BIO_free(bb);
1242 BIO_free(ob);
1243 if (cert)
1244 X509_free(cert);
1245 if (pkey)
1246 EVP_PKEY_free(pkey);
1247 fflush_rewind(op);
1248 Fclose(bp);
1250 rv = smime_decrypt_assemble(m, hp, op);
1251 jleave:
1252 NYD_LEAVE;
1253 return rv;
1256 FL enum okay
1257 smime_certsave(struct message *m, int n, FILE *op)
1259 struct message *x;
1260 char *to, *cc, *cnttype;
1261 int c, i;
1262 FILE *fp, *ip;
1263 off_t size;
1264 BIO *fb, *pb;
1265 PKCS7 *pkcs7;
1266 _STACKOF(X509) *certs, *chain = NULL;
1267 X509 *cert;
1268 enum okay rv = STOP;
1269 NYD_ENTER;
1271 _ssl_msgno = n;
1272 jloop:
1273 to = hfield1("to", m);
1274 cc = hfield1("cc", m);
1275 cnttype = hfield1("content-type", m);
1276 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
1277 goto jleave;
1278 if (cnttype && !strncmp(cnttype, "application/x-pkcs7-mime", 24)) {
1279 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
1280 goto jleave;
1281 if (x != (struct message*)-1) {
1282 m = x;
1283 goto jloop;
1286 size = m->m_size;
1288 if ((fp = Ftmp(NULL, "smimecert", OF_RDWR | OF_UNLINK | OF_REGISTER, 0600))
1289 == NULL) {
1290 perror("tempfile");
1291 goto jleave;
1294 while (size-- > 0) {
1295 c = getc(ip);
1296 putc(c, fp);
1298 fflush(fp);
1300 rewind(fp);
1301 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
1302 ssl_gen_err("Error creating BIO object for message %d", n);
1303 Fclose(fp);
1304 goto jleave;
1307 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
1308 ssl_gen_err(tr(562, "Error reading PKCS#7 object for message %d"), n);
1309 BIO_free(fb);
1310 Fclose(fp);
1311 goto jleave;
1313 BIO_free(fb);
1314 Fclose(fp);
1316 certs = PKCS7_get0_signers(pkcs7, chain, 0);
1317 if (certs == NULL) {
1318 fprintf(stderr, tr(563, "No certificates found in message %d\n"), n);
1319 goto jleave;
1322 for (i = 0; i < sk_X509_num(certs); ++i) {
1323 cert = sk_X509_value(certs, i);
1324 if (X509_print_fp(op, cert) == 0 || PEM_write_X509(op, cert) == 0) {
1325 ssl_gen_err(tr(564, "Error writing certificate %d from message %d"),
1326 i, n);
1327 goto jleave;
1330 rv = OKAY;
1331 jleave:
1332 NYD_LEAVE;
1333 return rv;
1335 #endif /* HAVE_OPENSSL */
1337 /* vim:set fenc=utf-8:s-it-mode */