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