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
dst_s_conv_bignum_u8_to_b64(char * out_buf,const unsigned out_len,const char * header,const u_char * bin_data,const unsigned bin_len)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
dst_s_verify_str(const char ** buf,const char * str)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
dst_s_conv_bignum_b64_to_u8(const char ** buf,u_char * loc,const unsigned loclen)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
dst_s_calculate_bits(const u_char * str,const int max_bits)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
dst_s_id_calc(const u_char * key,const unsigned keysize)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
dst_s_dns_key_id(const u_char * dns_key_rdata,const unsigned rdata_len)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
dst_s_get_int16(const u_char * buf)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
dst_s_get_int32(const u_char * buf)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
dst_s_put_int16(u_int8_t * buf,const u_int16_t val)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
dst_s_put_int32(u_int8_t * buf,const u_int32_t val)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
dst_s_filename_length(const char * name,const char * suffix)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
dst_s_build_filename(char * filename,const char * name,unsigned id,int alg,const char * suffix,size_t filename_length)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 *
dst_s_fopen(const char * filename,const char * mode,unsigned perm)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