Annotation of embedaddon/dhcp/minires/ns_sign.c, revision 1.1.1.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 ! misho      25: static const char rcsid[] = "$Id: ns_sign.c,v 1.6.786.2 2009/07/24 22:04:52 sar 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:        if (n < 0)
                    105:                return ISC_R_NOSPACE;
                    106:        name = cp;
                    107:        cp += n;
                    108: 
                    109:        /* Type, class, ttl, length (not filled in yet). */
                    110:        BOUNDS_CHECK(cp, INT16SZ + INT16SZ + INT32SZ + INT16SZ);
                    111:        PUTSHORT(ns_t_tsig, cp);
                    112:        PUTSHORT(ns_c_any, cp);
                    113:        PUTLONG(0, cp);         /* TTL */
                    114:        lenp = cp;
                    115:        cp += 2;
                    116: 
                    117:        /* Alg. */
                    118:        if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) {
                    119:                if (key->dk_alg != KEY_HMAC_MD5)
                    120:                        return ISC_R_BADKEY;
                    121:                n = dn_comp(NS_TSIG_ALG_HMAC_MD5,
                    122:                            cp, (unsigned)(eob - cp), NULL, NULL);
                    123:        }
                    124:        else
                    125:                n = dn_comp("", cp, (unsigned)(eob - cp), NULL, NULL);
                    126:        if (n < 0)
                    127:                return ISC_R_NOSPACE;
                    128:        alg = cp;
                    129:        cp += n;
                    130:        
                    131:        /* Time. */
                    132:        BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ);
                    133:        PUTSHORT(0, cp);
                    134:        timesigned = time(NULL);
                    135:        if (error != ns_r_badtime)
                    136:                PUTLONG(timesigned, cp);
                    137:        else
                    138:                PUTLONG(in_timesigned, cp);
                    139:        PUTSHORT(NS_TSIG_FUDGE, cp);
                    140: 
                    141:        /* Compute the signature. */
                    142:        if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) {
                    143:                void *ctx;
                    144:                u_char buf[MAXDNAME], *cp2;
                    145:                unsigned n;
                    146: 
                    147:                dst_sign_data(SIG_MODE_INIT, key, &ctx, NULL, 0, NULL, 0);
                    148: 
                    149:                /* Digest the query signature, if this is a response. */
                    150:                if (querysiglen > 0 && querysig != NULL) {
                    151:                        u_int16_t len_n = htons(querysiglen);
                    152:                        dst_sign_data(SIG_MODE_UPDATE, key, &ctx,
                    153:                                      (u_char *)&len_n, INT16SZ, NULL, 0);
                    154:                        dst_sign_data(SIG_MODE_UPDATE, key, &ctx,
                    155:                                      querysig, querysiglen, NULL, 0);
                    156:                }
                    157: 
                    158:                /* Digest the message. */
                    159:                dst_sign_data(SIG_MODE_UPDATE, key, &ctx, msg, *msglen,
                    160:                              NULL, 0);
                    161: 
                    162:                /* Digest the key name. */
                    163:                n = ns_name_ntol(name, buf, sizeof(buf));
                    164:                dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
                    165: 
                    166:                /* Digest the class and TTL. */
                    167:                cp2 = buf;
                    168:                PUTSHORT(ns_c_any, cp2);
                    169:                PUTLONG(0, cp2);
                    170:                dst_sign_data(SIG_MODE_UPDATE, key, &ctx,
                    171:                              buf, (unsigned)(cp2-buf), NULL, 0);
                    172: 
                    173:                /* Digest the algorithm. */
                    174:                n = ns_name_ntol(alg, buf, sizeof(buf));
                    175:                dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
                    176: 
                    177:                /* Digest the time signed, fudge, error, and other data */
                    178:                cp2 = buf;
                    179:                PUTSHORT(0, cp2);       /* Top 16 bits of time */
                    180:                if (error != ns_r_badtime)
                    181:                        PUTLONG(timesigned, cp2);
                    182:                else
                    183:                        PUTLONG(in_timesigned, cp2);
                    184:                PUTSHORT(NS_TSIG_FUDGE, cp2);
                    185:                PUTSHORT(error, cp2);   /* Error */
                    186:                if (error != ns_r_badtime)
                    187:                        PUTSHORT(0, cp2);       /* Other data length */
                    188:                else {
                    189:                        PUTSHORT(INT16SZ+INT32SZ, cp2); /* Other data length */
                    190:                        PUTSHORT(0, cp2);       /* Top 16 bits of time */
                    191:                        PUTLONG(timesigned, cp2);
                    192:                }
                    193:                dst_sign_data(SIG_MODE_UPDATE, key, &ctx,
                    194:                              buf, (unsigned)(cp2-buf), NULL, 0);
                    195: 
                    196:                n = dst_sign_data(SIG_MODE_FINAL, key, &ctx, NULL, 0,
                    197:                                  sig, *siglen);
                    198:                if (n < 0)
                    199:                        return ISC_R_BADKEY;
                    200:                *siglen = n;
                    201:        } else
                    202:                *siglen = 0;
                    203: 
                    204:        /* Add the signature. */
                    205:        BOUNDS_CHECK(cp, INT16SZ + (*siglen));
                    206:        PUTSHORT(*siglen, cp);
                    207:        memcpy(cp, sig, *siglen);
                    208:        cp += (*siglen);
                    209: 
                    210:        /* The original message ID & error. */
                    211:        BOUNDS_CHECK(cp, INT16SZ + INT16SZ);
                    212:        PUTSHORT(ntohs(hp->id), cp);    /* already in network order */
                    213:        PUTSHORT(error, cp);
                    214: 
                    215:        /* Other data. */
                    216:        BOUNDS_CHECK(cp, INT16SZ);
                    217:        if (error != ns_r_badtime)
                    218:                PUTSHORT(0, cp);        /* Other data length */
                    219:        else {
                    220:                PUTSHORT(INT16SZ+INT32SZ, cp);  /* Other data length */
                    221:                BOUNDS_CHECK(cp, INT32SZ+INT16SZ);
                    222:                PUTSHORT(0, cp);        /* Top 16 bits of time */
                    223:                PUTLONG(timesigned, cp);
                    224:        }
                    225: 
                    226:        /* Go back and fill in the length. */
                    227:        PUTSHORT(cp - lenp - INT16SZ, lenp);
                    228: 
                    229:        hp->arcount = htons(ntohs(hp->arcount) + 1);
                    230:        *msglen = (cp - msg);
                    231:        return ISC_R_SUCCESS;
                    232: }
                    233: 
                    234: #if 0
                    235: isc_result_t
                    236: ns_sign_tcp_init(void *k, const u_char *querysig, unsigned querysiglen,
                    237:                 ns_tcp_tsig_state *state)
                    238: {
                    239:        dst_init();
                    240:        if (state == NULL || k == NULL || querysig == NULL || querysiglen < 0)
                    241:                return ISC_R_INVALIDARG;
                    242:        state->counter = -1;
                    243:        state->key = k;
                    244:        if (state->key->dk_alg != KEY_HMAC_MD5)
                    245:                return ISC_R_BADKEY;
                    246:        if (querysiglen > sizeof(state->sig))
                    247:                return ISC_R_NOSPACE;
                    248:        memcpy(state->sig, querysig, querysiglen);
                    249:        state->siglen = querysiglen;
                    250:        return ISC_R_SUCCESS;
                    251: }
                    252: 
                    253: isc_result_t
                    254: ns_sign_tcp(u_char *msg, unsigned *msglen, unsigned msgsize, int error,
                    255:            ns_tcp_tsig_state *state, int done)
                    256: {
                    257:        u_char *cp, *eob, *lenp;
                    258:        u_char buf[MAXDNAME], *cp2;
                    259:        HEADER *hp = (HEADER *)msg;
                    260:        time_t timesigned;
                    261:        int n;
                    262: 
                    263:        if (msg == NULL || msglen == NULL || state == NULL)
                    264:                return ISC_R_INVALIDARG;
                    265: 
                    266:        state->counter++;
                    267:        if (state->counter == 0)
                    268:                return ns_sign(msg, msglen, msgsize, error, state->key,
                    269:                               state->sig, state->siglen,
                    270:                               state->sig, &state->siglen, 0);
                    271: 
                    272:        if (state->siglen > 0) {
                    273:                u_int16_t siglen_n = htons(state->siglen);
                    274:                dst_sign_data(SIG_MODE_INIT, state->key, &state->ctx,
                    275:                              NULL, 0, NULL, 0);
                    276:                dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx,
                    277:                              (u_char *)&siglen_n, INT16SZ, NULL, 0);
                    278:                dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx,
                    279:                              state->sig, state->siglen, NULL, 0);
                    280:                state->siglen = 0;
                    281:        }
                    282: 
                    283:        dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx, msg, *msglen,
                    284:                      NULL, 0);
                    285: 
                    286:        if (done == 0 && (state->counter % 100 != 0))
                    287:                return ISC_R_SUCCESS;
                    288: 
                    289:        cp = msg + *msglen;
                    290:        eob = msg + msgsize;
                    291: 
                    292:        /* Name. */
                    293:        n = dn_comp(state->key->dk_key_name,
                    294:                    cp, (unsigned)(eob - cp), NULL, NULL);
                    295:        if (n < 0)
                    296:                return ISC_R_NOSPACE;
                    297:        cp += n;
                    298: 
                    299:        /* Type, class, ttl, length (not filled in yet). */
                    300:        BOUNDS_CHECK(cp, INT16SZ + INT16SZ + INT32SZ + INT16SZ);
                    301:        PUTSHORT(ns_t_tsig, cp);
                    302:        PUTSHORT(ns_c_any, cp);
                    303:        PUTLONG(0, cp);         /* TTL */
                    304:        lenp = cp;
                    305:        cp += 2;
                    306: 
                    307:        /* Alg. */
                    308:        n = dn_comp(NS_TSIG_ALG_HMAC_MD5,
                    309:                    cp, (unsigned)(eob - cp), NULL, NULL);
                    310:        if (n < 0)
                    311:                return ISC_R_NOSPACE;
                    312:        cp += n;
                    313:        
                    314:        /* Time. */
                    315:        BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ);
                    316:        PUTSHORT(0, cp);
                    317:        timesigned = time(NULL);
                    318:        PUTLONG(timesigned, cp);
                    319:        PUTSHORT(NS_TSIG_FUDGE, cp);
                    320: 
                    321:        /*
                    322:         * Compute the signature.
                    323:         */
                    324: 
                    325:        /* Digest the time signed and fudge. */
                    326:        cp2 = buf;
                    327:        PUTSHORT(0, cp2);       /* Top 16 bits of time */
                    328:        PUTLONG(timesigned, cp2);
                    329:        PUTSHORT(NS_TSIG_FUDGE, cp2);
                    330: 
                    331:        dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx,
                    332:                      buf, (unsigned)(cp2 - buf), NULL, 0);
                    333: 
                    334:        n = dst_sign_data(SIG_MODE_FINAL, state->key, &state->ctx, NULL, 0,
                    335:                          state->sig, sizeof(state->sig));
                    336:        if (n < 0)
                    337:                return ISC_R_BADKEY;
                    338:        state->siglen = n;
                    339: 
                    340:        /* Add the signature. */
                    341:        BOUNDS_CHECK(cp, INT16SZ + state->siglen);
                    342:        PUTSHORT(state->siglen, cp);
                    343:        memcpy(cp, state->sig, state->siglen);
                    344:        cp += state->siglen;
                    345: 
                    346:        /* The original message ID & error. */
                    347:        BOUNDS_CHECK(cp, INT16SZ + INT16SZ);
                    348:        PUTSHORT(ntohs(hp->id), cp);    /* already in network order */
                    349:        PUTSHORT(error, cp);
                    350: 
                    351:        /* Other data. */
                    352:        BOUNDS_CHECK(cp, INT16SZ);
                    353:        PUTSHORT(0, cp);
                    354: 
                    355:        /* Go back and fill in the length. */
                    356:        PUTSHORT(cp - lenp - INT16SZ, lenp);
                    357: 
                    358:        hp->arcount = htons(ntohs(hp->arcount) + 1);
                    359:        *msglen = (cp - msg);
                    360:        return ISC_R_SUCCESS;
                    361: }
                    362: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>