Wed, 31 Dec 2014 07:16:47 +0100
Revert simplistic fix pending revisit of Mozilla integration attempt.
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/. */
5 /* Cert-O-Matic CGI */
8 #include "nspr.h"
9 #include "prtypes.h"
10 #include "prtime.h"
11 #include "prlong.h"
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"
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 ".."
34 static char *progName;
36 typedef struct PairStr Pair;
38 struct PairStr {
39 char *name;
40 char *data;
41 };
44 char prefix[PREFIX_LEN];
47 const SEC_ASN1Template CERTIA5TypeTemplate[] = {
48 { SEC_ASN1_IA5_STRING }
49 };
53 SECKEYPrivateKey *privkeys[9] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL,
54 NULL, NULL};
57 #ifdef notdef
58 const SEC_ASN1Template CERT_GeneralNameTemplate[] = {
59 { SEC_ASN1_SEQUENCE_OF, 0, SEC_AnyTemplate }
60 };
61 #endif
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 }
74 static void
75 error_allocate(void)
76 {
77 error_out("ERROR: Unable to allocate memory");
78 }
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;
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 }
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;
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 }
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;
194 name = make_copy_string(new_data, length, '=');
195 return name;
196 }
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;
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 }
216 static Pair
217 make_pair(char *new_data)
218 /* makes a pair name/data pair from the input string */
219 {
220 Pair temp;
222 temp.name = make_name(new_data);
223 temp.data = make_data(new_data);
224 return temp;
225 }
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;
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 }
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;
276 if ((data_struct + n)->name != NULL) {
277 name = (data_struct + n)->name;
278 return name;
279 } else {
280 return NULL;
281 }
282 }
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;
291 data = (data_struct + n)->data;
292 return data;
293 }
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;
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 }
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;
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 }
343 static PRBool
344 find_field_bool(Pair *data,
345 char *fieldname,
346 PRBool add_pre)
347 {
348 char *rv;
350 rv = find_field(data, fieldname, add_pre);
352 if ((rv != NULL) && (PORT_Strcmp(rv, "true")) == 0) {
353 return PR_TRUE;
354 } else {
355 return PR_FALSE;
356 }
357 }
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;
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 }
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;
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 }
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;
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 }
434 static CERTCertificateRequest *
435 makeCertReq(Pair *form_data,
436 int which_priv_key)
437 /* makes and encodes a certrequest */
438 {
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;
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 }
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;
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);
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 }
570 CERT_DestroyValidity(validity);
571 if ( issuerCert ) {
572 CERT_DestroyCertificate (issuerCert);
573 }
574 return(cert);
575 }
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;
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 }
645 typedef SECStatus (* EXTEN_VALUE_ENCODER)
646 (PLArenaPool *extHandle, void *value, SECItem *encodedValue);
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;
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 }
674 static SECStatus
675 AddKeyUsage (void *extHandle,
676 Pair *data)
677 {
678 SECItem bitStringValue;
679 unsigned char keyUsage = 0x0;
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 }
703 bitStringValue.data = &keyUsage;
704 bitStringValue.len = 1;
706 return (CERT_EncodeAndAddBitStrExtension
707 (extHandle, SEC_OID_X509_KEY_USAGE, &bitStringValue,
708 (find_field_bool(data, "keyUsage-crit", PR_TRUE))));
710 }
712 static CERTOidSequence *
713 CreateOidSequence(void)
714 {
715 CERTOidSequence *rv = (CERTOidSequence *)NULL;
716 PLArenaPool *arena = (PLArenaPool *)NULL;
718 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
719 if( (PLArenaPool *)NULL == arena ) {
720 goto loser;
721 }
723 rv = (CERTOidSequence *)PORT_ArenaZAlloc(arena, sizeof(CERTOidSequence));
724 if( (CERTOidSequence *)NULL == rv ) {
725 goto loser;
726 }
728 rv->oids = (SECItem **)PORT_ArenaZAlloc(arena, sizeof(SECItem *));
729 if( (SECItem **)NULL == rv->oids ) {
730 goto loser;
731 }
733 rv->arena = arena;
734 return rv;
736 loser:
737 if( (PLArenaPool *)NULL != arena ) {
738 PORT_FreeArena(arena, PR_FALSE);
739 }
741 return (CERTOidSequence *)NULL;
742 }
744 static SECStatus
745 AddOidToSequence(CERTOidSequence *os, SECOidTag oidTag)
746 {
747 SECItem **oids;
748 PRUint32 count = 0;
749 SECOidData *od;
751 od = SECOID_FindOIDByTag(oidTag);
752 if( (SECOidData *)NULL == od ) {
753 return SECFailure;
754 }
756 for( oids = os->oids; (SECItem *)NULL != *oids; oids++ ) {
757 count++;
758 }
760 /* ArenaZRealloc */
762 {
763 PRUint32 i;
765 oids = (SECItem **)PORT_ArenaZAlloc(os->arena, sizeof(SECItem *) * (count+2));
766 if( (SECItem **)NULL == oids ) {
767 return SECFailure;
768 }
770 for( i = 0; i < count; i++ ) {
771 oids[i] = os->oids[i];
772 }
774 /* ArenaZFree(os->oids); */
775 }
777 os->oids = oids;
778 os->oids[count] = &od->oid;
780 return SECSuccess;
781 }
783 static SECItem *
784 EncodeOidSequence(CERTOidSequence *os)
785 {
786 SECItem *rv;
787 extern const SEC_ASN1Template CERT_OidSeqTemplate[];
789 rv = (SECItem *)PORT_ArenaZAlloc(os->arena, sizeof(SECItem));
790 if( (SECItem *)NULL == rv ) {
791 goto loser;
792 }
794 if( !SEC_ASN1EncodeItem(os->arena, rv, os, CERT_OidSeqTemplate) ) {
795 goto loser;
796 }
798 return rv;
800 loser:
801 return (SECItem *)NULL;
802 }
804 static SECStatus
805 AddExtKeyUsage(void *extHandle, Pair *data)
806 {
807 SECStatus rv;
808 CERTOidSequence *os;
809 SECItem *value;
810 PRBool crit;
812 os = CreateOidSequence();
813 if( (CERTOidSequence *)NULL == os ) {
814 return SECFailure;
815 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
857 value = EncodeOidSequence(os);
859 crit = find_field_bool(data, "extKeyUsage-crit", PR_TRUE);
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 }
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;
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 }
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;
951 issuerCert = CERT_FindCertByNameString(handle, issuerNameStr);
952 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
953 if ( !arena ) {
954 error_allocate();
955 }
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 {
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;
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 }
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;
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 }
1135 PORT_Assert (arena);
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 }
1156 static SECStatus
1157 AddBasicConstraint(void *extHandle,
1158 Pair *data)
1159 {
1160 CERTBasicConstraints basicConstraint;
1161 SECItem encodedValue;
1162 SECStatus rv;
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 }
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);
1184 PORT_Free (encodedValue.data);
1185 return (rv);
1186 }
1190 static SECStatus
1191 AddNscpCertType (void *extHandle,
1192 Pair *data)
1193 {
1194 SECItem bitStringValue;
1195 unsigned char CertType = 0x0;
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 }
1222 bitStringValue.data = &CertType;
1223 bitStringValue.len = 1;
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 }
1231 static SECStatus
1232 add_IA5StringExtension(void *extHandle,
1233 char *string,
1234 PRBool crit,
1235 int idtag)
1236 {
1237 SECItem encodedValue;
1238 SECStatus rv;
1240 encodedValue.data = NULL;
1241 encodedValue.len = 0;
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 }
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;
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 }
1363 static SECItem *
1364 string_to_ipaddress(char *string)
1365 {
1366 int i = 0;
1367 int value;
1368 int j = 0;
1369 SECItem *ipaddress;
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 }
1420 static SECItem *
1421 string_to_binary(char *string)
1422 {
1423 SECItem *rv;
1424 int high_digit;
1425 int low_digit;
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 }
1468 return rv;
1469 }
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;
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;
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 }
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 }
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 }
1522 case certEDIPartyName:
1523 case certX400Address: {
1525 genName->name.other.data = PORT_ArenaAlloc (arena,
1526 PORT_Strlen (name) + 2);
1527 if (genName->name.other.data == NULL) {
1528 error_allocate();
1529 }
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 }
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 }
1590 case certDirectoryName: {
1591 CERTName *directoryName = NULL;
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);
1602 break;
1603 }
1604 }
1605 genName->l.next = &(genName->l);
1606 genName->l.prev = &(genName->l);
1607 return rv;
1608 }
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;
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) {
1633 rv = MakeGeneralName(name, current, arena);
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 }
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;
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);
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 }
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;
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);
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 }
1863 static SECStatus
1864 AddNameConstraints(void *extHandle,
1865 Pair *data)
1866 {
1867 PLArenaPool *arena = NULL;
1868 CERTNameConstraints *constraints = NULL;
1869 SECStatus rv = SECSuccess;
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 }
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;
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 }
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 }
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 }
2061 char *
2062 return_dbpasswd(PK11SlotInfo *slot, PRBool retry, void *data)
2063 {
2064 char *rv;
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 }
2076 SECKEYPrivateKey *
2077 FindPrivateKeyFromNameStr(char *name,
2078 CERTCertDBHandle *certHandle)
2079 {
2080 SECKEYPrivateKey *key;
2081 CERTCertificate *cert;
2082 CERTCertificate *p11Cert;
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 }
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;
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 }
2126 arena = cert->arena;
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 }
2135 rv = SECOID_SetAlgorithmID(arena, &cert->signature, algID, 0);
2136 if (rv != SECSuccess) {
2137 error_out("ERROR: Could not set signature algorithm id.");
2138 }
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 }
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;
2202 progName = strrchr(argv[0], '/');
2203 progName = progName ? progName+1 : argv[0];
2206 #ifdef TEST
2207 sleep(20);
2208 #endif
2209 SECU_ConfigDirectory(DBdir);
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();
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 }
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);
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
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 }