6889197 libkmf uses realloc incorrectly
authorWyllys Ingersoll <wyllys.ingersoll@sun.com>
Tue, 20 Oct 2009 09:39:20 -0700
changeset 10818 89e8703947be
parent 10817 7dfde45252f0
child 10819 d41e0e73a69e
6889197 libkmf uses realloc incorrectly 6889730 pktool fails to add EKUs to CSR and Cert requests 6889224 pktool incorrectly generates SAN
usr/src/cmd/cmd-crypto/pktool/common.c
usr/src/lib/libkmf/ber_der/common/encode.c
usr/src/lib/libkmf/ber_der/common/io.c
usr/src/lib/libkmf/ber_der/common/mapfile-vers
usr/src/lib/libkmf/ber_der/inc/ber_der.h
usr/src/lib/libkmf/libkmf/common/generalop.c
--- a/usr/src/cmd/cmd-crypto/pktool/common.c	Tue Oct 20 09:30:12 2009 -0700
+++ b/usr/src/cmd/cmd-crypto/pktool/common.c	Tue Oct 20 09:39:20 2009 -0700
@@ -1128,6 +1128,7 @@
 		}
 		free(ekus->ekulist);
 		free(ekus->critlist);
+		free(ekus);
 	}
 }
 
@@ -1166,6 +1167,10 @@
 	if (ekuliststr == NULL || strlen(ekuliststr) == 0)
 		return (0);
 
+	ekus = calloc(sizeof (EKU_LIST), 1);
+	if (ekus == NULL)
+		return (KMF_ERR_MEMORY);
+
 	/*
 	 * The list should be comma separated list of EKU Names.
 	 */
--- a/usr/src/lib/libkmf/ber_der/common/encode.c	Tue Oct 20 09:30:12 2009 -0700
+++ b/usr/src/lib/libkmf/ber_der/common/encode.c	Tue Oct 20 09:39:20 2009 -0700
@@ -30,12 +30,10 @@
  */
 
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 #include <netinet/in.h>
 #include <inttypes.h>
@@ -455,7 +453,9 @@
 
 	ber->ber_sos = new_sos;
 	if (ber->ber_sos->sos_ptr > ber->ber_end) {
-		(void) realloc(ber, ber->ber_sos->sos_ptr - ber->ber_end);
+		if (kmfber_realloc(ber, ber->ber_sos->sos_ptr -
+		    ber->ber_end) != 0)
+			return (-1);
 	}
 	return (0);
 }
--- a/usr/src/lib/libkmf/ber_der/common/io.c	Tue Oct 20 09:30:12 2009 -0700
+++ b/usr/src/lib/libkmf/ber_der/common/io.c	Tue Oct 20 09:39:20 2009 -0700
@@ -29,13 +29,10 @@
  * is provided ``as is'' without express or implied warranty.
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 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"
@@ -69,7 +66,7 @@
  * enlarge the ber buffer.
  * return 0 on success, -1 on error.
  */
-static int
+int
 kmfber_realloc(BerElement *ber, ber_len_t len)
 {
 	ber_uint_t	need, have, total;
@@ -77,6 +74,7 @@
 	Seqorset	*s;
 	size_t		off;
 	char		*oldbuf;
+	boolean_t	freeold = B_FALSE;
 
 	have_bytes = ber->ber_end - ber->ber_buf;
 	have = have_bytes / EXBUFSIZ;
@@ -96,16 +94,19 @@
 			/* transition to malloc'd buffer */
 			if ((ber->ber_buf = (char *)malloc(
 			    (size_t)total)) == NULL) {
+				free(oldbuf);
 				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);
+			freeold = B_TRUE;
 		} else {
 			if ((ber->ber_buf = (char *)realloc(
 			    ber->ber_buf, (size_t)total)) == NULL) {
 				return (-1);
 			}
+			freeold = B_FALSE; /* it was just realloced */
 		}
 	}
 
@@ -116,7 +117,6 @@
 	 * 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);
 
@@ -128,6 +128,8 @@
 			s->sos_ptr = ber->ber_buf + off;
 		}
 	}
+	if (freeold && oldbuf != NULL)
+		free(oldbuf);
 
 	return (0);
 }
@@ -162,11 +164,10 @@
 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);
+		if (freebuf &&
+		    !(ber->ber_flags & KMFBER_FLAG_NO_FREE_BUFFER))
+			free(ber->ber_buf);
+		free((char *)ber);
 	}
 }
 
