1/* 2 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (c) 1999-2003 by Internet Software Consortium 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 * Internet Systems Consortium, Inc. 18 * 950 Charter Street 19 * Redwood City, CA 94063 20 * <info@isc.org> 21 * http://www.isc.org/ 22 */ 23 24#ifndef lint 25static const char rcsid[] = "$Id: ns_sign.c,v 1.5 2007/05/27 16:27:57 tls Exp $"; 26#endif 27 28#if defined (TRACING) 29#define time(x) trace_mr_time (x) 30time_t trace_mr_time (time_t *); 31#endif 32 33/* Import. */ 34 35#include <sys/types.h> 36#include <sys/param.h> 37 38#include <netinet/in.h> 39#include <arpa/inet.h> 40#include <sys/socket.h> 41 42#include <errno.h> 43#include <netdb.h> 44#include <stdio.h> 45#include <stdlib.h> 46#include <string.h> 47#include <unistd.h> 48#include <time.h> 49 50#include "minires/minires.h" 51#include "omapip/trace_mr.h" 52#include "arpa/nameser.h" 53 54#include <isc-dhcp/dst.h> 55 56#define BOUNDS_CHECK(ptr, count) \ 57 do { \ 58 if ((ptr) + (count) > eob) { \ 59 return ISC_R_NOSPACE; \ 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 */ 82isc_result_t 83ns_sign(u_char *msg, unsigned *msglen, unsigned msgsize, int error, void *k, 84 const u_char *querysig, unsigned querysiglen, u_char *sig, 85 unsigned *siglen, time_t in_timesigned) 86{ 87 HEADER *hp = (HEADER *)msg; 88 DST_KEY *key = (DST_KEY *)k; 89 u_char *cp = msg + *msglen, *eob = msg + msgsize; 90 u_char *lenp; 91 u_char *name, *alg; 92 unsigned n; 93 time_t timesigned; 94 95 dst_init(); 96 if (msg == NULL || msglen == NULL || sig == NULL || siglen == NULL) 97 return ISC_R_INVALIDARG; 98 99 /* Name. */ 100 if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) 101 n = dn_comp(key->dk_key_name, 102 cp, (unsigned)(eob - cp), NULL, NULL); 103 else 104 n = dn_comp("", cp, (unsigned)(eob - cp), NULL, NULL); 105 if (n < 0) 106 return ISC_R_NOSPACE; 107 name = cp; 108 cp += n; 109 110 /* Type, class, ttl, length (not filled in yet). */ 111 BOUNDS_CHECK(cp, INT16SZ + INT16SZ + INT32SZ + INT16SZ); 112 PUTSHORT(ns_t_tsig, cp); 113 PUTSHORT(ns_c_any, cp); 114 PUTLONG(0, cp); /* TTL */ 115 lenp = cp; 116 cp += 2; 117 118 /* Alg. */ 119 if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) { 120 if (key->dk_alg != KEY_HMAC_MD5) 121 return ISC_R_BADKEY; 122 n = dn_comp(NS_TSIG_ALG_HMAC_MD5, 123 cp, (unsigned)(eob - cp), NULL, NULL); 124 } 125 else 126 n = dn_comp("", cp, (unsigned)(eob - cp), NULL, NULL); 127 if (n < 0) 128 return ISC_R_NOSPACE; 129 alg = cp; 130 cp += n; 131 132 /* Time. */ 133 BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ); 134 PUTSHORT(0, cp); 135 timesigned = time(NULL); 136 if (error != ns_r_badtime) 137 PUTLONG(timesigned, cp); 138 else 139 PUTLONG(in_timesigned, cp); 140 PUTSHORT(NS_TSIG_FUDGE, cp); 141 142 /* Compute the signature. */ 143 if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) { 144 void *ctx; 145 u_char buf[MAXDNAME], *cp2; 146 unsigned n; 147 148 dst_sign_data(SIG_MODE_INIT, key, &ctx, NULL, 0, NULL, 0); 149 150 /* Digest the query signature, if this is a response. */ 151 if (querysiglen > 0 && querysig != NULL) { 152 u_int16_t len_n = htons(querysiglen); 153 dst_sign_data(SIG_MODE_UPDATE, key, &ctx, 154 (u_char *)&len_n, INT16SZ, NULL, 0); 155 dst_sign_data(SIG_MODE_UPDATE, key, &ctx, 156 querysig, querysiglen, NULL, 0); 157 } 158 159 /* Digest the message. */ 160 dst_sign_data(SIG_MODE_UPDATE, key, &ctx, msg, *msglen, 161 NULL, 0); 162 163 /* Digest the key name. */ 164 n = ns_name_ntol(name, buf, sizeof(buf)); 165 dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0); 166 167 /* Digest the class and TTL. */ 168 cp2 = buf; 169 PUTSHORT(ns_c_any, cp2); 170 PUTLONG(0, cp2); 171 dst_sign_data(SIG_MODE_UPDATE, key, &ctx, 172 buf, (unsigned)(cp2-buf), NULL, 0); 173 174 /* Digest the algorithm. */ 175 n = ns_name_ntol(alg, buf, sizeof(buf)); 176 dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0); 177 178 /* Digest the time signed, fudge, error, and other data */ 179 cp2 = buf; 180 PUTSHORT(0, cp2); /* Top 16 bits of time */ 181 if (error != ns_r_badtime) 182 PUTLONG(timesigned, cp2); 183 else 184 PUTLONG(in_timesigned, cp2); 185 PUTSHORT(NS_TSIG_FUDGE, cp2); 186 PUTSHORT(error, cp2); /* Error */ 187 if (error != ns_r_badtime) 188 PUTSHORT(0, cp2); /* Other data length */ 189 else { 190 PUTSHORT(INT16SZ+INT32SZ, cp2); /* Other data length */ 191 PUTSHORT(0, cp2); /* Top 16 bits of time */ 192 PUTLONG(timesigned, cp2); 193 } 194 dst_sign_data(SIG_MODE_UPDATE, key, &ctx, 195 buf, (unsigned)(cp2-buf), NULL, 0); 196 197 n = dst_sign_data(SIG_MODE_FINAL, key, &ctx, NULL, 0, 198 sig, *siglen); 199 if (n < 0) 200 return ISC_R_BADKEY; 201 *siglen = n; 202 } else 203 *siglen = 0; 204 205 /* Add the signature. */ 206 BOUNDS_CHECK(cp, INT16SZ + (*siglen)); 207 PUTSHORT(*siglen, cp); 208 memcpy(cp, sig, *siglen); 209 cp += (*siglen); 210 211 /* The original message ID & error. */ 212 BOUNDS_CHECK(cp, INT16SZ + INT16SZ); 213 PUTSHORT(ntohs(hp->id), cp); /* already in network order */ 214 PUTSHORT(error, cp); 215 216 /* Other data. */ 217 BOUNDS_CHECK(cp, INT16SZ); 218 if (error != ns_r_badtime) 219 PUTSHORT(0, cp); /* Other data length */ 220 else { 221 PUTSHORT(INT16SZ+INT32SZ, cp); /* Other data length */ 222 BOUNDS_CHECK(cp, INT32SZ+INT16SZ); 223 PUTSHORT(0, cp); /* Top 16 bits of time */ 224 PUTLONG(timesigned, cp); 225 } 226 227 /* Go back and fill in the length. */ 228 PUTSHORT(cp - lenp - INT16SZ, lenp); 229 230 hp->arcount = htons(ntohs(hp->arcount) + 1); 231 *msglen = (cp - msg); 232 return ISC_R_SUCCESS; 233} 234 235#if 0 236isc_result_t 237ns_sign_tcp_init(void *k, const u_char *querysig, unsigned querysiglen, 238 ns_tcp_tsig_state *state) 239{ 240 dst_init(); 241 if (state == NULL || k == NULL || querysig == NULL || querysiglen < 0) 242 return ISC_R_INVALIDARG; 243 state->counter = -1; 244 state->key = k; 245 if (state->key->dk_alg != KEY_HMAC_MD5) 246 return ISC_R_BADKEY; 247 if (querysiglen > sizeof(state->sig)) 248 return ISC_R_NOSPACE; 249 memcpy(state->sig, querysig, querysiglen); 250 state->siglen = querysiglen; 251 return ISC_R_SUCCESS; 252} 253 254isc_result_t 255ns_sign_tcp(u_char *msg, unsigned *msglen, unsigned msgsize, int error, 256 ns_tcp_tsig_state *state, int done) 257{ 258 u_char *cp, *eob, *lenp; 259 u_char buf[MAXDNAME], *cp2; 260 HEADER *hp = (HEADER *)msg; 261 time_t timesigned; 262 int n; 263 264 if (msg == NULL || msglen == NULL || state == NULL) 265 return ISC_R_INVALIDARG; 266 267 state->counter++; 268 if (state->counter == 0) 269 return ns_sign(msg, msglen, msgsize, error, state->key, 270 state->sig, state->siglen, 271 state->sig, &state->siglen, 0); 272 273 if (state->siglen > 0) { 274 u_int16_t siglen_n = htons(state->siglen); 275 dst_sign_data(SIG_MODE_INIT, state->key, &state->ctx, 276 NULL, 0, NULL, 0); 277 dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx, 278 (u_char *)&siglen_n, INT16SZ, NULL, 0); 279 dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx, 280 state->sig, state->siglen, NULL, 0); 281 state->siglen = 0; 282 } 283 284 dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx, msg, *msglen, 285 NULL, 0); 286 287 if (done == 0 && (state->counter % 100 != 0)) 288 return ISC_R_SUCCESS; 289 290 cp = msg + *msglen; 291 eob = msg + msgsize; 292 293 /* Name. */ 294 n = dn_comp(state->key->dk_key_name, 295 cp, (unsigned)(eob - cp), NULL, NULL); 296 if (n < 0) 297 return ISC_R_NOSPACE; 298 cp += n; 299 300 /* Type, class, ttl, length (not filled in yet). */ 301 BOUNDS_CHECK(cp, INT16SZ + INT16SZ + INT32SZ + INT16SZ); 302 PUTSHORT(ns_t_tsig, cp); 303 PUTSHORT(ns_c_any, cp); 304 PUTLONG(0, cp); /* TTL */ 305 lenp = cp; 306 cp += 2; 307 308 /* Alg. */ 309 n = dn_comp(NS_TSIG_ALG_HMAC_MD5, 310 cp, (unsigned)(eob - cp), NULL, NULL); 311 if (n < 0) 312 return ISC_R_NOSPACE; 313 cp += n; 314 315 /* Time. */ 316 BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ); 317 PUTSHORT(0, cp); 318 timesigned = time(NULL); 319 PUTLONG(timesigned, cp); 320 PUTSHORT(NS_TSIG_FUDGE, cp); 321 322 /* 323 * Compute the signature. 324 */ 325 326 /* Digest the time signed and fudge. */ 327 cp2 = buf; 328 PUTSHORT(0, cp2); /* Top 16 bits of time */ 329 PUTLONG(timesigned, cp2); 330 PUTSHORT(NS_TSIG_FUDGE, cp2); 331 332 dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx, 333 buf, (unsigned)(cp2 - buf), NULL, 0); 334 335 n = dst_sign_data(SIG_MODE_FINAL, state->key, &state->ctx, NULL, 0, 336 state->sig, sizeof(state->sig)); 337 if (n < 0) 338 return ISC_R_BADKEY; 339 state->siglen = n; 340 341 /* Add the signature. */ 342 BOUNDS_CHECK(cp, INT16SZ + state->siglen); 343 PUTSHORT(state->siglen, cp); 344 memcpy(cp, state->sig, state->siglen); 345 cp += state->siglen; 346 347 /* The original message ID & error. */ 348 BOUNDS_CHECK(cp, INT16SZ + INT16SZ); 349 PUTSHORT(ntohs(hp->id), cp); /* already in network order */ 350 PUTSHORT(error, cp); 351 352 /* Other data. */ 353 BOUNDS_CHECK(cp, INT16SZ); 354 PUTSHORT(0, cp); 355 356 /* Go back and fill in the length. */ 357 PUTSHORT(cp - lenp - INT16SZ, lenp); 358 359 hp->arcount = htons(ntohs(hp->arcount) + 1); 360 *msglen = (cp - msg); 361 return ISC_R_SUCCESS; 362} 363#endif 364