PageRenderTime 45ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/usr/src/lib/libkmf/ber_der/common/encode.c

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