Imported Upstream version 3.13.6
[platform/upstream/nss.git] / mozilla / security / nss / cmd / certcgi / certcgi.c
1 /* ***** BEGIN LICENSE BLOCK *****
2  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3  *
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/
8  *
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.
13  *
14  * The Original Code is the Netscape security libraries.
15  *
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.
20  *
21  * Contributor(s):
22  *
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.
34  *
35  * ***** END LICENSE BLOCK ***** */
36
37 /* Cert-O-Matic CGI */
38
39
40 #include "nspr.h"
41 #include "prtypes.h"
42 #include "prtime.h"
43 #include "prlong.h"
44
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"
56
57
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   ".."
65
66 static char *progName;
67
68 typedef struct PairStr Pair;
69
70 struct PairStr {
71     char *name;
72     char *data;
73 };
74
75
76 char prefix[PREFIX_LEN];
77
78
79 const SEC_ASN1Template CERTIA5TypeTemplate[] = {
80     { SEC_ASN1_IA5_STRING }
81 };
82
83
84
85 SECKEYPrivateKey *privkeys[9] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL,
86                                  NULL, NULL};
87
88
89 #ifdef notdef
90 const SEC_ASN1Template CERT_GeneralNameTemplate[] = {
91     { SEC_ASN1_SEQUENCE_OF, 0, SEC_AnyTemplate }
92 };
93 #endif
94
95
96 static void
97 error_out(char  *error_string)
98 {
99     printf("Content-type: text/plain\n\n");
100     printf(error_string);
101     fflush(stderr);
102     fflush(stdout);
103     exit(1);
104 }
105
106 static void
107 error_allocate(void)
108 {
109     error_out("ERROR: Unable to allocate memory");
110 }
111
112
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 */
119 {
120     int                remaining = length;
121     char               *write_pos;
122     char               *new;
123
124     new = write_pos = (char *) PORT_Alloc (length);
125     if (new == NULL) {
126         error_allocate();
127     }
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();
135             }
136             write_pos = new + length - remaining;
137         }
138         *write_pos = *read_pos;
139         ++write_pos;
140         ++read_pos;
141         remaining = remaining - 1;
142     }
143     *write_pos = '\0';
144     return new;
145 }
146
147
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 */
152 {
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;
161
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 = ' ';
169             }
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");
182                     }
183                 }
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");
192                     }
193                 }
194                 character = (hi_digit << 4) | low_digit;
195                 if (character != 10) {
196                     *write_pos = character;
197                     ++write_pos;
198                 }
199             } else {
200                 *write_pos = *read_pos;
201                 ++write_pos;
202                 ++read_pos;
203             }
204         }
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;
213         }
214     }
215     return SECSuccess;
216 }
217
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 */
222 {
223     int         length = 20;
224     char        *name;
225
226     name = make_copy_string(new_data, length, '=');
227     return name;
228 }
229         
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 */
234 {
235     int         length = 100;
236     char        *data;
237     char        *read_pos;
238
239     read_pos = new_data;
240     while (*(read_pos - 1) != '=') {
241         ++read_pos;
242     }
243     data = make_copy_string(read_pos, length, '&');
244     return data;
245 }
246
247
248 static Pair
249 make_pair(char  *new_data)
250     /* makes a pair name/data pair from the input string */
251 {
252     Pair        temp;
253
254     temp.name = make_name(new_data);
255     temp.data = make_data(new_data);
256     return temp;
257 }
258
259
260
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 */
265 {
266     Pair              *datastruct;
267     Pair              *current;
268     char              *curr_pos;
269     int               fields = START_FIELDS;
270     int               remaining = START_FIELDS;
271
272     curr_pos = data;
273     datastruct = current = (Pair *) PORT_Alloc(fields * sizeof(Pair));
274     if (datastruct == NULL) {
275         error_allocate();
276     }
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();
285             }
286             current = datastruct + (fields - remaining);
287         }
288         *current = make_pair(curr_pos);
289         while (*curr_pos != '&') {
290             ++curr_pos;
291         }
292         ++curr_pos;
293         ++current;
294         remaining = remaining - 1;
295     }
296     current->name = NULL;
297     return datastruct;
298 }
299
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 */
305 {
306     char          *name;
307
308     if ((data_struct + n)->name != NULL) {
309         name = (data_struct + n)->name;
310         return name;
311     } else {
312         return NULL;
313     }
314 }
315
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 */
320 {
321     char          *data;
322
323     data = (data_struct + n)->data;
324     return data;
325 }
326
327
328 static char *
329 add_prefix(char  *field_name)
330 {
331     extern char  prefix[PREFIX_LEN];
332     int          i = 0;
333     char         *rv;
334     char         *write;
335
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++;
340     }
341     *write = '\0';
342     rv = PORT_Strcat(rv,field_name);
343     return rv;
344 }
345
346
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 */
353 {
354     int            i = 0;
355     char           *retrieved;
356     int            found = 0;
357
358     if (add_pre) {
359         field_name = add_prefix(field_name);
360     }
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;
366         }
367         i++;
368     }
369     if (!found) {
370         retrieved = NULL;
371     }
372     return retrieved;
373 }
374
375 static PRBool
376 find_field_bool(Pair    *data, 
377                 char    *fieldname, 
378                 PRBool  add_pre)
379 {
380     char                *rv;
381
382     rv = find_field(data, fieldname, add_pre);
383         
384     if  ((rv != NULL) && (PORT_Strcmp(rv, "true")) == 0) {
385         return PR_TRUE;
386     } else {
387         return PR_FALSE;
388     }
389 }
390
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 */
397 {
398     int                   i = 0;
399     int                   found = 0;
400     int                   length = 100;
401     char                  *new;
402
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;
410         }
411         i++;
412     }
413     if (!found) {
414         new = NULL;
415     }
416     return new;
417 }
418
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 */
424 {
425     int                    length = 100;
426     char                   *new;
427
428     new = make_copy_string(new_data, length, '\0');
429     PORT_Free(return_data(data, n));
430     (*(data + n)).data = new;
431     return new;
432 }
433
434
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 */
440 {
441     int          i = 0;
442     int          j;
443     int          name_length = 100;
444     int          data_length = 100;
445
446     while(return_name(data, i) != NULL) {
447         i++;
448     }
449     j = START_FIELDS;
450     while ( j < (i + 1) ) {
451         j = j * 2;
452     }
453     if (j == (i + 1)) {
454         data = (Pair *) PORT_Realloc(data, (j * 2) * sizeof(Pair));
455         if (data == NULL) {
456             error_allocate();
457         }
458     }
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;
463 }
464
465
466 static CERTCertificateRequest *
467 makeCertReq(Pair             *form_data,
468             int              which_priv_key)
469     /* makes and encodes a certrequest */
470 {
471
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;
485
486     name = CERT_AsciiToName(find_field(form_data, "subject", PR_TRUE));
487     if (name == NULL) {
488         error_out("ERROR: Unable to create Subject Name");
489     }
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");
504         }
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");
509             }
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);
516         }
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");
524         }
525     }
526     certReq = CERT_CreateCertificateRequest(name, spki, NULL);
527     if (certReq == NULL) {
528         error_out("ERROR: Unable to create Certificate Request");
529     }
530     if (pubkey != NULL) {
531         SECKEY_DestroyPublicKey(pubkey);
532     }
533     if (spki != NULL) {
534         SECKEY_DestroySubjectPublicKeyInfo(spki);
535     }
536     if (pqgParams != NULL) {
537         PK11_PQG_DestroyParams(pqgParams);
538     }
539     if (pqgVfy != NULL) {
540         PK11_PQG_DestroyVerify(pqgVfy);
541     }
542     return certReq;
543 }
544
545
546
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)
555 {
556     CERTCertificate                 *issuerCert = NULL;
557     CERTValidity                    *validity;
558     CERTCertificate                 *cert = NULL;
559     PRExplodedTime                  printableTime;
560     PRTime                          now, 
561                                     after;
562     SECStatus rv;
563    
564     
565
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;
571         }
572     }
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();
577     }
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);
583     }
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);
590     }
591     /* note that the time is now in micro-second unit */
592     validity = CERT_CreateValidity (now, after);
593
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);
600     }
601     
602     CERT_DestroyValidity(validity);
603     if ( issuerCert ) {
604         CERT_DestroyCertificate (issuerCert);
605     }
606     return(cert);
607 }
608
609 static int
610 get_serial_number(Pair  *data)
611 {
612     int                 serial = 0;
613     int                 error;
614     char                *filename = SERIAL_FILE;
615     char                *SN;
616     FILE                *serialFile;
617
618
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");
625             }
626             if (serial == 4294967295) {
627                 serial = 21;
628             }
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");
634             }
635             fwrite(&serial, sizeof(int), 1, serialFile);
636             if (ferror(serialFile) != 0) {
637                 error_out("Error: Unable to write to serial number file");
638             }
639         } else {
640             fclose(serialFile);
641             serialFile = fopen(filename,"w");
642             if (serialFile == NULL) {
643                 error_out("ERROR: Unable to open serial number file");
644             }
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");
649             }
650             error = ferror(serialFile);
651             if (error != 0) {
652                 error_out("ERROR: Unable to write to serial file");
653             }
654         }
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';
667                 }
668             }
669             ++SN;
670         }
671     }
672     return serial;
673 }
674         
675
676
677 typedef SECStatus (* EXTEN_VALUE_ENCODER)
678                 (PRArenaPool *extHandle, void *value, SECItem *encodedValue);
679
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)
688 {
689     SECItem                  encodedValue;
690     SECStatus                rv;
691         
692
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");
698     }
699     rv = CERT_AddExtension
700         (extHandle, extenType, &encodedValue, criticality, PR_TRUE);
701     return (rv);
702 }
703
704
705
706 static SECStatus 
707 AddKeyUsage (void  *extHandle, 
708              Pair  *data)
709 {
710     SECItem        bitStringValue;
711     unsigned char  keyUsage = 0x0;
712
713     if (find_field_bool(data,"keyUsage-digitalSignature", PR_TRUE)){
714         keyUsage |= (0x80 >> 0);
715     }
716     if (find_field_bool(data,"keyUsage-nonRepudiation", PR_TRUE)){
717         keyUsage |= (0x80 >> 1);
718     }
719     if (find_field_bool(data,"keyUsage-keyEncipherment", PR_TRUE)){
720         keyUsage |= (0x80 >> 2);
721     }
722     if (find_field_bool(data,"keyUsage-dataEncipherment", PR_TRUE)){
723         keyUsage |= (0x80 >> 3);
724     }
725     if (find_field_bool(data,"keyUsage-keyAgreement", PR_TRUE)){
726         keyUsage |= (0x80 >> 4);
727     }
728     if (find_field_bool(data,"keyUsage-keyCertSign", PR_TRUE)) {
729         keyUsage |= (0x80 >> 5);
730     }
731     if (find_field_bool(data,"keyUsage-cRLSign", PR_TRUE)) {
732         keyUsage |= (0x80 >> 6);
733     }
734
735     bitStringValue.data = &keyUsage;
736     bitStringValue.len = 1;
737
738     return (CERT_EncodeAndAddBitStrExtension
739             (extHandle, SEC_OID_X509_KEY_USAGE, &bitStringValue,
740              (find_field_bool(data, "keyUsage-crit", PR_TRUE))));
741
742 }
743
744 static CERTOidSequence *
745 CreateOidSequence(void)
746 {
747   CERTOidSequence *rv = (CERTOidSequence *)NULL;
748   PRArenaPool *arena = (PRArenaPool *)NULL;
749
750   arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
751   if( (PRArenaPool *)NULL == arena ) {
752     goto loser;
753   }
754
755   rv = (CERTOidSequence *)PORT_ArenaZAlloc(arena, sizeof(CERTOidSequence));
756   if( (CERTOidSequence *)NULL == rv ) {
757     goto loser;
758   }
759
760   rv->oids = (SECItem **)PORT_ArenaZAlloc(arena, sizeof(SECItem *));
761   if( (SECItem **)NULL == rv->oids ) {
762     goto loser;
763   }
764
765   rv->arena = arena;
766   return rv;
767
768  loser:
769   if( (PRArenaPool *)NULL != arena ) {
770     PORT_FreeArena(arena, PR_FALSE);
771   }
772
773   return (CERTOidSequence *)NULL;
774 }
775
776 static SECStatus
777 AddOidToSequence(CERTOidSequence *os, SECOidTag oidTag)
778 {
779   SECItem **oids;
780   PRUint32 count = 0;
781   SECOidData *od;
782
783   od = SECOID_FindOIDByTag(oidTag);
784   if( (SECOidData *)NULL == od ) {
785     return SECFailure;
786   }
787
788   for( oids = os->oids; (SECItem *)NULL != *oids; oids++ ) {
789     count++;
790   }
791
792   /* ArenaZRealloc */
793
794   {
795     PRUint32 i;
796
797     oids = (SECItem **)PORT_ArenaZAlloc(os->arena, sizeof(SECItem *) * (count+2));
798     if( (SECItem **)NULL == oids ) {
799       return SECFailure;
800     }
801     
802     for( i = 0; i < count; i++ ) {
803       oids[i] = os->oids[i];
804     }
805
806     /* ArenaZFree(os->oids); */
807   }
808
809   os->oids = oids;
810   os->oids[count] = &od->oid;
811
812   return SECSuccess;
813 }
814
815 static SECItem *
816 EncodeOidSequence(CERTOidSequence *os)
817 {
818   SECItem *rv;
819   extern const SEC_ASN1Template CERT_OidSeqTemplate[];
820
821   rv = (SECItem *)PORT_ArenaZAlloc(os->arena, sizeof(SECItem));
822   if( (SECItem *)NULL == rv ) {
823     goto loser;
824   }
825
826   if( !SEC_ASN1EncodeItem(os->arena, rv, os, CERT_OidSeqTemplate) ) {
827     goto loser;
828   }
829
830   return rv;
831
832  loser:
833   return (SECItem *)NULL;
834 }
835
836 static SECStatus
837 AddExtKeyUsage(void *extHandle, Pair *data)
838 {
839   SECStatus rv;
840   CERTOidSequence *os;
841   SECItem *value;
842   PRBool crit;
843
844   os = CreateOidSequence();
845   if( (CERTOidSequence *)NULL == os ) {
846     return SECFailure;
847   }
848
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;
852   }
853
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;
857   }
858
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;
862   }
863
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;
867   }
868
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;
872   }
873
874   if( find_field_bool(data, "extKeyUsage-ocspResponder", PR_TRUE) ) {
875     rv = AddOidToSequence(os, SEC_OID_OCSP_RESPONDER);
876     if( SECSuccess != rv ) goto loser;
877   }
878
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;
882   }
883
884   value = EncodeOidSequence(os);
885
886   crit = find_field_bool(data, "extKeyUsage-crit", PR_TRUE);
887
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;
894 }
895
896 static SECStatus
897 AddSubKeyID(void             *extHandle, 
898             Pair             *data, 
899             CERTCertificate  *subjectCert)
900 {
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;
911
912
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");
922         }
923         while (*read != '\0') {
924             if (!isxdigit(*read)) {
925                 error_out("ERROR: Improperly formated subject key identifier");
926             }
927             *read = toupper(*read);
928             if ((*read >= 'A') && (*read <= 'F')) {
929                 high_digit = *read - 'A' + 10;
930             }  else {
931                 high_digit = *read - '0';
932             }
933             ++read;
934             if (!isxdigit(*read)) {
935                 error_out("ERROR: Improperly formated subject key identifier");
936             }
937             *read = toupper(*read);
938             if ((*read >= 'A') && (*read <= 'F')) {
939                 low_digit = *(read) - 'A' + 10;
940             } else {
941                 low_digit = *(read) - '0';
942             }
943             character = (high_digit << 4) | low_digit;
944             *write = character;
945             ++write;
946             ++read;
947         }
948         *write = '\0';
949         len = write - first;
950     }
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);
958     }
959     return (CERT_AddExtension(extHandle,  SEC_OID_X509_SUBJECT_KEY_ID, 
960                               &encodedValue, PR_FALSE, PR_TRUE));
961 }
962
963
964 static SECStatus 
965 AddAuthKeyID (void              *extHandle,
966               Pair              *data, 
967               char              *issuerNameStr, 
968               CERTCertDBHandle  *handle)
969 {
970     CERTAuthKeyID               *authKeyID = NULL;    
971     PRArenaPool                 *arena = NULL;
972     SECStatus                   rv = SECSuccess;
973     CERTCertificate             *issuerCert = NULL;
974     CERTGeneralName             *genNames;
975     CERTName                    *directoryName = NULL;
976
977
978     issuerCert = CERT_FindCertByNameString(handle, issuerNameStr);
979     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
980     if ( !arena ) {
981         error_allocate();
982     }
983
984     authKeyID = PORT_ArenaZAlloc (arena, sizeof (CERTAuthKeyID));
985     if (authKeyID == NULL) {
986         error_allocate();
987     }
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();
994         }
995         PORT_Memcpy (authKeyID->keyID.data, issuerCert->subjectKeyID.data, 
996                      authKeyID->keyID.len = 
997                         PORT_Strlen((char *)issuerCert->subjectKeyID.data));
998     } else {
999         
1000         PORT_Assert (arena);
1001         genNames = (CERTGeneralName *) PORT_ArenaZAlloc (arena, (sizeof(CERTGeneralName)));
1002         if (genNames == NULL){
1003             error_allocate();
1004         }
1005         genNames->l.next = genNames->l.prev = &(genNames->l);
1006         genNames->type = certDirectoryName;
1007
1008         directoryName = CERT_AsciiToName(issuerCert->subjectName);
1009         if (!directoryName) {
1010             error_out("ERROR: Unable to create Directory Name");
1011         }
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");
1017         }
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");
1022         }
1023         authKeyID->authCertSerialNumber = issuerCert->serialNumber;
1024     }
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);
1031     }
1032     return (rv);
1033 }
1034
1035
1036 static SECStatus 
1037 AddPrivKeyUsagePeriod(void             *extHandle, 
1038                       Pair             *data, 
1039                       CERTCertificate  *cert)
1040 {
1041     char *notBeforeStr;
1042     char *notAfterStr;
1043     PRArenaPool *arena = NULL;
1044     SECStatus rv = SECSuccess;
1045     CERTPrivKeyUsagePeriod *pkup;
1046
1047
1048     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1049     if ( !arena ) {
1050         error_allocate();
1051     }
1052     pkup = PORT_ArenaZNew (arena, CERTPrivKeyUsagePeriod);
1053     if (pkup == NULL) {
1054         error_allocate();
1055     }
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");
1108             }
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");
1118             }
1119             PORT_Strcat(notBeforeStr, (char *)cert->validity.notBefore.data);
1120         }
1121     }
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");
1157         }
1158         *(notAfterStr + 14) = 'Z';
1159         *(notAfterStr + 15) = '\0';
1160     }
1161         
1162     PORT_Assert (arena);
1163
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);
1173     }
1174     if (notBeforeStr != NULL) {
1175         PORT_Free(notBeforeStr);
1176     }
1177     if (notAfterStr != NULL) {
1178         PORT_Free(notAfterStr);
1179     }
1180     return (rv);
1181 }    
1182
1183 static SECStatus 
1184 AddBasicConstraint(void   *extHandle, 
1185                    Pair   *data)
1186 {
1187     CERTBasicConstraints  basicConstraint;
1188     SECItem               encodedValue;
1189     SECStatus             rv;
1190
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));
1200     }
1201     
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);
1210
1211     PORT_Free (encodedValue.data);
1212     return (rv);
1213 }
1214
1215
1216
1217 static SECStatus 
1218 AddNscpCertType (void  *extHandle, 
1219                  Pair  *data)
1220 {
1221     SECItem            bitStringValue;
1222     unsigned char      CertType = 0x0;
1223
1224     if (find_field_bool(data,"netscape-cert-type-ssl-client", PR_TRUE)){
1225         CertType |= (0x80 >> 0);
1226     }
1227     if (find_field_bool(data,"netscape-cert-type-ssl-server", PR_TRUE)){
1228         CertType |= (0x80 >> 1);
1229     }
1230     if (find_field_bool(data,"netscape-cert-type-smime", PR_TRUE)){
1231         CertType |= (0x80 >> 2);
1232     }
1233     if (find_field_bool(data,"netscape-cert-type-object-signing", PR_TRUE)){
1234         CertType |= (0x80 >> 3);
1235     }
1236     if (find_field_bool(data,"netscape-cert-type-reserved", PR_TRUE)){
1237         CertType |= (0x80 >> 4);
1238     }
1239     if (find_field_bool(data,"netscape-cert-type-ssl-ca", PR_TRUE)) {
1240         CertType |= (0x80 >> 5);
1241     }
1242     if (find_field_bool(data,"netscape-cert-type-smime-ca", PR_TRUE)) {
1243         CertType |= (0x80 >> 6);
1244     }
1245     if (find_field_bool(data,"netscape-cert-type-object-signing-ca", PR_TRUE)) {
1246         CertType |= (0x80 >> 7);
1247     }
1248
1249     bitStringValue.data = &CertType;
1250     bitStringValue.len = 1;
1251
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))));
1255 }
1256
1257
1258 static SECStatus
1259 add_IA5StringExtension(void    *extHandle, 
1260                        char    *string, 
1261                        PRBool  crit, 
1262                        int     idtag)
1263 {
1264     SECItem                    encodedValue;
1265     SECStatus                  rv;
1266
1267     encodedValue.data = NULL;
1268     encodedValue.len = 0;
1269
1270     rv = CERT_EncodeIA5TypeExtension(NULL, string, &encodedValue);
1271     if (rv) {
1272         return (rv);
1273     }
1274     return (CERT_AddExtension(extHandle, idtag, &encodedValue, crit, PR_TRUE));
1275 }
1276
1277 static SECItem *
1278 string_to_oid(char  *string)
1279 {
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;
1292     
1293     
1294     remaining = length;
1295     i = 0;
1296     while (*string == ' ') {
1297         string++;
1298     }
1299     while (isdigit(*(string + i))) {
1300         i++;
1301     }
1302     if (*(string + i) == '.') {
1303         *(string + i) = '\0';
1304     } else {
1305         error_out("ERROR: Improperly formated OID");
1306     }
1307     first_value = atoi(string);
1308     if (first_value < 0 || first_value > 2) {
1309         error_out("ERROR: Improperly formated OID");
1310     }
1311     string += i + 1;
1312     i = 0;
1313     while (isdigit(*(string + i))) {
1314         i++;
1315     }
1316     if (*(string + i) == '.') {
1317         *(string + i) = '\0';
1318     } else {
1319         error_out("ERROR: Improperly formated OID");
1320     }
1321     second_value = atoi(string);
1322     if (second_value < 0 || second_value > 39) {
1323         error_out("ERROR: Improperly formated OID");
1324     }
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++;
1336         }
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");
1353                 }
1354             }
1355         }
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;
1363             }
1364             *write = (value & 0x7f) | (0x80);
1365             write++;
1366             remaining--;
1367             value = value >> 7;
1368         }
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++;
1378         }
1379         write = temp;
1380         remaining = length;
1381     }
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;
1388 }
1389
1390 static SECItem *
1391 string_to_ipaddress(char *string)
1392 {
1393     int      i = 0;
1394     int      value;
1395     int      j = 0;
1396     SECItem  *ipaddress;
1397     
1398
1399     while (*string == ' ') {
1400         string++;
1401     }
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++;
1407         }
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++;
1422                 }
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");
1429                 }
1430             }
1431         }
1432         if (value >= 0 || value < 256) {
1433             *(ipaddress->data + j) = value;
1434         } else {
1435             error_out("ERROR: Improperly formated IP Address");
1436         }
1437         j++;
1438     }
1439     *(ipaddress->data + j) = '\0';
1440     if (j != 4 && j != 8) {
1441         error_out("ERROR: Improperly formated IP Address");
1442     }
1443     ipaddress->len = j;
1444     return ipaddress;
1445 }
1446
1447 static SECItem *
1448 string_to_binary(char  *string)
1449 {
1450     SECItem            *rv;
1451     int                high_digit;
1452     int                low_digit;
1453
1454     rv = (SECItem *) PORT_ZAlloc(sizeof(SECItem));
1455     if (rv == NULL) {
1456         error_allocate();
1457     }
1458     rv->data = (unsigned char *) PORT_ZAlloc((PORT_Strlen(string))/3 + 2);
1459     while (!isxdigit(*string)) {
1460         string++;
1461     }
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';
1470             }
1471             string++;
1472             if (*string >= '0' && *string <= '9') {
1473                 low_digit = *string - '0';
1474             } else {
1475                 *string = toupper(*string);
1476                 low_digit = *string = 'A';
1477             }
1478             (rv->len)++;
1479         } else {
1480             if (*string == ':') {
1481                 string++;
1482             } else {
1483                 if (*string == ' ') {
1484                     while (*string == ' ') {
1485                         string++;
1486                     }
1487                 }
1488                 if (*string != '\0') {
1489                     error_out("ERROR: Improperly formated binary encoding");
1490                 }
1491             }
1492         } 
1493     }
1494
1495     return rv;
1496 }
1497
1498 static SECStatus
1499 MakeGeneralName(char             *name, 
1500                 CERTGeneralName  *genName,
1501                 PRArenaPool      *arena)
1502 {
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;
1512
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;
1519     }
1520     if (nameType < 1 || nameType > 9) {
1521         error_out("ERROR: Unknown General Name Type");
1522     }
1523     *(name + PORT_Strlen(name) - 4) = '\0';
1524     genName->type = nameType;
1525     
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;
1533       }
1534       
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;
1540       }
1541       
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;
1547       }
1548       
1549       case certEDIPartyName:
1550       case certX400Address: {
1551           
1552           genName->name.other.data = PORT_ArenaAlloc (arena, 
1553                                                       PORT_Strlen (name) + 2);
1554           if (genName->name.other.data == NULL) {
1555               error_allocate();
1556           }
1557           
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;
1566       }
1567       
1568       case certOtherName: {
1569           i = 0;
1570           if (!nickname) {
1571               while (!isdigit(*(name + PORT_Strlen(name) - i))) {
1572                   i++;
1573               }
1574               if (*(name + PORT_Strlen(name) - i) == '1') {
1575                   binary = PR_TRUE;
1576               } else {
1577                   binary = PR_FALSE;
1578               }  
1579               while (*(name + PORT_Strlen(name) - i) != '-') {
1580                   i++;
1581               }
1582               *(name + PORT_Strlen(name) - i - 1) = '\0';
1583               i = 0;
1584               while (*(name + i) != '-') {
1585                   i++;
1586               }
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++;
1594               }
1595               *(name + PORT_Strlen(name) - i) = '\0';
1596           }
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();
1607               }
1608               temp->data = (unsigned char *)name;
1609               temp->len = PORT_Strlen(name);
1610               SEC_ASN1EncodeItem (arena, &(genName->name.OthName.name), temp,
1611                                   CERTIA5TypeTemplate);
1612           }
1613           PORT_Free(temp);
1614           break;
1615       }
1616       
1617       case certDirectoryName: {
1618           CERTName *directoryName = NULL;
1619           
1620           directoryName = CERT_AsciiToName (name);
1621           if (!directoryName) {
1622               error_out("ERROR: Improperly formated alternative name");
1623               break;
1624           }
1625           rv = CERT_CopyName (arena, &genName->name.directoryName, 
1626                               directoryName);
1627           CERT_DestroyName (directoryName);
1628           
1629           break;
1630       }
1631     }
1632     genName->l.next = &(genName->l);
1633     genName->l.prev = &(genName->l);
1634     return rv;
1635 }
1636
1637
1638 static CERTGeneralName *
1639 MakeAltName(Pair             *data, 
1640             char             *which, 
1641             PRArenaPool      *arena)
1642 {
1643     CERTGeneralName          *SubAltName;
1644     CERTGeneralName          *current;
1645     CERTGeneralName          *newname;
1646     char                     *name = NULL;
1647     SECStatus                rv = SECSuccess;
1648     int                      len;
1649     
1650
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();
1657     }
1658     while (name != NULL) {
1659
1660         rv = MakeGeneralName(name, current, arena);
1661
1662         if (rv != SECSuccess) {
1663             break;
1664         }
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++;
1676             }
1677         }
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();
1684             }
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);
1692         }
1693     }
1694     if (rv == SECFailure) {
1695         return NULL;
1696     }
1697     return SubAltName;
1698 }
1699
1700 static CERTNameConstraints *
1701 MakeNameConstraints(Pair             *data, 
1702                     PRArenaPool      *arena)
1703 {
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;
1716     
1717
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();
1729         }
1730         i = 0;
1731         while (*(constraint + PORT_Strlen(constraint) - i) != '-') {
1732             i++;
1733         }
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);
1738         }
1739         i = 0;
1740         while (*(constraint + PORT_Strlen(constraint) - i) != '-') {
1741             i++;
1742         }
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++;
1748         }
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;
1754         }
1755         rv = MakeGeneralName(constraint, &(current->name), arena);
1756
1757         if (rv != SECSuccess) {
1758             break;
1759         }
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++;
1771             }
1772         }
1773         len = PORT_Strlen(which);
1774         if (permited) {
1775             if (NameConstraints->permited == NULL) {
1776                 NameConstraints->permited = last_permited = current;
1777             }
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;
1784             }
1785             last_excluded->l.next = &(current->l);
1786             current->l.prev = &(last_excluded->l);
1787             last_excluded = current;
1788         }
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();
1794             }
1795         }
1796     }
1797     if (NameConstraints->permited != NULL) {
1798         last_permited->l.next = &(NameConstraints->permited->l);
1799         NameConstraints->permited->l.prev = &(last_permited->l);
1800     }
1801     if (NameConstraints->excluded != NULL) {
1802         last_excluded->l.next = &(NameConstraints->excluded->l);
1803         NameConstraints->excluded->l.prev = &(last_excluded->l);
1804     }
1805     if (which != NULL) {
1806         PORT_Free(which);
1807     }
1808     if (rv == SECFailure) {
1809         return NULL;
1810     }
1811     return NameConstraints;
1812 }
1813
1814
1815
1816 static SECStatus
1817 AddAltName(void              *extHandle,
1818            Pair              *data,
1819            char              *issuerNameStr, 
1820            CERTCertDBHandle  *handle,
1821            int               type)
1822 {
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;
1831
1832     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1833     if (arena == NULL) {
1834         error_allocate();
1835     }
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");
1851             }
1852         } else {
1853             which = make_copy_string("IssuerAltNameSelect0", 20,'\0');
1854             genName = MakeAltName(data, which, arena);
1855         }
1856     }
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);
1864
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);
1878         }
1879     }
1880     if (which != NULL) {
1881         PORT_Free(which);
1882     }
1883     if (issuerCert != NULL) {
1884         CERT_DestroyCertificate(issuerCert);
1885     }
1886     return rv;
1887 }
1888
1889
1890 static SECStatus
1891 AddNameConstraints(void  *extHandle,
1892                    Pair  *data)
1893 {
1894     PRArenaPool         *arena = NULL;
1895     CERTNameConstraints *constraints = NULL;
1896     SECStatus           rv = SECSuccess;
1897
1898
1899     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1900     if (arena == NULL) {
1901         error_allocate();
1902     }
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);
1909     }
1910     if (arena != NULL) {
1911         PORT_ArenaRelease (arena, NULL);
1912     }
1913     return rv;
1914 }
1915
1916
1917 static SECStatus
1918 add_extensions(CERTCertificate   *subjectCert, 
1919                Pair              *data, 
1920                char              *issuerNameStr, 
1921                CERTCertDBHandle  *handle)
1922 {
1923     void                         *extHandle;
1924     SECStatus                    rv = SECSuccess;
1925
1926
1927     extHandle = CERT_StartCertExtensions (subjectCert);
1928     if (extHandle == NULL) {
1929         error_out("ERROR: Unable to get certificates extension handle");
1930     }
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");
1935         }
1936     }
1937
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");
1942       }
1943     }
1944
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");
1949         }
1950     }
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");
1955         }
1956     }
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");
1961         }
1962     }
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");
1967         }
1968     }
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");
1973         }
1974     }
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");
1979         }
1980     }
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");
1985         }
1986     }
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");
1991         }
1992     }
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");
2003         }
2004     }
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");
2016         }
2017     }
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");
2029         }
2030     }
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");
2042         }
2043     }
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");
2055         }
2056     }
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");
2068         }
2069     }
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");
2080         }
2081     }
2082     CERT_FinishExtensions(extHandle);
2083     return (rv);
2084 }
2085
2086
2087
2088 char *
2089 return_dbpasswd(PK11SlotInfo *slot, PRBool retry, void *data)
2090 {
2091     char *rv;
2092
2093     /* don't clobber our poor smart card */
2094     if (retry == PR_TRUE) {
2095         return NULL;
2096     }
2097     rv = PORT_Alloc(4);
2098     PORT_Strcpy(rv, "foo");
2099     return rv;
2100 }
2101
2102
2103 SECKEYPrivateKey *
2104 FindPrivateKeyFromNameStr(char              *name, 
2105                           CERTCertDBHandle  *certHandle)
2106 {
2107     SECKEYPrivateKey                        *key;
2108     CERTCertificate                         *cert;
2109     CERTCertificate                         *p11Cert;
2110
2111
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.
2118     */
2119     cert = CERT_FindCertByNameString(certHandle, name);
2120     if (cert == NULL || cert->nickname == NULL) {
2121         error_out("ERROR: Unable to retrieve issuers certificate");
2122     }
2123     p11Cert = PK11_FindCertFromNickname(cert->nickname, NULL);
2124     if (p11Cert == NULL) {
2125         error_out("ERROR: Unable to retrieve issuers certificate");
2126     }
2127     key = PK11_FindKeyByAnyCert(p11Cert, NULL);
2128     return key;
2129 }
2130
2131 static SECItem *
2132 SignCert(CERTCertificate   *cert,
2133          char              *issuerNameStr,
2134          Pair              *data,
2135          CERTCertDBHandle  *handle,
2136          int               which_key)
2137 {
2138     SECItem                der;
2139     SECKEYPrivateKey       *caPrivateKey = NULL;
2140     SECStatus              rv;
2141     PRArenaPool            *arena;
2142     SECOidTag              algID;
2143
2144     if (which_key == 0) {
2145         caPrivateKey = FindPrivateKeyFromNameStr(issuerNameStr, handle); 
2146     } else {
2147         caPrivateKey = privkeys[which_key - 1];
2148     }
2149     if (caPrivateKey == NULL) {
2150         error_out("ERROR: unable to retrieve issuers key");
2151     }
2152         
2153     arena = cert->arena;
2154
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;
2160     }
2161
2162     rv = SECOID_SetAlgorithmID(arena, &cert->signature, algID, 0);
2163     if (rv != SECSuccess) {
2164         error_out("ERROR: Could not set signature algorithm id.");
2165     }
2166
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;
2173     }
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");
2179     }
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");
2184     }
2185 done:
2186     SECKEY_DestroyPrivateKey(caPrivateKey);
2187     return &(cert->derCert);
2188 }
2189
2190
2191 int
2192 main(int argc, char **argv)
2193 {
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;
2227
2228
2229     progName = strrchr(argv[0], '/');
2230     progName = progName ? progName+1 : argv[0];
2231
2232
2233 #ifdef TEST
2234     sleep(20);
2235 #endif
2236     SECU_ConfigDirectory(DBdir);
2237
2238     PK11_SetPasswordFunc(return_dbpasswd);
2239     status = NSS_InitReadWrite(DBdir);
2240     if (status != SECSuccess) {
2241         SECU_PrintPRandOSError(progName);
2242         return -1;
2243     }
2244     handle = CERT_GetDefaultCertDB();
2245
2246     prefix[0]= '\0';
2247 #if !defined(OFFLINE)
2248     form_output = (char*) PORT_Alloc(length);
2249     if (form_output == NULL) {
2250         error_allocate();
2251     }
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();
2260             }
2261             pos = form_output + length - remaining;
2262         }
2263         n = fread(pos, 1, (size_t) (remaining - 1), stdin);
2264         pos += n;
2265         remaining -= n;
2266     }
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++;
2296     }
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;
2310         }
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");
2319             }
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");
2327         }
2328         chainLen = 0;
2329     }
2330
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]);
2338         }
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);
2350         }
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");
2355             }
2356         }
2357         status = cert_GetKeyID(cert);
2358         if (status == SECFailure) {
2359             error_out("ERROR: Unable to get Key ID.");
2360         }
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;
2368         }
2369         ++which_key;
2370     } while (i < 9 && UChain);
2371
2372
2373
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");
2382     }
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
2393
2394     } else {
2395         error_out("Error: Unable to DER encode certificate");
2396     }
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);
2405     }
2406     return 0;
2407 }
2408