1/* 2 * Copyright (c) 1999 by Internet Software Consortium, Inc. 3 * 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 9 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 10 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 11 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 12 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 13 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 14 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 15 * SOFTWARE. 16 */ 17 18#ifndef __APPLE__ 19#ifndef lint 20static const char rcsid[] = "$Id: ns_sign.c,v 1.1 2006/03/01 19:01:37 majka Exp $"; 21#endif 22#endif 23 24/* Import. */ 25 26#ifndef __APPLE__ 27#include "port_before.h" 28#include "fd_setsize.h" 29#endif 30 31#include <sys/types.h> 32#include <sys/param.h> 33 34#include <netinet/in.h> 35#include <arpa/nameser.h> 36#include <arpa/inet.h> 37 38#include <errno.h> 39#include <netdb.h> 40#include <resolv.h> 41#include <stdio.h> 42#include <stdlib.h> 43#include <string.h> 44#include <time.h> 45#include <unistd.h> 46 47#ifndef __APPLE__ 48#include <isc/dst.h> 49#include "port_after.h" 50#else 51#include "dst_internal.h" 52#include "res_private.h" 53#endif 54 55#define BOUNDS_CHECK(ptr, count) \ 56 do { \ 57 if ((ptr) + (count) > eob) { \ 58 errno = EMSGSIZE; \ 59 return(NS_TSIG_ERROR_NO_SPACE); \ 60 } \ 61 } while (0) 62 63/* ns_sign 64 * Parameters: 65 * msg message to be sent 66 * msglen input - length of message 67 * output - length of signed message 68 * msgsize length of buffer containing message 69 * error value to put in the error field 70 * key tsig key used for signing 71 * querysig (response), the signature in the query 72 * querysiglen (response), the length of the signature in the query 73 * sig a buffer to hold the generated signature 74 * siglen input - length of signature buffer 75 * output - length of signature 76 * 77 * Errors: 78 * - bad input data (-1) 79 * - bad key / sign failed (-BADKEY) 80 * - not enough space (NS_TSIG_ERROR_NO_SPACE) 81 */ 82int 83ns_sign(u_char *msg, int *msglen, int msgsize, int error, void *k, 84 const u_char *querysig, int querysiglen, u_char *sig, int *siglen, 85 time_t in_timesigned) 86{ 87 return(ns_sign2(msg, msglen, msgsize, error, k, 88 querysig, querysiglen, sig, siglen, 89 in_timesigned, NULL, NULL)); 90} 91 92int 93ns_sign2(u_char *msg, int *msglen, int msgsize, int error, void *k, 94 const u_char *querysig, int querysiglen, u_char *sig, int *siglen, 95 time_t in_timesigned, u_char **dnptrs, u_char **lastdnptr) 96{ 97 HEADER *hp = (HEADER *)msg; 98 DST_KEY *key = (DST_KEY *)k; 99 u_char *cp = msg + *msglen, *eob = msg + msgsize; 100 u_char *lenp; 101 u_char *name, *alg; 102 int n; 103 time_t timesigned; 104 105 dst_init(); 106 if (msg == NULL || msglen == NULL || sig == NULL || siglen == NULL) 107 return (-1); 108 109 /* Name. */ 110 if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) 111 n = dn_comp(key->dk_key_name, cp, eob - cp, dnptrs, lastdnptr); 112 else 113 n = dn_comp("", cp, eob - cp, NULL, NULL); 114 if (n < 0) 115 return (NS_TSIG_ERROR_NO_SPACE); 116 name = cp; 117 cp += n; 118 119 /* Type, class, ttl, length (not filled in yet). */ 120 BOUNDS_CHECK(cp, NS_INT16SZ + NS_INT16SZ + NS_INT32SZ + NS_INT16SZ); 121 NS_PUT16(ns_t_tsig, cp); 122 NS_PUT16(ns_c_any, cp); 123 NS_PUT32(0, cp); /* TTL */ 124 lenp = cp; 125 cp += 2; 126 127 /* Alg. */ 128 if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) { 129 if (key->dk_alg != KEY_HMAC_MD5) 130 return (-ns_r_badkey); 131 n = dn_comp(NS_TSIG_ALG_HMAC_MD5, cp, eob - cp, NULL, NULL); 132 } 133 else 134 n = dn_comp("", cp, eob - cp, NULL, NULL); 135 if (n < 0) 136 return (NS_TSIG_ERROR_NO_SPACE); 137 alg = cp; 138 cp += n; 139 140 /* Time. */ 141 BOUNDS_CHECK(cp, NS_INT16SZ + NS_INT32SZ + NS_INT16SZ); 142 NS_PUT16(0, cp); 143 timesigned = time(NULL); 144 if (error != ns_r_badtime) 145 NS_PUT32(timesigned, cp); 146 else 147 NS_PUT32(in_timesigned, cp); 148 NS_PUT16(NS_TSIG_FUDGE, cp); 149 150 /* Compute the signature. */ 151 if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) { 152 void *ctx; 153 u_char buf[NS_MAXDNAME], *cp2; 154 int n; 155 156 dst_sign_data(SIG_MODE_INIT, key, &ctx, NULL, 0, NULL, 0); 157 158 /* Digest the query signature, if this is a response. */ 159 if (querysiglen > 0 && querysig != NULL) { 160 u_int16_t len_n = htons(querysiglen); 161 dst_sign_data(SIG_MODE_UPDATE, key, &ctx, 162 (u_char *)&len_n, NS_INT16SZ, NULL, 0); 163 dst_sign_data(SIG_MODE_UPDATE, key, &ctx, 164 querysig, querysiglen, NULL, 0); 165 } 166 167 /* Digest the message. */ 168 dst_sign_data(SIG_MODE_UPDATE, key, &ctx, msg, *msglen, 169 NULL, 0); 170 171 /* Digest the key name. */ 172 n = ns_name_ntol(name, buf, sizeof(buf)); 173 dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0); 174 175 /* Digest the class and TTL. */ 176 cp2 = buf; 177 NS_PUT16(ns_c_any, cp2); 178 NS_PUT32(0, cp2); 179 dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, cp2-buf, 180 NULL, 0); 181 182 /* Digest the algorithm. */ 183 n = ns_name_ntol(alg, buf, sizeof(buf)); 184 dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0); 185 186 /* Digest the time signed, fudge, error, and other data */ 187 cp2 = buf; 188 NS_PUT16(0, cp2); /* Top 16 bits of time */ 189 if (error != ns_r_badtime) 190 NS_PUT32(timesigned, cp2); 191 else 192 NS_PUT32(in_timesigned, cp2); 193 NS_PUT16(NS_TSIG_FUDGE, cp2); 194 NS_PUT16(error, cp2); /* Error */ 195 if (error != ns_r_badtime) 196 NS_PUT16(0, cp2); /* Other data length */ 197 else { 198 NS_PUT16(NS_INT16SZ+NS_INT32SZ, cp2); /* Other data length */ 199 NS_PUT16(0, cp2); /* Top 16 bits of time */ 200 NS_PUT32(timesigned, cp2); 201 } 202 dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, cp2-buf, 203 NULL, 0); 204 205 n = dst_sign_data(SIG_MODE_FINAL, key, &ctx, NULL, 0, 206 sig, *siglen); 207 if (n < 0) 208 return (-ns_r_badkey); 209 *siglen = n; 210 } else 211 *siglen = 0; 212 213 /* Add the signature. */ 214 BOUNDS_CHECK(cp, NS_INT16SZ + (*siglen)); 215 NS_PUT16(*siglen, cp); 216 memcpy(cp, sig, *siglen); 217 cp += (*siglen); 218 219 /* The original message ID & error. */ 220 BOUNDS_CHECK(cp, NS_INT16SZ + NS_INT16SZ); 221 NS_PUT16(ntohs(hp->id), cp); /* already in network order */ 222 NS_PUT16(error, cp); 223 224 /* Other data. */ 225 BOUNDS_CHECK(cp, NS_INT16SZ); 226 if (error != ns_r_badtime) 227 NS_PUT16(0, cp); /* Other data length */ 228 else { 229 NS_PUT16(NS_INT16SZ+NS_INT32SZ, cp); /* Other data length */ 230 BOUNDS_CHECK(cp, NS_INT32SZ+NS_INT16SZ); 231 NS_PUT16(0, cp); /* Top 16 bits of time */ 232 NS_PUT32(timesigned, cp); 233 } 234 235 /* Go back and fill in the length. */ 236 NS_PUT16(cp - lenp - NS_INT16SZ, lenp); 237 238 hp->arcount = htons(ntohs(hp->arcount) + 1); 239 *msglen = (cp - msg); 240 return (0); 241} 242 243int 244ns_sign_tcp_init(void *k, const u_char *querysig, int querysiglen, 245 ns_tcp_tsig_state *state) 246{ 247 dst_init(); 248 if (state == NULL || k == NULL || querysig == NULL || querysiglen < 0) 249 return (-1); 250 state->counter = -1; 251 state->key = k; 252 if (state->key->dk_alg != KEY_HMAC_MD5) 253 return (-ns_r_badkey); 254 if (querysiglen > (int)sizeof(state->sig)) 255 return (-1); 256 memcpy(state->sig, querysig, querysiglen); 257 state->siglen = querysiglen; 258 return (0); 259} 260 261int 262ns_sign_tcp(u_char *msg, int *msglen, int msgsize, int error, 263 ns_tcp_tsig_state *state, int done) 264{ 265 return (ns_sign_tcp2(msg, msglen, msgsize, error, state, 266 done, NULL, NULL)); 267} 268 269int 270ns_sign_tcp2(u_char *msg, int *msglen, int msgsize, int error, 271 ns_tcp_tsig_state *state, int done, 272 u_char **dnptrs, u_char **lastdnptr) 273{ 274 u_char *cp, *eob, *lenp; 275 u_char buf[NS_MAXDNAME], *cp2; 276 HEADER *hp = (HEADER *)msg; 277 time_t timesigned; 278 int n; 279 280 if (msg == NULL || msglen == NULL || state == NULL) 281 return (-1); 282 283 state->counter++; 284 if (state->counter == 0) 285 return (ns_sign2(msg, msglen, msgsize, error, state->key, 286 state->sig, state->siglen, 287 state->sig, &state->siglen, 0, 288 dnptrs, lastdnptr)); 289 290 if (state->siglen > 0) { 291 u_int16_t siglen_n = htons(state->siglen); 292 dst_sign_data(SIG_MODE_INIT, state->key, &state->ctx, 293 NULL, 0, NULL, 0); 294 dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx, 295 (u_char *)&siglen_n, NS_INT16SZ, NULL, 0); 296 dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx, 297 state->sig, state->siglen, NULL, 0); 298 state->siglen = 0; 299 } 300 301 dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx, msg, *msglen, 302 NULL, 0); 303 304 if (done == 0 && (state->counter % 100 != 0)) 305 return (0); 306 307 cp = msg + *msglen; 308 eob = msg + msgsize; 309 310 /* Name. */ 311 n = dn_comp(state->key->dk_key_name, cp, eob - cp, dnptrs, lastdnptr); 312 if (n < 0) 313 return (NS_TSIG_ERROR_NO_SPACE); 314 cp += n; 315 316 /* Type, class, ttl, length (not filled in yet). */ 317 BOUNDS_CHECK(cp, NS_INT16SZ + NS_INT16SZ + NS_INT32SZ + NS_INT16SZ); 318 NS_PUT16(ns_t_tsig, cp); 319 NS_PUT16(ns_c_any, cp); 320 NS_PUT32(0, cp); /* TTL */ 321 lenp = cp; 322 cp += 2; 323 324 /* Alg. */ 325 n = dn_comp(NS_TSIG_ALG_HMAC_MD5, cp, eob - cp, NULL, NULL); 326 if (n < 0) 327 return (NS_TSIG_ERROR_NO_SPACE); 328 cp += n; 329 330 /* Time. */ 331 BOUNDS_CHECK(cp, NS_INT16SZ + NS_INT32SZ + NS_INT16SZ); 332 NS_PUT16(0, cp); 333 timesigned = time(NULL); 334 NS_PUT32(timesigned, cp); 335 NS_PUT16(NS_TSIG_FUDGE, cp); 336 337 /* 338 * Compute the signature. 339 */ 340 341 /* Digest the time signed and fudge. */ 342 cp2 = buf; 343 NS_PUT16(0, cp2); /* Top 16 bits of time */ 344 NS_PUT32(timesigned, cp2); 345 NS_PUT16(NS_TSIG_FUDGE, cp2); 346 347 dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx, 348 buf, cp2 - buf, NULL, 0); 349 350 n = dst_sign_data(SIG_MODE_FINAL, state->key, &state->ctx, NULL, 0, 351 state->sig, sizeof(state->sig)); 352 if (n < 0) 353 return (-ns_r_badkey); 354 state->siglen = n; 355 356 /* Add the signature. */ 357 BOUNDS_CHECK(cp, NS_INT16SZ + state->siglen); 358 NS_PUT16(state->siglen, cp); 359 memcpy(cp, state->sig, state->siglen); 360 cp += state->siglen; 361 362 /* The original message ID & error. */ 363 BOUNDS_CHECK(cp, NS_INT16SZ + NS_INT16SZ); 364 NS_PUT16(ntohs(hp->id), cp); /* already in network order */ 365 NS_PUT16(error, cp); 366 367 /* Other data. */ 368 BOUNDS_CHECK(cp, NS_INT16SZ); 369 NS_PUT16(0, cp); 370 371 /* Go back and fill in the length. */ 372 NS_PUT16(cp - lenp - NS_INT16SZ, lenp); 373 374 hp->arcount = htons(ntohs(hp->arcount) + 1); 375 *msglen = (cp - msg); 376 return (0); 377} 378