Fix reverso in [0cd5c9e]
[s-mailx.git] / openssl.c
blob028c5de773f77286ad8b49c395e124a1fb3701be
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_OPENSSL_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 #ifdef HAVE_OPENSSL_RAND_EGD
169 if ((cp = ok_vlook(ssl_rand_egd)) != NULL) {
170 if ((x = file_expand(cp)) == NULL || RAND_egd(cp = x) == -1)
171 fprintf(stderr, _("entropy daemon at \"%s\" not available\n"),
172 cp);
173 else
174 state = 1;
175 } else
176 #endif
177 if ((cp = ok_vlook(ssl_rand_file)) != NULL) {
178 if ((x = file_expand(cp)) == NULL || RAND_load_file(cp = x, 1024) == -1)
179 fprintf(stderr, _("entropy file at \"%s\" not available\n"), cp);
180 else {
181 struct stat st;
183 if (!stat(cp, &st) && S_ISREG(st.st_mode) && !access(cp, W_OK)) {
184 if (RAND_write_file(cp) == -1) {
185 fprintf(stderr, _(
186 "writing entropy data to \"%s\" failed\n"), cp);
189 state = 1;
192 NYD_LEAVE;
193 return state;
196 static void
197 _ssl_init(void)
199 NYD_ENTER;
200 if (_ssl_isinit == 0) {
201 SSL_library_init();
202 _ssl_isinit = 1;
204 if (_ssl_rand_isinit == 0)
205 _ssl_rand_isinit = _ssl_rand_init();
206 NYD_LEAVE;
209 static bool_t
210 _ssl_parse_asn1_time(ASN1_TIME *atp, char *bdat, size_t blen)
212 /* Shamelessly stolen from CURL */
213 char const *db, *gm;
214 int Y, M, d, h, m, s;
215 bool_t rv;
216 NYD_ENTER;
218 db = (char const*)atp->data;
219 if (atp->length < 10)
220 goto jerr;
222 for (s = 0; s < 10; ++s)
223 if (!digitchar(db[s]))
224 goto jerr;
226 gm = (db[atp->length - 1] == 'Z') ? "GMT" : "";
228 Y = (db[0] - '0') * 10 + (db[1] - '0');
229 if (Y < 50)
230 Y += 100;
231 Y += 1900;
233 M = (db[2] - '0') * 10 + (db[3] - '0');
234 if (M > 12 || M < 1)
235 goto jerr;
237 d = (db[4] - '0') * 10 + (db[5] - '0');
238 h = (db[6] - '0') * 10 + (db[7] - '0');
239 m = (db[8] - '0') * 10 + (db[9] - '0');
240 s = (db[10] >= '0' && db[10] <= '9' && db[11] >= '0' && db[11] <= '9')
241 ? ((db[10] - '0') * 10 + (db[11] - '0')) : 0;
243 snprintf(bdat, blen, "%04d-%02d-%02d %02d:%02d:%02d %s",
244 Y, M, d, h, m, s, gm);
245 rv = TRU1;
246 jleave:
247 NYD_LEAVE;
248 return rv;
249 jerr:
250 snprintf(bdat, blen, _("Bogus certificate date: %.*s\n"),
251 atp->length, db);
252 rv = FAL0;
253 goto jleave;
256 static int
257 _ssl_verify_cb(int success, X509_STORE_CTX *store)
259 char data[256];
260 X509 *cert;
261 int rv = TRU1;
262 NYD_ENTER;
264 if (success && !(options & OPT_VERB))
265 goto jleave;
267 if (_ssl_msgno != 0) {
268 fprintf(stderr, "Message %d:\n", _ssl_msgno);
269 _ssl_msgno = 0;
271 fprintf(stderr, _(" Certificate depth %d %s\n"),
272 X509_STORE_CTX_get_error_depth(store), (success ? "" : _("ERROR")));
274 cert = X509_STORE_CTX_get_current_cert(store);
276 X509_NAME_oneline(X509_get_subject_name(cert), data, sizeof data);
277 fprintf(stderr, _(" subject = %s\n"), data);
279 _ssl_parse_asn1_time(X509_get_notBefore(cert), data, sizeof data);
280 fprintf(stderr, _(" notBefore = %s\n"), data);
282 _ssl_parse_asn1_time(X509_get_notAfter(cert), data, sizeof data);
283 fprintf(stderr, _(" notAfter = %s\n"), data);
285 if (!success) {
286 int err = X509_STORE_CTX_get_error(store);
287 fprintf(stderr, _(" err %i: %s\n"),
288 err, X509_verify_cert_error_string(err));
289 _ssl_verify_error = 1;
292 X509_NAME_oneline(X509_get_issuer_name(cert), data, sizeof data);
293 fprintf(stderr, _(" issuer = %s\n"), data);
295 if (!success && ssl_verify_decide() != OKAY)
296 rv = FAL0;
297 jleave:
298 NYD_LEAVE;
299 return rv;
302 static SSL_METHOD const *
303 ssl_select_method(char const *uhp)
305 SSL_METHOD const *method;
306 char *cp;
307 size_t i;
308 NYD_ENTER;
310 if ((cp = ssl_method_string(uhp)) != NULL) {
311 method = NULL;
312 for (i = 0; i < NELEM(_ssl_methods); ++i)
313 if (!strcmp(_ssl_methods[i].sm_name, cp)) {
314 method = (*_ssl_methods[i].sm_fun)();
315 goto jleave;
317 fprintf(stderr, _("Invalid SSL method \"%s\"\n"), cp);
319 method = _SSL_DEFAULT_METHOD();
320 jleave:
321 NYD_LEAVE;
322 return method;
325 static void
326 ssl_load_verifications(struct sock *sp)
328 char *ca_dir, *ca_file;
329 X509_STORE *store;
330 NYD_ENTER;
332 if (ssl_verify_level == SSL_VERIFY_IGNORE)
333 goto jleave;
335 if ((ca_dir = ok_vlook(ssl_ca_dir)) != NULL)
336 ca_dir = file_expand(ca_dir);
337 if ((ca_file = ok_vlook(ssl_ca_file)) != NULL)
338 ca_file = file_expand(ca_file);
340 if (ca_dir != NULL || ca_file != NULL) {
341 if (SSL_CTX_load_verify_locations(sp->s_ctx, ca_file, ca_dir) != 1) {
342 fprintf(stderr, _("Error loading "));
343 if (ca_dir) {
344 fputs(ca_dir, stderr);
345 if (ca_file)
346 fputs(_(" or "), stderr);
348 if (ca_file)
349 fputs(ca_file, stderr);
350 fputs("\n", stderr);
354 if (!ok_blook(ssl_no_default_ca)) {
355 if (SSL_CTX_set_default_verify_paths(sp->s_ctx) != 1)
356 fprintf(stderr, _("Error loading default CA locations\n"));
359 _ssl_verify_error = 0;
360 _ssl_msgno = 0;
361 SSL_CTX_set_verify(sp->s_ctx, SSL_VERIFY_PEER, &_ssl_verify_cb);
362 store = SSL_CTX_get_cert_store(sp->s_ctx);
363 load_crls(store, ok_v_ssl_crl_file, ok_v_ssl_crl_dir);
364 jleave:
365 NYD_LEAVE;
368 static void
369 ssl_certificate(struct sock *sp, char const *uhp)
371 size_t i;
372 char *certvar, *keyvar, *cert, *key, *x;
373 NYD_ENTER;
375 i = strlen(uhp);
376 certvar = ac_alloc(i + 9 +1);
377 memcpy(certvar, "ssl-cert-", 9);
378 memcpy(certvar + 9, uhp, i +1);
380 if ((cert = vok_vlook(certvar)) != NULL ||
381 (cert = ok_vlook(ssl_cert)) != NULL) {
382 x = cert;
383 if ((cert = file_expand(cert)) == NULL) {
384 cert = x;
385 goto jbcert;
386 } else if (SSL_CTX_use_certificate_chain_file(sp->s_ctx, cert) == 1) {
387 keyvar = ac_alloc(strlen(uhp) + 8 +1);
388 memcpy(keyvar, "ssl-key-", 8);
389 memcpy(keyvar + 8, uhp, i +1);
390 if ((key = vok_vlook(keyvar)) == NULL &&
391 (key = ok_vlook(ssl_key)) == NULL)
392 key = cert;
393 else if ((x = key, key = file_expand(key)) == NULL) {
394 key = x;
395 goto jbkey;
397 if (SSL_CTX_use_PrivateKey_file(sp->s_ctx, key, SSL_FILETYPE_PEM) != 1)
398 jbkey:
399 fprintf(stderr, _("cannot load private key from file %s\n"),
400 key);
401 ac_free(keyvar);
402 } else
403 jbcert:
404 fprintf(stderr, _("cannot load certificate from file %s\n"),
405 cert);
407 ac_free(certvar);
408 NYD_LEAVE;
411 static enum okay
412 ssl_check_host(char const *server, struct sock *sp)
414 char data[256];
415 X509 *cert;
416 X509_NAME *subj;
417 _STACKOF(GENERAL_NAME) *gens;
418 GENERAL_NAME *gen;
419 int i;
420 enum okay rv = STOP;
421 NYD_ENTER;
423 if ((cert = SSL_get_peer_certificate(sp->s_ssl)) == NULL) {
424 fprintf(stderr, _("no certificate from \"%s\"\n"), server);
425 goto jleave;
428 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
429 if (gens != NULL) {
430 for (i = 0; i < sk_GENERAL_NAME_num(gens); ++i) {
431 gen = sk_GENERAL_NAME_value(gens, i);
432 if (gen->type == GEN_DNS) {
433 if (options & OPT_VERB)
434 fprintf(stderr, "Comparing DNS: <%s>; should <%s>\n",
435 server, (char*)gen->d.ia5->data);
436 rv = rfc2595_hostname_match(server, (char*)gen->d.ia5->data);
437 if (rv == OKAY)
438 goto jdone;
443 if ((subj = X509_get_subject_name(cert)) != NULL &&
444 X509_NAME_get_text_by_NID(subj, NID_commonName, data, sizeof data)
445 > 0) {
446 data[sizeof data - 1] = '\0';
447 if (options & OPT_VERB)
448 fprintf(stderr, "Comparing commonName: <%s>; should <%s>\n",
449 server, data);
450 rv = rfc2595_hostname_match(server, data);
452 jdone:
453 X509_free(cert);
454 jleave:
455 NYD_LEAVE;
456 return rv;
459 static int
460 smime_verify(struct message *m, int n, _STACKOF(X509) *chain, X509_STORE *store)
462 char data[LINESIZE], *sender, *to, *cc, *cnttype;
463 int rv, c, i, j;
464 struct message *x;
465 FILE *fp, *ip;
466 off_t size;
467 BIO *fb, *pb;
468 PKCS7 *pkcs7;
469 _STACKOF(X509) *certs;
470 _STACKOF(GENERAL_NAME) *gens;
471 X509 *cert;
472 X509_NAME *subj;
473 GENERAL_NAME *gen;
474 NYD_ENTER;
476 rv = 1;
477 fp = NULL;
478 fb = NULL;
479 _ssl_verify_error = 0;
480 _ssl_msgno = n;
482 for (;;) {
483 sender = getsender(m);
484 to = hfield1("to", m);
485 cc = hfield1("cc", m);
486 cnttype = hfield1("content-type", m);
487 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
488 goto jleave;
489 if (cnttype && !ascncasecmp(cnttype, "application/x-pkcs7-mime", 24)) {
490 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
491 goto jleave;
492 if (x != (struct message*)-1) {
493 m = x;
494 continue;
497 size = m->m_size;
498 break;
501 if ((fp = Ftmp(NULL, "smimever", OF_RDWR | OF_UNLINK | OF_REGISTER, 0600)) ==
502 NULL) {
503 perror("tempfile");
504 goto jleave;
506 while (size-- > 0) {
507 c = getc(ip);
508 putc(c, fp);
510 fflush_rewind(fp);
512 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
513 ssl_gen_err(_(
514 "Error creating BIO verification object for message %d"), n);
515 goto jleave;
518 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
519 ssl_gen_err(_("Error reading PKCS#7 object for message %d"), n);
520 goto jleave;
522 if (PKCS7_verify(pkcs7, chain, store, pb, NULL, 0) != 1) {
523 ssl_gen_err(_("Error verifying message %d"), n);
524 goto jleave;
527 if (sender == NULL) {
528 fprintf(stderr, _("Warning: Message %d has no sender.\n"), n);
529 rv = 0;
530 goto jleave;
533 certs = PKCS7_get0_signers(pkcs7, chain, 0);
534 if (certs == NULL) {
535 fprintf(stderr, _("No certificates found in message %d.\n"), n);
536 goto jleave;
539 for (i = 0; i < sk_X509_num(certs); ++i) {
540 cert = sk_X509_value(certs, i);
541 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
542 if (gens != NULL) {
543 for (j = 0; j < sk_GENERAL_NAME_num(gens); ++j) {
544 gen = sk_GENERAL_NAME_value(gens, j);
545 if (gen->type == GEN_EMAIL) {
546 if (options & OPT_VERB)
547 fprintf(stderr,
548 "Comparing subject_alt_name: <%s>; should <%s>\n",
549 sender, (char*)gen->d.ia5->data);
550 if (!asccasecmp((char*)gen->d.ia5->data, sender))
551 goto jfound;
556 if ((subj = X509_get_subject_name(cert)) != NULL &&
557 X509_NAME_get_text_by_NID(subj, NID_pkcs9_emailAddress,
558 data, sizeof data) > 0) {
559 data[sizeof data -1] = '\0';
560 if (options & OPT_VERB)
561 fprintf(stderr, "Comparing emailAddress: <%s>; should <%s>\n",
562 sender, data);
563 if (!asccasecmp(data, sender))
564 goto jfound;
567 fprintf(stderr, _("Message %d: certificate does not match <%s>\n"),
568 n, sender);
569 goto jleave;
570 jfound:
571 if (_ssl_verify_error == 0)
572 printf(_("Message %d was verified successfully.\n"), n);
573 rv = _ssl_verify_error;
574 jleave:
575 if (fb != NULL)
576 BIO_free(fb);
577 if (fp != NULL)
578 Fclose(fp);
579 NYD_LEAVE;
580 return rv;
583 static EVP_CIPHER const *
584 _smime_cipher(char const *name)
586 EVP_CIPHER const *cipher;
587 char *vn, *cp;
588 size_t i;
589 NYD_ENTER;
591 vn = ac_alloc(i = strlen(name) + 13 +1);
592 snprintf(vn, (int)i, "smime-cipher-%s", name);
593 cp = vok_vlook(vn);
594 ac_free(vn);
596 if (cp != NULL) {
597 cipher = NULL;
598 for (i = 0; i < NELEM(_smime_ciphers); ++i)
599 if (!strcmp(_smime_ciphers[i].sc_name, cp)) {
600 cipher = (*_smime_ciphers[i].sc_fun)();
601 goto jleave;
603 fprintf(stderr, _("Invalid cipher(s): %s\n"), cp);
604 } else
605 cipher = _SMIME_DEFAULT_CIPHER();
606 jleave:
607 NYD_LEAVE;
608 return cipher;
611 static int
612 ssl_password_cb(char *buf, int size, int rwflag, void *userdata)
614 char *pass;
615 size_t len;
616 NYD_ENTER;
617 UNUSED(rwflag);
618 UNUSED(userdata);
620 if ((pass = getpassword("PEM pass phrase:")) != NULL) {
621 len = strlen(pass);
622 if (UICMP(z, len, >=, size))
623 len = size -1;
624 memcpy(buf, pass, len);
625 buf[len] = '\0';
626 } else
627 len = 0;
628 NYD_LEAVE;
629 return (int)len;
632 static FILE *
633 smime_sign_cert(char const *xname, char const *xname2, bool_t dowarn)
635 char *vn, *cp;
636 int vs;
637 struct name *np;
638 char const *name = xname, *name2 = xname2;
639 FILE *fp = NULL;
640 NYD_ENTER;
642 jloop:
643 if (name) {
644 np = lextract(name, GTO | GSKIN);
645 while (np != NULL) {
646 /* This needs to be more intelligent since it will currently take the
647 * first name for which a private key is available regardless of
648 * whether it is the right one for the message */
649 vn = ac_alloc(vs = strlen(np->n_name) + 30);
650 snprintf(vn, vs, "smime-sign-cert-%s", np->n_name);
651 cp = vok_vlook(vn);
652 ac_free(vn);
653 if (cp != NULL)
654 goto jopen;
655 np = np->n_flink;
657 if (name2 != NULL) {
658 name = name2;
659 name2 = NULL;
660 goto jloop;
664 if ((cp = ok_vlook(smime_sign_cert)) == NULL)
665 goto jerr;
666 jopen:
667 if ((cp = file_expand(cp)) == NULL)
668 goto jleave;
669 if ((fp = Fopen(cp, "r")) == NULL)
670 perror(cp);
671 jleave:
672 NYD_LEAVE;
673 return fp;
674 jerr:
675 if (dowarn) {
676 fprintf(stderr, _("Could not find a certificate for %s"), xname);
677 if (xname2)
678 fprintf(stderr, _("or %s"), xname2);
679 fputc('\n', stderr);
681 goto jleave;
684 static char *
685 _smime_sign_include_certs(char const *name)
687 char *rv;
688 NYD_ENTER;
690 /* See comments in smime_sign_cert() for algorithm pitfalls */
691 if (name != NULL) {
692 struct name *np;
694 for (np = lextract(name, GTO | GSKIN); np != NULL; np = np->n_flink) {
695 int vs;
696 char *vn = ac_alloc(vs = strlen(np->n_name) + 30);
697 snprintf(vn, vs, "smime-sign-include-certs-%s", np->n_name);
698 rv = vok_vlook(vn);
699 ac_free(vn);
700 if (rv != NULL)
701 goto jleave;
704 rv = ok_vlook(smime_sign_include_certs);
705 jleave:
706 NYD_LEAVE;
707 return rv;
710 static bool_t
711 _smime_sign_include_chain_creat(_STACKOF(X509) **chain, char const *cfiles)
713 X509 *tmp;
714 FILE *fp;
715 char *nfield, *cfield, *x;
716 NYD_ENTER;
718 *chain = sk_X509_new_null();
720 for (nfield = savestr(cfiles);
721 (cfield = n_strsep(&nfield, ',', TRU1)) != NULL;) {
722 if ((x = file_expand(cfield)) == NULL ||
723 (fp = Fopen(cfield = x, "r")) == NULL) {
724 perror(cfiles);
725 goto jerr;
727 if ((tmp = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
728 ssl_gen_err(_("Error reading certificate from \"%s\""), cfield);
729 Fclose(fp);
730 goto jerr;
732 sk_X509_push(*chain, tmp);
733 Fclose(fp);
736 if (sk_X509_num(*chain) == 0) {
737 fprintf(stderr, _("smime-sign-include-certs defined but empty\n"));
738 goto jerr;
740 jleave:
741 NYD_LEAVE;
742 return (*chain != NULL);
743 jerr:
744 sk_X509_pop_free(*chain, X509_free);
745 *chain = NULL;
746 goto jleave;
749 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
750 static enum okay
751 load_crl1(X509_STORE *store, char const *name)
753 X509_LOOKUP *lookup;
754 enum okay rv = STOP;
755 NYD_ENTER;
757 if (options & OPT_VERB)
758 printf("Loading CRL from \"%s\".\n", name);
759 if ((lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) == NULL) {
760 ssl_gen_err(_("Error creating X509 lookup object"));
761 goto jleave;
763 if (X509_load_crl_file(lookup, name, X509_FILETYPE_PEM) != 1) {
764 ssl_gen_err(_("Error loading CRL from \"%s\""), name);
765 goto jleave;
767 rv = OKAY;
768 jleave:
769 NYD_LEAVE;
770 return rv;
772 #endif /* new OpenSSL */
774 static enum okay
775 load_crls(X509_STORE *store, enum okeys fok, enum okeys dok)
777 char *crl_file, *crl_dir;
778 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
779 DIR *dirp;
780 struct dirent *dp;
781 char *fn = NULL;
782 int fs = 0, ds, es;
783 #endif
784 enum okay rv = STOP;
785 NYD_ENTER;
787 if ((crl_file = _var_oklook(fok)) != NULL) {
788 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
789 if ((crl_file = file_expand(crl_file)) == NULL ||
790 load_crl1(store, crl_file) != OKAY)
791 goto jleave;
792 #else
793 fprintf(stderr, _(
794 "This OpenSSL version is too old to use CRLs.\n"));
795 goto jleave;
796 #endif
799 if ((crl_dir = _var_oklook(dok)) != NULL) {
800 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
801 char *x;
802 if ((x = file_expand(crl_dir)) == NULL ||
803 (dirp = opendir(crl_dir = x)) == NULL) {
804 perror(crl_dir);
805 goto jleave;
808 ds = strlen(crl_dir);
809 fn = smalloc(fs = ds + 20);
810 memcpy(fn, crl_dir, ds);
811 fn[ds] = '/';
812 while ((dp = readdir(dirp)) != NULL) {
813 if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
814 (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
815 continue;
816 if (dp->d_name[0] == '.')
817 continue;
818 if (ds + (es = strlen(dp->d_name)) + 2 < fs)
819 fn = srealloc(fn, fs = ds + es + 20);
820 memcpy(fn + ds + 1, dp->d_name, es + 1);
821 if (load_crl1(store, fn) != OKAY) {
822 closedir(dirp);
823 free(fn);
824 goto jleave;
827 closedir(dirp);
828 free(fn);
829 #else /* old OpenSSL */
830 fprintf(stderr, _(
831 "This OpenSSL version is too old to use CRLs.\n"));
832 goto jleave;
833 #endif
835 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
836 if (crl_file || crl_dir)
837 X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK |
838 X509_V_FLAG_CRL_CHECK_ALL);
839 #endif
840 rv = OKAY;
841 jleave:
842 NYD_LEAVE;
843 return rv;
846 FL enum okay
847 ssl_open(char const *server, struct sock *sp, char const *uhp)
849 char *cp;
850 long opts;
851 enum okay rv = STOP;
852 NYD_ENTER;
854 _ssl_init();
855 ssl_set_verify_level(uhp);
856 if ((sp->s_ctx = SSL_CTX_new(UNCONST(ssl_select_method(uhp)))) == NULL) {
857 ssl_gen_err(_("SSL_CTX_new() failed"));
858 goto jleave;
861 #ifdef SSL_MODE_AUTO_RETRY
862 /* available with OpenSSL 0.9.6 or later */
863 SSL_CTX_set_mode(sp->s_ctx, SSL_MODE_AUTO_RETRY);
864 #endif /* SSL_MODE_AUTO_RETRY */
865 opts = SSL_OP_ALL;
866 if (!ok_blook(ssl_v2_allow))
867 opts |= SSL_OP_NO_SSLv2;
868 SSL_CTX_set_options(sp->s_ctx, opts);
869 ssl_load_verifications(sp);
870 ssl_certificate(sp, uhp);
871 if ((cp = ok_vlook(ssl_cipher_list)) != NULL) {
872 if (SSL_CTX_set_cipher_list(sp->s_ctx, cp) != 1)
873 fprintf(stderr, _("Invalid cipher(s): %s\n"), cp);
876 if ((sp->s_ssl = SSL_new(sp->s_ctx)) == NULL) {
877 ssl_gen_err(_("SSL_new() failed"));
878 goto jleave;
880 SSL_set_fd(sp->s_ssl, sp->s_fd);
881 if (SSL_connect(sp->s_ssl) < 0) {
882 ssl_gen_err(_("could not initiate SSL/TLS connection"));
883 goto jleave;
885 if (ssl_verify_level != SSL_VERIFY_IGNORE) {
886 if (ssl_check_host(server, sp) != OKAY) {
887 fprintf(stderr, _("host certificate does not match \"%s\"\n"),
888 server);
889 if (ssl_verify_decide() != OKAY)
890 goto jleave;
893 sp->s_use_ssl = 1;
894 rv = OKAY;
895 jleave:
896 NYD_LEAVE;
897 return rv;
900 FL void
901 ssl_gen_err(char const *fmt, ...)
903 va_list ap;
904 NYD_ENTER;
906 va_start(ap, fmt);
907 vfprintf(stderr, fmt, ap);
908 va_end(ap);
909 SSL_load_error_strings();
910 fprintf(stderr, ": %s\n", ERR_error_string(ERR_get_error(), NULL));
911 NYD_LEAVE;
914 FL int
915 c_verify(void *vp)
917 int *msgvec = vp, *ip, ec = 0, rv = 1;
918 _STACKOF(X509) *chain = NULL;
919 X509_STORE *store;
920 char *ca_dir, *ca_file;
921 NYD_ENTER;
923 _ssl_init();
925 ssl_verify_level = SSL_VERIFY_STRICT;
926 if ((store = X509_STORE_new()) == NULL) {
927 ssl_gen_err(_("Error creating X509 store"));
928 goto jleave;
930 X509_STORE_set_verify_cb_func(store, &_ssl_verify_cb);
932 if ((ca_dir = ok_vlook(smime_ca_dir)) != NULL)
933 ca_dir = file_expand(ca_dir);
934 if ((ca_file = ok_vlook(smime_ca_file)) != NULL)
935 ca_file = file_expand(ca_file);
937 if (ca_dir != NULL || ca_file != NULL) {
938 if (X509_STORE_load_locations(store, ca_file, ca_dir) != 1) {
939 ssl_gen_err(_("Error loading %s"),
940 (ca_file != NULL) ? ca_file : ca_dir);
941 goto jleave;
944 if (!ok_blook(smime_no_default_ca)) {
945 if (X509_STORE_set_default_paths(store) != 1) {
946 ssl_gen_err(_("Error loading default CA locations"));
947 goto jleave;
951 if (load_crls(store, ok_v_smime_crl_file, ok_v_smime_crl_dir) != OKAY)
952 goto jleave;
953 for (ip = msgvec; *ip != 0; ++ip) {
954 struct message *mp = message + *ip - 1;
955 setdot(mp);
956 ec |= smime_verify(mp, *ip, chain, store);
958 if ((rv = ec) != 0)
959 exit_status |= EXIT_ERR;
960 jleave:
961 NYD_LEAVE;
962 return rv;
965 FL FILE *
966 smime_sign(FILE *ip, char const *addr)
968 FILE *rv = NULL, *sp = NULL, *fp = NULL, *bp, *hp;
969 X509 *cert = NULL;
970 _STACKOF(X509) *chain = NULL;
971 PKCS7 *pkcs7;
972 EVP_PKEY *pkey = NULL;
973 BIO *bb, *sb;
974 bool_t bail = FAL0;
975 NYD_ENTER;
977 _ssl_init();
979 if (addr == NULL) {
980 fprintf(stderr, _("No \"from\" address for signing specified\n"));
981 goto jleave;
983 if ((fp = smime_sign_cert(addr, NULL, 1)) == NULL)
984 goto jleave;
986 if ((pkey = PEM_read_PrivateKey(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
987 ssl_gen_err(_("Error reading private key from"));
988 goto jleave;
991 rewind(fp);
992 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
993 ssl_gen_err(_("Error reading signer certificate from"));
994 goto jleave;
996 Fclose(fp);
997 fp = NULL;
999 if ((addr = _smime_sign_include_certs(addr)) != NULL &&
1000 !_smime_sign_include_chain_creat(&chain, addr))
1001 goto jleave;
1003 if ((sp = Ftmp(NULL, "smimesign", OF_RDWR | OF_UNLINK | OF_REGISTER, 0600))
1004 == NULL) {
1005 perror("tempfile");
1006 goto jleave;
1009 rewind(ip);
1010 if (smime_split(ip, &hp, &bp, -1, 0) == STOP) {
1011 bail = TRU1;
1012 goto jerr1;
1015 sb = NULL;
1016 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
1017 (sb = BIO_new_fp(sp, BIO_NOCLOSE)) == NULL) {
1018 ssl_gen_err(_("Error creating BIO signing objects"));
1019 bail = TRU1;
1020 goto jerr;
1023 if ((pkcs7 = PKCS7_sign(cert, pkey, chain, bb, PKCS7_DETACHED)) == NULL) {
1024 ssl_gen_err(_("Error creating the PKCS#7 signing object"));
1025 bail = TRU1;
1026 goto jerr;
1028 if (PEM_write_bio_PKCS7(sb, pkcs7) == 0) {
1029 ssl_gen_err(_("Error writing signed S/MIME data"));
1030 bail = TRU1;
1031 /*goto jerr*/
1033 jerr:
1034 if (sb != NULL)
1035 BIO_free(sb);
1036 if (bb != NULL)
1037 BIO_free(bb);
1038 if (!bail) {
1039 rewind(bp);
1040 fflush_rewind(sp);
1041 rv = smime_sign_assemble(hp, bp, sp);
1042 } else
1043 jerr1:
1044 Fclose(sp);
1046 jleave:
1047 if (chain != NULL)
1048 sk_X509_pop_free(chain, X509_free);
1049 if (cert != NULL)
1050 X509_free(cert);
1051 if (pkey != NULL)
1052 EVP_PKEY_free(pkey);
1053 if (fp != NULL)
1054 Fclose(fp);
1055 NYD_LEAVE;
1056 return rv;
1059 FL FILE *
1060 smime_encrypt(FILE *ip, char const *xcertfile, char const *to)
1062 char *certfile = UNCONST(xcertfile);
1063 FILE *rv = NULL, *yp, *fp, *bp, *hp;
1064 X509 *cert;
1065 PKCS7 *pkcs7;
1066 BIO *bb, *yb;
1067 _STACKOF(X509) *certs;
1068 EVP_CIPHER const *cipher;
1069 bool_t bail = FAL0;
1070 NYD_ENTER;
1072 if ((certfile = file_expand(certfile)) == NULL)
1073 goto jleave;
1075 _ssl_init();
1077 if ((cipher = _smime_cipher(to)) == NULL)
1078 goto jleave;
1079 if ((fp = Fopen(certfile, "r")) == NULL) {
1080 perror(certfile);
1081 goto jleave;
1084 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
1085 ssl_gen_err(_("Error reading encryption certificate from \"%s\""),
1086 certfile);
1087 bail = TRU1;
1089 Fclose(fp);
1090 if (bail)
1091 goto jleave;
1092 bail = FAL0;
1094 certs = sk_X509_new_null();
1095 sk_X509_push(certs, cert);
1097 if ((yp = Ftmp(NULL, "smimeenc", OF_RDWR | OF_UNLINK | OF_REGISTER, 0600)) ==
1098 NULL) {
1099 perror("tempfile");
1100 goto jleave;
1103 rewind(ip);
1104 if (smime_split(ip, &hp, &bp, -1, 0) == STOP) {
1105 Fclose(yp);
1106 goto jleave;
1109 yb = NULL;
1110 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
1111 (yb = BIO_new_fp(yp, BIO_NOCLOSE)) == NULL) {
1112 ssl_gen_err(_("Error creating BIO encryption objects"));
1113 bail = TRU1;
1114 goto jerr;
1116 if ((pkcs7 = PKCS7_encrypt(certs, bb, cipher, 0)) == NULL) {
1117 ssl_gen_err(_("Error creating the PKCS#7 encryption object"));
1118 bail = TRU1;
1119 goto jerr;
1121 if (PEM_write_bio_PKCS7(yb, pkcs7) == 0) {
1122 ssl_gen_err(_("Error writing encrypted S/MIME data"));
1123 bail = TRU1;
1124 /* goto jerr */
1126 jerr:
1127 if (bb != NULL)
1128 BIO_free(bb);
1129 if (yb != NULL)
1130 BIO_free(yb);
1131 Fclose(bp);
1132 if (bail)
1133 Fclose(yp);
1134 else {
1135 fflush_rewind(yp);
1136 rv = smime_encrypt_assemble(hp, yp);
1138 jleave:
1139 NYD_LEAVE;
1140 return rv;
1143 FL struct message *
1144 smime_decrypt(struct message *m, char const *to, char const *cc, int signcall)
1146 struct message *rv;
1147 FILE *fp, *bp, *hp, *op;
1148 X509 *cert;
1149 PKCS7 *pkcs7;
1150 EVP_PKEY *pkey;
1151 BIO *bb, *pb, *ob;
1152 long size;
1153 FILE *yp;
1154 NYD_ENTER;
1156 rv = NULL;
1157 cert = NULL;
1158 pkey = NULL;
1159 size = m->m_size;
1161 if ((yp = setinput(&mb, m, NEED_BODY)) == NULL)
1162 goto jleave;
1164 _ssl_init();
1166 if ((fp = smime_sign_cert(to, cc, 0)) != NULL) {
1167 pkey = PEM_read_PrivateKey(fp, NULL, &ssl_password_cb, NULL);
1168 if (pkey == NULL) {
1169 ssl_gen_err(_("Error reading private key"));
1170 Fclose(fp);
1171 goto jleave;
1173 rewind(fp);
1175 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
1176 ssl_gen_err(_("Error reading decryption certificate"));
1177 Fclose(fp);
1178 EVP_PKEY_free(pkey);
1179 goto jleave;
1181 Fclose(fp);
1184 if ((op = Ftmp(NULL, "smimedec", OF_RDWR | OF_UNLINK | OF_REGISTER, 0600)) ==
1185 NULL) {
1186 perror("tempfile");
1187 goto j_ferr;
1190 if (smime_split(yp, &hp, &bp, size, 1) == STOP)
1191 goto jferr;
1193 if ((ob = BIO_new_fp(op, BIO_NOCLOSE)) == NULL ||
1194 (bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL) {
1195 ssl_gen_err(_("Error creating BIO decryption objects"));
1196 goto jferr;
1198 if ((pkcs7 = SMIME_read_PKCS7(bb, &pb)) == NULL) {
1199 ssl_gen_err(_("Error reading PKCS#7 object"));
1200 jferr:
1201 Fclose(op);
1202 j_ferr:
1203 if (cert)
1204 X509_free(cert);
1205 if (pkey)
1206 EVP_PKEY_free(pkey);
1207 goto jleave;
1210 if (PKCS7_type_is_signed(pkcs7)) {
1211 if (signcall) {
1212 setinput(&mb, m, NEED_BODY);
1213 rv = (struct message*)-1;
1214 goto jerr2;
1216 if (PKCS7_verify(pkcs7, NULL, NULL, NULL, ob,
1217 PKCS7_NOVERIFY | PKCS7_NOSIGS) != 1)
1218 goto jerr;
1219 fseek(hp, 0L, SEEK_END);
1220 fprintf(hp, "X-Encryption-Cipher: none\n");
1221 fflush(hp);
1222 rewind(hp);
1223 } else if (pkey == NULL) {
1224 fprintf(stderr, _("No appropriate private key found.\n"));
1225 goto jerr2;
1226 } else if (cert == NULL) {
1227 fprintf(stderr, _("No appropriate certificate found.\n"));
1228 goto jerr2;
1229 } else if (PKCS7_decrypt(pkcs7, pkey, cert, ob, 0) != 1) {
1230 jerr:
1231 ssl_gen_err(_("Error decrypting PKCS#7 object"));
1232 jerr2:
1233 BIO_free(bb);
1234 BIO_free(ob);
1235 Fclose(op);
1236 Fclose(bp);
1237 Fclose(hp);
1238 if (cert != NULL)
1239 X509_free(cert);
1240 if (pkey != NULL)
1241 EVP_PKEY_free(pkey);
1242 goto jleave;
1244 BIO_free(bb);
1245 BIO_free(ob);
1246 if (cert)
1247 X509_free(cert);
1248 if (pkey)
1249 EVP_PKEY_free(pkey);
1250 fflush_rewind(op);
1251 Fclose(bp);
1253 rv = smime_decrypt_assemble(m, hp, op);
1254 jleave:
1255 NYD_LEAVE;
1256 return rv;
1259 FL enum okay
1260 smime_certsave(struct message *m, int n, FILE *op)
1262 struct message *x;
1263 char *to, *cc, *cnttype;
1264 int c, i;
1265 FILE *fp, *ip;
1266 off_t size;
1267 BIO *fb, *pb;
1268 PKCS7 *pkcs7;
1269 _STACKOF(X509) *certs, *chain = NULL;
1270 X509 *cert;
1271 enum okay rv = STOP;
1272 NYD_ENTER;
1274 _ssl_msgno = n;
1275 jloop:
1276 to = hfield1("to", m);
1277 cc = hfield1("cc", m);
1278 cnttype = hfield1("content-type", m);
1279 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
1280 goto jleave;
1281 if (cnttype && !strncmp(cnttype, "application/x-pkcs7-mime", 24)) {
1282 if ((x = smime_decrypt(m, to, cc, 1)) == NULL)
1283 goto jleave;
1284 if (x != (struct message*)-1) {
1285 m = x;
1286 goto jloop;
1289 size = m->m_size;
1291 if ((fp = Ftmp(NULL, "smimecert", OF_RDWR | OF_UNLINK | OF_REGISTER, 0600))
1292 == NULL) {
1293 perror("tempfile");
1294 goto jleave;
1297 while (size-- > 0) {
1298 c = getc(ip);
1299 putc(c, fp);
1301 fflush(fp);
1303 rewind(fp);
1304 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
1305 ssl_gen_err("Error creating BIO object for message %d", n);
1306 Fclose(fp);
1307 goto jleave;
1310 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
1311 ssl_gen_err(_("Error reading PKCS#7 object for message %d"), n);
1312 BIO_free(fb);
1313 Fclose(fp);
1314 goto jleave;
1316 BIO_free(fb);
1317 Fclose(fp);
1319 certs = PKCS7_get0_signers(pkcs7, chain, 0);
1320 if (certs == NULL) {
1321 fprintf(stderr, _("No certificates found in message %d\n"), n);
1322 goto jleave;
1325 for (i = 0; i < sk_X509_num(certs); ++i) {
1326 cert = sk_X509_value(certs, i);
1327 if (X509_print_fp(op, cert) == 0 || PEM_write_X509(op, cert) == 0) {
1328 ssl_gen_err(_("Error writing certificate %d from message %d"),
1329 i, n);
1330 goto jleave;
1333 rv = OKAY;
1334 jleave:
1335 NYD_LEAVE;
1336 return rv;
1338 #endif /* HAVE_OPENSSL */
1340 /* s-it-mode */