nss: import at 3.0.1 beta 1
[mozilla-nss.git] / security / nss / cmd / certcgi / certcgi.c
blob038b55f98aba60d4e2ca2642d4122ad5afbf765f
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
37 /* Cert-O-Matic CGI */
40 #include "nspr.h"
41 #include "prtypes.h"
42 #include "prtime.h"
43 #include "prlong.h"
45 #include "pk11func.h"
46 #include "cert.h"
47 #include "cryptohi.h"
48 #include "secoid.h"
49 #include "secder.h"
50 #include "genname.h"
51 #include "xconst.h"
52 #include "secutil.h"
53 #include "pk11pqg.h"
54 #include "certxutl.h"
55 #include "nss.h"
58 /* #define TEST 1 */
59 /* #define FILEOUT 1 */
60 /* #define OFFLINE 1 */
61 #define START_FIELDS 100
62 #define PREFIX_LEN 6
63 #define SERIAL_FILE "../serial"
64 #define DB_DIRECTORY ".."
66 static char *progName;
68 typedef struct PairStr Pair;
70 struct PairStr {
71 char *name;
72 char *data;
76 char prefix[PREFIX_LEN];
79 const SEC_ASN1Template CERTIA5TypeTemplate[] = {
80 { SEC_ASN1_IA5_STRING }
85 SECKEYPrivateKey *privkeys[9] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL,
86 NULL, NULL};
89 #ifdef notdef
90 const SEC_ASN1Template CERT_GeneralNameTemplate[] = {
91 { SEC_ASN1_SEQUENCE_OF, 0, SEC_AnyTemplate }
93 #endif
96 static void
97 error_out(char *error_string)
99 printf("Content-type: text/plain\n\n");
100 printf(error_string);
101 fflush(stderr);
102 fflush(stdout);
103 exit(1);
106 static void
107 error_allocate(void)
109 error_out("ERROR: Unable to allocate memory");
113 static char *
114 make_copy_string(char *read_pos,
115 int length,
116 char sentinal_value)
117 /* copys string from to a new string it creates and
118 returns a pointer to the new string */
120 int remaining = length;
121 char *write_pos;
122 char *new;
124 new = write_pos = (char *) PORT_Alloc (length);
125 if (new == NULL) {
126 error_allocate();
128 while (*read_pos != sentinal_value) {
129 if (remaining == 1) {
130 remaining += length;
131 length = length * 2;
132 new = PORT_Realloc(new,length);
133 if (new == NULL) {
134 error_allocate();
136 write_pos = new + length - remaining;
138 *write_pos = *read_pos;
139 ++write_pos;
140 ++read_pos;
141 remaining = remaining - 1;
143 *write_pos = '\0';
144 return new;
148 static SECStatus
149 clean_input(Pair *data)
150 /* converts the non-alphanumeric characters in a form post
151 from hex codes back to characters */
153 int length;
154 int hi_digit;
155 int low_digit;
156 char character;
157 char *begin_pos;
158 char *read_pos;
159 char *write_pos;
160 PRBool name = PR_TRUE;
162 begin_pos = data->name;
163 while (begin_pos != NULL) {
164 length = strlen(begin_pos);
165 read_pos = write_pos = begin_pos;
166 while ((read_pos - begin_pos) < length) {
167 if (*read_pos == '+') {
168 *read_pos = ' ';
170 if (*read_pos == '%') {
171 hi_digit = *(read_pos + 1);
172 low_digit = *(read_pos +2);
173 read_pos += 3;
174 if (isdigit(hi_digit)){
175 hi_digit = hi_digit - '0';
176 } else {
177 hi_digit = toupper(hi_digit);
178 if (isxdigit(hi_digit)) {
179 hi_digit = (hi_digit - 'A') + 10;
180 } else {
181 error_out("ERROR: Form data incorrectly formated");
184 if (isdigit(low_digit)){
185 low_digit = low_digit - '0';
186 } else {
187 low_digit = toupper(low_digit);
188 if ((low_digit >='A') && (low_digit <= 'F')) {
189 low_digit = (low_digit - 'A') + 10;
190 } else {
191 error_out("ERROR: Form data incorrectly formated");
194 character = (hi_digit << 4) | low_digit;
195 if (character != 10) {
196 *write_pos = character;
197 ++write_pos;
199 } else {
200 *write_pos = *read_pos;
201 ++write_pos;
202 ++read_pos;
205 *write_pos = '\0';
206 if (name == PR_TRUE) {
207 begin_pos = data->data;
208 name = PR_FALSE;
209 } else {
210 data++;
211 begin_pos = data->name;
212 name = PR_TRUE;
215 return SECSuccess;
218 static char *
219 make_name(char *new_data)
220 /* gets the next field name in the input string and returns
221 a pointer to a string containing a copy of it */
223 int length = 20;
224 char *name;
226 name = make_copy_string(new_data, length, '=');
227 return name;
230 static char *
231 make_data(char *new_data)
232 /* gets the data for the next field in the input string
233 and returns a pointer to a string containing it */
235 int length = 100;
236 char *data;
237 char *read_pos;
239 read_pos = new_data;
240 while (*(read_pos - 1) != '=') {
241 ++read_pos;
243 data = make_copy_string(read_pos, length, '&');
244 return data;
248 static Pair
249 make_pair(char *new_data)
250 /* makes a pair name/data pair from the input string */
252 Pair temp;
254 temp.name = make_name(new_data);
255 temp.data = make_data(new_data);
256 return temp;
261 static Pair *
262 make_datastruct(char *data, int len)
263 /* parses the input from the form post into a data
264 structure of field name/data pairs */
266 Pair *datastruct;
267 Pair *current;
268 char *curr_pos;
269 int fields = START_FIELDS;
270 int remaining = START_FIELDS;
272 curr_pos = data;
273 datastruct = current = (Pair *) PORT_Alloc(fields * sizeof(Pair));
274 if (datastruct == NULL) {
275 error_allocate();
277 while (curr_pos - data < len) {
278 if (remaining == 1) {
279 remaining += fields;
280 fields = fields * 2;
281 datastruct = (Pair *) PORT_Realloc
282 (datastruct, fields * sizeof(Pair));
283 if (datastruct == NULL) {
284 error_allocate();
286 current = datastruct + (fields - remaining);
288 *current = make_pair(curr_pos);
289 while (*curr_pos != '&') {
290 ++curr_pos;
292 ++curr_pos;
293 ++current;
294 remaining = remaining - 1;
296 current->name = NULL;
297 return datastruct;
300 static char *
301 return_name(Pair *data_struct,
302 int n)
303 /* returns a pointer to the name of the nth
304 (starting from 0) item in the data structure */
306 char *name;
308 if ((data_struct + n)->name != NULL) {
309 name = (data_struct + n)->name;
310 return name;
311 } else {
312 return NULL;
316 static char *
317 return_data(Pair *data_struct,int n)
318 /* returns a pointer to the data of the nth (starting from 0)
319 itme in the data structure */
321 char *data;
323 data = (data_struct + n)->data;
324 return data;
328 static char *
329 add_prefix(char *field_name)
331 extern char prefix[PREFIX_LEN];
332 int i = 0;
333 char *rv;
334 char *write;
336 rv = write = PORT_Alloc(PORT_Strlen(prefix) + PORT_Strlen(field_name) + 1);
337 for(i = 0; i < PORT_Strlen(prefix); i++) {
338 *write = prefix[i];
339 write++;
341 *write = '\0';
342 rv = PORT_Strcat(rv,field_name);
343 return rv;
347 static char *
348 find_field(Pair *data,
349 char *field_name,
350 PRBool add_pre)
351 /* returns a pointer to the data of the first pair
352 thats name matches the string it is passed */
354 int i = 0;
355 char *retrieved;
356 int found = 0;
358 if (add_pre) {
359 field_name = add_prefix(field_name);
361 while(return_name(data, i) != NULL) {
362 if (PORT_Strcmp(return_name(data, i), field_name) == 0) {
363 retrieved = return_data(data, i);
364 found = 1;
365 break;
367 i++;
369 if (!found) {
370 retrieved = NULL;
372 return retrieved;
375 static PRBool
376 find_field_bool(Pair *data,
377 char *fieldname,
378 PRBool add_pre)
380 char *rv;
382 rv = find_field(data, fieldname, add_pre);
384 if ((rv != NULL) && (PORT_Strcmp(rv, "true")) == 0) {
385 return PR_TRUE;
386 } else {
387 return PR_FALSE;
391 static char *
392 update_data_by_name(Pair *data,
393 char *field_name,
394 char *new_data)
395 /* replaces the data in the data structure associated with
396 a name with new data, returns null if not found */
398 int i = 0;
399 int found = 0;
400 int length = 100;
401 char *new;
403 while (return_name(data, i) != NULL) {
404 if (PORT_Strcmp(return_name(data, i), field_name) == 0) {
405 new = make_copy_string( new_data, length, '\0');
406 PORT_Free(return_data(data, i));
407 found = 1;
408 (*(data + i)).data = new;
409 break;
411 i++;
413 if (!found) {
414 new = NULL;
416 return new;
419 static char *
420 update_data_by_index(Pair *data,
421 int n,
422 char *new_data)
423 /* replaces the data of a particular index in the data structure */
425 int length = 100;
426 char *new;
428 new = make_copy_string(new_data, length, '\0');
429 PORT_Free(return_data(data, n));
430 (*(data + n)).data = new;
431 return new;
435 static Pair *
436 add_field(Pair *data,
437 char* field_name,
438 char* field_data)
439 /* adds a new name/data pair to the data structure */
441 int i = 0;
442 int j;
443 int name_length = 100;
444 int data_length = 100;
446 while(return_name(data, i) != NULL) {
447 i++;
449 j = START_FIELDS;
450 while ( j < (i + 1) ) {
451 j = j * 2;
453 if (j == (i + 1)) {
454 data = (Pair *) PORT_Realloc(data, (j * 2) * sizeof(Pair));
455 if (data == NULL) {
456 error_allocate();
459 (*(data + i)).name = make_copy_string(field_name, name_length, '\0');
460 (*(data + i)).data = make_copy_string(field_data, data_length, '\0');
461 (data + i + 1)->name = NULL;
462 return data;
466 static CERTCertificateRequest *
467 makeCertReq(Pair *form_data,
468 int which_priv_key)
469 /* makes and encodes a certrequest */
472 PK11SlotInfo *slot;
473 CERTCertificateRequest *certReq = NULL;
474 CERTSubjectPublicKeyInfo *spki;
475 SECKEYPrivateKey *privkey = NULL;
476 SECKEYPublicKey *pubkey = NULL;
477 CERTName *name;
478 char *key;
479 extern SECKEYPrivateKey *privkeys[9];
480 int keySizeInBits;
481 char *challenge = "foo";
482 SECStatus rv = SECSuccess;
483 PQGParams *pqgParams = NULL;
484 PQGVerify *pqgVfy = NULL;
486 name = CERT_AsciiToName(find_field(form_data, "subject", PR_TRUE));
487 if (name == NULL) {
488 error_out("ERROR: Unable to create Subject Name");
490 key = find_field(form_data, "key", PR_TRUE);
491 if (key == NULL) {
492 switch (*find_field(form_data, "keysize", PR_TRUE)) {
493 case '0':
494 keySizeInBits = 2048;
495 break;
496 case '1':
497 keySizeInBits = 1024;
498 break;
499 case '2':
500 keySizeInBits = 512;
501 break;
502 default:
503 error_out("ERROR: Unsupported Key length selected");
505 if (find_field_bool(form_data, "keyType-dsa", PR_TRUE)) {
506 rv = PK11_PQG_ParamGen(keySizeInBits, &pqgParams, &pqgVfy);
507 if (rv != SECSuccess) {
508 error_out("ERROR: Unable to generate PQG parameters");
510 slot = PK11_GetBestSlot(CKM_DSA_KEY_PAIR_GEN, NULL);
511 privkey = PK11_GenerateKeyPair(slot, CKM_DSA_KEY_PAIR_GEN,
512 pqgParams,&pubkey, PR_FALSE,
513 PR_TRUE, NULL);
514 } else {
515 privkey = SECKEY_CreateRSAPrivateKey(keySizeInBits, &pubkey, NULL);
517 privkeys[which_priv_key] = privkey;
518 spki = SECKEY_CreateSubjectPublicKeyInfo(pubkey);
519 } else {
520 spki = SECKEY_ConvertAndDecodePublicKeyAndChallenge(key, challenge,
521 NULL);
522 if (spki == NULL) {
523 error_out("ERROR: Unable to decode Public Key and Challenge String");
526 certReq = CERT_CreateCertificateRequest(name, spki, NULL);
527 if (certReq == NULL) {
528 error_out("ERROR: Unable to create Certificate Request");
530 if (pubkey != NULL) {
531 SECKEY_DestroyPublicKey(pubkey);
533 if (spki != NULL) {
534 SECKEY_DestroySubjectPublicKeyInfo(spki);
536 if (pqgParams != NULL) {
537 PK11_PQG_DestroyParams(pqgParams);
539 if (pqgVfy != NULL) {
540 PK11_PQG_DestroyVerify(pqgVfy);
542 return certReq;
547 static CERTCertificate *
548 MakeV1Cert(CERTCertDBHandle *handle,
549 CERTCertificateRequest *req,
550 char *issuerNameStr,
551 PRBool selfsign,
552 int serialNumber,
553 int warpmonths,
554 Pair *data)
556 CERTCertificate *issuerCert = NULL;
557 CERTValidity *validity;
558 CERTCertificate *cert = NULL;
559 PRExplodedTime printableTime;
560 PRTime now,
561 after;
562 SECStatus rv;
566 if ( !selfsign ) {
567 issuerCert = CERT_FindCertByNameString(handle, issuerNameStr);
568 if (!issuerCert) {
569 error_out("ERROR: Could not find issuer's certificate");
570 return NULL;
573 if (find_field_bool(data, "manValidity", PR_TRUE)) {
574 rv = DER_AsciiToTime(&now, find_field(data, "notBefore", PR_TRUE));
575 } else {
576 now = PR_Now();
578 PR_ExplodeTime (now, PR_GMTParameters, &printableTime);
579 if ( warpmonths ) {
580 printableTime.tm_month += warpmonths;
581 now = PR_ImplodeTime (&printableTime);
582 PR_ExplodeTime (now, PR_GMTParameters, &printableTime);
584 if (find_field_bool(data, "manValidity", PR_TRUE)) {
585 rv = DER_AsciiToTime(&after, find_field(data, "notAfter", PR_TRUE));
586 PR_ExplodeTime (after, PR_GMTParameters, &printableTime);
587 } else {
588 printableTime.tm_month += 3;
589 after = PR_ImplodeTime (&printableTime);
591 /* note that the time is now in micro-second unit */
592 validity = CERT_CreateValidity (now, after);
594 if ( selfsign ) {
595 cert = CERT_CreateCertificate
596 (serialNumber,&(req->subject), validity, req);
597 } else {
598 cert = CERT_CreateCertificate
599 (serialNumber,&(issuerCert->subject), validity, req);
602 CERT_DestroyValidity(validity);
603 if ( issuerCert ) {
604 CERT_DestroyCertificate (issuerCert);
606 return(cert);
609 static int
610 get_serial_number(Pair *data)
612 int serial = 0;
613 int error;
614 char *filename = SERIAL_FILE;
615 char *SN;
616 FILE *serialFile;
619 if (find_field_bool(data, "serial-auto", PR_TRUE)) {
620 serialFile = fopen(filename, "r");
621 if (serialFile != NULL) {
622 fread(&serial, sizeof(int), 1, serialFile);
623 if (ferror(serialFile) != 0) {
624 error_out("Error: Unable to read serial number file");
626 if (serial == 4294967295) {
627 serial = 21;
629 fclose(serialFile);
630 ++serial;
631 serialFile = fopen(filename,"w");
632 if (serialFile == NULL) {
633 error_out("ERROR: Unable to open serial number file for writing");
635 fwrite(&serial, sizeof(int), 1, serialFile);
636 if (ferror(serialFile) != 0) {
637 error_out("Error: Unable to write to serial number file");
639 } else {
640 fclose(serialFile);
641 serialFile = fopen(filename,"w");
642 if (serialFile == NULL) {
643 error_out("ERROR: Unable to open serial number file");
645 serial = 21;
646 fwrite(&serial, sizeof(int), 1, serialFile);
647 if (ferror(serialFile) != 0) {
648 error_out("Error: Unable to write to serial number file");
650 error = ferror(serialFile);
651 if (error != 0) {
652 error_out("ERROR: Unable to write to serial file");
655 fclose(serialFile);
656 } else {
657 SN = find_field(data, "serial_value", PR_TRUE);
658 while (*SN != '\0') {
659 serial = serial * 16;
660 if ((*SN >= 'A') && (*SN <='F')) {
661 serial += *SN - 'A' + 10;
662 } else {
663 if ((*SN >= 'a') && (*SN <='f')) {
664 serial += *SN - 'a' + 10;
665 } else {
666 serial += *SN - '0';
669 ++SN;
672 return serial;
677 typedef SECStatus (* EXTEN_VALUE_ENCODER)
678 (PRArenaPool *extHandle, void *value, SECItem *encodedValue);
680 static SECStatus
681 EncodeAndAddExtensionValue(
682 PRArenaPool *arena,
683 void *extHandle,
684 void *value,
685 PRBool criticality,
686 int extenType,
687 EXTEN_VALUE_ENCODER EncodeValueFn)
689 SECItem encodedValue;
690 SECStatus rv;
693 encodedValue.data = NULL;
694 encodedValue.len = 0;
695 rv = (*EncodeValueFn)(arena, value, &encodedValue);
696 if (rv != SECSuccess) {
697 error_out("ERROR: Unable to encode extension value");
699 rv = CERT_AddExtension
700 (extHandle, extenType, &encodedValue, criticality, PR_TRUE);
701 return (rv);
706 static SECStatus
707 AddKeyUsage (void *extHandle,
708 Pair *data)
710 SECItem bitStringValue;
711 unsigned char keyUsage = 0x0;
713 if (find_field_bool(data,"keyUsage-digitalSignature", PR_TRUE)){
714 keyUsage |= (0x80 >> 0);
716 if (find_field_bool(data,"keyUsage-nonRepudiation", PR_TRUE)){
717 keyUsage |= (0x80 >> 1);
719 if (find_field_bool(data,"keyUsage-keyEncipherment", PR_TRUE)){
720 keyUsage |= (0x80 >> 2);
722 if (find_field_bool(data,"keyUsage-dataEncipherment", PR_TRUE)){
723 keyUsage |= (0x80 >> 3);
725 if (find_field_bool(data,"keyUsage-keyAgreement", PR_TRUE)){
726 keyUsage |= (0x80 >> 4);
728 if (find_field_bool(data,"keyUsage-keyCertSign", PR_TRUE)) {
729 keyUsage |= (0x80 >> 5);
731 if (find_field_bool(data,"keyUsage-cRLSign", PR_TRUE)) {
732 keyUsage |= (0x80 >> 6);
735 bitStringValue.data = &keyUsage;
736 bitStringValue.len = 1;
738 return (CERT_EncodeAndAddBitStrExtension
739 (extHandle, SEC_OID_X509_KEY_USAGE, &bitStringValue,
740 (find_field_bool(data, "keyUsage-crit", PR_TRUE))));
744 static CERTOidSequence *
745 CreateOidSequence(void)
747 CERTOidSequence *rv = (CERTOidSequence *)NULL;
748 PRArenaPool *arena = (PRArenaPool *)NULL;
750 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
751 if( (PRArenaPool *)NULL == arena ) {
752 goto loser;
755 rv = (CERTOidSequence *)PORT_ArenaZAlloc(arena, sizeof(CERTOidSequence));
756 if( (CERTOidSequence *)NULL == rv ) {
757 goto loser;
760 rv->oids = (SECItem **)PORT_ArenaZAlloc(arena, sizeof(SECItem *));
761 if( (SECItem **)NULL == rv->oids ) {
762 goto loser;
765 rv->arena = arena;
766 return rv;
768 loser:
769 if( (PRArenaPool *)NULL != arena ) {
770 PORT_FreeArena(arena, PR_FALSE);
773 return (CERTOidSequence *)NULL;
776 static SECStatus
777 AddOidToSequence(CERTOidSequence *os, SECOidTag oidTag)
779 SECItem **oids;
780 PRUint32 count = 0;
781 SECOidData *od;
783 od = SECOID_FindOIDByTag(oidTag);
784 if( (SECOidData *)NULL == od ) {
785 return SECFailure;
788 for( oids = os->oids; (SECItem *)NULL != *oids; oids++ ) {
789 count++;
792 /* ArenaZRealloc */
795 PRUint32 i;
797 oids = (SECItem **)PORT_ArenaZAlloc(os->arena, sizeof(SECItem *) * (count+2));
798 if( (SECItem **)NULL == oids ) {
799 return SECFailure;
802 for( i = 0; i < count; i++ ) {
803 oids[i] = os->oids[i];
806 /* ArenaZFree(os->oids); */
809 os->oids = oids;
810 os->oids[count] = &od->oid;
812 return SECSuccess;
815 static SECItem *
816 EncodeOidSequence(CERTOidSequence *os)
818 SECItem *rv;
819 extern const SEC_ASN1Template CERT_OidSeqTemplate[];
821 rv = (SECItem *)PORT_ArenaZAlloc(os->arena, sizeof(SECItem));
822 if( (SECItem *)NULL == rv ) {
823 goto loser;
826 if( !SEC_ASN1EncodeItem(os->arena, rv, os, CERT_OidSeqTemplate) ) {
827 goto loser;
830 return rv;
832 loser:
833 return (SECItem *)NULL;
836 static SECStatus
837 AddExtKeyUsage(void *extHandle, Pair *data)
839 SECStatus rv;
840 CERTOidSequence *os;
841 SECItem *value;
842 PRBool crit;
844 os = CreateOidSequence();
845 if( (CERTOidSequence *)NULL == os ) {
846 return SECFailure;
849 if( find_field_bool(data, "extKeyUsage-serverAuth", PR_TRUE) ) {
850 rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_SERVER_AUTH);
851 if( SECSuccess != rv ) goto loser;
854 if( find_field_bool(data, "extKeyUsage-clientAuth", PR_TRUE) ) {
855 rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH);
856 if( SECSuccess != rv ) goto loser;
859 if( find_field_bool(data, "extKeyUsage-codeSign", PR_TRUE) ) {
860 rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_CODE_SIGN);
861 if( SECSuccess != rv ) goto loser;
864 if( find_field_bool(data, "extKeyUsage-emailProtect", PR_TRUE) ) {
865 rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT);
866 if( SECSuccess != rv ) goto loser;
869 if( find_field_bool(data, "extKeyUsage-timeStamp", PR_TRUE) ) {
870 rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_TIME_STAMP);
871 if( SECSuccess != rv ) goto loser;
874 if( find_field_bool(data, "extKeyUsage-ocspResponder", PR_TRUE) ) {
875 rv = AddOidToSequence(os, SEC_OID_OCSP_RESPONDER);
876 if( SECSuccess != rv ) goto loser;
879 if( find_field_bool(data, "extKeyUsage-NS-govtApproved", PR_TRUE) ) {
880 rv = AddOidToSequence(os, SEC_OID_NS_KEY_USAGE_GOVT_APPROVED);
881 if( SECSuccess != rv ) goto loser;
884 value = EncodeOidSequence(os);
886 crit = find_field_bool(data, "extKeyUsage-crit", PR_TRUE);
888 rv = CERT_AddExtension(extHandle, SEC_OID_X509_EXT_KEY_USAGE, value,
889 crit, PR_TRUE);
890 /*FALLTHROUGH*/
891 loser:
892 CERT_DestroyOidSequence(os);
893 return rv;
896 static SECStatus
897 AddSubKeyID(void *extHandle,
898 Pair *data,
899 CERTCertificate *subjectCert)
901 SECItem encodedValue;
902 SECStatus rv;
903 char *read;
904 char *write;
905 char *first;
906 char character;
907 int high_digit = 0,
908 low_digit = 0;
909 int len;
910 PRBool odd = PR_FALSE;
913 encodedValue.data = NULL;
914 encodedValue.len = 0;
915 first = read = write = find_field(data,"subjectKeyIdentifier-text",
916 PR_TRUE);
917 len = PORT_Strlen(first);
918 odd = ((len % 2) != 0 ) ? PR_TRUE : PR_FALSE;
919 if (find_field_bool(data, "subjectKeyIdentifier-radio-hex", PR_TRUE)) {
920 if (odd) {
921 error_out("ERROR: Improperly formated subject key identifier, hex values must be expressed as an octet string");
923 while (*read != '\0') {
924 if (!isxdigit(*read)) {
925 error_out("ERROR: Improperly formated subject key identifier");
927 *read = toupper(*read);
928 if ((*read >= 'A') && (*read <= 'F')) {
929 high_digit = *read - 'A' + 10;
930 } else {
931 high_digit = *read - '0';
933 ++read;
934 if (!isxdigit(*read)) {
935 error_out("ERROR: Improperly formated subject key identifier");
937 *read = toupper(*read);
938 if ((*read >= 'A') && (*read <= 'F')) {
939 low_digit = *(read) - 'A' + 10;
940 } else {
941 low_digit = *(read) - '0';
943 character = (high_digit << 4) | low_digit;
944 *write = character;
945 ++write;
946 ++read;
948 *write = '\0';
949 len = write - first;
951 subjectCert->subjectKeyID.data = (unsigned char *) find_field
952 (data,"subjectKeyIdentifier-text", PR_TRUE);
953 subjectCert->subjectKeyID.len = len;
954 rv = CERT_EncodeSubjectKeyID
955 (NULL, &subjectCert->subjectKeyID, &encodedValue);
956 if (rv) {
957 return (rv);
959 return (CERT_AddExtension(extHandle, SEC_OID_X509_SUBJECT_KEY_ID,
960 &encodedValue, PR_FALSE, PR_TRUE));
964 static SECStatus
965 AddAuthKeyID (void *extHandle,
966 Pair *data,
967 char *issuerNameStr,
968 CERTCertDBHandle *handle)
970 CERTAuthKeyID *authKeyID = NULL;
971 PRArenaPool *arena = NULL;
972 SECStatus rv = SECSuccess;
973 CERTCertificate *issuerCert = NULL;
974 CERTGeneralName *genNames;
975 CERTName *directoryName = NULL;
978 issuerCert = CERT_FindCertByNameString(handle, issuerNameStr);
979 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
980 if ( !arena ) {
981 error_allocate();
984 authKeyID = PORT_ArenaZAlloc (arena, sizeof (CERTAuthKeyID));
985 if (authKeyID == NULL) {
986 error_allocate();
988 if (find_field_bool(data, "authorityKeyIdentifier-radio-keyIdentifier",
989 PR_TRUE)) {
990 authKeyID->keyID.data = PORT_ArenaAlloc (arena, PORT_Strlen
991 ((char *)issuerCert->subjectKeyID.data));
992 if (authKeyID->keyID.data == NULL) {
993 error_allocate();
995 PORT_Memcpy (authKeyID->keyID.data, issuerCert->subjectKeyID.data,
996 authKeyID->keyID.len =
997 PORT_Strlen((char *)issuerCert->subjectKeyID.data));
998 } else {
1000 PORT_Assert (arena);
1001 genNames = (CERTGeneralName *) PORT_ArenaZAlloc (arena, (sizeof(CERTGeneralName)));
1002 if (genNames == NULL){
1003 error_allocate();
1005 genNames->l.next = genNames->l.prev = &(genNames->l);
1006 genNames->type = certDirectoryName;
1008 directoryName = CERT_AsciiToName(issuerCert->subjectName);
1009 if (!directoryName) {
1010 error_out("ERROR: Unable to create Directory Name");
1012 rv = CERT_CopyName (arena, &genNames->name.directoryName,
1013 directoryName);
1014 CERT_DestroyName (directoryName);
1015 if (rv != SECSuccess) {
1016 error_out("ERROR: Unable to copy Directory Name");
1018 authKeyID->authCertIssuer = genNames;
1019 if (authKeyID->authCertIssuer == NULL && SECFailure ==
1020 PORT_GetError ()) {
1021 error_out("ERROR: Unable to get Issuer General Name for Authority Key ID Extension");
1023 authKeyID->authCertSerialNumber = issuerCert->serialNumber;
1025 rv = EncodeAndAddExtensionValue(arena, extHandle, authKeyID, PR_FALSE,
1026 SEC_OID_X509_AUTH_KEY_ID,
1027 (EXTEN_VALUE_ENCODER)
1028 CERT_EncodeAuthKeyID);
1029 if (arena) {
1030 PORT_FreeArena (arena, PR_FALSE);
1032 return (rv);
1036 static SECStatus
1037 AddPrivKeyUsagePeriod(void *extHandle,
1038 Pair *data,
1039 CERTCertificate *cert)
1041 char *notBeforeStr;
1042 char *notAfterStr;
1043 PRArenaPool *arena = NULL;
1044 SECStatus rv = SECSuccess;
1045 CERTPrivKeyUsagePeriod *pkup;
1048 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1049 if ( !arena ) {
1050 error_allocate();
1052 pkup = PORT_ArenaZNew (arena, CERTPrivKeyUsagePeriod);
1053 if (pkup == NULL) {
1054 error_allocate();
1056 notBeforeStr = (char *) PORT_Alloc(16 );
1057 notAfterStr = (char *) PORT_Alloc(16 );
1058 *notBeforeStr = '\0';
1059 *notAfterStr = '\0';
1060 pkup->arena = arena;
1061 pkup->notBefore.len = 0;
1062 pkup->notBefore.data = NULL;
1063 pkup->notAfter.len = 0;
1064 pkup->notAfter.data = NULL;
1065 if (find_field_bool(data, "privKeyUsagePeriod-radio-notBefore", PR_TRUE) ||
1066 find_field_bool(data, "privKeyUsagePeriod-radio-both", PR_TRUE)) {
1067 pkup->notBefore.len = 15;
1068 pkup->notBefore.data = (unsigned char *)notBeforeStr;
1069 if (find_field_bool(data, "privKeyUsagePeriod-notBefore-radio-manual",
1070 PR_TRUE)) {
1071 PORT_Strcat(notBeforeStr,find_field(data,
1072 "privKeyUsagePeriod-notBefore-year",
1073 PR_TRUE));
1074 PORT_Strcat(notBeforeStr,find_field(data,
1075 "privKeyUsagePeriod-notBefore-month",
1076 PR_TRUE));
1077 PORT_Strcat(notBeforeStr,find_field(data,
1078 "privKeyUsagePeriod-notBefore-day",
1079 PR_TRUE));
1080 PORT_Strcat(notBeforeStr,find_field(data,
1081 "privKeyUsagePeriod-notBefore-hour",
1082 PR_TRUE));
1083 PORT_Strcat(notBeforeStr,find_field(data,
1084 "privKeyUsagePeriod-notBefore-minute",
1085 PR_TRUE));
1086 PORT_Strcat(notBeforeStr,find_field(data,
1087 "privKeyUsagePeriod-notBefore-second",
1088 PR_TRUE));
1089 if ((*(notBeforeStr + 14) != '\0') ||
1090 (!isdigit(*(notBeforeStr + 13))) ||
1091 (*(notBeforeStr + 12) >= '5' && *(notBeforeStr + 12) <= '0') ||
1092 (!isdigit(*(notBeforeStr + 11))) ||
1093 (*(notBeforeStr + 10) >= '5' && *(notBeforeStr + 10) <= '0') ||
1094 (!isdigit(*(notBeforeStr + 9))) ||
1095 (*(notBeforeStr + 8) >= '2' && *(notBeforeStr + 8) <= '0') ||
1096 (!isdigit(*(notBeforeStr + 7))) ||
1097 (*(notBeforeStr + 6) >= '3' && *(notBeforeStr + 6) <= '0') ||
1098 (!isdigit(*(notBeforeStr + 5))) ||
1099 (*(notBeforeStr + 4) >= '1' && *(notBeforeStr + 4) <= '0') ||
1100 (!isdigit(*(notBeforeStr + 3))) ||
1101 (!isdigit(*(notBeforeStr + 2))) ||
1102 (!isdigit(*(notBeforeStr + 1))) ||
1103 (!isdigit(*(notBeforeStr + 0))) ||
1104 (*(notBeforeStr + 8) == '2' && *(notBeforeStr + 9) >= '4') ||
1105 (*(notBeforeStr + 6) == '3' && *(notBeforeStr + 7) >= '1') ||
1106 (*(notBeforeStr + 4) == '1' && *(notBeforeStr + 5) >= '2')) {
1107 error_out("ERROR: Improperly formated private key usage period");
1109 *(notBeforeStr + 14) = 'Z';
1110 *(notBeforeStr + 15) = '\0';
1111 } else {
1112 if ((*(cert->validity.notBefore.data) > '5') ||
1113 ((*(cert->validity.notBefore.data) == '5') &&
1114 (*(cert->validity.notBefore.data + 1) != '0'))) {
1115 PORT_Strcat(notBeforeStr, "19");
1116 } else {
1117 PORT_Strcat(notBeforeStr, "20");
1119 PORT_Strcat(notBeforeStr, (char *)cert->validity.notBefore.data);
1122 if (find_field_bool(data, "privKeyUsagePeriod-radio-notAfter", PR_TRUE) ||
1123 find_field_bool(data, "privKeyUsagePeriod-radio-both", PR_TRUE)) {
1124 pkup->notAfter.len = 15;
1125 pkup->notAfter.data = (unsigned char *)notAfterStr;
1126 PORT_Strcat(notAfterStr,find_field(data,"privKeyUsagePeriod-notAfter-year",
1127 PR_TRUE));
1128 PORT_Strcat(notAfterStr,find_field(data,"privKeyUsagePeriod-notAfter-month",
1129 PR_TRUE));
1130 PORT_Strcat(notAfterStr,find_field(data,"privKeyUsagePeriod-notAfter-day",
1131 PR_TRUE));
1132 PORT_Strcat(notAfterStr,find_field(data,"privKeyUsagePeriod-notAfter-hour",
1133 PR_TRUE));
1134 PORT_Strcat(notAfterStr,find_field(data,"privKeyUsagePeriod-notAfter-minute",
1135 PR_TRUE));
1136 PORT_Strcat(notAfterStr,find_field(data,"privKeyUsagePeriod-notAfter-second",
1137 PR_TRUE));
1138 if ((*(notAfterStr + 14) != '\0') ||
1139 (!isdigit(*(notAfterStr + 13))) ||
1140 (*(notAfterStr + 12) >= '5' && *(notAfterStr + 12) <= '0') ||
1141 (!isdigit(*(notAfterStr + 11))) ||
1142 (*(notAfterStr + 10) >= '5' && *(notAfterStr + 10) <= '0') ||
1143 (!isdigit(*(notAfterStr + 9))) ||
1144 (*(notAfterStr + 8) >= '2' && *(notAfterStr + 8) <= '0') ||
1145 (!isdigit(*(notAfterStr + 7))) ||
1146 (*(notAfterStr + 6) >= '3' && *(notAfterStr + 6) <= '0') ||
1147 (!isdigit(*(notAfterStr + 5))) ||
1148 (*(notAfterStr + 4) >= '1' && *(notAfterStr + 4) <= '0') ||
1149 (!isdigit(*(notAfterStr + 3))) ||
1150 (!isdigit(*(notAfterStr + 2))) ||
1151 (!isdigit(*(notAfterStr + 1))) ||
1152 (!isdigit(*(notAfterStr + 0))) ||
1153 (*(notAfterStr + 8) == '2' && *(notAfterStr + 9) >= '4') ||
1154 (*(notAfterStr + 6) == '3' && *(notAfterStr + 7) >= '1') ||
1155 (*(notAfterStr + 4) == '1' && *(notAfterStr + 5) >= '2')) {
1156 error_out("ERROR: Improperly formated private key usage period");
1158 *(notAfterStr + 14) = 'Z';
1159 *(notAfterStr + 15) = '\0';
1162 PORT_Assert (arena);
1164 rv = EncodeAndAddExtensionValue(arena, extHandle, pkup,
1165 find_field_bool(data,
1166 "privKeyUsagePeriod-crit",
1167 PR_TRUE),
1168 SEC_OID_X509_PRIVATE_KEY_USAGE_PERIOD,
1169 (EXTEN_VALUE_ENCODER)
1170 CERT_EncodePrivateKeyUsagePeriod);
1171 if (arena) {
1172 PORT_FreeArena (arena, PR_FALSE);
1174 if (notBeforeStr != NULL) {
1175 PORT_Free(notBeforeStr);
1177 if (notAfterStr != NULL) {
1178 PORT_Free(notAfterStr);
1180 return (rv);
1183 static SECStatus
1184 AddBasicConstraint(void *extHandle,
1185 Pair *data)
1187 CERTBasicConstraints basicConstraint;
1188 SECItem encodedValue;
1189 SECStatus rv;
1191 encodedValue.data = NULL;
1192 encodedValue.len = 0;
1193 basicConstraint.pathLenConstraint = CERT_UNLIMITED_PATH_CONSTRAINT;
1194 basicConstraint.isCA = (find_field_bool(data,"basicConstraints-cA-radio-CA",
1195 PR_TRUE));
1196 if (find_field_bool(data,"basicConstraints-pathLengthConstraint", PR_TRUE)){
1197 basicConstraint.pathLenConstraint = atoi
1198 (find_field(data,"basicConstraints-pathLengthConstraint-text",
1199 PR_TRUE));
1202 rv = CERT_EncodeBasicConstraintValue (NULL, &basicConstraint,
1203 &encodedValue);
1204 if (rv)
1205 return (rv);
1206 rv = CERT_AddExtension(extHandle, SEC_OID_X509_BASIC_CONSTRAINTS,
1207 &encodedValue,
1208 (find_field_bool(data,"basicConstraints-crit",
1209 PR_TRUE)), PR_TRUE);
1211 PORT_Free (encodedValue.data);
1212 return (rv);
1217 static SECStatus
1218 AddNscpCertType (void *extHandle,
1219 Pair *data)
1221 SECItem bitStringValue;
1222 unsigned char CertType = 0x0;
1224 if (find_field_bool(data,"netscape-cert-type-ssl-client", PR_TRUE)){
1225 CertType |= (0x80 >> 0);
1227 if (find_field_bool(data,"netscape-cert-type-ssl-server", PR_TRUE)){
1228 CertType |= (0x80 >> 1);
1230 if (find_field_bool(data,"netscape-cert-type-smime", PR_TRUE)){
1231 CertType |= (0x80 >> 2);
1233 if (find_field_bool(data,"netscape-cert-type-object-signing", PR_TRUE)){
1234 CertType |= (0x80 >> 3);
1236 if (find_field_bool(data,"netscape-cert-type-reserved", PR_TRUE)){
1237 CertType |= (0x80 >> 4);
1239 if (find_field_bool(data,"netscape-cert-type-ssl-ca", PR_TRUE)) {
1240 CertType |= (0x80 >> 5);
1242 if (find_field_bool(data,"netscape-cert-type-smime-ca", PR_TRUE)) {
1243 CertType |= (0x80 >> 6);
1245 if (find_field_bool(data,"netscape-cert-type-object-signing-ca", PR_TRUE)) {
1246 CertType |= (0x80 >> 7);
1249 bitStringValue.data = &CertType;
1250 bitStringValue.len = 1;
1252 return (CERT_EncodeAndAddBitStrExtension
1253 (extHandle, SEC_OID_NS_CERT_EXT_CERT_TYPE, &bitStringValue,
1254 (find_field_bool(data, "netscape-cert-type-crit", PR_TRUE))));
1258 static SECStatus
1259 add_IA5StringExtension(void *extHandle,
1260 char *string,
1261 PRBool crit,
1262 int idtag)
1264 SECItem encodedValue;
1265 SECStatus rv;
1267 encodedValue.data = NULL;
1268 encodedValue.len = 0;
1270 rv = CERT_EncodeIA5TypeExtension(NULL, string, &encodedValue);
1271 if (rv) {
1272 return (rv);
1274 return (CERT_AddExtension(extHandle, idtag, &encodedValue, crit, PR_TRUE));
1277 static SECItem *
1278 string_to_oid(char *string)
1280 int i;
1281 int length = 20;
1282 int remaining;
1283 int first_value;
1284 int second_value;
1285 int value;
1286 int oidLength;
1287 unsigned char *oidString;
1288 unsigned char *write;
1289 unsigned char *read;
1290 unsigned char *temp;
1291 SECItem *oid;
1294 remaining = length;
1295 i = 0;
1296 while (*string == ' ') {
1297 string++;
1299 while (isdigit(*(string + i))) {
1300 i++;
1302 if (*(string + i) == '.') {
1303 *(string + i) = '\0';
1304 } else {
1305 error_out("ERROR: Improperly formated OID");
1307 first_value = atoi(string);
1308 if (first_value < 0 || first_value > 2) {
1309 error_out("ERROR: Improperly formated OID");
1311 string += i + 1;
1312 i = 0;
1313 while (isdigit(*(string + i))) {
1314 i++;
1316 if (*(string + i) == '.') {
1317 *(string + i) = '\0';
1318 } else {
1319 error_out("ERROR: Improperly formated OID");
1321 second_value = atoi(string);
1322 if (second_value < 0 || second_value > 39) {
1323 error_out("ERROR: Improperly formated OID");
1325 oidString = PORT_ZAlloc(2);
1326 *oidString = (first_value * 40) + second_value;
1327 *(oidString + 1) = '\0';
1328 oidLength = 1;
1329 string += i + 1;
1330 i = 0;
1331 temp = write = PORT_ZAlloc(length);
1332 while (*string != '\0') {
1333 value = 0;
1334 while(isdigit(*(string + i))) {
1335 i++;
1337 if (*(string + i) == '\0') {
1338 value = atoi(string);
1339 string += i;
1340 } else {
1341 if (*(string + i) == '.') {
1342 *(string + i) = '\0';
1343 value = atoi(string);
1344 string += i + 1;
1345 } else {
1346 *(string + i) = '\0';
1347 i++;
1348 value = atoi(string);
1349 while (*(string + i) == ' ')
1350 i++;
1351 if (*(string + i) != '\0') {
1352 error_out("ERROR: Improperly formated OID");
1356 i = 0;
1357 while (value != 0) {
1358 if (remaining < 1) {
1359 remaining += length;
1360 length = length * 2;
1361 temp = PORT_Realloc(temp, length);
1362 write = temp + length - remaining;
1364 *write = (value & 0x7f) | (0x80);
1365 write++;
1366 remaining--;
1367 value = value >> 7;
1369 *temp = *temp & (0x7f);
1370 oidLength += write - temp;
1371 oidString = PORT_Realloc(oidString, (oidLength + 1));
1372 read = write - 1;
1373 write = oidLength + oidString - 1;
1374 for (i = 0; i < (length - remaining); i++) {
1375 *write = *read;
1376 write--;
1377 read++;
1379 write = temp;
1380 remaining = length;
1382 *(oidString + oidLength) = '\0';
1383 oid = (SECItem *) PORT_ZAlloc(sizeof(SECItem));
1384 oid->data = oidString;
1385 oid->len = oidLength;
1386 PORT_Free(temp);
1387 return oid;
1390 static SECItem *
1391 string_to_ipaddress(char *string)
1393 int i = 0;
1394 int value;
1395 int j = 0;
1396 SECItem *ipaddress;
1399 while (*string == ' ') {
1400 string++;
1402 ipaddress = (SECItem *) PORT_ZAlloc(sizeof(SECItem));
1403 ipaddress->data = PORT_ZAlloc(9);
1404 while (*string != '\0' && j < 8) {
1405 while (isdigit(*(string + i))) {
1406 i++;
1408 if (*(string + i) == '.') {
1409 *(string + i) = '\0';
1410 value = atoi(string);
1411 string = string + i + 1;
1412 i = 0;
1413 } else {
1414 if (*(string + i) == '\0') {
1415 value = atoi(string);
1416 string = string + i;
1417 i = 0;
1418 } else {
1419 *(string + i) = '\0';
1420 while (*(string + i) == ' ') {
1421 i++;
1423 if (*(string + i) == '\0') {
1424 value = atoi(string);
1425 string = string + i;
1426 i = 0;
1427 } else {
1428 error_out("ERROR: Improperly formated IP Address");
1432 if (value >= 0 || value < 256) {
1433 *(ipaddress->data + j) = value;
1434 } else {
1435 error_out("ERROR: Improperly formated IP Address");
1437 j++;
1439 *(ipaddress->data + j) = '\0';
1440 if (j != 4 && j != 8) {
1441 error_out("ERROR: Improperly formated IP Address");
1443 ipaddress->len = j;
1444 return ipaddress;
1447 static SECItem *
1448 string_to_binary(char *string)
1450 SECItem *rv;
1451 int high_digit;
1452 int low_digit;
1454 rv = (SECItem *) PORT_ZAlloc(sizeof(SECItem));
1455 if (rv == NULL) {
1456 error_allocate();
1458 rv->data = (unsigned char *) PORT_ZAlloc((PORT_Strlen(string))/3 + 2);
1459 while (!isxdigit(*string)) {
1460 string++;
1462 rv->len = 0;
1463 while (*string != '\0') {
1464 if (isxdigit(*string)) {
1465 if (*string >= '0' && *string <= '9') {
1466 high_digit = *string - '0';
1467 } else {
1468 *string = toupper(*string);
1469 high_digit = *string - 'A';
1471 string++;
1472 if (*string >= '0' && *string <= '9') {
1473 low_digit = *string - '0';
1474 } else {
1475 *string = toupper(*string);
1476 low_digit = *string = 'A';
1478 (rv->len)++;
1479 } else {
1480 if (*string == ':') {
1481 string++;
1482 } else {
1483 if (*string == ' ') {
1484 while (*string == ' ') {
1485 string++;
1488 if (*string != '\0') {
1489 error_out("ERROR: Improperly formated binary encoding");
1495 return rv;
1498 static SECStatus
1499 MakeGeneralName(char *name,
1500 CERTGeneralName *genName,
1501 PRArenaPool *arena)
1503 SECItem *oid;
1504 SECOidData *oidData;
1505 SECItem *ipaddress;
1506 SECItem *temp = NULL;
1507 int i;
1508 int nameType;
1509 PRBool binary = PR_FALSE;
1510 SECStatus rv = SECSuccess;
1511 PRBool nickname = PR_FALSE;
1513 PORT_Assert(genName);
1514 PORT_Assert(arena);
1515 nameType = *(name + PORT_Strlen(name) - 1) - '0';
1516 if (nameType == 0 && *(name +PORT_Strlen(name) - 2) == '1') {
1517 nickname = PR_TRUE;
1518 nameType = certOtherName;
1520 if (nameType < 1 || nameType > 9) {
1521 error_out("ERROR: Unknown General Name Type");
1523 *(name + PORT_Strlen(name) - 4) = '\0';
1524 genName->type = nameType;
1526 switch (genName->type) {
1527 case certURI:
1528 case certRFC822Name:
1529 case certDNSName: {
1530 genName->name.other.data = (unsigned char *)name;
1531 genName->name.other.len = PORT_Strlen(name);
1532 break;
1535 case certIPAddress: {
1536 ipaddress = string_to_ipaddress(name);
1537 genName->name.other.data = ipaddress->data;
1538 genName->name.other.len = ipaddress->len;
1539 break;
1542 case certRegisterID: {
1543 oid = string_to_oid(name);
1544 genName->name.other.data = oid->data;
1545 genName->name.other.len = oid->len;
1546 break;
1549 case certEDIPartyName:
1550 case certX400Address: {
1552 genName->name.other.data = PORT_ArenaAlloc (arena,
1553 PORT_Strlen (name) + 2);
1554 if (genName->name.other.data == NULL) {
1555 error_allocate();
1558 PORT_Memcpy (genName->name.other.data + 2, name, PORT_Strlen (name));
1559 /* This may not be accurate for all cases.
1560 For now, use this tag type */
1561 genName->name.other.data[0] = (char)(((genName->type - 1) &
1562 0x1f)| 0x80);
1563 genName->name.other.data[1] = (char)PORT_Strlen (name);
1564 genName->name.other.len = PORT_Strlen (name) + 2;
1565 break;
1568 case certOtherName: {
1569 i = 0;
1570 if (!nickname) {
1571 while (!isdigit(*(name + PORT_Strlen(name) - i))) {
1572 i++;
1574 if (*(name + PORT_Strlen(name) - i) == '1') {
1575 binary = PR_TRUE;
1576 } else {
1577 binary = PR_FALSE;
1579 while (*(name + PORT_Strlen(name) - i) != '-') {
1580 i++;
1582 *(name + PORT_Strlen(name) - i - 1) = '\0';
1583 i = 0;
1584 while (*(name + i) != '-') {
1585 i++;
1587 *(name + i - 1) = '\0';
1588 oid = string_to_oid(name + i + 2);
1589 } else {
1590 oidData = SECOID_FindOIDByTag(SEC_OID_NETSCAPE_NICKNAME);
1591 oid = &oidData->oid;
1592 while (*(name + PORT_Strlen(name) - i) != '-') {
1593 i++;
1595 *(name + PORT_Strlen(name) - i) = '\0';
1597 genName->name.OthName.oid.data = oid->data;
1598 genName->name.OthName.oid.len = oid->len;
1599 if (binary) {
1600 temp = string_to_binary(name);
1601 genName->name.OthName.name.data = temp->data;
1602 genName->name.OthName.name.len = temp->len;
1603 } else {
1604 temp = (SECItem *) PORT_ZAlloc(sizeof(SECItem));
1605 if (temp == NULL) {
1606 error_allocate();
1608 temp->data = (unsigned char *)name;
1609 temp->len = PORT_Strlen(name);
1610 SEC_ASN1EncodeItem (arena, &(genName->name.OthName.name), temp,
1611 CERTIA5TypeTemplate);
1613 PORT_Free(temp);
1614 break;
1617 case certDirectoryName: {
1618 CERTName *directoryName = NULL;
1620 directoryName = CERT_AsciiToName (name);
1621 if (!directoryName) {
1622 error_out("ERROR: Improperly formated alternative name");
1623 break;
1625 rv = CERT_CopyName (arena, &genName->name.directoryName,
1626 directoryName);
1627 CERT_DestroyName (directoryName);
1629 break;
1632 genName->l.next = &(genName->l);
1633 genName->l.prev = &(genName->l);
1634 return rv;
1638 static CERTGeneralName *
1639 MakeAltName(Pair *data,
1640 char *which,
1641 PRArenaPool *arena)
1643 CERTGeneralName *SubAltName;
1644 CERTGeneralName *current;
1645 CERTGeneralName *newname;
1646 char *name = NULL;
1647 SECStatus rv = SECSuccess;
1648 int len;
1651 len = PORT_Strlen(which);
1652 name = find_field(data, which, PR_TRUE);
1653 SubAltName = current = (CERTGeneralName *) PORT_ZAlloc
1654 (sizeof(CERTGeneralName));
1655 if (current == NULL) {
1656 error_allocate();
1658 while (name != NULL) {
1660 rv = MakeGeneralName(name, current, arena);
1662 if (rv != SECSuccess) {
1663 break;
1665 if (*(which + len -1) < '9') {
1666 *(which + len - 1) = *(which + len - 1) + 1;
1667 } else {
1668 if (isdigit(*(which + len - 2) )) {
1669 *(which + len - 2) = *(which + len - 2) + 1;
1670 *(which + len - 1) = '0';
1671 } else {
1672 *(which + len - 1) = '1';
1673 *(which + len) = '0';
1674 *(which + len + 1) = '\0';
1675 len++;
1678 len = PORT_Strlen(which);
1679 name = find_field(data, which, PR_TRUE);
1680 if (name != NULL) {
1681 newname = (CERTGeneralName *) PORT_ZAlloc(sizeof(CERTGeneralName));
1682 if (newname == NULL) {
1683 error_allocate();
1685 current->l.next = &(newname->l);
1686 newname->l.prev = &(current->l);
1687 current = newname;
1688 newname = NULL;
1689 } else {
1690 current->l.next = &(SubAltName->l);
1691 SubAltName->l.prev = &(current->l);
1694 if (rv == SECFailure) {
1695 return NULL;
1697 return SubAltName;
1700 static CERTNameConstraints *
1701 MakeNameConstraints(Pair *data,
1702 PRArenaPool *arena)
1704 CERTNameConstraints *NameConstraints;
1705 CERTNameConstraint *current = NULL;
1706 CERTNameConstraint *last_permited = NULL;
1707 CERTNameConstraint *last_excluded = NULL;
1708 char *constraint = NULL;
1709 char *which;
1710 SECStatus rv = SECSuccess;
1711 int len;
1712 int i;
1713 long max;
1714 long min;
1715 PRBool permited;
1718 NameConstraints = (CERTNameConstraints *) PORT_ZAlloc
1719 (sizeof(CERTNameConstraints));
1720 which = make_copy_string("NameConstraintSelect0", 25,'\0');
1721 len = PORT_Strlen(which);
1722 constraint = find_field(data, which, PR_TRUE);
1723 NameConstraints->permited = NameConstraints->excluded = NULL;
1724 while (constraint != NULL) {
1725 current = (CERTNameConstraint *) PORT_ZAlloc
1726 (sizeof(CERTNameConstraint));
1727 if (current == NULL) {
1728 error_allocate();
1730 i = 0;
1731 while (*(constraint + PORT_Strlen(constraint) - i) != '-') {
1732 i++;
1734 *(constraint + PORT_Strlen(constraint) - i - 1) = '\0';
1735 max = (long) atoi(constraint + PORT_Strlen(constraint) + 3);
1736 if (max > 0) {
1737 (void) SEC_ASN1EncodeInteger(arena, &current->max, max);
1739 i = 0;
1740 while (*(constraint + PORT_Strlen(constraint) - i) != '-') {
1741 i++;
1743 *(constraint + PORT_Strlen(constraint) - i - 1) = '\0';
1744 min = (long) atoi(constraint + PORT_Strlen(constraint) + 3);
1745 (void) SEC_ASN1EncodeInteger(arena, &current->min, min);
1746 while (*(constraint + PORT_Strlen(constraint) - i) != '-') {
1747 i++;
1749 *(constraint + PORT_Strlen(constraint) - i - 1) = '\0';
1750 if (*(constraint + PORT_Strlen(constraint) + 3) == 'p') {
1751 permited = PR_TRUE;
1752 } else {
1753 permited = PR_FALSE;
1755 rv = MakeGeneralName(constraint, &(current->name), arena);
1757 if (rv != SECSuccess) {
1758 break;
1760 if (*(which + len - 1) < '9') {
1761 *(which + len - 1) = *(which + len - 1) + 1;
1762 } else {
1763 if (isdigit(*(which + len - 2) )) {
1764 *(which + len - 2) = *(which + len - 2) + 1;
1765 *(which + len - 1) = '0';
1766 } else {
1767 *(which + len - 1) = '1';
1768 *(which + len) = '0';
1769 *(which + len + 1) = '\0';
1770 len++;
1773 len = PORT_Strlen(which);
1774 if (permited) {
1775 if (NameConstraints->permited == NULL) {
1776 NameConstraints->permited = last_permited = current;
1778 last_permited->l.next = &(current->l);
1779 current->l.prev = &(last_permited->l);
1780 last_permited = current;
1781 } else {
1782 if (NameConstraints->excluded == NULL) {
1783 NameConstraints->excluded = last_excluded = current;
1785 last_excluded->l.next = &(current->l);
1786 current->l.prev = &(last_excluded->l);
1787 last_excluded = current;
1789 constraint = find_field(data, which, PR_TRUE);
1790 if (constraint != NULL) {
1791 current = (CERTNameConstraint *) PORT_ZAlloc(sizeof(CERTNameConstraint));
1792 if (current == NULL) {
1793 error_allocate();
1797 if (NameConstraints->permited != NULL) {
1798 last_permited->l.next = &(NameConstraints->permited->l);
1799 NameConstraints->permited->l.prev = &(last_permited->l);
1801 if (NameConstraints->excluded != NULL) {
1802 last_excluded->l.next = &(NameConstraints->excluded->l);
1803 NameConstraints->excluded->l.prev = &(last_excluded->l);
1805 if (which != NULL) {
1806 PORT_Free(which);
1808 if (rv == SECFailure) {
1809 return NULL;
1811 return NameConstraints;
1816 static SECStatus
1817 AddAltName(void *extHandle,
1818 Pair *data,
1819 char *issuerNameStr,
1820 CERTCertDBHandle *handle,
1821 int type)
1823 PRBool autoIssuer = PR_FALSE;
1824 PRArenaPool *arena = NULL;
1825 CERTGeneralName *genName = NULL;
1826 char *which = NULL;
1827 char *name = NULL;
1828 SECStatus rv = SECSuccess;
1829 SECItem *issuersAltName = NULL;
1830 CERTCertificate *issuerCert = NULL;
1832 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1833 if (arena == NULL) {
1834 error_allocate();
1836 if (type == 0) {
1837 which = make_copy_string("SubAltNameSelect0", 20,'\0');
1838 genName = MakeAltName(data, which, arena);
1839 } else {
1840 if (autoIssuer) {
1841 autoIssuer = find_field_bool(data,"IssuerAltNameSourceRadio-auto",
1842 PR_TRUE);
1843 issuerCert = CERT_FindCertByNameString(handle, issuerNameStr);
1844 rv = cert_FindExtension((*issuerCert).extensions,
1845 SEC_OID_X509_SUBJECT_ALT_NAME,
1846 issuersAltName);
1847 if (issuersAltName == NULL) {
1848 name = PORT_Alloc(PORT_Strlen((*issuerCert).subjectName) + 4);
1849 PORT_Strcpy(name, (*issuerCert).subjectName);
1850 PORT_Strcat(name, " - 5");
1852 } else {
1853 which = make_copy_string("IssuerAltNameSelect0", 20,'\0');
1854 genName = MakeAltName(data, which, arena);
1857 if (type == 0) {
1858 EncodeAndAddExtensionValue(arena, extHandle, genName,
1859 find_field_bool(data, "SubAltName-crit",
1860 PR_TRUE),
1861 SEC_OID_X509_SUBJECT_ALT_NAME,
1862 (EXTEN_VALUE_ENCODER)
1863 CERT_EncodeAltNameExtension);
1865 } else {
1866 if (autoIssuer && (name == NULL)) {
1867 rv = CERT_AddExtension
1868 (extHandle, SEC_OID_X509_ISSUER_ALT_NAME, issuersAltName,
1869 find_field_bool(data, "IssuerAltName-crit", PR_TRUE), PR_TRUE);
1870 } else {
1871 EncodeAndAddExtensionValue(arena, extHandle, genName,
1872 find_field_bool(data,
1873 "IssuerAltName-crit",
1874 PR_TRUE),
1875 SEC_OID_X509_ISSUER_ALT_NAME,
1876 (EXTEN_VALUE_ENCODER)
1877 CERT_EncodeAltNameExtension);
1880 if (which != NULL) {
1881 PORT_Free(which);
1883 if (issuerCert != NULL) {
1884 CERT_DestroyCertificate(issuerCert);
1886 return rv;
1890 static SECStatus
1891 AddNameConstraints(void *extHandle,
1892 Pair *data)
1894 PRArenaPool *arena = NULL;
1895 CERTNameConstraints *constraints = NULL;
1896 SECStatus rv = SECSuccess;
1899 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1900 if (arena == NULL) {
1901 error_allocate();
1903 constraints = MakeNameConstraints(data, arena);
1904 if (constraints != NULL) {
1905 EncodeAndAddExtensionValue(arena, extHandle, constraints, PR_TRUE,
1906 SEC_OID_X509_NAME_CONSTRAINTS,
1907 (EXTEN_VALUE_ENCODER)
1908 CERT_EncodeNameConstraintsExtension);
1910 if (arena != NULL) {
1911 PORT_ArenaRelease (arena, NULL);
1913 return rv;
1917 static SECStatus
1918 add_extensions(CERTCertificate *subjectCert,
1919 Pair *data,
1920 char *issuerNameStr,
1921 CERTCertDBHandle *handle)
1923 void *extHandle;
1924 SECStatus rv = SECSuccess;
1927 extHandle = CERT_StartCertExtensions (subjectCert);
1928 if (extHandle == NULL) {
1929 error_out("ERROR: Unable to get certificates extension handle");
1931 if (find_field_bool(data, "keyUsage", PR_TRUE)) {
1932 rv = AddKeyUsage(extHandle, data);
1933 if (rv != SECSuccess) {
1934 error_out("ERROR: Unable to add Key Usage extension");
1938 if( find_field_bool(data, "extKeyUsage", PR_TRUE) ) {
1939 rv = AddExtKeyUsage(extHandle, data);
1940 if( SECSuccess != rv ) {
1941 error_out("ERROR: Unable to add Extended Key Usage extension");
1945 if (find_field_bool(data, "basicConstraints", PR_TRUE)) {
1946 rv = AddBasicConstraint(extHandle, data);
1947 if (rv != SECSuccess) {
1948 error_out("ERROR: Unable to add Basic Constraint extension");
1951 if (find_field_bool(data, "subjectKeyIdentifier", PR_TRUE)) {
1952 rv = AddSubKeyID(extHandle, data, subjectCert);
1953 if (rv != SECSuccess) {
1954 error_out("ERROR: Unable to add Subject Key Identifier Extension");
1957 if (find_field_bool(data, "authorityKeyIdentifier", PR_TRUE)) {
1958 rv = AddAuthKeyID (extHandle, data, issuerNameStr, handle);
1959 if (rv != SECSuccess) {
1960 error_out("ERROR: Unable to add Authority Key Identifier extension");
1963 if (find_field_bool(data, "privKeyUsagePeriod", PR_TRUE)) {
1964 rv = AddPrivKeyUsagePeriod (extHandle, data, subjectCert);
1965 if (rv != SECSuccess) {
1966 error_out("ERROR: Unable to add Private Key Usage Period extension");
1969 if (find_field_bool(data, "SubAltName", PR_TRUE)) {
1970 rv = AddAltName (extHandle, data, NULL, NULL, 0);
1971 if (rv != SECSuccess) {
1972 error_out("ERROR: Unable to add Subject Alternative Name extension");
1975 if (find_field_bool(data, "IssuerAltName", PR_TRUE)) {
1976 rv = AddAltName (extHandle, data, issuerNameStr, handle, 1);
1977 if (rv != SECSuccess) {
1978 error_out("ERROR: Unable to add Issuer Alternative Name Extension");
1981 if (find_field_bool(data, "NameConstraints", PR_TRUE)) {
1982 rv = AddNameConstraints(extHandle, data);
1983 if (rv != SECSuccess) {
1984 error_out("ERROR: Unable to add Name Constraints Extension");
1987 if (find_field_bool(data, "netscape-cert-type", PR_TRUE)) {
1988 rv = AddNscpCertType(extHandle, data);
1989 if (rv != SECSuccess) {
1990 error_out("ERROR: Unable to add Netscape Certificate Type Extension");
1993 if (find_field_bool(data, "netscape-base-url", PR_TRUE)) {
1994 rv = add_IA5StringExtension(extHandle,
1995 find_field(data, "netscape-base-url-text",
1996 PR_TRUE),
1997 find_field_bool(data,
1998 "netscape-base-url-crit",
1999 PR_TRUE),
2000 SEC_OID_NS_CERT_EXT_BASE_URL);
2001 if (rv != SECSuccess) {
2002 error_out("ERROR: Unable to add Netscape Base URL Extension");
2005 if (find_field_bool(data, "netscape-revocation-url", PR_TRUE)) {
2006 rv = add_IA5StringExtension(extHandle,
2007 find_field(data,
2008 "netscape-revocation-url-text",
2009 PR_TRUE),
2010 find_field_bool
2011 (data, "netscape-revocation-url-crit",
2012 PR_TRUE),
2013 SEC_OID_NS_CERT_EXT_REVOCATION_URL);
2014 if (rv != SECSuccess) {
2015 error_out("ERROR: Unable to add Netscape Revocation URL Extension");
2018 if (find_field_bool(data, "netscape-ca-revocation-url", PR_TRUE)) {
2019 rv = add_IA5StringExtension(extHandle,
2020 find_field(data,
2021 "netscape-ca-revocation-url-text",
2022 PR_TRUE),
2023 find_field_bool
2024 (data, "netscape-ca-revocation-url-crit"
2025 , PR_TRUE),
2026 SEC_OID_NS_CERT_EXT_CA_REVOCATION_URL);
2027 if (rv != SECSuccess) {
2028 error_out("ERROR: Unable to add Netscape CA Revocation URL Extension");
2031 if (find_field_bool(data, "netscape-cert-renewal-url", PR_TRUE)) {
2032 rv = add_IA5StringExtension(extHandle,
2033 find_field(data,
2034 "netscape-cert-renewal-url-text",
2035 PR_TRUE),
2036 find_field_bool
2037 (data, "netscape-cert-renewal-url-crit",
2038 PR_TRUE),
2039 SEC_OID_NS_CERT_EXT_CERT_RENEWAL_URL);
2040 if (rv != SECSuccess) {
2041 error_out("ERROR: Unable to add Netscape Certificate Renewal URL Extension");
2044 if (find_field_bool(data, "netscape-ca-policy-url", PR_TRUE)) {
2045 rv = add_IA5StringExtension(extHandle,
2046 find_field(data,
2047 "netscape-ca-policy-url-text",
2048 PR_TRUE),
2049 find_field_bool
2050 (data, "netscape-ca-policy-url-crit",
2051 PR_TRUE),
2052 SEC_OID_NS_CERT_EXT_CA_POLICY_URL);
2053 if (rv != SECSuccess) {
2054 error_out("ERROR: Unable to add Netscape CA Policy URL Extension");
2057 if (find_field_bool(data, "netscape-ssl-server-name", PR_TRUE)) {
2058 rv = add_IA5StringExtension(extHandle,
2059 find_field(data,
2060 "netscape-ssl-server-name-text",
2061 PR_TRUE),
2062 find_field_bool
2063 (data, "netscape-ssl-server-name-crit",
2064 PR_TRUE),
2065 SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME);
2066 if (rv != SECSuccess) {
2067 error_out("ERROR: Unable to add Netscape SSL Server Name Extension");
2070 if (find_field_bool(data, "netscape-comment", PR_TRUE)) {
2071 rv = add_IA5StringExtension(extHandle,
2072 find_field(data, "netscape-comment-text",
2073 PR_TRUE),
2074 find_field_bool(data,
2075 "netscape-comment-crit",
2076 PR_TRUE),
2077 SEC_OID_NS_CERT_EXT_COMMENT);
2078 if (rv != SECSuccess) {
2079 error_out("ERROR: Unable to add Netscape Comment Extension");
2082 CERT_FinishExtensions(extHandle);
2083 return (rv);
2088 char *
2089 return_dbpasswd(PK11SlotInfo *slot, PRBool retry, void *data)
2091 char *rv;
2093 /* don't clobber our poor smart card */
2094 if (retry == PR_TRUE) {
2095 return NULL;
2097 rv = PORT_Alloc(4);
2098 PORT_Strcpy(rv, "foo");
2099 return rv;
2103 SECKEYPrivateKey *
2104 FindPrivateKeyFromNameStr(char *name,
2105 CERTCertDBHandle *certHandle)
2107 SECKEYPrivateKey *key;
2108 CERTCertificate *cert;
2109 CERTCertificate *p11Cert;
2112 /* We don't presently have a PK11 function to find a cert by
2113 ** subject name.
2114 ** We do have a function to find a cert in the internal slot's
2115 ** cert db by subject name, but it doesn't setup the slot info.
2116 ** So, this HACK works, but should be replaced as soon as we
2117 ** have a function to search for certs accross slots by subject name.
2119 cert = CERT_FindCertByNameString(certHandle, name);
2120 if (cert == NULL || cert->nickname == NULL) {
2121 error_out("ERROR: Unable to retrieve issuers certificate");
2123 p11Cert = PK11_FindCertFromNickname(cert->nickname, NULL);
2124 if (p11Cert == NULL) {
2125 error_out("ERROR: Unable to retrieve issuers certificate");
2127 key = PK11_FindKeyByAnyCert(p11Cert, NULL);
2128 return key;
2131 static SECItem *
2132 SignCert(CERTCertificate *cert,
2133 char *issuerNameStr,
2134 Pair *data,
2135 CERTCertDBHandle *handle,
2136 int which_key)
2138 SECItem der;
2139 SECKEYPrivateKey *caPrivateKey = NULL;
2140 SECStatus rv;
2141 PRArenaPool *arena;
2142 SECOidTag algID;
2144 if (which_key == 0) {
2145 caPrivateKey = FindPrivateKeyFromNameStr(issuerNameStr, handle);
2146 } else {
2147 caPrivateKey = privkeys[which_key - 1];
2149 if (caPrivateKey == NULL) {
2150 error_out("ERROR: unable to retrieve issuers key");
2153 arena = cert->arena;
2155 algID = SEC_GetSignatureAlgorithmOidTag(caPrivateKey->keyType,
2156 SEC_OID_UNKNOWN);
2157 if (algID == SEC_OID_UNKNOWN) {
2158 error_out("ERROR: Unknown key type for issuer.");
2159 goto done;
2162 rv = SECOID_SetAlgorithmID(arena, &cert->signature, algID, 0);
2163 if (rv != SECSuccess) {
2164 error_out("ERROR: Could not set signature algorithm id.");
2167 if (find_field_bool(data,"ver-1", PR_TRUE)) {
2168 *(cert->version.data) = 0;
2169 cert->version.len = 1;
2170 } else {
2171 *(cert->version.data) = 2;
2172 cert->version.len = 1;
2174 der.data = NULL;
2175 der.len = 0;
2176 (void) SEC_ASN1EncodeItem (arena, &der, cert, CERT_CertificateTemplate);
2177 if (der.data == NULL) {
2178 error_out("ERROR: Could not encode certificate.\n");
2180 rv = SEC_DerSignData (arena, &(cert->derCert), der.data, der.len, caPrivateKey,
2181 algID);
2182 if (rv != SECSuccess) {
2183 error_out("ERROR: Could not sign encoded certificate data.\n");
2185 done:
2186 SECKEY_DestroyPrivateKey(caPrivateKey);
2187 return &(cert->derCert);
2192 main(int argc, char **argv)
2194 int length = 500;
2195 int remaining = 500;
2196 int n;
2197 int i;
2198 int serial;
2199 int chainLen;
2200 int which_key;
2201 char *pos;
2202 #ifdef OFFLINE
2203 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";
2204 #else
2205 char *form_output;
2206 #endif
2207 char *issuerNameStr;
2208 char *certName;
2209 char *DBdir = DB_DIRECTORY;
2210 char *prefixs[10] = {"CA#1-", "CA#2-", "CA#3-",
2211 "CA#4-", "CA#5-", "CA#6-",
2212 "CA#7-", "CA#8-", "CA#9-", ""};
2213 Pair *form_data;
2214 CERTCertificate *cert;
2215 CERTCertDBHandle *handle;
2216 CERTCertificateRequest *certReq = NULL;
2217 int warpmonths = 0;
2218 SECItem *certDER;
2219 #ifdef FILEOUT
2220 FILE *outfile;
2221 #endif
2222 SECStatus status = SECSuccess;
2223 extern char prefix[PREFIX_LEN];
2224 SEC_PKCS7ContentInfo *certChain;
2225 SECItem *encodedCertChain;
2226 PRBool UChain = PR_FALSE;
2229 progName = strrchr(argv[0], '/');
2230 progName = progName ? progName+1 : argv[0];
2233 #ifdef TEST
2234 sleep(20);
2235 #endif
2236 SECU_ConfigDirectory(DBdir);
2238 PK11_SetPasswordFunc(return_dbpasswd);
2239 status = NSS_InitReadWrite(DBdir);
2240 if (status != SECSuccess) {
2241 SECU_PrintPRandOSError(progName);
2242 return -1;
2244 handle = CERT_GetDefaultCertDB();
2246 prefix[0]= '\0';
2247 #if !defined(OFFLINE)
2248 form_output = (char*) PORT_Alloc(length);
2249 if (form_output == NULL) {
2250 error_allocate();
2252 pos = form_output;
2253 while (feof(stdin) == 0 ) {
2254 if (remaining <= 1) {
2255 remaining += length;
2256 length = length * 2;
2257 form_output = PORT_Realloc(form_output, (length));
2258 if (form_output == NULL) {
2259 error_allocate();
2261 pos = form_output + length - remaining;
2263 n = fread(pos, 1, (size_t) (remaining - 1), stdin);
2264 pos += n;
2265 remaining -= n;
2267 *pos = '&';
2268 pos++;
2269 length = pos - form_output;
2270 #else
2271 length = PORT_Strlen(form_output);
2272 #endif
2273 #ifdef FILEOUT
2274 printf("Content-type: text/plain\n\n");
2275 fwrite(form_output, 1, (size_t)length, stdout);
2276 printf("\n");
2277 #endif
2278 #ifdef FILEOUT
2279 fwrite(form_output, 1, (size_t)length, stdout);
2280 printf("\n");
2281 fflush(stdout);
2282 #endif
2283 form_data = make_datastruct(form_output, length);
2284 status = clean_input(form_data);
2285 #if !defined(OFFLINE)
2286 PORT_Free(form_output);
2287 #endif
2288 #ifdef FILEOUT
2289 i = 0;
2290 while(return_name(form_data, i) != NULL) {
2291 printf("%s",return_name(form_data,i));
2292 printf("=\n");
2293 printf("%s",return_data(form_data,i));
2294 printf("\n");
2295 i++;
2297 printf("I got that done, woo hoo\n");
2298 fflush(stdout);
2299 #endif
2300 issuerNameStr = PORT_Alloc(200);
2301 if (find_field_bool(form_data, "caChoiceradio-SignWithSpecifiedChain",
2302 PR_FALSE)) {
2303 UChain = PR_TRUE;
2304 chainLen = atoi(find_field(form_data, "manCAs", PR_FALSE));
2305 PORT_Strcpy(prefix, prefixs[0]);
2306 issuerNameStr = PORT_Strcpy(issuerNameStr,
2307 "CN=Cert-O-Matic II, O=Cert-O-Matic II");
2308 if (chainLen == 0) {
2309 UChain = PR_FALSE;
2311 } else {
2312 if (find_field_bool(form_data, "caChoiceradio-SignWithRandomChain",
2313 PR_FALSE)) {
2314 PORT_Strcpy(prefix,prefixs[9]);
2315 chainLen = atoi(find_field(form_data, "autoCAs", PR_FALSE));
2316 if (chainLen < 1 || chainLen > 18) {
2317 issuerNameStr = PORT_Strcpy(issuerNameStr,
2318 "CN=CA18, O=Cert-O-Matic II");
2320 issuerNameStr = PORT_Strcpy(issuerNameStr, "CN=CA");
2321 issuerNameStr = PORT_Strcat(issuerNameStr,
2322 find_field(form_data,"autoCAs", PR_FALSE));
2323 issuerNameStr = PORT_Strcat(issuerNameStr,", O=Cert-O-Matic II");
2324 } else {
2325 issuerNameStr = PORT_Strcpy(issuerNameStr,
2326 "CN=Cert-O-Matic II, O=Cert-O-Matic II");
2328 chainLen = 0;
2331 i = -1;
2332 which_key = 0;
2333 do {
2334 extern SECStatus cert_GetKeyID(CERTCertificate *cert);
2335 i++;
2336 if (i != 0 && UChain) {
2337 PORT_Strcpy(prefix, prefixs[i]);
2339 /* find_field(form_data,"subject", PR_TRUE); */
2340 certReq = makeCertReq(form_data, which_key);
2341 #ifdef OFFLINE
2342 serial = 900;
2343 #else
2344 serial = get_serial_number(form_data);
2345 #endif
2346 cert = MakeV1Cert(handle, certReq, issuerNameStr, PR_FALSE,
2347 serial, warpmonths, form_data);
2348 if (certReq != NULL) {
2349 CERT_DestroyCertificateRequest(certReq);
2351 if (find_field_bool(form_data,"ver-3", PR_TRUE)) {
2352 status = add_extensions(cert, form_data, issuerNameStr, handle);
2353 if (status != SECSuccess) {
2354 error_out("ERROR: Unable to add extensions");
2357 status = cert_GetKeyID(cert);
2358 if (status == SECFailure) {
2359 error_out("ERROR: Unable to get Key ID.");
2361 certDER = SignCert(cert, issuerNameStr, form_data, handle, which_key);
2362 CERT_NewTempCertificate(handle, certDER, NULL, PR_FALSE, PR_TRUE);
2363 issuerNameStr = find_field(form_data, "subject", PR_TRUE);
2364 /* SECITEM_FreeItem(certDER, PR_TRUE); */
2365 CERT_DestroyCertificate(cert);
2366 if (i == (chainLen - 1)) {
2367 i = 8;
2369 ++which_key;
2370 } while (i < 9 && UChain);
2374 #ifdef FILEOUT
2375 outfile = fopen("../certout", "wb");
2376 #endif
2377 certName = find_field(form_data, "subject", PR_FALSE);
2378 cert = CERT_FindCertByNameString(handle, certName);
2379 certChain = SEC_PKCS7CreateCertsOnly (cert, PR_TRUE, handle);
2380 if (certChain == NULL) {
2381 error_out("ERROR: No certificates in cert chain");
2383 encodedCertChain = SEC_PKCS7EncodeItem (NULL, NULL, certChain, NULL, NULL,
2384 NULL);
2385 if (encodedCertChain) {
2386 #if !defined(FILEOUT)
2387 printf("Content-type: application/x-x509-user-cert\r\n");
2388 printf("Content-length: %d\r\n\r\n", encodedCertChain->len);
2389 fwrite (encodedCertChain->data, 1, encodedCertChain->len, stdout);
2390 #else
2391 fwrite (encodedCertChain->data, 1, encodedCertChain->len, outfile);
2392 #endif
2394 } else {
2395 error_out("Error: Unable to DER encode certificate");
2397 #ifdef FILEOUT
2398 printf("\nI got here!\n");
2399 fflush(outfile);
2400 fclose(outfile);
2401 #endif
2402 fflush(stdout);
2403 if (NSS_Shutdown() != SECSuccess) {
2404 exit(1);
2406 return 0;