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