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