@@ -351,7 +352,7 @@
 		/* 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) {
+		    (ber_slen_t)bv->bv_len) {
 			kmfber_free(ber, 1);
 			return (NULL);
 		}
@@ -379,7 +380,7 @@
 		/* 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) {
+		    (ber_slen_t)bv->bv_len) {
 			kmfber_free(ber, 1);
 			return (NULL);
 		}
--- a/usr/src/lib/libkmf/ber_der/common/mapfile-vers	Tue Oct 20 09:30:12 2009 -0700
+++ b/usr/src/lib/libkmf/ber_der/common/mapfile-vers	Tue Oct 20 09:39:20 2009 -0700
@@ -63,6 +63,7 @@
 	ExtractX509CertParts;
 	GetKeyFromSpki;
 	kmfber_alloc;
+	kmfber_bvfree;
 	kmfber_first_element;
 	kmfber_flatten;
 	kmfber_free;
@@ -70,6 +71,7 @@
 	kmfber_next_element;
 	kmfber_printf;
 	kmfber_read;
+	kmfber_realloc;
 	kmfber_scanf;
 	kmfber_write;
 	kmfder_alloc;
--- a/usr/src/lib/libkmf/ber_der/inc/ber_der.h	Tue Oct 20 09:30:12 2009 -0700
+++ b/usr/src/lib/libkmf/ber_der/inc/ber_der.h	Tue Oct 20 09:39:20 2009 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -22,8 +22,6 @@
  * Reserved.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * This is the header file for some Basic Encoding Rules and Distinguished
  * Encoding Rules (BER/DER) routines.
@@ -49,6 +47,7 @@
 #define	BER_IA5STRING			22
 #define	BER_UTCTIME			23
 #define	BER_GENTIME			24
+#define	BER_GENERALSTRING		27
 #define	BER_UNIVERSAL_STRING		28
 #define	BER_BMP_STRING			30
 
@@ -114,6 +113,7 @@
  */
 extern int kmfber_printf(BerElement *, const char *, ...);
 extern int kmfber_flatten(BerElement *, struct berval **);
+extern int kmfber_realloc(BerElement *, ber_len_t);
 
 /*
  * miscellaneous public routines
--- a/usr/src/lib/libkmf/libkmf/common/generalop.c	Tue Oct 20 09:30:12 2009 -0700
+++ b/usr/src/lib/libkmf/libkmf/common/generalop.c	Tue Oct 20 09:39:20 2009 -0700
@@ -1699,6 +1699,7 @@
 {
 	KMF_RETURN rv = KMF_OK;
 	char *at, *realm;
+	char *slash, *inst = NULL;
 	BerElement *asn1 = NULL;
 	BerValue *extdata = NULL;
 
@@ -1706,42 +1707,149 @@
 	if (at == NULL)
 		return (KMF_ERR_ENCODING);
 
-	realm = at+1;
+	realm = at + 1;
 	*at = 0;
 
-	if ((asn1 = kmfder_alloc()) == NULL)
-		return (KMF_ERR_MEMORY);
-
-	if (kmfber_printf(asn1, "{D{", &KMFOID_PKINIT_san) == -1)
+	/*
+	 * KRB5PrincipalName ::= SEQUENCE {
+	 *	realm		[0] Realm,
+	 *	principalName	[1] PrincipalName
+	 * }
+	 *
+	 * KerberosString	::= GeneralString (IA5String)
+	 * Realm	::= KerberosString
+	 * PrincipalName	::= SEQUENCE {
+	 *	name-type	[0] Int32,
+	 *	name-string	[1] SEQUENCE OF KerberosString
+	 * }
+	 */
+
+	/*
+	 * Construct the "principalName" first.
+	 *
+	 * The name may be split with a "/" to indicate a new instance.
+	 * This must be separated in the ASN.1
+	 */
+	slash = strchr(name, '/');
+	if (slash != NULL) {
+		inst = name;
+		name = slash + 1;
+		*slash = 0;
+	}
+	if ((asn1 = kmfder_alloc()) == NULL) {
+		rv = KMF_ERR_MEMORY;
 		goto cleanup;
-
-	if (kmfber_printf(asn1, "l", strlen(realm)) == -1)
-		goto cleanup;
-	if (kmfber_write(asn1, realm, strlen(realm), 0) != strlen(realm))
+	}
+	if (kmfber_printf(asn1, "{Tli", 0xa0, 3, 0x01) == -1)
 		goto cleanup;
-	if (kmfber_printf(asn1, "l", strlen(name)) == -1)
-		goto cleanup;
-	if (kmfber_write(asn1, name, strlen(name), 0) != strlen(name))
-		goto cleanup;
+
+	if (inst != NULL) {
+		if (kmfber_printf(asn1, "Tl{Tl", 0xA1,
+		    strlen(inst) + strlen(name) + 6,
+		    BER_GENERALSTRING, strlen(inst)) == -1)
+			goto cleanup;
+		if (kmfber_write(asn1, inst, strlen(inst), 0) != strlen(inst))
+			goto cleanup;
+		if (kmfber_printf(asn1, "Tl", BER_GENERALSTRING,
+		    strlen(name)) == -1)
+			goto cleanup;
+		if (kmfber_write(asn1, name, strlen(name), 0) != strlen(name))
+			goto cleanup;
+	} else {
+		if (kmfber_printf(asn1, "Tl{Tl", 0xA1,
+		    strlen(name) + 4, BER_GENERALSTRING, strlen(name)) == -1)
+			goto cleanup;
+		if (kmfber_write(asn1, name, strlen(name), 0) != strlen(name))
+			goto cleanup;
+	}
+
 	if (kmfber_printf(asn1, "}}") == -1)
 		goto cleanup;
