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 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 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 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 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 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 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 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 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 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 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 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 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 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 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