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, 385 vt, (char *)valBuf, a); 386 return (rv); 387 } 388 } 389 /* matched no kind -- invalid tag */ 390 return (KMF_ERR_RDN_ATTR); 391 } 392 393 static int 394 rdnavcompare(const void *a, const void *b) 395 { 396 KMF_X509_RDN *r1, *r2; 397 KMF_X509_TYPE_VALUE_PAIR *av1, *av2; 398 int i, p1, p2; 399 const struct NameToKind *n2k; 400 KMF_OID *oidrec; 401 402 r1 = (KMF_X509_RDN *)a; 403 r2 = (KMF_X509_RDN *)b; 404 405 av1 = r1->AttributeTypeAndValue; 406 av2 = r2->AttributeTypeAndValue; 407 408 p1 = p2 = MAXINT; 409 /* 410 * The "Name2Kinds" list is ordered by significance. 411 * Compare the "ranking" of each of the OIDs to determine 412 * the result. 413 */ 414 for (n2k = name2kinds, i = 0; 415 n2k->name && (p1 == MAXINT || p2 == MAXINT); 416 n2k++, i++) { 417 oidrec = n2k->OID; 418 if (oidrec != NULL) { 419 if (IsEqualOid(&av1->type, oidrec)) 420 p1 = i; 421 if (IsEqualOid(&av2->type, oidrec)) 422 p2 = i; 423 } 424 } 425 426 if (p1 > p2) 427 return (-1); 428 else if (p1 < p2) 429 return (1); 430 else /* If equal, treat as if it is less than */ 431 return (1); 432 } 433 434 KMF_RETURN 435 ParseDistinguishedName(char *buf, int len, KMF_X509_NAME *name) 436 { 437 KMF_RETURN rv = KMF_OK; 438 char *bp, *e; 439 KMF_X509_TYPE_VALUE_PAIR *ava = NULL; 440 KMF_X509_RDN rdn; 441 442 (void) memset(name, 0, sizeof (KMF_X509_NAME)); 443 e = buf + len; 444 bp = buf; 445 while (bp < e) { 446 rv = ParseRdnAttribute(&bp, e, B_FALSE, &ava); 447 if (rv != KMF_OK) goto loser; 448 rv = CreateRDN(ava, &rdn); 449 if (rv != KMF_OK) goto loser; 450 if (AddRDN(name, &rdn) != KMF_OK) goto loser; 451 skipSpace(&bp, e); 452 } 453 454 /* 455 * Canonicalize the DN by sorting the elements 456 * in little-endian order, as per RFC 1485: 457 * "The name is presented/input in a little-endian 458 * order (most significant component last)." 459 */ 460 qsort((void *)name->RelativeDistinguishedName, 461 name->numberOfRDNs, 462 sizeof (KMF_X509_RDN), 463 rdnavcompare); 464 465 /* return result */ 466 return (rv); 467 468 loser: 469 KMF_FreeDN(name); 470 return (rv); 471 } 472 473 static KMF_BOOL 474 IsEqualData(KMF_DATA *d1, KMF_DATA *d2) 475 { 476 return ((d1->Length == d2->Length) && 477 !memcmp(d1->Data, d2->Data, d1->Length)); 478 } 479 480 /* 481 * Generic routine to compare 2 RDN structures. 482 * 483 * Because the ordering of the AV pairs may not be 484 * the same, we must compare each AV pair individually 485 * 486 * Return 0 if equal, 1 if not. 487 */ 488 int 489 KMF_CompareRDNs(KMF_X509_NAME *name1, KMF_X509_NAME *name2) 490 { 491 int i, j; 492 boolean_t avfound; 493 KMF_X509_RDN *r1, *r2; 494 KMF_X509_TYPE_VALUE_PAIR *av1, *av2; 495 496 if (name1 == NULL || name2 == NULL) 497 return (1); 498 499 if (name1->numberOfRDNs != name2->numberOfRDNs) 500 return (1); 501 502 for (i = 0; i < name1->numberOfRDNs; i++) { 503 r1 = (KMF_X509_RDN *)&name1->RelativeDistinguishedName[i]; 504 av1 = (KMF_X509_TYPE_VALUE_PAIR *)r1->AttributeTypeAndValue; 505 506 avfound = FALSE; 507 for (j = 0; j < name2->numberOfRDNs && !avfound; j++) { 508 r2 = (KMF_X509_RDN *) 509 &name2->RelativeDistinguishedName[j]; 510 av2 = (KMF_X509_TYPE_VALUE_PAIR *) 511 r2->AttributeTypeAndValue; 512 513 avfound = (IsEqualOid(&av1->type, &av2->type) && 514 IsEqualData(&av1->value, &av2->value)); 515 } 516 /* 517 * If the current AV from name1 was not found in name2, 518 * we are done. 519 */ 520 if (!avfound) 521 return (1); 522 } 523 524 /* If we got this far, it must be a match */ 525 return (0); 526 } 527