Annotation of embedaddon/dhcp/minires/ns_sign.c, revision 1.1.1.1.2.1
1.1 misho 1: /*
2: * Copyright (c) 2004,2009 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: * https://www.isc.org/
22: */
23:
24: #ifndef lint
1.1.1.1.2.1! misho 25: static const char rcsid[] = "$Id: ns_sign.c,v 1.1.1.1 2012/10/09 09:06:54 misho Exp $";
1.1 misho 26: #endif
27:
28: #if defined (TRACING)
29: #define time(x) trace_mr_time (x)
30: time_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 "arpa/nameser.h"
52:
53: #include <isc-dhcp/dst.h>
54:
55: #define BOUNDS_CHECK(ptr, count) \
56: do { \
57: if ((ptr) + (count) > eob) { \
58: return ISC_R_NOSPACE; \
59: } \
60: } while (0)
61:
62: /* ns_sign
63: * Parameters:
64: * msg message to be sent
65: * msglen input - length of message
66: * output - length of signed message
67: * msgsize length of buffer containing message
68: * error value to put in the error field
69: * key tsig key used for signing
70: * querysig (response), the signature in the query
71: * querysiglen (response), the length of the signature in the query
72: * sig a buffer to hold the generated signature
73: * siglen input - length of signature buffer
74: * output - length of signature
75: *
76: * Errors:
77: * - bad input data (-1)
78: * - bad key / sign failed (-BADKEY)
79: * - not enough space (NS_TSIG_ERROR_NO_SPACE)
80: */
81: isc_result_t
82: ns_sign(u_char *msg, unsigned *msglen, unsigned msgsize, int error, void *k,
83: const u_char *querysig, unsigned querysiglen, u_char *sig,
84: unsigned *siglen, time_t in_timesigned)
85: {
86: HEADER *hp = (HEADER *)msg;
87: DST_KEY *key = (DST_KEY *)k;
88: u_char *cp = msg + *msglen, *eob = msg + msgsize;
89: u_char *lenp;
90: u_char *name, *alg;
91: unsigned n;
92: time_t timesigned;
93:
94: dst_init();
95: if (msg == NULL || msglen == NULL || sig == NULL || siglen == NULL)
96: return ISC_R_INVALIDARG;
97:
98: /* Name. */
99: if (key != NULL && error != ns_r_badsig && error != ns_r_badkey)
100: n = dn_comp(key->dk_key_name,
101: cp, (unsigned)(eob - cp), NULL, NULL);
102: else
103: n = dn_comp("", cp, (unsigned)(eob - cp), NULL, NULL);
104: name = cp;
105: cp += n;
106:
107: /* Type, class, ttl, length (not filled in yet). */
108: BOUNDS_CHECK(cp, INT16SZ + INT16SZ + INT32SZ + INT16SZ);
109: PUTSHORT(ns_t_tsig, cp);
110: PUTSHORT(ns_c_any, cp);
111: PUTLONG(0, cp); /* TTL */
112: lenp = cp;
113: cp += 2;
114:
115: /* Alg. */
116: if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) {
117: if (key->dk_alg != KEY_HMAC_MD5)
118: return ISC_R_BADKEY;
119: n = dn_comp(NS_TSIG_ALG_HMAC_MD5,
120: cp, (unsigned)(eob - cp), NULL, NULL);
121: }
122: else
123: n = dn_comp("", cp, (unsigned)(eob - cp), NULL, NULL);
124: alg = cp;
125: cp += n;
126:
127: /* Time. */
128: BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ);
129: PUTSHORT(0, cp);
130: timesigned = time(NULL);
131: if (error != ns_r_badtime)
132: PUTLONG(timesigned, cp);
133: else
134: PUTLONG(in_timesigned, cp);
135: PUTSHORT(NS_TSIG_FUDGE, cp);
136:
137: /* Compute the signature. */
138: if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) {
139: void *ctx;
140: u_char buf[MAXDNAME], *cp2;
141: unsigned n;
142:
143: dst_sign_data(SIG_MODE_INIT, key, &ctx, NULL, 0, NULL, 0);
144:
145: /* Digest the query signature, if this is a response. */
146: if (querysiglen > 0 && querysig != NULL) {
147: u_int16_t len_n = htons(querysiglen);
148: dst_sign_data(SIG_MODE_UPDATE, key, &ctx,
149: (u_char *)&len_n, INT16SZ, NULL, 0);
150: dst_sign_data(SIG_MODE_UPDATE, key, &ctx,
151: querysig, querysiglen, NULL, 0);
152: }
153:
154: /* Digest the message. */
155: dst_sign_data(SIG_MODE_UPDATE, key, &ctx, msg, *msglen,
156: NULL, 0);
157:
158: /* Digest the key name. */
159: n = ns_name_ntol(name, buf, sizeof(buf));
160: dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
161:
162: /* Digest the class and TTL. */
163: cp2 = buf;
164: PUTSHORT(ns_c_any, cp2);
165: PUTLONG(0, cp2);
166: dst_sign_data(SIG_MODE_UPDATE, key, &ctx,
167: buf, (unsigned)(cp2-buf), NULL, 0);
168:
169: /* Digest the algorithm. */
170: n = ns_name_ntol(alg, buf, sizeof(buf));
171: dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
172:
173: /* Digest the time signed, fudge, error, and other data */
174: cp2 = buf;
175: PUTSHORT(0, cp2); /* Top 16 bits of time */
176: if (error != ns_r_badtime)
177: PUTLONG(timesigned, cp2);
178: else
179: PUTLONG(in_timesigned, cp2);
180: PUTSHORT(NS_TSIG_FUDGE, cp2);
181: PUTSHORT(error, cp2); /* Error */
182: if (error != ns_r_badtime)
183: PUTSHORT(0, cp2); /* Other data length */
184: else {
185: PUTSHORT(INT16SZ+INT32SZ, cp2); /* Other data length */
186: PUTSHORT(0, cp2); /* Top 16 bits of time */
187: PUTLONG(timesigned, cp2);
188: }
189: dst_sign_data(SIG_MODE_UPDATE, key, &ctx,
190: buf, (unsigned)(cp2-buf), NULL, 0);
191:
192: n = dst_sign_data(SIG_MODE_FINAL, key, &ctx, NULL, 0,
193: sig, *siglen);
1.1.1.1.2.1! misho 194: if (n)
1.1 misho 195: return ISC_R_BADKEY;
196: *siglen = n;
197: } else
198: *siglen = 0;
199:
200: /* Add the signature. */
201: BOUNDS_CHECK(cp, INT16SZ + (*siglen));
202: PUTSHORT(*siglen, cp);
203: memcpy(cp, sig, *siglen);
204: cp += (*siglen);
205:
206: /* The original message ID & error. */
207: BOUNDS_CHECK(cp, INT16SZ + INT16SZ);
208: PUTSHORT(ntohs(hp->id), cp); /* already in network order */
209: PUTSHORT(error, cp);
210:
211: /* Other data. */
212: BOUNDS_CHECK(cp, INT16SZ);
213: if (error != ns_r_badtime)
214: PUTSHORT(0, cp); /* Other data length */
215: else {
216: PUTSHORT(INT16SZ+INT32SZ, cp); /* Other data length */
217: BOUNDS_CHECK(cp, INT32SZ+INT16SZ);
218: PUTSHORT(0, cp); /* Top 16 bits of time */
219: PUTLONG(timesigned, cp);
220: }
221:
222: /* Go back and fill in the length. */
223: PUTSHORT(cp - lenp - INT16SZ, lenp);
224:
225: hp->arcount = htons(ntohs(hp->arcount) + 1);
226: *msglen = (cp - msg);
227: return ISC_R_SUCCESS;
228: }
229:
230: #if 0
231: isc_result_t
232: ns_sign_tcp_init(void *k, const u_char *querysig, unsigned querysiglen,
233: ns_tcp_tsig_state *state)
234: {
235: dst_init();
236: if (state == NULL || k == NULL || querysig == NULL || querysiglen < 0)
237: return ISC_R_INVALIDARG;
238: state->counter = -1;
239: state->key = k;
240: if (state->key->dk_alg != KEY_HMAC_MD5)
241: return ISC_R_BADKEY;
242: if (querysiglen > sizeof(state->sig))
243: return ISC_R_NOSPACE;
244: memcpy(state->sig, querysig, querysiglen);
245: state->siglen = querysiglen;
246: return ISC_R_SUCCESS;
247: }
248:
249: isc_result_t
250: ns_sign_tcp(u_char *msg, unsigned *msglen, unsigned msgsize, int error,
251: ns_tcp_tsig_state *state, int done)
252: {
253: u_char *cp, *eob, *lenp;
254: u_char buf[MAXDNAME], *cp2;
255: HEADER *hp = (HEADER *)msg;
256: time_t timesigned;
257: int n;
258:
259: if (msg == NULL || msglen == NULL || state == NULL)
260: return ISC_R_INVALIDARG;
261:
262: state->counter++;
263: if (state->counter == 0)
264: return ns_sign(msg, msglen, msgsize, error, state->key,
265: state->sig, state->siglen,
266: state->sig, &state->siglen, 0);
267:
268: if (state->siglen > 0) {
269: u_int16_t siglen_n = htons(state->siglen);
270: dst_sign_data(SIG_MODE_INIT, state->key, &state->ctx,
271: NULL, 0, NULL, 0);
272: dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx,
273: (u_char *)&siglen_n, INT16SZ, NULL, 0);
274: dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx,
275: state->sig, state->siglen, NULL, 0);
276: state->siglen = 0;
277: }
278:
279: dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx, msg, *msglen,
280: NULL, 0);
281:
282: if (done == 0 && (state->counter % 100 != 0))
283: return ISC_R_SUCCESS;
284:
285: cp = msg + *msglen;
286: eob = msg + msgsize;
287:
288: /* Name. */
289: n = dn_comp(state->key->dk_key_name,
290: cp, (unsigned)(eob - cp), NULL, NULL);
291: if (n < 0)
292: return ISC_R_NOSPACE;
293: cp += n;
294:
295: /* Type, class, ttl, length (not filled in yet). */
296: BOUNDS_CHECK(cp, INT16SZ + INT16SZ + INT32SZ + INT16SZ);
297: PUTSHORT(ns_t_tsig, cp);
298: PUTSHORT(ns_c_any, cp);
299: PUTLONG(0, cp); /* TTL */
300: lenp = cp;
301: cp += 2;
302:
303: /* Alg. */
304: n = dn_comp(NS_TSIG_ALG_HMAC_MD5,
305: cp, (unsigned)(eob - cp), NULL, NULL);
306: if (n < 0)
307: return ISC_R_NOSPACE;
308: cp += n;
309:
310: /* Time. */
311: BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ);
312: PUTSHORT(0, cp);
313: timesigned = time(NULL);
314: PUTLONG(timesigned, cp);
315: PUTSHORT(NS_TSIG_FUDGE, cp);
316:
317: /*
318: * Compute the signature.
319: */
320:
321: /* Digest the time signed and fudge. */
322: cp2 = buf;
323: PUTSHORT(0, cp2); /* Top 16 bits of time */
324: PUTLONG(timesigned, cp2);
325: PUTSHORT(NS_TSIG_FUDGE, cp2);
326:
327: dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx,
328: buf, (unsigned)(cp2 - buf), NULL, 0);
329:
330: n = dst_sign_data(SIG_MODE_FINAL, state->key, &state->ctx, NULL, 0,
331: state->sig, sizeof(state->sig));
332: if (n < 0)
333: return ISC_R_BADKEY;
334: state->siglen = n;
335:
336: /* Add the signature. */
337: BOUNDS_CHECK(cp, INT16SZ + state->siglen);
338: PUTSHORT(state->siglen, cp);
339: memcpy(cp, state->sig, state->siglen);
340: cp += state->siglen;
341:
342: /* The original message ID & error. */
343: BOUNDS_CHECK(cp, INT16SZ + INT16SZ);
344: PUTSHORT(ntohs(hp->id), cp); /* already in network order */
345: PUTSHORT(error, cp);
346:
347: /* Other data. */
348: BOUNDS_CHECK(cp, INT16SZ);
349: PUTSHORT(0, cp);
350:
351: /* Go back and fill in the length. */
352: PUTSHORT(cp - lenp - INT16SZ, lenp);
353:
354: hp->arcount = htons(ntohs(hp->arcount) + 1);
355: *msglen = (cp - msg);
356: return ISC_R_SUCCESS;
357: }
358: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>