]> git.saurik.com Git - apple/libresolv.git/blob - ns_sign.c
libresolv-67.40.1.tar.gz
[apple/libresolv.git] / ns_sign.c
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
20 static 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 */
82 int
83 ns_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
92 int
93 ns_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
243 int
244 ns_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
261 int
262 ns_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
269 int
270 ns_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 }