pkcs11uri.c (24727B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include "pkcs11.h" 6 #include "pkcs11uri.h" 7 #include "plarena.h" 8 #include "prprf.h" 9 #include "secport.h" 10 11 /* Character sets used in the ABNF rules in RFC7512. */ 12 #define PK11URI_DIGIT "0123456789" 13 #define PK11URI_ALPHA "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 14 #define PK11URI_HEXDIG PK11URI_DIGIT "abcdefABCDEF" 15 #define PK11URI_UNRESERVED PK11URI_ALPHA PK11URI_DIGIT "-._~" 16 #define PK11URI_RES_AVAIL ":[]@!$'()*+,=" 17 #define PK11URI_PATH_RES_AVAIL PK11URI_RES_AVAIL "&" 18 #define PK11URI_QUERY_RES_AVAIL PK11URI_RES_AVAIL "/?|" 19 #define PK11URI_ATTR_NM_CHAR PK11URI_ALPHA PK11URI_DIGIT "-_" 20 #define PK11URI_PCHAR PK11URI_UNRESERVED PK11URI_PATH_RES_AVAIL 21 #define PK11URI_QCHAR PK11URI_UNRESERVED PK11URI_QUERY_RES_AVAIL 22 23 /* Path attributes defined in RFC7512. */ 24 static const char *pattr_names[] = { 25 PK11URI_PATTR_TOKEN, 26 PK11URI_PATTR_MANUFACTURER, 27 PK11URI_PATTR_SERIAL, 28 PK11URI_PATTR_MODEL, 29 PK11URI_PATTR_LIBRARY_MANUFACTURER, 30 PK11URI_PATTR_LIBRARY_DESCRIPTION, 31 PK11URI_PATTR_LIBRARY_VERSION, 32 PK11URI_PATTR_OBJECT, 33 PK11URI_PATTR_TYPE, 34 PK11URI_PATTR_ID, 35 PK11URI_PATTR_SLOT_MANUFACTURER, 36 PK11URI_PATTR_SLOT_DESCRIPTION, 37 PK11URI_PATTR_SLOT_ID 38 }; 39 40 /* Query attributes defined in RFC7512. */ 41 static const char *qattr_names[] = { 42 PK11URI_QATTR_PIN_SOURCE, 43 PK11URI_QATTR_PIN_VALUE, 44 PK11URI_QATTR_MODULE_NAME, 45 PK11URI_QATTR_MODULE_PATH 46 }; 47 48 struct PK11URIBufferStr { 49 PLArenaPool *arena; 50 unsigned char *data; 51 size_t size; 52 size_t allocated; 53 }; 54 typedef struct PK11URIBufferStr PK11URIBuffer; 55 56 struct PK11URIAttributeListEntryStr { 57 char *name; 58 SECItem value; 59 }; 60 typedef struct PK11URIAttributeListEntryStr PK11URIAttributeListEntry; 61 62 struct PK11URIAttributeListStr { 63 PLArenaPool *arena; 64 PK11URIAttributeListEntry *attrs; 65 size_t num_attrs; 66 }; 67 typedef struct PK11URIAttributeListStr PK11URIAttributeList; 68 69 struct PK11URIStr { 70 PLArenaPool *arena; 71 72 PK11URIAttributeList pattrs; 73 PK11URIAttributeList vpattrs; 74 75 PK11URIAttributeList qattrs; 76 PK11URIAttributeList vqattrs; 77 }; 78 79 #define PK11URI_ARENA_SIZE 1024 80 81 typedef int (*PK11URIAttributeCompareNameFunc)(const char *a, const char *b); 82 83 /* This belongs in secport.h */ 84 #define PORT_ArenaGrowArray(poolp, oldptr, type, oldnum, newnum) \ 85 (type *)PORT_ArenaGrow((poolp), (oldptr), \ 86 (oldnum) * sizeof(type), (newnum) * sizeof(type)) 87 #define PORT_ReallocArray(oldptr, type, newnum) \ 88 (type *)PORT_Realloc((oldptr), (newnum) * sizeof(type)) 89 90 /* Functions for resizable buffer. */ 91 static SECStatus 92 pk11uri_AppendBuffer(PK11URIBuffer *buffer, const unsigned char *data, 93 size_t size) 94 { 95 /* Check overflow. */ 96 if (buffer->size + size < buffer->size) 97 return SECFailure; 98 99 if (buffer->size + size > buffer->allocated) { 100 size_t allocated = buffer->allocated * 2 + size; 101 if (allocated < buffer->allocated) 102 return SECFailure; 103 if (buffer->arena) 104 buffer->data = PORT_ArenaGrow(buffer->arena, buffer->data, 105 buffer->allocated, allocated); 106 else 107 buffer->data = PORT_Realloc(buffer->data, allocated); 108 if (buffer->data == NULL) 109 return SECFailure; 110 buffer->allocated = allocated; 111 } 112 113 memcpy(&buffer->data[buffer->size], data, size); 114 buffer->size += size; 115 116 return SECSuccess; 117 } 118 119 static void 120 pk11uri_InitBuffer(PK11URIBuffer *buffer, PLArenaPool *arena) 121 { 122 memset(buffer, 0, sizeof(PK11URIBuffer)); 123 buffer->arena = arena; 124 } 125 126 static void 127 pk11uri_DestroyBuffer(PK11URIBuffer *buffer) 128 { 129 if (buffer->arena == NULL) { 130 PORT_Free(buffer->data); 131 } 132 } 133 134 /* URI encoding functions. */ 135 static char * 136 pk11uri_Escape(PLArenaPool *arena, const unsigned char *value, size_t length, 137 const char *available) 138 { 139 PK11URIBuffer buffer; 140 const unsigned char *p; 141 unsigned char buf[4]; 142 char *result = NULL; 143 SECStatus ret; 144 145 pk11uri_InitBuffer(&buffer, arena); 146 147 for (p = value; p < value + length; p++) { 148 if (strchr(available, *p) == NULL) { 149 if (PR_snprintf((char *)buf, sizeof(buf), "%%%02X", *p) == (PRUint32)-1) { 150 goto fail; 151 } 152 ret = pk11uri_AppendBuffer(&buffer, buf, 3); 153 if (ret != SECSuccess) { 154 goto fail; 155 } 156 } else { 157 ret = pk11uri_AppendBuffer(&buffer, p, 1); 158 if (ret != SECSuccess) { 159 goto fail; 160 } 161 } 162 } 163 buf[0] = '\0'; 164 ret = pk11uri_AppendBuffer(&buffer, buf, 1); 165 if (ret != SECSuccess) { 166 goto fail; 167 } 168 169 /* Steal the memory allocated in buffer. */ 170 result = (char *)buffer.data; 171 buffer.data = NULL; 172 173 fail: 174 pk11uri_DestroyBuffer(&buffer); 175 176 return result; 177 } 178 179 static unsigned char * 180 pk11uri_Unescape(PLArenaPool *arena, const char *value, size_t *length) 181 { 182 PK11URIBuffer buffer; 183 const char *p; 184 unsigned char buf[1]; 185 unsigned char *result = NULL; 186 SECStatus ret; 187 188 pk11uri_InitBuffer(&buffer, arena); 189 190 for (p = value; p < value + *length; p++) { 191 if (*p == '%') { 192 int c; 193 size_t i; 194 195 p++; 196 for (c = 0, i = 0; i < 2; i++) { 197 int h = *(p + i); 198 if ('0' <= h && h <= '9') { 199 c = (c << 4) | (h - '0'); 200 } else if ('a' <= h && h <= 'f') { 201 c = (c << 4) | (h - 'a' + 10); 202 } else if ('A' <= h && h <= 'F') { 203 c = (c << 4) | (h - 'A' + 10); 204 } else { 205 break; 206 } 207 } 208 if (i != 2) { 209 goto fail; 210 } 211 p++; 212 buf[0] = c; 213 } else { 214 buf[0] = *p; 215 } 216 ret = pk11uri_AppendBuffer(&buffer, buf, 1); 217 if (ret != SECSuccess) { 218 goto fail; 219 } 220 } 221 *length = buffer.size; 222 buf[0] = '\0'; 223 ret = pk11uri_AppendBuffer(&buffer, buf, 1); 224 if (ret != SECSuccess) { 225 goto fail; 226 } 227 228 result = buffer.data; 229 buffer.data = NULL; 230 231 fail: 232 pk11uri_DestroyBuffer(&buffer); 233 234 return result; 235 } 236 237 /* Functions for manipulating attributes array. */ 238 239 /* Compare two attribute names by the array index in attr_names. Both 240 * attribute names must be present in attr_names, otherwise it is a 241 * programming error. */ 242 static int 243 pk11uri_CompareByPosition(const char *a, const char *b, 244 const char **attr_names, size_t num_attr_names) 245 { 246 size_t i, j; 247 248 for (i = 0; i < num_attr_names; i++) { 249 if (strcmp(a, attr_names[i]) == 0) { 250 break; 251 } 252 } 253 PR_ASSERT(i < num_attr_names); 254 255 for (j = 0; j < num_attr_names; j++) { 256 if (strcmp(b, attr_names[j]) == 0) { 257 break; 258 } 259 } 260 PR_ASSERT(j < num_attr_names); 261 262 return i - j; 263 } 264 265 /* Those pk11uri_Compare{Path,Query}AttributeName functions are used 266 * to reorder attributes when inserting. */ 267 static int 268 pk11uri_ComparePathAttributeName(const char *a, const char *b) 269 { 270 return pk11uri_CompareByPosition(a, b, pattr_names, PR_ARRAY_SIZE(pattr_names)); 271 } 272 273 static int 274 pk11uri_CompareQueryAttributeName(const char *a, const char *b) 275 { 276 return pk11uri_CompareByPosition(a, b, qattr_names, PR_ARRAY_SIZE(qattr_names)); 277 } 278 279 static SECStatus 280 pk11uri_InsertToAttributeList(PK11URIAttributeList *attrs, 281 char *name, unsigned char *value, size_t size, 282 PK11URIAttributeCompareNameFunc compare_name, 283 PRBool allow_duplicate) 284 { 285 size_t i; 286 287 if (attrs->arena) { 288 attrs->attrs = PORT_ArenaGrowArray(attrs->arena, attrs->attrs, 289 PK11URIAttributeListEntry, 290 attrs->num_attrs, 291 attrs->num_attrs + 1); 292 } else { 293 attrs->attrs = PORT_ReallocArray(attrs->attrs, 294 PK11URIAttributeListEntry, 295 attrs->num_attrs + 1); 296 } 297 if (attrs->attrs == NULL) { 298 return SECFailure; 299 } 300 301 for (i = 0; i < attrs->num_attrs; i++) { 302 if (!allow_duplicate && strcmp(name, attrs->attrs[i].name) == 0) { 303 return SECFailure; 304 } 305 if (compare_name(name, attrs->attrs[i].name) < 0) { 306 memmove(&attrs->attrs[i + 1], &attrs->attrs[i], 307 sizeof(PK11URIAttributeListEntry) * (attrs->num_attrs - i)); 308 break; 309 } 310 } 311 312 attrs->attrs[i].name = name; 313 attrs->attrs[i].value.type = siBuffer; 314 attrs->attrs[i].value.data = value; 315 attrs->attrs[i].value.len = size; 316 317 attrs->num_attrs++; 318 319 return SECSuccess; 320 } 321 322 static SECStatus 323 pk11uri_InsertToAttributeListEscaped(PK11URIAttributeList *attrs, 324 const char *name, size_t name_size, 325 const char *value, size_t value_size, 326 PK11URIAttributeCompareNameFunc compare_name, 327 PRBool allow_duplicate) 328 { 329 char *name_copy = NULL; 330 unsigned char *value_copy = NULL; 331 SECStatus ret; 332 333 if (attrs->arena) { 334 name_copy = PORT_ArenaNewArray(attrs->arena, char, name_size + 1); 335 } else { 336 name_copy = PORT_Alloc(name_size + 1); 337 } 338 if (name_copy == NULL) { 339 goto fail; 340 } 341 memcpy(name_copy, name, name_size); 342 name_copy[name_size] = '\0'; 343 344 value_copy = pk11uri_Unescape(attrs->arena, value, &value_size); 345 if (value_copy == NULL) { 346 goto fail; 347 } 348 349 ret = pk11uri_InsertToAttributeList(attrs, name_copy, value_copy, value_size, 350 compare_name, allow_duplicate); 351 if (ret != SECSuccess) { 352 goto fail; 353 } 354 355 return ret; 356 357 fail: 358 if (attrs->arena == NULL) { 359 PORT_Free(name_copy); 360 PORT_Free(value_copy); 361 } 362 363 return SECFailure; 364 } 365 366 static void 367 pk11uri_InitAttributeList(PK11URIAttributeList *attrs, PLArenaPool *arena) 368 { 369 memset(attrs, 0, sizeof(PK11URIAttributeList)); 370 attrs->arena = arena; 371 } 372 373 static void 374 pk11uri_DestroyAttributeList(PK11URIAttributeList *attrs) 375 { 376 if (attrs->arena == NULL) { 377 size_t i; 378 379 for (i = 0; i < attrs->num_attrs; i++) { 380 PORT_Free(attrs->attrs[i].name); 381 PORT_Free(attrs->attrs[i].value.data); 382 } 383 PORT_Free(attrs->attrs); 384 } 385 } 386 387 static SECStatus 388 pk11uri_AppendAttributeListToBuffer(PK11URIBuffer *buffer, 389 PK11URIAttributeList *attrs, 390 int separator, 391 const char *unescaped) 392 { 393 size_t i; 394 SECStatus ret; 395 396 for (i = 0; i < attrs->num_attrs; i++) { 397 unsigned char sep[1]; 398 char *escaped; 399 PK11URIAttributeListEntry *attr = &attrs->attrs[i]; 400 401 if (i > 0) { 402 sep[0] = separator; 403 ret = pk11uri_AppendBuffer(buffer, sep, 1); 404 if (ret != SECSuccess) { 405 return ret; 406 } 407 } 408 409 ret = pk11uri_AppendBuffer(buffer, (unsigned char *)attr->name, 410 strlen(attr->name)); 411 if (ret != SECSuccess) { 412 return ret; 413 } 414 415 sep[0] = '='; 416 ret = pk11uri_AppendBuffer(buffer, sep, 1); 417 if (ret != SECSuccess) { 418 return ret; 419 } 420 421 escaped = pk11uri_Escape(buffer->arena, attr->value.data, attr->value.len, 422 unescaped); 423 if (escaped == NULL) { 424 return ret; 425 } 426 ret = pk11uri_AppendBuffer(buffer, (unsigned char *)escaped, 427 strlen(escaped)); 428 if (buffer->arena == NULL) { 429 PORT_Free(escaped); 430 } 431 if (ret != SECSuccess) { 432 return ret; 433 } 434 } 435 436 return SECSuccess; 437 } 438 439 /* Creation of PK11URI object. */ 440 static PK11URI * 441 pk11uri_AllocURI(void) 442 { 443 PLArenaPool *arena; 444 PK11URI *result; 445 446 arena = PORT_NewArena(PK11URI_ARENA_SIZE); 447 if (arena == NULL) { 448 return NULL; 449 } 450 451 result = PORT_ArenaZAlloc(arena, sizeof(PK11URI)); 452 if (result == NULL) { 453 PORT_FreeArena(arena, PR_FALSE); 454 return NULL; 455 } 456 457 result->arena = arena; 458 pk11uri_InitAttributeList(&result->pattrs, arena); 459 pk11uri_InitAttributeList(&result->vpattrs, arena); 460 pk11uri_InitAttributeList(&result->qattrs, arena); 461 pk11uri_InitAttributeList(&result->vqattrs, arena); 462 463 return result; 464 } 465 466 static SECStatus 467 pk11uri_InsertAttributes(PK11URIAttributeList *dest_attrs, 468 PK11URIAttributeList *dest_vattrs, 469 const PK11URIAttribute *attrs, 470 size_t num_attrs, 471 const char **attr_names, 472 size_t num_attr_names, 473 PK11URIAttributeCompareNameFunc compare_name, 474 PRBool allow_duplicate, 475 PRBool vendor_allow_duplicate) 476 { 477 SECStatus ret; 478 size_t i; 479 480 for (i = 0; i < num_attrs; i++) { 481 char *name, *value; 482 const char *p; 483 size_t j; 484 485 p = attrs[i].name; 486 487 /* The attribute must not be empty. */ 488 if (*p == '\0') { 489 return SECFailure; 490 } 491 492 /* Check that the name doesn't contain invalid character. */ 493 for (; *p != '\0'; p++) { 494 if (strchr(PK11URI_ATTR_NM_CHAR, *p) == NULL) { 495 return SECFailure; 496 } 497 } 498 499 name = PORT_ArenaStrdup(dest_attrs->arena, attrs[i].name); 500 if (name == NULL) { 501 return SECFailure; 502 } 503 504 value = PORT_ArenaStrdup(dest_attrs->arena, attrs[i].value); 505 if (value == NULL) { 506 return SECFailure; 507 } 508 509 for (j = 0; j < num_attr_names; j++) { 510 if (strcmp(name, attr_names[j]) == 0) { 511 break; 512 } 513 } 514 if (j < num_attr_names) { 515 /* Named attribute. */ 516 ret = pk11uri_InsertToAttributeList(dest_attrs, 517 name, 518 (unsigned char *)value, 519 strlen(value), 520 compare_name, 521 allow_duplicate); 522 if (ret != SECSuccess) { 523 return ret; 524 } 525 } else { 526 /* Vendor attribute. */ 527 ret = pk11uri_InsertToAttributeList(dest_vattrs, 528 name, 529 (unsigned char *)value, 530 strlen(value), 531 strcmp, 532 vendor_allow_duplicate); 533 if (ret != SECSuccess) { 534 return ret; 535 } 536 } 537 } 538 539 return SECSuccess; 540 } 541 542 PK11URI * 543 PK11URI_CreateURI(const PK11URIAttribute *pattrs, 544 size_t num_pattrs, 545 const PK11URIAttribute *qattrs, 546 size_t num_qattrs) 547 { 548 PK11URI *result; 549 SECStatus ret; 550 551 result = pk11uri_AllocURI(); 552 553 ret = pk11uri_InsertAttributes(&result->pattrs, &result->vpattrs, 554 pattrs, num_pattrs, 555 pattr_names, PR_ARRAY_SIZE(pattr_names), 556 pk11uri_ComparePathAttributeName, 557 PR_FALSE, PR_FALSE); 558 if (ret != SECSuccess) { 559 goto fail; 560 } 561 562 ret = pk11uri_InsertAttributes(&result->qattrs, &result->vqattrs, 563 qattrs, num_qattrs, 564 qattr_names, PR_ARRAY_SIZE(qattr_names), 565 pk11uri_CompareQueryAttributeName, 566 PR_FALSE, PR_TRUE); 567 if (ret != SECSuccess) { 568 goto fail; 569 } 570 571 return result; 572 573 fail: 574 PK11URI_DestroyURI(result); 575 576 return NULL; 577 } 578 579 /* Parsing. */ 580 static SECStatus 581 pk11uri_ParseAttributes(const char **string, 582 const char *stop_chars, 583 int separator, 584 const char *accept_chars, 585 const char **attr_names, size_t num_attr_names, 586 PK11URIAttributeList *attrs, 587 PK11URIAttributeList *vattrs, 588 PK11URIAttributeCompareNameFunc compare_name, 589 PRBool allow_duplicate, 590 PRBool vendor_allow_duplicate) 591 { 592 const char *p = *string; 593 594 for (; *p != '\0'; p++) { 595 const char *name_start, *name_end, *value_start, *value_end; 596 size_t name_length, value_length, i; 597 SECStatus ret; 598 599 if (strchr(stop_chars, *p) != NULL) { 600 break; 601 } 602 for (name_start = p; *p != '=' && *p != '\0'; p++) { 603 if (strchr(PK11URI_ATTR_NM_CHAR, *p) != NULL) 604 continue; 605 606 return SECFailure; 607 } 608 if (*p == '\0') { 609 return SECFailure; 610 } 611 name_end = p++; 612 613 /* The attribute name must not be empty. */ 614 if (name_end == name_start) { 615 return SECFailure; 616 } 617 618 for (value_start = p; *p != separator && *p != '\0'; p++) { 619 if (strchr(stop_chars, *p) != NULL) { 620 break; 621 } 622 if (strchr(accept_chars, *p) != NULL) { 623 continue; 624 } 625 if (*p == '%') { 626 const char ch2 = *++p; 627 if (strchr(PK11URI_HEXDIG, ch2) != NULL) { 628 const char ch3 = *++p; 629 if (strchr(PK11URI_HEXDIG, ch3) != NULL) 630 continue; 631 } 632 } 633 634 return SECFailure; 635 } 636 value_end = p; 637 638 name_length = name_end - name_start; 639 value_length = value_end - value_start; 640 641 for (i = 0; i < num_attr_names; i++) { 642 if (name_length == strlen(attr_names[i]) && 643 memcmp(name_start, attr_names[i], name_length) == 0) { 644 break; 645 } 646 } 647 if (i < num_attr_names) { 648 /* Named attribute. */ 649 ret = pk11uri_InsertToAttributeListEscaped(attrs, 650 name_start, name_length, 651 value_start, value_length, 652 compare_name, 653 allow_duplicate); 654 if (ret != SECSuccess) { 655 return ret; 656 } 657 } else { 658 /* Vendor attribute. */ 659 ret = pk11uri_InsertToAttributeListEscaped(vattrs, 660 name_start, name_length, 661 value_start, value_length, 662 strcmp, 663 vendor_allow_duplicate); 664 if (ret != SECSuccess) { 665 return ret; 666 } 667 } 668 669 if (*p == '?' || *p == '\0') { 670 break; 671 } 672 } 673 674 *string = p; 675 return SECSuccess; 676 } 677 678 PK11URI * 679 PK11URI_ParseURI(const char *string) 680 { 681 PK11URI *result; 682 const char *p = string; 683 SECStatus ret; 684 685 if (PORT_Strncasecmp("pkcs11:", p, 7) != 0) { 686 return NULL; 687 } 688 p += 7; 689 690 result = pk11uri_AllocURI(); 691 if (result == NULL) { 692 return NULL; 693 } 694 695 /* Parse the path component and its attributes. */ 696 ret = pk11uri_ParseAttributes(&p, "?", ';', PK11URI_PCHAR, 697 pattr_names, PR_ARRAY_SIZE(pattr_names), 698 &result->pattrs, &result->vpattrs, 699 pk11uri_ComparePathAttributeName, 700 PR_FALSE, PR_FALSE); 701 if (ret != SECSuccess) { 702 goto fail; 703 } 704 705 /* Parse the query component and its attributes. */ 706 if (*p == '?') { 707 p++; 708 ret = pk11uri_ParseAttributes(&p, "", '&', PK11URI_QCHAR, 709 qattr_names, PR_ARRAY_SIZE(qattr_names), 710 &result->qattrs, &result->vqattrs, 711 pk11uri_CompareQueryAttributeName, 712 PR_FALSE, PR_TRUE); 713 if (ret != SECSuccess) { 714 goto fail; 715 } 716 } 717 718 return result; 719 720 fail: 721 PK11URI_DestroyURI(result); 722 723 return NULL; 724 } 725 726 /* Formatting. */ 727 char * 728 PK11URI_FormatURI(PLArenaPool *arena, PK11URI *uri) 729 { 730 PK11URIBuffer buffer; 731 SECStatus ret; 732 char *result = NULL; 733 734 pk11uri_InitBuffer(&buffer, arena); 735 736 ret = pk11uri_AppendBuffer(&buffer, (unsigned char *)"pkcs11:", 7); 737 if (ret != SECSuccess) 738 goto fail; 739 740 ret = pk11uri_AppendAttributeListToBuffer(&buffer, &uri->pattrs, ';', PK11URI_PCHAR); 741 if (ret != SECSuccess) { 742 goto fail; 743 } 744 745 if (uri->pattrs.num_attrs > 0 && uri->vpattrs.num_attrs > 0) { 746 ret = pk11uri_AppendBuffer(&buffer, (unsigned char *)";", 1); 747 if (ret != SECSuccess) { 748 goto fail; 749 } 750 } 751 752 ret = pk11uri_AppendAttributeListToBuffer(&buffer, &uri->vpattrs, ';', 753 PK11URI_PCHAR); 754 if (ret != SECSuccess) { 755 goto fail; 756 } 757 758 if (uri->qattrs.num_attrs > 0 || uri->vqattrs.num_attrs > 0) { 759 ret = pk11uri_AppendBuffer(&buffer, (unsigned char *)"?", 1); 760 if (ret != SECSuccess) { 761 goto fail; 762 } 763 } 764 765 ret = pk11uri_AppendAttributeListToBuffer(&buffer, &uri->qattrs, '&', PK11URI_QCHAR); 766 if (ret != SECSuccess) { 767 goto fail; 768 } 769 770 if (uri->qattrs.num_attrs > 0 && uri->vqattrs.num_attrs > 0) { 771 ret = pk11uri_AppendBuffer(&buffer, (unsigned char *)"&", 1); 772 if (ret != SECSuccess) { 773 goto fail; 774 } 775 } 776 777 ret = pk11uri_AppendAttributeListToBuffer(&buffer, &uri->vqattrs, '&', 778 PK11URI_QCHAR); 779 if (ret != SECSuccess) { 780 goto fail; 781 } 782 783 ret = pk11uri_AppendBuffer(&buffer, (unsigned char *)"\0", 1); 784 if (ret != SECSuccess) { 785 goto fail; 786 } 787 788 result = (char *)buffer.data; 789 buffer.data = NULL; 790 791 fail: 792 pk11uri_DestroyBuffer(&buffer); 793 794 return result; 795 } 796 797 /* Deallocating. */ 798 void 799 PK11URI_DestroyURI(PK11URI *uri) 800 { 801 pk11uri_DestroyAttributeList(&uri->pattrs); 802 pk11uri_DestroyAttributeList(&uri->vpattrs); 803 pk11uri_DestroyAttributeList(&uri->qattrs); 804 pk11uri_DestroyAttributeList(&uri->vqattrs); 805 PORT_FreeArena(uri->arena, PR_FALSE); 806 } 807 808 /* Accessors. */ 809 static const SECItem * 810 pk11uri_GetAttribute(PK11URIAttributeList *attrs, 811 PK11URIAttributeList *vattrs, 812 const char *name) 813 { 814 size_t i; 815 816 for (i = 0; i < attrs->num_attrs; i++) { 817 if (strcmp(name, attrs->attrs[i].name) == 0) { 818 return &attrs->attrs[i].value; 819 } 820 } 821 822 for (i = 0; i < vattrs->num_attrs; i++) { 823 if (strcmp(name, vattrs->attrs[i].name) == 0) { 824 return &vattrs->attrs[i].value; 825 } 826 } 827 828 return NULL; 829 } 830 831 const SECItem * 832 PK11URI_GetPathAttributeItem(PK11URI *uri, const char *name) 833 { 834 return pk11uri_GetAttribute(&uri->pattrs, &uri->vpattrs, name); 835 } 836 837 const char * 838 PK11URI_GetPathAttribute(PK11URI *uri, const char *name) 839 { 840 const SECItem *value; 841 842 value = PK11URI_GetPathAttributeItem(uri, name); 843 if (!value) { 844 return NULL; 845 } 846 847 return (const char *)value->data; 848 } 849 850 const SECItem * 851 PK11URI_GetQueryAttributeItem(PK11URI *uri, const char *name) 852 { 853 return pk11uri_GetAttribute(&uri->qattrs, &uri->vqattrs, name); 854 } 855 856 const char * 857 PK11URI_GetQueryAttribute(PK11URI *uri, const char *name) 858 { 859 const SECItem *value; 860 861 value = PK11URI_GetQueryAttributeItem(uri, name); 862 if (!value) { 863 return NULL; 864 } 865 866 return (const char *)value->data; 867 }