THANKS: Coverity.com (overdue)
[s-mailx.git] / src / mx / xtls.c
blob7e244a56b9e56ef2ec4d6c646fb3011a318b64b7
1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ OpenSSL client implementation according to: John Viega, Matt Messier,
3 *@ Pravir Chandra: Network Security with OpenSSL. Sebastopol, CA 2002.
5 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
6 * Copyright (c) 2012 - 2020 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
7 * SPDX-License-Identifier: BSD-4-Clause TODO ISC
8 */
9 /*
10 * Copyright (c) 2002
11 * Gunnar Ritter. All rights reserved.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgement:
23 * This product includes software developed by Gunnar Ritter
24 * and his contributors.
25 * 4. Neither the name of Gunnar Ritter nor the names of his contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY GUNNAR RITTER AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL GUNNAR RITTER OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * SUCH DAMAGE.
41 #undef su_FILE
42 #define su_FILE xtls
43 #define mx_SOURCE
45 #ifndef mx_HAVE_AMALGAMATION
46 # include "mx/nail.h"
47 #endif
49 su_EMPTY_FILE()
50 #ifdef mx_HAVE_XTLS /* Shorthand for mx_HAVE_TLS==mx_TLS_IMPL{...} */
51 #include <sys/socket.h>
53 #include <openssl/crypto.h>
54 #include <openssl/err.h>
55 #include <openssl/evp.h>
56 #include <openssl/opensslv.h>
57 #include <openssl/pem.h>
58 #include <openssl/rand.h>
59 #include <openssl/ssl.h>
60 #include <openssl/x509v3.h>
61 #include <openssl/x509.h>
63 #ifdef mx_XTLS_HAVE_CONFIG
64 # include <openssl/conf.h>
65 #endif
66 #ifdef mx_XTLS_HAVE_SET_RESEED_DEFAULTS
67 # include <openssl/rand_drbg.h>
68 #endif
70 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
71 # include <dirent.h>
72 #endif
74 #include <su/cs.h>
75 #include <su/mem.h>
77 #include "mx/cred-auth.h"
78 #include "mx/file-streams.h"
79 #include "mx/names.h"
80 #include "mx/net-socket.h"
81 #include "mx/random.h"
82 #include "mx/tty.h"
83 #include "mx/url.h"
85 /* TODO fake */
86 #include "su/code-in.h"
88 /* Compatibility shims which assume 0/-1 cannot really happen */
89 /* Always for _protocols #ifndef mx_XTLS_HAVE_CONF_CTX */
90 # ifndef SSL_OP_NO_SSLv2
91 # define SSL_OP_NO_SSLv2 0
92 # endif
93 # ifndef SSL_OP_NO_SSLv3
94 # define SSL_OP_NO_SSLv3 0
95 # endif
96 # ifndef SSL_OP_NO_TLSv1
97 # define SSL_OP_NO_TLSv1 0
98 # endif
99 # ifndef SSL_OP_NO_TLSv1_1
100 # define SSL_OP_NO_TLSv1_1 0
101 # endif
102 # ifndef SSL_OP_NO_TLSv1_2
103 # define SSL_OP_NO_TLSv1_2 0
104 # endif
105 # ifndef SSL_OP_NO_TLSv1_3
106 # define SSL_OP_NO_TLSv1_3 0
107 # endif
108 /* SSL_CONF_CTX and _OP_NO_SSL_MASK were both introduced with 1.0.2!?! */
109 # ifndef SSL_OP_NO_SSL_MASK
110 # define SSL_OP_NO_SSL_MASK \
111 ( SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | \
112 SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2 | \
113 SSL_OP_NO_TLSv1_3 )
114 # endif
116 CTA(SSL_OP_NO_SSL_MASK != 0,
117 "One of _SSLv[23], _TLSv1, _TLSv1_[123] is needed");
119 # ifndef SSL2_VERSION
120 # define SSL2_VERSION 0
121 # endif
122 # ifndef SSL3_VERSION
123 # define SSL3_VERSION 0
124 # endif
125 # ifndef TLS1_VERSION
126 # define TLS1_VERSION 0
127 # endif
128 # ifndef TLS1_1_VERSION
129 # define TLS1_1_VERSION 0
130 # endif
131 # ifndef TLS1_2_VERSION
132 # define TLS1_2_VERSION 0
133 # endif
134 # ifndef TLS1_3_VERSION
135 # define TLS1_3_VERSION 0
136 # endif
137 /* #endif */
139 #ifdef mx_XTLS_HAVE_STACK_OF
140 # define a_XTLS_STACKOF(X) STACK_OF(X)
141 #else
142 # define a_XTLS_STACKOF(X) /*X*/STACK
143 #endif
145 #ifdef mx_XTLS_HAVE_RAND_FILE
146 # if OPENSSL_VERSION_NUMBER + 0 >= 0x0090581fL
147 # define a_XTLS_RAND_LOAD_FILE_MAXBYTES -1
148 # else
149 # define a_XTLS_RAND_LOAD_FILE_MAXBYTES 1024
150 # endif
151 #endif
153 /* More cute compatibility sighs */
154 #if mx_HAVE_XTLS >= 0x10100
155 # define a_xtls_X509_get_notBefore X509_get0_notBefore
156 # define a_xtls_X509_get_notAfter X509_get0_notAfter
157 # define a_xtls_SSL_get_verified_chain SSL_get0_verified_chain
158 #else
159 # define a_xtls_X509_get_notBefore X509_get_notBefore
160 # define a_xtls_X509_get_notAfter X509_get_notAfter
161 # define a_xtls_SSL_get_verified_chain SSL_get_peer_cert_chain
162 #endif
164 #if mx_HAVE_XTLS >= 0x30000
165 /* OpenSSL 3.0: algorithm providers are dynamic and lazily resolved,
166 * so anything "implicitly fetched" (crypto(7)) may fail later on.
167 * As pre 3.0.0 was only "implicit" it is a complicated backward-incompat-
168 * ible mess (internal lazy fetching is then a single line of code) */
169 # define a_XTLS_CRYPTO_FETCH
170 # define a_XTLS__NFETCH_INJ(X)
171 # define a_XTLS__JFETCH jfetch
173 # define a_xtls_SSL_CTX_load_verify_file(CTXP,FILE) \
174 SSL_CTX_load_verify_file(CTXP, FILE)
175 # define a_xtls_SSL_CTX_load_verify_dir(CTXP,DIR) \
176 SSL_CTX_load_verify_dir(ctxp, ca_dir)
178 # define a_xtls_X509_STORE_load_file(STORE,FILE) \
179 X509_STORE_load_file(STORE, FILE)
180 # define a_xtls_X509_STORE_load_path(STORE,PATH) \
181 X509_STORE_load_path(STORE, PATH)
183 # define a_xtls_SSL_get_peer_certificate(TLSP) \
184 SSL_get0_peer_certificate(TLSP)
185 # define a_xtls_SSL_get_peer_certificate__FREE(CERT)
187 #else
188 # undef a_XTLS_CRYPTO_FETCH
189 # define a_XTLS__NFETCH_INJ(X) X
190 # define a_XTLS__JFETCH jleave
192 # define a_xtls_SSL_CTX_load_verify_file(CTXP,FILE) \
193 SSL_CTX_load_verify_locations(CTXP, FILE, NIL)
194 # define a_xtls_SSL_CTX_load_verify_dir(CTXP,DIR) \
195 SSL_CTX_load_verify_locations(CTXP, NIL, DIR)
197 # define a_xtls_X509_STORE_load_file(STORE,FILE) \
198 X509_STORE_load_locations(STORE, FILE, NIL)
199 # define a_xtls_X509_STORE_load_path(STORE,PATH) \
200 X509_STORE_load_locations(STORE, NIL, PATH)
202 # define a_xtls_SSL_get_peer_certificate(TLSP) \
203 SSL_get_peer_certificate(TLSP)
204 # define a_xtls_SSL_get_peer_certificate__FREE(CERT) \
205 X509_free(CERT)
206 #endif /* mx_HAVE_XTLS >= 0x30000 */
208 /* X509_STORE_set_flags */
209 #undef a_XTLS_X509_V_ANY
210 #ifndef X509_V_FLAG_NO_ALT_CHAINS
211 # define X509_V_FLAG_NO_ALT_CHAINS -1
212 #else
213 # undef a_XTLS_X509_V_ANY
214 # define a_XTLS_X509_V_ANY
215 #endif
216 #ifndef X509_V_FLAG_NO_CHECK_TIME
217 # define X509_V_FLAG_NO_CHECK_TIME -1
218 #else
219 # undef a_XTLS_X509_V_ANY
220 # define a_XTLS_X509_V_ANY
221 #endif
222 #ifndef X509_V_FLAG_PARTIAL_CHAIN
223 # define X509_V_FLAG_PARTIAL_CHAIN -1
224 #else
225 # undef a_XTLS_X509_V_ANY
226 # define a_XTLS_X509_V_ANY
227 #endif
228 #ifndef X509_V_FLAG_X509_STRICT
229 # define X509_V_FLAG_X509_STRICT -1
230 #else
231 # undef a_XTLS_X509_V_ANY
232 # define a_XTLS_X509_V_ANY
233 #endif
234 #ifndef X509_V_FLAG_TRUSTED_FIRST
235 # define X509_V_FLAG_TRUSTED_FIRST -1
236 #else
237 # undef a_XTLS_X509_V_ANY
238 # define a_XTLS_X509_V_ANY
239 #endif
241 enum a_xtls_state{
242 a_XTLS_S_INIT = 1u<<0,
243 a_XTLS_S_RAND_DRBG_INIT = 1u<<1,
244 a_XTLS_S_RAND_INIT = 1u<<2,
245 a_XTLS_S_CONF_LOAD = 1u<<3,
247 #if mx_HAVE_XTLS < 0x10100
248 a_XTLS_S_EXIT_HDL = 1u<<8,
249 a_XTLS_S_ALGO_LOAD = 1u<<9,
250 #endif
252 a_XTLS_S_VERIFY_ERROR = 1u<<16
255 struct ssl_method { /* TODO v15 obsolete */
256 char const sm_name[8];
257 char const sm_map[16];
260 struct a_xtls_protocol{
261 char const xp_name[8];
262 sl xp_op_no; /* SSL_OP_NO_* bit */
263 u16 xp_version; /* *_VERSION number */
264 boole xp_ok_minmaxproto; /* Valid for {Min,Max}Protocol= */
265 boole xp_ok_proto; /* Valid for Protocol= */
266 boole xp_last;
267 boole xp_is_all; /* The special "ALL" */
268 u8 xp__dummy[2];
271 struct a_xtls_cipher{
272 char const xc_name[8];
273 EVP_CIPHER const *(*xc_fun)(void);
276 struct a_xtls_digest{
277 char const xd_name[16];
278 EVP_MD const *(*xd_fun)(void);
281 struct a_xtls_x509_v_flags{
282 char const xxvf_name[20];
283 s32 xxvf_flag;
286 /* Supported SSL/TLS methods: update manual on change! */
287 static struct ssl_method const _ssl_methods[] = { /* TODO obsolete */
288 {"auto", "ALL,-SSLv2"},
289 {"ssl3", "-ALL,SSLv3"},
290 {"tls1", "-ALL,TLSv1"},
291 {"tls1.1", "-ALL,TLSv1.1"},
292 {"tls1.2", "-ALL,TLSv1.2"}
295 /* Update manual on change!
296 * Ensure array size by adding \0 to longest entry.
297 * Strictly to be sorted new/up to old/down, [0]=ALL, [x-1]=None! */
298 static struct a_xtls_protocol const a_xtls_protocols[] = {
299 {"ALL", SSL_OP_NO_SSL_MASK, 0, FAL0, TRU1, FAL0, TRU1, {0}},
300 {"TLSv1.3\0", SSL_OP_NO_TLSv1_3, TLS1_3_VERSION, TRU1,TRU1,FAL0,FAL0,{0}},
301 {"TLSv1.2", SSL_OP_NO_TLSv1_2, TLS1_2_VERSION, TRU1, TRU1, FAL0, FAL0, {0}},
302 {"TLSv1.1", SSL_OP_NO_TLSv1_1, TLS1_1_VERSION, TRU1, TRU1, FAL0, FAL0, {0}},
303 {"TLSv1", SSL_OP_NO_TLSv1, TLS1_VERSION, TRU1, TRU1, FAL0, FAL0, {0}},
304 {"SSLv3", SSL_OP_NO_SSLv3, SSL3_VERSION, TRU1, TRU1, FAL0, FAL0, {0}},
305 {"SSLv2", SSL_OP_NO_SSLv2, SSL2_VERSION, TRU1, TRU1, FAL0, FAL0, {0}},
306 {"None", SSL_OP_NO_SSL_MASK, 0, TRU1, FAL0, TRU1, FAL0, {0}}
309 /* Supported S/MIME cipher algorithms */
310 static struct a_xtls_cipher const a_xtls_ciphers[] = { /*Manual!*/
311 #ifndef OPENSSL_NO_AES
312 # define a_XTLS_SMIME_DEFAULT_CIPHER EVP_aes_128_cbc /* According RFC 5751 */
313 # define a_XTLS_SMIME_DEFAULT_CIPHER_S "AES128"
314 {"AES128", &EVP_aes_128_cbc},
315 {"AES256", &EVP_aes_256_cbc},
316 {"AES192", &EVP_aes_192_cbc},
317 #endif
318 #ifndef OPENSSL_NO_DES
319 # ifndef a_XTLS_SMIME_DEFAULT_CIPHER
320 # define a_XTLS_SMIME_DEFAULT_CIPHER EVP_des_ede3_cbc
321 # define a_XTLS_SMIME_DEFAULT_CIPHER_S "DES3"
322 # endif
323 {"DES3", &EVP_des_ede3_cbc},
324 {"DES", &EVP_des_cbc},
325 #endif
327 #ifndef a_XTLS_SMIME_DEFAULT_CIPHER
328 # error Your OpenSSL library does not include the necessary
329 # error cipher algorithms that are required to support S/MIME
330 #endif
332 #ifndef OPENSSL_NO_AES
333 /* TODO obsolete a_xtls_smime_ciphers_obs */
334 static struct a_xtls_cipher const a_xtls_smime_ciphers_obs[] = {
335 {"AES-128", &EVP_aes_128_cbc},
336 {"AES-256", &EVP_aes_256_cbc},
337 {"AES-192", &EVP_aes_192_cbc}
339 #endif
341 /* Supported S/MIME message digest algorithms.
342 * Update manual on default changes! */
343 static struct a_xtls_digest const a_xtls_digests[] = { /*Manual!*/
344 #ifdef mx_XTLS_HAVE_BLAKE2
345 {"BLAKE2b512\0", &EVP_blake2b512},
346 {"BLAKE2s256", &EVP_blake2s256},
347 # ifndef a_XTLS_FINGERPRINT_DEFAULT_DIGEST
348 # define a_XTLS_FINGERPRINT_DEFAULT_DIGEST EVP_blake2s256
349 # define a_XTLS_FINGERPRINT_DEFAULT_DIGEST_S "BLAKE2s256"
350 # endif
351 #endif
353 #ifdef mx_XTLS_HAVE_SHA3
354 {"SHA3-512\0", &EVP_sha3_512},
355 {"SHA3-384", &EVP_sha3_384},
356 {"SHA3-256", &EVP_sha3_256},
357 {"SHA3-224", &EVP_sha3_224},
358 #endif
360 #ifndef OPENSSL_NO_SHA512
361 {"SHA512\0", &EVP_sha512},
362 {"SHA384", &EVP_sha384},
363 # ifndef a_XTLS_SMIME_DEFAULT_DIGEST
364 # define a_XTLS_SMIME_DEFAULT_DIGEST EVP_sha512
365 # define a_XTLS_SMIME_DEFAULT_DIGEST_S "SHA512"
366 # endif
367 #endif
369 #ifndef OPENSSL_NO_SHA256
370 {"SHA256\0", &EVP_sha256},
371 {"SHA224", &EVP_sha224},
372 # ifndef a_XTLS_SMIME_DEFAULT_DIGEST
373 # define a_XTLS_SMIME_DEFAULT_DIGEST EVP_sha256
374 # define a_XTLS_SMIME_DEFAULT_DIGEST_S "SHA256"
375 # endif
376 # ifndef a_XTLS_FINGERPRINT_DEFAULT_DIGEST
377 # define a_XTLS_FINGERPRINT_DEFAULT_DIGEST EVP_sha256
378 # define a_XTLS_FINGERPRINT_DEFAULT_DIGEST_S "SHA256"
379 # endif
380 #endif
382 #ifndef OPENSSL_NO_SHA
383 {"SHA1\0", &EVP_sha1},
384 # ifndef a_XTLS_SMIME_DEFAULT_DIGEST
385 # define a_XTLS_SMIME_DEFAULT_DIGEST EVP_sha1
386 # define a_XTLS_SMIME_DEFAULT_DIGEST_S "SHA1"
387 # endif
388 # ifndef a_XTLS_FINGERPRINT_DEFAULT_DIGEST
389 # define a_XTLS_FINGERPRINT_DEFAULT_DIGEST EVP_sha1
390 # define a_XTLS_FINGERPRINT_DEFAULT_DIGEST_S "SHA1"
391 # endif
392 #endif
394 #ifndef OPENSSL_NO_MD5
395 {"MD5\0", &EVP_md5},
396 #endif
399 #if !defined a_XTLS_SMIME_DEFAULT_DIGEST || \
400 !defined a_XTLS_FINGERPRINT_DEFAULT_DIGEST
401 # error Not enough supported message digest algorithms available
402 #endif
404 /* X509_STORE_set_flags() for *{smime,ssl}-ca-flags* */
405 static struct a_xtls_x509_v_flags const a_xtls_x509_v_flags[] = { /* Manual! */
406 {"no-alt-chains", X509_V_FLAG_NO_ALT_CHAINS},
407 {"no-check-time", X509_V_FLAG_NO_CHECK_TIME},
408 {"partial-chain", X509_V_FLAG_PARTIAL_CHAIN},
409 {"strict", X509_V_FLAG_X509_STRICT},
410 {"trusted-first", X509_V_FLAG_TRUSTED_FIRST},
413 static uz a_xtls_state;
414 static uz a_xtls_msgno;
416 /* Special pre-PRNG PRNG init */
417 #ifdef mx_XTLS_HAVE_SET_RESEED_DEFAULTS
418 SINLINE void a_xtls_rand_drbg_init(void);
419 #else
420 # define a_xtls_rand_drbg_init() \
421 do {a_xtls_state |= a_XTLS_S_RAND_DRBG_INIT;} while(0)
422 #endif
424 /* PRNG init */
425 #ifdef mx_XTLS_HAVE_RAND_FILE
426 static void a_xtls_rand_init(void);
427 #else
428 # define a_xtls_rand_init() \
429 do {a_xtls_state |= a_XTLS_S_RAND_INIT;} while(0)
430 #endif
432 /* Library init */
433 static void a_xtls_init(void);
435 #if mx_HAVE_XTLS < 0x10100
436 # ifdef mx_HAVE_TLS_ALL_ALGORITHMS
437 static void a_xtls__load_algos(void);
438 # define a_xtls_load_algos a_xtls__load_algos
439 # endif
440 # if defined mx_XTLS_HAVE_CONFIG || defined mx_HAVE_TLS_ALL_ALGORITHMS
441 static void a_xtls_atexit(void);
442 # endif
443 #endif
444 #ifndef a_xtls_load_algos
445 # define a_xtls_load_algos() do{;}while(0)
446 #endif
448 static boole a_xtls_parse_asn1_time(ASN1_TIME const *atp,
449 char *bdat, uz blen);
450 static int a_xtls_verify_cb(int success, X509_STORE_CTX *store);
452 static boole a_xtls_digest_find(boole fingerprint, char const *name,
453 EVP_MD const **mdp, char const **normalized_name_or_nil, boole *freeit);
455 /* *smime-ca-flags*, *tls-ca-flags* */
456 static void a_xtls_ca_flags(X509_STORE *store, char const *flags);
458 /* SSL_CTX configuration; the latter always NULLs *confp */
459 static void *a_xtls_conf_setup(SSL_CTX *ctxp, struct mx_url const *urlp);
460 static boole a_xtls_conf(void *confp, char const *cmd, char const *value);
461 static boole a_xtls_conf_finish(void **confp, boole error);
463 static boole a_xtls_obsolete_conf_vars(void *confp, struct mx_url const *urlp);
464 static boole a_xtls_config_pairs(void *confp, struct mx_url const *urlp);
465 static boole a_xtls_load_verifications(SSL_CTX *ctxp,
466 struct mx_url const *urlp);
468 static boole a_xtls_check_host(struct mx_socket *sop, X509 *peercert,
469 struct mx_url const *urlp);
471 static int smime_verify(struct message *m, int n,
472 a_XTLS_STACKOF(X509) *chain, X509_STORE *store);
473 static EVP_CIPHER const *a_xtls_smime_cipher(char const *name, boole *freeit);
475 static int ssl_password_cb(char *buf, int size, int rwflag,
476 void *userdata);
477 static FILE * smime_sign_cert(char const *xname, char const *xname2,
478 boole dowarn, char const **match, boole fallback_from);
479 static char const *a_xtls_smime_sign_include_certs(char const *name);
480 static boole a_xtls_smime_sign_include_chain_creat(a_XTLS_STACKOF(X509) **chain,
481 char const *cfiles, char const *addr);
482 static EVP_MD const *a_xtls_smime_sign_digest(char const *name,
483 char const **digname, boole *freeit);
484 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
485 static enum okay load_crl1(X509_STORE *store, char const *name);
486 #endif
487 static enum okay load_crls(X509_STORE *store, enum okeys fok, enum okeys dok);
489 #ifdef mx_XTLS_HAVE_SET_RESEED_DEFAULTS
490 SINLINE void
491 a_xtls_rand_drbg_init(void){
492 (void)RAND_DRBG_set_reseed_defaults(0, 0, 0, 0); /* (does not fail here) */
493 a_xtls_state |= a_XTLS_S_RAND_DRBG_INIT;
495 #endif
497 #ifdef mx_XTLS_HAVE_RAND_FILE
498 static void
499 a_xtls_rand_init(void){
500 # define a_XTLS_RAND_ENTROPY 32
501 char b64buf[a_XTLS_RAND_ENTROPY * 5 +1], *randfile;
502 char const *cp, *x;
503 boole err;
504 NYD2_IN;
506 a_xtls_rand_drbg_init();
507 a_xtls_state |= a_XTLS_S_RAND_INIT;
509 # ifdef mx_XTLS_HAVE_CONFIG
510 if(!(a_xtls_state & a_XTLS_S_INIT))
511 a_xtls_init();
512 # endif
514 err = TRU1;
515 randfile = NULL;
517 /* Prefer possible user setting */
518 if((cp = ok_vlook(tls_rand_file)) != NULL ||
519 (cp = ok_vlook(ssl_rand_file)) != NULL){
520 x = NULL;
521 if(*cp != '\0'){
522 if((x = fexpand(cp, (FEXP_NOPROTO | FEXP_LOCAL_FILE | FEXP_NSHELL))
523 ) == NIL)
524 n_err(_("*tls-rand-file*: expansion of %s failed "
525 "(using default)\n"),
526 n_shexp_quote_cp(cp, FAL0));
528 cp = x;
530 if(cp == NULL){
531 randfile = n_lofi_alloc(PATH_MAX);
532 if((cp = RAND_file_name(randfile, PATH_MAX)) == NULL){
533 n_err(_("*tls-rand-file*: no TLS entropy file, can't seed PRNG\n"));
534 goto jleave;
538 (void)RAND_load_file(cp, a_XTLS_RAND_LOAD_FILE_MAXBYTES);
540 /* And feed in some data, then write the updated file.
541 * While this rather feeds the PRNG with itself in the RANDOM_IMPL_TLS
542 * case, let us stir the buffer a little bit.
543 * Estimate a low but likely still too high number of entropy bytes, use
544 * 20%: base64 uses 3 input = 4 output bytes relation, and the base64
545 * alphabet is a 6 bit one */
546 for(x = (char*)-1;;){
547 RAND_add(mx_random_create_buf(b64buf, sizeof(b64buf) -1, NIL),
548 sizeof(b64buf) -1, a_XTLS_RAND_ENTROPY);
549 if((x = (char*)((up)x >> (1
550 # if mx_HAVE_RANDOM == mx_RANDOM_IMPL_TLS
552 # endif
553 ))) == NULL){
554 err = (RAND_status() == 0);
555 break;
557 # if mx_HAVE_RANDOM != mx_RANDOM_IMPL_TLS
558 if(!(err = (RAND_status() == 0)))
559 break;
560 # endif
563 if(!err)
564 err = (RAND_write_file(cp) == -1);
566 jleave:
567 if(randfile != NULL)
568 n_lofi_free(randfile);
569 if(err)
570 n_panic(_("Cannot seed the *TLS PseudoRandomNumberGenerator, "
571 "RAND_status() is 0!\n"
572 " Please set *tls-rand-file* to a file with sufficient entropy.\n"
573 " On a machine with entropy: "
574 "\"$ dd if=/dev/urandom of=FILE bs=1024 count=1\"\n"));
575 NYD2_OU;
577 #endif /* mx_XTLS_HAVE_RAND_FILE */
579 static void
580 a_xtls_init(void){
581 #ifdef mx_XTLS_HAVE_CONFIG
582 char const *cp;
583 #endif
584 NYD2_IN;
586 if(a_xtls_state & a_XTLS_S_INIT)
587 goto jleave;
589 #if mx_HAVE_XTLS >= 0x10100
590 OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS |
591 OPENSSL_INIT_LOAD_CRYPTO_STRINGS
592 # ifdef mx_HAVE_TLS_ALL_ALGORITHMS
593 # ifdef OPENSSL_INIT_ADD_ALL_CIPHERS
594 | OPENSSL_INIT_ADD_ALL_CIPHERS
595 # endif
596 # ifdef OPENSSL_INIT_ADD_ALL_DIGESTS
597 | OPENSSL_INIT_ADD_ALL_DIGESTS
598 # endif
599 # endif
600 # ifdef OPENSSL_INIT_NO_LOAD_CONFIG
601 | OPENSSL_INIT_NO_LOAD_CONFIG
602 # endif
603 , NIL);
604 #else
605 SSL_load_error_strings();
606 SSL_library_init();
607 a_xtls_load_algos();
608 #endif
609 a_xtls_state |= a_XTLS_S_INIT;
611 a_xtls_rand_drbg_init();
613 /* Load openssl.cnf or whatever was given in *tls-config-file* */
614 #ifdef mx_XTLS_HAVE_CONFIG
615 if((cp = ok_vlook(tls_config_file)) != NULL ||
616 (cp = ok_vlook(ssl_config_file)) != NULL){
617 char const *msg;
618 ul flags;
620 if(*cp == '\0'){
621 msg = "[default]";
622 cp = NULL;
623 flags = CONF_MFLAGS_IGNORE_MISSING_FILE;
624 }else if((msg = cp, cp = fexpand(cp, (FEXP_NOPROTO | FEXP_LOCAL_FILE |
625 FEXP_NSHELL))) != NIL)
626 flags = 0;
627 else{
628 n_err(_("*tls-config-file*: file expansion failed: %s\n"),
629 n_shexp_quote_cp(msg, FAL0));
630 goto jefile;
633 if(CONF_modules_load_file(cp, n_uagent, flags) == 1){
634 a_xtls_state |= a_XTLS_S_CONF_LOAD;
635 # if mx_HAVE_XTLS < 0x10100
636 if(!(a_xtls_state & a_XTLS_S_EXIT_HDL)){
637 a_xtls_state |= a_XTLS_S_EXIT_HDL;
638 atexit(&a_xtls_atexit); /* TODO generic program-wide event mech. */
640 # endif
641 if(n_poption & n_PO_D_V)
642 n_err(_("Loaded TLS configuration for %s from %s\n"), n_uagent,
643 n_shexp_quote_cp(msg, FAL0));
644 jefile:;
645 }else
646 ssl_gen_err(_("TLS CONF_modules_load_file() load error"));
648 #endif /* mx_XTLS_HAVE_CONFIG */
650 if(!(a_xtls_state & a_XTLS_S_RAND_INIT))
651 a_xtls_rand_init();
653 jleave:
654 NYD2_OU;
657 #if mx_HAVE_XTLS < 0x10100
658 # ifdef mx_HAVE_TLS_ALL_ALGORITHMS
659 static void
660 a_xtls__load_algos(void){
661 NYD2_IN;
662 if(!(a_xtls_state & a_XTLS_S_ALGO_LOAD)){
663 a_xtls_state |= a_XTLS_S_ALGO_LOAD;
664 OpenSSL_add_all_algorithms();
666 if(!(a_xtls_state & a_XTLS_S_EXIT_HDL)){
667 a_xtls_state |= a_XTLS_S_EXIT_HDL;
668 atexit(&a_xtls_atexit); /* TODO generic program-wide event mech. */
671 NYD2_OU;
673 # endif
675 # if defined mx_XTLS_HAVE_CONFIG || defined mx_HAVE_TLS_ALL_ALGORITHMS
676 static void
677 a_xtls_atexit(void){
678 NYD2_IN;
680 # ifdef mx_XTLS_HAVE_CONFIG
681 if(a_xtls_state & a_XTLS_S_CONF_LOAD)
682 CONF_modules_free();
683 # endif
685 # ifdef mx_HAVE_TLS_ALL_ALGORITHMS
686 if(a_xtls_state & a_XTLS_S_ALGO_LOAD)
687 EVP_cleanup();
688 # endif
690 NYD2_OU;
692 # endif
693 #endif /* mx_HAVE_XTLS < 0x10100 */
695 static boole
696 a_xtls_parse_asn1_time(ASN1_TIME const *atp, char *bdat, uz blen)
698 BIO *mbp;
699 char *mcp;
700 long l;
701 NYD_IN;
703 mbp = BIO_new(BIO_s_mem());
705 if (ASN1_TIME_print(mbp, C(ASN1_TIME*,atp)) &&
706 (l = BIO_get_mem_data(mbp, &mcp)) > 0)
707 snprintf(bdat, blen, "%.*s", (int)l, mcp);
708 else {
709 snprintf(bdat, blen, _("Bogus certificate date: %.*s"),
710 /*is (int)*/atp->length, (char const*)atp->data);
711 mcp = NULL;
714 BIO_free(mbp);
715 NYD_OU;
716 return (mcp != NULL);
719 static int
720 a_xtls_verify_cb(int success, X509_STORE_CTX *store)
722 char data[256];
723 X509 *cert;
724 int rv = TRU1;
725 NYD_IN;
727 if (success && !(n_poption & n_PO_D_V))
728 goto jleave;
730 if (a_xtls_msgno != 0) {
731 n_err(_("Message %lu:\n"), (ul)a_xtls_msgno);
732 a_xtls_msgno = 0;
734 n_err(_(" Certificate depth %d %s\n"),
735 X509_STORE_CTX_get_error_depth(store),
736 (success ? su_empty : V_(n_error)));
738 if ((cert = X509_STORE_CTX_get_current_cert(store)) != NULL) {
739 X509_NAME_oneline(X509_get_subject_name(cert), data, sizeof data);
740 n_err(_(" subject = %s\n"), data);
742 a_xtls_parse_asn1_time(a_xtls_X509_get_notBefore(cert),
743 data, sizeof data);
744 n_err(_(" notBefore = %s\n"), data);
746 a_xtls_parse_asn1_time(a_xtls_X509_get_notAfter(cert),
747 data, sizeof data);
748 n_err(_(" notAfter = %s\n"), data);
750 X509_NAME_oneline(X509_get_issuer_name(cert), data, sizeof data);
751 n_err(_(" issuer = %s\n"), data);
754 if (!success) {
755 int err = X509_STORE_CTX_get_error(store);
757 n_err(_(" err %i: %s\n"), err, X509_verify_cert_error_string(err));
758 a_xtls_state |= a_XTLS_S_VERIFY_ERROR;
761 if(!success)
762 rv = n_tls_verify_decide();
763 jleave:
764 NYD_OU;
765 return rv;
768 static boole
769 a_xtls_digest_find(boole fingerprint, char const *name, EVP_MD const **mdp,
770 char const **normalized_name_or_nil, boole *freeit){
771 uz i;
772 NYD2_IN;
774 *freeit = FAL0;
776 if(name == NIL){
777 name = fingerprint ? a_XTLS_FINGERPRINT_DEFAULT_DIGEST_S
778 : a_XTLS_SMIME_DEFAULT_DIGEST_S;
779 a_XTLS__NFETCH_INJ(*mdp = fingerprint
780 ? a_XTLS_FINGERPRINT_DEFAULT_DIGEST()
781 : a_XTLS_SMIME_DEFAULT_DIGEST();)
782 goto a_XTLS__JFETCH;
785 /* C99 */{
786 char *cp, *nn, c;
788 i = su_cs_len(name);
789 nn = cp = su_LOFI_ALLOC(i +1);
790 while((c = *name++) != '\0')
791 *cp++ = su_cs_to_upper(c);
792 *cp = '\0';
793 name = savestrbuf(nn, P2UZ(cp - nn));
794 su_LOFI_FREE(nn);
797 for(i = 0; i < NELEM(a_xtls_digests); ++i)
798 if(!su_cs_cmp(a_xtls_digests[i].xd_name, name)){
799 a_XTLS__NFETCH_INJ(*mdp = (*a_xtls_digests[i].xd_fun)();)
800 name = a_xtls_digests[i].xd_name;
801 goto a_XTLS__JFETCH;
804 /* Not a built-in algorithm, but we may have dynamic support for more */
805 #if defined mx_HAVE_TLS_ALL_ALGORITHMS && !defined a_XTLS_CRYPTO_FETCH
806 if((*mdp = EVP_get_digestbyname(name)) != NIL)
807 goto jleave;
808 #endif
810 #ifdef a_XTLS_CRYPTO_FETCH
811 a_XTLS__JFETCH:
812 if((*mdp = EVP_MD_fetch(NIL, name, NIL)) != NIL){
813 *freeit = TRU1;
814 goto jleave;
816 #endif
818 n_err(_("Invalid message digest: %s\n"), n_shexp_quote_cp(name, FAL0));
819 *mdp = NIL;
821 jleave:
822 if(normalized_name_or_nil != NIL)
823 *normalized_name_or_nil = name;
825 NYD2_OU;
826 return (*mdp != NIL);
829 static void
830 a_xtls_ca_flags(X509_STORE *store, char const *flags){
831 NYD2_IN;
832 if(flags != NULL){
833 char *iolist, *cp;
835 iolist = savestr(flags);
836 jouter:
837 while((cp = su_cs_sep_c(&iolist, ',', TRU1)) != NULL){
838 struct a_xtls_x509_v_flags const *xvfp;
840 for(xvfp = &a_xtls_x509_v_flags[0];
841 xvfp < &a_xtls_x509_v_flags[NELEM(a_xtls_x509_v_flags)];
842 ++xvfp)
843 if(!su_cs_cmp_case(cp, xvfp->xxvf_name)){
844 if(xvfp->xxvf_flag != -1){
845 #ifdef a_XTLS_X509_V_ANY
846 X509_STORE_set_flags(store, xvfp->xxvf_flag);
847 #endif
848 }else if(n_poption & n_PO_D_V)
849 n_err(_("*{smime,tls}-ca-flags*: "
850 "directive not supported: %s\n"), cp);
851 goto jouter;
853 n_err(_("*{smime,tls}-ca-flags*: invalid directive: %s\n"), cp);
856 NYD2_OU;
859 #ifdef mx_XTLS_HAVE_CONF_CTX
860 static void *
861 a_xtls_conf_setup(SSL_CTX *ctxp, struct mx_url const *urlp){
862 char const *cp;
863 SSL_CONF_CTX *sccp;
864 NYD2_IN;
866 sccp = NULL;
868 if((cp = xok_vlook(tls_config_module, urlp, OXM_ALL)) != NULL ||
869 (cp = xok_vlook(ssl_config_module, urlp, OXM_ALL)) != NULL){
870 # ifdef mx_XTLS_HAVE_CTX_CONFIG
871 if(!(a_xtls_state & a_XTLS_S_CONF_LOAD)){
872 n_err(_("*tls-config-module*: no *tls-config-file* loaded: %s\n"),
873 n_shexp_quote_cp(cp, FAL0));
874 goto jleave;
875 }else if(!SSL_CTX_config(ctxp, cp)){
876 ssl_gen_err(_("*tls-config-module*: load error for %s, section [%s]"),
877 n_uagent, n_shexp_quote_cp(cp, FAL0));
878 goto jleave;
880 # else
881 n_err(_("*tls-config-module*: set but not supported: %s\n"),
882 n_shexp_quote_cp(cp, FAL0));
883 goto jleave;
884 # endif
887 if((sccp = SSL_CONF_CTX_new()) != NULL){
888 SSL_CONF_CTX_set_flags(sccp,
889 SSL_CONF_FLAG_FILE | SSL_CONF_FLAG_CLIENT |
890 SSL_CONF_FLAG_CERTIFICATE | SSL_CONF_FLAG_SHOW_ERRORS);
892 SSL_CONF_CTX_set_ssl_ctx(sccp, ctxp);
893 }else
894 ssl_gen_err(_("SSL_CONF_CTX_new() failed"));
895 jleave:
896 NYD2_OU;
897 return sccp;
900 static boole
901 a_xtls_conf(void *confp, char const *cmd, char const *value){
902 int rv;
903 SSL_CONF_CTX *sccp;
904 NYD2_IN;
906 if(n_poption & n_PO_D_V)
907 n_err(_("TLS: applying config: %s = %s\n"),
908 n_shexp_quote_cp(cmd, FAL0), n_shexp_quote_cp(value, FAL0));
910 rv = SSL_CONF_cmd(sccp = confp, cmd, value);
911 if(rv == 2)
912 rv = 0;
913 else{
914 cmd = n_shexp_quote_cp(cmd, FAL0);
915 value = n_shexp_quote_cp(value, FAL0);
916 if(rv == 0)
917 ssl_gen_err(_("TLS: config failure: %s = %s"), cmd, value);
918 else{
919 char const *err;
921 switch(rv){
922 case -2: err = N_("TLS: config command not recognized"); break;
923 case -3: err = N_("TLS: missing required config argument"); break;
924 default: err = N_("TLS: unspecified config error"); break;
926 err = V_(err);
927 n_err(_("%s (%d): %s = %s\n"), err, rv, cmd, value);
929 rv = 1;
931 NYD2_OU;
932 return (rv == 0);
935 static boole
936 a_xtls_conf_finish(void **confp, boole error){
937 SSL_CONF_CTX *sccp;
938 boole rv;
939 NYD2_IN;
941 sccp = (SSL_CONF_CTX*)*confp;
942 *confp = NULL;
944 if(!(rv = error))
945 rv = (SSL_CONF_CTX_finish(sccp) != 0);
947 SSL_CONF_CTX_free(sccp);
948 NYD2_OU;
949 return rv;
952 #else /* mx_XTLS_HAVE_CONF_CTX */
953 # ifdef mx_XTLS_HAVE_CTX_CONFIG
954 # error SSL_CTX_config(3) support unexpected without SSL_CONF_CTX support
955 # endif
957 static void *
958 a_xtls_conf_setup(SSL_CTX* ctxp, struct mx_url const *urlp){
959 char const *cp;
960 NYD2_IN;
962 if((cp = xok_vlook(tls_config_module, urlp, OXM_ALL)) != NULL ||
963 (cp = xok_vlook(ssl_config_module, urlp, OXM_ALL)) != NULL){
964 n_err(_("*tls-config-module*: set but not supported: %s\n"),
965 n_shexp_quote_cp(cp, FAL0));
966 ctxp = NULL;
968 NYD2_OU;
969 return ctxp;
972 static boole
973 a_xtls_conf(void *confp, char const *cmd, char const *value){
974 char const *xcmd, *emsg;
975 SSL_CTX *ctxp;
976 NYD2_IN;
978 if(n_poption & n_PO_D_V)
979 n_err(_("TLS: applying config: %s = %s\n"),
980 n_shexp_quote_cp(cmd, FAL0), n_shexp_quote_cp(value, FAL0));
982 ctxp = confp;
984 if(!su_cs_cmp_case(cmd, xcmd = "Certificate")){
985 if(SSL_CTX_use_certificate_chain_file(ctxp, value) != 1){
986 emsg = N_("TLS: %s: cannot load from file %s\n");
987 goto jerr;
989 }else if(!su_cs_cmp_case(cmd, xcmd = "CipherString") ||
990 !su_cs_cmp_case(cmd, xcmd = "CipherList")/* XXX bad bug in past! */){
991 if(SSL_CTX_set_cipher_list(ctxp, value) != 1){
992 emsg = N_("TLS: %s: invalid: %s\n");
993 goto jerr;
995 }else if(!su_cs_cmp_case(cmd, xcmd = "Ciphersuites")){
996 # ifdef mx_XTLS_HAVE_SET_CIPHERSUITES
997 if(SSL_CTX_set_ciphersuites(ctxp, value) != 1){
998 emsg = N_("TLS: %s: invalid: %s\n");
999 goto jerr;
1001 # else
1002 value = NULL;
1003 emsg = N_("TLS: %s: directive not supported\n");
1004 goto jxerr;
1005 # endif
1006 }else if(!su_cs_cmp_case(cmd, xcmd = "Curves")){
1007 # ifdef SSL_CTRL_SET_CURVES_LIST
1008 if(SSL_CTX_set1_curves_list(ctxp, n_UNCONST(value)) != 1){
1009 emsg = N_("TLS: %s: invalid: %s\n");
1010 goto jerr;
1012 # else
1013 value = NULL;
1014 emsg = N_("TLS: %s: directive not supported\n");
1015 goto jxerr;
1016 # endif
1017 }else if((emsg = NULL, !su_cs_cmp_case(cmd, xcmd = "MaxProtocol")) ||
1018 (emsg = (char*)-1, !su_cs_cmp_case(cmd, xcmd = "MinProtocol"))){
1019 # ifndef mx_XTLS_HAVE_SET_MIN_PROTO_VERSION
1020 value = NULL;
1021 emsg = N_("TLS: %s: directive not supported\n");
1022 goto jxerr;
1023 # else
1024 struct a_xtls_protocol const *xpp;
1026 for(xpp = &a_xtls_protocols[1] /* [0] == ALL */;;)
1027 if(xpp->xp_ok_minmaxproto && !su_cs_cmp_case(value, xpp->xp_name)){
1028 if(xpp->xp_op_no == 0 || xpp->xp_version == 0)
1029 goto jenoproto;
1030 break;
1031 }else if((++xpp)->xp_last)
1032 goto jenoproto;
1034 if((emsg == NULL ? SSL_CTX_set_max_proto_version(ctxp, xpp->xp_version)
1035 : SSL_CTX_set_min_proto_version(ctxp, xpp->xp_version)) != 1){
1036 emsg = N_("TLS: %s: cannot set protocol version: %s\n");
1037 goto jerr;
1039 # endif /* !mx_XTLS_HAVE_SET_MIN_PROTO_VERSION */
1040 }else if(!su_cs_cmp_case(cmd, xcmd = "Options")){
1041 if(su_cs_cmp_case(value, "Bugs")){
1042 emsg = N_("TLS: %s: fallback only supports value \"Bugs\": %s\n");
1043 goto jxerr;
1045 SSL_CTX_set_options(ctxp, SSL_OP_ALL);
1046 }else if(!su_cs_cmp_case(cmd, xcmd = "PrivateKey")){
1047 if(SSL_CTX_use_PrivateKey_file(ctxp, value, SSL_FILETYPE_PEM) != 1){
1048 emsg = N_("%s: cannot load from file %s\n");
1049 goto jerr;
1051 }else if(!su_cs_cmp_case(cmd, xcmd = "Protocol")){
1052 struct a_xtls_protocol const *xpp;
1053 char *iolist, *cp, addin;
1054 sl opts;
1056 opts = 0;
1058 for(iolist = cp = savestr(value);
1059 (cp = su_cs_sep_c(&iolist, ',', FAL0)) != NULL;){
1060 if(*cp == '\0'){
1061 value = NULL;
1062 emsg = N_("TLS: %s: empty elements are not supported\n");
1063 goto jxerr;
1066 addin = TRU1;
1067 switch(cp[0]){
1068 case '-': addin = FAL0; /* FALLTHRU */
1069 case '+': ++cp; /* FALLTHRU */
1070 default : break;
1073 for(xpp = &a_xtls_protocols[0];;){
1074 if(xpp->xp_ok_proto && !su_cs_cmp_case(cp, xpp->xp_name)){
1075 if((xpp->xp_op_no == 0 || xpp->xp_version == 0) &&
1076 !xpp->xp_is_all)
1077 goto jenoproto;
1078 /* We need to inverse the meaning of the _NO_s */
1079 if(!addin)
1080 opts |= xpp->xp_op_no;
1081 else
1082 opts &= ~xpp->xp_op_no;
1083 break;
1084 }else if((++xpp)->xp_last){
1085 jenoproto:
1086 emsg = N_("TLS: %s: unknown or unsupported protocol: %s\n");
1087 goto jxerr;
1092 SSL_CTX_clear_options(ctxp, SSL_OP_NO_SSL_MASK);
1093 SSL_CTX_set_options(ctxp, opts);
1094 }else{
1095 xcmd = n_shexp_quote_cp(cmd, FAL0);
1096 emsg = N_("TLS: unsupported directive: %s: value: %s\n");
1097 goto jxerr;
1100 jleave:
1101 NYD2_OU;
1102 return (confp != NULL);
1103 jerr:
1104 ssl_gen_err(V_(emsg), xcmd, n_shexp_quote_cp(value, FAL0));
1105 confp = NULL;
1106 goto jleave;
1107 jxerr:
1108 if(value != NULL)
1109 value = n_shexp_quote_cp(value, FAL0);
1110 n_err(V_(emsg), xcmd, value);
1111 confp = NULL;
1112 goto jleave;
1115 static boole
1116 a_xtls_conf_finish(void **confp, boole error){
1117 UNUSED(confp);
1118 UNUSED(error);
1119 *confp = NULL;
1120 return TRU1;
1122 #endif /* !mx_XTLS_HAVE_CONF_CTX */
1124 static boole
1125 a_xtls_obsolete_conf_vars(void *confp, struct mx_url const *urlp){
1126 char const *cp, *cp_base, *certchain;
1127 boole rv;
1128 NYD2_IN;
1130 rv = FAL0;
1132 /* Certificate via ssl-cert */
1133 if((certchain = cp = xok_vlook(ssl_cert, urlp, OXM_ALL)) != NULL){
1134 n_OBSOLETE(_("please use *tls-config-pairs* instead of *ssl-cert*"));
1135 if((cp_base = fexpand(cp, (FEXP_NOPROTO | FEXP_LOCAL_FILE | FEXP_NSHELL))
1136 ) == NIL){
1137 n_err(_("*ssl-cert* value expansion failed: %s\n"),
1138 n_shexp_quote_cp(cp, FAL0));
1139 goto jleave;
1141 if(!a_xtls_conf(confp, "Certificate", certchain = cp_base))
1142 goto jleave;
1145 /* CipherString via ssl-ciper-list */
1146 if((cp = xok_vlook(ssl_cipher_list, urlp, OXM_ALL)) != NULL){
1147 n_OBSOLETE(_("please use *tls-config-pairs* instead of "
1148 "*ssl-cipher-list*"));
1149 if(!a_xtls_conf(confp, "CipherString", cp))
1150 goto jleave;
1153 /* Curves via ssl-curves */
1154 if((cp = xok_vlook(ssl_curves, urlp, OXM_ALL)) != NULL){
1155 n_OBSOLETE(_("please use *tls-config-pairs* instead of *ssl-curves*"));
1156 if(!a_xtls_conf(confp, "Curves", cp))
1157 goto jleave;
1160 /* PrivateKey via ssl-key */
1161 if((cp = xok_vlook(ssl_key, urlp, OXM_ALL)) != NULL){
1162 n_OBSOLETE(_("please use *tls-config-pairs* instead of *ssl-key*"));
1163 if((cp_base = fexpand(cp, (FEXP_NOPROTO | FEXP_LOCAL_FILE | FEXP_NSHELL))
1164 ) == NIL){
1165 n_err(_("*ssl-key* value expansion failed: %s\n"),
1166 n_shexp_quote_cp(cp, FAL0));
1167 goto jleave;
1169 cp = cp_base;
1170 if(certchain == NULL){
1171 n_err(_("*ssl-key* can only be used together with *ssl-cert*! "
1172 "And use *ssl-config-pairs*!\n"));
1173 goto jleave;
1176 if((cp != NULL || (cp = certchain) != NULL) &&
1177 !a_xtls_conf(confp, "PrivateKey", cp))
1178 goto jleave;
1180 /* Protocol via ssl-method or ssl-protocol */
1181 if((cp = xok_vlook(ssl_method, urlp, OXM_ALL)) != NULL){
1182 uz i;
1184 n_OBSOLETE(_("please use *tls-config-pairs* instead of *ssl-method*"));
1185 for(i = 0;;){
1186 if(!su_cs_cmp_case(_ssl_methods[i].sm_name, cp)){
1187 cp = _ssl_methods[i].sm_map;
1188 break;
1190 if(++i == NELEM(_ssl_methods)){
1191 n_err(_("Unsupported SSL method: %s\n"), cp);
1192 goto jleave;
1196 if((cp_base = xok_vlook(ssl_protocol, urlp, OXM_ALL)) != NULL){
1197 n_OBSOLETE(_("please use *tls-config-pairs* instead of *ssl-protocol*"));
1198 if(cp != NULL && (n_poption & n_PO_D_V))
1199 n_err(_("*ssl-protocol* overrides *ssl-method*! "
1200 "And please use *tls-config-pairs* instead!\n"));
1201 cp = cp_base;
1203 if(cp != NULL && !a_xtls_conf(confp, "Protocol", cp))
1204 goto jleave;
1206 rv = TRU1;
1207 jleave:
1208 NYD2_OU;
1209 return rv;
1212 static boole
1213 a_xtls_config_pairs(void *confp, struct mx_url const *urlp){
1214 /* Due to interdependencies some commands have to be delayed a bit */
1215 static char const cmdcert[] = "Certificate", cmdprivkey[] = "PrivateKey";
1216 char const *valcert, *valprivkey;
1217 char *pairs, *cp, *cmd, *val;
1218 NYD2_IN;
1220 if((pairs = n_UNCONST(xok_vlook(tls_config_pairs, urlp, OXM_ALL))
1221 ) == NULL &&
1222 (pairs = n_UNCONST(xok_vlook(ssl_config_pairs, urlp, OXM_ALL))
1223 ) == NULL)
1224 goto jleave;
1225 pairs = savestr(pairs);
1227 valcert = valprivkey = NULL;
1229 while((cp = su_cs_sep_escable_c(&pairs, ',', FAL0)) != NULL){
1230 char c;
1231 enum{
1232 a_NONE,
1233 a_EXPAND = 1u<<0,
1234 a_CERT = 1u<<1,
1235 a_PRIVKEY = 1u<<2,
1236 a_EXPAND_MASK = a_EXPAND | a_CERT | a_PRIVKEY
1237 } f;
1239 /* Directive, space trimmed */
1240 if((cmd = su_cs_find_c(cp, '=')) == NULL){
1241 jenocmd:
1242 if(pairs == NULL)
1243 pairs = n_UNCONST(n_empty);
1244 n_err(_("*tls-config-pairs*: missing directive: %s; rest: %s\n"),
1245 n_shexp_quote_cp(cp, FAL0), n_shexp_quote_cp(pairs, FAL0));
1246 goto jleave;
1248 val = &cmd[1];
1250 if((cmd > cp && cmd[-1] == '*')){
1251 --cmd;
1252 f = a_EXPAND;
1253 }else
1254 f = a_NONE;
1255 while(cmd > cp && (c = cmd[-1], su_cs_is_space(c)))
1256 --cmd;
1257 if(cmd == cp)
1258 goto jenocmd;
1259 *cmd = '\0';
1260 cmd = cp;
1262 /* Command with special treatment? */
1263 if(!su_cs_cmp_case(cmd, cmdcert))
1264 f |= a_CERT;
1265 else if(!su_cs_cmp_case(cmd, cmdprivkey))
1266 f |= a_PRIVKEY;
1268 /* Value, space trimmed */
1269 while((c = *val) != '\0' && su_cs_is_space(c))
1270 ++val;
1271 cp = &val[su_cs_len(val)];
1272 while(cp > val && (c = cp[-1], su_cs_is_space(c)))
1273 --cp;
1274 *cp = '\0';
1275 if(cp == val){
1276 if(pairs == NULL)
1277 pairs = n_UNCONST(n_empty);
1278 n_err(_("*tls-config-pairs*: missing value: %s; rest: %s\n"),
1279 n_shexp_quote_cp(cmd, FAL0), n_shexp_quote_cp(pairs, FAL0));
1280 goto jleave;
1283 /* Filename transformations to be applied? */
1284 if(f & a_EXPAND_MASK){
1285 if((cp = fexpand(val, (FEXP_NOPROTO | FEXP_LOCAL_FILE | FEXP_NSHELL))
1286 ) == NIL){
1287 if(pairs == NULL)
1288 pairs = n_UNCONST(n_empty);
1289 n_err(_("*tls-config-pairs*: value expansion failed: %s: %s; "
1290 "rest: %s\n"),
1291 n_shexp_quote_cp(cmd, FAL0), n_shexp_quote_cp(val, FAL0),
1292 n_shexp_quote_cp(pairs, FAL0));
1293 goto jleave;
1295 val = cp;
1298 /* Some things have to be delayed */
1299 if(f & a_CERT)
1300 valcert = val;
1301 else if(f & a_PRIVKEY)
1302 valprivkey = val;
1303 else if(!a_xtls_conf(confp, cmd, val)){
1304 pairs = n_UNCONST(n_empty);
1305 goto jleave;
1309 /* Work the delayed ones */
1310 if((valcert != NULL && !a_xtls_conf(confp, cmdcert, valcert)) ||
1311 ((valprivkey != NULL || (valprivkey = valcert) != NULL) &&
1312 !a_xtls_conf(confp, cmdprivkey, valprivkey)))
1313 pairs = n_UNCONST(n_empty);
1315 jleave:
1316 NYD2_OU;
1317 return (pairs == NULL);
1320 static boole
1321 a_xtls_load_verifications(SSL_CTX *ctxp, struct mx_url const *urlp){
1322 char *ca_dir, *ca_file;
1323 X509_STORE *store;
1324 boole rv;
1325 NYD2_IN;
1327 if(n_tls_verify_level == n_TLS_VERIFY_IGNORE){
1328 rv = TRU1;
1329 goto jleave;
1331 rv = FAL0;
1333 if((ca_dir = xok_vlook(tls_ca_dir, urlp, OXM_ALL)) != NULL ||
1334 (ca_dir = xok_vlook(ssl_ca_dir, urlp, OXM_ALL)) != NULL)
1335 ca_dir = fexpand(ca_dir, (FEXP_NOPROTO | FEXP_LOCAL_FILE | FEXP_NSHELL));
1336 if((ca_file = xok_vlook(tls_ca_file, urlp, OXM_ALL)) != NULL ||
1337 (ca_file = xok_vlook(ssl_ca_file, urlp, OXM_ALL)) != NULL)
1338 ca_file = fexpand(ca_file, (FEXP_NOPROTO | FEXP_LOCAL_FILE |
1339 FEXP_NSHELL));
1341 if(ca_file != NIL && a_xtls_SSL_CTX_load_verify_file(ctxp, ca_file) != 1){
1342 ssl_gen_err(_("Error loading %s\n"), n_shexp_quote_cp(ca_file, FAL0));
1343 goto jleave;
1346 if(ca_dir != NIL && a_xtls_SSL_CTX_load_verify_dir(ctxp, ca_dir) != 1){
1347 ssl_gen_err(_("Error loading %s\n"), n_shexp_quote_cp(ca_dir, FAL0));
1348 goto jleave;
1351 /* C99 */{
1352 boole xv15;
1354 if((xv15 = ok_blook(ssl_no_default_ca)))
1355 n_OBSOLETE(_("please use *tls-ca-no-defaults*, "
1356 "not *ssl-no-default-ca*"));
1357 if(!xok_blook(tls_ca_no_defaults, urlp, OXM_ALL) &&
1358 !xok_blook(ssl_ca_no_defaults, urlp, OXM_ALL) && !xv15 &&
1359 SSL_CTX_set_default_verify_paths(ctxp) != 1) {
1360 ssl_gen_err(_("Error loading built-in default CA locations\n"));
1361 goto jleave;
1365 a_xtls_state &= ~a_XTLS_S_VERIFY_ERROR;
1366 a_xtls_msgno = 0;
1367 SSL_CTX_set_verify(ctxp, SSL_VERIFY_PEER, &a_xtls_verify_cb);
1368 store = SSL_CTX_get_cert_store(ctxp);
1369 load_crls(store, ok_v_tls_crl_file, ok_v_tls_crl_dir);
1370 a_xtls_ca_flags(store, xok_vlook(tls_ca_flags, urlp, OXM_ALL));
1371 a_xtls_ca_flags(store, xok_vlook(ssl_ca_flags, urlp, OXM_ALL));
1373 rv = TRU1;
1374 jleave:
1375 NYD2_OU;
1376 return rv;
1379 static boole
1380 a_xtls_check_host(struct mx_socket *sop, X509 *peercert,
1381 struct mx_url const *urlp){
1382 char data[256];
1383 a_XTLS_STACKOF(GENERAL_NAME) *gens;
1384 GENERAL_NAME *gen;
1385 X509_NAME *subj;
1386 boole rv;
1387 NYD_IN;
1388 UNUSED(sop);
1390 rv = FAL0;
1392 if((gens = X509_get_ext_d2i(peercert, NID_subject_alt_name, NULL, NULL)
1393 ) != NULL){
1394 int i;
1396 for(i = 0; i < sk_GENERAL_NAME_num(gens); ++i){
1397 gen = sk_GENERAL_NAME_value(gens, i);
1398 if(gen->type == GEN_DNS){
1399 if(n_poption & n_PO_D_V)
1400 n_err(_("Comparing subject_alt_name: need<%s> is<%s>\n"),
1401 urlp->url_host.s, (char*)gen->d.ia5->data);
1402 if((rv = n_tls_rfc2595_hostname_match(urlp->url_host.s,
1403 (char*)gen->d.ia5->data)))
1404 goto jleave;
1409 if((subj = X509_get_subject_name(peercert)) != NULL &&
1410 X509_NAME_get_text_by_NID(subj, NID_commonName, data, sizeof data
1411 ) > 0){
1412 data[sizeof data - 1] = '\0';
1413 if(n_poption & n_PO_D_V)
1414 n_err(_("Comparing commonName: need<%s> is<%s>\n"),
1415 urlp->url_host.s, data);
1416 rv = n_tls_rfc2595_hostname_match(urlp->url_host.s, data);
1418 jleave:
1419 NYD_OU;
1420 return rv;
1423 static int
1424 smime_verify(struct message *m, int n, a_XTLS_STACKOF(X509) *chain,
1425 X509_STORE *store)
1427 char data[LINESIZE], *sender, *to, *cc, *cnttype;
1428 int rv, c, i, j;
1429 struct message *x;
1430 FILE *fp, *ip;
1431 off_t size;
1432 BIO *fb, *pb;
1433 PKCS7 *pkcs7;
1434 a_XTLS_STACKOF(X509) *certs;
1435 a_XTLS_STACKOF(GENERAL_NAME) *gens;
1436 X509 *cert;
1437 X509_NAME *subj;
1438 GENERAL_NAME *gen;
1439 NYD_IN;
1441 rv = 1;
1442 fp = NULL;
1443 fb = pb = NULL;
1444 pkcs7 = NULL;
1445 certs = NULL;
1446 a_xtls_state &= ~a_XTLS_S_VERIFY_ERROR;
1447 a_xtls_msgno = (uz)n;
1449 for (;;) {
1450 sender = getsender(m);
1451 to = hfield1("to", m);
1452 cc = hfield1("cc", m);
1453 cnttype = hfield1("content-type", m);
1455 #undef _X
1456 #undef _Y
1457 #define _X (sizeof("application/") -1)
1458 #define _Y(X) X, sizeof(X) -1
1459 if (cnttype && su_cs_starts_with_case(cnttype, "application/") &&
1460 (!su_cs_cmp_case_n(cnttype + _X, _Y("pkcs7-mime")) ||
1461 !su_cs_cmp_case_n(cnttype + _X, _Y("x-pkcs7-mime")))) {
1462 #undef _Y
1463 #undef _X
1464 if ((x = smime_decrypt(m, to, cc, TRU1)) == NULL)
1465 goto jleave;
1466 if (x != (struct message*)-1) {
1467 m = x;
1468 continue;
1472 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
1473 goto jleave;
1474 size = m->m_size;
1475 break;
1478 if((fp = mx_fs_tmp_open("smimever", (mx_FS_O_RDWR | mx_FS_O_UNLINK |
1479 mx_FS_O_REGISTER), NIL)) == NIL){
1480 n_perr(_("tempfile"), 0);
1481 goto jleave;
1483 while (size-- > 0) {
1484 c = getc(ip);
1485 putc(c, fp);
1487 fflush_rewind(fp);
1489 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
1490 ssl_gen_err(_(
1491 "Error creating BIO verification object for message %d"), n);
1492 goto jleave;
1495 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
1496 ssl_gen_err(_("Error reading PKCS#7 object for message %d"), n);
1497 goto jleave;
1499 if (PKCS7_verify(pkcs7, chain, store, pb, NULL, 0) != 1) {
1500 ssl_gen_err(_("Error verifying message %d"), n);
1501 goto jleave;
1504 if (sender == NULL) {
1505 n_err(_("Warning: Message %d has no sender\n"), n);
1506 rv = 0;
1507 goto jleave;
1510 certs = PKCS7_get0_signers(pkcs7, chain, 0);
1511 if (certs == NULL) {
1512 n_err(_("No certificates found in message %d\n"), n);
1513 goto jleave;
1516 for (i = 0; i < sk_X509_num(certs); ++i) {
1517 cert = sk_X509_value(certs, i);
1518 gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
1519 if (gens != NULL) {
1520 for (j = 0; j < sk_GENERAL_NAME_num(gens); ++j) {
1521 gen = sk_GENERAL_NAME_value(gens, j);
1522 if (gen->type == GEN_EMAIL) {
1523 if (n_poption & n_PO_D_V)
1524 n_err(_("Comparing subject_alt_name: need<%s> is<%s>)\n"),
1525 sender, (char*)gen->d.ia5->data);
1526 if (!su_cs_cmp_case((char*)gen->d.ia5->data, sender))
1527 goto jfound;
1532 if ((subj = X509_get_subject_name(cert)) != NULL &&
1533 X509_NAME_get_text_by_NID(subj, NID_pkcs9_emailAddress,
1534 data, sizeof data) > 0) {
1535 data[sizeof data -1] = '\0';
1536 if (n_poption & n_PO_D_V)
1537 n_err(_("Comparing emailAddress: need<%s> is<%s>\n"),
1538 sender, data);
1539 if (!su_cs_cmp_case(data, sender))
1540 goto jfound;
1543 n_err(_("Message %d: certificate does not match <%s>\n"), n, sender);
1544 goto jleave;
1545 jfound:
1546 rv = ((a_xtls_state & a_XTLS_S_VERIFY_ERROR) != 0);
1547 if (!rv)
1548 fprintf(n_stdout, _("Message %d was verified successfully\n"), n);
1549 jleave:
1550 if (certs != NULL)
1551 sk_X509_free(certs);
1552 if (pb != NULL)
1553 BIO_free(pb);
1554 if (fb != NULL)
1555 BIO_free(fb);
1556 if (pkcs7 != NULL)
1557 PKCS7_free(pkcs7);
1558 if(fp != NIL)
1559 mx_fs_close(fp);
1560 NYD_OU;
1561 return rv;
1564 static EVP_CIPHER const *
1565 a_xtls_smime_cipher(char const *name, boole *freeit){
1566 EVP_CIPHER const *cipher;
1567 char *vn;
1568 char const *cp;
1569 uz i;
1570 NYD_IN;
1572 *freeit = FAL0;
1574 vn = su_LOFI_ALLOC(i = su_cs_len(name) + sizeof("smime-cipher-") -1 +1);
1575 snprintf(vn, S(int,i), "smime-cipher-%s", name);
1576 cp = n_var_vlook(vn, FAL0);
1577 su_LOFI_FREE(vn);
1579 if(cp == NIL && (cp = ok_vlook(smime_cipher)) == NIL){
1580 a_XTLS__NFETCH_INJ(cipher = a_XTLS_SMIME_DEFAULT_CIPHER();)
1581 cp = a_XTLS_SMIME_DEFAULT_CIPHER_S;
1582 goto a_XTLS__JFETCH;
1584 cipher = NIL;
1586 for(i = 0; i < NELEM(a_xtls_ciphers); ++i)
1587 if(!su_cs_cmp_case(a_xtls_ciphers[i].xc_name, cp)){
1588 a_XTLS__NFETCH_INJ(cipher = (*a_xtls_ciphers[i].xc_fun)();)
1589 cp = a_xtls_ciphers[i].xc_name;
1590 goto a_XTLS__JFETCH;
1592 #ifndef OPENSSL_NO_AES
1593 for(i = 0; i < NELEM(a_xtls_smime_ciphers_obs); ++i)/* TODO v15-compat */
1594 if(!su_cs_cmp_case(a_xtls_smime_ciphers_obs[i].xc_name, cp)){
1595 n_OBSOLETE2(_("*smime-cipher* names with hyphens will vanish"), cp);
1596 a_XTLS__NFETCH_INJ(cipher = (*a_xtls_smime_ciphers_obs[i].xc_fun)();)
1597 cp = a_xtls_smime_ciphers_obs[i].xc_name;
1598 goto a_XTLS__JFETCH;
1600 #endif
1602 /* Not a built-in algorithm, but we may have dynamic support for more */
1603 #if defined mx_HAVE_TLS_ALL_ALGORITHMS && !defined a_XTLS_CRYPTO_FETCH
1604 if((cipher = EVP_get_cipherbyname(cp)) != NIL)
1605 goto jleave;
1606 #endif
1608 #ifdef a_XTLS_CRYPTO_FETCH
1609 a_XTLS__JFETCH:
1610 if((cipher = EVP_CIPHER_fetch(NIL, cp, NIL)) != NIL){
1611 *freeit = TRU1;
1612 goto jleave;
1614 #endif
1616 n_err(_("Invalid S/MIME cipher(s): %s\n"), cp);
1617 jleave:
1618 NYD_OU;
1619 return cipher;
1622 static int
1623 ssl_password_cb(char *buf, int size, int rwflag, void *userdata)
1625 char *pass;
1626 uz len;
1627 NYD_IN;
1628 UNUSED(rwflag);
1629 UNUSED(userdata);
1631 /* New-style */
1632 if(userdata != NULL){
1633 struct mx_url url;
1634 struct mx_cred_ctx cred;
1636 if(mx_url_parse(&url, CPROTO_CCRED, userdata)){
1637 if(mx_cred_auth_lookup(&cred, &url)){
1638 char *end;
1640 if((end = su_cs_pcopy_n(buf, cred.cc_pass.s, size)) != NULL){
1641 size = (int)P2UZ(end - buf);
1642 goto jleave;
1645 size = 0;
1646 goto jleave;
1650 /* Old-style */
1651 if((pass = mx_tty_getpass("PEM pass phrase:")) != NIL){
1652 len = su_cs_len(pass);
1653 if (UCMP(z, len, >=, size))
1654 len = size -1;
1655 su_mem_copy(buf, pass, len);
1656 buf[len] = '\0';
1657 size = (int)len;
1658 } else
1659 size = 0;
1660 jleave:
1661 NYD_OU;
1662 return size;
1665 static FILE *
1666 smime_sign_cert(char const *xname, char const *xname2, boole dowarn,
1667 char const **match, boole fallback_from)
1669 char *vn;
1670 int vs;
1671 struct mx_name *np;
1672 char const *name = xname, *name2 = xname2, *cp;
1673 FILE *fp = NULL;
1674 NYD_IN;
1676 jloop:
1677 if (name) {
1678 np = lextract(name, GTO | GSKIN);
1679 while (np != NULL) {
1680 /* This needs to be more intelligent since it will currently take the
1681 * first name for which a private key is available regardless of
1682 * whether it is the right one for the message */
1683 vn = n_lofi_alloc(vs = su_cs_len(np->n_name) + 30);
1684 snprintf(vn, vs, "smime-sign-cert-%s", np->n_name);
1685 cp = n_var_vlook(vn, FAL0);
1686 n_lofi_free(vn);
1687 if (cp != NULL) {
1688 if (match != NULL)
1689 *match = np->n_name;
1690 goto jopen;
1692 np = np->n_flink;
1694 if (name2 != NULL) {
1695 name = name2;
1696 name2 = NULL;
1697 goto jloop;
1701 /* It is the default *smime-sign-cert* / *from* pair */
1702 if((cp = ok_vlook(smime_sign_cert)) == NIL)
1703 goto jerr;
1705 if(match != NIL){
1706 name = fallback_from ? myorigin(NIL) : NIL;
1707 *match = (name == NIL) ? NIL : savestr(name);
1710 jopen:
1711 if((cp = fexpand(cp, (FEXP_NOPROTO | FEXP_LOCAL_FILE | FEXP_NSHELL))
1712 ) == NIL)
1713 goto jleave;
1714 if((fp = mx_fs_open(cp, "r")) == NIL)
1715 n_perr(cp, 0);
1717 jleave:
1718 NYD_OU;
1719 return fp;
1721 jerr:
1722 if (dowarn)
1723 n_err(_("Could not find a certificate for %s%s%s\n"),
1724 xname, (xname2 != NULL ? _("or ") : n_empty),
1725 (xname2 != NULL ? xname2 : n_empty));
1726 goto jleave;
1729 static char const *
1730 a_xtls_smime_sign_include_certs(char const *name)
1732 char const *rv;
1733 NYD_IN;
1735 /* See comments in smime_sign_cert() for algorithm pitfalls */
1736 if (name != NULL) {
1737 struct mx_name *np;
1739 for (np = lextract(name, GTO | GSKIN); np != NULL; np = np->n_flink) {
1740 int vs;
1741 char *vn;
1743 vn = n_lofi_alloc(vs = su_cs_len(np->n_name) + 30);
1744 snprintf(vn, vs, "smime-sign-include-certs-%s", np->n_name);
1745 rv = n_var_vlook(vn, FAL0);
1746 n_lofi_free(vn);
1747 if (rv != NULL)
1748 goto jleave;
1751 rv = ok_vlook(smime_sign_include_certs);
1752 jleave:
1753 NYD_OU;
1754 return rv;
1757 static boole
1758 a_xtls_smime_sign_include_chain_creat(a_XTLS_STACKOF(X509) **chain,
1759 char const *cfiles, char const *addr)
1761 X509 *tmp;
1762 FILE *fp;
1763 char *nfield, *cfield, *x;
1764 NYD_IN;
1766 *chain = sk_X509_new_null();
1768 for (nfield = savestr(cfiles);
1769 (cfield = su_cs_sep_c(&nfield, ',', TRU1)) != NULL;) {
1770 if((x = fexpand(cfield, (FEXP_NOPROTO | FEXP_LOCAL_FILE | FEXP_NSHELL))
1771 ) == NIL || (fp = mx_fs_open(cfield = x, "r")) == NIL){
1772 n_perr(cfiles, 0);
1773 goto jerr;
1775 if ((tmp = PEM_read_X509(fp, NULL, &ssl_password_cb, n_UNCONST(addr))
1776 ) == NULL) {
1777 ssl_gen_err(_("Error reading certificate from %s"),
1778 n_shexp_quote_cp(cfield, FAL0));
1779 mx_fs_close(fp);
1780 goto jerr;
1782 sk_X509_push(*chain, tmp);
1783 mx_fs_close(fp);
1786 if (sk_X509_num(*chain) == 0) {
1787 n_err(_("*smime-sign-include-certs* defined but empty\n"));
1788 goto jerr;
1790 jleave:
1791 NYD_OU;
1792 return (*chain != NULL);
1793 jerr:
1794 sk_X509_pop_free(*chain, X509_free);
1795 *chain = NULL;
1796 goto jleave;
1799 static EVP_MD const *
1800 a_xtls_smime_sign_digest(char const *name, char const **digname,
1801 boole *freeit){
1802 EVP_MD const *md;
1803 char const *cp;
1804 NYD2_IN;
1806 /* See comments in smime_sign_cert() for algorithm pitfalls */
1807 if(name != NIL){
1808 struct mx_name *np;
1810 for(np = lextract(name, GTO | GSKIN); np != NIL; np = np->n_flink){
1811 int vs;
1812 char *vn;
1814 vn = su_LOFI_ALLOC(vs = su_cs_len(np->n_name) + 30);
1815 snprintf(vn, vs, "smime-sign-digest-%s", np->n_name);
1816 if((cp = n_var_vlook(vn, FAL0)) == NIL){
1817 snprintf(vn, vs, "smime-sign-message-digest-%s",np->n_name);/*v15*/
1818 cp = n_var_vlook(vn, FAL0);
1820 su_LOFI_FREE(vn);
1822 if(cp != NIL)
1823 goto jhave_name;
1827 if((cp = ok_vlook(smime_sign_digest)) != NIL)
1828 goto jhave_name;
1829 cp = ok_vlook(smime_sign_message_digest)/* v15 */;
1831 jhave_name:
1832 if(a_xtls_digest_find(FAL0, cp, &md, digname, freeit)){
1833 #ifndef PKCS7_PARTIAL
1834 n_err(_("ALERT: old OpenSSL version, *smime-sign-digest*=%s ignored\n"),
1835 *digname);
1836 #endif
1839 NYD2_OU;
1840 return md;
1843 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1844 static enum okay
1845 load_crl1(X509_STORE *store, char const *name)
1847 X509_LOOKUP *lookup;
1848 enum okay rv = STOP;
1849 NYD_IN;
1851 if (n_poption & n_PO_D_V)
1852 n_err(_("Loading CRL from %s\n"), n_shexp_quote_cp(name, FAL0));
1853 if ((lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) == NULL) {
1854 ssl_gen_err(_("Error creating X509 lookup object"));
1855 goto jleave;
1857 if (X509_load_crl_file(lookup, name, X509_FILETYPE_PEM) != 1) {
1858 ssl_gen_err(_("Error loading CRL from %s"),
1859 n_shexp_quote_cp(name, FAL0));
1860 goto jleave;
1862 rv = OKAY;
1863 jleave:
1864 NYD_OU;
1865 return rv;
1867 #endif /* new OpenSSL */
1869 static enum okay
1870 load_crls(X509_STORE *store, enum okeys fok, enum okeys dok)/*TODO nevertried*/
1872 char *crl_file, *crl_dir;
1873 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1874 DIR *dirp;
1875 struct dirent *dp;
1876 char *fn = NULL;
1877 int fs = 0, ds, es;
1878 #endif
1879 boole any;
1880 enum okay rv;
1881 NYD_IN;
1883 rv = STOP;
1884 any = FAL0;
1886 jredo_v15:
1887 if ((crl_file = n_var_oklook(fok)) != NULL) {
1888 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1889 if((crl_file = fexpand(crl_file, (FEXP_NOPROTO | FEXP_LOCAL_FILE |
1890 FEXP_NSHELL))) == NIL || load_crl1(store, crl_file) != OKAY)
1891 goto jleave;
1892 any = TRU1;
1893 #else
1894 n_err(_("This OpenSSL version is too old to use CRLs\n"));
1895 goto jleave;
1896 #endif
1899 if ((crl_dir = n_var_oklook(dok)) != NULL) {
1900 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1901 char *x;
1903 if((x = fexpand(crl_dir, (FEXP_NOPROTO | FEXP_LOCAL_FILE | FEXP_NSHELL))
1904 ) == NIL || (dirp = opendir(crl_dir = x)) == NIL){
1905 n_perr(crl_dir, 0);
1906 goto jleave;
1909 ds = su_cs_len(crl_dir);
1910 fn = n_alloc(fs = ds + 20);
1911 su_mem_copy(fn, crl_dir, ds);
1912 fn[ds] = '/';
1913 while ((dp = readdir(dirp)) != NULL) {
1914 if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
1915 (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
1916 continue;
1917 if (dp->d_name[0] == '.')
1918 continue;
1919 if (ds + (es = su_cs_len(dp->d_name)) + 2 < fs)
1920 fn = n_realloc(fn, fs = ds + es + 20);
1921 su_mem_copy(fn + ds + 1, dp->d_name, es + 1);
1922 if (load_crl1(store, fn) != OKAY) {
1923 closedir(dirp);
1924 n_free(fn);
1925 goto jleave;
1927 any = TRU1;
1929 closedir(dirp);
1930 n_free(fn);
1931 #else /* old OpenSSL */
1932 n_err(_("This OpenSSL version is too old to use CRLs\n"));
1933 goto jleave;
1934 #endif
1937 if(fok == ok_v_tls_crl_file){
1938 fok = ok_v_ssl_crl_file;
1939 dok = ok_v_ssl_crl_dir;
1940 goto jredo_v15;
1942 #if defined X509_V_FLAG_CRL_CHECK && defined X509_V_FLAG_CRL_CHECK_ALL
1943 if(any)
1944 X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK |
1945 X509_V_FLAG_CRL_CHECK_ALL);
1946 #endif
1947 rv = OKAY;
1948 jleave:
1949 NYD_OU;
1950 return rv;
1953 #if mx_HAVE_RANDOM == mx_RANDOM_IMPL_TLS
1954 FL void
1955 mx_tls_rand_bytes(void *buf, uz blen){
1956 NYD2_IN;
1957 if(!(a_xtls_state & a_XTLS_S_RAND_INIT))
1958 a_xtls_rand_init();
1960 while(blen > 0){
1961 s32 i;
1963 switch(RAND_bytes(buf, i = MIN(S32_MAX, blen))){
1964 default:
1965 /* LibreSSL always succeeds, i think it aborts otherwise.
1966 * With elder OpenSSL we ensure via RAND_status() in
1967 * a_xtls_rand_init() that the PRNG is seeded, so it does not fail.
1969 * With newer OpenSSL we disable automatic reseeding, but do not
1970 * ASSERT RAND_status() ("Since you always have to check RAND_bytes's
1971 * return value now, RAND_status is mostly useless.",
1972 * 20190104180735.GA25041@roeckx.be), so we have not that many options
1973 * on what to do. Since OSs will try hard to serve, a simple sleep
1974 * may be it, so do that */
1975 #if mx_HAVE_TLS != mx_TLS_IMPL_RESSL && !defined mx_XTLS_HAVE_RAND_FILE
1976 n_err(_("TLS RAND_bytes(3ssl) failed (missing entropy?), "
1977 "waiting a bit\n"));
1978 /* Around ~Y2K+1 anything <= was a busy loop iirc, so give pad */
1979 n_msleep(250, FAL0);
1980 continue;
1981 #endif
1982 /* FALLTHRU */
1983 case 1:
1984 break;
1986 blen -= i;
1987 buf = (u8*)buf + i;
1989 NYD2_OU;
1991 #endif /* HAVE_RANDOM == RANDOM_IMPL_TLS */
1993 FL boole
1994 n_tls_open(struct mx_url *urlp, struct mx_socket *sop){ /* TODO split */
1995 void *confp;
1996 SSL_CTX *ctxp;
1997 const EVP_MD *fprnt_mdp;
1998 char const *fprnt, *fprnt_namep;
1999 boole free_md;
2000 NYD_IN;
2002 free_md = FAL0;
2004 a_xtls_init();
2005 n_tls_set_verify_level(urlp); /* TODO should come in via URL! */
2007 sop->s_tls = NULL;
2008 if(urlp->url_cproto != CPROTO_CERTINFO)
2009 fprnt = xok_vlook(tls_fingerprint, urlp, OXM_ALL);
2010 else
2011 fprnt = NULL;
2012 fprnt_namep = NULL;
2013 fprnt_mdp = NULL;
2015 if(fprnt != NIL || urlp->url_cproto == CPROTO_CERTINFO ||
2016 (n_poption & n_PO_D_V)){
2017 fprnt_namep = xok_vlook(tls_fingerprint_digest, urlp, OXM_ALL);
2018 if(!a_xtls_digest_find(TRU1, fprnt_namep, &fprnt_mdp, &fprnt_namep,
2019 &free_md))
2020 goto j_leave;
2023 if((ctxp = SSL_CTX_new(mx_XTLS_CLIENT_METHOD())) == NULL){
2024 ssl_gen_err(_("SSL_CTX_new() failed"));
2025 goto j_leave;
2028 /* Available with OpenSSL 0.9.6 or later */
2029 #ifdef SSL_MODE_AUTO_RETRY
2030 SSL_CTX_set_mode(ctxp, SSL_MODE_AUTO_RETRY);
2031 #endif
2033 if((confp = a_xtls_conf_setup(ctxp, urlp)) == NULL)
2034 goto jleave;
2036 if(!a_xtls_obsolete_conf_vars(confp, urlp))
2037 goto jerr1;
2038 if(!a_xtls_config_pairs(confp, urlp))
2039 goto jerr1;
2040 if((fprnt == NULL || urlp->url_cproto == CPROTO_CERTINFO) &&
2041 !a_xtls_load_verifications(ctxp, urlp))
2042 goto jerr1;
2044 /* Done with context setup, create our new per-connection structure */
2045 if(!a_xtls_conf_finish(&confp, FAL0))
2046 goto jleave;
2047 ASSERT(confp == NULL);
2049 if((sop->s_tls = SSL_new(ctxp)) == NULL){
2050 ssl_gen_err(_("SSL_new() failed"));
2051 goto jleave;
2054 /* Try establish SNI extension; even though this is a TLS extension the
2055 * protocol isn't checked by OpenSSL once the host name is set, and
2056 * therefore i refrained from changing so much code just to check out
2057 * whether we are using SSLv3, which should become more and more rare */
2058 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
2059 if((urlp->url_flags & mx_URL_TLS_MASK) &&
2060 (urlp->url_flags & mx_URL_HOST_IS_NAME)){
2061 if(!SSL_set_tlsext_host_name(sop->s_tls, urlp->url_host.s) &&
2062 (n_poption & n_PO_D_V))
2063 n_err(_("Hostname cannot be used with ServerNameIndication "
2064 "TLS extension: %s\n"),
2065 n_shexp_quote_cp(urlp->url_host.s, FAL0));
2067 #endif
2069 SSL_set_fd(sop->s_tls, sop->s_fd);
2070 mx_socket_reset_io_buf(sop);
2072 if(SSL_connect(sop->s_tls) < 0){
2073 ssl_gen_err(_("could not initiate TLS connection"));
2074 goto jerr2;
2077 if(fprnt != NULL || urlp->url_cproto == CPROTO_CERTINFO ||
2078 n_tls_verify_level != n_TLS_VERIFY_IGNORE){
2079 boole stay;
2080 X509 *peercert;
2082 if((peercert = a_xtls_SSL_get_peer_certificate(sop->s_tls)) == NIL){
2083 n_err(_("TLS: no certificate from peer: %s\n"), urlp->url_h_p.s);
2084 goto jerr2;
2087 stay = FAL0;
2089 if(fprnt == NULL){
2090 if(!a_xtls_check_host(sop, peercert, urlp)){
2091 n_err(_("TLS certificate does not match: %s\n"), urlp->url_h_p.s);
2092 stay = n_tls_verify_decide();
2093 }else{
2094 if(n_poption & n_PO_D_V)
2095 n_err(_("TLS certificate ok\n"));
2096 stay = TRU1;
2100 if(fprnt != NULL || urlp->url_cproto == CPROTO_CERTINFO ||
2101 (n_poption & n_PO_D_V)){
2102 char fpmdhexbuf[EVP_MAX_MD_SIZE * 3], *cp;
2103 unsigned char fpmdbuf[EVP_MAX_MD_SIZE], *ucp;
2104 unsigned int fpmdlen;
2106 if(!X509_digest(peercert, fprnt_mdp, fpmdbuf, &fpmdlen)){
2107 ssl_gen_err(_("TLS %s fingerprint creation failed"), fprnt_namep);
2108 goto jpeer_leave;
2110 ASSERT(fpmdlen <= EVP_MAX_MD_SIZE);
2112 for(cp = fpmdhexbuf, ucp = fpmdbuf; fpmdlen > 0; --fpmdlen){
2113 n_c_to_hex_base16(cp, (char)*ucp++);
2114 cp[2] = ':';
2115 cp += 3;
2117 cp[-1] = '\0';
2119 if(n_poption & n_PO_D_V)
2120 n_err(_("TLS %s fingerprint: %s\n"), fprnt_namep, fpmdhexbuf);
2121 if(fprnt != NULL){
2122 if(!(stay = !su_cs_cmp_case(fprnt, fpmdhexbuf))){
2123 n_err(_("TLS fingerprint mismatch: %s\n"
2124 " Expected: %s\n Detected: %s\n"),
2125 urlp->url_h_p.s, fprnt, fpmdhexbuf);
2126 stay = n_tls_verify_decide();
2127 }else if(n_poption & n_PO_D_V)
2128 n_err(_("TLS fingerprint ok\n"));
2129 goto jpeer_leave;
2130 }else if(urlp->url_cproto == CPROTO_CERTINFO){
2131 char *xcp;
2132 long i;
2133 BIO *biop;
2134 a_XTLS_STACKOF(X509) *certs;
2136 sop->s_tls_finger = savestrbuf(fpmdhexbuf,
2137 P2UZ(cp - fpmdhexbuf));
2139 /* For the sake of `tls cert(chain|ificate)', this too */
2141 /*if((certs = SSL_get_peer_cert_chain(sop->s_tls)) != NIL)*/
2142 if((certs = a_xtls_SSL_get_verified_chain(sop->s_tls)) != NIL){
2143 if((biop = BIO_new(BIO_s_mem())) != NIL){
2144 xcp = NIL;
2145 peercert = NIL;
2147 for(i = 0; i < sk_X509_num(certs); ++i){
2148 peercert = sk_X509_value(certs, i);
2149 if(((n_poption & n_PO_D_V) &&
2150 X509_print(biop, peercert) == 0) ||
2151 PEM_write_bio_X509(biop, peercert) == 0){
2152 ssl_gen_err(_("Error storing certificate %d from %s"),
2153 i, urlp->url_h_p.s);
2154 peercert = NIL;
2155 break;
2158 if(i == 0){
2159 i = BIO_get_mem_data(biop, &xcp);
2160 if(i > 0)
2161 sop->s_tls_certificate = savestrbuf(xcp, i);
2162 i = 0;
2166 if(peercert != NIL){
2167 i = BIO_get_mem_data(biop, &xcp);
2168 if(i > 0)
2169 sop->s_tls_certchain = savestrbuf(xcp, i);
2172 BIO_free(biop);
2178 jpeer_leave:
2179 a_xtls_SSL_get_peer_certificate__FREE(peercert);
2180 if(!stay)
2181 goto jerr2;
2184 if(n_poption & n_PO_D_V){
2185 struct a_xtls_protocol const *xpp;
2186 int ver;
2188 ver = SSL_version(sop->s_tls);
2189 for(xpp = &a_xtls_protocols[1] /* [0] == ALL */;; ++xpp)
2190 if(xpp->xp_version == ver || xpp->xp_last){
2191 n_err(_("TLS connection using %s / %s\n"),
2192 (xpp->xp_last ? n_qm : xpp->xp_name),
2193 SSL_get_cipher(sop->s_tls));
2194 break;
2198 sop->s_use_tls = 1;
2199 jleave:
2200 /* We're fully setup: since we don't reuse the SSL_CTX (pooh) keep it local
2201 * and free it right now -- it is reference counted by sp->s_tls.. */
2202 SSL_CTX_free(ctxp);
2204 j_leave:
2205 #ifdef a_XTLS_CRYPTO_FETCH
2206 if(free_md)
2207 EVP_MD_free(UNCONST(EVP_MD*,fprnt_mdp));
2208 #endif
2210 NYD_OU;
2211 return (sop->s_tls != NIL);
2213 jerr2:
2214 SSL_free(sop->s_tls);
2215 sop->s_tls = NIL;
2216 jerr1:
2217 if(confp != NIL)
2218 a_xtls_conf_finish(&confp, TRU1);
2219 goto jleave;
2222 FL void
2223 ssl_gen_err(char const *fmt, ...)
2225 va_list ap;
2226 NYD_IN;
2228 va_start(ap, fmt);
2229 n_verr(fmt, ap);
2230 va_end(ap);
2232 n_err(_(": %s\n"), ERR_error_string(ERR_get_error(), NULL));
2233 NYD_OU;
2236 FL int
2237 c_verify(void *vp)
2239 int *msgvec = vp, *ip, ec = 0, rv = 1;
2240 X509_STORE *store = NULL;
2241 char *ca_dir, *ca_file;
2242 NYD_IN;
2244 a_xtls_init();
2246 n_tls_verify_level = n_TLS_VERIFY_STRICT;
2247 if ((store = X509_STORE_new()) == NULL) {
2248 ssl_gen_err(_("Error creating X509 store"));
2249 goto jleave;
2251 X509_STORE_set_verify_cb_func(store, &a_xtls_verify_cb);
2253 if((ca_dir = ok_vlook(smime_ca_dir)) != NIL)
2254 ca_dir = fexpand(ca_dir, (FEXP_NOPROTO | FEXP_LOCAL_FILE | FEXP_NSHELL));
2255 if((ca_file = ok_vlook(smime_ca_file)) != NIL)
2256 ca_file = fexpand(ca_file, (FEXP_NOPROTO | FEXP_LOCAL_FILE |
2257 FEXP_NSHELL));
2259 if(ca_file != NIL && a_xtls_X509_STORE_load_file(store, ca_file) != 1){
2260 ssl_gen_err(_("Error loading %s\n"), n_shexp_quote_cp(ca_file, FAL0));
2261 goto jleave;
2264 if(ca_dir != NIL && a_xtls_X509_STORE_load_path(store, ca_dir) != 1){
2265 ssl_gen_err(_("Error loading %s\n"), n_shexp_quote_cp(ca_dir, FAL0));
2266 goto jleave;
2269 /* C99 */{
2270 boole xv15;
2272 if((xv15 = ok_blook(smime_no_default_ca)))
2273 n_OBSOLETE(_("please use *smime-ca-no-defaults*, "
2274 "not *smime-no-default-ca*"));
2275 if(!ok_blook(smime_ca_no_defaults) && !xv15 &&
2276 X509_STORE_set_default_paths(store) != 1) {
2277 ssl_gen_err(_("Error loading built-in default CA locations\n"));
2278 goto jleave;
2282 if (load_crls(store, ok_v_smime_crl_file, ok_v_smime_crl_dir) != OKAY)
2283 goto jleave;
2285 a_xtls_ca_flags(store, ok_vlook(smime_ca_flags));
2287 srelax_hold();
2288 for (ip = msgvec; *ip != 0; ++ip) {
2289 struct message *mp = message + *ip - 1;
2290 setdot(mp);
2291 ec |= smime_verify(mp, *ip, NULL, store);
2292 srelax();
2294 srelax_rele();
2296 if ((rv = ec) != 0)
2297 n_exit_status |= n_EXIT_ERR;
2298 jleave:
2299 if (store != NULL)
2300 X509_STORE_free(store);
2301 NYD_OU;
2302 return rv;
2305 FL FILE *
2306 smime_sign(FILE *ip, char const *addr){
2307 BIO *bb, *sb;
2308 PKCS7 *pkcs7;
2309 char const *name;
2310 a_XTLS_STACKOF(X509) *chain;
2311 X509 *cert;
2312 EVP_PKEY *pkey;
2313 FILE *rv, *sfp, *fp, *bp, *hp;
2314 EVP_MD const *md;
2315 boole bail, free_md;
2316 NYD_IN;
2318 /* TODO smime_sign(): addr should vanish, it is either *from* aka *sender*
2319 * TODO or what we parsed as From:/Sender: from a template. This latter
2320 * TODO should set *from* / *sender* in a scope, we should use *sender*:
2321 * TODO *sender* should be set to the real *from*! */
2322 ASSERT(addr != NIL);
2323 bail = free_md = FAL0;
2324 UNINIT(md, NIL);
2325 rv = sfp = fp = bp = hp = NIL;
2326 pkey = NIL;
2327 cert = NIL;
2328 chain = NIL;
2330 a_xtls_init();
2332 if((fp = smime_sign_cert(addr, NIL, 1, NIL, FAL0)) == NIL)
2333 goto jleave;
2335 if((pkey = PEM_read_PrivateKey(fp, NIL, &ssl_password_cb,
2336 savecat(addr, ".smime-cert-key"))) == NIL){
2337 ssl_gen_err(_("Error reading private key from"));
2338 goto jleave;
2341 rewind(fp);
2343 if((cert = PEM_read_X509(fp, NIL, &ssl_password_cb,
2344 savecat(addr, ".smime-cert-cert"))) == NIL){
2345 ssl_gen_err(_("Error reading signer certificate from"));
2346 goto jleave;
2349 mx_fs_close(fp);
2350 fp = NIL;
2352 if((name = a_xtls_smime_sign_include_certs(addr)) != NIL &&
2353 !a_xtls_smime_sign_include_chain_creat(&chain, name,
2354 savecat(addr, ".smime-include-certs")))
2355 goto jleave;
2357 name = NIL;
2358 if((md = a_xtls_smime_sign_digest(addr, &name, &free_md)) == NIL)
2359 goto jleave;
2361 if((sfp = mx_fs_tmp_open("smimesign", (mx_FS_O_RDWR | mx_FS_O_UNLINK |
2362 mx_FS_O_REGISTER), NIL)) == NIL){
2363 n_perr(_("tempfile"), 0);
2364 goto jleave;
2367 rewind(ip);
2368 if(!mx_smime_split(ip, &hp, &bp, -1, FAL0))
2369 goto jleave;
2371 sb = NIL;
2372 pkcs7 = NIL;
2374 if((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NIL ||
2375 (sb = BIO_new_fp(sfp, BIO_NOCLOSE)) == NIL){
2376 ssl_gen_err(_("Error creating BIO signing objects"));
2377 bail = TRU1;
2378 goto jerr;
2381 #ifdef PKCS7_PARTIAL
2382 if((pkcs7 = PKCS7_sign(NULL, NIL, chain, bb,
2383 (PKCS7_DETACHED | PKCS7_PARTIAL))) == NIL){
2384 ssl_gen_err(_("Error creating the PKCS#7 signing object"));
2385 bail = TRU1;
2386 goto jerr;
2388 if(PKCS7_sign_add_signer(pkcs7, cert, pkey, md,
2389 (PKCS7_DETACHED | PKCS7_PARTIAL)) == NIL){
2390 ssl_gen_err(_("Error setting PKCS#7 signing object signer"));
2391 bail = TRU1;
2392 goto jerr;
2394 if(!PKCS7_final(pkcs7, bb, (PKCS7_DETACHED | PKCS7_PARTIAL))){
2395 ssl_gen_err(_("Error finalizing the PKCS#7 signing object"));
2396 bail = TRU1;
2397 goto jerr;
2399 #else
2400 if((pkcs7 = PKCS7_sign(cert, pkey, chain, bb, PKCS7_DETACHED)) == NIL){
2401 ssl_gen_err(_("Error creating the PKCS#7 signing object"));
2402 bail = TRU1;
2403 goto jerr;
2405 #endif /* !PKCS7_PARTIAL */
2407 if(PEM_write_bio_PKCS7(sb, pkcs7) == 0){
2408 ssl_gen_err(_("Error writing signed S/MIME data"));
2409 bail = TRU1;
2410 /*goto jerr*/
2413 jerr:
2414 if(pkcs7 != NIL)
2415 PKCS7_free(pkcs7);
2416 if(sb != NIL)
2417 BIO_free(sb);
2418 if(bb != NIL)
2419 BIO_free(bb);
2420 if(!bail){
2421 rewind(bp);
2422 fflush_rewind(sfp);
2423 rv = smime_sign_assemble(hp, bp, sfp, name);
2424 hp = bp = sfp = NIL;
2427 jleave:
2428 if(chain != NIL)
2429 sk_X509_pop_free(chain, X509_free);
2430 if(cert != NIL)
2431 X509_free(cert);
2432 if(pkey != NIL)
2433 EVP_PKEY_free(pkey);
2434 if(fp != NIL)
2435 mx_fs_close(fp);
2436 if(hp != NIL)
2437 mx_fs_close(hp);
2438 if(bp != NIL)
2439 mx_fs_close(bp);
2440 if(sfp != NIL)
2441 mx_fs_close(sfp);
2442 #ifdef a_XTLS_CRYPTO_FETCH
2443 if(free_md)
2444 EVP_MD_free(UNCONST(EVP_MD*,md));
2445 #endif
2447 NYD_OU;
2448 return rv;
2451 FL FILE *
2452 smime_encrypt(FILE *ip, char const *xcertfile, char const *to)
2454 FILE *rv, *yp, *fp, *bp, *hp;
2455 X509 *cert;
2456 PKCS7 *pkcs7;
2457 BIO *bb, *yb;
2458 a_XTLS_STACKOF(X509) *certs;
2459 EVP_CIPHER const *cipher;
2460 char *certfile;
2461 boole bail, free_cipher;
2462 NYD_IN;
2464 bail = free_cipher = FAL0;
2465 rv = yp = fp = bp = hp = NULL;
2467 if((certfile = fexpand(xcertfile, (FEXP_NOPROTO | FEXP_LOCAL_FILE |
2468 FEXP_NSHELL))) == NIL)
2469 goto jleave;
2471 a_xtls_init();
2473 if((cipher = a_xtls_smime_cipher(to, &free_cipher)) == NIL)
2474 goto jleave;
2476 if((fp = mx_fs_open(certfile, "r")) == NIL){
2477 n_perr(certfile, 0);
2478 goto jleave;
2480 if ((cert = PEM_read_X509(fp, NULL, &ssl_password_cb, NULL)) == NULL) {
2481 ssl_gen_err(_("Error reading encryption certificate from %s"),
2482 n_shexp_quote_cp(certfile, FAL0));
2483 bail = TRU1;
2485 if (bail)
2486 goto jleave;
2487 mx_fs_close(fp);
2488 fp = NULL;
2489 bail = FAL0;
2491 certs = sk_X509_new_null();
2492 sk_X509_push(certs, cert);
2494 if((yp = mx_fs_tmp_open("smimeenc", (mx_FS_O_RDWR | mx_FS_O_UNLINK |
2495 mx_FS_O_REGISTER), NIL)) == NIL){
2496 n_perr(_("tempfile"), 0);
2497 goto jerr1;
2500 rewind(ip);
2501 if(!mx_smime_split(ip, &hp, &bp, -1, FAL0))
2502 goto jerr1;
2504 yb = NULL;
2505 if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
2506 (yb = BIO_new_fp(yp, BIO_NOCLOSE)) == NULL) {
2507 ssl_gen_err(_("Error creating BIO encryption objects"));
2508 bail = TRU1;
2509 goto jerr2;
2511 if ((pkcs7 = PKCS7_encrypt(certs, bb, cipher, 0)) == NULL) {
2512 ssl_gen_err(_("Error creating the PKCS#7 encryption object"));
2513 bail = TRU1;
2514 goto jerr2;
2516 if (PEM_write_bio_PKCS7(yb, pkcs7) == 0) {
2517 ssl_gen_err(_("Error writing encrypted S/MIME data"));
2518 bail = TRU1;
2519 /* goto jerr2 */
2521 PKCS7_free(pkcs7);
2523 jerr2:
2524 if(bb != NIL)
2525 BIO_free(bb);
2526 if(yb != NIL)
2527 BIO_free(yb);
2528 mx_fs_close(bp);
2529 bp = NIL;
2530 if(!bail){
2531 fflush_rewind(yp);
2532 rv = smime_encrypt_assemble(hp, yp);
2533 hp = yp = NIL;
2535 jerr1:
2536 sk_X509_pop_free(certs, X509_free);
2538 jleave:
2539 if(yp != NIL)
2540 mx_fs_close(yp);
2541 if(fp != NIL)
2542 mx_fs_close(fp);
2543 if(bp != NIL)
2544 mx_fs_close(bp);
2545 if(hp != NIL)
2546 mx_fs_close(hp);
2547 #ifdef a_XTLS_CRYPTO_FETCH
2548 if(free_cipher)
2549 EVP_CIPHER_free(UNCONST(EVP_CIPHER*,cipher));
2550 #endif
2552 NYD_OU;
2553 return rv;
2556 FL struct message *
2557 smime_decrypt(struct message *m, char const *to, char const *cc,
2558 boole is_a_verify_call)
2560 char const *myaddr;
2561 long size;
2562 struct message *rv;
2563 FILE *bp, *hp, *op;
2564 PKCS7 *pkcs7;
2565 BIO *ob, *bb, *pb;
2566 X509 *cert;
2567 EVP_PKEY *pkey;
2568 FILE *yp;
2569 NYD_IN;
2571 pkey = NULL;
2572 cert = NULL;
2573 ob = bb = pb = NULL;
2574 pkcs7 = NULL;
2575 bp = hp = op = NULL;
2576 rv = NULL;
2577 size = m->m_size;
2579 if((yp = setinput(&mb, m, NEED_BODY)) == NULL)
2580 goto jleave;
2582 a_xtls_init();
2584 if((op = smime_sign_cert(to, cc, 0, &myaddr, TRU1)) != NULL){
2585 pkey = PEM_read_PrivateKey(op, NULL, &ssl_password_cb,
2586 savecat(myaddr, ".smime-cert-key"));
2587 if(pkey == NULL){
2588 ssl_gen_err(_("Error reading private key"));
2589 goto jleave;
2592 rewind(op);
2593 if((cert = PEM_read_X509(op, NULL, &ssl_password_cb,
2594 savecat(myaddr, ".smime-cert-cert"))) == NULL){
2595 ssl_gen_err(_("Error reading decryption certificate"));
2596 goto jleave;
2599 mx_fs_close(op);
2600 op = NULL;
2603 if((op = mx_fs_tmp_open("smimed", (mx_FS_O_RDWR | mx_FS_O_UNLINK |
2604 mx_FS_O_REGISTER), NIL)) == NIL){
2605 n_perr(_("tempfile"), 0);
2606 goto jleave;
2609 if(!mx_smime_split(yp, &hp, &bp, size, TRU1))
2610 goto jleave;
2612 if((ob = BIO_new_fp(op, BIO_NOCLOSE)) == NULL ||
2613 (bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL){
2614 ssl_gen_err(_("Error creating BIO decryption objects"));
2615 goto jleave;
2618 if((pkcs7 = SMIME_read_PKCS7(bb, &pb)) == NULL){
2619 ssl_gen_err(_("Error reading PKCS#7 object"));
2620 goto jleave;
2623 if(PKCS7_type_is_signed(pkcs7)){
2624 if(!is_a_verify_call){
2625 setinput(&mb, m, NEED_BODY);
2626 rv = (struct message*)-1;
2627 goto jleave;
2629 if(PKCS7_verify(pkcs7, NULL, NULL, NULL, ob,
2630 PKCS7_NOVERIFY | PKCS7_NOSIGS) != 1)
2631 goto jerr;
2632 fseek(hp, 0L, SEEK_END);
2633 fprintf(hp, "X-Encryption-Cipher: none\n");
2634 fflush_rewind(hp);
2635 }else if(pkey == NULL){
2636 n_err(_("No appropriate private key found\n"));
2637 goto jleave;
2638 }else if(cert == NULL){
2639 n_err(_("No appropriate certificate found\n"));
2640 goto jleave;
2641 }else if(PKCS7_decrypt(pkcs7, pkey, cert, ob, 0) != 1){
2642 jerr:
2643 ssl_gen_err(_("Error decrypting PKCS#7 object"));
2644 goto jleave;
2646 fflush_rewind(op);
2648 mx_fs_close(bp);
2649 bp = NIL;
2651 if((rv = mx_smime_decrypt_assemble(m, hp, op)) == NIL)
2652 n_err(_("I/O error while creating decrypted message\n"));
2653 jleave:
2654 if(op != NIL)
2655 mx_fs_close(op);
2656 if(hp != NIL)
2657 mx_fs_close(hp);
2658 if(bp != NIL)
2659 mx_fs_close(bp);
2660 if(bb != NIL)
2661 BIO_free(bb);
2662 if(ob != NIL)
2663 BIO_free(ob);
2664 if(pkcs7 != NIL)
2665 PKCS7_free(pkcs7);
2666 if(cert != NIL)
2667 X509_free(cert);
2668 if(pkey != NIL)
2669 EVP_PKEY_free(pkey);
2671 NYD_OU;
2672 return rv;
2675 FL enum okay
2676 smime_certsave(struct message *m, int n, FILE *op)
2678 struct message *x;
2679 char *to, *cc, *cnttype;
2680 int c, i;
2681 FILE *fp, *ip;
2682 off_t size;
2683 BIO *fb, *pb;
2684 PKCS7 *pkcs7;
2685 a_XTLS_STACKOF(X509) *certs, *chain = NIL;
2686 X509 *cert;
2687 enum okay rv = STOP;
2688 NYD_IN;
2690 pkcs7 = NULL;
2692 a_xtls_msgno = (uz)n;
2693 jloop:
2694 to = hfield1("to", m);
2695 cc = hfield1("cc", m);
2696 cnttype = hfield1("content-type", m);
2698 if ((ip = setinput(&mb, m, NEED_BODY)) == NULL)
2699 goto jleave;
2701 #undef _X
2702 #undef _Y
2703 #define _X (sizeof("application/") -1)
2704 #define _Y(X) X, sizeof(X) -1
2705 if (cnttype && su_cs_starts_with_case(cnttype, "application/") &&
2706 (!su_cs_cmp_case_n(cnttype + _X, _Y("pkcs7-mime")) ||
2707 !su_cs_cmp_case_n(cnttype + _X, _Y("x-pkcs7-mime")))) {
2708 #undef _Y
2709 #undef _X
2710 if ((x = smime_decrypt(m, to, cc, TRU1)) == NULL)
2711 goto jleave;
2712 if (x != (struct message*)-1) {
2713 m = x;
2714 goto jloop;
2717 size = m->m_size;
2719 if((fp = mx_fs_tmp_open("smimecert", (mx_FS_O_RDWR | mx_FS_O_UNLINK |
2720 mx_FS_O_REGISTER), NIL)) == NIL){
2721 n_perr(_("tempfile"), 0);
2722 goto jleave;
2725 while (size-- > 0) {
2726 c = getc(ip);
2727 putc(c, fp);
2729 fflush(fp);
2731 rewind(fp);
2732 if ((fb = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) {
2733 ssl_gen_err("Error creating BIO object for message %d", n);
2734 mx_fs_close(fp);
2735 goto jleave;
2738 if ((pkcs7 = SMIME_read_PKCS7(fb, &pb)) == NULL) {
2739 ssl_gen_err(_("Error reading PKCS#7 object for message %d"), n);
2740 BIO_free(fb);
2741 mx_fs_close(fp);
2742 goto jleave;
2744 BIO_free(fb);
2745 mx_fs_close(fp);
2747 certs = PKCS7_get0_signers(pkcs7, chain, 0);
2748 if (certs == NULL) {
2749 n_err(_("No certificates found in message %d\n"), n);
2750 goto jleave;
2753 for (i = 0; i < sk_X509_num(certs); ++i) {
2754 cert = sk_X509_value(certs, i);
2755 if (X509_print_fp(op, cert) == 0 || PEM_write_X509(op, cert) == 0) {
2756 ssl_gen_err(_("Error writing certificate %d from message %d"),
2757 i, n);
2758 goto jleave;
2761 rv = OKAY;
2762 jleave:
2763 if(pkcs7 != NULL)
2764 PKCS7_free(pkcs7);
2765 NYD_OU;
2766 return rv;
2769 #include "su/code-ou.h"
2770 #endif /* mx_HAVE_XTLS */
2771 /* s-it-mode */