1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright 2001-2002 Sun Microsystems, Inc. All rights reserved. 3*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 4*7c478bd9Sstevel@tonic-gate */ 5*7c478bd9Sstevel@tonic-gate 6*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 7*7c478bd9Sstevel@tonic-gate 8*7c478bd9Sstevel@tonic-gate /* 9*7c478bd9Sstevel@tonic-gate * Copyright (c) 1999 by Internet Software Consortium, Inc. 10*7c478bd9Sstevel@tonic-gate * 11*7c478bd9Sstevel@tonic-gate * Permission to use, copy, modify, and distribute this software for any 12*7c478bd9Sstevel@tonic-gate * purpose with or without fee is hereby granted, provided that the above 13*7c478bd9Sstevel@tonic-gate * copyright notice and this permission notice appear in all copies. 14*7c478bd9Sstevel@tonic-gate * 15*7c478bd9Sstevel@tonic-gate * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 16*7c478bd9Sstevel@tonic-gate * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 17*7c478bd9Sstevel@tonic-gate * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 18*7c478bd9Sstevel@tonic-gate * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 19*7c478bd9Sstevel@tonic-gate * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 20*7c478bd9Sstevel@tonic-gate * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 21*7c478bd9Sstevel@tonic-gate * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 22*7c478bd9Sstevel@tonic-gate * SOFTWARE. 23*7c478bd9Sstevel@tonic-gate */ 24*7c478bd9Sstevel@tonic-gate 25*7c478bd9Sstevel@tonic-gate #ifndef lint 26*7c478bd9Sstevel@tonic-gate static const char rcsid[] = "$Id: ns_verify.c,v 8.14 2001/05/29 05:49:40 marka Exp $"; 27*7c478bd9Sstevel@tonic-gate #endif 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate /* Import. */ 30*7c478bd9Sstevel@tonic-gate 31*7c478bd9Sstevel@tonic-gate #include "port_before.h" 32*7c478bd9Sstevel@tonic-gate #include "fd_setsize.h" 33*7c478bd9Sstevel@tonic-gate 34*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 36*7c478bd9Sstevel@tonic-gate 37*7c478bd9Sstevel@tonic-gate #include <netinet/in.h> 38*7c478bd9Sstevel@tonic-gate #include <arpa/nameser.h> 39*7c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 40*7c478bd9Sstevel@tonic-gate 41*7c478bd9Sstevel@tonic-gate #include <errno.h> 42*7c478bd9Sstevel@tonic-gate #include <netdb.h> 43*7c478bd9Sstevel@tonic-gate #include <resolv.h> 44*7c478bd9Sstevel@tonic-gate #include <stdio.h> 45*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 46*7c478bd9Sstevel@tonic-gate #include <string.h> 47*7c478bd9Sstevel@tonic-gate #include <time.h> 48*7c478bd9Sstevel@tonic-gate #include <unistd.h> 49*7c478bd9Sstevel@tonic-gate 50*7c478bd9Sstevel@tonic-gate #include <isc/dst.h> 51*7c478bd9Sstevel@tonic-gate 52*7c478bd9Sstevel@tonic-gate #include "port_after.h" 53*7c478bd9Sstevel@tonic-gate 54*7c478bd9Sstevel@tonic-gate /* Private. */ 55*7c478bd9Sstevel@tonic-gate 56*7c478bd9Sstevel@tonic-gate #define BOUNDS_CHECK(ptr, count) \ 57*7c478bd9Sstevel@tonic-gate do { \ 58*7c478bd9Sstevel@tonic-gate if ((ptr) + (count) > eom) { \ 59*7c478bd9Sstevel@tonic-gate return (NS_TSIG_ERROR_FORMERR); \ 60*7c478bd9Sstevel@tonic-gate } \ 61*7c478bd9Sstevel@tonic-gate } while (0) 62*7c478bd9Sstevel@tonic-gate 63*7c478bd9Sstevel@tonic-gate /* Public. */ 64*7c478bd9Sstevel@tonic-gate 65*7c478bd9Sstevel@tonic-gate u_char * 66*7c478bd9Sstevel@tonic-gate ns_find_tsig(u_char *msg, u_char *eom) { 67*7c478bd9Sstevel@tonic-gate HEADER *hp = (HEADER *)msg; 68*7c478bd9Sstevel@tonic-gate int n, type; 69*7c478bd9Sstevel@tonic-gate u_char *cp = msg, *start; 70*7c478bd9Sstevel@tonic-gate 71*7c478bd9Sstevel@tonic-gate if (msg == NULL || eom == NULL || msg > eom) 72*7c478bd9Sstevel@tonic-gate return (NULL); 73*7c478bd9Sstevel@tonic-gate 74*7c478bd9Sstevel@tonic-gate if (cp + HFIXEDSZ >= eom) 75*7c478bd9Sstevel@tonic-gate return (NULL); 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate if (hp->arcount == 0) 78*7c478bd9Sstevel@tonic-gate return (NULL); 79*7c478bd9Sstevel@tonic-gate 80*7c478bd9Sstevel@tonic-gate cp += HFIXEDSZ; 81*7c478bd9Sstevel@tonic-gate 82*7c478bd9Sstevel@tonic-gate n = ns_skiprr(cp, eom, ns_s_qd, ntohs(hp->qdcount)); 83*7c478bd9Sstevel@tonic-gate if (n < 0) 84*7c478bd9Sstevel@tonic-gate return (NULL); 85*7c478bd9Sstevel@tonic-gate cp += n; 86*7c478bd9Sstevel@tonic-gate 87*7c478bd9Sstevel@tonic-gate n = ns_skiprr(cp, eom, ns_s_an, ntohs(hp->ancount)); 88*7c478bd9Sstevel@tonic-gate if (n < 0) 89*7c478bd9Sstevel@tonic-gate return (NULL); 90*7c478bd9Sstevel@tonic-gate cp += n; 91*7c478bd9Sstevel@tonic-gate 92*7c478bd9Sstevel@tonic-gate n = ns_skiprr(cp, eom, ns_s_ns, ntohs(hp->nscount)); 93*7c478bd9Sstevel@tonic-gate if (n < 0) 94*7c478bd9Sstevel@tonic-gate return (NULL); 95*7c478bd9Sstevel@tonic-gate cp += n; 96*7c478bd9Sstevel@tonic-gate 97*7c478bd9Sstevel@tonic-gate n = ns_skiprr(cp, eom, ns_s_ar, ntohs(hp->arcount) - 1); 98*7c478bd9Sstevel@tonic-gate if (n < 0) 99*7c478bd9Sstevel@tonic-gate return (NULL); 100*7c478bd9Sstevel@tonic-gate cp += n; 101*7c478bd9Sstevel@tonic-gate 102*7c478bd9Sstevel@tonic-gate start = cp; 103*7c478bd9Sstevel@tonic-gate n = dn_skipname(cp, eom); 104*7c478bd9Sstevel@tonic-gate if (n < 0) 105*7c478bd9Sstevel@tonic-gate return (NULL); 106*7c478bd9Sstevel@tonic-gate cp += n; 107*7c478bd9Sstevel@tonic-gate if (cp + INT16SZ >= eom) 108*7c478bd9Sstevel@tonic-gate return (NULL); 109*7c478bd9Sstevel@tonic-gate 110*7c478bd9Sstevel@tonic-gate GETSHORT(type, cp); 111*7c478bd9Sstevel@tonic-gate if (type != ns_t_tsig) 112*7c478bd9Sstevel@tonic-gate return (NULL); 113*7c478bd9Sstevel@tonic-gate return (start); 114*7c478bd9Sstevel@tonic-gate } 115*7c478bd9Sstevel@tonic-gate 116*7c478bd9Sstevel@tonic-gate /* ns_verify 117*7c478bd9Sstevel@tonic-gate * Parameters: 118*7c478bd9Sstevel@tonic-gate * statp res stuff 119*7c478bd9Sstevel@tonic-gate * msg received message 120*7c478bd9Sstevel@tonic-gate * msglen length of message 121*7c478bd9Sstevel@tonic-gate * key tsig key used for verifying. 122*7c478bd9Sstevel@tonic-gate * querysig (response), the signature in the query 123*7c478bd9Sstevel@tonic-gate * querysiglen (response), the length of the signature in the query 124*7c478bd9Sstevel@tonic-gate * sig (query), a buffer to hold the signature 125*7c478bd9Sstevel@tonic-gate * siglen (query), input - length of signature buffer 126*7c478bd9Sstevel@tonic-gate * output - length of signature 127*7c478bd9Sstevel@tonic-gate * 128*7c478bd9Sstevel@tonic-gate * Errors: 129*7c478bd9Sstevel@tonic-gate * - bad input (-1) 130*7c478bd9Sstevel@tonic-gate * - invalid dns message (NS_TSIG_ERROR_FORMERR) 131*7c478bd9Sstevel@tonic-gate * - TSIG is not present (NS_TSIG_ERROR_NO_TSIG) 132*7c478bd9Sstevel@tonic-gate * - key doesn't match (-ns_r_badkey) 133*7c478bd9Sstevel@tonic-gate * - TSIG verification fails with BADKEY (-ns_r_badkey) 134*7c478bd9Sstevel@tonic-gate * - TSIG verification fails with BADSIG (-ns_r_badsig) 135*7c478bd9Sstevel@tonic-gate * - TSIG verification fails with BADTIME (-ns_r_badtime) 136*7c478bd9Sstevel@tonic-gate * - TSIG verification succeeds, error set to BAKEY (ns_r_badkey) 137*7c478bd9Sstevel@tonic-gate * - TSIG verification succeeds, error set to BADSIG (ns_r_badsig) 138*7c478bd9Sstevel@tonic-gate * - TSIG verification succeeds, error set to BADTIME (ns_r_badtime) 139*7c478bd9Sstevel@tonic-gate */ 140*7c478bd9Sstevel@tonic-gate int 141*7c478bd9Sstevel@tonic-gate ns_verify(u_char *msg, int *msglen, void *k, 142*7c478bd9Sstevel@tonic-gate const u_char *querysig, int querysiglen, u_char *sig, int *siglen, 143*7c478bd9Sstevel@tonic-gate time_t *timesigned, int nostrip) 144*7c478bd9Sstevel@tonic-gate { 145*7c478bd9Sstevel@tonic-gate HEADER *hp = (HEADER *)msg; 146*7c478bd9Sstevel@tonic-gate DST_KEY *key = (DST_KEY *)k; 147*7c478bd9Sstevel@tonic-gate u_char *cp = msg, *eom; 148*7c478bd9Sstevel@tonic-gate char name[MAXDNAME], alg[MAXDNAME]; 149*7c478bd9Sstevel@tonic-gate u_char *recstart, *rdatastart; 150*7c478bd9Sstevel@tonic-gate u_char *sigstart, *otherstart; 151*7c478bd9Sstevel@tonic-gate int n; 152*7c478bd9Sstevel@tonic-gate int error; 153*7c478bd9Sstevel@tonic-gate u_int16_t type, length; 154*7c478bd9Sstevel@tonic-gate u_int16_t fudge, sigfieldlen, id, otherfieldlen; 155*7c478bd9Sstevel@tonic-gate 156*7c478bd9Sstevel@tonic-gate dst_init(); 157*7c478bd9Sstevel@tonic-gate if (msg == NULL || msglen == NULL || *msglen < 0) 158*7c478bd9Sstevel@tonic-gate return (-1); 159*7c478bd9Sstevel@tonic-gate 160*7c478bd9Sstevel@tonic-gate eom = msg + *msglen; 161*7c478bd9Sstevel@tonic-gate 162*7c478bd9Sstevel@tonic-gate recstart = ns_find_tsig(msg, eom); 163*7c478bd9Sstevel@tonic-gate if (recstart == NULL) 164*7c478bd9Sstevel@tonic-gate return (NS_TSIG_ERROR_NO_TSIG); 165*7c478bd9Sstevel@tonic-gate 166*7c478bd9Sstevel@tonic-gate cp = recstart; 167*7c478bd9Sstevel@tonic-gate 168*7c478bd9Sstevel@tonic-gate /* Read the key name. */ 169*7c478bd9Sstevel@tonic-gate n = dn_expand(msg, eom, cp, name, MAXDNAME); 170*7c478bd9Sstevel@tonic-gate if (n < 0) 171*7c478bd9Sstevel@tonic-gate return (NS_TSIG_ERROR_FORMERR); 172*7c478bd9Sstevel@tonic-gate cp += n; 173*7c478bd9Sstevel@tonic-gate 174*7c478bd9Sstevel@tonic-gate /* Read the type. */ 175*7c478bd9Sstevel@tonic-gate BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ); 176*7c478bd9Sstevel@tonic-gate GETSHORT(type, cp); 177*7c478bd9Sstevel@tonic-gate if (type != ns_t_tsig) 178*7c478bd9Sstevel@tonic-gate return (NS_TSIG_ERROR_NO_TSIG); 179*7c478bd9Sstevel@tonic-gate 180*7c478bd9Sstevel@tonic-gate /* Skip the class and TTL, save the length. */ 181*7c478bd9Sstevel@tonic-gate cp += INT16SZ + INT32SZ; 182*7c478bd9Sstevel@tonic-gate GETSHORT(length, cp); 183*7c478bd9Sstevel@tonic-gate if (eom - cp != length) 184*7c478bd9Sstevel@tonic-gate return (NS_TSIG_ERROR_FORMERR); 185*7c478bd9Sstevel@tonic-gate 186*7c478bd9Sstevel@tonic-gate /* Read the algorithm name. */ 187*7c478bd9Sstevel@tonic-gate rdatastart = cp; 188*7c478bd9Sstevel@tonic-gate n = dn_expand(msg, eom, cp, alg, MAXDNAME); 189*7c478bd9Sstevel@tonic-gate if (n < 0) 190*7c478bd9Sstevel@tonic-gate return (NS_TSIG_ERROR_FORMERR); 191*7c478bd9Sstevel@tonic-gate if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1) 192*7c478bd9Sstevel@tonic-gate return (-ns_r_badkey); 193*7c478bd9Sstevel@tonic-gate cp += n; 194*7c478bd9Sstevel@tonic-gate 195*7c478bd9Sstevel@tonic-gate /* Read the time signed and fudge. */ 196*7c478bd9Sstevel@tonic-gate BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ); 197*7c478bd9Sstevel@tonic-gate cp += INT16SZ; 198*7c478bd9Sstevel@tonic-gate GETLONG((*timesigned), cp); 199*7c478bd9Sstevel@tonic-gate GETSHORT(fudge, cp); 200*7c478bd9Sstevel@tonic-gate 201*7c478bd9Sstevel@tonic-gate /* Read the signature. */ 202*7c478bd9Sstevel@tonic-gate BOUNDS_CHECK(cp, INT16SZ); 203*7c478bd9Sstevel@tonic-gate GETSHORT(sigfieldlen, cp); 204*7c478bd9Sstevel@tonic-gate BOUNDS_CHECK(cp, sigfieldlen); 205*7c478bd9Sstevel@tonic-gate sigstart = cp; 206*7c478bd9Sstevel@tonic-gate cp += sigfieldlen; 207*7c478bd9Sstevel@tonic-gate 208*7c478bd9Sstevel@tonic-gate /* Read the original id and error. */ 209*7c478bd9Sstevel@tonic-gate BOUNDS_CHECK(cp, 2*INT16SZ); 210*7c478bd9Sstevel@tonic-gate GETSHORT(id, cp); 211*7c478bd9Sstevel@tonic-gate GETSHORT(error, cp); 212*7c478bd9Sstevel@tonic-gate 213*7c478bd9Sstevel@tonic-gate /* Parse the other data. */ 214*7c478bd9Sstevel@tonic-gate BOUNDS_CHECK(cp, INT16SZ); 215*7c478bd9Sstevel@tonic-gate GETSHORT(otherfieldlen, cp); 216*7c478bd9Sstevel@tonic-gate BOUNDS_CHECK(cp, otherfieldlen); 217*7c478bd9Sstevel@tonic-gate otherstart = cp; 218*7c478bd9Sstevel@tonic-gate cp += otherfieldlen; 219*7c478bd9Sstevel@tonic-gate 220*7c478bd9Sstevel@tonic-gate if (cp != eom) 221*7c478bd9Sstevel@tonic-gate return (NS_TSIG_ERROR_FORMERR); 222*7c478bd9Sstevel@tonic-gate 223*7c478bd9Sstevel@tonic-gate /* Verify that the key used is OK. */ 224*7c478bd9Sstevel@tonic-gate if (key != NULL) { 225*7c478bd9Sstevel@tonic-gate if (key->dk_alg != KEY_HMAC_MD5) 226*7c478bd9Sstevel@tonic-gate return (-ns_r_badkey); 227*7c478bd9Sstevel@tonic-gate if (error != ns_r_badsig && error != ns_r_badkey) { 228*7c478bd9Sstevel@tonic-gate if (ns_samename(key->dk_key_name, name) != 1) 229*7c478bd9Sstevel@tonic-gate return (-ns_r_badkey); 230*7c478bd9Sstevel@tonic-gate } 231*7c478bd9Sstevel@tonic-gate } 232*7c478bd9Sstevel@tonic-gate 233*7c478bd9Sstevel@tonic-gate hp->arcount = htons(ntohs(hp->arcount) - 1); 234*7c478bd9Sstevel@tonic-gate 235*7c478bd9Sstevel@tonic-gate /* 236*7c478bd9Sstevel@tonic-gate * Do the verification. 237*7c478bd9Sstevel@tonic-gate */ 238*7c478bd9Sstevel@tonic-gate 239*7c478bd9Sstevel@tonic-gate if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) { 240*7c478bd9Sstevel@tonic-gate void *ctx; 241*7c478bd9Sstevel@tonic-gate u_char buf[MAXDNAME]; 242*7c478bd9Sstevel@tonic-gate u_char buf2[MAXDNAME]; 243*7c478bd9Sstevel@tonic-gate 244*7c478bd9Sstevel@tonic-gate /* Digest the query signature, if this is a response. */ 245*7c478bd9Sstevel@tonic-gate dst_verify_data(SIG_MODE_INIT, key, &ctx, NULL, 0, NULL, 0); 246*7c478bd9Sstevel@tonic-gate if (querysiglen > 0 && querysig != NULL) { 247*7c478bd9Sstevel@tonic-gate u_int16_t len_n = htons(querysiglen); 248*7c478bd9Sstevel@tonic-gate dst_verify_data(SIG_MODE_UPDATE, key, &ctx, 249*7c478bd9Sstevel@tonic-gate (u_char *)&len_n, INT16SZ, NULL, 0); 250*7c478bd9Sstevel@tonic-gate dst_verify_data(SIG_MODE_UPDATE, key, &ctx, 251*7c478bd9Sstevel@tonic-gate querysig, querysiglen, NULL, 0); 252*7c478bd9Sstevel@tonic-gate } 253*7c478bd9Sstevel@tonic-gate 254*7c478bd9Sstevel@tonic-gate /* Digest the message. */ 255*7c478bd9Sstevel@tonic-gate dst_verify_data(SIG_MODE_UPDATE, key, &ctx, msg, recstart - msg, 256*7c478bd9Sstevel@tonic-gate NULL, 0); 257*7c478bd9Sstevel@tonic-gate 258*7c478bd9Sstevel@tonic-gate /* Digest the key name. */ 259*7c478bd9Sstevel@tonic-gate n = ns_name_pton(name, buf2, sizeof(buf2)); 260*7c478bd9Sstevel@tonic-gate if (n < 0) 261*7c478bd9Sstevel@tonic-gate return (-1); 262*7c478bd9Sstevel@tonic-gate n = ns_name_ntol(buf2, buf, sizeof(buf)); 263*7c478bd9Sstevel@tonic-gate if (n < 0) 264*7c478bd9Sstevel@tonic-gate return (-1); 265*7c478bd9Sstevel@tonic-gate dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0); 266*7c478bd9Sstevel@tonic-gate 267*7c478bd9Sstevel@tonic-gate /* Digest the class and TTL. */ 268*7c478bd9Sstevel@tonic-gate dst_verify_data(SIG_MODE_UPDATE, key, &ctx, 269*7c478bd9Sstevel@tonic-gate recstart + dn_skipname(recstart, eom) + INT16SZ, 270*7c478bd9Sstevel@tonic-gate INT16SZ + INT32SZ, NULL, 0); 271*7c478bd9Sstevel@tonic-gate 272*7c478bd9Sstevel@tonic-gate /* Digest the algorithm. */ 273*7c478bd9Sstevel@tonic-gate n = ns_name_pton(alg, buf2, sizeof(buf2)); 274*7c478bd9Sstevel@tonic-gate if (n < 0) 275*7c478bd9Sstevel@tonic-gate return (-1); 276*7c478bd9Sstevel@tonic-gate n = ns_name_ntol(buf2, buf, sizeof(buf)); 277*7c478bd9Sstevel@tonic-gate if (n < 0) 278*7c478bd9Sstevel@tonic-gate return (-1); 279*7c478bd9Sstevel@tonic-gate dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0); 280*7c478bd9Sstevel@tonic-gate 281*7c478bd9Sstevel@tonic-gate /* Digest the time signed and fudge. */ 282*7c478bd9Sstevel@tonic-gate dst_verify_data(SIG_MODE_UPDATE, key, &ctx, 283*7c478bd9Sstevel@tonic-gate rdatastart + dn_skipname(rdatastart, eom), 284*7c478bd9Sstevel@tonic-gate INT16SZ + INT32SZ + INT16SZ, NULL, 0); 285*7c478bd9Sstevel@tonic-gate 286*7c478bd9Sstevel@tonic-gate /* Digest the error and other data. */ 287*7c478bd9Sstevel@tonic-gate dst_verify_data(SIG_MODE_UPDATE, key, &ctx, 288*7c478bd9Sstevel@tonic-gate otherstart - INT16SZ - INT16SZ, 289*7c478bd9Sstevel@tonic-gate otherfieldlen + INT16SZ + INT16SZ, NULL, 0); 290*7c478bd9Sstevel@tonic-gate 291*7c478bd9Sstevel@tonic-gate n = dst_verify_data(SIG_MODE_FINAL, key, &ctx, NULL, 0, 292*7c478bd9Sstevel@tonic-gate sigstart, sigfieldlen); 293*7c478bd9Sstevel@tonic-gate 294*7c478bd9Sstevel@tonic-gate if (n < 0) 295*7c478bd9Sstevel@tonic-gate return (-ns_r_badsig); 296*7c478bd9Sstevel@tonic-gate 297*7c478bd9Sstevel@tonic-gate if (sig != NULL && siglen != NULL) { 298*7c478bd9Sstevel@tonic-gate if (*siglen < sigfieldlen) 299*7c478bd9Sstevel@tonic-gate return (NS_TSIG_ERROR_NO_SPACE); 300*7c478bd9Sstevel@tonic-gate memcpy(sig, sigstart, sigfieldlen); 301*7c478bd9Sstevel@tonic-gate *siglen = sigfieldlen; 302*7c478bd9Sstevel@tonic-gate } 303*7c478bd9Sstevel@tonic-gate } else { 304*7c478bd9Sstevel@tonic-gate if (sigfieldlen > 0) 305*7c478bd9Sstevel@tonic-gate return (NS_TSIG_ERROR_FORMERR); 306*7c478bd9Sstevel@tonic-gate if (sig != NULL && siglen != NULL) 307*7c478bd9Sstevel@tonic-gate *siglen = 0; 308*7c478bd9Sstevel@tonic-gate } 309*7c478bd9Sstevel@tonic-gate 310*7c478bd9Sstevel@tonic-gate /* Reset the counter, since we still need to check for badtime. */ 311*7c478bd9Sstevel@tonic-gate hp->arcount = htons(ntohs(hp->arcount) + 1); 312*7c478bd9Sstevel@tonic-gate 313*7c478bd9Sstevel@tonic-gate /* Verify the time. */ 314*7c478bd9Sstevel@tonic-gate if (abs((*timesigned) - time(NULL)) > fudge) 315*7c478bd9Sstevel@tonic-gate return (-ns_r_badtime); 316*7c478bd9Sstevel@tonic-gate 317*7c478bd9Sstevel@tonic-gate if (nostrip == 0) { 318*7c478bd9Sstevel@tonic-gate *msglen = recstart - msg; 319*7c478bd9Sstevel@tonic-gate hp->arcount = htons(ntohs(hp->arcount) - 1); 320*7c478bd9Sstevel@tonic-gate } 321*7c478bd9Sstevel@tonic-gate 322*7c478bd9Sstevel@tonic-gate if (error != NOERROR) 323*7c478bd9Sstevel@tonic-gate return (error); 324*7c478bd9Sstevel@tonic-gate 325*7c478bd9Sstevel@tonic-gate return (0); 326*7c478bd9Sstevel@tonic-gate } 327*7c478bd9Sstevel@tonic-gate 328*7c478bd9Sstevel@tonic-gate int 329*7c478bd9Sstevel@tonic-gate ns_verify_tcp_init(void *k, const u_char *querysig, int querysiglen, 330*7c478bd9Sstevel@tonic-gate ns_tcp_tsig_state *state) 331*7c478bd9Sstevel@tonic-gate { 332*7c478bd9Sstevel@tonic-gate dst_init(); 333*7c478bd9Sstevel@tonic-gate if (state == NULL || k == NULL || querysig == NULL || querysiglen < 0) 334*7c478bd9Sstevel@tonic-gate return (-1); 335*7c478bd9Sstevel@tonic-gate state->counter = -1; 336*7c478bd9Sstevel@tonic-gate state->key = k; 337*7c478bd9Sstevel@tonic-gate if (state->key->dk_alg != KEY_HMAC_MD5) 338*7c478bd9Sstevel@tonic-gate return (-ns_r_badkey); 339*7c478bd9Sstevel@tonic-gate if (querysiglen > (int)sizeof(state->sig)) 340*7c478bd9Sstevel@tonic-gate return (-1); 341*7c478bd9Sstevel@tonic-gate memcpy(state->sig, querysig, querysiglen); 342*7c478bd9Sstevel@tonic-gate state->siglen = querysiglen; 343*7c478bd9Sstevel@tonic-gate return (0); 344*7c478bd9Sstevel@tonic-gate } 345*7c478bd9Sstevel@tonic-gate 346*7c478bd9Sstevel@tonic-gate int 347*7c478bd9Sstevel@tonic-gate ns_verify_tcp(u_char *msg, int *msglen, ns_tcp_tsig_state *state, 348*7c478bd9Sstevel@tonic-gate int required) 349*7c478bd9Sstevel@tonic-gate { 350*7c478bd9Sstevel@tonic-gate HEADER *hp = (HEADER *)msg; 351*7c478bd9Sstevel@tonic-gate u_char *recstart, *rdatastart, *sigstart; 352*7c478bd9Sstevel@tonic-gate unsigned int sigfieldlen, otherfieldlen; 353*7c478bd9Sstevel@tonic-gate u_char *cp, *eom = msg + *msglen, *cp2; 354*7c478bd9Sstevel@tonic-gate char name[MAXDNAME], alg[MAXDNAME]; 355*7c478bd9Sstevel@tonic-gate u_char buf[MAXDNAME]; 356*7c478bd9Sstevel@tonic-gate int n, type, length, fudge, id, error; 357*7c478bd9Sstevel@tonic-gate time_t timesigned; 358*7c478bd9Sstevel@tonic-gate 359*7c478bd9Sstevel@tonic-gate if (msg == NULL || msglen == NULL || state == NULL) 360*7c478bd9Sstevel@tonic-gate return (-1); 361*7c478bd9Sstevel@tonic-gate 362*7c478bd9Sstevel@tonic-gate state->counter++; 363*7c478bd9Sstevel@tonic-gate if (state->counter == 0) 364*7c478bd9Sstevel@tonic-gate return (ns_verify(msg, msglen, state->key, 365*7c478bd9Sstevel@tonic-gate state->sig, state->siglen, 366*7c478bd9Sstevel@tonic-gate state->sig, &state->siglen, ×igned, 0)); 367*7c478bd9Sstevel@tonic-gate 368*7c478bd9Sstevel@tonic-gate if (state->siglen > 0) { 369*7c478bd9Sstevel@tonic-gate u_int16_t siglen_n = htons(state->siglen); 370*7c478bd9Sstevel@tonic-gate 371*7c478bd9Sstevel@tonic-gate dst_verify_data(SIG_MODE_INIT, state->key, &state->ctx, 372*7c478bd9Sstevel@tonic-gate NULL, 0, NULL, 0); 373*7c478bd9Sstevel@tonic-gate dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx, 374*7c478bd9Sstevel@tonic-gate (u_char *)&siglen_n, INT16SZ, NULL, 0); 375*7c478bd9Sstevel@tonic-gate dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx, 376*7c478bd9Sstevel@tonic-gate state->sig, state->siglen, NULL, 0); 377*7c478bd9Sstevel@tonic-gate state->siglen = 0; 378*7c478bd9Sstevel@tonic-gate } 379*7c478bd9Sstevel@tonic-gate 380*7c478bd9Sstevel@tonic-gate cp = recstart = ns_find_tsig(msg, eom); 381*7c478bd9Sstevel@tonic-gate 382*7c478bd9Sstevel@tonic-gate if (recstart == NULL) { 383*7c478bd9Sstevel@tonic-gate if (required) 384*7c478bd9Sstevel@tonic-gate return (NS_TSIG_ERROR_NO_TSIG); 385*7c478bd9Sstevel@tonic-gate dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx, 386*7c478bd9Sstevel@tonic-gate msg, *msglen, NULL, 0); 387*7c478bd9Sstevel@tonic-gate return (0); 388*7c478bd9Sstevel@tonic-gate } 389*7c478bd9Sstevel@tonic-gate 390*7c478bd9Sstevel@tonic-gate hp->arcount = htons(ntohs(hp->arcount) - 1); 391*7c478bd9Sstevel@tonic-gate dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx, 392*7c478bd9Sstevel@tonic-gate msg, recstart - msg, NULL, 0); 393*7c478bd9Sstevel@tonic-gate 394*7c478bd9Sstevel@tonic-gate /* Read the key name. */ 395*7c478bd9Sstevel@tonic-gate n = dn_expand(msg, eom, cp, name, MAXDNAME); 396*7c478bd9Sstevel@tonic-gate if (n < 0) 397*7c478bd9Sstevel@tonic-gate return (NS_TSIG_ERROR_FORMERR); 398*7c478bd9Sstevel@tonic-gate cp += n; 399*7c478bd9Sstevel@tonic-gate 400*7c478bd9Sstevel@tonic-gate /* Read the type. */ 401*7c478bd9Sstevel@tonic-gate BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ); 402*7c478bd9Sstevel@tonic-gate GETSHORT(type, cp); 403*7c478bd9Sstevel@tonic-gate if (type != ns_t_tsig) 404*7c478bd9Sstevel@tonic-gate return (NS_TSIG_ERROR_NO_TSIG); 405*7c478bd9Sstevel@tonic-gate 406*7c478bd9Sstevel@tonic-gate /* Skip the class and TTL, save the length. */ 407*7c478bd9Sstevel@tonic-gate cp += INT16SZ + INT32SZ; 408*7c478bd9Sstevel@tonic-gate GETSHORT(length, cp); 409*7c478bd9Sstevel@tonic-gate if (eom - cp != length) 410*7c478bd9Sstevel@tonic-gate return (NS_TSIG_ERROR_FORMERR); 411*7c478bd9Sstevel@tonic-gate 412*7c478bd9Sstevel@tonic-gate /* Read the algorithm name. */ 413*7c478bd9Sstevel@tonic-gate rdatastart = cp; 414*7c478bd9Sstevel@tonic-gate n = dn_expand(msg, eom, cp, alg, MAXDNAME); 415*7c478bd9Sstevel@tonic-gate if (n < 0) 416*7c478bd9Sstevel@tonic-gate return (NS_TSIG_ERROR_FORMERR); 417*7c478bd9Sstevel@tonic-gate if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1) 418*7c478bd9Sstevel@tonic-gate return (-ns_r_badkey); 419*7c478bd9Sstevel@tonic-gate cp += n; 420*7c478bd9Sstevel@tonic-gate 421*7c478bd9Sstevel@tonic-gate /* Verify that the key used is OK. */ 422*7c478bd9Sstevel@tonic-gate if ((ns_samename(state->key->dk_key_name, name) != 1 || 423*7c478bd9Sstevel@tonic-gate state->key->dk_alg != KEY_HMAC_MD5)) 424*7c478bd9Sstevel@tonic-gate return (-ns_r_badkey); 425*7c478bd9Sstevel@tonic-gate 426*7c478bd9Sstevel@tonic-gate /* Read the time signed and fudge. */ 427*7c478bd9Sstevel@tonic-gate BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ); 428*7c478bd9Sstevel@tonic-gate cp += INT16SZ; 429*7c478bd9Sstevel@tonic-gate GETLONG(timesigned, cp); 430*7c478bd9Sstevel@tonic-gate GETSHORT(fudge, cp); 431*7c478bd9Sstevel@tonic-gate 432*7c478bd9Sstevel@tonic-gate /* Read the signature. */ 433*7c478bd9Sstevel@tonic-gate BOUNDS_CHECK(cp, INT16SZ); 434*7c478bd9Sstevel@tonic-gate GETSHORT(sigfieldlen, cp); 435*7c478bd9Sstevel@tonic-gate BOUNDS_CHECK(cp, sigfieldlen); 436*7c478bd9Sstevel@tonic-gate sigstart = cp; 437*7c478bd9Sstevel@tonic-gate cp += sigfieldlen; 438*7c478bd9Sstevel@tonic-gate 439*7c478bd9Sstevel@tonic-gate /* Read the original id and error. */ 440*7c478bd9Sstevel@tonic-gate BOUNDS_CHECK(cp, 2*INT16SZ); 441*7c478bd9Sstevel@tonic-gate GETSHORT(id, cp); 442*7c478bd9Sstevel@tonic-gate GETSHORT(error, cp); 443*7c478bd9Sstevel@tonic-gate 444*7c478bd9Sstevel@tonic-gate /* Parse the other data. */ 445*7c478bd9Sstevel@tonic-gate BOUNDS_CHECK(cp, INT16SZ); 446*7c478bd9Sstevel@tonic-gate GETSHORT(otherfieldlen, cp); 447*7c478bd9Sstevel@tonic-gate BOUNDS_CHECK(cp, otherfieldlen); 448*7c478bd9Sstevel@tonic-gate cp += otherfieldlen; 449*7c478bd9Sstevel@tonic-gate 450*7c478bd9Sstevel@tonic-gate if (cp != eom) 451*7c478bd9Sstevel@tonic-gate return (NS_TSIG_ERROR_FORMERR); 452*7c478bd9Sstevel@tonic-gate 453*7c478bd9Sstevel@tonic-gate /* 454*7c478bd9Sstevel@tonic-gate * Do the verification. 455*7c478bd9Sstevel@tonic-gate */ 456*7c478bd9Sstevel@tonic-gate 457*7c478bd9Sstevel@tonic-gate /* Digest the time signed and fudge. */ 458*7c478bd9Sstevel@tonic-gate cp2 = buf; 459*7c478bd9Sstevel@tonic-gate PUTSHORT(0, cp2); /* Top 16 bits of time. */ 460*7c478bd9Sstevel@tonic-gate PUTLONG(timesigned, cp2); 461*7c478bd9Sstevel@tonic-gate PUTSHORT(NS_TSIG_FUDGE, cp2); 462*7c478bd9Sstevel@tonic-gate 463*7c478bd9Sstevel@tonic-gate dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx, 464*7c478bd9Sstevel@tonic-gate buf, cp2 - buf, NULL, 0); 465*7c478bd9Sstevel@tonic-gate 466*7c478bd9Sstevel@tonic-gate n = dst_verify_data(SIG_MODE_FINAL, state->key, &state->ctx, NULL, 0, 467*7c478bd9Sstevel@tonic-gate sigstart, sigfieldlen); 468*7c478bd9Sstevel@tonic-gate if (n < 0) 469*7c478bd9Sstevel@tonic-gate return (-ns_r_badsig); 470*7c478bd9Sstevel@tonic-gate 471*7c478bd9Sstevel@tonic-gate if (sigfieldlen > sizeof(state->sig)) 472*7c478bd9Sstevel@tonic-gate return (NS_TSIG_ERROR_NO_SPACE); 473*7c478bd9Sstevel@tonic-gate 474*7c478bd9Sstevel@tonic-gate memcpy(state->sig, sigstart, sigfieldlen); 475*7c478bd9Sstevel@tonic-gate state->siglen = sigfieldlen; 476*7c478bd9Sstevel@tonic-gate 477*7c478bd9Sstevel@tonic-gate /* Verify the time. */ 478*7c478bd9Sstevel@tonic-gate if (abs(timesigned - time(NULL)) > fudge) 479*7c478bd9Sstevel@tonic-gate return (-ns_r_badtime); 480*7c478bd9Sstevel@tonic-gate 481*7c478bd9Sstevel@tonic-gate *msglen = recstart - msg; 482*7c478bd9Sstevel@tonic-gate 483*7c478bd9Sstevel@tonic-gate if (error != NOERROR) 484*7c478bd9Sstevel@tonic-gate return (error); 485*7c478bd9Sstevel@tonic-gate 486*7c478bd9Sstevel@tonic-gate return (0); 487*7c478bd9Sstevel@tonic-gate } 488