xref: /netbsd-src/external/ibm-public/postfix/dist/src/tls/tls_proxy_client_scan.c (revision 82d56013d7b633d116a93943de88e08335357a7c)
1 /*	$NetBSD: tls_proxy_client_scan.c,v 1.2 2020/03/18 19:05:21 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_MASTER_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_MASTER_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_MASTER_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 #include <tls.h>
116 #include <tls_proxy.h>
117 
118 #define STR(x) vstring_str(x)
119 #define LEN(x) VSTRING_LEN(x)
120 
121 /* tls_proxy_client_param_free - destroy TLS_CLIENT_PARAMS structure */
122 
123 void    tls_proxy_client_param_free(TLS_CLIENT_PARAMS *params)
124 {
125     myfree(params->tls_high_clist);
126     myfree(params->tls_medium_clist);
127     myfree(params->tls_low_clist);
128     myfree(params->tls_export_clist);
129     myfree(params->tls_null_clist);
130     myfree(params->tls_eecdh_auto);
131     myfree(params->tls_eecdh_strong);
132     myfree(params->tls_eecdh_ultra);
133     myfree(params->tls_bug_tweaks);
134     myfree(params->tls_ssl_options);
135     myfree(params->tls_dane_digests);
136     myfree(params->tls_mgr_service);
137     myfree(params->tls_tkt_cipher);
138     myfree((void *) params);
139 }
140 
141 /* tls_proxy_client_param_scan - receive TLS_CLIENT_PARAMS from stream */
142 
143 int     tls_proxy_client_param_scan(ATTR_SCAN_MASTER_FN scan_fn, VSTREAM *fp,
144 				            int flags, void *ptr)
145 {
146     TLS_CLIENT_PARAMS *params
147     = (TLS_CLIENT_PARAMS *) mymalloc(sizeof(*params));
148     int     ret;
149     VSTRING *tls_high_clist = vstring_alloc(25);
150     VSTRING *tls_medium_clist = vstring_alloc(25);
151     VSTRING *tls_low_clist = vstring_alloc(25);
152     VSTRING *tls_export_clist = vstring_alloc(25);
153     VSTRING *tls_null_clist = vstring_alloc(25);
154     VSTRING *tls_eecdh_auto = vstring_alloc(25);
155     VSTRING *tls_eecdh_strong = vstring_alloc(25);
156     VSTRING *tls_eecdh_ultra = vstring_alloc(25);
157     VSTRING *tls_bug_tweaks = vstring_alloc(25);
158     VSTRING *tls_ssl_options = vstring_alloc(25);
159     VSTRING *tls_dane_digests = vstring_alloc(25);
160     VSTRING *tls_mgr_service = vstring_alloc(25);
161     VSTRING *tls_tkt_cipher = vstring_alloc(25);
162 
163     if (msg_verbose)
164 	msg_info("begin tls_proxy_client_param_scan");
165 
166     /*
167      * Note: memset() is not a portable way to initialize non-integer types.
168      */
169     memset(params, 0, sizeof(*params));
170     ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
171 		  RECV_ATTR_STR(VAR_TLS_HIGH_CLIST, tls_high_clist),
172 		  RECV_ATTR_STR(VAR_TLS_MEDIUM_CLIST, tls_medium_clist),
173 		  RECV_ATTR_STR(VAR_TLS_LOW_CLIST, tls_low_clist),
174 		  RECV_ATTR_STR(VAR_TLS_EXPORT_CLIST, tls_export_clist),
175 		  RECV_ATTR_STR(VAR_TLS_NULL_CLIST, tls_null_clist),
176 		  RECV_ATTR_STR(VAR_TLS_EECDH_AUTO, tls_eecdh_auto),
177 		  RECV_ATTR_STR(VAR_TLS_EECDH_STRONG, tls_eecdh_strong),
178 		  RECV_ATTR_STR(VAR_TLS_EECDH_ULTRA, tls_eecdh_ultra),
179 		  RECV_ATTR_STR(VAR_TLS_BUG_TWEAKS, tls_bug_tweaks),
180 		  RECV_ATTR_STR(VAR_TLS_SSL_OPTIONS, tls_ssl_options),
181 		  RECV_ATTR_STR(VAR_TLS_DANE_DIGESTS, tls_dane_digests),
182 		  RECV_ATTR_STR(VAR_TLS_MGR_SERVICE, tls_mgr_service),
183 		  RECV_ATTR_STR(VAR_TLS_TKT_CIPHER, tls_tkt_cipher),
184 		  RECV_ATTR_INT(VAR_TLS_DAEMON_RAND_BYTES,
185 				&params->tls_daemon_rand_bytes),
186 		  RECV_ATTR_INT(VAR_TLS_APPEND_DEF_CA,
187 				&params->tls_append_def_CA),
188 		  RECV_ATTR_INT(VAR_TLS_BC_PKEY_FPRINT,
189 				&params->tls_bc_pkey_fprint),
190 		  RECV_ATTR_INT(VAR_TLS_PREEMPT_CLIST,
191 				&params->tls_preempt_clist),
192 		  RECV_ATTR_INT(VAR_TLS_MULTI_WILDCARD,
193 				&params->tls_multi_wildcard),
194 		  ATTR_TYPE_END);
195     /* Always construct a well-formed structure. */
196     params->tls_high_clist = vstring_export(tls_high_clist);
197     params->tls_medium_clist = vstring_export(tls_medium_clist);
198     params->tls_low_clist = vstring_export(tls_low_clist);
199     params->tls_export_clist = vstring_export(tls_export_clist);
200     params->tls_null_clist = vstring_export(tls_null_clist);
201     params->tls_eecdh_auto = vstring_export(tls_eecdh_auto);
202     params->tls_eecdh_strong = vstring_export(tls_eecdh_strong);
203     params->tls_eecdh_ultra = vstring_export(tls_eecdh_ultra);
204     params->tls_bug_tweaks = vstring_export(tls_bug_tweaks);
205     params->tls_ssl_options = vstring_export(tls_ssl_options);
206     params->tls_dane_digests = vstring_export(tls_dane_digests);
207     params->tls_mgr_service = vstring_export(tls_mgr_service);
208     params->tls_tkt_cipher = vstring_export(tls_tkt_cipher);
209 
210     ret = (ret == 18 ? 1 : -1);
211     if (ret != 1) {
212 	tls_proxy_client_param_free(params);
213 	params = 0;
214     }
215     *(TLS_CLIENT_PARAMS **) ptr = params;
216     if (msg_verbose)
217 	msg_info("tls_proxy_client_param_scan ret=%d", ret);
218     return (ret);
219 }
220 
221 /* tls_proxy_client_init_free - destroy TLS_CLIENT_INIT_PROPS structure */
222 
223 void    tls_proxy_client_init_free(TLS_CLIENT_INIT_PROPS *props)
224 {
225     myfree((void *) props->log_param);
226     myfree((void *) props->log_level);
227     myfree((void *) props->cache_type);
228     myfree((void *) props->chain_files);
229     myfree((void *) props->cert_file);
230     myfree((void *) props->key_file);
231     myfree((void *) props->dcert_file);
232     myfree((void *) props->dkey_file);
233     myfree((void *) props->eccert_file);
234     myfree((void *) props->eckey_file);
235     myfree((void *) props->CAfile);
236     myfree((void *) props->CApath);
237     myfree((void *) props->mdalg);
238     myfree((void *) props);
239 }
240 
241 /* tls_proxy_client_init_scan - receive TLS_CLIENT_INIT_PROPS from stream */
242 
243 int     tls_proxy_client_init_scan(ATTR_SCAN_MASTER_FN scan_fn, VSTREAM *fp,
244 				           int flags, void *ptr)
245 {
246     TLS_CLIENT_INIT_PROPS *props
247     = (TLS_CLIENT_INIT_PROPS *) mymalloc(sizeof(*props));
248     int     ret;
249     VSTRING *log_param = vstring_alloc(25);
250     VSTRING *log_level = vstring_alloc(25);
251     VSTRING *cache_type = vstring_alloc(25);
252     VSTRING *chain_files = vstring_alloc(25);
253     VSTRING *cert_file = vstring_alloc(25);
254     VSTRING *key_file = vstring_alloc(25);
255     VSTRING *dcert_file = vstring_alloc(25);
256     VSTRING *dkey_file = vstring_alloc(25);
257     VSTRING *eccert_file = vstring_alloc(25);
258     VSTRING *eckey_file = vstring_alloc(25);
259     VSTRING *CAfile = vstring_alloc(25);
260     VSTRING *CApath = vstring_alloc(25);
261     VSTRING *mdalg = vstring_alloc(25);
262 
263     if (msg_verbose)
264 	msg_info("begin tls_proxy_client_init_scan");
265 
266     /*
267      * Note: memset() is not a portable way to initialize non-integer types.
268      */
269     memset(props, 0, sizeof(*props));
270     ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
271 		  RECV_ATTR_STR(TLS_ATTR_LOG_PARAM, log_param),
272 		  RECV_ATTR_STR(TLS_ATTR_LOG_LEVEL, log_level),
273 		  RECV_ATTR_INT(TLS_ATTR_VERIFYDEPTH, &props->verifydepth),
274 		  RECV_ATTR_STR(TLS_ATTR_CACHE_TYPE, cache_type),
275 		  RECV_ATTR_STR(TLS_ATTR_CHAIN_FILES, chain_files),
276 		  RECV_ATTR_STR(TLS_ATTR_CERT_FILE, cert_file),
277 		  RECV_ATTR_STR(TLS_ATTR_KEY_FILE, key_file),
278 		  RECV_ATTR_STR(TLS_ATTR_DCERT_FILE, dcert_file),
279 		  RECV_ATTR_STR(TLS_ATTR_DKEY_FILE, dkey_file),
280 		  RECV_ATTR_STR(TLS_ATTR_ECCERT_FILE, eccert_file),
281 		  RECV_ATTR_STR(TLS_ATTR_ECKEY_FILE, eckey_file),
282 		  RECV_ATTR_STR(TLS_ATTR_CAFILE, CAfile),
283 		  RECV_ATTR_STR(TLS_ATTR_CAPATH, CApath),
284 		  RECV_ATTR_STR(TLS_ATTR_MDALG, mdalg),
285 		  ATTR_TYPE_END);
286     /* Always construct a well-formed structure. */
287     props->log_param = vstring_export(log_param);
288     props->log_level = vstring_export(log_level);
289     props->cache_type = vstring_export(cache_type);
290     props->chain_files = vstring_export(chain_files);
291     props->cert_file = vstring_export(cert_file);
292     props->key_file = vstring_export(key_file);
293     props->dcert_file = vstring_export(dcert_file);
294     props->dkey_file = vstring_export(dkey_file);
295     props->eccert_file = vstring_export(eccert_file);
296     props->eckey_file = vstring_export(eckey_file);
297     props->CAfile = vstring_export(CAfile);
298     props->CApath = vstring_export(CApath);
299     props->mdalg = vstring_export(mdalg);
300     ret = (ret == 14 ? 1 : -1);
301     if (ret != 1) {
302 	tls_proxy_client_init_free(props);
303 	props = 0;
304     }
305     *(TLS_CLIENT_INIT_PROPS **) ptr = props;
306     if (msg_verbose)
307 	msg_info("tls_proxy_client_init_scan ret=%d", ret);
308     return (ret);
309 }
310 
311 /* tls_proxy_client_certs_free - destroy TLS_PKEYS from stream */
312 
313 static void tls_proxy_client_certs_free(TLS_CERTS *tp)
314 {
315     if (tp->next)
316 	tls_proxy_client_certs_free(tp->next);
317     if (tp->cert)
318 	X509_free(tp->cert);
319     myfree((void *) tp);
320 }
321 
322 /* tls_proxy_client_pkeys_free - destroy TLS_PKEYS from stream */
323 
324 static void tls_proxy_client_pkeys_free(TLS_PKEYS *tp)
325 {
326     if (tp->next)
327 	tls_proxy_client_pkeys_free(tp->next);
328     if (tp->pkey)
329 	EVP_PKEY_free(tp->pkey);
330     myfree((void *) tp);
331 }
332 
333 /* tls_proxy_client_tlsa_free - destroy TLS_TLSA from stream */
334 
335 static void tls_proxy_client_tlsa_free(TLS_TLSA *tp)
336 {
337     if (tp->next)
338 	tls_proxy_client_tlsa_free(tp->next);
339     myfree(tp->mdalg);
340     if (tp->certs)
341 	argv_free(tp->certs);
342     if (tp->pkeys)
343 	argv_free(tp->pkeys);
344     myfree((void *) tp);
345 }
346 
347 /* tls_proxy_client_dane_free - destroy TLS_DANE from stream */
348 
349 static void tls_proxy_client_dane_free(TLS_DANE *dane)
350 {
351     if (dane->ta)
352 	tls_proxy_client_tlsa_free(dane->ta);
353     if (dane->ee)
354 	tls_proxy_client_tlsa_free(dane->ee);
355     if (dane->certs)
356 	tls_proxy_client_certs_free(dane->certs);
357     if (dane->pkeys)
358 	tls_proxy_client_pkeys_free(dane->pkeys);
359     myfree(dane->base_domain);
360     if (dane->refs-- == 1)
361 	myfree((void *) dane);
362 }
363 
364 /* tls_proxy_client_start_free - destroy TLS_CLIENT_START_PROPS structure */
365 
366 void    tls_proxy_client_start_free(TLS_CLIENT_START_PROPS *props)
367 {
368     myfree((void *) props->nexthop);
369     myfree((void *) props->host);
370     myfree((void *) props->namaddr);
371     myfree((void *) props->sni);
372     myfree((void *) props->serverid);
373     myfree((void *) props->helo);
374     myfree((void *) props->protocols);
375     myfree((void *) props->cipher_grade);
376     myfree((void *) props->cipher_exclusions);
377     if (props->matchargv)
378 	argv_free((ARGV *) props->matchargv);
379     myfree((void *) props->mdalg);
380     if (props->dane)
381 	tls_proxy_client_dane_free((TLS_DANE *) props->dane);
382     myfree((void *) props);
383 }
384 
385 /* tls_proxy_client_certs_scan - receive TLS_CERTS from stream */
386 
387 static int tls_proxy_client_certs_scan(ATTR_SCAN_MASTER_FN scan_fn,
388 				          VSTREAM *fp, int flags, void *ptr)
389 {
390     int     ret;
391     int     count;
392     VSTRING *buf = 0;
393     TLS_CERTS **tpp;
394     TLS_CERTS *head = 0;
395     TLS_CERTS *tp;
396     int     n;
397 
398     ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
399 		  RECV_ATTR_INT(TLS_ATTR_COUNT, &count),
400 		  ATTR_TYPE_END);
401     if (msg_verbose)
402 	msg_info("tls_proxy_client_certs_scan count=%d", count);
403 
404     for (tpp = &head, n = 0; ret == 1 && n < count; n++, tpp = &tp->next) {
405 	*tpp = tp = (TLS_CERTS *) mymalloc(sizeof(*tp));
406 	const unsigned char *bp;
407 
408 	if (buf == 0)
409 	    buf = vstring_alloc(100);
410 
411 	/*
412 	 * Note: memset() is not a portable way to initialize non-integer
413 	 * types.
414 	 */
415 	memset(tp, 0, sizeof(*tp));
416 	ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
417 		      RECV_ATTR_DATA(TLS_ATTR_CERT, buf),
418 		      ATTR_TYPE_END);
419 	/* Always construct a well-formed structure. */
420 	if (ret == 1) {
421 	    bp = (const unsigned char *) STR(buf);
422 	    if (d2i_X509(&tp->cert, &bp, LEN(buf)) == 0
423 		|| LEN(buf) != ((char *) bp) - STR(buf)) {
424 		msg_warn("malformed certificate in TLS_CERTS");
425 		ret = -1;
426 	    }
427 	} else {
428 	    tp->cert = 0;
429 	}
430 	tp->next = 0;
431     }
432     if (buf)
433 	vstring_free(buf);
434     if (ret != 1) {
435 	tls_proxy_client_certs_free(head);
436 	head = 0;
437     }
438     *(TLS_CERTS **) ptr = head;
439     if (msg_verbose)
440 	msg_info("tls_proxy_client_certs_scan ret=%d", ret);
441     return (ret);
442 }
443 
444 /* tls_proxy_client_pkeys_scan - receive TLS_PKEYS from stream */
445 
446 static int tls_proxy_client_pkeys_scan(ATTR_SCAN_MASTER_FN scan_fn,
447 				          VSTREAM *fp, int flags, void *ptr)
448 {
449     int     ret;
450     int     count;
451     VSTRING *buf = vstring_alloc(100);
452     TLS_PKEYS **tpp;
453     TLS_PKEYS *head = 0;
454     TLS_PKEYS *tp;
455     int     n;
456 
457     ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
458 		  RECV_ATTR_INT(TLS_ATTR_COUNT, &count),
459 		  ATTR_TYPE_END);
460     if (msg_verbose)
461 	msg_info("tls_proxy_client_pkeys_scan count=%d", count);
462 
463     for (tpp = &head, n = 0; ret == 1 && n < count; n++, tpp = &tp->next) {
464 	*tpp = tp = (TLS_PKEYS *) mymalloc(sizeof(*tp));
465 	const unsigned char *bp;
466 
467 	if (buf == 0)
468 	    buf = vstring_alloc(100);
469 
470 	/*
471 	 * Note: memset() is not a portable way to initialize non-integer
472 	 * types.
473 	 */
474 	memset(tp, 0, sizeof(*tp));
475 	ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
476 		      RECV_ATTR_DATA(TLS_ATTR_PKEY, buf),
477 		      ATTR_TYPE_END);
478 	/* Always construct a well-formed structure. */
479 	if (ret == 1) {
480 	    bp = (const unsigned char *) STR(buf);
481 	    if (d2i_PUBKEY(&tp->pkey, &bp, LEN(buf)) == 0
482 		|| LEN(buf) != (char *) bp - STR(buf)) {
483 		msg_warn("malformed public key in TLS_PKEYS");
484 		ret = -1;
485 	    }
486 	} else {
487 	    tp->pkey = 0;
488 	}
489 	tp->next = 0;
490     }
491     if (buf)
492 	vstring_free(buf);
493     if (ret != 1) {
494 	tls_proxy_client_pkeys_free(head);
495 	head = 0;
496     }
497     *(TLS_PKEYS **) ptr = head;
498     if (msg_verbose)
499 	msg_info("tls_proxy_client_pkeys_scan ret=%d", ret);
500     return (ret);
501 }
502 
503 /* tls_proxy_client_tlsa_scan - receive TLS_TLSA from stream */
504 
505 static int tls_proxy_client_tlsa_scan(ATTR_SCAN_MASTER_FN scan_fn,
506 				          VSTREAM *fp, int flags, void *ptr)
507 {
508     int     ret;
509     int     count;
510     TLS_TLSA **tpp;
511     TLS_TLSA *head = 0;
512     TLS_TLSA *tp;
513     int     n;
514 
515     ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
516 		  RECV_ATTR_INT(TLS_ATTR_COUNT, &count),
517 		  ATTR_TYPE_END);
518     if (msg_verbose)
519 	msg_info("tls_proxy_client_tlsa_scan count=%d", count);
520 
521     for (tpp = &head, n = 0; ret == 1 && n < count; n++, tpp = &tp->next) {
522 	*tpp = tp = (TLS_TLSA *) mymalloc(sizeof(*tp));
523 	VSTRING *mdalg = vstring_alloc(25);
524 
525 	/*
526 	 * Note: memset() is not a portable way to initialize non-integer
527 	 * types.
528 	 */
529 	memset(tp, 0, sizeof(*tp));
530 	/* Always construct a well-formed structure. */
531 	tp->certs = 0;				/* scan_fn may return early */
532 	tp->pkeys = 0;
533 	ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
534 		      RECV_ATTR_STR(TLS_ATTR_MDALG, mdalg),
535 		      RECV_ATTR_FUNC(argv_attr_scan, &tp->certs),
536 		      RECV_ATTR_FUNC(argv_attr_scan, &tp->pkeys),
537 		      ATTR_TYPE_END);
538 	tp->mdalg = vstring_export(mdalg);
539 	tp->next = 0;
540 	ret = (ret == 3 ? 1 : -1);
541     }
542     if (ret != 1) {
543 	tls_proxy_client_tlsa_free(head);
544 	head = 0;
545     }
546     *(TLS_TLSA **) ptr = head;
547     if (msg_verbose)
548 	msg_info("tls_proxy_client_tlsa_scan ret=%d", ret);
549     return (ret);
550 }
551 
552 /* tls_proxy_client_dane_scan - receive TLS_DANE from stream */
553 
554 static int tls_proxy_client_dane_scan(ATTR_SCAN_MASTER_FN scan_fn,
555 				          VSTREAM *fp, int flags, void *ptr)
556 {
557     TLS_DANE *dane = 0;
558     int     ret;
559     int     have_dane = 0;
560 
561     ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
562 		  RECV_ATTR_INT(TLS_ATTR_DANE, &have_dane),
563 		  ATTR_TYPE_END);
564     if (msg_verbose)
565 	msg_info("tls_proxy_client_dane_scan have_dane=%d", have_dane);
566 
567     if (ret == 1 && have_dane) {
568 	VSTRING *base_domain = vstring_alloc(25);
569 	long    expires;
570 
571 	dane = (TLS_DANE *) mymalloc(sizeof(*dane));
572 
573 	/*
574 	 * Note: memset() is not a portable way to initialize non-integer
575 	 * types.
576 	 */
577 	memset(dane, 0, sizeof(*dane));
578 	/* Always construct a well-formed structure. */
579 	dane->ta = 0;				/* scan_fn may return early */
580 	dane->ee = 0;
581 	dane->certs = 0;
582 	dane->pkeys = 0;
583 	ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
584 		      RECV_ATTR_FUNC(tls_proxy_client_tlsa_scan,
585 				     &dane->ta),
586 		      RECV_ATTR_FUNC(tls_proxy_client_tlsa_scan,
587 				     &dane->ee),
588 		      RECV_ATTR_FUNC(tls_proxy_client_certs_scan,
589 				     &dane->certs),
590 		      RECV_ATTR_FUNC(tls_proxy_client_pkeys_scan,
591 				     &dane->pkeys),
592 		      RECV_ATTR_STR(TLS_ATTR_DOMAIN, base_domain),
593 		      RECV_ATTR_INT(TLS_ATTR_FLAGS, &dane->flags),
594 		      RECV_ATTR_LONG(TLS_ATTR_EXP, &expires),
595 		      ATTR_TYPE_END);
596 	/* Always construct a well-formed structure. */
597 	dane->base_domain = vstring_export(base_domain);
598 	dane->expires = expires;
599 	dane->refs = 1;
600 	ret = (ret == 7 ? 1 : -1);
601 	/* XXX if scan_fn() completed normally, sanity check dane->flags. */
602 	if (ret != 1) {
603 	    tls_proxy_client_dane_free(dane);
604 	    dane = 0;
605 	}
606     }
607     *(TLS_DANE **) ptr = dane;
608     if (msg_verbose)
609 	msg_info("tls_proxy_client_dane_scan ret=%d", ret);
610     return (ret);
611 }
612 
613 /* tls_proxy_client_start_scan - receive TLS_CLIENT_START_PROPS from stream */
614 
615 int     tls_proxy_client_start_scan(ATTR_SCAN_MASTER_FN scan_fn, VSTREAM *fp,
616 				            int flags, void *ptr)
617 {
618     TLS_CLIENT_START_PROPS *props
619     = (TLS_CLIENT_START_PROPS *) mymalloc(sizeof(*props));
620     int     ret;
621     VSTRING *nexthop = vstring_alloc(25);
622     VSTRING *host = vstring_alloc(25);
623     VSTRING *namaddr = vstring_alloc(25);
624     VSTRING *sni = vstring_alloc(25);
625     VSTRING *serverid = vstring_alloc(25);
626     VSTRING *helo = vstring_alloc(25);
627     VSTRING *protocols = vstring_alloc(25);
628     VSTRING *cipher_grade = vstring_alloc(25);
629     VSTRING *cipher_exclusions = vstring_alloc(25);
630     VSTRING *mdalg = vstring_alloc(25);
631 
632     if (msg_verbose)
633 	msg_info("begin tls_proxy_client_start_scan");
634 
635     /*
636      * Note: memset() is not a portable way to initialize non-integer types.
637      */
638     memset(props, 0, sizeof(*props));
639     props->ctx = 0;
640     props->stream = 0;
641     props->fd = -1;
642     props->dane = 0;				/* scan_fn may return early */
643     ret = scan_fn(fp, flags | ATTR_FLAG_MORE,
644 		  RECV_ATTR_INT(TLS_ATTR_TIMEOUT, &props->timeout),
645 		  RECV_ATTR_INT(TLS_ATTR_TLS_LEVEL, &props->tls_level),
646 		  RECV_ATTR_STR(TLS_ATTR_NEXTHOP, nexthop),
647 		  RECV_ATTR_STR(TLS_ATTR_HOST, host),
648 		  RECV_ATTR_STR(TLS_ATTR_NAMADDR, namaddr),
649 		  RECV_ATTR_STR(TLS_ATTR_SNI, sni),
650 		  RECV_ATTR_STR(TLS_ATTR_SERVERID, serverid),
651 		  RECV_ATTR_STR(TLS_ATTR_HELO, helo),
652 		  RECV_ATTR_STR(TLS_ATTR_PROTOCOLS, protocols),
653 		  RECV_ATTR_STR(TLS_ATTR_CIPHER_GRADE, cipher_grade),
654 		  RECV_ATTR_STR(TLS_ATTR_CIPHER_EXCLUSIONS,
655 				cipher_exclusions),
656 		  RECV_ATTR_FUNC(argv_attr_scan, &props->matchargv),
657 		  RECV_ATTR_STR(TLS_ATTR_MDALG, mdalg),
658 		  RECV_ATTR_FUNC(tls_proxy_client_dane_scan,
659 				 &props->dane),
660 		  ATTR_TYPE_END);
661     /* Always construct a well-formed structure. */
662     props->nexthop = vstring_export(nexthop);
663     props->host = vstring_export(host);
664     props->namaddr = vstring_export(namaddr);
665     props->sni = vstring_export(sni);
666     props->serverid = vstring_export(serverid);
667     props->helo = vstring_export(helo);
668     props->protocols = vstring_export(protocols);
669     props->cipher_grade = vstring_export(cipher_grade);
670     props->cipher_exclusions = vstring_export(cipher_exclusions);
671     props->mdalg = vstring_export(mdalg);
672     ret = (ret == 14 ? 1 : -1);
673     if (ret != 1) {
674 	tls_proxy_client_start_free(props);
675 	props = 0;
676     }
677     *(TLS_CLIENT_START_PROPS **) ptr = props;
678     if (msg_verbose)
679 	msg_info("tls_proxy_client_start_scan ret=%d", ret);
680     return (ret);
681 }
682 
683 #endif
684