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