-
 	if (kmfber_flatten(asn1, &extdata) == -1) {
 		rv = KMF_ERR_ENCODING;
 		goto cleanup;
 	}
+	kmfber_free(asn1, 1);
+	asn1 = NULL;
+
+	/* Next construct the KRB5PrincipalNameSeq */
+	if ((asn1 = kmfder_alloc()) == NULL) {
+		kmfber_bvfree(extdata);
+		rv = KMF_ERR_MEMORY;
+		goto cleanup;
+	}
+	if (kmfber_printf(asn1, "{TlTl", 0xA0, strlen(realm) + 2,
+	    BER_GENERALSTRING, strlen(realm)) == -1)
+		goto cleanup;
+	if (kmfber_write(asn1, realm, strlen(realm), 0) != strlen(realm))
+		goto cleanup;
+	if (kmfber_printf(asn1, "Tl", 0xA1, extdata->bv_len) == -1)
+		goto cleanup;
+	if (kmfber_write(asn1, extdata->bv_val,
+	    extdata->bv_len, 0) != extdata->bv_len)
+		goto cleanup;
+	if (kmfber_printf(asn1, "}") == -1)
+		goto cleanup;
+	kmfber_bvfree(extdata);
+	extdata = NULL;
+	if (kmfber_flatten(asn1, &extdata) == -1) {
+		rv = KMF_ERR_ENCODING;
+		goto cleanup;
+	}
+	kmfber_free(asn1, 1);
+	asn1 = NULL;
+
+	/*
+	 * GeneralName ::= CHOICE {
+	 *	otherName	[0]	OtherName,
+	 *	...
+	 * }
+	 *
+	 * OtherName ::= SEQUENCE {
+	 *	type-id	OBJECT IDENTIFIER,
+	 *	value	[0] EXPLICIT ANY DEFINED BY type-id
+	 * }
+	 */
+
+	/* Now construct the SAN: OID + typed data. */
+	if ((asn1 = kmfder_alloc()) == NULL) {
+		kmfber_bvfree(extdata);
+		rv = KMF_ERR_MEMORY;
+		goto cleanup;
+	}
+	if (kmfber_printf(asn1, "D", &KMFOID_PKINIT_san) == -1)
+		goto cleanup;
+	if (kmfber_printf(asn1, "Tl", 0xA0, extdata->bv_len) == -1)
+		goto cleanup;
+	if (kmfber_write(asn1, extdata->bv_val,
+	    extdata->bv_len, 0) != extdata->bv_len)
+		goto cleanup;
+	kmfber_bvfree(extdata);
+	extdata = NULL;
+	if (kmfber_flatten(asn1, &extdata) == -1) {
+		rv = KMF_ERR_ENCODING;
+		goto cleanup;
+	}
+	kmfber_free(asn1, 1);
+	asn1 = NULL;
 
 	derdata->Data = (uchar_t *)extdata->bv_val;
+	extdata->bv_val = NULL; /* clear it so it is not freed later */
 	derdata->Length = extdata->bv_len;
 
-	free(extdata);
 cleanup:
 	if (asn1 != NULL)
 		kmfber_free(asn1, 1);
 
+	if (extdata != NULL)
+		kmfber_bvfree(extdata);
+
 	if (*at == 0)
 		*at = '@';
 
+	if (inst != NULL)
+		*slash = '/';
+
 	return (rv);
 }
 
@@ -1864,14 +1972,14 @@
 				ret = DerEncodeName(&dnname, encodedname);
 			}
 			(void) kmf_free_dn(&dnname);
-			tagval = (0xA0 | nametype);
+			tagval = (0x80 | nametype);
 			break;
 		case GENNAME_KRB5PRINC:
-			tagval = (0x80 | GENNAME_OTHERNAME);
+			tagval = (0xA0 | GENNAME_OTHERNAME);
 			ret = encode_krb5(namedata, encodedname);
 			break;
 		case GENNAME_SCLOGON_UPN:
-			tagval = (0x80 | GENNAME_OTHERNAME);
+			tagval = (0xA0 | GENNAME_OTHERNAME);
 			ret = encode_sclogon(namedata, encodedname);
 			break;
 		default: