summaryrefslogtreecommitdiff
path: root/usr/src/lib/libkmf/ber_der/common/io.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libkmf/ber_der/common/io.c')
-rw-r--r--usr/src/lib/libkmf/ber_der/common/io.c419
1 files changed, 419 insertions, 0 deletions
diff --git a/usr/src/lib/libkmf/ber_der/common/io.c b/usr/src/lib/libkmf/ber_der/common/io.c
new file mode 100644
index 0000000000..415bbba9c4
--- /dev/null
+++ b/usr/src/lib/libkmf/ber_der/common/io.c
@@ -0,0 +1,419 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.0 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+
+/*
+ * Copyright (c) 1990 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+#include <stdlib.h>
+#include <ber_der.h>
+#include "kmfber_int.h"
+
+#define EXBUFSIZ 1024
+
+/*
+ * Note: kmfber_read() only uses the ber_end and ber_ptr elements of ber.
+ * Functions like kmfber_get_tag(), kmfber_skip_tag, and kmfber_peek_tag()
+ * rely on that fact, so if this code is changed to use any additional
+ * elements of the ber structure, those functions will need to be changed
+ * as well.
+ */
+ber_int_t
+kmfber_read(BerElement *ber, char *buf, ber_len_t len)
+{
+ size_t actuallen;
+ size_t nleft;
+
+ nleft = ber->ber_end - ber->ber_ptr;
+ actuallen = nleft < len ? nleft : len;
+
+ (void) memmove(buf, ber->ber_ptr, (size_t)actuallen);
+
+ ber->ber_ptr += actuallen;
+
+ return ((ber_int_t)actuallen);
+}
+
+/*
+ * enlarge the ber buffer.
+ * return 0 on success, -1 on error.
+ */
+static int
+kmfber_realloc(BerElement *ber, ber_len_t len)
+{
+ ber_uint_t need, have, total;
+ size_t have_bytes;
+ Seqorset *s;
+ size_t off;
+ char *oldbuf;
+
+ have_bytes = ber->ber_end - ber->ber_buf;
+ have = have_bytes / EXBUFSIZ;
+ need = (len < EXBUFSIZ ? 1 : (len + (EXBUFSIZ - 1)) / EXBUFSIZ);
+ total = have * EXBUFSIZ + need * EXBUFSIZ;
+
+ oldbuf = ber->ber_buf;
+
+ if (ber->ber_buf == NULL) {
+ if ((ber->ber_buf = (char *)malloc((size_t)total))
+ == NULL) {
+ return (-1);
+ }
+ ber->ber_flags &= ~KMFBER_FLAG_NO_FREE_BUFFER;
+ } else {
+ if (ber->ber_flags & KMFBER_FLAG_NO_FREE_BUFFER) {
+ /* transition to malloc'd buffer */
+ if ((ber->ber_buf = (char *)malloc(
+ (size_t)total)) == NULL) {
+ return (-1);
+ }
+ ber->ber_flags &= ~KMFBER_FLAG_NO_FREE_BUFFER;
+ /* copy existing data into new malloc'd buffer */
+ (void) memmove(ber->ber_buf, oldbuf, have_bytes);
+ } else {
+ if ((ber->ber_buf = (char *)realloc(
+ ber->ber_buf, (size_t)total)) == NULL) {
+ return (-1);
+ }
+ }
+ }
+
+ ber->ber_end = ber->ber_buf + total;
+
+ /*
+ * If the stinking thing was moved, we need to go through and
+ * reset all the sos and ber pointers. Offsets would've been
+ * a better idea... oh well.
+ */
+
+ if (ber->ber_buf != oldbuf) {
+ ber->ber_ptr = ber->ber_buf + (ber->ber_ptr - oldbuf);
+
+ for (s = ber->ber_sos; s != NULLSEQORSET; s = s->sos_next) {
+ off = s->sos_first - oldbuf;
+ s->sos_first = ber->ber_buf + off;
+
+ off = s->sos_ptr - oldbuf;
+ s->sos_ptr = ber->ber_buf + off;
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * returns "len" on success and -1 on failure.
+ */
+ber_int_t
+kmfber_write(BerElement *ber, char *buf, ber_len_t len, int nosos)
+{
+ if (nosos || ber->ber_sos == NULL) {
+ if (ber->ber_ptr + len > ber->ber_end) {
+ if (kmfber_realloc(ber, len) != 0)
+ return (-1);
+ }
+ (void) memmove(ber->ber_ptr, buf, (size_t)len);
+ ber->ber_ptr += len;
+ return (len);
+ } else {
+ if (ber->ber_sos->sos_ptr + len > ber->ber_end) {
+ if (kmfber_realloc(ber, len) != 0)
+ return (-1);
+ }
+ (void) memmove(ber->ber_sos->sos_ptr, buf, (size_t)len);
+ ber->ber_sos->sos_ptr += len;
+ ber->ber_sos->sos_clen += len;
+ return (len);
+ }
+}
+
+void
+kmfber_free(BerElement *ber, int freebuf)
+{
+ if (ber != NULL) {
+ if (freebuf &&
+ !(ber->ber_flags & KMFBER_FLAG_NO_FREE_BUFFER)) {
+ free(ber->ber_buf);
+ }
+ free((char *)ber);
+ }
+}
+
+/* we pre-allocate a buffer to save the extra malloc later */
+BerElement *
+kmfber_alloc_t(int options)
+{
+ BerElement *ber;
+
+ if ((ber = (BerElement*)calloc(1,
+ sizeof (struct berelement) + EXBUFSIZ)) == NULL) {
+ return (NULL);
+ }
+
+ ber->ber_tag = KMFBER_DEFAULT;
+ ber->ber_options = options;
+ ber->ber_buf = (char *)ber + sizeof (struct berelement);
+ ber->ber_ptr = ber->ber_buf;
+ ber->ber_end = ber->ber_buf + EXBUFSIZ;
+ ber->ber_flags = KMFBER_FLAG_NO_FREE_BUFFER;
+
+ return (ber);
+}
+
+
+BerElement *
+kmfber_alloc()
+{
+ return (kmfber_alloc_t(0));
+}
+
+BerElement *
+kmfder_alloc()
+{
+ return (kmfber_alloc_t(KMFBER_OPT_USE_DER));
+}
+
+BerElement *
+kmfber_dup(BerElement *ber)
+{
+ BerElement *new;
+
+ if ((new = kmfber_alloc()) == NULL)
+ return (NULL);
+
+ *new = *ber;
+
+ return (new);
+}
+
+
+void
+ber_init_w_nullchar(BerElement *ber, int options)
+{
+ (void) memset((char *)ber, '\0', sizeof (struct berelement));
+ ber->ber_tag = KMFBER_DEFAULT;
+
+ ber->ber_options = options;
+}
+
+
+void
+kmfber_reset(BerElement *ber, int was_writing)
+{
+ if (was_writing) {
+ ber->ber_end = ber->ber_ptr;
+ ber->ber_ptr = ber->ber_buf;
+ } else {
+ ber->ber_ptr = ber->ber_end;
+ }
+
+ ber->ber_rwptr = NULL;
+}
+
+
+#ifdef KMFBER_DEBUG
+
+void
+ber_dump(BerElement *ber, int inout)
+{
+ char msg[128];
+ sprintf(msg, "ber_dump: buf 0x%lx, ptr 0x%lx, rwptr 0x%lx, end 0x%lx\n",
+ ber->ber_buf, ber->ber_ptr, ber->ber_rwptr, ber->ber_end);
+ ber_err_print(msg);
+ if (inout == 1) {
+ sprintf(msg, " current len %ld, contents:\n",
+ ber->ber_end - ber->ber_ptr);
+ ber_err_print(msg);
+ lber_bprint(ber->ber_ptr, ber->ber_end - ber->ber_ptr);
+ } else {
+ sprintf(msg, " current len %ld, contents:\n",
+ ber->ber_ptr - ber->ber_buf);
+ ber_err_print(msg);
+ lber_bprint(ber->ber_buf, ber->ber_ptr - ber->ber_buf);
+ }
+}
+
+void
+ber_sos_dump(Seqorset *sos)
+{
+ char msg[80];
+ ber_err_print("*** sos dump ***\n");
+ while (sos != NULLSEQORSET) {
+ sprintf(msg, "ber_sos_dump: clen %ld first 0x%lx ptr 0x%lx\n",
+ sos->sos_clen, sos->sos_first, sos->sos_ptr);
+ ber_err_print(msg);
+ sprintf(msg, " current len %ld contents:\n",
+ sos->sos_ptr - sos->sos_first);
+ ber_err_print(msg);
+ lber_bprint(sos->sos_first, sos->sos_ptr - sos->sos_first);
+
+ sos = sos->sos_next;
+ }
+ ber_err_print("*** end dump ***\n");
+}
+
+#endif
+
+/* new dboreham code below: */
+struct byte_buffer {
+ unsigned char *p;
+ int offset;
+ int length;
+};
+typedef struct byte_buffer byte_buffer;
+
+/*
+ * The kmfber_flatten routine allocates a struct berval whose contents
+ * are a BER encoding taken from the ber argument. The bvPtr pointer
+ * points to the returned berval, which must be freed using
+ * kmfber_bvfree(). This routine returns 0 on success and -1 on error.
+ * The use of kmfber_flatten on a BerElement in which all '{' and '}'
+ * format modifiers have not been properly matched can result in a
+ * berval whose contents are not a valid BER encoding.
+ * Note that the ber_ptr is not modified.
+ */
+int
+kmfber_flatten(BerElement *ber, struct berval **bvPtr)
+{
+ struct berval *new;
+ ber_len_t len;
+
+ /* allocate a struct berval */
+ new = (struct berval *)malloc((size_t)(sizeof (struct berval)));
+ if (new == NULL) {
+ return (-1);
+ }
+ (void) memset(new, 0, sizeof (struct berval));
+
+ /*
+ * Copy everything from the BerElement's ber_buf to ber_ptr
+ * into the berval structure.
+ */
+ if (ber == NULL) {
+ new->bv_val = NULL;
+ new->bv_len = 0;
+ } else {
+ len = ber->ber_ptr - ber->ber_buf;
+ new->bv_val = (char *)malloc((size_t)(len + 1));
+ if (new->bv_val == NULL) {
+ kmfber_bvfree(new);
+ return (-1);
+ }
+ (void) memmove(new->bv_val, ber->ber_buf, (size_t)len);
+ new->bv_val[len] = '\0';
+ new->bv_len = len;
+ }
+
+ /* set bvPtr pointer to point to the returned berval */
+ *bvPtr = new;
+
+ return (0);
+}
+
+BerElement *
+kmfder_init(const struct berval *bv)
+{
+ BerElement *ber;
+
+ /* construct BerElement */
+ if ((ber = kmfber_alloc_t(KMFBER_OPT_USE_DER)) != NULL) {
+ /* copy data from the bv argument into BerElement */
+ /* XXXmcs: had to cast unsigned long bv_len to long */
+ if ((kmfber_write(ber, bv->bv_val, bv->bv_len, 0)) !=
+ (ber_slen_t)bv->bv_len) {
+ kmfber_free(ber, 1);
+ return (NULL);
+ }
+ }
+ /*
+ * reset ber_ptr back to the beginning of buffer so that this new
+ * and initialized ber element can be READ
+ */
+ kmfber_reset(ber, 1);
+
+ /*
+ * return a ptr to a new BerElement containing a copy of the data
+ * in the bv argument or a null pointer on error
+ */
+ return (ber);
+}
+
+BerElement *
+kmfber_init(const struct berval *bv)
+{
+ BerElement *ber;
+
+ /* construct BerElement */
+ if ((ber = kmfber_alloc_t(0)) != NULL) {
+ /* copy data from the bv argument into BerElement */
+ /* XXXmcs: had to cast unsigned long bv_len to long */
+ if ((kmfber_write(ber, bv->bv_val, bv->bv_len, 0)) !=
+ (ber_slen_t)bv->bv_len) {
+ kmfber_free(ber, 1);
+ return (NULL);
+ }
+ }
+ /*
+ * reset ber_ptr back to the beginning of buffer so that this new
+ * and initialized ber element can be READ
+ */
+ kmfber_reset(ber, 1);
+
+ /*
+ * return a ptr to a new BerElement containing a copy of the data
+ * in the bv argument or a null pointer on error
+ */
+ return (ber);
+}