xref: /minix/external/bsd/dhcp/dist/dst/dst_support.c (revision bb9622b5)
1 /*	$NetBSD: dst_support.c,v 1.1.1.4 2014/07/12 11:57:50 spz Exp $	*/
2 static const char rcsid[] = "Header: /tmp/cvstest/DHCP/dst/dst_support.c,v 1.7 2009/11/24 02:06:56 sar Exp ";
3 
4 
5 /*
6  * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc.
7  * Portions Copyright (c) 2007,2009 by Internet Systems Consortium, Inc. ("ISC")
8  * Portions Copyright (c) 2012 by Internet Systems Consortium, Inc. ("ISC")
9  *
10  * Permission to use, copy modify, and distribute this software for any
11  * purpose with or without fee is hereby granted, provided that the above
12  * copyright notice and this permission notice appear in all copies.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS
15  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL
17  * TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT,
18  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
19  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
20  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
21  * WITH THE USE OR PERFORMANCE OF THE SOFTWARE.
22  */
23 
24 #include <sys/cdefs.h>
25 __RCSID("$NetBSD: dst_support.c,v 1.1.1.4 2014/07/12 11:57:50 spz Exp $");
26 
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <memory.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <sys/stat.h>
33 #include <netinet/in.h>
34 #include <sys/socket.h>
35 
36 #include "cdefs.h"
37 #include "osdep.h"
38 #include "arpa/nameser.h"
39 
40 #include "dst_internal.h"
41 
42 /*
43  * dst_s_conv_bignum_u8_to_b64
44  *	This function converts binary data stored as a u_char[] to a
45  *	base-64 string.  Leading zeroes are discarded.  If a header is
46  *	supplied, it is prefixed to the input prior to encoding.  The
47  *	output is \n\0 terminated (the \0 is not included in output length).
48  * Parameters
49  *     out_buf   binary data to convert
50  *     header    character string to prefix to the output (label)
51  *     bin_data  binary data
52  *     bin_len   size of binary data
53  * Return
54  *     -1     not enough space in output work area
55  *	0     no output
56  *     >0     number of bytes written to output work area
57  */
58 
59 int
60 dst_s_conv_bignum_u8_to_b64(char *out_buf, const unsigned out_len,
61 			    const char *header, const u_char *bin_data,
62 			    const unsigned bin_len)
63 {
64 	const u_char *bp = bin_data;
65 	char *op = out_buf;
66 	int res = 0;
67 	unsigned lenh = 0, len64 = 0;
68 	unsigned local_in_len = bin_len;
69 	unsigned local_out_len = out_len;
70 
71 	if (bin_data == NULL)	/* no data no */
72 		return (0);
73 
74 	if (out_buf == NULL || out_len <= 0)	/* no output_work area */
75 		return (-1);
76 
77 	/* suppress leading \0  */
78 	for (; (*bp == 0x0) && (local_in_len > 0); local_in_len--)
79 		bp++;
80 
81 	if (header) {		/* add header to output string */
82 		lenh = strlen(header);
83 		if (lenh < out_len)
84 			memcpy(op, header, lenh);
85 		else
86 			return (-1);
87 		local_out_len -= lenh;
88 		op += lenh;
89 	}
90 	res = b64_ntop(bp, local_in_len, op, local_out_len - 2);
91 	if (res < 0)
92 		return (-1);
93 	len64 = (unsigned) res;
94 	op += len64++;
95 	*(op++) = '\n';		/* put CR in the output */
96 	*op = '\0';		/* make sure output is 0 terminated */
97 	return (lenh + len64);
98 }
99 
100 
101 /*
102  * dst_s_verify_str()
103  *     Validate that the input string(*str) is at the head of the input
104  *     buffer(**buf).  If so, move the buffer head pointer (*buf) to
105  *     the first byte of data following the string(*str).
106  * Parameters
107  *     buf     Input buffer.
108  *     str     Input string.
109  * Return
110  *	0       *str is not the head of **buff
111  *	1       *str is the head of **buff, *buf is is advanced to
112  *	the tail of **buf.
113  */
114 
115 int
116 dst_s_verify_str(const char **buf, const char *str)
117 {
118 	unsigned b, s;
119 	if (*buf == NULL)	/* error checks */
120 		return (0);
121 	if (str == NULL || *str == '\0')
122 		return (1);
123 
124 	b = strlen(*buf);	/* get length of strings */
125 	s = strlen(str);
126 	if (s > b || strncmp(*buf, str, s))	/* check if same */
127 		return (0);	/* not a match */
128 	(*buf) += s;		/* advance pointer */
129 	return (1);
130 }
131 
132 
133 /*
134  * dst_s_conv_bignum_b64_to_u8
135  *     Read a line of base-64 encoded string from the input buffer,
136  *     convert it to binary, and store it in an output area.  The
137  *     input buffer is read until reaching a newline marker or the
138  *     end of the buffer.  The binary data is stored in the last X
139  *     number of bytes of the output area where X is the size of the
140  *     binary output.  If the operation is successful, the input buffer
141  *     pointer is advanced.  This procedure does not do network to host
142  *     byte order conversion.
143  * Parameters
144  *     buf     Pointer to encoded input string. Pointer is updated if
145  *	   function is successful.
146  *     loc     Output area.
147  *     loclen  Size in bytes of output area.
148  * Return
149  *	>0      Return = number of bytes of binary data stored in loc.
150  *	 0      Failure.
151  */
152 
153 int
154 dst_s_conv_bignum_b64_to_u8(const char **buf,
155 			    u_char *loc, const unsigned loclen)
156 {
157 	unsigned blen;
158 	char *bp;
159 	u_char bstr[RAW_KEY_SIZE];
160 	int res = 0;
161 
162 	if (buf == NULL || *buf == NULL) {	/* error checks */
163 		EREPORT(("dst_s_conv_bignum_b64_to_u8: null input buffer.\n"));
164 		return (0);
165 	}
166 	bp = strchr(*buf, '\n');	/* find length of input line */
167 	if (bp != NULL)
168 		*bp = '\0';
169 
170 	res = b64_pton(*buf, bstr, sizeof(bstr));
171 	if (res <= 0) {
172 		EREPORT(("dst_s_conv_bignum_b64_to_u8: decoded value is null.\n"));
173 		return (0);
174 	}
175 	blen = (unsigned) res;
176 	if (loclen < blen) {
177 		EREPORT(("dst_s_conv_bignum_b64_to_u8: decoded value is longer than output buffer.\n"));
178 		return (0);
179 	}
180 	if (bp)
181 		*buf = bp;	/* advancing buffer past \n */
182 	memset(loc, 0, loclen - blen);	/* clearing unused output area */
183 	memcpy(loc + loclen - blen, bstr, blen);	/* write last blen bytes  */
184 	return (blen);
185 }
186 
187 
188 /*
189  * dst_s_calculate_bits
190  *     Given a binary number represented in a u_char[], determine
191  *     the number of significant bits used.
192  * Parameters
193  *     str       An input character string containing a binary number.
194  *     max_bits The maximum possible significant bits.
195  * Return
196  *     N       The number of significant bits in str.
197  */
198 
199 int
200 dst_s_calculate_bits(const u_char *str, const int max_bits)
201 {
202 	const u_char *p = str;
203 	u_char i, j = 0x80;
204 	int bits;
205 	for (bits = max_bits; *p == 0x00 && bits > 0; p++)
206 		bits -= 8;
207 	for (i = *p; (i & j) != j; j >>= 1)
208 		bits--;
209 	return (bits);
210 }
211 
212 
213 /*
214  * calculates a checksum used in kmt for a id.
215  * takes an array of bytes and a length.
216  * returns a 16  bit checksum.
217  */
218 u_int16_t
219 dst_s_id_calc(const u_char *key, const unsigned keysize)
220 {
221 	u_int32_t ac;
222 	const u_char *kp = key;
223 	unsigned size = keysize;
224 
225 	if (!key)
226 		return 0;
227 
228 	for (ac = 0; size > 1; size -= 2, kp += 2)
229 		ac += ((*kp) << 8) + *(kp + 1);
230 
231 	if (size > 0)
232 		ac += ((*kp) << 8);
233 	ac += (ac >> 16) & 0xffff;
234 
235 	return (ac & 0xffff);
236 }
237 
238 /*
239  * dst_s_dns_key_id() Function to calculated DNSSEC footprint from KEY record
240  *   rdata (all of  record)
241  * Input:
242  *	dns_key_rdata: the raw data in wire format
243  *      rdata_len: the size of the input data
244  * Output:
245  *      the key footprint/id calculated from the key data
246  */
247 u_int16_t
248 dst_s_dns_key_id(const u_char *dns_key_rdata, const unsigned rdata_len)
249 {
250 	unsigned key_data = 4;
251 
252 	if (!dns_key_rdata || (rdata_len < key_data))
253 		return 0;
254 
255 	/* check the extended parameters bit in the DNS Key RR flags */
256 	if (dst_s_get_int16(dns_key_rdata) & DST_EXTEND_FLAG)
257 		key_data += 2;
258 
259 	/* compute id */
260 	if (dns_key_rdata[3] == KEY_RSA)	/* Algorithm RSA */
261 		return dst_s_get_int16((const u_char *)
262 				       &dns_key_rdata[rdata_len - 3]);
263 	else
264 		/* compute a checksum on the key part of the key rr */
265 		return dst_s_id_calc(&dns_key_rdata[key_data],
266 				     (rdata_len - key_data));
267 }
268 
269 /*
270  * dst_s_get_int16
271  *     This routine extracts a 16 bit integer from a two byte character
272  *     string.  The character string is assumed to be in network byte
273  *     order and may be unaligned.  The number returned is in host order.
274  * Parameter
275  *     buf     A two byte character string.
276  * Return
277  *     The converted integer value.
278  */
279 
280 u_int16_t
281 dst_s_get_int16(const u_char *buf)
282 {
283 	register u_int16_t a = 0;
284 	a = ((u_int16_t)(buf[0] << 8)) | ((u_int16_t)(buf[1]));
285 	return (a);
286 }
287 
288 
289 /*
290  * dst_s_get_int32
291  *     This routine extracts a 32 bit integer from a four byte character
292  *     string.  The character string is assumed to be in network byte
293  *     order and may be unaligned.  The number returned is in host order.
294  * Parameter
295  *     buf     A four byte character string.
296  * Return
297  *     The converted integer value.
298  */
299 
300 u_int32_t
301 dst_s_get_int32(const u_char *buf)
302 {
303 	register u_int32_t a = 0;
304 	a = ((u_int32_t)(buf[0] << 24)) | ((u_int32_t)(buf[1] << 16)) |
305 		((u_int32_t)(buf[2] << 8)) | ((u_int32_t)(buf[3]));
306 	return (a);
307 }
308 
309 
310 /*
311  * dst_s_put_int16
312  *     Take a 16 bit integer and store the value in a two byte
313  *     character string.  The integer is assumed to be in network
314  *     order and the string is returned in host order.
315  *
316  * Parameters
317  *     buf     Storage for a two byte character string.
318  *     val     16 bit integer.
319  */
320 
321 void
322 dst_s_put_int16(u_int8_t *buf, const u_int16_t val)
323 {
324 	buf[0] = (u_int8_t)(val >> 8);
325 	buf[1] = (u_int8_t)(val);
326 }
327 
328 
329 /*
330  * dst_s_put_int32
331  *     Take a 32 bit integer and store the value in a four byte
332  *     character string.  The integer is assumed to be in network
333  *     order and the string is returned in host order.
334  *
335  * Parameters
336  *     buf     Storage for a four byte character string.
337  *     val     32 bit integer.
338  */
339 
340 void
341 dst_s_put_int32(u_int8_t *buf, const u_int32_t val)
342 {
343 	buf[0] = (u_int8_t)(val >> 24);
344 	buf[1] = (u_int8_t)(val >> 16);
345 	buf[2] = (u_int8_t)(val >> 8);
346 	buf[3] = (u_int8_t)(val);
347 }
348 
349 
350 /*
351  *  dst_s_filename_length
352  *
353  *	This function returns the number of bytes needed to hold the
354  *	filename for a key file.  '/', '\' and ':' are not allowed.
355  *	form:  K<keyname>+<alg>+<id>.<suffix>
356  *
357  *	Returns 0 if the filename would contain either '\', '/' or ':'
358  */
359 size_t
360 dst_s_filename_length(const char *name, const char *suffix)
361 {
362 	if (name == NULL)
363 		return (0);
364 	if (strrchr(name, '\\'))
365 		return (0);
366 	if (strrchr(name, '/'))
367 		return (0);
368 	if (strrchr(name, ':'))
369 		return (0);
370 	if (suffix == NULL)
371 		return (0);
372 	if (strrchr(suffix, '\\'))
373 		return (0);
374 	if (strrchr(suffix, '/'))
375 		return (0);
376 	if (strrchr(suffix, ':'))
377 		return (0);
378 	return (1 + strlen(name) + 6 + strlen(suffix));
379 }
380 
381 
382 /*
383  *  dst_s_build_filename ()
384  *	Builds a key filename from the key name, it's id, and a
385  *	suffix.  '\', '/' and ':' are not allowed. fA filename is of the
386  *	form:  K<keyname><id>.<suffix>
387  *	form: K<keyname>+<alg>+<id>.<suffix>
388  *
389  *	Returns -1 if the conversion fails:
390  *	  if the filename would be too long for space allotted
391  *	  if the filename would contain a '\', '/' or ':'
392  *	Returns 0 on success
393  */
394 
395 int
396 dst_s_build_filename(char *filename, const char *name, unsigned id,
397 		     int alg, const char *suffix, size_t filename_length)
398 {
399 	unsigned my_id;
400 	if (filename == NULL)
401 		return (-1);
402 	memset(filename, 0, filename_length);
403 	if (name == NULL)
404 		return (-1);
405 	if (suffix == NULL)
406 		return (-1);
407 	if (filename_length < 1 + strlen(name) + 4 + 6 + 1 + strlen(suffix))
408 		return (-1);
409 	my_id = id;
410 	sprintf(filename, "K%s+%03d+%05d.%s", name, alg, my_id,
411 		(const char *) suffix);
412 	if (strrchr(filename, '/'))
413 		return (-1);
414 	if (strrchr(filename, '\\'))
415 		return (-1);
416 	if (strrchr(filename, ':'))
417 		return (-1);
418 	return (0);
419 }
420 
421 /*
422  *  dst_s_fopen ()
423  *     Open a file in the dst_path directory.  If perm is specified, the
424  *     file is checked for existence first, and not opened if it exists.
425  *  Parameters
426  *     filename  File to open
427  *     mode       Mode to open the file (passed directly to fopen)
428  *     perm       File permission, if creating a new file.
429  *  Returns
430  *     NULL       Failure
431  *     NON-NULL  (FILE *) of opened file.
432  */
433 FILE *
434 dst_s_fopen(const char *filename, const char *mode, unsigned perm)
435 {
436 	FILE *fp;
437 	char pathname[PATH_MAX];
438 	unsigned plen = sizeof(pathname);
439 
440 	if (*dst_path != '\0') {
441 		strncpy(pathname, dst_path, PATH_MAX);
442 		plen -= strlen(pathname);
443 	}
444 	else
445 		pathname[0] = '\0';
446 
447 	if (plen > strlen(filename))
448 		strncpy(&pathname[PATH_MAX - plen], filename, plen-1);
449 	else
450 		return (NULL);
451 
452 	fp = fopen(pathname, mode);
453 	if (perm)
454 		chmod(pathname, perm);
455 	return (fp);
456 }
457 
458 #if 0
459 void
460 dst_s_dump(const int mode, const u_char *data, const int size,
461 	    const char *msg)
462 {
463 	if (size > 0) {
464 #ifdef LONG_TEST
465 		static u_char scratch[1000];
466 		int n ;
467 		n = b64_ntop(data, scratch, size, sizeof(scratch));
468 		printf("%s: %x %d %s\n", msg, mode, n, scratch);
469 #else
470 		printf("%s,%x %d\n", msg, mode, size);
471 #endif
472 	}
473 }
474 #endif
475