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