xref: /onnv-gate/usr/src/lib/libkmf/libkmf/common/rdn_parser.c (revision 3089:8ddeb2ace8aa)
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  * The contents of this file are subject to the Mozilla Public
23*3089Swyllys  * License Version 1.1 (the "License"); you may not use this file
24*3089Swyllys  * except in compliance with the License. You may obtain a copy of
25*3089Swyllys  * the License at http://www.mozilla.org/MPL/
26*3089Swyllys  *
27*3089Swyllys  * Software distributed under the License is distributed on an "AS
28*3089Swyllys  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
29*3089Swyllys  * implied. See the License for the specific language governing
30*3089Swyllys  * rights and limitations under the License.
31*3089Swyllys  *
32*3089Swyllys  * The Original Code is the Netscape security libraries.
33*3089Swyllys  *
34*3089Swyllys  * The Initial Developer of the Original Code is Netscape
35*3089Swyllys  * Communications Corporation.  Portions created by Netscape are
36*3089Swyllys  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
37*3089Swyllys  * Rights Reserved.
38*3089Swyllys  *
39*3089Swyllys  * Contributor(s):
40*3089Swyllys  *
41*3089Swyllys  * Alternatively, the contents of this file may be used under the
42*3089Swyllys  * terms of the GNU General Public License Version 2 or later (the
43*3089Swyllys  * "GPL"), in which case the provisions of the GPL are applicable
44*3089Swyllys  * instead of those above.  If you wish to allow use of your
45*3089Swyllys  * version of this file only under the terms of the GPL and not to
46*3089Swyllys  * allow others to use your version of this file under the MPL,
47*3089Swyllys  * indicate your decision by deleting the provisions above and
48*3089Swyllys  * replace them with the notice and other provisions required by
49*3089Swyllys  * the GPL.  If you do not delete the provisions above, a recipient
50*3089Swyllys  * may use your version of this file under either the MPL or the
51*3089Swyllys  * GPL.
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  * File: rdn_parser.c
58*3089Swyllys  */
59*3089Swyllys 
60*3089Swyllys #pragma ident	"%Z%%M%	%I%	%E% SMI"
61*3089Swyllys 
62*3089Swyllys 
63*3089Swyllys #include <strings.h>
64*3089Swyllys #include <stdlib.h>
65*3089Swyllys #include <kmfapi.h>
66*3089Swyllys #include <kmfapiP.h>
67*3089Swyllys #include <ber_der.h>
68*3089Swyllys #include <rdn_parser.h>
69*3089Swyllys #include <stdio.h>
70*3089Swyllys #include <values.h>
71*3089Swyllys 
72*3089Swyllys /*
73*3089Swyllys  * The order here is important.  The OIDs are arranged in order of
74*3089Swyllys  * significance.  The CN is the most specific value, the C (country)
75*3089Swyllys  * is less specific, etc.  Add to this list with care.
76*3089Swyllys  */
77*3089Swyllys static const struct NameToKind name2kinds[] = {
78*3089Swyllys { "CN",		OID_AVA_COMMON_NAME,	(KMF_OID *)&KMFOID_CommonName},
79*3089Swyllys { "SN",		OID_AVA_SURNAME,	(KMF_OID *)&KMFOID_Surname},
80*3089Swyllys { "GN",		OID_AVA_GIVEN_NAME,	(KMF_OID *)&KMFOID_GivenName},
81*3089Swyllys { "emailAddress", OID_PKCS9_EMAIL_ADDRESS, (KMF_OID *)&KMFOID_EmailAddress},
82*3089Swyllys { "E",		OID_PKCS9_EMAIL_ADDRESS, (KMF_OID *)&KMFOID_EmailAddress},
83*3089Swyllys { "MAIL",	OID_RFC1274_MAIL,	(KMF_OID *)&KMFOID_RFC822mailbox},
84*3089Swyllys { "STREET",	OID_AVA_STREET_ADDRESS, (KMF_OID *)&KMFOID_StreetAddress},
85*3089Swyllys { "UID",	OID_RFC1274_UID,	(KMF_OID *)&KMFOID_userid},
86*3089Swyllys { "OU",		OID_AVA_ORGANIZATIONAL_UNIT_NAME,
87*3089Swyllys 			(KMF_OID *)&KMFOID_OrganizationalUnitName},
88*3089Swyllys { "O",		OID_AVA_ORGANIZATION_NAME, (KMF_OID *)&KMFOID_OrganizationName},
89*3089Swyllys { "L",		OID_AVA_LOCALITY,	(KMF_OID *)&KMFOID_LocalityName},
90*3089Swyllys { "ST",		OID_AVA_STATE_OR_PROVINCE,
91*3089Swyllys 	(KMF_OID *)&KMFOID_StateProvinceName},
92*3089Swyllys { "C",		OID_AVA_COUNTRY_NAME,	(KMF_OID *)&KMFOID_CountryName},
93*3089Swyllys { "DC",		OID_AVA_DC,		(KMF_OID *)&KMFOID_domainComponent},
94*3089Swyllys { 0,		OID_UNKNOWN, NULL}
95*3089Swyllys };
96*3089Swyllys 
97*3089Swyllys static KMF_BOOL
98*3089Swyllys IsPrintable(unsigned char *data, unsigned len)
99*3089Swyllys {
100*3089Swyllys 	unsigned char ch, *end;
101*3089Swyllys 
102*3089Swyllys 	end = data + len;
103*3089Swyllys 	while (data < end) {
104*3089Swyllys 		ch = *data++;
105*3089Swyllys 		if (!IS_PRINTABLE(ch)) {
106*3089Swyllys 			return (B_FALSE);
107*3089Swyllys 		}
108*3089Swyllys 	}
109*3089Swyllys 	return (B_TRUE);
110*3089Swyllys }
111*3089Swyllys 
112*3089Swyllys static KMF_BOOL
113*3089Swyllys Is7Bit(unsigned char *data, unsigned len)
114*3089Swyllys {
115*3089Swyllys 	unsigned char ch, *end;
116*3089Swyllys 
117*3089Swyllys 	end = data + len;
118*3089Swyllys 	while (data < end) {
119*3089Swyllys 		ch = *data++;
120*3089Swyllys 		if ((ch & 0x80)) {
121*3089Swyllys 			return (B_FALSE);
122*3089Swyllys 		}
123*3089Swyllys 	}
124*3089Swyllys 	return (B_TRUE);
125*3089Swyllys }
126*3089Swyllys 
127*3089Swyllys static void
128*3089Swyllys skipSpace(char **pbp, char *endptr)
129*3089Swyllys {
130*3089Swyllys 	char *bp = *pbp;
131*3089Swyllys 	while (bp < endptr && OPTIONAL_SPACE(*bp)) {
132*3089Swyllys 		bp++;
133*3089Swyllys 	}
134*3089Swyllys 	*pbp = bp;
135*3089Swyllys }
136*3089Swyllys 
137*3089Swyllys static KMF_RETURN
138*3089Swyllys scanTag(char **pbp, char *endptr, char *tagBuf, int tagBufSize)
139*3089Swyllys {
140*3089Swyllys 	char *bp, *tagBufp;
141*3089Swyllys 	int taglen;
142*3089Swyllys 
143*3089Swyllys 	if (tagBufSize <= 0)
144*3089Swyllys 		return (KMF_ERR_INTERNAL);
145*3089Swyllys 
146*3089Swyllys 	/* skip optional leading space */
147*3089Swyllys 	skipSpace(pbp, endptr);
148*3089Swyllys 	if (*pbp == endptr) {
149*3089Swyllys 		/* nothing left */
150*3089Swyllys 		return (KMF_ERR_RDN_PARSER);
151*3089Swyllys 	}
152*3089Swyllys 
153*3089Swyllys 	/* fill tagBuf */
154*3089Swyllys 	taglen = 0;
155*3089Swyllys 	bp = *pbp;
156*3089Swyllys 	tagBufp = tagBuf;
157*3089Swyllys 	while (bp < endptr && !OPTIONAL_SPACE(*bp) && (*bp != C_EQUAL)) {
158*3089Swyllys 		if (++taglen >= tagBufSize) {
159*3089Swyllys 			*pbp = bp;
160*3089Swyllys 			return (KMF_ERR_RDN_PARSER);
161*3089Swyllys 		}
162*3089Swyllys 		*tagBufp++ = *bp++;
163*3089Swyllys 	}
164*3089Swyllys 	/* null-terminate tagBuf -- guaranteed at least one space left */
165*3089Swyllys 	*tagBufp++ = 0;
166*3089Swyllys 	*pbp = bp;
167*3089Swyllys 
168*3089Swyllys 	/*
169*3089Swyllys 	 * skip trailing spaces till we hit something - should be
170*3089Swyllys 	 * an equal sign
171*3089Swyllys 	 */
172*3089Swyllys 	skipSpace(pbp, endptr);
173*3089Swyllys 	if (*pbp == endptr) {
174*3089Swyllys 		/* nothing left */
175*3089Swyllys 		return (KMF_ERR_RDN_PARSER);
176*3089Swyllys 	}
177*3089Swyllys 	if (**pbp != C_EQUAL) {
178*3089Swyllys 		/* should be an equal sign */
179*3089Swyllys 		return (KMF_ERR_RDN_PARSER);
180*3089Swyllys 	}
181*3089Swyllys 	/* skip over the equal sign */
182*3089Swyllys 	(*pbp)++;
183*3089Swyllys 
184*3089Swyllys 	return (KMF_OK);
185*3089Swyllys }
186*3089Swyllys 
187*3089Swyllys static KMF_RETURN
188*3089Swyllys scanVal(char **pbp, char *endptr, char *valBuf, int valBufSize)
189*3089Swyllys {
190*3089Swyllys 	char *bp, *valBufp;
191*3089Swyllys 	int vallen;
192*3089Swyllys 	boolean_t isQuoted;
193*3089Swyllys 
194*3089Swyllys 	if (valBufSize <= 0)
195*3089Swyllys 		return (KMF_ERR_INTERNAL);
196*3089Swyllys 
197*3089Swyllys 	/* skip optional leading space */
198*3089Swyllys 	skipSpace(pbp, endptr);
199*3089Swyllys 	if (*pbp == endptr) {
200*3089Swyllys 		/* nothing left */
201*3089Swyllys 		return (KMF_ERR_RDN_PARSER);
202*3089Swyllys 	}
203*3089Swyllys 
204*3089Swyllys 	bp = *pbp;
205*3089Swyllys 
206*3089Swyllys 	/* quoted? */
207*3089Swyllys 	if (*bp == C_DOUBLE_QUOTE) {
208*3089Swyllys 		isQuoted = B_TRUE;
209*3089Swyllys 		/* skip over it */
210*3089Swyllys 		bp++;
211*3089Swyllys 	} else {
212*3089Swyllys 		isQuoted = B_FALSE;
213*3089Swyllys 	}
214*3089Swyllys 
215*3089Swyllys 	valBufp = valBuf;
216*3089Swyllys 	vallen = 0;
217*3089Swyllys 	while (bp < endptr) {
218*3089Swyllys 		char c = *bp;
219*3089Swyllys 		if (c == C_BACKSLASH) {
220*3089Swyllys 			/* escape character */
221*3089Swyllys 			bp++;
222*3089Swyllys 			if (bp >= endptr) {
223*3089Swyllys 				/*
224*3089Swyllys 				 * escape charater must appear with paired char
225*3089Swyllys 				 */
226*3089Swyllys 				*pbp = bp;
227*3089Swyllys 				return (KMF_ERR_RDN_PARSER);
228*3089Swyllys 			}
229*3089Swyllys 		} else if (!isQuoted && SPECIAL_CHAR(c)) {
230*3089Swyllys 			/* unescaped special and not within quoted value */
231*3089Swyllys 			break;
232*3089Swyllys 		} else if (c == C_DOUBLE_QUOTE) {
233*3089Swyllys 			/* reached unescaped double quote */
234*3089Swyllys 			break;
235*3089Swyllys 		}
236*3089Swyllys 		/* append character */
237*3089Swyllys 		vallen++;
238*3089Swyllys 		if (vallen >= valBufSize) {
239*3089Swyllys 			*pbp = bp;
240*3089Swyllys 			return (KMF_ERR_RDN_PARSER);
241*3089Swyllys 		}
242*3089Swyllys 		*valBufp++ = *bp++;
243*3089Swyllys 	}
244*3089Swyllys 
245*3089Swyllys 	/* stip trailing spaces from unquoted values */
246*3089Swyllys 	if (!isQuoted) {
247*3089Swyllys 		if (valBufp > valBuf) {
248*3089Swyllys 			valBufp--;
249*3089Swyllys 			while ((valBufp > valBuf) && OPTIONAL_SPACE(*valBufp)) {
250*3089Swyllys 				valBufp--;
251*3089Swyllys 			}
252*3089Swyllys 			valBufp++;
253*3089Swyllys 		}
254*3089Swyllys 	}
255*3089Swyllys 
256*3089Swyllys 	if (isQuoted) {
257*3089Swyllys 		/* insist that we stopped on a double quote */
258*3089Swyllys 		if (*bp != C_DOUBLE_QUOTE) {
259*3089Swyllys 			*pbp = bp;
260*3089Swyllys 			return (KMF_ERR_RDN_PARSER);
261*3089Swyllys 		}
262*3089Swyllys 		/* skip over the quote and skip optional space */
263*3089Swyllys 		bp++;
264*3089Swyllys 		skipSpace(&bp, endptr);
265*3089Swyllys 	}
266*3089Swyllys 
267*3089Swyllys 	*pbp = bp;
268*3089Swyllys 
269*3089Swyllys 	if (valBufp == valBuf) {
270*3089Swyllys 		/* empty value -- not allowed */
271*3089Swyllys 		return (KMF_ERR_RDN_PARSER);
272*3089Swyllys 	}
273*3089Swyllys 
274*3089Swyllys 	/* null-terminate valBuf -- guaranteed at least one space left */
275*3089Swyllys 	*valBufp++ = 0;
276*3089Swyllys 
277*3089Swyllys 	return (KMF_OK);
278*3089Swyllys }
279*3089Swyllys 
280*3089Swyllys static KMF_RETURN
281*3089Swyllys CreateRDN(KMF_X509_TYPE_VALUE_PAIR *ava, KMF_X509_RDN *newrdn)
282*3089Swyllys {
283*3089Swyllys 	/* Each RDN has 1 AttrTypeAndValue */
284*3089Swyllys 	(void) memset(newrdn, 0, sizeof (KMF_X509_RDN));
285*3089Swyllys 	newrdn->numberOfPairs = 1;
286*3089Swyllys 	newrdn->AttributeTypeAndValue = ava;
287*3089Swyllys 
288*3089Swyllys 	return (KMF_OK);
289*3089Swyllys }
290*3089Swyllys 
291*3089Swyllys static KMF_RETURN
292*3089Swyllys copy_oid(KMF_OID *dst, KMF_OID *src)
293*3089Swyllys {
294*3089Swyllys 	KMF_RETURN ret = KMF_OK;
295*3089Swyllys 
296*3089Swyllys 	if (dst == NULL || src == NULL)
297*3089Swyllys 		return (KMF_ERR_BAD_PARAMETER);
298*3089Swyllys 
299*3089Swyllys 	dst->Data = malloc(src->Length);
300*3089Swyllys 	if (dst->Data == NULL)
301*3089Swyllys 		return (KMF_ERR_MEMORY);
302*3089Swyllys 
303*3089Swyllys 	dst->Length = src->Length;
304*3089Swyllys 	(void) memcpy(dst->Data, src->Data, src->Length);
305*3089Swyllys 
306*3089Swyllys 	return (ret);
307*3089Swyllys }
308*3089Swyllys 
309*3089Swyllys static KMF_RETURN
310*3089Swyllys CreateAVA(KMF_OID *oid, int valueType, char *value,
311*3089Swyllys     KMF_X509_TYPE_VALUE_PAIR **newava)
312*3089Swyllys {
313*3089Swyllys 	int rv = KMF_OK;
314*3089Swyllys 	KMF_X509_TYPE_VALUE_PAIR *ava = NULL;
315*3089Swyllys 
316*3089Swyllys 	*newava = NULL;
317*3089Swyllys 	ava = (KMF_X509_TYPE_VALUE_PAIR*) malloc(
318*3089Swyllys 	    sizeof (KMF_X509_TYPE_VALUE_PAIR));
319*3089Swyllys 	if (ava == NULL) {
320*3089Swyllys 		return (KMF_ERR_MEMORY);
321*3089Swyllys 	} else {
322*3089Swyllys 		(void) memset(ava, 0, sizeof (KMF_X509_TYPE_VALUE_PAIR));
323*3089Swyllys 		ava->valueType = valueType;
324*3089Swyllys 		ava->value.Data = malloc(strlen(value));
325*3089Swyllys 		if (ava->value.Data == NULL) {
326*3089Swyllys 			free(ava);
327*3089Swyllys 			return (KMF_ERR_MEMORY);
328*3089Swyllys 		}
329*3089Swyllys 		(void) memcpy(ava->value.Data, value, strlen(value));
330*3089Swyllys 		ava->value.Length = strlen(value);
331*3089Swyllys 
332*3089Swyllys 		rv = copy_oid(&ava->type, oid);
333*3089Swyllys 		if (rv != KMF_OK) {
334*3089Swyllys 			/* Illegal AVA type */
335*3089Swyllys 			free(ava->value.Data);
336*3089Swyllys 			free(ava);
337*3089Swyllys 			return (rv);
338*3089Swyllys 		}
339*3089Swyllys 	}
340*3089Swyllys 	*newava = ava;
341*3089Swyllys 
342*3089Swyllys 	return (rv);
343*3089Swyllys }
344*3089Swyllys 
345*3089Swyllys static KMF_RETURN
346*3089Swyllys ParseRdnAttribute(char **pbp, char *endptr, boolean_t singleAVA,
347*3089Swyllys     KMF_X509_TYPE_VALUE_PAIR **a)
348*3089Swyllys {
349*3089Swyllys 	KMF_RETURN rv;
350*3089Swyllys 	const struct NameToKind *n2k;
351*3089Swyllys 	int vt;
352*3089Swyllys 	int valLen;
353*3089Swyllys 	char *bp;
354*3089Swyllys 
355*3089Swyllys 	char tagBuf[32];
356*3089Swyllys 	char valBuf[384];
357*3089Swyllys 
358*3089Swyllys 	rv = scanTag(pbp, endptr, tagBuf, sizeof (tagBuf));
359*3089Swyllys 	if (rv != KMF_OK)
360*3089Swyllys 		return (rv);
361*3089Swyllys 	rv = scanVal(pbp, endptr, valBuf, sizeof (valBuf));
362*3089Swyllys 	if (rv != KMF_OK)
363*3089Swyllys 		return (rv);
364*3089Swyllys 
365*3089Swyllys 	/* insist that if we haven't finished we've stopped on a separator */
366*3089Swyllys 	bp = *pbp;
367*3089Swyllys 	if (bp < endptr) {
368*3089Swyllys 		if (singleAVA || (*bp != ',' && *bp != ';')) {
369*3089Swyllys 			*pbp = bp;
370*3089Swyllys 			return (KMF_ERR_RDN_ATTR);
371*3089Swyllys 		}
372*3089Swyllys 		/* ok, skip over separator */
373*3089Swyllys 		bp++;
374*3089Swyllys 	}
375*3089Swyllys 	*pbp = bp;
376*3089Swyllys 
377*3089Swyllys 	for (n2k = name2kinds; n2k->name; n2k++) {
378*3089Swyllys 		if (strcasecmp(n2k->name, tagBuf) == 0) {
379*3089Swyllys 			valLen = strlen(valBuf);
380*3089Swyllys 			if (n2k->kind == OID_AVA_COUNTRY_NAME) {
381*3089Swyllys 				vt = BER_PRINTABLE_STRING;
382*3089Swyllys 				if (valLen != 2) {
383*3089Swyllys 					return (KMF_ERR_RDN_ATTR);
384*3089Swyllys 				}
385*3089Swyllys 				if (!IsPrintable((unsigned char *) valBuf, 2)) {
386*3089Swyllys 					return (KMF_ERR_RDN_ATTR);
387*3089Swyllys 				}
388*3089Swyllys 			} else if ((n2k->kind == OID_PKCS9_EMAIL_ADDRESS) ||
389*3089Swyllys 				(n2k->kind == OID_RFC1274_MAIL)) {
390*3089Swyllys 				vt = BER_IA5STRING;
391*3089Swyllys 			} else {
392*3089Swyllys 				/*
393*3089Swyllys 				 * Hack -- for rationale see X.520
394*3089Swyllys 				 * DirectoryString defn
395*3089Swyllys 				 */
396*3089Swyllys 				if (IsPrintable((unsigned char *)valBuf,
397*3089Swyllys 				    valLen)) {
398*3089Swyllys 					vt = BER_PRINTABLE_STRING;
399*3089Swyllys 				} else if (Is7Bit((unsigned char *)valBuf,
400*3089Swyllys 				    valLen)) {
401*3089Swyllys 					vt = BER_T61STRING;
402*3089Swyllys 				}
403*3089Swyllys 			}
404*3089Swyllys 			rv = CreateAVA(n2k->OID,
405*3089Swyllys 				vt, (char *)valBuf, a);
406*3089Swyllys 			return (rv);
407*3089Swyllys 		}
408*3089Swyllys 	}
409*3089Swyllys 	/* matched no kind -- invalid tag */
410*3089Swyllys 	return (KMF_ERR_RDN_ATTR);
411*3089Swyllys }
412*3089Swyllys 
413*3089Swyllys static int
414*3089Swyllys rdnavcompare(const void *a, const void *b)
415*3089Swyllys {
416*3089Swyllys 	KMF_X509_RDN *r1, *r2;
417*3089Swyllys 	KMF_X509_TYPE_VALUE_PAIR *av1, *av2;
418*3089Swyllys 	int i, p1, p2;
419*3089Swyllys 	const struct NameToKind *n2k;
420*3089Swyllys 	KMF_OID *oidrec;
421*3089Swyllys 
422*3089Swyllys 	r1 = (KMF_X509_RDN *)a;
423*3089Swyllys 	r2 = (KMF_X509_RDN *)b;
424*3089Swyllys 
425*3089Swyllys 	av1 = r1->AttributeTypeAndValue;
426*3089Swyllys 	av2 = r2->AttributeTypeAndValue;
427*3089Swyllys 
428*3089Swyllys 	p1 = p2 = MAXINT;
429*3089Swyllys 	/*
430*3089Swyllys 	 * The "Name2Kinds" list is ordered by significance.
431*3089Swyllys 	 * Compare the "ranking" of each of the OIDs to determine
432*3089Swyllys 	 * the result.
433*3089Swyllys 	 */
434*3089Swyllys 	for (n2k = name2kinds, i = 0;
435*3089Swyllys 		n2k->name && (p1 == MAXINT || p2 == MAXINT);
436*3089Swyllys 		n2k++, i++) {
437*3089Swyllys 		oidrec = n2k->OID;
438*3089Swyllys 		if (oidrec != NULL) {
439*3089Swyllys 			if (IsEqualOid(&av1->type, oidrec))
440*3089Swyllys 				p1 = i;
441*3089Swyllys 			if (IsEqualOid(&av2->type, oidrec))
442*3089Swyllys 				p2 = i;
443*3089Swyllys 		}
444*3089Swyllys 	}
445*3089Swyllys 
446*3089Swyllys 	if (p1 > p2)
447*3089Swyllys 		return (-1);
448*3089Swyllys 	else if (p1 < p2)
449*3089Swyllys 		return (1);
450*3089Swyllys 	else  /* If equal, treat as if it is less than */
451*3089Swyllys 		return (1);
452*3089Swyllys }
453*3089Swyllys 
454*3089Swyllys KMF_RETURN
455*3089Swyllys ParseDistinguishedName(char *buf, int len, KMF_X509_NAME *name)
456*3089Swyllys {
457*3089Swyllys 	KMF_RETURN rv = KMF_OK;
458*3089Swyllys 	char *bp, *e;
459*3089Swyllys 	KMF_X509_TYPE_VALUE_PAIR *ava = NULL;
460*3089Swyllys 	KMF_X509_RDN rdn;
461*3089Swyllys 
462*3089Swyllys 	(void) memset(name, 0, sizeof (KMF_X509_NAME));
463*3089Swyllys 	e = buf + len;
464*3089Swyllys 	bp = buf;
465*3089Swyllys 	while (bp < e) {
466*3089Swyllys 		rv = ParseRdnAttribute(&bp, e, B_FALSE, &ava);
467*3089Swyllys 		if (rv != KMF_OK) goto loser;
468*3089Swyllys 		rv = CreateRDN(ava, &rdn);
469*3089Swyllys 		if (rv != KMF_OK) goto loser;
470*3089Swyllys 		if (AddRDN(name, &rdn) != KMF_OK) goto loser;
471*3089Swyllys 		skipSpace(&bp, e);
472*3089Swyllys 	}
473*3089Swyllys 
474*3089Swyllys 	/*
475*3089Swyllys 	 * Canonicalize the DN by sorting the elements
476*3089Swyllys 	 * in little-endian order, as per RFC 1485:
477*3089Swyllys 	 * "The name is presented/input in a little-endian
478*3089Swyllys 	 * order (most significant component last)."
479*3089Swyllys 	 */
480*3089Swyllys 	qsort((void *)name->RelativeDistinguishedName,
481*3089Swyllys 		name->numberOfRDNs,
482*3089Swyllys 		sizeof (KMF_X509_RDN),
483*3089Swyllys 		rdnavcompare);
484*3089Swyllys 
485*3089Swyllys 	/* return result */
486*3089Swyllys 	return (rv);
487*3089Swyllys 
488*3089Swyllys loser:
489*3089Swyllys 	KMF_FreeDN(name);
490*3089Swyllys 	return (rv);
491*3089Swyllys }
492*3089Swyllys 
493*3089Swyllys static KMF_BOOL
494*3089Swyllys IsEqualData(KMF_DATA *d1, KMF_DATA *d2)
495*3089Swyllys {
496*3089Swyllys 	return ((d1->Length == d2->Length) &&
497*3089Swyllys 	    !memcmp(d1->Data, d2->Data, d1->Length));
498*3089Swyllys }
499*3089Swyllys 
500*3089Swyllys /*
501*3089Swyllys  * Generic routine to compare 2 RDN structures.
502*3089Swyllys  *
503*3089Swyllys  * Because the ordering of the AV pairs may not be
504*3089Swyllys  * the same, we must compare each AV pair individually
505*3089Swyllys  *
506*3089Swyllys  * Return 0 if equal, 1 if not.
507*3089Swyllys  */
508*3089Swyllys int
509*3089Swyllys KMF_CompareRDNs(KMF_X509_NAME *name1, KMF_X509_NAME *name2)
510*3089Swyllys {
511*3089Swyllys 	int i, j;
512*3089Swyllys 	boolean_t avfound;
513*3089Swyllys 	KMF_X509_RDN *r1, *r2;
514*3089Swyllys 	KMF_X509_TYPE_VALUE_PAIR *av1, *av2;
515*3089Swyllys 
516*3089Swyllys 	if (name1 == NULL || name2 == NULL)
517*3089Swyllys 		return (1);
518*3089Swyllys 
519*3089Swyllys 	if (name1->numberOfRDNs != name2->numberOfRDNs)
520*3089Swyllys 		return (1);
521*3089Swyllys 
522*3089Swyllys 	for (i = 0; i < name1->numberOfRDNs; i++) {
523*3089Swyllys 		r1 = (KMF_X509_RDN *)&name1->RelativeDistinguishedName[i];
524*3089Swyllys 		av1 = (KMF_X509_TYPE_VALUE_PAIR *)r1->AttributeTypeAndValue;
525*3089Swyllys 
526*3089Swyllys 		avfound = FALSE;
527*3089Swyllys 		for (j = 0; j < name2->numberOfRDNs && !avfound; j++) {
528*3089Swyllys 			r2 = (KMF_X509_RDN *)
529*3089Swyllys 				&name2->RelativeDistinguishedName[j];
530*3089Swyllys 			av2 = (KMF_X509_TYPE_VALUE_PAIR *)
531*3089Swyllys 				r2->AttributeTypeAndValue;
532*3089Swyllys 
533*3089Swyllys 			avfound = (IsEqualOid(&av1->type, &av2->type) &&
534*3089Swyllys 				    IsEqualData(&av1->value, &av2->value));
535*3089Swyllys 		}
536*3089Swyllys 		/*
537*3089Swyllys 		 * If the current AV from name1 was not found in name2,
538*3089Swyllys 		 * we are done.
539*3089Swyllys 		 */
540*3089Swyllys 		if (!avfound)
541*3089Swyllys 			return (1);
542*3089Swyllys 	}
543*3089Swyllys 
544*3089Swyllys 	/* If we got this far, it must be a match */
545*3089Swyllys 	return (0);
546*3089Swyllys }
547