1*0d63ce2bSvenki /* 2*0d63ce2bSvenki * CDDL HEADER START 3*0d63ce2bSvenki * 4*0d63ce2bSvenki * The contents of this file are subject to the terms of the 5*0d63ce2bSvenki * Common Development and Distribution License (the "License"). 6*0d63ce2bSvenki * You may not use this file except in compliance with the License. 7*0d63ce2bSvenki * 8*0d63ce2bSvenki * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*0d63ce2bSvenki * or http://www.opensolaris.org/os/licensing. 10*0d63ce2bSvenki * See the License for the specific language governing permissions 11*0d63ce2bSvenki * and limitations under the License. 12*0d63ce2bSvenki * 13*0d63ce2bSvenki * When distributing Covered Code, include this CDDL HEADER in each 14*0d63ce2bSvenki * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*0d63ce2bSvenki * If applicable, add the following below this CDDL HEADER, with the 16*0d63ce2bSvenki * fields enclosed by brackets "[]" replaced with your own identifying 17*0d63ce2bSvenki * information: Portions Copyright [yyyy] [name of copyright owner] 18*0d63ce2bSvenki * 19*0d63ce2bSvenki * CDDL HEADER END 20*0d63ce2bSvenki */ 21*0d63ce2bSvenki 22*0d63ce2bSvenki /* 23*0d63ce2bSvenki * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24*0d63ce2bSvenki * Use is subject to license terms. 25*0d63ce2bSvenki */ 26*0d63ce2bSvenki 27*0d63ce2bSvenki #pragma ident "%Z%%M% %I% %E% SMI" 28*0d63ce2bSvenki 29*0d63ce2bSvenki /* 30*0d63ce2bSvenki * ASN.1 encoding related routines 31*0d63ce2bSvenki */ 32*0d63ce2bSvenki 33*0d63ce2bSvenki #include <stdio.h> 34*0d63ce2bSvenki #include <stdlib.h> 35*0d63ce2bSvenki #include <string.h> 36*0d63ce2bSvenki #include <sys/types.h> 37*0d63ce2bSvenki #include "asn1.h" 38*0d63ce2bSvenki #include "pdu.h" 39*0d63ce2bSvenki #include "debug.h" 40*0d63ce2bSvenki 41*0d63ce2bSvenki /* 42*0d63ce2bSvenki * This routine builds a 'SEQUENCE OF' ASN.1 object in the buffer 43*0d63ce2bSvenki * using the 'id' and 'length' supplied. This is probably the place 44*0d63ce2bSvenki * where using "reverse" asn encoding will help. 45*0d63ce2bSvenki */ 46*0d63ce2bSvenki uchar_t * 47*0d63ce2bSvenki asn_build_sequence(uchar_t *buf, size_t *bufsz_p, uchar_t id, size_t length) 48*0d63ce2bSvenki { 49*0d63ce2bSvenki /* 50*0d63ce2bSvenki * When rebuilding sequence (which we do many times), we'll 51*0d63ce2bSvenki * simply pass NULL to bufsz_p to skip the error check. 52*0d63ce2bSvenki */ 53*0d63ce2bSvenki if ((bufsz_p) && (*bufsz_p < 4)) 54*0d63ce2bSvenki return (NULL); 55*0d63ce2bSvenki 56*0d63ce2bSvenki buf[0] = id; 57*0d63ce2bSvenki buf[1] = (uchar_t)(ASN_LONG_LEN | 0x02); /* following 2 octets */ 58*0d63ce2bSvenki buf[2] = (uchar_t)((length >> 8) & 0xff); 59*0d63ce2bSvenki buf[3] = (uchar_t)(length & 0xff); 60*0d63ce2bSvenki 61*0d63ce2bSvenki if (bufsz_p) 62*0d63ce2bSvenki *bufsz_p -= 4; 63*0d63ce2bSvenki 64*0d63ce2bSvenki LOGASNSEQ(buf, 4); 65*0d63ce2bSvenki 66*0d63ce2bSvenki return (buf + 4); 67*0d63ce2bSvenki } 68*0d63ce2bSvenki 69*0d63ce2bSvenki /* 70*0d63ce2bSvenki * The next two routines, asn_build_header() and asn_build_length(), build 71*0d63ce2bSvenki * the header and length for an arbitrary object type into the buffer. The 72*0d63ce2bSvenki * length of the object is encoded using as few length octets as possible. 73*0d63ce2bSvenki */ 74*0d63ce2bSvenki uchar_t * 75*0d63ce2bSvenki asn_build_header(uchar_t *buf, size_t *bufsz_p, uchar_t id, size_t length) 76*0d63ce2bSvenki { 77*0d63ce2bSvenki if (*bufsz_p < 1) 78*0d63ce2bSvenki return (NULL); 79*0d63ce2bSvenki 80*0d63ce2bSvenki buf[0] = id; 81*0d63ce2bSvenki (*bufsz_p)--; 82*0d63ce2bSvenki 83*0d63ce2bSvenki return (asn_build_length(buf + 1, bufsz_p, length)); 84*0d63ce2bSvenki } 85*0d63ce2bSvenki uchar_t * 86*0d63ce2bSvenki asn_build_length(uchar_t *buf, size_t *bufsz_p, size_t length) 87*0d63ce2bSvenki { 88*0d63ce2bSvenki if (length < 0x80) { 89*0d63ce2bSvenki if (*bufsz_p < 1) 90*0d63ce2bSvenki return (NULL); 91*0d63ce2bSvenki buf[0] = (uchar_t)length; 92*0d63ce2bSvenki (*bufsz_p)--; 93*0d63ce2bSvenki 94*0d63ce2bSvenki LOGASNLENGTH(buf, 1); 95*0d63ce2bSvenki 96*0d63ce2bSvenki return (buf + 1); 97*0d63ce2bSvenki 98*0d63ce2bSvenki } else if (length <= 0xFF) { 99*0d63ce2bSvenki if (*bufsz_p < 2) 100*0d63ce2bSvenki return (NULL); 101*0d63ce2bSvenki buf[0] = (uchar_t)(ASN_LONG_LEN | 0x01); 102*0d63ce2bSvenki buf[1] = (uchar_t)length; 103*0d63ce2bSvenki *bufsz_p -= 2; 104*0d63ce2bSvenki 105*0d63ce2bSvenki LOGASNLENGTH(buf, 2); 106*0d63ce2bSvenki 107*0d63ce2bSvenki return (buf + 2); 108*0d63ce2bSvenki 109*0d63ce2bSvenki } else { 110*0d63ce2bSvenki if (*bufsz_p < 3) 111*0d63ce2bSvenki return (NULL); 112*0d63ce2bSvenki 113*0d63ce2bSvenki buf[0] = (uchar_t)(ASN_LONG_LEN | 0x02); 114*0d63ce2bSvenki buf[1] = (uchar_t)((length >> 8) & 0xff); 115*0d63ce2bSvenki buf[2] = (uchar_t)(length & 0xff); 116*0d63ce2bSvenki *bufsz_p -= 3; 117*0d63ce2bSvenki 118*0d63ce2bSvenki LOGASNLENGTH(buf, 3); 119*0d63ce2bSvenki 120*0d63ce2bSvenki return (buf + 3); 121*0d63ce2bSvenki } 122*0d63ce2bSvenki } 123*0d63ce2bSvenki /* 124*0d63ce2bSvenki * Builds an ASN.1 encoded integer in the buffer using as few octets 125*0d63ce2bSvenki * as possible. 126*0d63ce2bSvenki */ 127*0d63ce2bSvenki uchar_t * 128*0d63ce2bSvenki asn_build_int(uchar_t *buf, size_t *bufsz_p, uchar_t id, int val) 129*0d63ce2bSvenki { 130*0d63ce2bSvenki uint_t uival; 131*0d63ce2bSvenki int ival, i; 132*0d63ce2bSvenki short sval; 133*0d63ce2bSvenki char cval; 134*0d63ce2bSvenki 135*0d63ce2bSvenki size_t valsz; 136*0d63ce2bSvenki uchar_t *p, *valp; 137*0d63ce2bSvenki 138*0d63ce2bSvenki /* 139*0d63ce2bSvenki * We need to "pack" the integer before sending it, so determine 140*0d63ce2bSvenki * the minimum number of bytes in which we can pack the integer 141*0d63ce2bSvenki */ 142*0d63ce2bSvenki uival = ((uint_t)val >> BUILD_INT_SHIFT) & BUILD_INT_MASK; 143*0d63ce2bSvenki ival = val; 144*0d63ce2bSvenki sval = (short)val; /* yes, loss of data intended */ 145*0d63ce2bSvenki cval = (char)val; /* yes, loss of data intended */ 146*0d63ce2bSvenki 147*0d63ce2bSvenki if (val == (int)cval) 148*0d63ce2bSvenki valsz = 1; 149*0d63ce2bSvenki else if (val == (int)sval) 150*0d63ce2bSvenki valsz = 2; 151*0d63ce2bSvenki else if (uival == BUILD_INT_MASK || uival == 0) 152*0d63ce2bSvenki valsz = 3; 153*0d63ce2bSvenki else 154*0d63ce2bSvenki valsz = 4; 155*0d63ce2bSvenki 156*0d63ce2bSvenki /* 157*0d63ce2bSvenki * Prepare the ASN.1 header for the integer 158*0d63ce2bSvenki */ 159*0d63ce2bSvenki if ((p = asn_build_header(buf, bufsz_p, id, valsz)) == NULL) 160*0d63ce2bSvenki return (NULL); 161*0d63ce2bSvenki 162*0d63ce2bSvenki /* 163*0d63ce2bSvenki * If we have enough space left, encode the integer 164*0d63ce2bSvenki */ 165*0d63ce2bSvenki if (*bufsz_p < valsz) 166*0d63ce2bSvenki return (NULL); 167*0d63ce2bSvenki else { 168*0d63ce2bSvenki valp = (uchar_t *)&ival; 169*0d63ce2bSvenki for (i = 0; i < valsz; i++) 170*0d63ce2bSvenki p[i] = valp[sizeof (int) - valsz + i]; 171*0d63ce2bSvenki 172*0d63ce2bSvenki *bufsz_p -= valsz; 173*0d63ce2bSvenki 174*0d63ce2bSvenki LOGASNINT(buf, p + valsz - buf); 175*0d63ce2bSvenki 176*0d63ce2bSvenki return (p + valsz); 177*0d63ce2bSvenki } 178*0d63ce2bSvenki } 179*0d63ce2bSvenki /* 180*0d63ce2bSvenki * Builds an ASN.1 encoded octet string in the buffer. The source string 181*0d63ce2bSvenki * need not be null-terminated. 182*0d63ce2bSvenki */ 183*0d63ce2bSvenki uchar_t * 184*0d63ce2bSvenki asn_build_string(uchar_t *buf, size_t *bufsz_p, uchar_t id, uchar_t *str, 185*0d63ce2bSvenki size_t slen) 186*0d63ce2bSvenki { 187*0d63ce2bSvenki uchar_t *p; 188*0d63ce2bSvenki 189*0d63ce2bSvenki if ((p = asn_build_header(buf, bufsz_p, id, slen)) == NULL) 190*0d63ce2bSvenki return (NULL); 191*0d63ce2bSvenki 192*0d63ce2bSvenki if (*bufsz_p < slen) 193*0d63ce2bSvenki return (NULL); 194*0d63ce2bSvenki else { 195*0d63ce2bSvenki if (str) { 196*0d63ce2bSvenki (void) memcpy(p, str, slen); 197*0d63ce2bSvenki } else { 198*0d63ce2bSvenki (void) memset(p, 0, slen); 199*0d63ce2bSvenki } 200*0d63ce2bSvenki 201*0d63ce2bSvenki *bufsz_p -= slen; 202*0d63ce2bSvenki 203*0d63ce2bSvenki LOGASNOCTSTR(buf, p + slen - buf); 204*0d63ce2bSvenki 205*0d63ce2bSvenki return (p + slen); 206*0d63ce2bSvenki } 207*0d63ce2bSvenki } 208*0d63ce2bSvenki 209*0d63ce2bSvenki /* 210*0d63ce2bSvenki * Builds an Object Identifier into the buffer according to the OID 211*0d63ce2bSvenki * packing and encoding rules. 212*0d63ce2bSvenki */ 213*0d63ce2bSvenki uchar_t * 214*0d63ce2bSvenki asn_build_objid(uchar_t *buf, size_t *bufsz_p, uchar_t id, void *oidp, 215*0d63ce2bSvenki size_t n_subids) 216*0d63ce2bSvenki { 217*0d63ce2bSvenki oid *objid = oidp; 218*0d63ce2bSvenki size_t oid_asnlen; 219*0d63ce2bSvenki oid subid, first_subid; 220*0d63ce2bSvenki uchar_t subid_len[MAX_SUBIDS_IN_OID]; 221*0d63ce2bSvenki uchar_t *p; 222*0d63ce2bSvenki int i, ndx; 223*0d63ce2bSvenki 224*0d63ce2bSvenki /* 225*0d63ce2bSvenki * Eliminate invalid cases 226*0d63ce2bSvenki */ 227*0d63ce2bSvenki if (n_subids < MIN_SUBIDS_IN_OID || n_subids > MAX_SUBIDS_IN_OID) 228*0d63ce2bSvenki return (NULL); 229*0d63ce2bSvenki if ((objid[0] > 2) || (objid[0] < 2 && objid[1] >= 40)) 230*0d63ce2bSvenki return (NULL); 231*0d63ce2bSvenki 232*0d63ce2bSvenki /* 233*0d63ce2bSvenki * The BER encoding rule for the ASN.1 Object Identifier states 234*0d63ce2bSvenki * that after packing the first two subids into one, each subsequent 235*0d63ce2bSvenki * component is considered as the next subid. Each subidentifier is 236*0d63ce2bSvenki * then encoded as a non-negative integer using as few 7-bit blocks 237*0d63ce2bSvenki * as possible. The blocks are packed in octets with the first bit of 238*0d63ce2bSvenki * each octet equal to 1, except for the last octet of each subid. 239*0d63ce2bSvenki */ 240*0d63ce2bSvenki oid_asnlen = 0; 241*0d63ce2bSvenki for (i = 0, ndx = 0; i < n_subids; i++, ndx++) { 242*0d63ce2bSvenki if (i == 0) { 243*0d63ce2bSvenki /* 244*0d63ce2bSvenki * The packing formula for the first two subids 245*0d63ce2bSvenki * of an OID is given by Z = (X * 40) + Y 246*0d63ce2bSvenki */ 247*0d63ce2bSvenki subid = objid[0] * 40 + objid[1]; 248*0d63ce2bSvenki first_subid = subid; 249*0d63ce2bSvenki i++; /* done with both subids 0 and 1 */ 250*0d63ce2bSvenki } else { 251*0d63ce2bSvenki subid = objid[i]; 252*0d63ce2bSvenki } 253*0d63ce2bSvenki 254*0d63ce2bSvenki if (subid < (oid) 0x80) 255*0d63ce2bSvenki subid_len[ndx] = 1; 256*0d63ce2bSvenki else if (subid < (oid) 0x4000) 257*0d63ce2bSvenki subid_len[ndx] = 2; 258*0d63ce2bSvenki else if (subid < (oid) 0x200000) 259*0d63ce2bSvenki subid_len[ndx] = 3; 260*0d63ce2bSvenki else if (subid < (oid) 0x10000000) 261*0d63ce2bSvenki subid_len[ndx] = 4; 262*0d63ce2bSvenki else { 263*0d63ce2bSvenki subid_len[ndx] = 5; 264*0d63ce2bSvenki } 265*0d63ce2bSvenki 266*0d63ce2bSvenki oid_asnlen += subid_len[ndx]; 267*0d63ce2bSvenki } 268*0d63ce2bSvenki 269*0d63ce2bSvenki if ((p = asn_build_header(buf, bufsz_p, id, oid_asnlen)) == NULL) 270*0d63ce2bSvenki return (NULL); 271*0d63ce2bSvenki 272*0d63ce2bSvenki if (*bufsz_p < oid_asnlen) 273*0d63ce2bSvenki return (NULL); 274*0d63ce2bSvenki 275*0d63ce2bSvenki /* 276*0d63ce2bSvenki * Store the encoded OID 277*0d63ce2bSvenki */ 278*0d63ce2bSvenki for (i = 0, ndx = 0; i < n_subids; i++, ndx++) { 279*0d63ce2bSvenki if (i == 0) { 280*0d63ce2bSvenki subid = first_subid; 281*0d63ce2bSvenki i++; 282*0d63ce2bSvenki } else { 283*0d63ce2bSvenki subid = objid[i]; 284*0d63ce2bSvenki } 285*0d63ce2bSvenki 286*0d63ce2bSvenki switch (subid_len[ndx]) { 287*0d63ce2bSvenki case 1: 288*0d63ce2bSvenki *p++ = (uchar_t)subid; 289*0d63ce2bSvenki break; 290*0d63ce2bSvenki 291*0d63ce2bSvenki case 2: 292*0d63ce2bSvenki *p++ = (uchar_t)((subid >> 7) | 0x80); 293*0d63ce2bSvenki *p++ = (uchar_t)(subid & 0x7f); 294*0d63ce2bSvenki break; 295*0d63ce2bSvenki 296*0d63ce2bSvenki case 3: 297*0d63ce2bSvenki *p++ = (uchar_t)((subid >> 14) | 0x80); 298*0d63ce2bSvenki *p++ = (uchar_t)(((subid >> 7) & 0x7f) | 0x80); 299*0d63ce2bSvenki *p++ = (uchar_t)(subid & 0x7f); 300*0d63ce2bSvenki break; 301*0d63ce2bSvenki 302*0d63ce2bSvenki case 4: 303*0d63ce2bSvenki *p++ = (uchar_t)((subid >> 21) | 0x80); 304*0d63ce2bSvenki *p++ = (uchar_t)(((subid >> 14) & 0x7f) | 0x80); 305*0d63ce2bSvenki *p++ = (uchar_t)(((subid >> 7) & 0x7f) | 0x80); 306*0d63ce2bSvenki *p++ = (uchar_t)(subid & 0x7f); 307*0d63ce2bSvenki break; 308*0d63ce2bSvenki 309*0d63ce2bSvenki case 5: 310*0d63ce2bSvenki *p++ = (uchar_t)((subid >> 28) | 0x80); 311*0d63ce2bSvenki *p++ = (uchar_t)(((subid >> 21) & 0x7f) | 0x80); 312*0d63ce2bSvenki *p++ = (uchar_t)(((subid >> 14) & 0x7f) | 0x80); 313*0d63ce2bSvenki *p++ = (uchar_t)(((subid >> 7) & 0x7f) | 0x80); 314*0d63ce2bSvenki *p++ = (uchar_t)(subid & 0x7f); 315*0d63ce2bSvenki break; 316*0d63ce2bSvenki } 317*0d63ce2bSvenki } 318*0d63ce2bSvenki 319*0d63ce2bSvenki *bufsz_p -= oid_asnlen; 320*0d63ce2bSvenki 321*0d63ce2bSvenki LOGASNOID(buf, p - buf); 322*0d63ce2bSvenki 323*0d63ce2bSvenki return (p); 324*0d63ce2bSvenki } 325*0d63ce2bSvenki /* 326*0d63ce2bSvenki * Build an ASN_NULL object val into the request packet 327*0d63ce2bSvenki */ 328*0d63ce2bSvenki uchar_t * 329*0d63ce2bSvenki asn_build_null(uchar_t *buf, size_t *bufsz_p, uchar_t id) 330*0d63ce2bSvenki { 331*0d63ce2bSvenki uchar_t *p; 332*0d63ce2bSvenki 333*0d63ce2bSvenki p = asn_build_header(buf, bufsz_p, id, 0); 334*0d63ce2bSvenki 335*0d63ce2bSvenki LOGASNNULL(buf, p - buf); 336*0d63ce2bSvenki 337*0d63ce2bSvenki return (p); 338*0d63ce2bSvenki } 339*0d63ce2bSvenki 340*0d63ce2bSvenki 341*0d63ce2bSvenki 342*0d63ce2bSvenki /* 343*0d63ce2bSvenki * This routine parses a 'SEQUENCE OF' object header from the input 344*0d63ce2bSvenki * buffer stream. If the identifier tag (made up of class, constructed 345*0d63ce2bSvenki * type and data type tag) does not match the expected identifier tag, 346*0d63ce2bSvenki * returns failure. 347*0d63ce2bSvenki */ 348*0d63ce2bSvenki uchar_t * 349*0d63ce2bSvenki asn_parse_sequence(uchar_t *buf, size_t *bufsz_p, uchar_t exp_id) 350*0d63ce2bSvenki { 351*0d63ce2bSvenki uchar_t *p; 352*0d63ce2bSvenki uchar_t id; 353*0d63ce2bSvenki 354*0d63ce2bSvenki if ((p = asn_parse_header(buf, bufsz_p, &id)) == NULL) 355*0d63ce2bSvenki return (NULL); 356*0d63ce2bSvenki 357*0d63ce2bSvenki if (id != exp_id) 358*0d63ce2bSvenki return (NULL); 359*0d63ce2bSvenki 360*0d63ce2bSvenki return (p); 361*0d63ce2bSvenki } 362*0d63ce2bSvenki /* 363*0d63ce2bSvenki * Return the type identifier of the ASN object via 'id' 364*0d63ce2bSvenki */ 365*0d63ce2bSvenki uchar_t * 366*0d63ce2bSvenki asn_parse_header(uchar_t *buf, size_t *bufsz_p, uchar_t *id) 367*0d63ce2bSvenki { 368*0d63ce2bSvenki uchar_t *p; 369*0d63ce2bSvenki size_t asnobj_len, hdrlen; 370*0d63ce2bSvenki 371*0d63ce2bSvenki /* 372*0d63ce2bSvenki * Objects with extension tag type are not supported 373*0d63ce2bSvenki */ 374*0d63ce2bSvenki if ((buf[0] & ASN_EXT_TAG) == ASN_EXT_TAG) 375*0d63ce2bSvenki return (NULL); 376*0d63ce2bSvenki 377*0d63ce2bSvenki /* 378*0d63ce2bSvenki * Parse the length field of the ASN object in the header 379*0d63ce2bSvenki */ 380*0d63ce2bSvenki if ((p = asn_parse_length(buf + 1, &asnobj_len)) == NULL) 381*0d63ce2bSvenki return (NULL); 382*0d63ce2bSvenki 383*0d63ce2bSvenki /* 384*0d63ce2bSvenki * Check if the rest of the msg packet is big enough for the 385*0d63ce2bSvenki * full length of the object 386*0d63ce2bSvenki */ 387*0d63ce2bSvenki hdrlen = p - buf; 388*0d63ce2bSvenki if (*bufsz_p < (asnobj_len + hdrlen)) 389*0d63ce2bSvenki return (NULL); 390*0d63ce2bSvenki 391*0d63ce2bSvenki *id = buf[0]; 392*0d63ce2bSvenki *bufsz_p -= hdrlen; 393*0d63ce2bSvenki 394*0d63ce2bSvenki return (p); 395*0d63ce2bSvenki } 396*0d63ce2bSvenki /* 397*0d63ce2bSvenki * This routine parses the length of the object as specified in its 398*0d63ce2bSvenki * header. The 'Indefinite' form of representing length is not supported. 399*0d63ce2bSvenki */ 400*0d63ce2bSvenki uchar_t * 401*0d63ce2bSvenki asn_parse_length(uchar_t *buf, size_t *asnobj_len_p) 402*0d63ce2bSvenki { 403*0d63ce2bSvenki uchar_t *p; 404*0d63ce2bSvenki int n_length_octets; 405*0d63ce2bSvenki 406*0d63ce2bSvenki /* 407*0d63ce2bSvenki * First, check for the short-definite form. Length of 408*0d63ce2bSvenki * the object is simply the least significant 7-bits of 409*0d63ce2bSvenki * the first byte. 410*0d63ce2bSvenki */ 411*0d63ce2bSvenki if ((buf[0] & ASN_LONG_LEN) == 0) { 412*0d63ce2bSvenki *asnobj_len_p = (size_t)buf[0]; 413*0d63ce2bSvenki return (buf + 1); 414*0d63ce2bSvenki } 415*0d63ce2bSvenki 416*0d63ce2bSvenki /* 417*0d63ce2bSvenki * Then, eliminate the indefinite form. The ASN_LONG_LEN 418*0d63ce2bSvenki * bit of the first byte will be set and the least significant 419*0d63ce2bSvenki * 7-bites of that byte will be zeros. 420*0d63ce2bSvenki */ 421*0d63ce2bSvenki if (buf[0] == (uchar_t)ASN_LONG_LEN) 422*0d63ce2bSvenki return (NULL); 423*0d63ce2bSvenki 424*0d63ce2bSvenki /* 425*0d63ce2bSvenki * Then, eliminate the long-definite case when the number of 426*0d63ce2bSvenki * follow-up octets is more than what the size var can hold. 427*0d63ce2bSvenki */ 428*0d63ce2bSvenki n_length_octets = buf[0] & ~ASN_LONG_LEN; 429*0d63ce2bSvenki if (n_length_octets > sizeof (*asnobj_len_p)) 430*0d63ce2bSvenki return (NULL); 431*0d63ce2bSvenki 432*0d63ce2bSvenki /* 433*0d63ce2bSvenki * Finally gather the length 434*0d63ce2bSvenki */ 435*0d63ce2bSvenki p = buf + 1; 436*0d63ce2bSvenki *asnobj_len_p = 0; 437*0d63ce2bSvenki while (n_length_octets--) { 438*0d63ce2bSvenki *asnobj_len_p <<= 8; 439*0d63ce2bSvenki *asnobj_len_p |= *p++; 440*0d63ce2bSvenki } 441*0d63ce2bSvenki 442*0d63ce2bSvenki return (p); 443*0d63ce2bSvenki } 444*0d63ce2bSvenki /* 445*0d63ce2bSvenki * Parses an integer out of the input buffer 446*0d63ce2bSvenki */ 447*0d63ce2bSvenki uchar_t * 448*0d63ce2bSvenki asn_parse_int(uchar_t *buf, size_t *bufsz_p, int *ival) 449*0d63ce2bSvenki { 450*0d63ce2bSvenki size_t asnobj_len, hdrlen; 451*0d63ce2bSvenki uchar_t int_id; 452*0d63ce2bSvenki uchar_t *p; 453*0d63ce2bSvenki 454*0d63ce2bSvenki int_id = ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER; 455*0d63ce2bSvenki if (buf[0] != int_id) 456*0d63ce2bSvenki return (NULL); 457*0d63ce2bSvenki 458*0d63ce2bSvenki /* 459*0d63ce2bSvenki * Read in the length of the object; Note that integers are 460*0d63ce2bSvenki * "packed" when sent from agent to manager and vice-versa, 461*0d63ce2bSvenki * so the size of the object could be less than sizeof (int). 462*0d63ce2bSvenki */ 463*0d63ce2bSvenki if ((p = asn_parse_length(buf + 1, &asnobj_len)) == NULL) 464*0d63ce2bSvenki return (NULL); 465*0d63ce2bSvenki 466*0d63ce2bSvenki /* 467*0d63ce2bSvenki * Is there sufficient space left in the packet to read the integer ? 468*0d63ce2bSvenki */ 469*0d63ce2bSvenki hdrlen = p - buf; 470*0d63ce2bSvenki if (*bufsz_p < (hdrlen + asnobj_len)) 471*0d63ce2bSvenki return (NULL); 472*0d63ce2bSvenki 473*0d63ce2bSvenki /* 474*0d63ce2bSvenki * Update space left in the buffer after the integer is read 475*0d63ce2bSvenki */ 476*0d63ce2bSvenki *bufsz_p -= (hdrlen + asnobj_len); 477*0d63ce2bSvenki 478*0d63ce2bSvenki /* 479*0d63ce2bSvenki * Read in the integer value 480*0d63ce2bSvenki */ 481*0d63ce2bSvenki *ival = (*p & ASN_BIT8) ? -1 : 0; 482*0d63ce2bSvenki while (asnobj_len--) { 483*0d63ce2bSvenki *ival <<= 8; 484*0d63ce2bSvenki *ival |= *p++; 485*0d63ce2bSvenki } 486*0d63ce2bSvenki 487*0d63ce2bSvenki return (p); 488*0d63ce2bSvenki } 489*0d63ce2bSvenki /* 490*0d63ce2bSvenki * Parses an unsigned integer out of the input buffer 491*0d63ce2bSvenki */ 492*0d63ce2bSvenki uchar_t * 493*0d63ce2bSvenki asn_parse_uint(uchar_t *buf, size_t *bufsz_p, uint_t *uival) 494*0d63ce2bSvenki { 495*0d63ce2bSvenki size_t asnobj_len, hdrlen; 496*0d63ce2bSvenki uchar_t *p; 497*0d63ce2bSvenki 498*0d63ce2bSvenki if ((buf[0] != ASN_COUNTER) && (buf[0] != ASN_TIMETICKS)) 499*0d63ce2bSvenki return (NULL); 500*0d63ce2bSvenki 501*0d63ce2bSvenki /* 502*0d63ce2bSvenki * Read in the length of the object. Integers are sent the same 503*0d63ce2bSvenki * way unsigned integers are sent. Except that, if the MSB was 1 504*0d63ce2bSvenki * in the unsigned int value, a null-byte is attached to the front. 505*0d63ce2bSvenki * Otherwise, packing rules are the same as for integer values. 506*0d63ce2bSvenki */ 507*0d63ce2bSvenki if ((p = asn_parse_length(buf + 1, &asnobj_len)) == NULL) 508*0d63ce2bSvenki return (NULL); 509*0d63ce2bSvenki 510*0d63ce2bSvenki /* 511*0d63ce2bSvenki * Is there sufficient space left in the packet to read in the value ? 512*0d63ce2bSvenki */ 513*0d63ce2bSvenki hdrlen = p - buf; 514*0d63ce2bSvenki if (*bufsz_p < (hdrlen + asnobj_len)) 515*0d63ce2bSvenki return (NULL); 516*0d63ce2bSvenki 517*0d63ce2bSvenki /* 518*0d63ce2bSvenki * Update space left in the buffer after the uint is read 519*0d63ce2bSvenki */ 520*0d63ce2bSvenki *bufsz_p -= (hdrlen + asnobj_len); 521*0d63ce2bSvenki 522*0d63ce2bSvenki /* 523*0d63ce2bSvenki * Read in the unsigned integer (this should never get 524*0d63ce2bSvenki * initialized to ~0 if it was sent right) 525*0d63ce2bSvenki */ 526*0d63ce2bSvenki *uival = (*p & ASN_BIT8) ? ~0 : 0; 527*0d63ce2bSvenki while (asnobj_len--) { 528*0d63ce2bSvenki *uival <<= 8; 529*0d63ce2bSvenki *uival |= *p++; 530*0d63ce2bSvenki } 531*0d63ce2bSvenki 532*0d63ce2bSvenki return (p); 533*0d63ce2bSvenki } 534*0d63ce2bSvenki /* 535*0d63ce2bSvenki * Parses a string (ASN_OCTET_STR or ASN_BIT_STR) out of the input buffer. 536*0d63ce2bSvenki * The memory for the string is allocated inside the routine and must be 537*0d63ce2bSvenki * freed by the caller when it is no longer needed. If the string type is 538*0d63ce2bSvenki * ASN_OCTET_STR, the returned string is null-terminated, and the returned 539*0d63ce2bSvenki * length indicates the strlen value. If the string type is ASN_BIT_STR, 540*0d63ce2bSvenki * the returned string is not null-terminated, and the returned length 541*0d63ce2bSvenki * indicates the number of bytes. 542*0d63ce2bSvenki */ 543*0d63ce2bSvenki uchar_t * 544*0d63ce2bSvenki asn_parse_string(uchar_t *buf, size_t *bufsz_p, uchar_t **str_p, size_t *slen) 545*0d63ce2bSvenki { 546*0d63ce2bSvenki uchar_t *p; 547*0d63ce2bSvenki uchar_t id1, id2; 548*0d63ce2bSvenki size_t asnobj_len, hdrlen; 549*0d63ce2bSvenki 550*0d63ce2bSvenki /* 551*0d63ce2bSvenki * Octet and bit strings are supported 552*0d63ce2bSvenki */ 553*0d63ce2bSvenki id1 = ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR; 554*0d63ce2bSvenki id2 = ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_BIT_STR; 555*0d63ce2bSvenki if ((buf[0] != id1) && (buf[0] != id2)) 556*0d63ce2bSvenki return (NULL); 557*0d63ce2bSvenki 558*0d63ce2bSvenki /* 559*0d63ce2bSvenki * Parse out the length of the object and verify source buf sz 560*0d63ce2bSvenki */ 561*0d63ce2bSvenki if ((p = asn_parse_length(buf + 1, &asnobj_len)) == NULL) 562*0d63ce2bSvenki return (NULL); 563*0d63ce2bSvenki 564*0d63ce2bSvenki hdrlen = p - buf; 565*0d63ce2bSvenki if (*bufsz_p < (hdrlen + asnobj_len)) 566*0d63ce2bSvenki return (NULL); 567*0d63ce2bSvenki 568*0d63ce2bSvenki /* 569*0d63ce2bSvenki * Allocate for and copy out the string 570*0d63ce2bSvenki */ 571*0d63ce2bSvenki if ((*str_p = (uchar_t *)calloc(1, asnobj_len + 1)) == NULL) 572*0d63ce2bSvenki return (NULL); 573*0d63ce2bSvenki 574*0d63ce2bSvenki (void) memcpy(*str_p, p, asnobj_len); 575*0d63ce2bSvenki 576*0d63ce2bSvenki /* 577*0d63ce2bSvenki * Terminate the octet string with a null 578*0d63ce2bSvenki */ 579*0d63ce2bSvenki if (buf[0] == id1) { 580*0d63ce2bSvenki (*str_p)[asnobj_len] = 0; 581*0d63ce2bSvenki } 582*0d63ce2bSvenki 583*0d63ce2bSvenki /* 584*0d63ce2bSvenki * Update pointers and return 585*0d63ce2bSvenki */ 586*0d63ce2bSvenki *slen = asnobj_len; 587*0d63ce2bSvenki *bufsz_p -= (hdrlen + asnobj_len); 588*0d63ce2bSvenki 589*0d63ce2bSvenki return (p + asnobj_len); 590*0d63ce2bSvenki } 591*0d63ce2bSvenki /* 592*0d63ce2bSvenki * Parses an object identifier out of the input packet buffer. Space for 593*0d63ce2bSvenki * the oid object is allocated within this routine and must be freed by the 594*0d63ce2bSvenki * caller when no longer needed. 595*0d63ce2bSvenki */ 596*0d63ce2bSvenki uchar_t * 597*0d63ce2bSvenki asn_parse_objid(uchar_t *msg, size_t *varsz_p, void *oidp, size_t *n_subids) 598*0d63ce2bSvenki { 599*0d63ce2bSvenki oid **objid_p = oidp; 600*0d63ce2bSvenki oid *objid; 601*0d63ce2bSvenki uchar_t *p; 602*0d63ce2bSvenki size_t hdrlen, asnobj_len; 603*0d63ce2bSvenki oid subid; 604*0d63ce2bSvenki int i, ndx; 605*0d63ce2bSvenki uchar_t exp_id; 606*0d63ce2bSvenki 607*0d63ce2bSvenki /* 608*0d63ce2bSvenki * Check id 609*0d63ce2bSvenki */ 610*0d63ce2bSvenki exp_id = ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID; 611*0d63ce2bSvenki if (msg[0] != exp_id) 612*0d63ce2bSvenki return (NULL); 613*0d63ce2bSvenki 614*0d63ce2bSvenki /* 615*0d63ce2bSvenki * Read object length 616*0d63ce2bSvenki */ 617*0d63ce2bSvenki if ((p = asn_parse_length(msg + 1, &asnobj_len)) == NULL) 618*0d63ce2bSvenki return (NULL); 619*0d63ce2bSvenki 620*0d63ce2bSvenki /* 621*0d63ce2bSvenki * Check space in input message 622*0d63ce2bSvenki */ 623*0d63ce2bSvenki hdrlen = p - msg; 624*0d63ce2bSvenki if (*varsz_p < (hdrlen + asnobj_len)) 625*0d63ce2bSvenki return (NULL); 626*0d63ce2bSvenki 627*0d63ce2bSvenki /* 628*0d63ce2bSvenki * Since the OID subidentifiers are packed in 7-bit blocks with 629*0d63ce2bSvenki * MSB set to 1 for all but the last octet, the number of subids 630*0d63ce2bSvenki * is simply the number of octets with MSB equal to 0, plus 1 631*0d63ce2bSvenki * (since the first two subids were packed into one subid and have 632*0d63ce2bSvenki * to be expanded back to two). 633*0d63ce2bSvenki */ 634*0d63ce2bSvenki *n_subids = 1; 635*0d63ce2bSvenki for (i = 0; i < asnobj_len; i++) { 636*0d63ce2bSvenki if ((p[i] & ASN_BIT8) == 0) 637*0d63ce2bSvenki (*n_subids)++; 638*0d63ce2bSvenki } 639*0d63ce2bSvenki 640*0d63ce2bSvenki /* 641*0d63ce2bSvenki * Now allocate for the oid and parse the OID into it 642*0d63ce2bSvenki */ 643*0d63ce2bSvenki if ((objid = (oid *) calloc(1, (*n_subids) * sizeof (oid))) == NULL) 644*0d63ce2bSvenki return (NULL); 645*0d63ce2bSvenki 646*0d63ce2bSvenki ndx = 1; /* start from 1 to allow for unpacking later */ 647*0d63ce2bSvenki subid = 0; 648*0d63ce2bSvenki for (i = 0; i < asnobj_len; i++) { 649*0d63ce2bSvenki subid = subid << 7; 650*0d63ce2bSvenki subid |= (p[i] & ~ASN_BIT8); 651*0d63ce2bSvenki 652*0d63ce2bSvenki if ((p[i] & ASN_BIT8) == 0) { 653*0d63ce2bSvenki objid[ndx] = subid; 654*0d63ce2bSvenki ndx++; 655*0d63ce2bSvenki subid = 0; 656*0d63ce2bSvenki } 657*0d63ce2bSvenki } 658*0d63ce2bSvenki 659*0d63ce2bSvenki /* 660*0d63ce2bSvenki * Now unpack the first two subids from the subid at index 1. 661*0d63ce2bSvenki */ 662*0d63ce2bSvenki if (objid[1] < 40) { 663*0d63ce2bSvenki objid[0] = 0; 664*0d63ce2bSvenki } else if (objid[1] < 80) { 665*0d63ce2bSvenki objid[0] = 1; 666*0d63ce2bSvenki objid[1] -= 40; 667*0d63ce2bSvenki } else { 668*0d63ce2bSvenki objid[0] = 2; 669*0d63ce2bSvenki objid[1] -= 80; 670*0d63ce2bSvenki } 671*0d63ce2bSvenki 672*0d63ce2bSvenki *objid_p = objid; 673*0d63ce2bSvenki *varsz_p -= (hdrlen + asnobj_len); 674*0d63ce2bSvenki 675*0d63ce2bSvenki return (msg + hdrlen + asnobj_len); 676*0d63ce2bSvenki } 677*0d63ce2bSvenki /* 678*0d63ce2bSvenki * Parses the value of an OID object out of the input message buffer. 679*0d63ce2bSvenki * Only type tags less than ASN_EXT_TAG (0x1f) are supported. 680*0d63ce2bSvenki */ 681*0d63ce2bSvenki uchar_t * 682*0d63ce2bSvenki asn_parse_objval(uchar_t *msg, size_t *varsz_p, void *varlistp) 683*0d63ce2bSvenki { 684*0d63ce2bSvenki pdu_varlist_t *vp = varlistp; 685*0d63ce2bSvenki uchar_t *p; 686*0d63ce2bSvenki size_t n_subids; 687*0d63ce2bSvenki size_t hdrlen, asnobj_len; 688*0d63ce2bSvenki 689*0d63ce2bSvenki vp->type = msg[0] & ASN_EXT_TAG; 690*0d63ce2bSvenki if (vp->type == ASN_EXT_TAG) 691*0d63ce2bSvenki return (NULL); 692*0d63ce2bSvenki 693*0d63ce2bSvenki /* 694*0d63ce2bSvenki * Currently we handle ASN_INTEGER, ASN_OCTET_STR, ASN_BIT_STR 695*0d63ce2bSvenki * and ASN_TIMETICKS types. 696*0d63ce2bSvenki */ 697*0d63ce2bSvenki switch (msg[0]) { 698*0d63ce2bSvenki case ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER: 699*0d63ce2bSvenki vp->val.iptr = (int *)calloc(1, sizeof (int)); 700*0d63ce2bSvenki if (vp->val.iptr == NULL) 701*0d63ce2bSvenki return (NULL); 702*0d63ce2bSvenki 703*0d63ce2bSvenki if ((p = asn_parse_int(msg, varsz_p, vp->val.iptr)) == NULL) { 704*0d63ce2bSvenki free(vp->val.iptr); 705*0d63ce2bSvenki return (NULL); 706*0d63ce2bSvenki } 707*0d63ce2bSvenki vp->val_len = sizeof (int); 708*0d63ce2bSvenki break; 709*0d63ce2bSvenki 710*0d63ce2bSvenki case ASN_COUNTER: 711*0d63ce2bSvenki case ASN_TIMETICKS: 712*0d63ce2bSvenki vp->val.uiptr = (uint_t *)calloc(1, sizeof (uint_t)); 713*0d63ce2bSvenki if (vp->val.uiptr == NULL) 714*0d63ce2bSvenki return (NULL); 715*0d63ce2bSvenki 716*0d63ce2bSvenki if ((p = asn_parse_uint(msg, varsz_p, vp->val.uiptr)) == NULL) { 717*0d63ce2bSvenki free(vp->val.uiptr); 718*0d63ce2bSvenki return (NULL); 719*0d63ce2bSvenki } 720*0d63ce2bSvenki vp->val_len = sizeof (uint_t); 721*0d63ce2bSvenki vp->type = msg[0]; 722*0d63ce2bSvenki break; 723*0d63ce2bSvenki 724*0d63ce2bSvenki case ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR: 725*0d63ce2bSvenki case ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_BIT_STR: 726*0d63ce2bSvenki p = asn_parse_string(msg, varsz_p, &vp->val.str, &vp->val_len); 727*0d63ce2bSvenki if (p == NULL) 728*0d63ce2bSvenki return (NULL); 729*0d63ce2bSvenki break; 730*0d63ce2bSvenki 731*0d63ce2bSvenki case ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID: 732*0d63ce2bSvenki p = asn_parse_objid(msg, varsz_p, &vp->val.objid, &n_subids); 733*0d63ce2bSvenki if (p == NULL) 734*0d63ce2bSvenki return (NULL); 735*0d63ce2bSvenki vp->val_len = n_subids * sizeof (oid); 736*0d63ce2bSvenki break; 737*0d63ce2bSvenki 738*0d63ce2bSvenki case ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_NULL: 739*0d63ce2bSvenki case SNMP_NOSUCHOBJECT: 740*0d63ce2bSvenki case SNMP_NOSUCHINSTANCE: 741*0d63ce2bSvenki case SNMP_ENDOFMIBVIEW: 742*0d63ce2bSvenki default: 743*0d63ce2bSvenki p = asn_parse_length(msg + 1, &asnobj_len); 744*0d63ce2bSvenki if (p == NULL) 745*0d63ce2bSvenki return (NULL); 746*0d63ce2bSvenki 747*0d63ce2bSvenki hdrlen = p - msg; 748*0d63ce2bSvenki if (*varsz_p < (hdrlen + asnobj_len)) 749*0d63ce2bSvenki return (NULL); 750*0d63ce2bSvenki 751*0d63ce2bSvenki vp->type = msg[0]; 752*0d63ce2bSvenki vp->val_len = asnobj_len; 753*0d63ce2bSvenki 754*0d63ce2bSvenki *varsz_p -= (hdrlen + asnobj_len); 755*0d63ce2bSvenki p += asnobj_len; 756*0d63ce2bSvenki break; 757*0d63ce2bSvenki } 758*0d63ce2bSvenki 759*0d63ce2bSvenki return (p); 760*0d63ce2bSvenki } 761