1*99ebb4caSwyllys /* 2*99ebb4caSwyllys * CDDL HEADER START 3*99ebb4caSwyllys * 4*99ebb4caSwyllys * The contents of this file are subject to the terms of the 5*99ebb4caSwyllys * Common Development and Distribution License (the "License"). 6*99ebb4caSwyllys * You may not use this file except in compliance with the License. 7*99ebb4caSwyllys * 8*99ebb4caSwyllys * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*99ebb4caSwyllys * or http://www.opensolaris.org/os/licensing. 10*99ebb4caSwyllys * See the License for the specific language governing permissions 11*99ebb4caSwyllys * and limitations under the License. 12*99ebb4caSwyllys * 13*99ebb4caSwyllys * When distributing Covered Code, include this CDDL HEADER in each 14*99ebb4caSwyllys * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*99ebb4caSwyllys * If applicable, add the following below this CDDL HEADER, with the 16*99ebb4caSwyllys * fields enclosed by brackets "[]" replaced with your own identifying 17*99ebb4caSwyllys * information: Portions Copyright [yyyy] [name of copyright owner] 18*99ebb4caSwyllys * 19*99ebb4caSwyllys * CDDL HEADER END 20*99ebb4caSwyllys */ 21*99ebb4caSwyllys 22*99ebb4caSwyllys /* 23*99ebb4caSwyllys * -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- 24*99ebb4caSwyllys * 25*99ebb4caSwyllys * The contents of this file are subject to the Netscape Public License 26*99ebb4caSwyllys * Version 1.0 (the "NPL"); you may not use this file except in 27*99ebb4caSwyllys * compliance with the NPL. You may obtain a copy of the NPL at 28*99ebb4caSwyllys * http://www.mozilla.org/NPL/ 29*99ebb4caSwyllys * 30*99ebb4caSwyllys * Software distributed under the NPL is distributed on an "AS IS" basis, 31*99ebb4caSwyllys * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL 32*99ebb4caSwyllys * for the specific language governing rights and limitations under the 33*99ebb4caSwyllys * NPL. 34*99ebb4caSwyllys * 35*99ebb4caSwyllys * The Initial Developer of this code under the NPL is Netscape 36*99ebb4caSwyllys * Communications Corporation. Portions created by Netscape are 37*99ebb4caSwyllys * Copyright (C) 1998 Netscape Communications Corporation. All Rights 38*99ebb4caSwyllys * Reserved. 39*99ebb4caSwyllys */ 40*99ebb4caSwyllys 41*99ebb4caSwyllys /* 42*99ebb4caSwyllys * Copyright (c) 1990 Regents of the University of Michigan. 43*99ebb4caSwyllys * All rights reserved. 44*99ebb4caSwyllys * 45*99ebb4caSwyllys * Redistribution and use in source and binary forms are permitted 46*99ebb4caSwyllys * provided that this notice is preserved and that due credit is given 47*99ebb4caSwyllys * to the University of Michigan at Ann Arbor. The name of the University 48*99ebb4caSwyllys * may not be used to endorse or promote products derived from this 49*99ebb4caSwyllys * software without specific prior written permission. This software 50*99ebb4caSwyllys * is provided ``as is'' without express or implied warranty. 51*99ebb4caSwyllys */ 52*99ebb4caSwyllys 53*99ebb4caSwyllys /* 54*99ebb4caSwyllys * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 55*99ebb4caSwyllys * Use is subject to license terms. 56*99ebb4caSwyllys */ 57*99ebb4caSwyllys 58*99ebb4caSwyllys #pragma ident "%Z%%M% %I% %E% SMI" 59*99ebb4caSwyllys 60*99ebb4caSwyllys #include <sys/types.h> 61*99ebb4caSwyllys #include <netinet/in.h> 62*99ebb4caSwyllys #include <inttypes.h> 63*99ebb4caSwyllys 64*99ebb4caSwyllys #include <ber_der.h> 65*99ebb4caSwyllys #include "kmfber_int.h" 66*99ebb4caSwyllys 67*99ebb4caSwyllys /* the following constants are used in kmfber_calc_lenlen */ 68*99ebb4caSwyllys 69*99ebb4caSwyllys #define LENMASK1 0xFF 70*99ebb4caSwyllys #define LENMASK2 0xFFFF 71*99ebb4caSwyllys #define LENMASK3 0xFFFFFF 72*99ebb4caSwyllys #define LENMASK4 0xFFFFFFFF 73*99ebb4caSwyllys #define _MASK 0x80 74*99ebb4caSwyllys 75*99ebb4caSwyllys int 76*99ebb4caSwyllys kmfber_calc_taglen(ber_tag_t tag) 77*99ebb4caSwyllys { 78*99ebb4caSwyllys int i; 79*99ebb4caSwyllys ber_int_t mask; 80*99ebb4caSwyllys 81*99ebb4caSwyllys /* find the first non-all-zero byte in the tag */ 82*99ebb4caSwyllys for (i = sizeof (ber_int_t) - 1; i > 0; i--) { 83*99ebb4caSwyllys mask = (LENMASK3 << (i * 8)); 84*99ebb4caSwyllys /* not all zero */ 85*99ebb4caSwyllys if (tag & mask) 86*99ebb4caSwyllys break; 87*99ebb4caSwyllys } 88*99ebb4caSwyllys 89*99ebb4caSwyllys return (i + 1); 90*99ebb4caSwyllys } 91*99ebb4caSwyllys 92*99ebb4caSwyllys static int 93*99ebb4caSwyllys ber_put_tag(BerElement *ber, ber_tag_t tag, int nosos) 94*99ebb4caSwyllys { 95*99ebb4caSwyllys ber_int_t taglen; 96*99ebb4caSwyllys ber_tag_t ntag; 97*99ebb4caSwyllys 98*99ebb4caSwyllys taglen = kmfber_calc_taglen(tag); 99*99ebb4caSwyllys 100*99ebb4caSwyllys ntag = htonl(tag); 101*99ebb4caSwyllys 102*99ebb4caSwyllys return (kmfber_write(ber, 103*99ebb4caSwyllys ((char *) &ntag) + sizeof (ber_int_t) - taglen, 104*99ebb4caSwyllys taglen, nosos)); 105*99ebb4caSwyllys } 106*99ebb4caSwyllys 107*99ebb4caSwyllys int 108*99ebb4caSwyllys kmfber_calc_lenlen(ber_int_t len) 109*99ebb4caSwyllys { 110*99ebb4caSwyllys /* 111*99ebb4caSwyllys * short len if it's less than 128 - one byte giving the len, 112*99ebb4caSwyllys * with bit 8 0. 113*99ebb4caSwyllys */ 114*99ebb4caSwyllys 115*99ebb4caSwyllys if (len <= 0x7F) 116*99ebb4caSwyllys return (1); 117*99ebb4caSwyllys 118*99ebb4caSwyllys /* 119*99ebb4caSwyllys * long len otherwise - one byte with bit 8 set, giving the 120*99ebb4caSwyllys * length of the length, followed by the length itself. 121*99ebb4caSwyllys */ 122*99ebb4caSwyllys 123*99ebb4caSwyllys if (len <= LENMASK1) 124*99ebb4caSwyllys return (2); 125*99ebb4caSwyllys if (len <= LENMASK2) 126*99ebb4caSwyllys return (3); 127*99ebb4caSwyllys if (len <= LENMASK3) 128*99ebb4caSwyllys return (4); 129*99ebb4caSwyllys 130*99ebb4caSwyllys return (5); 131*99ebb4caSwyllys } 132*99ebb4caSwyllys 133*99ebb4caSwyllys int 134*99ebb4caSwyllys kmfber_put_len(BerElement *ber, ber_int_t len, int nosos) 135*99ebb4caSwyllys { 136*99ebb4caSwyllys int i; 137*99ebb4caSwyllys char lenlen; 138*99ebb4caSwyllys ber_int_t mask, netlen; 139*99ebb4caSwyllys 140*99ebb4caSwyllys /* 141*99ebb4caSwyllys * short len if it's less than 128 - one byte giving the len, 142*99ebb4caSwyllys * with bit 8 0. 143*99ebb4caSwyllys */ 144*99ebb4caSwyllys if (len <= 127) { 145*99ebb4caSwyllys netlen = htonl(len); 146*99ebb4caSwyllys return (kmfber_write(ber, 147*99ebb4caSwyllys (char *)&netlen + sizeof (ber_int_t) - 1, 148*99ebb4caSwyllys 1, nosos)); 149*99ebb4caSwyllys } 150*99ebb4caSwyllys 151*99ebb4caSwyllys /* 152*99ebb4caSwyllys * long len otherwise - one byte with bit 8 set, giving the 153*99ebb4caSwyllys * length of the length, followed by the length itself. 154*99ebb4caSwyllys */ 155*99ebb4caSwyllys 156*99ebb4caSwyllys /* find the first non-all-zero byte */ 157*99ebb4caSwyllys for (i = sizeof (ber_int_t) - 1; i > 0; i--) { 158*99ebb4caSwyllys mask = (LENMASK1 << (i * 8)); 159*99ebb4caSwyllys /* not all zero */ 160*99ebb4caSwyllys if (len & mask) 161*99ebb4caSwyllys break; 162*99ebb4caSwyllys } 163*99ebb4caSwyllys lenlen = ++i; 164*99ebb4caSwyllys if (lenlen > 4) 165*99ebb4caSwyllys return (-1); 166*99ebb4caSwyllys lenlen |= 0x80; 167*99ebb4caSwyllys 168*99ebb4caSwyllys /* write the length of the length */ 169*99ebb4caSwyllys if (kmfber_write(ber, &lenlen, 1, nosos) != 1) 170*99ebb4caSwyllys return (-1); 171*99ebb4caSwyllys 172*99ebb4caSwyllys /* write the length itself */ 173*99ebb4caSwyllys netlen = htonl(len); 174*99ebb4caSwyllys if (kmfber_write(ber, 175*99ebb4caSwyllys (char *) &netlen + (sizeof (ber_int_t) - i), i, nosos) != i) 176*99ebb4caSwyllys return (-1); 177*99ebb4caSwyllys 178*99ebb4caSwyllys return (i + 1); 179*99ebb4caSwyllys } 180*99ebb4caSwyllys 181*99ebb4caSwyllys static int 182*99ebb4caSwyllys ber_put_int_or_enum(BerElement *ber, ber_int_t num, ber_tag_t tag) 183*99ebb4caSwyllys { 184*99ebb4caSwyllys int i, sign; 185*99ebb4caSwyllys ber_int_t len, lenlen, taglen, netnum, mask; 186*99ebb4caSwyllys 187*99ebb4caSwyllys sign = (num < 0); 188*99ebb4caSwyllys 189*99ebb4caSwyllys /* 190*99ebb4caSwyllys * high bit is set - look for first non-all-one byte 191*99ebb4caSwyllys * high bit is clear - look for first non-all-zero byte 192*99ebb4caSwyllys */ 193*99ebb4caSwyllys for (i = sizeof (ber_int_t) - 1; i > 0; i--) { 194*99ebb4caSwyllys mask = (LENMASK1 << (i * 8)); 195*99ebb4caSwyllys 196*99ebb4caSwyllys if (sign) { 197*99ebb4caSwyllys /* not all ones */ 198*99ebb4caSwyllys if ((num & mask) != mask) 199*99ebb4caSwyllys break; 200*99ebb4caSwyllys } else { 201*99ebb4caSwyllys /* not all zero */ 202*99ebb4caSwyllys if (num & mask) 203*99ebb4caSwyllys break; 204*99ebb4caSwyllys } 205*99ebb4caSwyllys } 206*99ebb4caSwyllys 207*99ebb4caSwyllys /* 208*99ebb4caSwyllys * we now have the "leading byte". if the high bit on this 209*99ebb4caSwyllys * byte matches the sign bit, we need to "back up" a byte. 210*99ebb4caSwyllys */ 211*99ebb4caSwyllys mask = (num & (_MASK << (i * 8))); 212*99ebb4caSwyllys if ((mask && !sign) || (sign && !mask)) 213*99ebb4caSwyllys i++; 214*99ebb4caSwyllys 215*99ebb4caSwyllys len = i + 1; 216*99ebb4caSwyllys 217*99ebb4caSwyllys if ((taglen = ber_put_tag(ber, tag, 0)) == -1) 218*99ebb4caSwyllys return (-1); 219*99ebb4caSwyllys 220*99ebb4caSwyllys if ((lenlen = kmfber_put_len(ber, len, 0)) == -1) 221*99ebb4caSwyllys return (-1); 222*99ebb4caSwyllys i++; 223*99ebb4caSwyllys netnum = htonl(num); 224*99ebb4caSwyllys if (kmfber_write(ber, 225*99ebb4caSwyllys (char *) &netnum + (sizeof (ber_int_t) - i), i, 0) == i) 226*99ebb4caSwyllys /* length of tag + length + contents */ 227*99ebb4caSwyllys return (taglen + lenlen + i); 228*99ebb4caSwyllys 229*99ebb4caSwyllys return (-1); 230*99ebb4caSwyllys } 231*99ebb4caSwyllys 232*99ebb4caSwyllys static int 233*99ebb4caSwyllys kmfber_put_enum(BerElement *ber, ber_int_t num, ber_tag_t tag) 234*99ebb4caSwyllys { 235*99ebb4caSwyllys if (tag == KMFBER_DEFAULT) 236*99ebb4caSwyllys tag = BER_ENUMERATED; 237*99ebb4caSwyllys 238*99ebb4caSwyllys return (ber_put_int_or_enum(ber, num, tag)); 239*99ebb4caSwyllys } 240*99ebb4caSwyllys 241*99ebb4caSwyllys int 242*99ebb4caSwyllys ber_put_int(BerElement *ber, ber_int_t num, ber_tag_t tag) 243*99ebb4caSwyllys { 244*99ebb4caSwyllys if (tag == KMFBER_DEFAULT) 245*99ebb4caSwyllys tag = BER_INTEGER; 246*99ebb4caSwyllys 247*99ebb4caSwyllys return (ber_put_int_or_enum(ber, num, tag)); 248*99ebb4caSwyllys } 249*99ebb4caSwyllys 250*99ebb4caSwyllys int 251*99ebb4caSwyllys ber_put_oid(BerElement *ber, struct berval *oid, ber_tag_t tag) 252*99ebb4caSwyllys { 253*99ebb4caSwyllys ber_int_t taglen, lenlen, rc, len; 254*99ebb4caSwyllys 255*99ebb4caSwyllys if (tag == KMFBER_DEFAULT) 256*99ebb4caSwyllys tag = 0x06; /* TODO: Add new OID constant to header */ 257*99ebb4caSwyllys 258*99ebb4caSwyllys if ((taglen = ber_put_tag(ber, tag, 0)) == -1) 259*99ebb4caSwyllys return (-1); 260*99ebb4caSwyllys 261*99ebb4caSwyllys len = (ber_int_t)oid->bv_len; 262*99ebb4caSwyllys if ((lenlen = kmfber_put_len(ber, len, 0)) == -1 || 263*99ebb4caSwyllys kmfber_write(ber, oid->bv_val, oid->bv_len, 0) != 264*99ebb4caSwyllys (ber_int_t)oid->bv_len) { 265*99ebb4caSwyllys rc = -1; 266*99ebb4caSwyllys } else { 267*99ebb4caSwyllys /* return length of tag + length + contents */ 268*99ebb4caSwyllys rc = taglen + lenlen + oid->bv_len; 269*99ebb4caSwyllys } 270*99ebb4caSwyllys return (rc); 271*99ebb4caSwyllys } 272*99ebb4caSwyllys 273*99ebb4caSwyllys int 274*99ebb4caSwyllys ber_put_big_int(BerElement *ber, ber_tag_t tag, char *data, 275*99ebb4caSwyllys ber_len_t len) 276*99ebb4caSwyllys { 277*99ebb4caSwyllys ber_int_t taglen, lenlen, ilen, rc; 278*99ebb4caSwyllys 279*99ebb4caSwyllys if (tag == KMFBER_DEFAULT) 280*99ebb4caSwyllys tag = BER_INTEGER; 281*99ebb4caSwyllys 282*99ebb4caSwyllys if ((taglen = ber_put_tag(ber, tag, 0)) == -1) 283*99ebb4caSwyllys return (-1); 284*99ebb4caSwyllys 285*99ebb4caSwyllys ilen = (ber_int_t)len; 286*99ebb4caSwyllys if ((lenlen = kmfber_put_len(ber, ilen, 0)) == -1 || 287*99ebb4caSwyllys kmfber_write(ber, data, len, 0) != (ber_int_t)len) { 288*99ebb4caSwyllys rc = -1; 289*99ebb4caSwyllys } else { 290*99ebb4caSwyllys /* return length of tag + length + contents */ 291*99ebb4caSwyllys rc = taglen + lenlen + len; 292*99ebb4caSwyllys } 293*99ebb4caSwyllys return (rc); 294*99ebb4caSwyllys } 295*99ebb4caSwyllys 296*99ebb4caSwyllys static int 297*99ebb4caSwyllys kmfber_put_ostring(BerElement *ber, char *str, ber_len_t len, 298*99ebb4caSwyllys ber_tag_t tag) 299*99ebb4caSwyllys { 300*99ebb4caSwyllys ber_int_t taglen, lenlen, ilen, rc; 301*99ebb4caSwyllys #ifdef STR_TRANSLATION 302*99ebb4caSwyllys int free_str; 303*99ebb4caSwyllys #endif /* STR_TRANSLATION */ 304*99ebb4caSwyllys 305*99ebb4caSwyllys if (tag == KMFBER_DEFAULT) 306*99ebb4caSwyllys tag = BER_OCTET_STRING; 307*99ebb4caSwyllys 308*99ebb4caSwyllys if ((taglen = ber_put_tag(ber, tag, 0)) == -1) 309*99ebb4caSwyllys return (-1); 310*99ebb4caSwyllys 311*99ebb4caSwyllys #ifdef STR_TRANSLATION 312*99ebb4caSwyllys if (len > 0 && (ber->ber_options & KMFBER_OPT_TRANSLATE_STRINGS) != 0 && 313*99ebb4caSwyllys ber->ber_encode_translate_proc != NULL) { 314*99ebb4caSwyllys if ((*(ber->ber_encode_translate_proc))(&str, &len, 0) 315*99ebb4caSwyllys != 0) { 316*99ebb4caSwyllys return (-1); 317*99ebb4caSwyllys } 318*99ebb4caSwyllys free_str = 1; 319*99ebb4caSwyllys } else { 320*99ebb4caSwyllys free_str = 0; 321*99ebb4caSwyllys } 322*99ebb4caSwyllys #endif /* STR_TRANSLATION */ 323*99ebb4caSwyllys 324*99ebb4caSwyllys /* 325*99ebb4caSwyllys * Note: below is a spot where we limit ber_write 326*99ebb4caSwyllys * to signed long (instead of unsigned long) 327*99ebb4caSwyllys */ 328*99ebb4caSwyllys ilen = (ber_int_t)len; 329*99ebb4caSwyllys if ((lenlen = kmfber_put_len(ber, ilen, 0)) == -1 || 330*99ebb4caSwyllys kmfber_write(ber, str, len, 0) != (ber_int_t)len) { 331*99ebb4caSwyllys rc = -1; 332*99ebb4caSwyllys } else { 333*99ebb4caSwyllys /* return length of tag + length + contents */ 334*99ebb4caSwyllys rc = taglen + lenlen + len; 335*99ebb4caSwyllys } 336*99ebb4caSwyllys 337*99ebb4caSwyllys #ifdef STR_TRANSLATION 338*99ebb4caSwyllys if (free_str) { 339*99ebb4caSwyllys free(str); 340*99ebb4caSwyllys } 341*99ebb4caSwyllys #endif /* STR_TRANSLATION */ 342*99ebb4caSwyllys 343*99ebb4caSwyllys return (rc); 344*99ebb4caSwyllys } 345*99ebb4caSwyllys 346*99ebb4caSwyllys static int 347*99ebb4caSwyllys kmfber_put_string(BerElement *ber, char *str, ber_tag_t tag) 348*99ebb4caSwyllys { 349*99ebb4caSwyllys return (kmfber_put_ostring(ber, str, (ber_len_t)strlen(str), tag)); 350*99ebb4caSwyllys } 351*99ebb4caSwyllys 352*99ebb4caSwyllys static int 353*99ebb4caSwyllys kmfber_put_bitstring(BerElement *ber, char *str, 354*99ebb4caSwyllys ber_len_t blen /* in bits */, ber_tag_t tag) 355*99ebb4caSwyllys { 356*99ebb4caSwyllys ber_int_t taglen, lenlen, len; 357*99ebb4caSwyllys unsigned char unusedbits; 358*99ebb4caSwyllys 359*99ebb4caSwyllys if (tag == KMFBER_DEFAULT) 360*99ebb4caSwyllys tag = BER_BIT_STRING; 361*99ebb4caSwyllys 362*99ebb4caSwyllys if ((taglen = ber_put_tag(ber, tag, 0)) == -1) 363*99ebb4caSwyllys return (-1); 364*99ebb4caSwyllys 365*99ebb4caSwyllys len = (blen + 7) / 8; 366*99ebb4caSwyllys unusedbits = (unsigned char) (len * 8 - blen); 367*99ebb4caSwyllys if ((lenlen = kmfber_put_len(ber, len + 1, 0)) == -1) 368*99ebb4caSwyllys return (-1); 369*99ebb4caSwyllys 370*99ebb4caSwyllys if (kmfber_write(ber, (char *)&unusedbits, 1, 0) != 1) 371*99ebb4caSwyllys return (-1); 372*99ebb4caSwyllys 373*99ebb4caSwyllys if (kmfber_write(ber, str, len, 0) != len) 374*99ebb4caSwyllys return (-1); 375*99ebb4caSwyllys 376*99ebb4caSwyllys /* return length of tag + length + unused bit count + contents */ 377*99ebb4caSwyllys return (taglen + 1 + lenlen + len); 378*99ebb4caSwyllys } 379*99ebb4caSwyllys 380*99ebb4caSwyllys static int 381*99ebb4caSwyllys kmfber_put_null(BerElement *ber, ber_tag_t tag) 382*99ebb4caSwyllys { 383*99ebb4caSwyllys int taglen; 384*99ebb4caSwyllys 385*99ebb4caSwyllys if (tag == KMFBER_DEFAULT) 386*99ebb4caSwyllys tag = BER_NULL; 387*99ebb4caSwyllys 388*99ebb4caSwyllys if ((taglen = ber_put_tag(ber, tag, 0)) == -1) 389*99ebb4caSwyllys return (-1); 390*99ebb4caSwyllys 391*99ebb4caSwyllys if (kmfber_put_len(ber, 0, 0) != 1) 392*99ebb4caSwyllys return (-1); 393*99ebb4caSwyllys 394*99ebb4caSwyllys return (taglen + 1); 395*99ebb4caSwyllys } 396*99ebb4caSwyllys 397*99ebb4caSwyllys static int 398*99ebb4caSwyllys kmfber_put_boolean(BerElement *ber, int boolval, ber_tag_t tag) 399*99ebb4caSwyllys { 400*99ebb4caSwyllys int taglen; 401*99ebb4caSwyllys unsigned char trueval = 0xff; 402*99ebb4caSwyllys unsigned char falseval = 0x00; 403*99ebb4caSwyllys 404*99ebb4caSwyllys if (tag == KMFBER_DEFAULT) 405*99ebb4caSwyllys tag = BER_BOOLEAN; 406*99ebb4caSwyllys 407*99ebb4caSwyllys if ((taglen = ber_put_tag(ber, tag, 0)) == -1) 408*99ebb4caSwyllys return (-1); 409*99ebb4caSwyllys 410*99ebb4caSwyllys if (kmfber_put_len(ber, 1, 0) != 1) 411*99ebb4caSwyllys return (-1); 412*99ebb4caSwyllys 413*99ebb4caSwyllys if (kmfber_write(ber, (char *)(boolval ? &trueval : &falseval), 1, 0) 414*99ebb4caSwyllys != 1) 415*99ebb4caSwyllys return (-1); 416*99ebb4caSwyllys 417*99ebb4caSwyllys return (taglen + 2); 418*99ebb4caSwyllys } 419*99ebb4caSwyllys 420*99ebb4caSwyllys #define FOUR_BYTE_LEN 5 421*99ebb4caSwyllys 422*99ebb4caSwyllys 423*99ebb4caSwyllys /* 424*99ebb4caSwyllys * The idea here is roughly this: we maintain a stack of these Seqorset 425*99ebb4caSwyllys * structures. This is pushed when we see the beginning of a new set or 426*99ebb4caSwyllys * sequence. It is popped when we see the end of a set or sequence. 427*99ebb4caSwyllys * Since we don't want to malloc and free these structures all the time, 428*99ebb4caSwyllys * we pre-allocate a small set of them within the ber element structure. 429*99ebb4caSwyllys * thus we need to spot when we've overflowed this stack and fall back to 430*99ebb4caSwyllys * malloc'ing instead. 431*99ebb4caSwyllys */ 432*99ebb4caSwyllys static int 433*99ebb4caSwyllys ber_start_seqorset(BerElement *ber, ber_tag_t tag) 434*99ebb4caSwyllys { 435*99ebb4caSwyllys Seqorset *new_sos; 436*99ebb4caSwyllys 437*99ebb4caSwyllys /* can we fit into the local stack ? */ 438*99ebb4caSwyllys if (ber->ber_sos_stack_posn < SOS_STACK_SIZE) { 439*99ebb4caSwyllys /* yes */ 440*99ebb4caSwyllys new_sos = &ber->ber_sos_stack[ber->ber_sos_stack_posn]; 441*99ebb4caSwyllys } else { 442*99ebb4caSwyllys /* no */ 443*99ebb4caSwyllys if ((new_sos = (Seqorset *)malloc(sizeof (Seqorset))) 444*99ebb4caSwyllys == NULLSEQORSET) { 445*99ebb4caSwyllys return (-1); 446*99ebb4caSwyllys } 447*99ebb4caSwyllys } 448*99ebb4caSwyllys ber->ber_sos_stack_posn++; 449*99ebb4caSwyllys 450*99ebb4caSwyllys if (ber->ber_sos == NULLSEQORSET) 451*99ebb4caSwyllys new_sos->sos_first = ber->ber_ptr; 452*99ebb4caSwyllys else 453*99ebb4caSwyllys new_sos->sos_first = ber->ber_sos->sos_ptr; 454*99ebb4caSwyllys 455*99ebb4caSwyllys /* Set aside room for a 4 byte length field */ 456*99ebb4caSwyllys new_sos->sos_ptr = new_sos->sos_first + kmfber_calc_taglen(tag) + 457*99ebb4caSwyllys FOUR_BYTE_LEN; 458*99ebb4caSwyllys new_sos->sos_tag = tag; 459*99ebb4caSwyllys 460*99ebb4caSwyllys new_sos->sos_next = ber->ber_sos; 461*99ebb4caSwyllys new_sos->sos_clen = 0; 462*99ebb4caSwyllys 463*99ebb4caSwyllys ber->ber_sos = new_sos; 464*99ebb4caSwyllys if (ber->ber_sos->sos_ptr > ber->ber_end) { 465*99ebb4caSwyllys (void) realloc(ber, ber->ber_sos->sos_ptr - ber->ber_end); 466*99ebb4caSwyllys } 467*99ebb4caSwyllys return (0); 468*99ebb4caSwyllys } 469*99ebb4caSwyllys 470*99ebb4caSwyllys static int 471*99ebb4caSwyllys kmfber_start_seq(BerElement *ber, ber_tag_t tag) 472*99ebb4caSwyllys { 473*99ebb4caSwyllys if (tag == KMFBER_DEFAULT) 474*99ebb4caSwyllys tag = BER_CONSTRUCTED_SEQUENCE; 475*99ebb4caSwyllys 476*99ebb4caSwyllys return (ber_start_seqorset(ber, tag)); 477*99ebb4caSwyllys } 478*99ebb4caSwyllys 479*99ebb4caSwyllys static int 480*99ebb4caSwyllys kmfber_start_set(BerElement *ber, ber_tag_t tag) 481*99ebb4caSwyllys { 482*99ebb4caSwyllys if (tag == KMFBER_DEFAULT) 483*99ebb4caSwyllys tag = BER_CONSTRUCTED_SET; 484*99ebb4caSwyllys 485*99ebb4caSwyllys return (ber_start_seqorset(ber, tag)); 486*99ebb4caSwyllys } 487*99ebb4caSwyllys 488*99ebb4caSwyllys static int 489*99ebb4caSwyllys ber_put_seqorset(BerElement *ber) 490*99ebb4caSwyllys { 491*99ebb4caSwyllys ber_int_t netlen, len, taglen, lenlen; 492*99ebb4caSwyllys unsigned char ltag = 0x80 + FOUR_BYTE_LEN - 1; 493*99ebb4caSwyllys Seqorset *next; 494*99ebb4caSwyllys Seqorset **sos = &ber->ber_sos; 495*99ebb4caSwyllys 496*99ebb4caSwyllys /* 497*99ebb4caSwyllys * If this is the toplevel sequence or set, we need to actually 498*99ebb4caSwyllys * write the stuff out. Otherwise, it's already been put in 499*99ebb4caSwyllys * the appropriate buffer and will be written when the toplevel 500*99ebb4caSwyllys * one is written. In this case all we need to do is update the 501*99ebb4caSwyllys * length and tag. 502*99ebb4caSwyllys */ 503*99ebb4caSwyllys 504*99ebb4caSwyllys len = (*sos)->sos_clen; 505*99ebb4caSwyllys netlen = (ber_len_t)htonl(len); 506*99ebb4caSwyllys 507*99ebb4caSwyllys if (ber->ber_options & KMFBER_OPT_USE_DER) { 508*99ebb4caSwyllys lenlen = kmfber_calc_lenlen(len); 509*99ebb4caSwyllys } else { 510*99ebb4caSwyllys lenlen = FOUR_BYTE_LEN; 511*99ebb4caSwyllys } 512*99ebb4caSwyllys 513*99ebb4caSwyllys if ((next = (*sos)->sos_next) == NULLSEQORSET) { 514*99ebb4caSwyllys /* write the tag */ 515*99ebb4caSwyllys if ((taglen = ber_put_tag(ber, (*sos)->sos_tag, 1)) == -1) 516*99ebb4caSwyllys return (-1); 517*99ebb4caSwyllys 518*99ebb4caSwyllys if (ber->ber_options & KMFBER_OPT_USE_DER) { 519*99ebb4caSwyllys /* Write the length in the minimum # of octets */ 520*99ebb4caSwyllys if (kmfber_put_len(ber, len, 1) == -1) 521*99ebb4caSwyllys return (-1); 522*99ebb4caSwyllys 523*99ebb4caSwyllys if (lenlen != FOUR_BYTE_LEN) { 524*99ebb4caSwyllys /* 525*99ebb4caSwyllys * We set aside FOUR_BYTE_LEN bytes for 526*99ebb4caSwyllys * the length field. Move the data if 527*99ebb4caSwyllys * we don't actually need that much 528*99ebb4caSwyllys */ 529*99ebb4caSwyllys (void) memmove((*sos)->sos_first + taglen + 530*99ebb4caSwyllys lenlen, (*sos)->sos_first + taglen + 531*99ebb4caSwyllys FOUR_BYTE_LEN, len); 532*99ebb4caSwyllys } 533*99ebb4caSwyllys } else { 534*99ebb4caSwyllys /* Fill FOUR_BYTE_LEN bytes for length field */ 535*99ebb4caSwyllys /* one byte of length length */ 536*99ebb4caSwyllys if (kmfber_write(ber, (char *)<ag, 1, 1) != 1) 537*99ebb4caSwyllys return (-1); 538*99ebb4caSwyllys 539*99ebb4caSwyllys /* the length itself */ 540*99ebb4caSwyllys if (kmfber_write(ber, 541*99ebb4caSwyllys (char *)&netlen + sizeof (ber_int_t) 542*99ebb4caSwyllys - (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1, 1) != 543*99ebb4caSwyllys FOUR_BYTE_LEN - 1) 544*99ebb4caSwyllys return (-1); 545*99ebb4caSwyllys } 546*99ebb4caSwyllys /* The ber_ptr is at the set/seq start - move it to the end */ 547*99ebb4caSwyllys ber->ber_ptr += len; 548*99ebb4caSwyllys } else { 549*99ebb4caSwyllys ber_tag_t ntag; 550*99ebb4caSwyllys 551*99ebb4caSwyllys /* the tag */ 552*99ebb4caSwyllys taglen = kmfber_calc_taglen((*sos)->sos_tag); 553*99ebb4caSwyllys ntag = htonl((*sos)->sos_tag); 554*99ebb4caSwyllys (void) memmove((*sos)->sos_first, (char *)&ntag + 555*99ebb4caSwyllys sizeof (ber_int_t) - taglen, taglen); 556*99ebb4caSwyllys 557*99ebb4caSwyllys if (ber->ber_options & KMFBER_OPT_USE_DER) { 558*99ebb4caSwyllys ltag = (lenlen == 1) ? (unsigned char)len : 559*99ebb4caSwyllys (unsigned char) (0x80 + (lenlen - 1)); 560*99ebb4caSwyllys } 561*99ebb4caSwyllys 562*99ebb4caSwyllys /* one byte of length length */ 563*99ebb4caSwyllys (void) memmove((*sos)->sos_first + 1, <ag, 1); 564*99ebb4caSwyllys 565*99ebb4caSwyllys if (ber->ber_options & KMFBER_OPT_USE_DER) { 566*99ebb4caSwyllys if (lenlen > 1) { 567*99ebb4caSwyllys /* Write the length itself */ 568*99ebb4caSwyllys (void) memmove((*sos)->sos_first + 2, 569*99ebb4caSwyllys (char *)&netlen + sizeof (ber_uint_t) - 570*99ebb4caSwyllys (lenlen - 1), 571*99ebb4caSwyllys lenlen - 1); 572*99ebb4caSwyllys } 573*99ebb4caSwyllys if (lenlen != FOUR_BYTE_LEN) { 574*99ebb4caSwyllys /* 575*99ebb4caSwyllys * We set aside FOUR_BYTE_LEN bytes for 576*99ebb4caSwyllys * the length field. Move the data if 577*99ebb4caSwyllys * we don't actually need that much 578*99ebb4caSwyllys */ 579*99ebb4caSwyllys (void) memmove((*sos)->sos_first + taglen + 580*99ebb4caSwyllys lenlen, (*sos)->sos_first + taglen + 581*99ebb4caSwyllys FOUR_BYTE_LEN, len); 582*99ebb4caSwyllys } 583*99ebb4caSwyllys } else { 584*99ebb4caSwyllys /* the length itself */ 585*99ebb4caSwyllys (void) memmove((*sos)->sos_first + taglen + 1, 586*99ebb4caSwyllys (char *) &netlen + sizeof (ber_int_t) - 587*99ebb4caSwyllys (FOUR_BYTE_LEN - 1), FOUR_BYTE_LEN - 1); 588*99ebb4caSwyllys } 589*99ebb4caSwyllys 590*99ebb4caSwyllys next->sos_clen += (taglen + lenlen + len); 591*99ebb4caSwyllys next->sos_ptr += (taglen + lenlen + len); 592*99ebb4caSwyllys } 593*99ebb4caSwyllys 594*99ebb4caSwyllys /* we're done with this seqorset, so free it up */ 595*99ebb4caSwyllys /* was this one from the local stack ? */ 596*99ebb4caSwyllys if (ber->ber_sos_stack_posn > SOS_STACK_SIZE) { 597*99ebb4caSwyllys free((char *)(*sos)); 598*99ebb4caSwyllys } 599*99ebb4caSwyllys ber->ber_sos_stack_posn--; 600*99ebb4caSwyllys *sos = next; 601*99ebb4caSwyllys 602*99ebb4caSwyllys return (taglen + lenlen + len); 603*99ebb4caSwyllys } 604*99ebb4caSwyllys 605*99ebb4caSwyllys /* VARARGS */ 606*99ebb4caSwyllys int 607*99ebb4caSwyllys kmfber_printf(BerElement *ber, const char *fmt, ...) 608*99ebb4caSwyllys { 609*99ebb4caSwyllys va_list ap; 610*99ebb4caSwyllys char *s, **ss; 611*99ebb4caSwyllys struct berval **bv, *oid; 612*99ebb4caSwyllys int rc, i, t; 613*99ebb4caSwyllys ber_int_t len; 614*99ebb4caSwyllys 615*99ebb4caSwyllys va_start(ap, fmt); 616*99ebb4caSwyllys 617*99ebb4caSwyllys #ifdef KMFBER_DEBUG 618*99ebb4caSwyllys if (lber_debug & 64) { 619*99ebb4caSwyllys char msg[80]; 620*99ebb4caSwyllys sprintf(msg, "kmfber_printf fmt (%s)\n", fmt); 621*99ebb4caSwyllys ber_err_print(msg); 622*99ebb4caSwyllys } 623*99ebb4caSwyllys #endif 624*99ebb4caSwyllys 625*99ebb4caSwyllys for (rc = 0; *fmt && rc != -1; fmt++) { 626*99ebb4caSwyllys switch (*fmt) { 627*99ebb4caSwyllys case 'b': /* boolean */ 628*99ebb4caSwyllys i = va_arg(ap, int); 629*99ebb4caSwyllys rc = kmfber_put_boolean(ber, i, ber->ber_tag); 630*99ebb4caSwyllys break; 631*99ebb4caSwyllys 632*99ebb4caSwyllys case 'i': /* int */ 633*99ebb4caSwyllys i = va_arg(ap, int); 634*99ebb4caSwyllys rc = ber_put_int(ber, (ber_int_t)i, ber->ber_tag); 635*99ebb4caSwyllys break; 636*99ebb4caSwyllys 637*99ebb4caSwyllys case 'D': /* Object ID */ 638*99ebb4caSwyllys if ((oid = va_arg(ap, struct berval *)) == NULL) 639*99ebb4caSwyllys break; 640*99ebb4caSwyllys rc = ber_put_oid(ber, oid, ber->ber_tag); 641*99ebb4caSwyllys break; 642*99ebb4caSwyllys case 'I': /* int */ 643*99ebb4caSwyllys s = va_arg(ap, char *); 644*99ebb4caSwyllys len = va_arg(ap, ber_int_t); 645*99ebb4caSwyllys rc = ber_put_big_int(ber, ber->ber_tag, s, len); 646*99ebb4caSwyllys break; 647*99ebb4caSwyllys 648*99ebb4caSwyllys case 'e': /* enumeration */ 649*99ebb4caSwyllys i = va_arg(ap, int); 650*99ebb4caSwyllys rc = kmfber_put_enum(ber, (ber_int_t)i, ber->ber_tag); 651*99ebb4caSwyllys break; 652*99ebb4caSwyllys 653*99ebb4caSwyllys case 'l': 654*99ebb4caSwyllys t = va_arg(ap, int); 655*99ebb4caSwyllys rc = kmfber_put_len(ber, t, 0); 656*99ebb4caSwyllys break; 657*99ebb4caSwyllys case 'n': /* null */ 658*99ebb4caSwyllys rc = kmfber_put_null(ber, ber->ber_tag); 659*99ebb4caSwyllys break; 660*99ebb4caSwyllys 661*99ebb4caSwyllys case 'o': /* octet string (non-null terminated) */ 662*99ebb4caSwyllys s = va_arg(ap, char *); 663*99ebb4caSwyllys len = va_arg(ap, int); 664*99ebb4caSwyllys rc = kmfber_put_ostring(ber, s, len, ber->ber_tag); 665*99ebb4caSwyllys break; 666*99ebb4caSwyllys 667*99ebb4caSwyllys case 's': /* string */ 668*99ebb4caSwyllys s = va_arg(ap, char *); 669*99ebb4caSwyllys rc = kmfber_put_string(ber, s, ber->ber_tag); 670*99ebb4caSwyllys break; 671*99ebb4caSwyllys 672*99ebb4caSwyllys case 'B': /* bit string */ 673*99ebb4caSwyllys s = va_arg(ap, char *); 674*99ebb4caSwyllys len = va_arg(ap, int); /* in bits */ 675*99ebb4caSwyllys rc = kmfber_put_bitstring(ber, s, len, ber->ber_tag); 676*99ebb4caSwyllys break; 677*99ebb4caSwyllys 678*99ebb4caSwyllys case 't': /* tag for the next element */ 679*99ebb4caSwyllys ber->ber_tag = va_arg(ap, ber_tag_t); 680*99ebb4caSwyllys ber->ber_usertag = 1; 681*99ebb4caSwyllys break; 682*99ebb4caSwyllys 683*99ebb4caSwyllys case 'T': /* Write an explicit tag, but don't change current */ 684*99ebb4caSwyllys t = va_arg(ap, int); 685*99ebb4caSwyllys rc = ber_put_tag(ber, t, 0); 686*99ebb4caSwyllys break; 687*99ebb4caSwyllys 688*99ebb4caSwyllys case 'v': /* vector of strings */ 689*99ebb4caSwyllys if ((ss = va_arg(ap, char **)) == NULL) 690*99ebb4caSwyllys break; 691*99ebb4caSwyllys for (i = 0; ss[i] != NULL; i++) { 692*99ebb4caSwyllys if ((rc = kmfber_put_string(ber, ss[i], 693*99ebb4caSwyllys ber->ber_tag)) == -1) 694*99ebb4caSwyllys break; 695*99ebb4caSwyllys } 696*99ebb4caSwyllys break; 697*99ebb4caSwyllys 698*99ebb4caSwyllys case 'V': /* sequences of strings + lengths */ 699*99ebb4caSwyllys if ((bv = va_arg(ap, struct berval **)) == NULL) 700*99ebb4caSwyllys break; 701*99ebb4caSwyllys for (i = 0; bv[i] != NULL; i++) { 702*99ebb4caSwyllys if ((rc = kmfber_put_ostring(ber, bv[i]->bv_val, 703*99ebb4caSwyllys bv[i]->bv_len, ber->ber_tag)) == -1) 704*99ebb4caSwyllys break; 705*99ebb4caSwyllys } 706*99ebb4caSwyllys break; 707*99ebb4caSwyllys 708*99ebb4caSwyllys case '{': /* begin sequence */ 709*99ebb4caSwyllys rc = kmfber_start_seq(ber, ber->ber_tag); 710*99ebb4caSwyllys break; 711*99ebb4caSwyllys 712*99ebb4caSwyllys case '}': /* end sequence */ 713*99ebb4caSwyllys rc = ber_put_seqorset(ber); 714*99ebb4caSwyllys break; 715*99ebb4caSwyllys 716*99ebb4caSwyllys case '[': /* begin set */ 717*99ebb4caSwyllys rc = kmfber_start_set(ber, ber->ber_tag); 718*99ebb4caSwyllys break; 719*99ebb4caSwyllys 720*99ebb4caSwyllys case ']': /* end set */ 721*99ebb4caSwyllys rc = ber_put_seqorset(ber); 722*99ebb4caSwyllys break; 723*99ebb4caSwyllys 724*99ebb4caSwyllys default: { 725*99ebb4caSwyllys #ifdef KMFBER_DEBUG 726*99ebb4caSwyllys char msg[80]; 727*99ebb4caSwyllys sprintf(msg, "unknown fmt %c\n", *fmt); 728*99ebb4caSwyllys ber_err_print(msg); 729*99ebb4caSwyllys #endif 730*99ebb4caSwyllys rc = -1; 731*99ebb4caSwyllys break; 732*99ebb4caSwyllys } 733*99ebb4caSwyllys } 734*99ebb4caSwyllys 735*99ebb4caSwyllys if (ber->ber_usertag == 0) 736*99ebb4caSwyllys ber->ber_tag = KMFBER_DEFAULT; 737*99ebb4caSwyllys else 738*99ebb4caSwyllys ber->ber_usertag = 0; 739*99ebb4caSwyllys } 740*99ebb4caSwyllys 741*99ebb4caSwyllys va_end(ap); 742*99ebb4caSwyllys 743*99ebb4caSwyllys return (rc); 744*99ebb4caSwyllys } 745