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>