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