xref: /netbsd-src/external/ibm-public/postfix/dist/src/tls/tls_proxy_client_scan.c (revision d16b7486a53dcb8072b60ec6fcb4373a2d0c27b7)
1 /*	$NetBSD: tls_proxy_client_scan.c,v 1.3 2022/10/08 16:12:50 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 
124 void    tls_proxy_client_param_free(TLS_CLIENT_PARAMS *params)
125 {
126     myfree(params->tls_high_clist);
127     myfree(params->tls_medium_clist);
128     myfree(params->tls_low_clist);
129     myfree(params->tls_export_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_bug_tweaks);
135     myfree(params->tls_ssl_options);
136     myfree(params->tls_dane_digests);
137     myfree(params->tls_mgr_service);
138     myfree(params->tls_tkt_cipher);
139     myfree((void *) params);
140 }
141 
142 /* tls_proxy_client_param_scan - receive TLS_CLIENT_PARAMS from stream */
143 
144 int     tls_proxy_client_param_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
145 				            int flags, void *ptr)
146 {
147     TLS_CLIENT_PARAMS *params
148     = (TLS_CLIENT_PARAMS *) mymalloc(sizeof(*params));
149     int     ret;
150     VSTRING *tls_high_clist = vstring_alloc(25);
151     VSTRING *tls_medium_clist = vstring_alloc(25);
152     VSTRING *tls_low_clist = vstring_alloc(25);
153     VSTRING *tls_export_clist = vstring_alloc(25);
154     VSTRING *tls_null_clist = vstring_alloc(25);
155     VSTRING *tls_eecdh_auto = vstring_alloc(25);
156     VSTRING *tls_eecdh_strong = vstring_alloc(25);
157     VSTRING *tls_eecdh_ultra = vstring_alloc(25);
158     VSTRING *tls_bug_tweaks = vstring_alloc(25);
159     VSTRING *tls_ssl_options = vstring_alloc(25);
160     VSTRING *tls_dane_digests = vstring_alloc(25);
161     VSTRING *tls_mgr_service = vstring_alloc(25);
162     VSTRING *tls_tkt_cipher = vstring_alloc(25);
163 
164     if (msg_verbose)
165 	msg_info("begin tls_proxy_client_param_scan");
166 
167     /*
168      * Note: memset() is not a portable way to initialize non-integer types.
169      */
170     memset(params, 0, sizeof(*params));
171     ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
172 		  RECV_ATTR_STR(VAR_TLS_HIGH_CLIST, tls_high_clist),
173 		  RECV_ATTR_STR(VAR_TLS_MEDIUM_CLIST, tls_medium_clist),
174 		  RECV_ATTR_STR(VAR_TLS_LOW_CLIST, tls_low_clist),
175 		  RECV_ATTR_STR(VAR_TLS_EXPORT_CLIST, tls_export_clist),
176 		  RECV_ATTR_STR(VAR_TLS_NULL_CLIST, tls_null_clist),
177 		  RECV_ATTR_STR(VAR_TLS_EECDH_AUTO, tls_eecdh_auto),
178 		  RECV_ATTR_STR(VAR_TLS_EECDH_STRONG, tls_eecdh_strong),
179 		  RECV_ATTR_STR(VAR_TLS_EECDH_ULTRA, tls_eecdh_ultra),
180 		  RECV_ATTR_STR(VAR_TLS_BUG_TWEAKS, tls_bug_tweaks),
181 		  RECV_ATTR_STR(VAR_TLS_SSL_OPTIONS, tls_ssl_options),
182 		  RECV_ATTR_STR(VAR_TLS_DANE_DIGESTS, tls_dane_digests),
183 		  RECV_ATTR_STR(VAR_TLS_MGR_SERVICE, tls_mgr_service),
184 		  RECV_ATTR_STR(VAR_TLS_TKT_CIPHER, tls_tkt_cipher),
185 		  RECV_ATTR_INT(VAR_TLS_DAEMON_RAND_BYTES,
186 				&params->tls_daemon_rand_bytes),
187 		  RECV_ATTR_INT(VAR_TLS_APPEND_DEF_CA,
188 				&params->tls_append_def_CA),
189 		  RECV_ATTR_INT(VAR_TLS_BC_PKEY_FPRINT,
190 				&params->tls_bc_pkey_fprint),
191 		  RECV_ATTR_INT(VAR_TLS_PREEMPT_CLIST,
192 				&params->tls_preempt_clist),
193 		  RECV_ATTR_INT(VAR_TLS_MULTI_WILDCARD,
194 				&params->tls_multi_wildcard),
195 		  ATTR_TYPE_END);
196     /* Always construct a well-formed structure. */
197     params->tls_high_clist = vstring_export(tls_high_clist);
198     params->tls_medium_clist = vstring_export(tls_medium_clist);
199     params->tls_low_clist = vstring_export(tls_low_clist);
200     params->tls_export_clist = vstring_export(tls_export_clist);
201     params->tls_null_clist = vstring_export(tls_null_clist);
202     params->tls_eecdh_auto = vstring_export(tls_eecdh_auto);
203     params->tls_eecdh_strong = vstring_export(tls_eecdh_strong);
204     params->tls_eecdh_ultra = vstring_export(tls_eecdh_ultra);
205     params->tls_bug_tweaks = vstring_export(tls_bug_tweaks);
206     params->tls_ssl_options = vstring_export(tls_ssl_options);
207     params->tls_dane_digests = vstring_export(tls_dane_digests);
208     params->tls_mgr_service = vstring_export(tls_mgr_service);
209     params->tls_tkt_cipher = vstring_export(tls_tkt_cipher);
210 
211     ret = (ret == 18 ? 1 : -1);
212     if (ret != 1) {
213 	tls_proxy_client_param_free(params);
214 	params = 0;
215     }
216     *(TLS_CLIENT_PARAMS **) ptr = params;
217     if (msg_verbose)
218 	msg_info("tls_proxy_client_param_scan ret=%d", ret);
219     return (ret);
220 }
221 
222 /* tls_proxy_client_init_free - destroy TLS_CLIENT_INIT_PROPS structure */
223 
224 void    tls_proxy_client_init_free(TLS_CLIENT_INIT_PROPS *props)
225 {
226     myfree((void *) props->log_param);
227     myfree((void *) props->log_level);
228     myfree((void *) props->cache_type);
229     myfree((void *) props->chain_files);
230     myfree((void *) props->cert_file);
231     myfree((void *) props->key_file);
232     myfree((void *) props->dcert_file);
233     myfree((void *) props->dkey_file);
234     myfree((void *) props->eccert_file);
235     myfree((void *) props->eckey_file);
236     myfree((void *) props->CAfile);
237     myfree((void *) props->CApath);
238     myfree((void *) props->mdalg);
239     myfree((void *) props);
240 }
241 
242 /* tls_proxy_client_init_scan - receive TLS_CLIENT_INIT_PROPS from stream */
243 
244 int     tls_proxy_client_init_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
245 				           int flags, void *ptr)
246 {
247     TLS_CLIENT_INIT_PROPS *props
248     = (TLS_CLIENT_INIT_PROPS *) mymalloc(sizeof(*props));
249     int     ret;
250     VSTRING *log_param = vstring_alloc(25);
251     VSTRING *log_level = vstring_alloc(25);
252     VSTRING *cache_type = vstring_alloc(25);
253     VSTRING *chain_files = vstring_alloc(25);
254     VSTRING *cert_file = vstring_alloc(25);
255     VSTRING *key_file = vstring_alloc(25);
256     VSTRING *dcert_file = vstring_alloc(25);
257     VSTRING *dkey_file = vstring_alloc(25);
258     VSTRING *eccert_file = vstring_alloc(25);
259     VSTRING *eckey_file = vstring_alloc(25);
260     VSTRING *CAfile = vstring_alloc(25);
261     VSTRING *CApath = vstring_alloc(25);
262     VSTRING *mdalg = vstring_alloc(25);
263 
264     if (msg_verbose)
265 	msg_info("begin tls_proxy_client_init_scan");
266 
267     /*
268      * Note: memset() is not a portable way to initialize non-integer types.
269      */
270     memset(props, 0, sizeof(*props));
271     ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
272 		  RECV_ATTR_STR(TLS_ATTR_LOG_PARAM, log_param),
273 		  RECV_ATTR_STR(TLS_ATTR_LOG_LEVEL, log_level),
274 		  RECV_ATTR_INT(TLS_ATTR_VERIFYDEPTH, &props->verifydepth),
275 		  RECV_ATTR_STR(TLS_ATTR_CACHE_TYPE, cache_type),
276 		  RECV_ATTR_STR(TLS_ATTR_CHAIN_FILES, chain_files),
277 		  RECV_ATTR_STR(TLS_ATTR_CERT_FILE, cert_file),
278 		  RECV_ATTR_STR(TLS_ATTR_KEY_FILE, key_file),
279 		  RECV_ATTR_STR(TLS_ATTR_DCERT_FILE, dcert_file),
280 		  RECV_ATTR_STR(TLS_ATTR_DKEY_FILE, dkey_file),
281 		  RECV_ATTR_STR(TLS_ATTR_ECCERT_FILE, eccert_file),
282 		  RECV_ATTR_STR(TLS_ATTR_ECKEY_FILE, eckey_file),
283 		  RECV_ATTR_STR(TLS_ATTR_CAFILE, CAfile),
284 		  RECV_ATTR_STR(TLS_ATTR_CAPATH, CApath),
285 		  RECV_ATTR_STR(TLS_ATTR_MDALG, mdalg),
286 		  ATTR_TYPE_END);
287     /* Always construct a well-formed structure. */
288     props->log_param = vstring_export(log_param);
289     props->log_level = vstring_export(log_level);
290     props->cache_type = vstring_export(cache_type);
291     props->chain_files = vstring_export(chain_files);
292     props->cert_file = vstring_export(cert_file);
293     props->key_file = vstring_export(key_file);
294     props->dcert_file = vstring_export(dcert_file);
295     props->dkey_file = vstring_export(dkey_file);
296     props->eccert_file = vstring_export(eccert_file);
297     props->eckey_file = vstring_export(eckey_file);
298     props->CAfile = vstring_export(CAfile);
299     props->CApath = vstring_export(CApath);
300     props->mdalg = vstring_export(mdalg);
301     ret = (ret == 14 ? 1 : -1);
302     if (ret != 1) {
303 	tls_proxy_client_init_free(props);
304 	props = 0;
305     }
306     *(TLS_CLIENT_INIT_PROPS **) ptr = props;
307     if (msg_verbose)
308 	msg_info("tls_proxy_client_init_scan ret=%d", ret);
309     return (ret);
310 }
311 
312 /* tls_proxy_client_start_free - destroy TLS_CLIENT_START_PROPS structure */
313 
314 void    tls_proxy_client_start_free(TLS_CLIENT_START_PROPS *props)
315 {
316     myfree((void *) props->nexthop);
317     myfree((void *) props->host);
318     myfree((void *) props->namaddr);
319     myfree((void *) props->sni);
320     myfree((void *) props->serverid);
321     myfree((void *) props->helo);
322     myfree((void *) props->protocols);
323     myfree((void *) props->cipher_grade);
324     myfree((void *) props->cipher_exclusions);
325     if (props->matchargv)
326 	argv_free((ARGV *) props->matchargv);
327     myfree((void *) props->mdalg);
328     if (props->dane)
329 	tls_dane_free((TLS_DANE *) props->dane);
330     myfree((void *) props);
331 }
332 
333 /* tls_proxy_client_tlsa_scan - receive TLS_TLSA from stream */
334 
335 static int tls_proxy_client_tlsa_scan(ATTR_SCAN_COMMON_FN scan_fn,
336 				          VSTREAM *fp, int flags, void *ptr)
337 {
338     static VSTRING *data;
339     TLS_TLSA *head;
340     int     count;
341     int     ret;
342 
343     if (data == 0)
344 	data = vstring_alloc(64);
345 
346     ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
347 		  RECV_ATTR_INT(TLS_ATTR_COUNT, &count),
348 		  ATTR_TYPE_END);
349     if (ret == 1 && msg_verbose)
350 	msg_info("tls_proxy_client_tlsa_scan count=%d", count);
351 
352     for (head = 0; ret == 1 && count > 0; --count) {
353 	int     u, s, m;
354 
355 	ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
356 		      RECV_ATTR_INT(TLS_ATTR_USAGE, &u),
357 		      RECV_ATTR_INT(TLS_ATTR_SELECTOR, &s),
358 		      RECV_ATTR_INT(TLS_ATTR_MTYPE, &m),
359 		      RECV_ATTR_DATA(TLS_ATTR_DATA, data),
360 		      ATTR_TYPE_END);
361 	if (ret == 4) {
362 	    ret = 1;
363 	    /* This makes a copy of the static vstring content */
364 	    head = tlsa_prepend(head, u, s, m, (unsigned char *) STR(data),
365 				LEN(data));
366 	} else
367 	    ret = -1;
368     }
369 
370     if (ret != 1) {
371 	tls_tlsa_free(head);
372 	head = 0;
373     }
374     *(TLS_TLSA **) ptr = head;
375     if (msg_verbose)
376 	msg_info("tls_proxy_client_tlsa_scan ret=%d", ret);
377     return (ret);
378 }
379 
380 /* tls_proxy_client_dane_scan - receive TLS_DANE from stream */
381 
382 static int tls_proxy_client_dane_scan(ATTR_SCAN_COMMON_FN scan_fn,
383 				          VSTREAM *fp, int flags, void *ptr)
384 {
385     TLS_DANE *dane = 0;
386     int     ret;
387     int     have_dane = 0;
388 
389     ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
390 		  RECV_ATTR_INT(TLS_ATTR_DANE, &have_dane),
391 		  ATTR_TYPE_END);
392     if (msg_verbose)
393 	msg_info("tls_proxy_client_dane_scan have_dane=%d", have_dane);
394 
395     if (ret == 1 && have_dane) {
396 	VSTRING *base_domain = vstring_alloc(25);
397 
398 	dane = tls_dane_alloc();
399 	/* We only need the base domain and TLSA RRs */
400 	ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
401 		      RECV_ATTR_STR(TLS_ATTR_DOMAIN, base_domain),
402 		      RECV_ATTR_FUNC(tls_proxy_client_tlsa_scan,
403 				     &dane->tlsa),
404 		      ATTR_TYPE_END);
405 
406 	/* Always construct a well-formed structure. */
407 	dane->base_domain = vstring_export(base_domain);
408 	ret = (ret == 2 ? 1 : -1);
409 	if (ret != 1) {
410 	    tls_dane_free(dane);
411 	    dane = 0;
412 	}
413     }
414     *(TLS_DANE **) ptr = dane;
415     if (msg_verbose)
416 	msg_info("tls_proxy_client_dane_scan ret=%d", ret);
417     return (ret);
418 }
419 
420 /* tls_proxy_client_start_scan - receive TLS_CLIENT_START_PROPS from stream */
421 
422 int     tls_proxy_client_start_scan(ATTR_SCAN_COMMON_FN scan_fn, VSTREAM *fp,
423 				            int flags, void *ptr)
424 {
425     TLS_CLIENT_START_PROPS *props
426     = (TLS_CLIENT_START_PROPS *) mymalloc(sizeof(*props));
427     int     ret;
428     VSTRING *nexthop = vstring_alloc(25);
429     VSTRING *host = vstring_alloc(25);
430     VSTRING *namaddr = vstring_alloc(25);
431     VSTRING *sni = vstring_alloc(25);
432     VSTRING *serverid = vstring_alloc(25);
433     VSTRING *helo = vstring_alloc(25);
434     VSTRING *protocols = vstring_alloc(25);
435     VSTRING *cipher_grade = vstring_alloc(25);
436     VSTRING *cipher_exclusions = vstring_alloc(25);
437     VSTRING *mdalg = vstring_alloc(25);
438 
439     if (msg_verbose)
440 	msg_info("begin tls_proxy_client_start_scan");
441 
442     /*
443      * Note: memset() is not a portable way to initialize non-integer types.
444      */
445     memset(props, 0, sizeof(*props));
446     props->ctx = 0;
447     props->stream = 0;
448     props->fd = -1;
449     props->dane = 0;				/* scan_fn may return early */
450     ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
451 		  RECV_ATTR_INT(TLS_ATTR_TIMEOUT, &props->timeout),
452 		  RECV_ATTR_INT(TLS_ATTR_TLS_LEVEL, &props->tls_level),
453 		  RECV_ATTR_STR(TLS_ATTR_NEXTHOP, nexthop),
454 		  RECV_ATTR_STR(TLS_ATTR_HOST, host),
455 		  RECV_ATTR_STR(TLS_ATTR_NAMADDR, namaddr),
456 		  RECV_ATTR_STR(TLS_ATTR_SNI, sni),
457 		  RECV_ATTR_STR(TLS_ATTR_SERVERID, serverid),
458 		  RECV_ATTR_STR(TLS_ATTR_HELO, helo),
459 		  RECV_ATTR_STR(TLS_ATTR_PROTOCOLS, protocols),
460 		  RECV_ATTR_STR(TLS_ATTR_CIPHER_GRADE, cipher_grade),
461 		  RECV_ATTR_STR(TLS_ATTR_CIPHER_EXCLUSIONS,
462 				cipher_exclusions),
463 		  RECV_ATTR_FUNC(argv_attr_scan, &props->matchargv),
464 		  RECV_ATTR_STR(TLS_ATTR_MDALG, mdalg),
465 		  RECV_ATTR_FUNC(tls_proxy_client_dane_scan,
466 				 &props->dane),
467 		  ATTR_TYPE_END);
468     /* Always construct a well-formed structure. */
469     props->nexthop = vstring_export(nexthop);
470     props->host = vstring_export(host);
471     props->namaddr = vstring_export(namaddr);
472     props->sni = vstring_export(sni);
473     props->serverid = vstring_export(serverid);
474     props->helo = vstring_export(helo);
475     props->protocols = vstring_export(protocols);
476     props->cipher_grade = vstring_export(cipher_grade);
477     props->cipher_exclusions = vstring_export(cipher_exclusions);
478     props->mdalg = vstring_export(mdalg);
479     ret = (ret == 14 ? 1 : -1);
480     if (ret != 1) {
481 	tls_proxy_client_start_free(props);
482 	props = 0;
483     }
484     *(TLS_CLIENT_START_PROPS **) ptr = props;
485     if (msg_verbose)
486 	msg_info("tls_proxy_client_start_scan ret=%d", ret);
487     return (ret);
488 }
489 
490 #endif
491