1/*	$NetBSD: tls_proxy_client_scan.c,v 1.4 2023/12/23 20:30:45 christos Exp $	*/
2
3/*++
4/* NAME
5/*	tls_proxy_client_scan 3
6/* SUMMARY
7/*	read TLS_CLIENT_XXX structures from stream
8/* SYNOPSIS
9/*	#include <tls_proxy.h>
10/*
11/*	int	tls_proxy_client_param_scan(scan_fn, stream, flags, ptr)
12/*	ATTR_SCAN_COMMON_FN scan_fn;
13/*	VSTREAM	*stream;
14/*	int	flags;
15/*	void	*ptr;
16/*
17/*	void	tls_proxy_client_param_free(params)
18/*	TLS_CLIENT_PARAMS *params;
19/*
20/*	int	tls_proxy_client_init_scan(scan_fn, stream, flags, ptr)
21/*	ATTR_SCAN_COMMON_FN scan_fn;
22/*	VSTREAM	*stream;
23/*	int	flags;
24/*	void	*ptr;
25/*
26/*	void	tls_proxy_client_init_free(init_props)
27/*	TLS_CLIENT_INIT_PROPS *init_props;
28/*
29/*	int	tls_proxy_client_start_scan(scan_fn, stream, flags, ptr)
30/*	ATTR_SCAN_COMMON_FN scan_fn;
31/*	VSTREAM	*stream;
32/*	int	flags;
33/*	void	*ptr;
34/*
35/*	void	tls_proxy_client_start_free(start_props)
36/*	TLS_CLIENT_START_PROPS *start_props;
37/* DESCRIPTION
38/*	tls_proxy_client_param_scan() reads a TLS_CLIENT_PARAMS structure from
39/*	the named stream using the specified attribute scan routine.
40/*	tls_proxy_client_param_scan() is meant to be passed as a call-back
41/*	function to attr_scan(), as shown below.
42/*
43/*	tls_proxy_client_param_free() destroys a TLS_CLIENT_PARAMS structure
44/*	that was created by tls_proxy_client_param_scan().
45/*
46/*	TLS_CLIENT_PARAMS *param = 0;
47/*	...
48/*	... RECV_ATTR_FUNC(tls_proxy_client_param_scan, (void *) &param)
49/*	...
50/*	if (param != 0)
51/*	    tls_proxy_client_param_free(param);
52/*
53/*	tls_proxy_client_init_scan() reads a full TLS_CLIENT_INIT_PROPS
54/*	structure from the named stream using the specified attribute
55/*	scan routine. tls_proxy_client_init_scan() is meant to be passed
56/*	as a call-back function to attr_scan(), as shown below.
57/*
58/*	tls_proxy_client_init_free() destroys a TLS_CLIENT_INIT_PROPS
59/*	structure that was created by tls_proxy_client_init_scan().
60/*
61/*	TLS_CLIENT_INIT_PROPS *init_props = 0;
62/*	...
63/*	... RECV_ATTR_FUNC(tls_proxy_client_init_scan, (void *) &init_props)
64/*	...
65/*	if (init_props != 0)
66/*	    tls_proxy_client_init_free(init_props);
67/*
68/*	tls_proxy_client_start_scan() reads a TLS_CLIENT_START_PROPS
69/*	structure, without the stream of file descriptor members,
70/*	from the named stream using the specified attribute scan
71/*	routine. tls_proxy_client_start_scan() is meant to be passed
72/*	as a call-back function to attr_scan(), as shown below.
73/*
74/*	tls_proxy_client_start_free() destroys a TLS_CLIENT_START_PROPS
75/*	structure that was created by tls_proxy_client_start_scan().
76/*
77/*	TLS_CLIENT_START_PROPS *start_props = 0;
78/*	...
79/*	... RECV_ATTR_FUNC(tls_proxy_client_start_scan, (void *) &start_props)
80/*	...
81/*	if (start_props != 0)
82/*	    tls_proxy_client_start_free(start_props);
83/* DIAGNOSTICS
84/*	Fatal: out of memory.
85/* LICENSE
86/* .ad
87/* .fi
88/*	The Secure Mailer license must be distributed with this software.
89/* AUTHOR(S)
90/*	Wietse Venema
91/*	Google, Inc.
92/*	111 8th Avenue
93/*	New York, NY 10011, USA
94/*--*/
95
96#ifdef USE_TLS
97
98/* System library. */
99
100#include <sys_defs.h>
101
102/* Utility library */
103
104#include <argv_attr.h>
105#include <attr.h>
106#include <msg.h>
107#include <vstring.h>
108
109/* Global library. */
110
111#include <mail_params.h>
112
113/* TLS library. */
114
115#define TLS_INTERNAL
116#include <tls.h>
117#include <tls_proxy.h>
118
119#define STR(x) vstring_str(x)
120#define LEN(x) VSTRING_LEN(x)
121
122/* tls_proxy_client_param_free - destroy TLS_CLIENT_PARAMS structure */
123
124void    tls_proxy_client_param_free(TLS_CLIENT_PARAMS *params)
125{
126    myfree(params->tls_cnf_file);
127    myfree(params->tls_cnf_name);
128    myfree(params->tls_high_clist);
129    myfree(params->tls_medium_clist);
130    myfree(params->tls_null_clist);
131    myfree(params->tls_eecdh_auto);
132    myfree(params->tls_eecdh_strong);
133    myfree(params->tls_eecdh_ultra);
134    myfree(params->tls_ffdhe_auto);
135    myfree(params->tls_bug_tweaks);
136    myfree(params->tls_ssl_options);
137    myfree(params->tls_dane_digests);
138    myfree(params->tls_mgr_service);
139    myfree(params->tls_tkt_cipher);
140    myfree((void *) params);
141}
142
143/* tls_proxy_client_param_scan - receive TLS_CLIENT_PARAMS from stream */
144
145int     tls_proxy_client_param_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
146				            int flags, void *ptr)
147{
148    TLS_CLIENT_PARAMS *params
149    = (TLS_CLIENT_PARAMS *) mymalloc(sizeof(*params));
150    int     ret;
151    VSTRING *cnf_file = vstring_alloc(25);
152    VSTRING *cnf_name = vstring_alloc(25);
153    VSTRING *tls_high_clist = vstring_alloc(25);
154    VSTRING *tls_medium_clist = vstring_alloc(25);
155    VSTRING *tls_null_clist = vstring_alloc(25);
156    VSTRING *tls_eecdh_auto = vstring_alloc(25);
157    VSTRING *tls_eecdh_strong = vstring_alloc(25);
158    VSTRING *tls_eecdh_ultra = vstring_alloc(25);
159    VSTRING *tls_ffdhe_auto = vstring_alloc(25);
160    VSTRING *tls_bug_tweaks = vstring_alloc(25);
161    VSTRING *tls_ssl_options = vstring_alloc(25);
162    VSTRING *tls_dane_digests = vstring_alloc(25);
163    VSTRING *tls_mgr_service = vstring_alloc(25);
164    VSTRING *tls_tkt_cipher = vstring_alloc(25);
165
166    if (msg_verbose)
167	msg_info("begin tls_proxy_client_param_scan");
168
169    /*
170     * Note: memset() is not a portable way to initialize non-integer types.
171     */
172    memset(params, 0, sizeof(*params));
173    ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
174		  RECV_ATTR_STR(TLS_ATTR_CNF_FILE, cnf_file),
175		  RECV_ATTR_STR(TLS_ATTR_CNF_NAME, cnf_name),
176		  RECV_ATTR_STR(VAR_TLS_HIGH_CLIST, tls_high_clist),
177		  RECV_ATTR_STR(VAR_TLS_MEDIUM_CLIST, tls_medium_clist),
178		  RECV_ATTR_STR(VAR_TLS_NULL_CLIST, tls_null_clist),
179		  RECV_ATTR_STR(VAR_TLS_EECDH_AUTO, tls_eecdh_auto),
180		  RECV_ATTR_STR(VAR_TLS_EECDH_STRONG, tls_eecdh_strong),
181		  RECV_ATTR_STR(VAR_TLS_EECDH_ULTRA, tls_eecdh_ultra),
182		  RECV_ATTR_STR(VAR_TLS_FFDHE_AUTO, tls_ffdhe_auto),
183		  RECV_ATTR_STR(VAR_TLS_BUG_TWEAKS, tls_bug_tweaks),
184		  RECV_ATTR_STR(VAR_TLS_SSL_OPTIONS, tls_ssl_options),
185		  RECV_ATTR_STR(VAR_TLS_DANE_DIGESTS, tls_dane_digests),
186		  RECV_ATTR_STR(VAR_TLS_MGR_SERVICE, tls_mgr_service),
187		  RECV_ATTR_STR(VAR_TLS_TKT_CIPHER, tls_tkt_cipher),
188		  RECV_ATTR_INT(VAR_TLS_DAEMON_RAND_BYTES,
189				&params->tls_daemon_rand_bytes),
190		  RECV_ATTR_INT(VAR_TLS_APPEND_DEF_CA,
191				&params->tls_append_def_CA),
192		  RECV_ATTR_INT(VAR_TLS_BC_PKEY_FPRINT,
193				&params->tls_bc_pkey_fprint),
194		  RECV_ATTR_INT(VAR_TLS_PREEMPT_CLIST,
195				&params->tls_preempt_clist),
196		  RECV_ATTR_INT(VAR_TLS_MULTI_WILDCARD,
197				&params->tls_multi_wildcard),
198		  ATTR_TYPE_END);
199    /* Always construct a well-formed structure. */
200    params->tls_cnf_file = vstring_export(cnf_file);
201    params->tls_cnf_name = vstring_export(cnf_name);
202    params->tls_high_clist = vstring_export(tls_high_clist);
203    params->tls_medium_clist = vstring_export(tls_medium_clist);
204    params->tls_null_clist = vstring_export(tls_null_clist);
205    params->tls_eecdh_auto = vstring_export(tls_eecdh_auto);
206    params->tls_eecdh_strong = vstring_export(tls_eecdh_strong);
207    params->tls_eecdh_ultra = vstring_export(tls_eecdh_ultra);
208    params->tls_ffdhe_auto = vstring_export(tls_ffdhe_auto);
209    params->tls_bug_tweaks = vstring_export(tls_bug_tweaks);
210    params->tls_ssl_options = vstring_export(tls_ssl_options);
211    params->tls_dane_digests = vstring_export(tls_dane_digests);
212    params->tls_mgr_service = vstring_export(tls_mgr_service);
213    params->tls_tkt_cipher = vstring_export(tls_tkt_cipher);
214
215    ret = (ret == 19 ? 1 : -1);
216    if (ret != 1) {
217	tls_proxy_client_param_free(params);
218	params = 0;
219    }
220    *(TLS_CLIENT_PARAMS **) ptr = params;
221    if (msg_verbose)
222	msg_info("tls_proxy_client_param_scan ret=%d", ret);
223    return (ret);
224}
225
226/* tls_proxy_client_init_free - destroy TLS_CLIENT_INIT_PROPS structure */
227
228void    tls_proxy_client_init_free(TLS_CLIENT_INIT_PROPS *props)
229{
230    myfree((void *) props->log_param);
231    myfree((void *) props->log_level);
232    myfree((void *) props->cache_type);
233    myfree((void *) props->chain_files);
234    myfree((void *) props->cert_file);
235    myfree((void *) props->key_file);
236    myfree((void *) props->dcert_file);
237    myfree((void *) props->dkey_file);
238    myfree((void *) props->eccert_file);
239    myfree((void *) props->eckey_file);
240    myfree((void *) props->CAfile);
241    myfree((void *) props->CApath);
242    myfree((void *) props->mdalg);
243    myfree((void *) props);
244}
245
246/* tls_proxy_client_init_scan - receive TLS_CLIENT_INIT_PROPS from stream */
247
248int     tls_proxy_client_init_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
249				           int flags, void *ptr)
250{
251    TLS_CLIENT_INIT_PROPS *props
252    = (TLS_CLIENT_INIT_PROPS *) mymalloc(sizeof(*props));
253    int     ret;
254    VSTRING *log_param = vstring_alloc(25);
255    VSTRING *log_level = vstring_alloc(25);
256    VSTRING *cache_type = vstring_alloc(25);
257    VSTRING *chain_files = vstring_alloc(25);
258    VSTRING *cert_file = vstring_alloc(25);
259    VSTRING *key_file = vstring_alloc(25);
260    VSTRING *dcert_file = vstring_alloc(25);
261    VSTRING *dkey_file = vstring_alloc(25);
262    VSTRING *eccert_file = vstring_alloc(25);
263    VSTRING *eckey_file = vstring_alloc(25);
264    VSTRING *CAfile = vstring_alloc(25);
265    VSTRING *CApath = vstring_alloc(25);
266    VSTRING *mdalg = vstring_alloc(25);
267
268    if (msg_verbose)
269	msg_info("begin tls_proxy_client_init_scan");
270
271    /*
272     * Note: memset() is not a portable way to initialize non-integer types.
273     */
274    memset(props, 0, sizeof(*props));
275    ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
276		  RECV_ATTR_STR(TLS_ATTR_LOG_PARAM, log_param),
277		  RECV_ATTR_STR(TLS_ATTR_LOG_LEVEL, log_level),
278		  RECV_ATTR_INT(TLS_ATTR_VERIFYDEPTH, &props->verifydepth),
279		  RECV_ATTR_STR(TLS_ATTR_CACHE_TYPE, cache_type),
280		  RECV_ATTR_STR(TLS_ATTR_CHAIN_FILES, chain_files),
281		  RECV_ATTR_STR(TLS_ATTR_CERT_FILE, cert_file),
282		  RECV_ATTR_STR(TLS_ATTR_KEY_FILE, key_file),
283		  RECV_ATTR_STR(TLS_ATTR_DCERT_FILE, dcert_file),
284		  RECV_ATTR_STR(TLS_ATTR_DKEY_FILE, dkey_file),
285		  RECV_ATTR_STR(TLS_ATTR_ECCERT_FILE, eccert_file),
286		  RECV_ATTR_STR(TLS_ATTR_ECKEY_FILE, eckey_file),
287		  RECV_ATTR_STR(TLS_ATTR_CAFILE, CAfile),
288		  RECV_ATTR_STR(TLS_ATTR_CAPATH, CApath),
289		  RECV_ATTR_STR(TLS_ATTR_MDALG, mdalg),
290		  ATTR_TYPE_END);
291    /* Always construct a well-formed structure. */
292    props->log_param = vstring_export(log_param);
293    props->log_level = vstring_export(log_level);
294    props->cache_type = vstring_export(cache_type);
295    props->chain_files = vstring_export(chain_files);
296    props->cert_file = vstring_export(cert_file);
297    props->key_file = vstring_export(key_file);
298    props->dcert_file = vstring_export(dcert_file);
299    props->dkey_file = vstring_export(dkey_file);
300    props->eccert_file = vstring_export(eccert_file);
301    props->eckey_file = vstring_export(eckey_file);
302    props->CAfile = vstring_export(CAfile);
303    props->CApath = vstring_export(CApath);
304    props->mdalg = vstring_export(mdalg);
305    ret = (ret == 14 ? 1 : -1);
306    if (ret != 1) {
307	tls_proxy_client_init_free(props);
308	props = 0;
309    }
310    *(TLS_CLIENT_INIT_PROPS **) ptr = props;
311    if (msg_verbose)
312	msg_info("tls_proxy_client_init_scan ret=%d", ret);
313    return (ret);
314}
315
316/* tls_proxy_client_start_free - destroy TLS_CLIENT_START_PROPS structure */
317
318void    tls_proxy_client_start_free(TLS_CLIENT_START_PROPS *props)
319{
320    myfree((void *) props->nexthop);
321    myfree((void *) props->host);
322    myfree((void *) props->namaddr);
323    myfree((void *) props->sni);
324    myfree((void *) props->serverid);
325    myfree((void *) props->helo);
326    myfree((void *) props->protocols);
327    myfree((void *) props->cipher_grade);
328    myfree((void *) props->cipher_exclusions);
329    if (props->matchargv)
330	argv_free((ARGV *) props->matchargv);
331    myfree((void *) props->mdalg);
332    if (props->dane)
333	tls_dane_free((TLS_DANE *) props->dane);
334    myfree((void *) props);
335}
336
337/* tls_proxy_client_tlsa_scan - receive TLS_TLSA from stream */
338
339static int tls_proxy_client_tlsa_scan(ATTR_SCAN_COMMON_FN scan_fn,
340				          VSTREAM *fp, int flags, void *ptr)
341{
342    static VSTRING *data;
343    TLS_TLSA *head;
344    int     count;
345    int     ret;
346
347    if (data == 0)
348	data = vstring_alloc(64);
349
350    ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
351		  RECV_ATTR_INT(TLS_ATTR_COUNT, &count),
352		  ATTR_TYPE_END);
353    if (ret == 1 && msg_verbose)
354	msg_info("tls_proxy_client_tlsa_scan count=%d", count);
355
356    for (head = 0; ret == 1 && count > 0; --count) {
357	int     u, s, m;
358
359	ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
360		      RECV_ATTR_INT(TLS_ATTR_USAGE, &u),
361		      RECV_ATTR_INT(TLS_ATTR_SELECTOR, &s),
362		      RECV_ATTR_INT(TLS_ATTR_MTYPE, &m),
363		      RECV_ATTR_DATA(TLS_ATTR_DATA, data),
364		      ATTR_TYPE_END);
365	if (ret == 4) {
366	    ret = 1;
367	    /* This makes a copy of the static vstring content */
368	    head = tlsa_prepend(head, u, s, m, (unsigned char *) STR(data),
369				LEN(data));
370	} else
371	    ret = -1;
372    }
373
374    if (ret != 1) {
375	tls_tlsa_free(head);
376	head = 0;
377    }
378    *(TLS_TLSA **) ptr = head;
379    if (msg_verbose)
380	msg_info("tls_proxy_client_tlsa_scan ret=%d", ret);
381    return (ret);
382}
383
384/* tls_proxy_client_dane_scan - receive TLS_DANE from stream */
385
386static int tls_proxy_client_dane_scan(ATTR_SCAN_COMMON_FN scan_fn,
387				          VSTREAM *fp, int flags, void *ptr)
388{
389    TLS_DANE *dane = 0;
390    int     ret;
391    int     have_dane = 0;
392
393    ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
394		  RECV_ATTR_INT(TLS_ATTR_DANE, &have_dane),
395		  ATTR_TYPE_END);
396    if (msg_verbose)
397	msg_info("tls_proxy_client_dane_scan have_dane=%d", have_dane);
398
399    if (ret == 1 && have_dane) {
400	VSTRING *base_domain = vstring_alloc(25);
401
402	dane = tls_dane_alloc();
403	/* We only need the base domain and TLSA RRs */
404	ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
405		      RECV_ATTR_STR(TLS_ATTR_DOMAIN, base_domain),
406		      RECV_ATTR_FUNC(tls_proxy_client_tlsa_scan,
407				     &dane->tlsa),
408		      ATTR_TYPE_END);
409
410	/* Always construct a well-formed structure. */
411	dane->base_domain = vstring_export(base_domain);
412	ret = (ret == 2 ? 1 : -1);
413	if (ret != 1) {
414	    tls_dane_free(dane);
415	    dane = 0;
416	}
417    }
418    *(TLS_DANE **) ptr = dane;
419    if (msg_verbose)
420	msg_info("tls_proxy_client_dane_scan ret=%d", ret);
421    return (ret);
422}
423
424/* tls_proxy_client_start_scan - receive TLS_CLIENT_START_PROPS from stream */
425
426int     tls_proxy_client_start_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
427				            int flags, void *ptr)
428{
429    TLS_CLIENT_START_PROPS *props
430    = (TLS_CLIENT_START_PROPS *) mymalloc(sizeof(*props));
431    int     ret;
432    VSTRING *nexthop = vstring_alloc(25);
433    VSTRING *host = vstring_alloc(25);
434    VSTRING *namaddr = vstring_alloc(25);
435    VSTRING *sni = vstring_alloc(25);
436    VSTRING *serverid = vstring_alloc(25);
437    VSTRING *helo = vstring_alloc(25);
438    VSTRING *protocols = vstring_alloc(25);
439    VSTRING *cipher_grade = vstring_alloc(25);
440    VSTRING *cipher_exclusions = vstring_alloc(25);
441    VSTRING *mdalg = vstring_alloc(25);
442
443    if (msg_verbose)
444	msg_info("begin tls_proxy_client_start_scan");
445
446    /*
447     * Note: memset() is not a portable way to initialize non-integer types.
448     */
449    memset(props, 0, sizeof(*props));
450    props->ctx = 0;
451    props->stream = 0;
452    props->fd = -1;
453    props->dane = 0;				/* scan_fn may return early */
454    ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
455		  RECV_ATTR_INT(TLS_ATTR_TIMEOUT, &props->timeout),
456		  RECV_ATTR_INT(TLS_ATTR_TLS_LEVEL, &props->tls_level),
457		  RECV_ATTR_STR(TLS_ATTR_NEXTHOP, nexthop),
458		  RECV_ATTR_STR(TLS_ATTR_HOST, host),
459		  RECV_ATTR_STR(TLS_ATTR_NAMADDR, namaddr),
460		  RECV_ATTR_STR(TLS_ATTR_SNI, sni),
461		  RECV_ATTR_STR(TLS_ATTR_SERVERID, serverid),
462		  RECV_ATTR_STR(TLS_ATTR_HELO, helo),
463		  RECV_ATTR_STR(TLS_ATTR_PROTOCOLS, protocols),
464		  RECV_ATTR_STR(TLS_ATTR_CIPHER_GRADE, cipher_grade),
465		  RECV_ATTR_STR(TLS_ATTR_CIPHER_EXCLUSIONS,
466				cipher_exclusions),
467		  RECV_ATTR_FUNC(argv_attr_scan, &props->matchargv),
468		  RECV_ATTR_STR(TLS_ATTR_MDALG, mdalg),
469		  RECV_ATTR_FUNC(tls_proxy_client_dane_scan,
470				 &props->dane),
471		  ATTR_TYPE_END);
472    /* Always construct a well-formed structure. */
473    props->nexthop = vstring_export(nexthop);
474    props->host = vstring_export(host);
475    props->namaddr = vstring_export(namaddr);
476    props->sni = vstring_export(sni);
477    props->serverid = vstring_export(serverid);
478    props->helo = vstring_export(helo);
479    props->protocols = vstring_export(protocols);
480    props->cipher_grade = vstring_export(cipher_grade);
481    props->cipher_exclusions = vstring_export(cipher_exclusions);
482    props->mdalg = vstring_export(mdalg);
483    ret = (ret == 14 ? 1 : -1);
484    if (ret != 1) {
485	tls_proxy_client_start_free(props);
486	props = 0;
487    }
488    *(TLS_CLIENT_START_PROPS **) ptr = props;
489    if (msg_verbose)
490	msg_info("tls_proxy_client_start_scan ret=%d", ret);
491    return (ret);
492}
493
494#endif
495