security/nss/cmd/certcgi/certcgi.c

Wed, 31 Dec 2014 07:16:47 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:16:47 +0100
branch
TOR_BUG_9701
changeset 3
141e0f1194b1
permissions
-rw-r--r--

Revert simplistic fix pending revisit of Mozilla integration attempt.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 /* Cert-O-Matic CGI */
michael@0 6
michael@0 7
michael@0 8 #include "nspr.h"
michael@0 9 #include "prtypes.h"
michael@0 10 #include "prtime.h"
michael@0 11 #include "prlong.h"
michael@0 12
michael@0 13 #include "pk11func.h"
michael@0 14 #include "cert.h"
michael@0 15 #include "cryptohi.h"
michael@0 16 #include "secoid.h"
michael@0 17 #include "secder.h"
michael@0 18 #include "genname.h"
michael@0 19 #include "xconst.h"
michael@0 20 #include "secutil.h"
michael@0 21 #include "pk11pqg.h"
michael@0 22 #include "certxutl.h"
michael@0 23 #include "nss.h"
michael@0 24
michael@0 25
michael@0 26 /* #define TEST 1 */
michael@0 27 /* #define FILEOUT 1 */
michael@0 28 /* #define OFFLINE 1 */
michael@0 29 #define START_FIELDS 100
michael@0 30 #define PREFIX_LEN 6
michael@0 31 #define SERIAL_FILE "../serial"
michael@0 32 #define DB_DIRECTORY ".."
michael@0 33
michael@0 34 static char *progName;
michael@0 35
michael@0 36 typedef struct PairStr Pair;
michael@0 37
michael@0 38 struct PairStr {
michael@0 39 char *name;
michael@0 40 char *data;
michael@0 41 };
michael@0 42
michael@0 43
michael@0 44 char prefix[PREFIX_LEN];
michael@0 45
michael@0 46
michael@0 47 const SEC_ASN1Template CERTIA5TypeTemplate[] = {
michael@0 48 { SEC_ASN1_IA5_STRING }
michael@0 49 };
michael@0 50
michael@0 51
michael@0 52
michael@0 53 SECKEYPrivateKey *privkeys[9] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL,
michael@0 54 NULL, NULL};
michael@0 55
michael@0 56
michael@0 57 #ifdef notdef
michael@0 58 const SEC_ASN1Template CERT_GeneralNameTemplate[] = {
michael@0 59 { SEC_ASN1_SEQUENCE_OF, 0, SEC_AnyTemplate }
michael@0 60 };
michael@0 61 #endif
michael@0 62
michael@0 63
michael@0 64 static void
michael@0 65 error_out(char *error_string)
michael@0 66 {
michael@0 67 printf("Content-type: text/plain\n\n");
michael@0 68 printf("%s", error_string);
michael@0 69 fflush(stderr);
michael@0 70 fflush(stdout);
michael@0 71 exit(1);
michael@0 72 }
michael@0 73
michael@0 74 static void
michael@0 75 error_allocate(void)
michael@0 76 {
michael@0 77 error_out("ERROR: Unable to allocate memory");
michael@0 78 }
michael@0 79
michael@0 80
michael@0 81 static char *
michael@0 82 make_copy_string(char *read_pos,
michael@0 83 int length,
michael@0 84 char sentinal_value)
michael@0 85 /* copys string from to a new string it creates and
michael@0 86 returns a pointer to the new string */
michael@0 87 {
michael@0 88 int remaining = length;
michael@0 89 char *write_pos;
michael@0 90 char *new;
michael@0 91
michael@0 92 new = write_pos = (char *) PORT_Alloc (length);
michael@0 93 if (new == NULL) {
michael@0 94 error_allocate();
michael@0 95 }
michael@0 96 while (*read_pos != sentinal_value) {
michael@0 97 if (remaining == 1) {
michael@0 98 remaining += length;
michael@0 99 length = length * 2;
michael@0 100 new = PORT_Realloc(new,length);
michael@0 101 if (new == NULL) {
michael@0 102 error_allocate();
michael@0 103 }
michael@0 104 write_pos = new + length - remaining;
michael@0 105 }
michael@0 106 *write_pos = *read_pos;
michael@0 107 ++write_pos;
michael@0 108 ++read_pos;
michael@0 109 remaining = remaining - 1;
michael@0 110 }
michael@0 111 *write_pos = '\0';
michael@0 112 return new;
michael@0 113 }
michael@0 114
michael@0 115
michael@0 116 static SECStatus
michael@0 117 clean_input(Pair *data)
michael@0 118 /* converts the non-alphanumeric characters in a form post
michael@0 119 from hex codes back to characters */
michael@0 120 {
michael@0 121 int length;
michael@0 122 int hi_digit;
michael@0 123 int low_digit;
michael@0 124 char character;
michael@0 125 char *begin_pos;
michael@0 126 char *read_pos;
michael@0 127 char *write_pos;
michael@0 128 PRBool name = PR_TRUE;
michael@0 129
michael@0 130 begin_pos = data->name;
michael@0 131 while (begin_pos != NULL) {
michael@0 132 length = strlen(begin_pos);
michael@0 133 read_pos = write_pos = begin_pos;
michael@0 134 while ((read_pos - begin_pos) < length) {
michael@0 135 if (*read_pos == '+') {
michael@0 136 *read_pos = ' ';
michael@0 137 }
michael@0 138 if (*read_pos == '%') {
michael@0 139 hi_digit = *(read_pos + 1);
michael@0 140 low_digit = *(read_pos +2);
michael@0 141 read_pos += 3;
michael@0 142 if (isdigit(hi_digit)){
michael@0 143 hi_digit = hi_digit - '0';
michael@0 144 } else {
michael@0 145 hi_digit = toupper(hi_digit);
michael@0 146 if (isxdigit(hi_digit)) {
michael@0 147 hi_digit = (hi_digit - 'A') + 10;
michael@0 148 } else {
michael@0 149 error_out("ERROR: Form data incorrectly formated");
michael@0 150 }
michael@0 151 }
michael@0 152 if (isdigit(low_digit)){
michael@0 153 low_digit = low_digit - '0';
michael@0 154 } else {
michael@0 155 low_digit = toupper(low_digit);
michael@0 156 if ((low_digit >='A') && (low_digit <= 'F')) {
michael@0 157 low_digit = (low_digit - 'A') + 10;
michael@0 158 } else {
michael@0 159 error_out("ERROR: Form data incorrectly formated");
michael@0 160 }
michael@0 161 }
michael@0 162 character = (hi_digit << 4) | low_digit;
michael@0 163 if (character != 10) {
michael@0 164 *write_pos = character;
michael@0 165 ++write_pos;
michael@0 166 }
michael@0 167 } else {
michael@0 168 *write_pos = *read_pos;
michael@0 169 ++write_pos;
michael@0 170 ++read_pos;
michael@0 171 }
michael@0 172 }
michael@0 173 *write_pos = '\0';
michael@0 174 if (name == PR_TRUE) {
michael@0 175 begin_pos = data->data;
michael@0 176 name = PR_FALSE;
michael@0 177 } else {
michael@0 178 data++;
michael@0 179 begin_pos = data->name;
michael@0 180 name = PR_TRUE;
michael@0 181 }
michael@0 182 }
michael@0 183 return SECSuccess;
michael@0 184 }
michael@0 185
michael@0 186 static char *
michael@0 187 make_name(char *new_data)
michael@0 188 /* gets the next field name in the input string and returns
michael@0 189 a pointer to a string containing a copy of it */
michael@0 190 {
michael@0 191 int length = 20;
michael@0 192 char *name;
michael@0 193
michael@0 194 name = make_copy_string(new_data, length, '=');
michael@0 195 return name;
michael@0 196 }
michael@0 197
michael@0 198 static char *
michael@0 199 make_data(char *new_data)
michael@0 200 /* gets the data for the next field in the input string
michael@0 201 and returns a pointer to a string containing it */
michael@0 202 {
michael@0 203 int length = 100;
michael@0 204 char *data;
michael@0 205 char *read_pos;
michael@0 206
michael@0 207 read_pos = new_data;
michael@0 208 while (*(read_pos - 1) != '=') {
michael@0 209 ++read_pos;
michael@0 210 }
michael@0 211 data = make_copy_string(read_pos, length, '&');
michael@0 212 return data;
michael@0 213 }
michael@0 214
michael@0 215
michael@0 216 static Pair
michael@0 217 make_pair(char *new_data)
michael@0 218 /* makes a pair name/data pair from the input string */
michael@0 219 {
michael@0 220 Pair temp;
michael@0 221
michael@0 222 temp.name = make_name(new_data);
michael@0 223 temp.data = make_data(new_data);
michael@0 224 return temp;
michael@0 225 }
michael@0 226
michael@0 227
michael@0 228
michael@0 229 static Pair *
michael@0 230 make_datastruct(char *data, int len)
michael@0 231 /* parses the input from the form post into a data
michael@0 232 structure of field name/data pairs */
michael@0 233 {
michael@0 234 Pair *datastruct;
michael@0 235 Pair *current;
michael@0 236 char *curr_pos;
michael@0 237 int fields = START_FIELDS;
michael@0 238 int remaining = START_FIELDS;
michael@0 239
michael@0 240 curr_pos = data;
michael@0 241 datastruct = current = (Pair *) PORT_Alloc(fields * sizeof(Pair));
michael@0 242 if (datastruct == NULL) {
michael@0 243 error_allocate();
michael@0 244 }
michael@0 245 while (curr_pos - data < len) {
michael@0 246 if (remaining == 1) {
michael@0 247 remaining += fields;
michael@0 248 fields = fields * 2;
michael@0 249 datastruct = (Pair *) PORT_Realloc
michael@0 250 (datastruct, fields * sizeof(Pair));
michael@0 251 if (datastruct == NULL) {
michael@0 252 error_allocate();
michael@0 253 }
michael@0 254 current = datastruct + (fields - remaining);
michael@0 255 }
michael@0 256 *current = make_pair(curr_pos);
michael@0 257 while (*curr_pos != '&') {
michael@0 258 ++curr_pos;
michael@0 259 }
michael@0 260 ++curr_pos;
michael@0 261 ++current;
michael@0 262 remaining = remaining - 1;
michael@0 263 }
michael@0 264 current->name = NULL;
michael@0 265 return datastruct;
michael@0 266 }
michael@0 267
michael@0 268 static char *
michael@0 269 return_name(Pair *data_struct,
michael@0 270 int n)
michael@0 271 /* returns a pointer to the name of the nth
michael@0 272 (starting from 0) item in the data structure */
michael@0 273 {
michael@0 274 char *name;
michael@0 275
michael@0 276 if ((data_struct + n)->name != NULL) {
michael@0 277 name = (data_struct + n)->name;
michael@0 278 return name;
michael@0 279 } else {
michael@0 280 return NULL;
michael@0 281 }
michael@0 282 }
michael@0 283
michael@0 284 static char *
michael@0 285 return_data(Pair *data_struct,int n)
michael@0 286 /* returns a pointer to the data of the nth (starting from 0)
michael@0 287 itme in the data structure */
michael@0 288 {
michael@0 289 char *data;
michael@0 290
michael@0 291 data = (data_struct + n)->data;
michael@0 292 return data;
michael@0 293 }
michael@0 294
michael@0 295
michael@0 296 static char *
michael@0 297 add_prefix(char *field_name)
michael@0 298 {
michael@0 299 extern char prefix[PREFIX_LEN];
michael@0 300 int i = 0;
michael@0 301 char *rv;
michael@0 302 char *write;
michael@0 303
michael@0 304 rv = write = PORT_Alloc(PORT_Strlen(prefix) + PORT_Strlen(field_name) + 1);
michael@0 305 for(i = 0; i < PORT_Strlen(prefix); i++) {
michael@0 306 *write = prefix[i];
michael@0 307 write++;
michael@0 308 }
michael@0 309 *write = '\0';
michael@0 310 rv = PORT_Strcat(rv,field_name);
michael@0 311 return rv;
michael@0 312 }
michael@0 313
michael@0 314
michael@0 315 static char *
michael@0 316 find_field(Pair *data,
michael@0 317 char *field_name,
michael@0 318 PRBool add_pre)
michael@0 319 /* returns a pointer to the data of the first pair
michael@0 320 thats name matches the string it is passed */
michael@0 321 {
michael@0 322 int i = 0;
michael@0 323 char *retrieved;
michael@0 324 int found = 0;
michael@0 325
michael@0 326 if (add_pre) {
michael@0 327 field_name = add_prefix(field_name);
michael@0 328 }
michael@0 329 while(return_name(data, i) != NULL) {
michael@0 330 if (PORT_Strcmp(return_name(data, i), field_name) == 0) {
michael@0 331 retrieved = return_data(data, i);
michael@0 332 found = 1;
michael@0 333 break;
michael@0 334 }
michael@0 335 i++;
michael@0 336 }
michael@0 337 if (!found) {
michael@0 338 retrieved = NULL;
michael@0 339 }
michael@0 340 return retrieved;
michael@0 341 }
michael@0 342
michael@0 343 static PRBool
michael@0 344 find_field_bool(Pair *data,
michael@0 345 char *fieldname,
michael@0 346 PRBool add_pre)
michael@0 347 {
michael@0 348 char *rv;
michael@0 349
michael@0 350 rv = find_field(data, fieldname, add_pre);
michael@0 351
michael@0 352 if ((rv != NULL) && (PORT_Strcmp(rv, "true")) == 0) {
michael@0 353 return PR_TRUE;
michael@0 354 } else {
michael@0 355 return PR_FALSE;
michael@0 356 }
michael@0 357 }
michael@0 358
michael@0 359 static char *
michael@0 360 update_data_by_name(Pair *data,
michael@0 361 char *field_name,
michael@0 362 char *new_data)
michael@0 363 /* replaces the data in the data structure associated with
michael@0 364 a name with new data, returns null if not found */
michael@0 365 {
michael@0 366 int i = 0;
michael@0 367 int found = 0;
michael@0 368 int length = 100;
michael@0 369 char *new;
michael@0 370
michael@0 371 while (return_name(data, i) != NULL) {
michael@0 372 if (PORT_Strcmp(return_name(data, i), field_name) == 0) {
michael@0 373 new = make_copy_string( new_data, length, '\0');
michael@0 374 PORT_Free(return_data(data, i));
michael@0 375 found = 1;
michael@0 376 (*(data + i)).data = new;
michael@0 377 break;
michael@0 378 }
michael@0 379 i++;
michael@0 380 }
michael@0 381 if (!found) {
michael@0 382 new = NULL;
michael@0 383 }
michael@0 384 return new;
michael@0 385 }
michael@0 386
michael@0 387 static char *
michael@0 388 update_data_by_index(Pair *data,
michael@0 389 int n,
michael@0 390 char *new_data)
michael@0 391 /* replaces the data of a particular index in the data structure */
michael@0 392 {
michael@0 393 int length = 100;
michael@0 394 char *new;
michael@0 395
michael@0 396 new = make_copy_string(new_data, length, '\0');
michael@0 397 PORT_Free(return_data(data, n));
michael@0 398 (*(data + n)).data = new;
michael@0 399 return new;
michael@0 400 }
michael@0 401
michael@0 402
michael@0 403 static Pair *
michael@0 404 add_field(Pair *data,
michael@0 405 char* field_name,
michael@0 406 char* field_data)
michael@0 407 /* adds a new name/data pair to the data structure */
michael@0 408 {
michael@0 409 int i = 0;
michael@0 410 int j;
michael@0 411 int name_length = 100;
michael@0 412 int data_length = 100;
michael@0 413
michael@0 414 while(return_name(data, i) != NULL) {
michael@0 415 i++;
michael@0 416 }
michael@0 417 j = START_FIELDS;
michael@0 418 while ( j < (i + 1) ) {
michael@0 419 j = j * 2;
michael@0 420 }
michael@0 421 if (j == (i + 1)) {
michael@0 422 data = (Pair *) PORT_Realloc(data, (j * 2) * sizeof(Pair));
michael@0 423 if (data == NULL) {
michael@0 424 error_allocate();
michael@0 425 }
michael@0 426 }
michael@0 427 (*(data + i)).name = make_copy_string(field_name, name_length, '\0');
michael@0 428 (*(data + i)).data = make_copy_string(field_data, data_length, '\0');
michael@0 429 (data + i + 1)->name = NULL;
michael@0 430 return data;
michael@0 431 }
michael@0 432
michael@0 433
michael@0 434 static CERTCertificateRequest *
michael@0 435 makeCertReq(Pair *form_data,
michael@0 436 int which_priv_key)
michael@0 437 /* makes and encodes a certrequest */
michael@0 438 {
michael@0 439
michael@0 440 PK11SlotInfo *slot;
michael@0 441 CERTCertificateRequest *certReq = NULL;
michael@0 442 CERTSubjectPublicKeyInfo *spki;
michael@0 443 SECKEYPrivateKey *privkey = NULL;
michael@0 444 SECKEYPublicKey *pubkey = NULL;
michael@0 445 CERTName *name;
michael@0 446 char *key;
michael@0 447 extern SECKEYPrivateKey *privkeys[9];
michael@0 448 int keySizeInBits;
michael@0 449 char *challenge = "foo";
michael@0 450 SECStatus rv = SECSuccess;
michael@0 451 PQGParams *pqgParams = NULL;
michael@0 452 PQGVerify *pqgVfy = NULL;
michael@0 453
michael@0 454 name = CERT_AsciiToName(find_field(form_data, "subject", PR_TRUE));
michael@0 455 if (name == NULL) {
michael@0 456 error_out("ERROR: Unable to create Subject Name");
michael@0 457 }
michael@0 458 key = find_field(form_data, "key", PR_TRUE);
michael@0 459 if (key == NULL) {
michael@0 460 switch (*find_field(form_data, "keysize", PR_TRUE)) {
michael@0 461 case '0':
michael@0 462 keySizeInBits = 2048;
michael@0 463 break;
michael@0 464 case '1':
michael@0 465 keySizeInBits = 1024;
michael@0 466 break;
michael@0 467 case '2':
michael@0 468 keySizeInBits = 512;
michael@0 469 break;
michael@0 470 default:
michael@0 471 error_out("ERROR: Unsupported Key length selected");
michael@0 472 }
michael@0 473 if (find_field_bool(form_data, "keyType-dsa", PR_TRUE)) {
michael@0 474 rv = PK11_PQG_ParamGen(keySizeInBits, &pqgParams, &pqgVfy);
michael@0 475 if (rv != SECSuccess) {
michael@0 476 error_out("ERROR: Unable to generate PQG parameters");
michael@0 477 }
michael@0 478 slot = PK11_GetBestSlot(CKM_DSA_KEY_PAIR_GEN, NULL);
michael@0 479 privkey = PK11_GenerateKeyPair(slot, CKM_DSA_KEY_PAIR_GEN,
michael@0 480 pqgParams,&pubkey, PR_FALSE,
michael@0 481 PR_TRUE, NULL);
michael@0 482 } else {
michael@0 483 privkey = SECKEY_CreateRSAPrivateKey(keySizeInBits, &pubkey, NULL);
michael@0 484 }
michael@0 485 privkeys[which_priv_key] = privkey;
michael@0 486 spki = SECKEY_CreateSubjectPublicKeyInfo(pubkey);
michael@0 487 } else {
michael@0 488 spki = SECKEY_ConvertAndDecodePublicKeyAndChallenge(key, challenge,
michael@0 489 NULL);
michael@0 490 if (spki == NULL) {
michael@0 491 error_out("ERROR: Unable to decode Public Key and Challenge String");
michael@0 492 }
michael@0 493 }
michael@0 494 certReq = CERT_CreateCertificateRequest(name, spki, NULL);
michael@0 495 if (certReq == NULL) {
michael@0 496 error_out("ERROR: Unable to create Certificate Request");
michael@0 497 }
michael@0 498 if (pubkey != NULL) {
michael@0 499 SECKEY_DestroyPublicKey(pubkey);
michael@0 500 }
michael@0 501 if (spki != NULL) {
michael@0 502 SECKEY_DestroySubjectPublicKeyInfo(spki);
michael@0 503 }
michael@0 504 if (pqgParams != NULL) {
michael@0 505 PK11_PQG_DestroyParams(pqgParams);
michael@0 506 }
michael@0 507 if (pqgVfy != NULL) {
michael@0 508 PK11_PQG_DestroyVerify(pqgVfy);
michael@0 509 }
michael@0 510 return certReq;
michael@0 511 }
michael@0 512
michael@0 513
michael@0 514
michael@0 515 static CERTCertificate *
michael@0 516 MakeV1Cert(CERTCertDBHandle *handle,
michael@0 517 CERTCertificateRequest *req,
michael@0 518 char *issuerNameStr,
michael@0 519 PRBool selfsign,
michael@0 520 int serialNumber,
michael@0 521 int warpmonths,
michael@0 522 Pair *data)
michael@0 523 {
michael@0 524 CERTCertificate *issuerCert = NULL;
michael@0 525 CERTValidity *validity;
michael@0 526 CERTCertificate *cert = NULL;
michael@0 527 PRExplodedTime printableTime;
michael@0 528 PRTime now,
michael@0 529 after;
michael@0 530 SECStatus rv;
michael@0 531
michael@0 532
michael@0 533
michael@0 534 if ( !selfsign ) {
michael@0 535 issuerCert = CERT_FindCertByNameString(handle, issuerNameStr);
michael@0 536 if (!issuerCert) {
michael@0 537 error_out("ERROR: Could not find issuer's certificate");
michael@0 538 return NULL;
michael@0 539 }
michael@0 540 }
michael@0 541 if (find_field_bool(data, "manValidity", PR_TRUE)) {
michael@0 542 rv = DER_AsciiToTime(&now, find_field(data, "notBefore", PR_TRUE));
michael@0 543 } else {
michael@0 544 now = PR_Now();
michael@0 545 }
michael@0 546 PR_ExplodeTime (now, PR_GMTParameters, &printableTime);
michael@0 547 if ( warpmonths ) {
michael@0 548 printableTime.tm_month += warpmonths;
michael@0 549 now = PR_ImplodeTime (&printableTime);
michael@0 550 PR_ExplodeTime (now, PR_GMTParameters, &printableTime);
michael@0 551 }
michael@0 552 if (find_field_bool(data, "manValidity", PR_TRUE)) {
michael@0 553 rv = DER_AsciiToTime(&after, find_field(data, "notAfter", PR_TRUE));
michael@0 554 PR_ExplodeTime (after, PR_GMTParameters, &printableTime);
michael@0 555 } else {
michael@0 556 printableTime.tm_month += 3;
michael@0 557 after = PR_ImplodeTime (&printableTime);
michael@0 558 }
michael@0 559 /* note that the time is now in micro-second unit */
michael@0 560 validity = CERT_CreateValidity (now, after);
michael@0 561
michael@0 562 if ( selfsign ) {
michael@0 563 cert = CERT_CreateCertificate
michael@0 564 (serialNumber,&(req->subject), validity, req);
michael@0 565 } else {
michael@0 566 cert = CERT_CreateCertificate
michael@0 567 (serialNumber,&(issuerCert->subject), validity, req);
michael@0 568 }
michael@0 569
michael@0 570 CERT_DestroyValidity(validity);
michael@0 571 if ( issuerCert ) {
michael@0 572 CERT_DestroyCertificate (issuerCert);
michael@0 573 }
michael@0 574 return(cert);
michael@0 575 }
michael@0 576
michael@0 577 static int
michael@0 578 get_serial_number(Pair *data)
michael@0 579 {
michael@0 580 int serial = 0;
michael@0 581 int error;
michael@0 582 char *filename = SERIAL_FILE;
michael@0 583 char *SN;
michael@0 584 FILE *serialFile;
michael@0 585
michael@0 586
michael@0 587 if (find_field_bool(data, "serial-auto", PR_TRUE)) {
michael@0 588 serialFile = fopen(filename, "r");
michael@0 589 if (serialFile != NULL) {
michael@0 590 fread(&serial, sizeof(int), 1, serialFile);
michael@0 591 if (ferror(serialFile) != 0) {
michael@0 592 error_out("Error: Unable to read serial number file");
michael@0 593 }
michael@0 594 if (serial == 4294967295) {
michael@0 595 serial = 21;
michael@0 596 }
michael@0 597 fclose(serialFile);
michael@0 598 ++serial;
michael@0 599 serialFile = fopen(filename,"w");
michael@0 600 if (serialFile == NULL) {
michael@0 601 error_out("ERROR: Unable to open serial number file for writing");
michael@0 602 }
michael@0 603 fwrite(&serial, sizeof(int), 1, serialFile);
michael@0 604 if (ferror(serialFile) != 0) {
michael@0 605 error_out("Error: Unable to write to serial number file");
michael@0 606 }
michael@0 607 } else {
michael@0 608 fclose(serialFile);
michael@0 609 serialFile = fopen(filename,"w");
michael@0 610 if (serialFile == NULL) {
michael@0 611 error_out("ERROR: Unable to open serial number file");
michael@0 612 }
michael@0 613 serial = 21;
michael@0 614 fwrite(&serial, sizeof(int), 1, serialFile);
michael@0 615 if (ferror(serialFile) != 0) {
michael@0 616 error_out("Error: Unable to write to serial number file");
michael@0 617 }
michael@0 618 error = ferror(serialFile);
michael@0 619 if (error != 0) {
michael@0 620 error_out("ERROR: Unable to write to serial file");
michael@0 621 }
michael@0 622 }
michael@0 623 fclose(serialFile);
michael@0 624 } else {
michael@0 625 SN = find_field(data, "serial_value", PR_TRUE);
michael@0 626 while (*SN != '\0') {
michael@0 627 serial = serial * 16;
michael@0 628 if ((*SN >= 'A') && (*SN <='F')) {
michael@0 629 serial += *SN - 'A' + 10;
michael@0 630 } else {
michael@0 631 if ((*SN >= 'a') && (*SN <='f')) {
michael@0 632 serial += *SN - 'a' + 10;
michael@0 633 } else {
michael@0 634 serial += *SN - '0';
michael@0 635 }
michael@0 636 }
michael@0 637 ++SN;
michael@0 638 }
michael@0 639 }
michael@0 640 return serial;
michael@0 641 }
michael@0 642
michael@0 643
michael@0 644
michael@0 645 typedef SECStatus (* EXTEN_VALUE_ENCODER)
michael@0 646 (PLArenaPool *extHandle, void *value, SECItem *encodedValue);
michael@0 647
michael@0 648 static SECStatus
michael@0 649 EncodeAndAddExtensionValue(
michael@0 650 PLArenaPool *arena,
michael@0 651 void *extHandle,
michael@0 652 void *value,
michael@0 653 PRBool criticality,
michael@0 654 int extenType,
michael@0 655 EXTEN_VALUE_ENCODER EncodeValueFn)
michael@0 656 {
michael@0 657 SECItem encodedValue;
michael@0 658 SECStatus rv;
michael@0 659
michael@0 660
michael@0 661 encodedValue.data = NULL;
michael@0 662 encodedValue.len = 0;
michael@0 663 rv = (*EncodeValueFn)(arena, value, &encodedValue);
michael@0 664 if (rv != SECSuccess) {
michael@0 665 error_out("ERROR: Unable to encode extension value");
michael@0 666 }
michael@0 667 rv = CERT_AddExtension
michael@0 668 (extHandle, extenType, &encodedValue, criticality, PR_TRUE);
michael@0 669 return (rv);
michael@0 670 }
michael@0 671
michael@0 672
michael@0 673
michael@0 674 static SECStatus
michael@0 675 AddKeyUsage (void *extHandle,
michael@0 676 Pair *data)
michael@0 677 {
michael@0 678 SECItem bitStringValue;
michael@0 679 unsigned char keyUsage = 0x0;
michael@0 680
michael@0 681 if (find_field_bool(data,"keyUsage-digitalSignature", PR_TRUE)){
michael@0 682 keyUsage |= (0x80 >> 0);
michael@0 683 }
michael@0 684 if (find_field_bool(data,"keyUsage-nonRepudiation", PR_TRUE)){
michael@0 685 keyUsage |= (0x80 >> 1);
michael@0 686 }
michael@0 687 if (find_field_bool(data,"keyUsage-keyEncipherment", PR_TRUE)){
michael@0 688 keyUsage |= (0x80 >> 2);
michael@0 689 }
michael@0 690 if (find_field_bool(data,"keyUsage-dataEncipherment", PR_TRUE)){
michael@0 691 keyUsage |= (0x80 >> 3);
michael@0 692 }
michael@0 693 if (find_field_bool(data,"keyUsage-keyAgreement", PR_TRUE)){
michael@0 694 keyUsage |= (0x80 >> 4);
michael@0 695 }
michael@0 696 if (find_field_bool(data,"keyUsage-keyCertSign", PR_TRUE)) {
michael@0 697 keyUsage |= (0x80 >> 5);
michael@0 698 }
michael@0 699 if (find_field_bool(data,"keyUsage-cRLSign", PR_TRUE)) {
michael@0 700 keyUsage |= (0x80 >> 6);
michael@0 701 }
michael@0 702
michael@0 703 bitStringValue.data = &keyUsage;
michael@0 704 bitStringValue.len = 1;
michael@0 705
michael@0 706 return (CERT_EncodeAndAddBitStrExtension
michael@0 707 (extHandle, SEC_OID_X509_KEY_USAGE, &bitStringValue,
michael@0 708 (find_field_bool(data, "keyUsage-crit", PR_TRUE))));
michael@0 709
michael@0 710 }
michael@0 711
michael@0 712 static CERTOidSequence *
michael@0 713 CreateOidSequence(void)
michael@0 714 {
michael@0 715 CERTOidSequence *rv = (CERTOidSequence *)NULL;
michael@0 716 PLArenaPool *arena = (PLArenaPool *)NULL;
michael@0 717
michael@0 718 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 719 if( (PLArenaPool *)NULL == arena ) {
michael@0 720 goto loser;
michael@0 721 }
michael@0 722
michael@0 723 rv = (CERTOidSequence *)PORT_ArenaZAlloc(arena, sizeof(CERTOidSequence));
michael@0 724 if( (CERTOidSequence *)NULL == rv ) {
michael@0 725 goto loser;
michael@0 726 }
michael@0 727
michael@0 728 rv->oids = (SECItem **)PORT_ArenaZAlloc(arena, sizeof(SECItem *));
michael@0 729 if( (SECItem **)NULL == rv->oids ) {
michael@0 730 goto loser;
michael@0 731 }
michael@0 732
michael@0 733 rv->arena = arena;
michael@0 734 return rv;
michael@0 735
michael@0 736 loser:
michael@0 737 if( (PLArenaPool *)NULL != arena ) {
michael@0 738 PORT_FreeArena(arena, PR_FALSE);
michael@0 739 }
michael@0 740
michael@0 741 return (CERTOidSequence *)NULL;
michael@0 742 }
michael@0 743
michael@0 744 static SECStatus
michael@0 745 AddOidToSequence(CERTOidSequence *os, SECOidTag oidTag)
michael@0 746 {
michael@0 747 SECItem **oids;
michael@0 748 PRUint32 count = 0;
michael@0 749 SECOidData *od;
michael@0 750
michael@0 751 od = SECOID_FindOIDByTag(oidTag);
michael@0 752 if( (SECOidData *)NULL == od ) {
michael@0 753 return SECFailure;
michael@0 754 }
michael@0 755
michael@0 756 for( oids = os->oids; (SECItem *)NULL != *oids; oids++ ) {
michael@0 757 count++;
michael@0 758 }
michael@0 759
michael@0 760 /* ArenaZRealloc */
michael@0 761
michael@0 762 {
michael@0 763 PRUint32 i;
michael@0 764
michael@0 765 oids = (SECItem **)PORT_ArenaZAlloc(os->arena, sizeof(SECItem *) * (count+2));
michael@0 766 if( (SECItem **)NULL == oids ) {
michael@0 767 return SECFailure;
michael@0 768 }
michael@0 769
michael@0 770 for( i = 0; i < count; i++ ) {
michael@0 771 oids[i] = os->oids[i];
michael@0 772 }
michael@0 773
michael@0 774 /* ArenaZFree(os->oids); */
michael@0 775 }
michael@0 776
michael@0 777 os->oids = oids;
michael@0 778 os->oids[count] = &od->oid;
michael@0 779
michael@0 780 return SECSuccess;
michael@0 781 }
michael@0 782
michael@0 783 static SECItem *
michael@0 784 EncodeOidSequence(CERTOidSequence *os)
michael@0 785 {
michael@0 786 SECItem *rv;
michael@0 787 extern const SEC_ASN1Template CERT_OidSeqTemplate[];
michael@0 788
michael@0 789 rv = (SECItem *)PORT_ArenaZAlloc(os->arena, sizeof(SECItem));
michael@0 790 if( (SECItem *)NULL == rv ) {
michael@0 791 goto loser;
michael@0 792 }
michael@0 793
michael@0 794 if( !SEC_ASN1EncodeItem(os->arena, rv, os, CERT_OidSeqTemplate) ) {
michael@0 795 goto loser;
michael@0 796 }
michael@0 797
michael@0 798 return rv;
michael@0 799
michael@0 800 loser:
michael@0 801 return (SECItem *)NULL;
michael@0 802 }
michael@0 803
michael@0 804 static SECStatus
michael@0 805 AddExtKeyUsage(void *extHandle, Pair *data)
michael@0 806 {
michael@0 807 SECStatus rv;
michael@0 808 CERTOidSequence *os;
michael@0 809 SECItem *value;
michael@0 810 PRBool crit;
michael@0 811
michael@0 812 os = CreateOidSequence();
michael@0 813 if( (CERTOidSequence *)NULL == os ) {
michael@0 814 return SECFailure;
michael@0 815 }
michael@0 816
michael@0 817 if( find_field_bool(data, "extKeyUsage-serverAuth", PR_TRUE) ) {
michael@0 818 rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_SERVER_AUTH);
michael@0 819 if( SECSuccess != rv ) goto loser;
michael@0 820 }
michael@0 821
michael@0 822 if( find_field_bool(data, "extKeyUsage-msTrustListSign", PR_TRUE) ) {
michael@0 823 rv = AddOidToSequence(os, SEC_OID_MS_EXT_KEY_USAGE_CTL_SIGNING);
michael@0 824 if( SECSuccess != rv ) goto loser;
michael@0 825 }
michael@0 826
michael@0 827 if( find_field_bool(data, "extKeyUsage-clientAuth", PR_TRUE) ) {
michael@0 828 rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH);
michael@0 829 if( SECSuccess != rv ) goto loser;
michael@0 830 }
michael@0 831
michael@0 832 if( find_field_bool(data, "extKeyUsage-codeSign", PR_TRUE) ) {
michael@0 833 rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_CODE_SIGN);
michael@0 834 if( SECSuccess != rv ) goto loser;
michael@0 835 }
michael@0 836
michael@0 837 if( find_field_bool(data, "extKeyUsage-emailProtect", PR_TRUE) ) {
michael@0 838 rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT);
michael@0 839 if( SECSuccess != rv ) goto loser;
michael@0 840 }
michael@0 841
michael@0 842 if( find_field_bool(data, "extKeyUsage-timeStamp", PR_TRUE) ) {
michael@0 843 rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_TIME_STAMP);
michael@0 844 if( SECSuccess != rv ) goto loser;
michael@0 845 }
michael@0 846
michael@0 847 if( find_field_bool(data, "extKeyUsage-ocspResponder", PR_TRUE) ) {
michael@0 848 rv = AddOidToSequence(os, SEC_OID_OCSP_RESPONDER);
michael@0 849 if( SECSuccess != rv ) goto loser;
michael@0 850 }
michael@0 851
michael@0 852 if( find_field_bool(data, "extKeyUsage-NS-govtApproved", PR_TRUE) ) {
michael@0 853 rv = AddOidToSequence(os, SEC_OID_NS_KEY_USAGE_GOVT_APPROVED);
michael@0 854 if( SECSuccess != rv ) goto loser;
michael@0 855 }
michael@0 856
michael@0 857 value = EncodeOidSequence(os);
michael@0 858
michael@0 859 crit = find_field_bool(data, "extKeyUsage-crit", PR_TRUE);
michael@0 860
michael@0 861 rv = CERT_AddExtension(extHandle, SEC_OID_X509_EXT_KEY_USAGE, value,
michael@0 862 crit, PR_TRUE);
michael@0 863 /*FALLTHROUGH*/
michael@0 864 loser:
michael@0 865 CERT_DestroyOidSequence(os);
michael@0 866 return rv;
michael@0 867 }
michael@0 868
michael@0 869 static SECStatus
michael@0 870 AddSubKeyID(void *extHandle,
michael@0 871 Pair *data,
michael@0 872 CERTCertificate *subjectCert)
michael@0 873 {
michael@0 874 SECItem encodedValue;
michael@0 875 SECStatus rv;
michael@0 876 char *read;
michael@0 877 char *write;
michael@0 878 char *first;
michael@0 879 char character;
michael@0 880 int high_digit = 0,
michael@0 881 low_digit = 0;
michael@0 882 int len;
michael@0 883 PRBool odd = PR_FALSE;
michael@0 884
michael@0 885
michael@0 886 encodedValue.data = NULL;
michael@0 887 encodedValue.len = 0;
michael@0 888 first = read = write = find_field(data,"subjectKeyIdentifier-text",
michael@0 889 PR_TRUE);
michael@0 890 len = PORT_Strlen(first);
michael@0 891 odd = ((len % 2) != 0 ) ? PR_TRUE : PR_FALSE;
michael@0 892 if (find_field_bool(data, "subjectKeyIdentifier-radio-hex", PR_TRUE)) {
michael@0 893 if (odd) {
michael@0 894 error_out("ERROR: Improperly formated subject key identifier, hex values must be expressed as an octet string");
michael@0 895 }
michael@0 896 while (*read != '\0') {
michael@0 897 if (!isxdigit(*read)) {
michael@0 898 error_out("ERROR: Improperly formated subject key identifier");
michael@0 899 }
michael@0 900 *read = toupper(*read);
michael@0 901 if ((*read >= 'A') && (*read <= 'F')) {
michael@0 902 high_digit = *read - 'A' + 10;
michael@0 903 } else {
michael@0 904 high_digit = *read - '0';
michael@0 905 }
michael@0 906 ++read;
michael@0 907 if (!isxdigit(*read)) {
michael@0 908 error_out("ERROR: Improperly formated subject key identifier");
michael@0 909 }
michael@0 910 *read = toupper(*read);
michael@0 911 if ((*read >= 'A') && (*read <= 'F')) {
michael@0 912 low_digit = *(read) - 'A' + 10;
michael@0 913 } else {
michael@0 914 low_digit = *(read) - '0';
michael@0 915 }
michael@0 916 character = (high_digit << 4) | low_digit;
michael@0 917 *write = character;
michael@0 918 ++write;
michael@0 919 ++read;
michael@0 920 }
michael@0 921 *write = '\0';
michael@0 922 len = write - first;
michael@0 923 }
michael@0 924 subjectCert->subjectKeyID.data = (unsigned char *) find_field
michael@0 925 (data,"subjectKeyIdentifier-text", PR_TRUE);
michael@0 926 subjectCert->subjectKeyID.len = len;
michael@0 927 rv = CERT_EncodeSubjectKeyID
michael@0 928 (NULL, &subjectCert->subjectKeyID, &encodedValue);
michael@0 929 if (rv) {
michael@0 930 return (rv);
michael@0 931 }
michael@0 932 return (CERT_AddExtension(extHandle, SEC_OID_X509_SUBJECT_KEY_ID,
michael@0 933 &encodedValue, PR_FALSE, PR_TRUE));
michael@0 934 }
michael@0 935
michael@0 936
michael@0 937 static SECStatus
michael@0 938 AddAuthKeyID (void *extHandle,
michael@0 939 Pair *data,
michael@0 940 char *issuerNameStr,
michael@0 941 CERTCertDBHandle *handle)
michael@0 942 {
michael@0 943 CERTAuthKeyID *authKeyID = NULL;
michael@0 944 PLArenaPool *arena = NULL;
michael@0 945 SECStatus rv = SECSuccess;
michael@0 946 CERTCertificate *issuerCert = NULL;
michael@0 947 CERTGeneralName *genNames;
michael@0 948 CERTName *directoryName = NULL;
michael@0 949
michael@0 950
michael@0 951 issuerCert = CERT_FindCertByNameString(handle, issuerNameStr);
michael@0 952 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 953 if ( !arena ) {
michael@0 954 error_allocate();
michael@0 955 }
michael@0 956
michael@0 957 authKeyID = PORT_ArenaZAlloc (arena, sizeof (CERTAuthKeyID));
michael@0 958 if (authKeyID == NULL) {
michael@0 959 error_allocate();
michael@0 960 }
michael@0 961 if (find_field_bool(data, "authorityKeyIdentifier-radio-keyIdentifier",
michael@0 962 PR_TRUE)) {
michael@0 963 authKeyID->keyID.data = PORT_ArenaAlloc (arena, PORT_Strlen
michael@0 964 ((char *)issuerCert->subjectKeyID.data));
michael@0 965 if (authKeyID->keyID.data == NULL) {
michael@0 966 error_allocate();
michael@0 967 }
michael@0 968 PORT_Memcpy (authKeyID->keyID.data, issuerCert->subjectKeyID.data,
michael@0 969 authKeyID->keyID.len =
michael@0 970 PORT_Strlen((char *)issuerCert->subjectKeyID.data));
michael@0 971 } else {
michael@0 972
michael@0 973 PORT_Assert (arena);
michael@0 974 genNames = (CERTGeneralName *) PORT_ArenaZAlloc (arena, (sizeof(CERTGeneralName)));
michael@0 975 if (genNames == NULL){
michael@0 976 error_allocate();
michael@0 977 }
michael@0 978 genNames->l.next = genNames->l.prev = &(genNames->l);
michael@0 979 genNames->type = certDirectoryName;
michael@0 980
michael@0 981 directoryName = CERT_AsciiToName(issuerCert->subjectName);
michael@0 982 if (!directoryName) {
michael@0 983 error_out("ERROR: Unable to create Directory Name");
michael@0 984 }
michael@0 985 rv = CERT_CopyName (arena, &genNames->name.directoryName,
michael@0 986 directoryName);
michael@0 987 CERT_DestroyName (directoryName);
michael@0 988 if (rv != SECSuccess) {
michael@0 989 error_out("ERROR: Unable to copy Directory Name");
michael@0 990 }
michael@0 991 authKeyID->authCertIssuer = genNames;
michael@0 992 if (authKeyID->authCertIssuer == NULL && SECFailure ==
michael@0 993 PORT_GetError ()) {
michael@0 994 error_out("ERROR: Unable to get Issuer General Name for Authority Key ID Extension");
michael@0 995 }
michael@0 996 authKeyID->authCertSerialNumber = issuerCert->serialNumber;
michael@0 997 }
michael@0 998 rv = EncodeAndAddExtensionValue(arena, extHandle, authKeyID, PR_FALSE,
michael@0 999 SEC_OID_X509_AUTH_KEY_ID,
michael@0 1000 (EXTEN_VALUE_ENCODER)
michael@0 1001 CERT_EncodeAuthKeyID);
michael@0 1002 if (arena) {
michael@0 1003 PORT_FreeArena (arena, PR_FALSE);
michael@0 1004 }
michael@0 1005 return (rv);
michael@0 1006 }
michael@0 1007
michael@0 1008
michael@0 1009 static SECStatus
michael@0 1010 AddPrivKeyUsagePeriod(void *extHandle,
michael@0 1011 Pair *data,
michael@0 1012 CERTCertificate *cert)
michael@0 1013 {
michael@0 1014 char *notBeforeStr;
michael@0 1015 char *notAfterStr;
michael@0 1016 PLArenaPool *arena = NULL;
michael@0 1017 SECStatus rv = SECSuccess;
michael@0 1018 CERTPrivKeyUsagePeriod *pkup;
michael@0 1019
michael@0 1020
michael@0 1021 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 1022 if ( !arena ) {
michael@0 1023 error_allocate();
michael@0 1024 }
michael@0 1025 pkup = PORT_ArenaZNew (arena, CERTPrivKeyUsagePeriod);
michael@0 1026 if (pkup == NULL) {
michael@0 1027 error_allocate();
michael@0 1028 }
michael@0 1029 notBeforeStr = (char *) PORT_Alloc(16 );
michael@0 1030 notAfterStr = (char *) PORT_Alloc(16 );
michael@0 1031 *notBeforeStr = '\0';
michael@0 1032 *notAfterStr = '\0';
michael@0 1033 pkup->arena = arena;
michael@0 1034 pkup->notBefore.len = 0;
michael@0 1035 pkup->notBefore.data = NULL;
michael@0 1036 pkup->notAfter.len = 0;
michael@0 1037 pkup->notAfter.data = NULL;
michael@0 1038 if (find_field_bool(data, "privKeyUsagePeriod-radio-notBefore", PR_TRUE) ||
michael@0 1039 find_field_bool(data, "privKeyUsagePeriod-radio-both", PR_TRUE)) {
michael@0 1040 pkup->notBefore.len = 15;
michael@0 1041 pkup->notBefore.data = (unsigned char *)notBeforeStr;
michael@0 1042 if (find_field_bool(data, "privKeyUsagePeriod-notBefore-radio-manual",
michael@0 1043 PR_TRUE)) {
michael@0 1044 PORT_Strcat(notBeforeStr,find_field(data,
michael@0 1045 "privKeyUsagePeriod-notBefore-year",
michael@0 1046 PR_TRUE));
michael@0 1047 PORT_Strcat(notBeforeStr,find_field(data,
michael@0 1048 "privKeyUsagePeriod-notBefore-month",
michael@0 1049 PR_TRUE));
michael@0 1050 PORT_Strcat(notBeforeStr,find_field(data,
michael@0 1051 "privKeyUsagePeriod-notBefore-day",
michael@0 1052 PR_TRUE));
michael@0 1053 PORT_Strcat(notBeforeStr,find_field(data,
michael@0 1054 "privKeyUsagePeriod-notBefore-hour",
michael@0 1055 PR_TRUE));
michael@0 1056 PORT_Strcat(notBeforeStr,find_field(data,
michael@0 1057 "privKeyUsagePeriod-notBefore-minute",
michael@0 1058 PR_TRUE));
michael@0 1059 PORT_Strcat(notBeforeStr,find_field(data,
michael@0 1060 "privKeyUsagePeriod-notBefore-second",
michael@0 1061 PR_TRUE));
michael@0 1062 if ((*(notBeforeStr + 14) != '\0') ||
michael@0 1063 (!isdigit(*(notBeforeStr + 13))) ||
michael@0 1064 (*(notBeforeStr + 12) >= '5' && *(notBeforeStr + 12) <= '0') ||
michael@0 1065 (!isdigit(*(notBeforeStr + 11))) ||
michael@0 1066 (*(notBeforeStr + 10) >= '5' && *(notBeforeStr + 10) <= '0') ||
michael@0 1067 (!isdigit(*(notBeforeStr + 9))) ||
michael@0 1068 (*(notBeforeStr + 8) >= '2' && *(notBeforeStr + 8) <= '0') ||
michael@0 1069 (!isdigit(*(notBeforeStr + 7))) ||
michael@0 1070 (*(notBeforeStr + 6) >= '3' && *(notBeforeStr + 6) <= '0') ||
michael@0 1071 (!isdigit(*(notBeforeStr + 5))) ||
michael@0 1072 (*(notBeforeStr + 4) >= '1' && *(notBeforeStr + 4) <= '0') ||
michael@0 1073 (!isdigit(*(notBeforeStr + 3))) ||
michael@0 1074 (!isdigit(*(notBeforeStr + 2))) ||
michael@0 1075 (!isdigit(*(notBeforeStr + 1))) ||
michael@0 1076 (!isdigit(*(notBeforeStr + 0))) ||
michael@0 1077 (*(notBeforeStr + 8) == '2' && *(notBeforeStr + 9) >= '4') ||
michael@0 1078 (*(notBeforeStr + 6) == '3' && *(notBeforeStr + 7) >= '1') ||
michael@0 1079 (*(notBeforeStr + 4) == '1' && *(notBeforeStr + 5) >= '2')) {
michael@0 1080 error_out("ERROR: Improperly formated private key usage period");
michael@0 1081 }
michael@0 1082 *(notBeforeStr + 14) = 'Z';
michael@0 1083 *(notBeforeStr + 15) = '\0';
michael@0 1084 } else {
michael@0 1085 if ((*(cert->validity.notBefore.data) > '5') ||
michael@0 1086 ((*(cert->validity.notBefore.data) == '5') &&
michael@0 1087 (*(cert->validity.notBefore.data + 1) != '0'))) {
michael@0 1088 PORT_Strcat(notBeforeStr, "19");
michael@0 1089 } else {
michael@0 1090 PORT_Strcat(notBeforeStr, "20");
michael@0 1091 }
michael@0 1092 PORT_Strcat(notBeforeStr, (char *)cert->validity.notBefore.data);
michael@0 1093 }
michael@0 1094 }
michael@0 1095 if (find_field_bool(data, "privKeyUsagePeriod-radio-notAfter", PR_TRUE) ||
michael@0 1096 find_field_bool(data, "privKeyUsagePeriod-radio-both", PR_TRUE)) {
michael@0 1097 pkup->notAfter.len = 15;
michael@0 1098 pkup->notAfter.data = (unsigned char *)notAfterStr;
michael@0 1099 PORT_Strcat(notAfterStr,find_field(data,"privKeyUsagePeriod-notAfter-year",
michael@0 1100 PR_TRUE));
michael@0 1101 PORT_Strcat(notAfterStr,find_field(data,"privKeyUsagePeriod-notAfter-month",
michael@0 1102 PR_TRUE));
michael@0 1103 PORT_Strcat(notAfterStr,find_field(data,"privKeyUsagePeriod-notAfter-day",
michael@0 1104 PR_TRUE));
michael@0 1105 PORT_Strcat(notAfterStr,find_field(data,"privKeyUsagePeriod-notAfter-hour",
michael@0 1106 PR_TRUE));
michael@0 1107 PORT_Strcat(notAfterStr,find_field(data,"privKeyUsagePeriod-notAfter-minute",
michael@0 1108 PR_TRUE));
michael@0 1109 PORT_Strcat(notAfterStr,find_field(data,"privKeyUsagePeriod-notAfter-second",
michael@0 1110 PR_TRUE));
michael@0 1111 if ((*(notAfterStr + 14) != '\0') ||
michael@0 1112 (!isdigit(*(notAfterStr + 13))) ||
michael@0 1113 (*(notAfterStr + 12) >= '5' && *(notAfterStr + 12) <= '0') ||
michael@0 1114 (!isdigit(*(notAfterStr + 11))) ||
michael@0 1115 (*(notAfterStr + 10) >= '5' && *(notAfterStr + 10) <= '0') ||
michael@0 1116 (!isdigit(*(notAfterStr + 9))) ||
michael@0 1117 (*(notAfterStr + 8) >= '2' && *(notAfterStr + 8) <= '0') ||
michael@0 1118 (!isdigit(*(notAfterStr + 7))) ||
michael@0 1119 (*(notAfterStr + 6) >= '3' && *(notAfterStr + 6) <= '0') ||
michael@0 1120 (!isdigit(*(notAfterStr + 5))) ||
michael@0 1121 (*(notAfterStr + 4) >= '1' && *(notAfterStr + 4) <= '0') ||
michael@0 1122 (!isdigit(*(notAfterStr + 3))) ||
michael@0 1123 (!isdigit(*(notAfterStr + 2))) ||
michael@0 1124 (!isdigit(*(notAfterStr + 1))) ||
michael@0 1125 (!isdigit(*(notAfterStr + 0))) ||
michael@0 1126 (*(notAfterStr + 8) == '2' && *(notAfterStr + 9) >= '4') ||
michael@0 1127 (*(notAfterStr + 6) == '3' && *(notAfterStr + 7) >= '1') ||
michael@0 1128 (*(notAfterStr + 4) == '1' && *(notAfterStr + 5) >= '2')) {
michael@0 1129 error_out("ERROR: Improperly formated private key usage period");
michael@0 1130 }
michael@0 1131 *(notAfterStr + 14) = 'Z';
michael@0 1132 *(notAfterStr + 15) = '\0';
michael@0 1133 }
michael@0 1134
michael@0 1135 PORT_Assert (arena);
michael@0 1136
michael@0 1137 rv = EncodeAndAddExtensionValue(arena, extHandle, pkup,
michael@0 1138 find_field_bool(data,
michael@0 1139 "privKeyUsagePeriod-crit",
michael@0 1140 PR_TRUE),
michael@0 1141 SEC_OID_X509_PRIVATE_KEY_USAGE_PERIOD,
michael@0 1142 (EXTEN_VALUE_ENCODER)
michael@0 1143 CERT_EncodePrivateKeyUsagePeriod);
michael@0 1144 if (arena) {
michael@0 1145 PORT_FreeArena (arena, PR_FALSE);
michael@0 1146 }
michael@0 1147 if (notBeforeStr != NULL) {
michael@0 1148 PORT_Free(notBeforeStr);
michael@0 1149 }
michael@0 1150 if (notAfterStr != NULL) {
michael@0 1151 PORT_Free(notAfterStr);
michael@0 1152 }
michael@0 1153 return (rv);
michael@0 1154 }
michael@0 1155
michael@0 1156 static SECStatus
michael@0 1157 AddBasicConstraint(void *extHandle,
michael@0 1158 Pair *data)
michael@0 1159 {
michael@0 1160 CERTBasicConstraints basicConstraint;
michael@0 1161 SECItem encodedValue;
michael@0 1162 SECStatus rv;
michael@0 1163
michael@0 1164 encodedValue.data = NULL;
michael@0 1165 encodedValue.len = 0;
michael@0 1166 basicConstraint.pathLenConstraint = CERT_UNLIMITED_PATH_CONSTRAINT;
michael@0 1167 basicConstraint.isCA = (find_field_bool(data,"basicConstraints-cA-radio-CA",
michael@0 1168 PR_TRUE));
michael@0 1169 if (find_field_bool(data,"basicConstraints-pathLengthConstraint", PR_TRUE)){
michael@0 1170 basicConstraint.pathLenConstraint = atoi
michael@0 1171 (find_field(data,"basicConstraints-pathLengthConstraint-text",
michael@0 1172 PR_TRUE));
michael@0 1173 }
michael@0 1174
michael@0 1175 rv = CERT_EncodeBasicConstraintValue (NULL, &basicConstraint,
michael@0 1176 &encodedValue);
michael@0 1177 if (rv)
michael@0 1178 return (rv);
michael@0 1179 rv = CERT_AddExtension(extHandle, SEC_OID_X509_BASIC_CONSTRAINTS,
michael@0 1180 &encodedValue,
michael@0 1181 (find_field_bool(data,"basicConstraints-crit",
michael@0 1182 PR_TRUE)), PR_TRUE);
michael@0 1183
michael@0 1184 PORT_Free (encodedValue.data);
michael@0 1185 return (rv);
michael@0 1186 }
michael@0 1187
michael@0 1188
michael@0 1189
michael@0 1190 static SECStatus
michael@0 1191 AddNscpCertType (void *extHandle,
michael@0 1192 Pair *data)
michael@0 1193 {
michael@0 1194 SECItem bitStringValue;
michael@0 1195 unsigned char CertType = 0x0;
michael@0 1196
michael@0 1197 if (find_field_bool(data,"netscape-cert-type-ssl-client", PR_TRUE)){
michael@0 1198 CertType |= (0x80 >> 0);
michael@0 1199 }
michael@0 1200 if (find_field_bool(data,"netscape-cert-type-ssl-server", PR_TRUE)){
michael@0 1201 CertType |= (0x80 >> 1);
michael@0 1202 }
michael@0 1203 if (find_field_bool(data,"netscape-cert-type-smime", PR_TRUE)){
michael@0 1204 CertType |= (0x80 >> 2);
michael@0 1205 }
michael@0 1206 if (find_field_bool(data,"netscape-cert-type-object-signing", PR_TRUE)){
michael@0 1207 CertType |= (0x80 >> 3);
michael@0 1208 }
michael@0 1209 if (find_field_bool(data,"netscape-cert-type-reserved", PR_TRUE)){
michael@0 1210 CertType |= (0x80 >> 4);
michael@0 1211 }
michael@0 1212 if (find_field_bool(data,"netscape-cert-type-ssl-ca", PR_TRUE)) {
michael@0 1213 CertType |= (0x80 >> 5);
michael@0 1214 }
michael@0 1215 if (find_field_bool(data,"netscape-cert-type-smime-ca", PR_TRUE)) {
michael@0 1216 CertType |= (0x80 >> 6);
michael@0 1217 }
michael@0 1218 if (find_field_bool(data,"netscape-cert-type-object-signing-ca", PR_TRUE)) {
michael@0 1219 CertType |= (0x80 >> 7);
michael@0 1220 }
michael@0 1221
michael@0 1222 bitStringValue.data = &CertType;
michael@0 1223 bitStringValue.len = 1;
michael@0 1224
michael@0 1225 return (CERT_EncodeAndAddBitStrExtension
michael@0 1226 (extHandle, SEC_OID_NS_CERT_EXT_CERT_TYPE, &bitStringValue,
michael@0 1227 (find_field_bool(data, "netscape-cert-type-crit", PR_TRUE))));
michael@0 1228 }
michael@0 1229
michael@0 1230
michael@0 1231 static SECStatus
michael@0 1232 add_IA5StringExtension(void *extHandle,
michael@0 1233 char *string,
michael@0 1234 PRBool crit,
michael@0 1235 int idtag)
michael@0 1236 {
michael@0 1237 SECItem encodedValue;
michael@0 1238 SECStatus rv;
michael@0 1239
michael@0 1240 encodedValue.data = NULL;
michael@0 1241 encodedValue.len = 0;
michael@0 1242
michael@0 1243 rv = CERT_EncodeIA5TypeExtension(NULL, string, &encodedValue);
michael@0 1244 if (rv) {
michael@0 1245 return (rv);
michael@0 1246 }
michael@0 1247 return (CERT_AddExtension(extHandle, idtag, &encodedValue, crit, PR_TRUE));
michael@0 1248 }
michael@0 1249
michael@0 1250 static SECItem *
michael@0 1251 string_to_oid(char *string)
michael@0 1252 {
michael@0 1253 int i;
michael@0 1254 int length = 20;
michael@0 1255 int remaining;
michael@0 1256 int first_value;
michael@0 1257 int second_value;
michael@0 1258 int value;
michael@0 1259 int oidLength;
michael@0 1260 unsigned char *oidString;
michael@0 1261 unsigned char *write;
michael@0 1262 unsigned char *read;
michael@0 1263 unsigned char *temp;
michael@0 1264 SECItem *oid;
michael@0 1265
michael@0 1266
michael@0 1267 remaining = length;
michael@0 1268 i = 0;
michael@0 1269 while (*string == ' ') {
michael@0 1270 string++;
michael@0 1271 }
michael@0 1272 while (isdigit(*(string + i))) {
michael@0 1273 i++;
michael@0 1274 }
michael@0 1275 if (*(string + i) == '.') {
michael@0 1276 *(string + i) = '\0';
michael@0 1277 } else {
michael@0 1278 error_out("ERROR: Improperly formated OID");
michael@0 1279 }
michael@0 1280 first_value = atoi(string);
michael@0 1281 if (first_value < 0 || first_value > 2) {
michael@0 1282 error_out("ERROR: Improperly formated OID");
michael@0 1283 }
michael@0 1284 string += i + 1;
michael@0 1285 i = 0;
michael@0 1286 while (isdigit(*(string + i))) {
michael@0 1287 i++;
michael@0 1288 }
michael@0 1289 if (*(string + i) == '.') {
michael@0 1290 *(string + i) = '\0';
michael@0 1291 } else {
michael@0 1292 error_out("ERROR: Improperly formated OID");
michael@0 1293 }
michael@0 1294 second_value = atoi(string);
michael@0 1295 if (second_value < 0 || second_value > 39) {
michael@0 1296 error_out("ERROR: Improperly formated OID");
michael@0 1297 }
michael@0 1298 oidString = PORT_ZAlloc(2);
michael@0 1299 *oidString = (first_value * 40) + second_value;
michael@0 1300 *(oidString + 1) = '\0';
michael@0 1301 oidLength = 1;
michael@0 1302 string += i + 1;
michael@0 1303 i = 0;
michael@0 1304 temp = write = PORT_ZAlloc(length);
michael@0 1305 while (*string != '\0') {
michael@0 1306 value = 0;
michael@0 1307 while(isdigit(*(string + i))) {
michael@0 1308 i++;
michael@0 1309 }
michael@0 1310 if (*(string + i) == '\0') {
michael@0 1311 value = atoi(string);
michael@0 1312 string += i;
michael@0 1313 } else {
michael@0 1314 if (*(string + i) == '.') {
michael@0 1315 *(string + i) = '\0';
michael@0 1316 value = atoi(string);
michael@0 1317 string += i + 1;
michael@0 1318 } else {
michael@0 1319 *(string + i) = '\0';
michael@0 1320 i++;
michael@0 1321 value = atoi(string);
michael@0 1322 while (*(string + i) == ' ')
michael@0 1323 i++;
michael@0 1324 if (*(string + i) != '\0') {
michael@0 1325 error_out("ERROR: Improperly formated OID");
michael@0 1326 }
michael@0 1327 }
michael@0 1328 }
michael@0 1329 i = 0;
michael@0 1330 while (value != 0) {
michael@0 1331 if (remaining < 1) {
michael@0 1332 remaining += length;
michael@0 1333 length = length * 2;
michael@0 1334 temp = PORT_Realloc(temp, length);
michael@0 1335 write = temp + length - remaining;
michael@0 1336 }
michael@0 1337 *write = (value & 0x7f) | (0x80);
michael@0 1338 write++;
michael@0 1339 remaining--;
michael@0 1340 value = value >> 7;
michael@0 1341 }
michael@0 1342 *temp = *temp & (0x7f);
michael@0 1343 oidLength += write - temp;
michael@0 1344 oidString = PORT_Realloc(oidString, (oidLength + 1));
michael@0 1345 read = write - 1;
michael@0 1346 write = oidLength + oidString - 1;
michael@0 1347 for (i = 0; i < (length - remaining); i++) {
michael@0 1348 *write = *read;
michael@0 1349 write--;
michael@0 1350 read++;
michael@0 1351 }
michael@0 1352 write = temp;
michael@0 1353 remaining = length;
michael@0 1354 }
michael@0 1355 *(oidString + oidLength) = '\0';
michael@0 1356 oid = (SECItem *) PORT_ZAlloc(sizeof(SECItem));
michael@0 1357 oid->data = oidString;
michael@0 1358 oid->len = oidLength;
michael@0 1359 PORT_Free(temp);
michael@0 1360 return oid;
michael@0 1361 }
michael@0 1362
michael@0 1363 static SECItem *
michael@0 1364 string_to_ipaddress(char *string)
michael@0 1365 {
michael@0 1366 int i = 0;
michael@0 1367 int value;
michael@0 1368 int j = 0;
michael@0 1369 SECItem *ipaddress;
michael@0 1370
michael@0 1371
michael@0 1372 while (*string == ' ') {
michael@0 1373 string++;
michael@0 1374 }
michael@0 1375 ipaddress = (SECItem *) PORT_ZAlloc(sizeof(SECItem));
michael@0 1376 ipaddress->data = PORT_ZAlloc(9);
michael@0 1377 while (*string != '\0' && j < 8) {
michael@0 1378 while (isdigit(*(string + i))) {
michael@0 1379 i++;
michael@0 1380 }
michael@0 1381 if (*(string + i) == '.') {
michael@0 1382 *(string + i) = '\0';
michael@0 1383 value = atoi(string);
michael@0 1384 string = string + i + 1;
michael@0 1385 i = 0;
michael@0 1386 } else {
michael@0 1387 if (*(string + i) == '\0') {
michael@0 1388 value = atoi(string);
michael@0 1389 string = string + i;
michael@0 1390 i = 0;
michael@0 1391 } else {
michael@0 1392 *(string + i) = '\0';
michael@0 1393 while (*(string + i) == ' ') {
michael@0 1394 i++;
michael@0 1395 }
michael@0 1396 if (*(string + i) == '\0') {
michael@0 1397 value = atoi(string);
michael@0 1398 string = string + i;
michael@0 1399 i = 0;
michael@0 1400 } else {
michael@0 1401 error_out("ERROR: Improperly formated IP Address");
michael@0 1402 }
michael@0 1403 }
michael@0 1404 }
michael@0 1405 if (value >= 0 && value < 256) {
michael@0 1406 *(ipaddress->data + j) = value;
michael@0 1407 } else {
michael@0 1408 error_out("ERROR: Improperly formated IP Address");
michael@0 1409 }
michael@0 1410 j++;
michael@0 1411 }
michael@0 1412 *(ipaddress->data + j) = '\0';
michael@0 1413 if (j != 4 && j != 8) {
michael@0 1414 error_out("ERROR: Improperly formated IP Address");
michael@0 1415 }
michael@0 1416 ipaddress->len = j;
michael@0 1417 return ipaddress;
michael@0 1418 }
michael@0 1419
michael@0 1420 static SECItem *
michael@0 1421 string_to_binary(char *string)
michael@0 1422 {
michael@0 1423 SECItem *rv;
michael@0 1424 int high_digit;
michael@0 1425 int low_digit;
michael@0 1426
michael@0 1427 rv = (SECItem *) PORT_ZAlloc(sizeof(SECItem));
michael@0 1428 if (rv == NULL) {
michael@0 1429 error_allocate();
michael@0 1430 }
michael@0 1431 rv->data = (unsigned char *) PORT_ZAlloc((PORT_Strlen(string))/3 + 2);
michael@0 1432 while (!isxdigit(*string)) {
michael@0 1433 string++;
michael@0 1434 }
michael@0 1435 rv->len = 0;
michael@0 1436 while (*string != '\0') {
michael@0 1437 if (isxdigit(*string)) {
michael@0 1438 if (*string >= '0' && *string <= '9') {
michael@0 1439 high_digit = *string - '0';
michael@0 1440 } else {
michael@0 1441 *string = toupper(*string);
michael@0 1442 high_digit = *string - 'A' + 10;
michael@0 1443 }
michael@0 1444 string++;
michael@0 1445 if (*string >= '0' && *string <= '9') {
michael@0 1446 low_digit = *string - '0';
michael@0 1447 } else {
michael@0 1448 *string = toupper(*string);
michael@0 1449 low_digit = *string - 'A' + 10;
michael@0 1450 }
michael@0 1451 (rv->len)++;
michael@0 1452 } else {
michael@0 1453 if (*string == ':') {
michael@0 1454 string++;
michael@0 1455 } else {
michael@0 1456 if (*string == ' ') {
michael@0 1457 while (*string == ' ') {
michael@0 1458 string++;
michael@0 1459 }
michael@0 1460 }
michael@0 1461 if (*string != '\0') {
michael@0 1462 error_out("ERROR: Improperly formated binary encoding");
michael@0 1463 }
michael@0 1464 }
michael@0 1465 }
michael@0 1466 }
michael@0 1467
michael@0 1468 return rv;
michael@0 1469 }
michael@0 1470
michael@0 1471 static SECStatus
michael@0 1472 MakeGeneralName(char *name,
michael@0 1473 CERTGeneralName *genName,
michael@0 1474 PLArenaPool *arena)
michael@0 1475 {
michael@0 1476 SECItem *oid;
michael@0 1477 SECOidData *oidData;
michael@0 1478 SECItem *ipaddress;
michael@0 1479 SECItem *temp = NULL;
michael@0 1480 int i;
michael@0 1481 int nameType;
michael@0 1482 PRBool binary = PR_FALSE;
michael@0 1483 SECStatus rv = SECSuccess;
michael@0 1484 PRBool nickname = PR_FALSE;
michael@0 1485
michael@0 1486 PORT_Assert(genName);
michael@0 1487 PORT_Assert(arena);
michael@0 1488 nameType = *(name + PORT_Strlen(name) - 1) - '0';
michael@0 1489 if (nameType == 0 && *(name +PORT_Strlen(name) - 2) == '1') {
michael@0 1490 nickname = PR_TRUE;
michael@0 1491 nameType = certOtherName;
michael@0 1492 }
michael@0 1493 if (nameType < 1 || nameType > 9) {
michael@0 1494 error_out("ERROR: Unknown General Name Type");
michael@0 1495 }
michael@0 1496 *(name + PORT_Strlen(name) - 4) = '\0';
michael@0 1497 genName->type = nameType;
michael@0 1498
michael@0 1499 switch (genName->type) {
michael@0 1500 case certURI:
michael@0 1501 case certRFC822Name:
michael@0 1502 case certDNSName: {
michael@0 1503 genName->name.other.data = (unsigned char *)name;
michael@0 1504 genName->name.other.len = PORT_Strlen(name);
michael@0 1505 break;
michael@0 1506 }
michael@0 1507
michael@0 1508 case certIPAddress: {
michael@0 1509 ipaddress = string_to_ipaddress(name);
michael@0 1510 genName->name.other.data = ipaddress->data;
michael@0 1511 genName->name.other.len = ipaddress->len;
michael@0 1512 break;
michael@0 1513 }
michael@0 1514
michael@0 1515 case certRegisterID: {
michael@0 1516 oid = string_to_oid(name);
michael@0 1517 genName->name.other.data = oid->data;
michael@0 1518 genName->name.other.len = oid->len;
michael@0 1519 break;
michael@0 1520 }
michael@0 1521
michael@0 1522 case certEDIPartyName:
michael@0 1523 case certX400Address: {
michael@0 1524
michael@0 1525 genName->name.other.data = PORT_ArenaAlloc (arena,
michael@0 1526 PORT_Strlen (name) + 2);
michael@0 1527 if (genName->name.other.data == NULL) {
michael@0 1528 error_allocate();
michael@0 1529 }
michael@0 1530
michael@0 1531 PORT_Memcpy (genName->name.other.data + 2, name, PORT_Strlen (name));
michael@0 1532 /* This may not be accurate for all cases.
michael@0 1533 For now, use this tag type */
michael@0 1534 genName->name.other.data[0] = (char)(((genName->type - 1) &
michael@0 1535 0x1f)| 0x80);
michael@0 1536 genName->name.other.data[1] = (char)PORT_Strlen (name);
michael@0 1537 genName->name.other.len = PORT_Strlen (name) + 2;
michael@0 1538 break;
michael@0 1539 }
michael@0 1540
michael@0 1541 case certOtherName: {
michael@0 1542 i = 0;
michael@0 1543 if (!nickname) {
michael@0 1544 while (!isdigit(*(name + PORT_Strlen(name) - i))) {
michael@0 1545 i++;
michael@0 1546 }
michael@0 1547 if (*(name + PORT_Strlen(name) - i) == '1') {
michael@0 1548 binary = PR_TRUE;
michael@0 1549 } else {
michael@0 1550 binary = PR_FALSE;
michael@0 1551 }
michael@0 1552 while (*(name + PORT_Strlen(name) - i) != '-') {
michael@0 1553 i++;
michael@0 1554 }
michael@0 1555 *(name + PORT_Strlen(name) - i - 1) = '\0';
michael@0 1556 i = 0;
michael@0 1557 while (*(name + i) != '-') {
michael@0 1558 i++;
michael@0 1559 }
michael@0 1560 *(name + i - 1) = '\0';
michael@0 1561 oid = string_to_oid(name + i + 2);
michael@0 1562 } else {
michael@0 1563 oidData = SECOID_FindOIDByTag(SEC_OID_NETSCAPE_NICKNAME);
michael@0 1564 oid = &oidData->oid;
michael@0 1565 while (*(name + PORT_Strlen(name) - i) != '-') {
michael@0 1566 i++;
michael@0 1567 }
michael@0 1568 *(name + PORT_Strlen(name) - i) = '\0';
michael@0 1569 }
michael@0 1570 genName->name.OthName.oid.data = oid->data;
michael@0 1571 genName->name.OthName.oid.len = oid->len;
michael@0 1572 if (binary) {
michael@0 1573 temp = string_to_binary(name);
michael@0 1574 genName->name.OthName.name.data = temp->data;
michael@0 1575 genName->name.OthName.name.len = temp->len;
michael@0 1576 } else {
michael@0 1577 temp = (SECItem *) PORT_ZAlloc(sizeof(SECItem));
michael@0 1578 if (temp == NULL) {
michael@0 1579 error_allocate();
michael@0 1580 }
michael@0 1581 temp->data = (unsigned char *)name;
michael@0 1582 temp->len = PORT_Strlen(name);
michael@0 1583 SEC_ASN1EncodeItem (arena, &(genName->name.OthName.name), temp,
michael@0 1584 CERTIA5TypeTemplate);
michael@0 1585 }
michael@0 1586 PORT_Free(temp);
michael@0 1587 break;
michael@0 1588 }
michael@0 1589
michael@0 1590 case certDirectoryName: {
michael@0 1591 CERTName *directoryName = NULL;
michael@0 1592
michael@0 1593 directoryName = CERT_AsciiToName (name);
michael@0 1594 if (!directoryName) {
michael@0 1595 error_out("ERROR: Improperly formated alternative name");
michael@0 1596 break;
michael@0 1597 }
michael@0 1598 rv = CERT_CopyName (arena, &genName->name.directoryName,
michael@0 1599 directoryName);
michael@0 1600 CERT_DestroyName (directoryName);
michael@0 1601
michael@0 1602 break;
michael@0 1603 }
michael@0 1604 }
michael@0 1605 genName->l.next = &(genName->l);
michael@0 1606 genName->l.prev = &(genName->l);
michael@0 1607 return rv;
michael@0 1608 }
michael@0 1609
michael@0 1610
michael@0 1611 static CERTGeneralName *
michael@0 1612 MakeAltName(Pair *data,
michael@0 1613 char *which,
michael@0 1614 PLArenaPool *arena)
michael@0 1615 {
michael@0 1616 CERTGeneralName *SubAltName;
michael@0 1617 CERTGeneralName *current;
michael@0 1618 CERTGeneralName *newname;
michael@0 1619 char *name = NULL;
michael@0 1620 SECStatus rv = SECSuccess;
michael@0 1621 int len;
michael@0 1622
michael@0 1623
michael@0 1624 len = PORT_Strlen(which);
michael@0 1625 name = find_field(data, which, PR_TRUE);
michael@0 1626 SubAltName = current = (CERTGeneralName *) PORT_ZAlloc
michael@0 1627 (sizeof(CERTGeneralName));
michael@0 1628 if (current == NULL) {
michael@0 1629 error_allocate();
michael@0 1630 }
michael@0 1631 while (name != NULL) {
michael@0 1632
michael@0 1633 rv = MakeGeneralName(name, current, arena);
michael@0 1634
michael@0 1635 if (rv != SECSuccess) {
michael@0 1636 break;
michael@0 1637 }
michael@0 1638 if (*(which + len -1) < '9') {
michael@0 1639 *(which + len - 1) = *(which + len - 1) + 1;
michael@0 1640 } else {
michael@0 1641 if (isdigit(*(which + len - 2) )) {
michael@0 1642 *(which + len - 2) = *(which + len - 2) + 1;
michael@0 1643 *(which + len - 1) = '0';
michael@0 1644 } else {
michael@0 1645 *(which + len - 1) = '1';
michael@0 1646 *(which + len) = '0';
michael@0 1647 *(which + len + 1) = '\0';
michael@0 1648 len++;
michael@0 1649 }
michael@0 1650 }
michael@0 1651 len = PORT_Strlen(which);
michael@0 1652 name = find_field(data, which, PR_TRUE);
michael@0 1653 if (name != NULL) {
michael@0 1654 newname = (CERTGeneralName *) PORT_ZAlloc(sizeof(CERTGeneralName));
michael@0 1655 if (newname == NULL) {
michael@0 1656 error_allocate();
michael@0 1657 }
michael@0 1658 current->l.next = &(newname->l);
michael@0 1659 newname->l.prev = &(current->l);
michael@0 1660 current = newname;
michael@0 1661 newname = NULL;
michael@0 1662 } else {
michael@0 1663 current->l.next = &(SubAltName->l);
michael@0 1664 SubAltName->l.prev = &(current->l);
michael@0 1665 }
michael@0 1666 }
michael@0 1667 if (rv == SECFailure) {
michael@0 1668 return NULL;
michael@0 1669 }
michael@0 1670 return SubAltName;
michael@0 1671 }
michael@0 1672
michael@0 1673 static CERTNameConstraints *
michael@0 1674 MakeNameConstraints(Pair *data,
michael@0 1675 PLArenaPool *arena)
michael@0 1676 {
michael@0 1677 CERTNameConstraints *NameConstraints;
michael@0 1678 CERTNameConstraint *current = NULL;
michael@0 1679 CERTNameConstraint *last_permited = NULL;
michael@0 1680 CERTNameConstraint *last_excluded = NULL;
michael@0 1681 char *constraint = NULL;
michael@0 1682 char *which;
michael@0 1683 SECStatus rv = SECSuccess;
michael@0 1684 int len;
michael@0 1685 int i;
michael@0 1686 long max;
michael@0 1687 long min;
michael@0 1688 PRBool permited;
michael@0 1689
michael@0 1690
michael@0 1691 NameConstraints = (CERTNameConstraints *) PORT_ZAlloc
michael@0 1692 (sizeof(CERTNameConstraints));
michael@0 1693 which = make_copy_string("NameConstraintSelect0", 25,'\0');
michael@0 1694 len = PORT_Strlen(which);
michael@0 1695 constraint = find_field(data, which, PR_TRUE);
michael@0 1696 NameConstraints->permited = NameConstraints->excluded = NULL;
michael@0 1697 while (constraint != NULL) {
michael@0 1698 current = (CERTNameConstraint *) PORT_ZAlloc
michael@0 1699 (sizeof(CERTNameConstraint));
michael@0 1700 if (current == NULL) {
michael@0 1701 error_allocate();
michael@0 1702 }
michael@0 1703 i = 0;
michael@0 1704 while (*(constraint + PORT_Strlen(constraint) - i) != '-') {
michael@0 1705 i++;
michael@0 1706 }
michael@0 1707 *(constraint + PORT_Strlen(constraint) - i - 1) = '\0';
michael@0 1708 max = (long) atoi(constraint + PORT_Strlen(constraint) + 3);
michael@0 1709 if (max > 0) {
michael@0 1710 (void) SEC_ASN1EncodeInteger(arena, &current->max, max);
michael@0 1711 }
michael@0 1712 i = 0;
michael@0 1713 while (*(constraint + PORT_Strlen(constraint) - i) != '-') {
michael@0 1714 i++;
michael@0 1715 }
michael@0 1716 *(constraint + PORT_Strlen(constraint) - i - 1) = '\0';
michael@0 1717 min = (long) atoi(constraint + PORT_Strlen(constraint) + 3);
michael@0 1718 (void) SEC_ASN1EncodeInteger(arena, &current->min, min);
michael@0 1719 while (*(constraint + PORT_Strlen(constraint) - i) != '-') {
michael@0 1720 i++;
michael@0 1721 }
michael@0 1722 *(constraint + PORT_Strlen(constraint) - i - 1) = '\0';
michael@0 1723 if (*(constraint + PORT_Strlen(constraint) + 3) == 'p') {
michael@0 1724 permited = PR_TRUE;
michael@0 1725 } else {
michael@0 1726 permited = PR_FALSE;
michael@0 1727 }
michael@0 1728 rv = MakeGeneralName(constraint, &(current->name), arena);
michael@0 1729
michael@0 1730 if (rv != SECSuccess) {
michael@0 1731 break;
michael@0 1732 }
michael@0 1733 if (*(which + len - 1) < '9') {
michael@0 1734 *(which + len - 1) = *(which + len - 1) + 1;
michael@0 1735 } else {
michael@0 1736 if (isdigit(*(which + len - 2) )) {
michael@0 1737 *(which + len - 2) = *(which + len - 2) + 1;
michael@0 1738 *(which + len - 1) = '0';
michael@0 1739 } else {
michael@0 1740 *(which + len - 1) = '1';
michael@0 1741 *(which + len) = '0';
michael@0 1742 *(which + len + 1) = '\0';
michael@0 1743 len++;
michael@0 1744 }
michael@0 1745 }
michael@0 1746 len = PORT_Strlen(which);
michael@0 1747 if (permited) {
michael@0 1748 if (NameConstraints->permited == NULL) {
michael@0 1749 NameConstraints->permited = last_permited = current;
michael@0 1750 }
michael@0 1751 last_permited->l.next = &(current->l);
michael@0 1752 current->l.prev = &(last_permited->l);
michael@0 1753 last_permited = current;
michael@0 1754 } else {
michael@0 1755 if (NameConstraints->excluded == NULL) {
michael@0 1756 NameConstraints->excluded = last_excluded = current;
michael@0 1757 }
michael@0 1758 last_excluded->l.next = &(current->l);
michael@0 1759 current->l.prev = &(last_excluded->l);
michael@0 1760 last_excluded = current;
michael@0 1761 }
michael@0 1762 constraint = find_field(data, which, PR_TRUE);
michael@0 1763 if (constraint != NULL) {
michael@0 1764 current = (CERTNameConstraint *) PORT_ZAlloc(sizeof(CERTNameConstraint));
michael@0 1765 if (current == NULL) {
michael@0 1766 error_allocate();
michael@0 1767 }
michael@0 1768 }
michael@0 1769 }
michael@0 1770 if (NameConstraints->permited != NULL) {
michael@0 1771 last_permited->l.next = &(NameConstraints->permited->l);
michael@0 1772 NameConstraints->permited->l.prev = &(last_permited->l);
michael@0 1773 }
michael@0 1774 if (NameConstraints->excluded != NULL) {
michael@0 1775 last_excluded->l.next = &(NameConstraints->excluded->l);
michael@0 1776 NameConstraints->excluded->l.prev = &(last_excluded->l);
michael@0 1777 }
michael@0 1778 if (which != NULL) {
michael@0 1779 PORT_Free(which);
michael@0 1780 }
michael@0 1781 if (rv == SECFailure) {
michael@0 1782 return NULL;
michael@0 1783 }
michael@0 1784 return NameConstraints;
michael@0 1785 }
michael@0 1786
michael@0 1787
michael@0 1788
michael@0 1789 static SECStatus
michael@0 1790 AddAltName(void *extHandle,
michael@0 1791 Pair *data,
michael@0 1792 char *issuerNameStr,
michael@0 1793 CERTCertDBHandle *handle,
michael@0 1794 int type)
michael@0 1795 {
michael@0 1796 PRBool autoIssuer = PR_FALSE;
michael@0 1797 PLArenaPool *arena = NULL;
michael@0 1798 CERTGeneralName *genName = NULL;
michael@0 1799 char *which = NULL;
michael@0 1800 char *name = NULL;
michael@0 1801 SECStatus rv = SECSuccess;
michael@0 1802 SECItem *issuersAltName = NULL;
michael@0 1803 CERTCertificate *issuerCert = NULL;
michael@0 1804
michael@0 1805 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 1806 if (arena == NULL) {
michael@0 1807 error_allocate();
michael@0 1808 }
michael@0 1809 if (type == 0) {
michael@0 1810 which = make_copy_string("SubAltNameSelect0", 20,'\0');
michael@0 1811 genName = MakeAltName(data, which, arena);
michael@0 1812 } else {
michael@0 1813 if (autoIssuer) {
michael@0 1814 autoIssuer = find_field_bool(data,"IssuerAltNameSourceRadio-auto",
michael@0 1815 PR_TRUE);
michael@0 1816 issuerCert = CERT_FindCertByNameString(handle, issuerNameStr);
michael@0 1817 rv = cert_FindExtension((*issuerCert).extensions,
michael@0 1818 SEC_OID_X509_SUBJECT_ALT_NAME,
michael@0 1819 issuersAltName);
michael@0 1820 if (issuersAltName == NULL) {
michael@0 1821 name = PORT_Alloc(PORT_Strlen((*issuerCert).subjectName) + 4);
michael@0 1822 PORT_Strcpy(name, (*issuerCert).subjectName);
michael@0 1823 PORT_Strcat(name, " - 5");
michael@0 1824 }
michael@0 1825 } else {
michael@0 1826 which = make_copy_string("IssuerAltNameSelect0", 20,'\0');
michael@0 1827 genName = MakeAltName(data, which, arena);
michael@0 1828 }
michael@0 1829 }
michael@0 1830 if (type == 0) {
michael@0 1831 EncodeAndAddExtensionValue(arena, extHandle, genName,
michael@0 1832 find_field_bool(data, "SubAltName-crit",
michael@0 1833 PR_TRUE),
michael@0 1834 SEC_OID_X509_SUBJECT_ALT_NAME,
michael@0 1835 (EXTEN_VALUE_ENCODER)
michael@0 1836 CERT_EncodeAltNameExtension);
michael@0 1837
michael@0 1838 } else {
michael@0 1839 if (autoIssuer && (name == NULL)) {
michael@0 1840 rv = CERT_AddExtension
michael@0 1841 (extHandle, SEC_OID_X509_ISSUER_ALT_NAME, issuersAltName,
michael@0 1842 find_field_bool(data, "IssuerAltName-crit", PR_TRUE), PR_TRUE);
michael@0 1843 } else {
michael@0 1844 EncodeAndAddExtensionValue(arena, extHandle, genName,
michael@0 1845 find_field_bool(data,
michael@0 1846 "IssuerAltName-crit",
michael@0 1847 PR_TRUE),
michael@0 1848 SEC_OID_X509_ISSUER_ALT_NAME,
michael@0 1849 (EXTEN_VALUE_ENCODER)
michael@0 1850 CERT_EncodeAltNameExtension);
michael@0 1851 }
michael@0 1852 }
michael@0 1853 if (which != NULL) {
michael@0 1854 PORT_Free(which);
michael@0 1855 }
michael@0 1856 if (issuerCert != NULL) {
michael@0 1857 CERT_DestroyCertificate(issuerCert);
michael@0 1858 }
michael@0 1859 return rv;
michael@0 1860 }
michael@0 1861
michael@0 1862
michael@0 1863 static SECStatus
michael@0 1864 AddNameConstraints(void *extHandle,
michael@0 1865 Pair *data)
michael@0 1866 {
michael@0 1867 PLArenaPool *arena = NULL;
michael@0 1868 CERTNameConstraints *constraints = NULL;
michael@0 1869 SECStatus rv = SECSuccess;
michael@0 1870
michael@0 1871
michael@0 1872 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
michael@0 1873 if (arena == NULL) {
michael@0 1874 error_allocate();
michael@0 1875 }
michael@0 1876 constraints = MakeNameConstraints(data, arena);
michael@0 1877 if (constraints != NULL) {
michael@0 1878 EncodeAndAddExtensionValue(arena, extHandle, constraints, PR_TRUE,
michael@0 1879 SEC_OID_X509_NAME_CONSTRAINTS,
michael@0 1880 (EXTEN_VALUE_ENCODER)
michael@0 1881 CERT_EncodeNameConstraintsExtension);
michael@0 1882 }
michael@0 1883 if (arena != NULL) {
michael@0 1884 PORT_ArenaRelease (arena, NULL);
michael@0 1885 }
michael@0 1886 return rv;
michael@0 1887 }
michael@0 1888
michael@0 1889
michael@0 1890 static SECStatus
michael@0 1891 add_extensions(CERTCertificate *subjectCert,
michael@0 1892 Pair *data,
michael@0 1893 char *issuerNameStr,
michael@0 1894 CERTCertDBHandle *handle)
michael@0 1895 {
michael@0 1896 void *extHandle;
michael@0 1897 SECStatus rv = SECSuccess;
michael@0 1898
michael@0 1899
michael@0 1900 extHandle = CERT_StartCertExtensions (subjectCert);
michael@0 1901 if (extHandle == NULL) {
michael@0 1902 error_out("ERROR: Unable to get certificates extension handle");
michael@0 1903 }
michael@0 1904 if (find_field_bool(data, "keyUsage", PR_TRUE)) {
michael@0 1905 rv = AddKeyUsage(extHandle, data);
michael@0 1906 if (rv != SECSuccess) {
michael@0 1907 error_out("ERROR: Unable to add Key Usage extension");
michael@0 1908 }
michael@0 1909 }
michael@0 1910
michael@0 1911 if( find_field_bool(data, "extKeyUsage", PR_TRUE) ) {
michael@0 1912 rv = AddExtKeyUsage(extHandle, data);
michael@0 1913 if( SECSuccess != rv ) {
michael@0 1914 error_out("ERROR: Unable to add Extended Key Usage extension");
michael@0 1915 }
michael@0 1916 }
michael@0 1917
michael@0 1918 if (find_field_bool(data, "basicConstraints", PR_TRUE)) {
michael@0 1919 rv = AddBasicConstraint(extHandle, data);
michael@0 1920 if (rv != SECSuccess) {
michael@0 1921 error_out("ERROR: Unable to add Basic Constraint extension");
michael@0 1922 }
michael@0 1923 }
michael@0 1924 if (find_field_bool(data, "subjectKeyIdentifier", PR_TRUE)) {
michael@0 1925 rv = AddSubKeyID(extHandle, data, subjectCert);
michael@0 1926 if (rv != SECSuccess) {
michael@0 1927 error_out("ERROR: Unable to add Subject Key Identifier Extension");
michael@0 1928 }
michael@0 1929 }
michael@0 1930 if (find_field_bool(data, "authorityKeyIdentifier", PR_TRUE)) {
michael@0 1931 rv = AddAuthKeyID (extHandle, data, issuerNameStr, handle);
michael@0 1932 if (rv != SECSuccess) {
michael@0 1933 error_out("ERROR: Unable to add Authority Key Identifier extension");
michael@0 1934 }
michael@0 1935 }
michael@0 1936 if (find_field_bool(data, "privKeyUsagePeriod", PR_TRUE)) {
michael@0 1937 rv = AddPrivKeyUsagePeriod (extHandle, data, subjectCert);
michael@0 1938 if (rv != SECSuccess) {
michael@0 1939 error_out("ERROR: Unable to add Private Key Usage Period extension");
michael@0 1940 }
michael@0 1941 }
michael@0 1942 if (find_field_bool(data, "SubAltName", PR_TRUE)) {
michael@0 1943 rv = AddAltName (extHandle, data, NULL, NULL, 0);
michael@0 1944 if (rv != SECSuccess) {
michael@0 1945 error_out("ERROR: Unable to add Subject Alternative Name extension");
michael@0 1946 }
michael@0 1947 }
michael@0 1948 if (find_field_bool(data, "IssuerAltName", PR_TRUE)) {
michael@0 1949 rv = AddAltName (extHandle, data, issuerNameStr, handle, 1);
michael@0 1950 if (rv != SECSuccess) {
michael@0 1951 error_out("ERROR: Unable to add Issuer Alternative Name Extension");
michael@0 1952 }
michael@0 1953 }
michael@0 1954 if (find_field_bool(data, "NameConstraints", PR_TRUE)) {
michael@0 1955 rv = AddNameConstraints(extHandle, data);
michael@0 1956 if (rv != SECSuccess) {
michael@0 1957 error_out("ERROR: Unable to add Name Constraints Extension");
michael@0 1958 }
michael@0 1959 }
michael@0 1960 if (find_field_bool(data, "netscape-cert-type", PR_TRUE)) {
michael@0 1961 rv = AddNscpCertType(extHandle, data);
michael@0 1962 if (rv != SECSuccess) {
michael@0 1963 error_out("ERROR: Unable to add Netscape Certificate Type Extension");
michael@0 1964 }
michael@0 1965 }
michael@0 1966 if (find_field_bool(data, "netscape-base-url", PR_TRUE)) {
michael@0 1967 rv = add_IA5StringExtension(extHandle,
michael@0 1968 find_field(data, "netscape-base-url-text",
michael@0 1969 PR_TRUE),
michael@0 1970 find_field_bool(data,
michael@0 1971 "netscape-base-url-crit",
michael@0 1972 PR_TRUE),
michael@0 1973 SEC_OID_NS_CERT_EXT_BASE_URL);
michael@0 1974 if (rv != SECSuccess) {
michael@0 1975 error_out("ERROR: Unable to add Netscape Base URL Extension");
michael@0 1976 }
michael@0 1977 }
michael@0 1978 if (find_field_bool(data, "netscape-revocation-url", PR_TRUE)) {
michael@0 1979 rv = add_IA5StringExtension(extHandle,
michael@0 1980 find_field(data,
michael@0 1981 "netscape-revocation-url-text",
michael@0 1982 PR_TRUE),
michael@0 1983 find_field_bool
michael@0 1984 (data, "netscape-revocation-url-crit",
michael@0 1985 PR_TRUE),
michael@0 1986 SEC_OID_NS_CERT_EXT_REVOCATION_URL);
michael@0 1987 if (rv != SECSuccess) {
michael@0 1988 error_out("ERROR: Unable to add Netscape Revocation URL Extension");
michael@0 1989 }
michael@0 1990 }
michael@0 1991 if (find_field_bool(data, "netscape-ca-revocation-url", PR_TRUE)) {
michael@0 1992 rv = add_IA5StringExtension(extHandle,
michael@0 1993 find_field(data,
michael@0 1994 "netscape-ca-revocation-url-text",
michael@0 1995 PR_TRUE),
michael@0 1996 find_field_bool
michael@0 1997 (data, "netscape-ca-revocation-url-crit"
michael@0 1998 , PR_TRUE),
michael@0 1999 SEC_OID_NS_CERT_EXT_CA_REVOCATION_URL);
michael@0 2000 if (rv != SECSuccess) {
michael@0 2001 error_out("ERROR: Unable to add Netscape CA Revocation URL Extension");
michael@0 2002 }
michael@0 2003 }
michael@0 2004 if (find_field_bool(data, "netscape-cert-renewal-url", PR_TRUE)) {
michael@0 2005 rv = add_IA5StringExtension(extHandle,
michael@0 2006 find_field(data,
michael@0 2007 "netscape-cert-renewal-url-text",
michael@0 2008 PR_TRUE),
michael@0 2009 find_field_bool
michael@0 2010 (data, "netscape-cert-renewal-url-crit",
michael@0 2011 PR_TRUE),
michael@0 2012 SEC_OID_NS_CERT_EXT_CERT_RENEWAL_URL);
michael@0 2013 if (rv != SECSuccess) {
michael@0 2014 error_out("ERROR: Unable to add Netscape Certificate Renewal URL Extension");
michael@0 2015 }
michael@0 2016 }
michael@0 2017 if (find_field_bool(data, "netscape-ca-policy-url", PR_TRUE)) {
michael@0 2018 rv = add_IA5StringExtension(extHandle,
michael@0 2019 find_field(data,
michael@0 2020 "netscape-ca-policy-url-text",
michael@0 2021 PR_TRUE),
michael@0 2022 find_field_bool
michael@0 2023 (data, "netscape-ca-policy-url-crit",
michael@0 2024 PR_TRUE),
michael@0 2025 SEC_OID_NS_CERT_EXT_CA_POLICY_URL);
michael@0 2026 if (rv != SECSuccess) {
michael@0 2027 error_out("ERROR: Unable to add Netscape CA Policy URL Extension");
michael@0 2028 }
michael@0 2029 }
michael@0 2030 if (find_field_bool(data, "netscape-ssl-server-name", PR_TRUE)) {
michael@0 2031 rv = add_IA5StringExtension(extHandle,
michael@0 2032 find_field(data,
michael@0 2033 "netscape-ssl-server-name-text",
michael@0 2034 PR_TRUE),
michael@0 2035 find_field_bool
michael@0 2036 (data, "netscape-ssl-server-name-crit",
michael@0 2037 PR_TRUE),
michael@0 2038 SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME);
michael@0 2039 if (rv != SECSuccess) {
michael@0 2040 error_out("ERROR: Unable to add Netscape SSL Server Name Extension");
michael@0 2041 }
michael@0 2042 }
michael@0 2043 if (find_field_bool(data, "netscape-comment", PR_TRUE)) {
michael@0 2044 rv = add_IA5StringExtension(extHandle,
michael@0 2045 find_field(data, "netscape-comment-text",
michael@0 2046 PR_TRUE),
michael@0 2047 find_field_bool(data,
michael@0 2048 "netscape-comment-crit",
michael@0 2049 PR_TRUE),
michael@0 2050 SEC_OID_NS_CERT_EXT_COMMENT);
michael@0 2051 if (rv != SECSuccess) {
michael@0 2052 error_out("ERROR: Unable to add Netscape Comment Extension");
michael@0 2053 }
michael@0 2054 }
michael@0 2055 CERT_FinishExtensions(extHandle);
michael@0 2056 return (rv);
michael@0 2057 }
michael@0 2058
michael@0 2059
michael@0 2060
michael@0 2061 char *
michael@0 2062 return_dbpasswd(PK11SlotInfo *slot, PRBool retry, void *data)
michael@0 2063 {
michael@0 2064 char *rv;
michael@0 2065
michael@0 2066 /* don't clobber our poor smart card */
michael@0 2067 if (retry == PR_TRUE) {
michael@0 2068 return NULL;
michael@0 2069 }
michael@0 2070 rv = PORT_Alloc(4);
michael@0 2071 PORT_Strcpy(rv, "foo");
michael@0 2072 return rv;
michael@0 2073 }
michael@0 2074
michael@0 2075
michael@0 2076 SECKEYPrivateKey *
michael@0 2077 FindPrivateKeyFromNameStr(char *name,
michael@0 2078 CERTCertDBHandle *certHandle)
michael@0 2079 {
michael@0 2080 SECKEYPrivateKey *key;
michael@0 2081 CERTCertificate *cert;
michael@0 2082 CERTCertificate *p11Cert;
michael@0 2083
michael@0 2084
michael@0 2085 /* We don't presently have a PK11 function to find a cert by
michael@0 2086 ** subject name.
michael@0 2087 ** We do have a function to find a cert in the internal slot's
michael@0 2088 ** cert db by subject name, but it doesn't setup the slot info.
michael@0 2089 ** So, this HACK works, but should be replaced as soon as we
michael@0 2090 ** have a function to search for certs accross slots by subject name.
michael@0 2091 */
michael@0 2092 cert = CERT_FindCertByNameString(certHandle, name);
michael@0 2093 if (cert == NULL || cert->nickname == NULL) {
michael@0 2094 error_out("ERROR: Unable to retrieve issuers certificate");
michael@0 2095 }
michael@0 2096 p11Cert = PK11_FindCertFromNickname(cert->nickname, NULL);
michael@0 2097 if (p11Cert == NULL) {
michael@0 2098 error_out("ERROR: Unable to retrieve issuers certificate");
michael@0 2099 }
michael@0 2100 key = PK11_FindKeyByAnyCert(p11Cert, NULL);
michael@0 2101 return key;
michael@0 2102 }
michael@0 2103
michael@0 2104 static SECItem *
michael@0 2105 SignCert(CERTCertificate *cert,
michael@0 2106 char *issuerNameStr,
michael@0 2107 Pair *data,
michael@0 2108 CERTCertDBHandle *handle,
michael@0 2109 int which_key)
michael@0 2110 {
michael@0 2111 SECItem der;
michael@0 2112 SECKEYPrivateKey *caPrivateKey = NULL;
michael@0 2113 SECStatus rv;
michael@0 2114 PLArenaPool *arena;
michael@0 2115 SECOidTag algID;
michael@0 2116
michael@0 2117 if (which_key == 0) {
michael@0 2118 caPrivateKey = FindPrivateKeyFromNameStr(issuerNameStr, handle);
michael@0 2119 } else {
michael@0 2120 caPrivateKey = privkeys[which_key - 1];
michael@0 2121 }
michael@0 2122 if (caPrivateKey == NULL) {
michael@0 2123 error_out("ERROR: unable to retrieve issuers key");
michael@0 2124 }
michael@0 2125
michael@0 2126 arena = cert->arena;
michael@0 2127
michael@0 2128 algID = SEC_GetSignatureAlgorithmOidTag(caPrivateKey->keyType,
michael@0 2129 SEC_OID_UNKNOWN);
michael@0 2130 if (algID == SEC_OID_UNKNOWN) {
michael@0 2131 error_out("ERROR: Unknown key type for issuer.");
michael@0 2132 goto done;
michael@0 2133 }
michael@0 2134
michael@0 2135 rv = SECOID_SetAlgorithmID(arena, &cert->signature, algID, 0);
michael@0 2136 if (rv != SECSuccess) {
michael@0 2137 error_out("ERROR: Could not set signature algorithm id.");
michael@0 2138 }
michael@0 2139
michael@0 2140 if (find_field_bool(data,"ver-1", PR_TRUE)) {
michael@0 2141 *(cert->version.data) = 0;
michael@0 2142 cert->version.len = 1;
michael@0 2143 } else {
michael@0 2144 *(cert->version.data) = 2;
michael@0 2145 cert->version.len = 1;
michael@0 2146 }
michael@0 2147 der.data = NULL;
michael@0 2148 der.len = 0;
michael@0 2149 (void) SEC_ASN1EncodeItem (arena, &der, cert, CERT_CertificateTemplate);
michael@0 2150 if (der.data == NULL) {
michael@0 2151 error_out("ERROR: Could not encode certificate.\n");
michael@0 2152 }
michael@0 2153 rv = SEC_DerSignData (arena, &(cert->derCert), der.data, der.len, caPrivateKey,
michael@0 2154 algID);
michael@0 2155 if (rv != SECSuccess) {
michael@0 2156 error_out("ERROR: Could not sign encoded certificate data.\n");
michael@0 2157 }
michael@0 2158 done:
michael@0 2159 SECKEY_DestroyPrivateKey(caPrivateKey);
michael@0 2160 return &(cert->derCert);
michael@0 2161 }
michael@0 2162
michael@0 2163
michael@0 2164 int
michael@0 2165 main(int argc, char **argv)
michael@0 2166 {
michael@0 2167 int length = 500;
michael@0 2168 int remaining = 500;
michael@0 2169 int n;
michael@0 2170 int i;
michael@0 2171 int serial;
michael@0 2172 int chainLen;
michael@0 2173 int which_key;
michael@0 2174 char *pos;
michael@0 2175 #ifdef OFFLINE
michael@0 2176 char *form_output = "key=MIIBPTCBpzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA7SLqjWBL9Wl11Vlg%0AaMqZCvcQOL%2FnvSqYPPRP0XZy9SoAeyWzQnBOiCm2t8H5mK7r2jnKdAQOmfhjaJil%0A3hNVu3SekHOXF6Ze7bkWa6%2FSGVcY%2FojkydxFSgY43nd1iydzPQDp8WWLL%2BpVpt%2B%2B%0ATRhFtVXbF0fQI03j9h3BoTgP2lkCAwEAARYDZm9vMA0GCSqGSIb3DQEBBAUAA4GB%0AAJ8UfRKJ0GtG%2B%2BufCC6tAfTzKrq3CTBHnom55EyXcsAsv6WbDqI%2F0rLAPkn2Xo1r%0AnNhtMxIuj441blMt%2Fa3AGLOy5zmC7Qawt8IytvQikQ1XTpTBCXevytrmLjCmlURr%0ANJryTM48WaMQHiMiJpbXCqVJC1d%2FpEWBtqvALzZaOOIy&subject=CN%3D%22test%22%26serial-auto%3Dtrue%26serial_value%3D%26ver-1%3Dtrue%26ver-3%3Dfalse%26caChoiceradio-SignWithDefaultkey%3Dtrue%26caChoiceradio-SignWithRandomChain%3Dfalse%26autoCAs%3D%26caChoiceradio-SignWithSpecifiedChain%3Dfalse%26manCAs%3D%26%24";
michael@0 2177 #else
michael@0 2178 char *form_output;
michael@0 2179 #endif
michael@0 2180 char *issuerNameStr;
michael@0 2181 char *certName;
michael@0 2182 char *DBdir = DB_DIRECTORY;
michael@0 2183 char *prefixs[10] = {"CA#1-", "CA#2-", "CA#3-",
michael@0 2184 "CA#4-", "CA#5-", "CA#6-",
michael@0 2185 "CA#7-", "CA#8-", "CA#9-", ""};
michael@0 2186 Pair *form_data;
michael@0 2187 CERTCertificate *cert;
michael@0 2188 CERTCertDBHandle *handle;
michael@0 2189 CERTCertificateRequest *certReq = NULL;
michael@0 2190 int warpmonths = 0;
michael@0 2191 SECItem *certDER;
michael@0 2192 #ifdef FILEOUT
michael@0 2193 FILE *outfile;
michael@0 2194 #endif
michael@0 2195 SECStatus status = SECSuccess;
michael@0 2196 extern char prefix[PREFIX_LEN];
michael@0 2197 SEC_PKCS7ContentInfo *certChain;
michael@0 2198 SECItem *encodedCertChain;
michael@0 2199 PRBool UChain = PR_FALSE;
michael@0 2200
michael@0 2201
michael@0 2202 progName = strrchr(argv[0], '/');
michael@0 2203 progName = progName ? progName+1 : argv[0];
michael@0 2204
michael@0 2205
michael@0 2206 #ifdef TEST
michael@0 2207 sleep(20);
michael@0 2208 #endif
michael@0 2209 SECU_ConfigDirectory(DBdir);
michael@0 2210
michael@0 2211 PK11_SetPasswordFunc(return_dbpasswd);
michael@0 2212 status = NSS_InitReadWrite(DBdir);
michael@0 2213 if (status != SECSuccess) {
michael@0 2214 SECU_PrintPRandOSError(progName);
michael@0 2215 return -1;
michael@0 2216 }
michael@0 2217 handle = CERT_GetDefaultCertDB();
michael@0 2218
michael@0 2219 prefix[0]= '\0';
michael@0 2220 #if !defined(OFFLINE)
michael@0 2221 form_output = (char*) PORT_Alloc(length);
michael@0 2222 if (form_output == NULL) {
michael@0 2223 error_allocate();
michael@0 2224 }
michael@0 2225 pos = form_output;
michael@0 2226 while (feof(stdin) == 0 ) {
michael@0 2227 if (remaining <= 1) {
michael@0 2228 remaining += length;
michael@0 2229 length = length * 2;
michael@0 2230 form_output = PORT_Realloc(form_output, (length));
michael@0 2231 if (form_output == NULL) {
michael@0 2232 error_allocate();
michael@0 2233 }
michael@0 2234 pos = form_output + length - remaining;
michael@0 2235 }
michael@0 2236 n = fread(pos, 1, (size_t) (remaining - 1), stdin);
michael@0 2237 pos += n;
michael@0 2238 remaining -= n;
michael@0 2239 }
michael@0 2240 *pos = '&';
michael@0 2241 pos++;
michael@0 2242 length = pos - form_output;
michael@0 2243 #else
michael@0 2244 length = PORT_Strlen(form_output);
michael@0 2245 #endif
michael@0 2246 #ifdef FILEOUT
michael@0 2247 printf("Content-type: text/plain\n\n");
michael@0 2248 fwrite(form_output, 1, (size_t)length, stdout);
michael@0 2249 printf("\n");
michael@0 2250 #endif
michael@0 2251 #ifdef FILEOUT
michael@0 2252 fwrite(form_output, 1, (size_t)length, stdout);
michael@0 2253 printf("\n");
michael@0 2254 fflush(stdout);
michael@0 2255 #endif
michael@0 2256 form_data = make_datastruct(form_output, length);
michael@0 2257 status = clean_input(form_data);
michael@0 2258 #if !defined(OFFLINE)
michael@0 2259 PORT_Free(form_output);
michael@0 2260 #endif
michael@0 2261 #ifdef FILEOUT
michael@0 2262 i = 0;
michael@0 2263 while(return_name(form_data, i) != NULL) {
michael@0 2264 printf("%s",return_name(form_data,i));
michael@0 2265 printf("=\n");
michael@0 2266 printf("%s",return_data(form_data,i));
michael@0 2267 printf("\n");
michael@0 2268 i++;
michael@0 2269 }
michael@0 2270 printf("I got that done, woo hoo\n");
michael@0 2271 fflush(stdout);
michael@0 2272 #endif
michael@0 2273 issuerNameStr = PORT_Alloc(200);
michael@0 2274 if (find_field_bool(form_data, "caChoiceradio-SignWithSpecifiedChain",
michael@0 2275 PR_FALSE)) {
michael@0 2276 UChain = PR_TRUE;
michael@0 2277 chainLen = atoi(find_field(form_data, "manCAs", PR_FALSE));
michael@0 2278 PORT_Strcpy(prefix, prefixs[0]);
michael@0 2279 issuerNameStr = PORT_Strcpy(issuerNameStr,
michael@0 2280 "CN=Cert-O-Matic II, O=Cert-O-Matic II");
michael@0 2281 if (chainLen == 0) {
michael@0 2282 UChain = PR_FALSE;
michael@0 2283 }
michael@0 2284 } else {
michael@0 2285 if (find_field_bool(form_data, "caChoiceradio-SignWithRandomChain",
michael@0 2286 PR_FALSE)) {
michael@0 2287 PORT_Strcpy(prefix,prefixs[9]);
michael@0 2288 chainLen = atoi(find_field(form_data, "autoCAs", PR_FALSE));
michael@0 2289 if (chainLen < 1 || chainLen > 18) {
michael@0 2290 issuerNameStr = PORT_Strcpy(issuerNameStr,
michael@0 2291 "CN=CA18, O=Cert-O-Matic II");
michael@0 2292 }
michael@0 2293 issuerNameStr = PORT_Strcpy(issuerNameStr, "CN=CA");
michael@0 2294 issuerNameStr = PORT_Strcat(issuerNameStr,
michael@0 2295 find_field(form_data,"autoCAs", PR_FALSE));
michael@0 2296 issuerNameStr = PORT_Strcat(issuerNameStr,", O=Cert-O-Matic II");
michael@0 2297 } else {
michael@0 2298 issuerNameStr = PORT_Strcpy(issuerNameStr,
michael@0 2299 "CN=Cert-O-Matic II, O=Cert-O-Matic II");
michael@0 2300 }
michael@0 2301 chainLen = 0;
michael@0 2302 }
michael@0 2303
michael@0 2304 i = -1;
michael@0 2305 which_key = 0;
michael@0 2306 do {
michael@0 2307 extern SECStatus cert_GetKeyID(CERTCertificate *cert);
michael@0 2308 i++;
michael@0 2309 if (i != 0 && UChain) {
michael@0 2310 PORT_Strcpy(prefix, prefixs[i]);
michael@0 2311 }
michael@0 2312 /* find_field(form_data,"subject", PR_TRUE); */
michael@0 2313 certReq = makeCertReq(form_data, which_key);
michael@0 2314 #ifdef OFFLINE
michael@0 2315 serial = 900;
michael@0 2316 #else
michael@0 2317 serial = get_serial_number(form_data);
michael@0 2318 #endif
michael@0 2319 cert = MakeV1Cert(handle, certReq, issuerNameStr, PR_FALSE,
michael@0 2320 serial, warpmonths, form_data);
michael@0 2321 if (certReq != NULL) {
michael@0 2322 CERT_DestroyCertificateRequest(certReq);
michael@0 2323 }
michael@0 2324 if (find_field_bool(form_data,"ver-3", PR_TRUE)) {
michael@0 2325 status = add_extensions(cert, form_data, issuerNameStr, handle);
michael@0 2326 if (status != SECSuccess) {
michael@0 2327 error_out("ERROR: Unable to add extensions");
michael@0 2328 }
michael@0 2329 }
michael@0 2330 status = cert_GetKeyID(cert);
michael@0 2331 if (status == SECFailure) {
michael@0 2332 error_out("ERROR: Unable to get Key ID.");
michael@0 2333 }
michael@0 2334 certDER = SignCert(cert, issuerNameStr, form_data, handle, which_key);
michael@0 2335 CERT_NewTempCertificate(handle, certDER, NULL, PR_FALSE, PR_TRUE);
michael@0 2336 issuerNameStr = find_field(form_data, "subject", PR_TRUE);
michael@0 2337 /* SECITEM_FreeItem(certDER, PR_TRUE); */
michael@0 2338 CERT_DestroyCertificate(cert);
michael@0 2339 if (i == (chainLen - 1)) {
michael@0 2340 i = 8;
michael@0 2341 }
michael@0 2342 ++which_key;
michael@0 2343 } while (i < 9 && UChain);
michael@0 2344
michael@0 2345
michael@0 2346
michael@0 2347 #ifdef FILEOUT
michael@0 2348 outfile = fopen("../certout", "wb");
michael@0 2349 #endif
michael@0 2350 certName = find_field(form_data, "subject", PR_FALSE);
michael@0 2351 cert = CERT_FindCertByNameString(handle, certName);
michael@0 2352 certChain = SEC_PKCS7CreateCertsOnly (cert, PR_TRUE, handle);
michael@0 2353 if (certChain == NULL) {
michael@0 2354 error_out("ERROR: No certificates in cert chain");
michael@0 2355 }
michael@0 2356 encodedCertChain = SEC_PKCS7EncodeItem (NULL, NULL, certChain, NULL, NULL,
michael@0 2357 NULL);
michael@0 2358 if (encodedCertChain) {
michael@0 2359 #if !defined(FILEOUT)
michael@0 2360 printf("Content-type: application/x-x509-user-cert\r\n");
michael@0 2361 printf("Content-length: %d\r\n\r\n", encodedCertChain->len);
michael@0 2362 fwrite (encodedCertChain->data, 1, encodedCertChain->len, stdout);
michael@0 2363 #else
michael@0 2364 fwrite (encodedCertChain->data, 1, encodedCertChain->len, outfile);
michael@0 2365 #endif
michael@0 2366
michael@0 2367 } else {
michael@0 2368 error_out("Error: Unable to DER encode certificate");
michael@0 2369 }
michael@0 2370 #ifdef FILEOUT
michael@0 2371 printf("\nI got here!\n");
michael@0 2372 fflush(outfile);
michael@0 2373 fclose(outfile);
michael@0 2374 #endif
michael@0 2375 fflush(stdout);
michael@0 2376 if (NSS_Shutdown() != SECSuccess) {
michael@0 2377 exit(1);
michael@0 2378 }
michael@0 2379 return 0;
michael@0 2380 }
michael@0 2381

mercurial