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