Back to index

lightning-sunbird  0.9+nobinonly
certcgi.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 /* Cert-O-Matic CGI */
00038 
00039 
00040 #include "nspr.h"
00041 #include "prtypes.h"
00042 #include "prtime.h"
00043 #include "prlong.h"
00044 
00045 #include "pk11func.h"
00046 #include "cert.h"
00047 #include "cryptohi.h"
00048 #include "secoid.h"
00049 #include "secder.h"
00050 #include "genname.h"
00051 #include "xconst.h"
00052 #include "secutil.h"
00053 #include "pk11pqg.h"
00054 #include "certxutl.h"
00055 #include "nss.h"
00056 
00057 
00058 /* #define TEST           1 */
00059 /* #define FILEOUT        1 */
00060 /* #define OFFLINE        1 */
00061 #define START_FIELDS   100
00062 #define PREFIX_LEN     6
00063 #define SERIAL_FILE    "../serial"
00064 #define DB_DIRECTORY   ".."
00065 
00066 static char *progName;
00067 
00068 typedef struct PairStr Pair;
00069 
00070 struct PairStr {
00071     char *name;
00072     char *data;
00073 };
00074 
00075 
00076 char prefix[PREFIX_LEN];
00077 
00078 
00079 const SEC_ASN1Template CERTIA5TypeTemplate[] = {
00080     { SEC_ASN1_IA5_STRING }
00081 };
00082 
00083 
00084 
00085 SECKEYPrivateKey *privkeys[9] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL,
00086                              NULL, NULL};
00087 
00088 
00089 #ifdef notdef
00090 const SEC_ASN1Template CERT_GeneralNameTemplate[] = {
00091     { SEC_ASN1_SEQUENCE_OF, 0, SEC_AnyTemplate }
00092 };
00093 #endif
00094 
00095 
00096 static void
00097 error_out(char  *error_string)
00098 {
00099     printf("Content-type: text/plain\n\n");
00100     printf(error_string);
00101     fflush(stderr);
00102     fflush(stdout);
00103     exit(1);
00104 }
00105 
00106 static void
00107 error_allocate(void)
00108 {
00109     error_out("ERROR: Unable to allocate memory");
00110 }
00111 
00112 
00113 static char *
00114 make_copy_string(char  *read_pos, 
00115                int   length, 
00116                char  sentinal_value)
00117     /* copys string from to a new string it creates and 
00118        returns a pointer to the new string */
00119 {
00120     int                remaining = length;
00121     char               *write_pos;
00122     char               *new;
00123 
00124     new = write_pos = (char *) PORT_Alloc (length);
00125     if (new == NULL) {
00126        error_allocate();
00127     }
00128     while (*read_pos != sentinal_value) {
00129        if (remaining == 1) {
00130            remaining += length;
00131            length = length * 2;
00132            new = PORT_Realloc(new,length);
00133            if (new == NULL) {
00134               error_allocate();
00135            }
00136            write_pos = new + length - remaining;
00137        }
00138        *write_pos = *read_pos;
00139        ++write_pos;
00140        ++read_pos;
00141        remaining = remaining - 1;
00142     }
00143     *write_pos = '\0';
00144     return new;
00145 }
00146 
00147 
00148 static SECStatus
00149 clean_input(Pair *data)
00150     /* converts the non-alphanumeric characters in a form post 
00151        from hex codes back to characters */
00152 {
00153     int           length;
00154     int           hi_digit;
00155     int           low_digit;
00156     char          character;
00157     char          *begin_pos;
00158     char          *read_pos;
00159     char          *write_pos;
00160     PRBool        name = PR_TRUE;
00161 
00162     begin_pos = data->name;
00163     while (begin_pos != NULL) {
00164        length = strlen(begin_pos);
00165        read_pos = write_pos = begin_pos;
00166        while ((read_pos - begin_pos) < length) {
00167            if (*read_pos == '+') {
00168               *read_pos = ' ';
00169            }
00170            if (*read_pos == '%') {
00171               hi_digit = *(read_pos + 1);
00172               low_digit = *(read_pos +2);
00173               read_pos += 3;
00174               if (isdigit(hi_digit)){
00175                   hi_digit = hi_digit - '0';
00176               } else {
00177                   hi_digit = toupper(hi_digit);
00178                   if (isxdigit(hi_digit)) {
00179                      hi_digit = (hi_digit - 'A') + 10;
00180                   } else {
00181                      error_out("ERROR: Form data incorrectly formated");
00182                   }
00183               }
00184               if (isdigit(low_digit)){
00185                   low_digit = low_digit - '0';
00186               } else {
00187                   low_digit = toupper(low_digit);
00188                   if ((low_digit >='A') && (low_digit <= 'F')) {
00189                      low_digit = (low_digit - 'A') + 10;
00190                   } else {
00191                      error_out("ERROR: Form data incorrectly formated");
00192                   }
00193               }
00194               character = (hi_digit << 4) | low_digit;
00195               if (character != 10) {
00196                   *write_pos = character;
00197                   ++write_pos;
00198               }
00199            } else {
00200               *write_pos = *read_pos;
00201               ++write_pos;
00202               ++read_pos;
00203            }
00204        }
00205        *write_pos = '\0';
00206        if (name == PR_TRUE) {
00207            begin_pos = data->data;
00208            name = PR_FALSE;
00209        } else {
00210            data++;
00211            begin_pos = data->name;
00212            name = PR_TRUE;
00213        }
00214     }
00215     return SECSuccess;
00216 }
00217 
00218 static char *
00219 make_name(char  *new_data)
00220     /* gets the next field name in the input string and returns
00221        a pointer to a string containing a copy of it */
00222 {
00223     int         length = 20;
00224     char        *name;
00225 
00226     name = make_copy_string(new_data, length, '=');
00227     return name;
00228 }
00229        
00230 static char *
00231 make_data(char  *new_data)
00232     /* gets the data for the next field in the input string 
00233        and returns a pointer to a string containing it */
00234 {
00235     int         length = 100;
00236     char        *data;
00237     char        *read_pos;
00238 
00239     read_pos = new_data;
00240     while (*(read_pos - 1) != '=') {
00241        ++read_pos;
00242     }
00243     data = make_copy_string(read_pos, length, '&');
00244     return data;
00245 }
00246 
00247 
00248 static Pair
00249 make_pair(char  *new_data)
00250     /* makes a pair name/data pair from the input string */
00251 {
00252     Pair        temp;
00253 
00254     temp.name = make_name(new_data);
00255     temp.data = make_data(new_data);
00256     return temp;
00257 }
00258 
00259 
00260 
00261 static Pair *
00262 make_datastruct(char  *data, int len)
00263     /* parses the input from the form post into a data 
00264        structure of field name/data pairs */
00265 {
00266     Pair              *datastruct;
00267     Pair              *current;
00268     char              *curr_pos;
00269     int               fields = START_FIELDS;
00270     int               remaining = START_FIELDS;
00271 
00272     curr_pos = data;
00273     datastruct = current = (Pair *) PORT_Alloc(fields * sizeof(Pair));
00274     if (datastruct == NULL) {
00275        error_allocate();
00276     }
00277     while (curr_pos - data < len) {
00278        if (remaining == 1) {
00279            remaining += fields;
00280            fields = fields * 2;
00281            datastruct = (Pair *) PORT_Realloc
00282               (datastruct, fields * sizeof(Pair));
00283            if (datastruct == NULL) {
00284               error_allocate();
00285            }
00286            current = datastruct + (fields - remaining);
00287        }
00288        *current = make_pair(curr_pos);
00289        while (*curr_pos != '&') {
00290            ++curr_pos;
00291        }
00292        ++curr_pos;
00293        ++current;
00294        remaining = remaining - 1;
00295     }
00296     current->name = NULL;
00297     return datastruct;
00298 }
00299 
00300 static char *
00301 return_name(Pair  *data_struct,
00302            int   n)
00303     /* returns a pointer to the name of the nth 
00304        (starting from 0) item in the data structure */
00305 {
00306     char          *name;
00307 
00308     if ((data_struct + n)->name != NULL) {
00309        name = (data_struct + n)->name;
00310        return name;
00311     } else {
00312        return NULL;
00313     }
00314 }
00315 
00316 static char *
00317 return_data(Pair  *data_struct,int n)
00318     /* returns a pointer to the data of the nth (starting from 0) 
00319        itme in the data structure */
00320 {
00321     char          *data;
00322 
00323     data = (data_struct + n)->data;
00324     return data;
00325 }
00326 
00327 
00328 static char *
00329 add_prefix(char  *field_name)
00330 {
00331     extern char  prefix[PREFIX_LEN];
00332     int          i = 0;
00333     char         *rv;
00334     char         *write;
00335 
00336     rv = write = PORT_Alloc(PORT_Strlen(prefix) + PORT_Strlen(field_name) + 1);
00337     for(i = 0; i < PORT_Strlen(prefix); i++) {
00338        *write = prefix[i];
00339        write++;
00340     }
00341     *write = '\0';
00342     rv = PORT_Strcat(rv,field_name);
00343     return rv;
00344 }
00345 
00346 
00347 static char *
00348 find_field(Pair    *data, 
00349           char    *field_name, 
00350           PRBool  add_pre)
00351     /* returns a pointer to the data of the first pair 
00352        thats name matches the string it is passed */
00353 {
00354     int            i = 0;
00355     char           *retrieved;
00356     int            found = 0;
00357 
00358     if (add_pre) {
00359        field_name = add_prefix(field_name);
00360     }
00361     while(return_name(data, i) != NULL) {
00362        if (PORT_Strcmp(return_name(data, i), field_name) == 0) {
00363            retrieved = return_data(data, i);
00364            found = 1;
00365            break;
00366        }
00367        i++;
00368     }
00369     if (!found) {
00370        retrieved = NULL;
00371     }
00372     return retrieved;
00373 }
00374 
00375 static PRBool
00376 find_field_bool(Pair    *data, 
00377               char    *fieldname, 
00378               PRBool  add_pre)
00379 {
00380     char                *rv;
00381 
00382     rv = find_field(data, fieldname, add_pre);
00383        
00384     if  ((rv != NULL) && (PORT_Strcmp(rv, "true")) == 0) {
00385        return PR_TRUE;
00386     } else {
00387        return PR_FALSE;
00388     }
00389 }
00390 
00391 static char *
00392 update_data_by_name(Pair  *data, 
00393                   char  *field_name,
00394                     char  *new_data)
00395     /* replaces the data in the data structure associated with 
00396        a name with new data, returns null if not found */
00397 {
00398     int                   i = 0;
00399     int                   found = 0;
00400     int                   length = 100;
00401     char                  *new;
00402 
00403     while (return_name(data, i) != NULL) {
00404        if (PORT_Strcmp(return_name(data, i), field_name) == 0) {
00405            new = make_copy_string( new_data, length, '\0');
00406            PORT_Free(return_data(data, i));
00407            found = 1;
00408            (*(data + i)).data = new;
00409            break;
00410        }
00411        i++;
00412     }
00413     if (!found) {
00414        new = NULL;
00415     }
00416     return new;
00417 }
00418 
00419 static char *
00420 update_data_by_index(Pair  *data, 
00421                    int   n, 
00422                    char  *new_data)
00423     /* replaces the data of a particular index in the data structure */
00424 {
00425     int                    length = 100;
00426     char                   *new;
00427 
00428     new = make_copy_string(new_data, length, '\0');
00429     PORT_Free(return_data(data, n));
00430     (*(data + n)).data = new;
00431     return new;
00432 }
00433 
00434 
00435 static Pair *
00436 add_field(Pair   *data, 
00437          char*  field_name, 
00438          char*  field_data)
00439     /* adds a new name/data pair to the data structure */
00440 {
00441     int          i = 0;
00442     int          j;
00443     int          name_length = 100;
00444     int          data_length = 100;
00445 
00446     while(return_name(data, i) != NULL) {
00447        i++;
00448     }
00449     j = START_FIELDS;
00450     while ( j < (i + 1) ) {
00451        j = j * 2;
00452     }
00453     if (j == (i + 1)) {
00454        data = (Pair *) PORT_Realloc(data, (j * 2) * sizeof(Pair));
00455        if (data == NULL) {
00456            error_allocate();
00457        }
00458     }
00459     (*(data + i)).name = make_copy_string(field_name, name_length, '\0');
00460     (*(data + i)).data = make_copy_string(field_data, data_length, '\0');
00461     (data + i + 1)->name = NULL;
00462     return data;
00463 }
00464 
00465 
00466 static CERTCertificateRequest *
00467 makeCertReq(Pair             *form_data,
00468            int              which_priv_key)
00469     /* makes and encodes a certrequest */
00470 {
00471 
00472     PK11SlotInfo             *slot;
00473     CERTCertificateRequest   *certReq = NULL;
00474     CERTSubjectPublicKeyInfo *spki;
00475     SECKEYPrivateKey         *privkey = NULL;
00476     SECKEYPublicKey          *pubkey = NULL;
00477     CERTName                 *name;
00478     char                     *key;
00479     extern SECKEYPrivateKey  *privkeys[9];
00480     int                      keySizeInBits;
00481     char                     *challenge = "foo";
00482     SECStatus                rv = SECSuccess;
00483     PQGParams                *pqgParams = NULL;
00484     PQGVerify                *pqgVfy = NULL;
00485 
00486     name = CERT_AsciiToName(find_field(form_data, "subject", PR_TRUE));
00487     if (name == NULL) {
00488        error_out("ERROR: Unable to create Subject Name");
00489     }
00490     key = find_field(form_data, "key", PR_TRUE);
00491     if (key == NULL) {
00492        switch (*find_field(form_data, "keysize", PR_TRUE)) {
00493          case '0':
00494            keySizeInBits = 2048;
00495            break;
00496          case '1':
00497            keySizeInBits = 1024;
00498            break;
00499          case '2':
00500            keySizeInBits = 512;
00501            break;
00502          default:
00503            error_out("ERROR: Unsupported Key length selected");
00504        }
00505        if (find_field_bool(form_data, "keyType-dsa", PR_TRUE)) {
00506            rv = PK11_PQG_ParamGen(keySizeInBits, &pqgParams, &pqgVfy);
00507            if (rv != SECSuccess) {
00508               error_out("ERROR: Unable to generate PQG parameters");
00509            }
00510            slot = PK11_GetBestSlot(CKM_DSA_KEY_PAIR_GEN, NULL);
00511            privkey = PK11_GenerateKeyPair(slot, CKM_DSA_KEY_PAIR_GEN, 
00512                                       pqgParams,&pubkey, PR_FALSE, 
00513                                       PR_TRUE, NULL);
00514        } else {
00515            privkey = SECKEY_CreateRSAPrivateKey(keySizeInBits, &pubkey, NULL);
00516        }
00517        privkeys[which_priv_key] = privkey;
00518        spki = SECKEY_CreateSubjectPublicKeyInfo(pubkey);
00519     } else {
00520        spki = SECKEY_ConvertAndDecodePublicKeyAndChallenge(key, challenge, 
00521                                                      NULL);
00522        if (spki == NULL) {
00523            error_out("ERROR: Unable to decode Public Key and Challenge String");
00524        }
00525     }
00526     certReq = CERT_CreateCertificateRequest(name, spki, NULL);
00527     if (certReq == NULL) {
00528        error_out("ERROR: Unable to create Certificate Request");
00529     }
00530     if (pubkey != NULL) {
00531        SECKEY_DestroyPublicKey(pubkey);
00532     }
00533     if (spki != NULL) {
00534        SECKEY_DestroySubjectPublicKeyInfo(spki);
00535     }
00536     if (pqgParams != NULL) {
00537        PK11_PQG_DestroyParams(pqgParams);
00538     }
00539     if (pqgVfy != NULL) {
00540        PK11_PQG_DestroyVerify(pqgVfy);
00541     }
00542     return certReq;
00543 }
00544 
00545 
00546 
00547 static CERTCertificate *
00548 MakeV1Cert(CERTCertDBHandle        *handle, 
00549           CERTCertificateRequest  *req,
00550           char                    *issuerNameStr, 
00551           PRBool                  selfsign, 
00552           int                     serialNumber,
00553           int                     warpmonths,
00554           Pair                    *data)
00555 {
00556     CERTCertificate                 *issuerCert = NULL;
00557     CERTValidity                    *validity;
00558     CERTCertificate                 *cert = NULL;
00559     PRExplodedTime                  printableTime;
00560     PRTime                          now, 
00561                                    after;
00562     SECStatus rv;
00563    
00564     
00565 
00566     if ( !selfsign ) {
00567        issuerCert = CERT_FindCertByNameString(handle, issuerNameStr);
00568        if (!issuerCert) {
00569            error_out("ERROR: Could not find issuer's certificate");
00570            return NULL;
00571        }
00572     }
00573     if (find_field_bool(data, "manValidity", PR_TRUE)) {
00574        rv = DER_AsciiToTime(&now, find_field(data, "notBefore", PR_TRUE));
00575     } else {
00576        now = PR_Now();
00577     }
00578     PR_ExplodeTime (now, PR_GMTParameters, &printableTime);
00579     if ( warpmonths ) {
00580        printableTime.tm_month += warpmonths;
00581        now = PR_ImplodeTime (&printableTime);
00582        PR_ExplodeTime (now, PR_GMTParameters, &printableTime);
00583     }
00584     if (find_field_bool(data, "manValidity", PR_TRUE)) {
00585        rv = DER_AsciiToTime(&after, find_field(data, "notAfter", PR_TRUE));
00586        PR_ExplodeTime (after, PR_GMTParameters, &printableTime);
00587     } else {
00588        printableTime.tm_month += 3;
00589        after = PR_ImplodeTime (&printableTime);
00590     }
00591     /* note that the time is now in micro-second unit */
00592     validity = CERT_CreateValidity (now, after);
00593 
00594     if ( selfsign ) {
00595        cert = CERT_CreateCertificate
00596            (serialNumber,&(req->subject), validity, req);
00597     } else {
00598        cert = CERT_CreateCertificate
00599            (serialNumber,&(issuerCert->subject), validity, req);
00600     }
00601     
00602     CERT_DestroyValidity(validity);
00603     if ( issuerCert ) {
00604        CERT_DestroyCertificate (issuerCert);
00605     }
00606     return(cert);
00607 }
00608 
00609 static int
00610 get_serial_number(Pair  *data)
00611 {
00612     int                 serial = 0;
00613     int                 error;
00614     char                *filename = SERIAL_FILE;
00615     char                *SN;
00616     FILE                *serialFile;
00617 
00618 
00619     if (find_field_bool(data, "serial-auto", PR_TRUE)) {
00620        serialFile = fopen(filename, "r");
00621        if (serialFile != NULL) {
00622            fread(&serial, sizeof(int), 1, serialFile);
00623            if (ferror(serialFile) != 0) {
00624               error_out("Error: Unable to read serial number file");
00625            }
00626            if (serial == 4294967295) {
00627               serial = 21;
00628            }
00629            fclose(serialFile);
00630            ++serial;
00631            serialFile = fopen(filename,"w");
00632            if (serialFile == NULL) {
00633                error_out("ERROR: Unable to open serial number file for writing");
00634            }
00635            fwrite(&serial, sizeof(int), 1, serialFile);
00636            if (ferror(serialFile) != 0) {
00637               error_out("Error: Unable to write to serial number file");
00638            }
00639        } else {
00640            fclose(serialFile);
00641            serialFile = fopen(filename,"w");
00642            if (serialFile == NULL) {
00643               error_out("ERROR: Unable to open serial number file");
00644            }
00645            serial = 21;
00646            fwrite(&serial, sizeof(int), 1, serialFile);
00647            if (ferror(serialFile) != 0) {
00648               error_out("Error: Unable to write to serial number file");
00649            }
00650            error = ferror(serialFile);
00651            if (error != 0) {
00652               error_out("ERROR: Unable to write to serial file");
00653            }
00654        }
00655        fclose(serialFile);
00656     } else {
00657        SN = find_field(data, "serial_value", PR_TRUE);
00658        while (*SN != '\0') {
00659            serial = serial * 16;
00660            if ((*SN >= 'A') && (*SN <='F')) {
00661               serial += *SN - 'A' + 10; 
00662            } else {
00663               if ((*SN >= 'a') && (*SN <='f')) {
00664                   serial += *SN - 'a' + 10;
00665               } else {
00666                   serial += *SN - '0';
00667               }
00668            }
00669            ++SN;
00670        }
00671     }
00672     return serial;
00673 }
00674        
00675 
00676 
00677 typedef SECStatus (* EXTEN_VALUE_ENCODER)
00678               (PRArenaPool *extHandle, void *value, SECItem *encodedValue);
00679 
00680 static SECStatus 
00681 EncodeAndAddExtensionValue(
00682        PRArenaPool          *arena, 
00683        void                 *extHandle, 
00684        void                 *value, 
00685        PRBool                    criticality,
00686        int                extenType, 
00687        EXTEN_VALUE_ENCODER  EncodeValueFn)
00688 {
00689     SECItem                  encodedValue;
00690     SECStatus                rv;
00691        
00692 
00693     encodedValue.data = NULL;
00694     encodedValue.len = 0;
00695     rv = (*EncodeValueFn)(arena, value, &encodedValue);
00696     if (rv != SECSuccess) {
00697        error_out("ERROR: Unable to encode extension value");
00698     }
00699     rv = CERT_AddExtension
00700        (extHandle, extenType, &encodedValue, criticality, PR_TRUE);
00701     return (rv);
00702 }
00703 
00704 
00705 
00706 static SECStatus 
00707 AddKeyUsage (void  *extHandle, 
00708             Pair  *data)
00709 {
00710     SECItem        bitStringValue;
00711     unsigned char  keyUsage = 0x0;
00712 
00713     if (find_field_bool(data,"keyUsage-digitalSignature", PR_TRUE)){
00714        keyUsage |= (0x80 >> 0);
00715     }
00716     if (find_field_bool(data,"keyUsage-nonRepudiation", PR_TRUE)){
00717        keyUsage |= (0x80 >> 1);
00718     }
00719     if (find_field_bool(data,"keyUsage-keyEncipherment", PR_TRUE)){
00720        keyUsage |= (0x80 >> 2);
00721     }
00722     if (find_field_bool(data,"keyUsage-dataEncipherment", PR_TRUE)){
00723        keyUsage |= (0x80 >> 3);
00724     }
00725     if (find_field_bool(data,"keyUsage-keyAgreement", PR_TRUE)){
00726        keyUsage |= (0x80 >> 4);
00727     }
00728     if (find_field_bool(data,"keyUsage-keyCertSign", PR_TRUE)) {
00729        keyUsage |= (0x80 >> 5);
00730     }
00731     if (find_field_bool(data,"keyUsage-cRLSign", PR_TRUE)) {
00732        keyUsage |= (0x80 >> 6);
00733     }
00734 
00735     bitStringValue.data = &keyUsage;
00736     bitStringValue.len = 1;
00737 
00738     return (CERT_EncodeAndAddBitStrExtension
00739            (extHandle, SEC_OID_X509_KEY_USAGE, &bitStringValue,
00740             (find_field_bool(data, "keyUsage-crit", PR_TRUE))));
00741 
00742 }
00743 
00744 static CERTOidSequence *
00745 CreateOidSequence(void)
00746 {
00747   CERTOidSequence *rv = (CERTOidSequence *)NULL;
00748   PRArenaPool *arena = (PRArenaPool *)NULL;
00749 
00750   arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00751   if( (PRArenaPool *)NULL == arena ) {
00752     goto loser;
00753   }
00754 
00755   rv = (CERTOidSequence *)PORT_ArenaZAlloc(arena, sizeof(CERTOidSequence));
00756   if( (CERTOidSequence *)NULL == rv ) {
00757     goto loser;
00758   }
00759 
00760   rv->oids = (SECItem **)PORT_ArenaZAlloc(arena, sizeof(SECItem *));
00761   if( (SECItem **)NULL == rv->oids ) {
00762     goto loser;
00763   }
00764 
00765   rv->arena = arena;
00766   return rv;
00767 
00768  loser:
00769   if( (PRArenaPool *)NULL != arena ) {
00770     PORT_FreeArena(arena, PR_FALSE);
00771   }
00772 
00773   return (CERTOidSequence *)NULL;
00774 }
00775 
00776 static SECStatus
00777 AddOidToSequence(CERTOidSequence *os, SECOidTag oidTag)
00778 {
00779   SECItem **oids;
00780   PRUint32 count = 0;
00781   SECOidData *od;
00782 
00783   od = SECOID_FindOIDByTag(oidTag);
00784   if( (SECOidData *)NULL == od ) {
00785     return SECFailure;
00786   }
00787 
00788   for( oids = os->oids; (SECItem *)NULL != *oids; oids++ ) {
00789     count++;
00790   }
00791 
00792   /* ArenaZRealloc */
00793 
00794   {
00795     PRUint32 i;
00796 
00797     oids = (SECItem **)PORT_ArenaZAlloc(os->arena, sizeof(SECItem *) * (count+2));
00798     if( (SECItem **)NULL == oids ) {
00799       return SECFailure;
00800     }
00801     
00802     for( i = 0; i < count; i++ ) {
00803       oids[i] = os->oids[i];
00804     }
00805 
00806     /* ArenaZFree(os->oids); */
00807   }
00808 
00809   os->oids = oids;
00810   os->oids[count] = &od->oid;
00811 
00812   return SECSuccess;
00813 }
00814 
00815 static SECItem *
00816 EncodeOidSequence(CERTOidSequence *os)
00817 {
00818   SECItem *rv;
00819   extern const SEC_ASN1Template CERT_OidSeqTemplate[];
00820 
00821   rv = (SECItem *)PORT_ArenaZAlloc(os->arena, sizeof(SECItem));
00822   if( (SECItem *)NULL == rv ) {
00823     goto loser;
00824   }
00825 
00826   if( !SEC_ASN1EncodeItem(os->arena, rv, os, CERT_OidSeqTemplate) ) {
00827     goto loser;
00828   }
00829 
00830   return rv;
00831 
00832  loser:
00833   return (SECItem *)NULL;
00834 }
00835 
00836 static SECStatus
00837 AddExtKeyUsage(void *extHandle, Pair *data)
00838 {
00839   SECStatus rv;
00840   CERTOidSequence *os;
00841   SECItem *value;
00842   PRBool crit;
00843 
00844   os = CreateOidSequence();
00845   if( (CERTOidSequence *)NULL == os ) {
00846     return SECFailure;
00847   }
00848 
00849   if( find_field_bool(data, "extKeyUsage-serverAuth", PR_TRUE) ) {
00850     rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_SERVER_AUTH);
00851     if( SECSuccess != rv ) goto loser;
00852   }
00853 
00854   if( find_field_bool(data, "extKeyUsage-clientAuth", PR_TRUE) ) {
00855     rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH);
00856     if( SECSuccess != rv ) goto loser;
00857   }
00858 
00859   if( find_field_bool(data, "extKeyUsage-codeSign", PR_TRUE) ) {
00860     rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_CODE_SIGN);
00861     if( SECSuccess != rv ) goto loser;
00862   }
00863 
00864   if( find_field_bool(data, "extKeyUsage-emailProtect", PR_TRUE) ) {
00865     rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT);
00866     if( SECSuccess != rv ) goto loser;
00867   }
00868 
00869   if( find_field_bool(data, "extKeyUsage-timeStamp", PR_TRUE) ) {
00870     rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_TIME_STAMP);
00871     if( SECSuccess != rv ) goto loser;
00872   }
00873 
00874   if( find_field_bool(data, "extKeyUsage-ocspResponder", PR_TRUE) ) {
00875     rv = AddOidToSequence(os, SEC_OID_OCSP_RESPONDER);
00876     if( SECSuccess != rv ) goto loser;
00877   }
00878 
00879   if( find_field_bool(data, "extKeyUsage-NS-govtApproved", PR_TRUE) ) {
00880     rv = AddOidToSequence(os, SEC_OID_NS_KEY_USAGE_GOVT_APPROVED);
00881     if( SECSuccess != rv ) goto loser;
00882   }
00883 
00884   value = EncodeOidSequence(os);
00885 
00886   crit = find_field_bool(data, "extKeyUsage-crit", PR_TRUE);
00887 
00888   rv = CERT_AddExtension(extHandle, SEC_OID_X509_EXT_KEY_USAGE, value,
00889                          crit, PR_TRUE);
00890   /*FALLTHROUGH*/
00891  loser:
00892   CERT_DestroyOidSequence(os);
00893   return rv;
00894 }
00895 
00896 static SECStatus
00897 AddSubKeyID(void             *extHandle, 
00898            Pair             *data, 
00899            CERTCertificate  *subjectCert)
00900 {
00901     SECItem                  encodedValue;
00902     SECStatus                rv;
00903     char                     *read;
00904     char                     *write;
00905     char                     *first;
00906     char                     character;
00907     int                      high_digit = 0,
00908                             low_digit = 0;
00909     int                      len;
00910     PRBool                   odd = PR_FALSE;
00911 
00912 
00913     encodedValue.data = NULL;
00914     encodedValue.len = 0;
00915     first = read = write = find_field(data,"subjectKeyIdentifier-text", 
00916                                   PR_TRUE);
00917     len = PORT_Strlen(first);
00918     odd = ((len % 2) != 0 ) ? PR_TRUE : PR_FALSE;
00919     if (find_field_bool(data, "subjectKeyIdentifier-radio-hex", PR_TRUE)) {
00920        if (odd) {
00921            error_out("ERROR: Improperly formated subject key identifier, hex values must be expressed as an octet string");
00922        }
00923        while (*read != '\0') {
00924            if (!isxdigit(*read)) {
00925               error_out("ERROR: Improperly formated subject key identifier");
00926            }
00927            *read = toupper(*read);
00928            if ((*read >= 'A') && (*read <= 'F')) {
00929               high_digit = *read - 'A' + 10;
00930            }  else {
00931               high_digit = *read - '0';
00932            }
00933            ++read;
00934            if (!isxdigit(*read)) {
00935               error_out("ERROR: Improperly formated subject key identifier");
00936            }
00937            *read = toupper(*read);
00938            if ((*read >= 'A') && (*read <= 'F')) {
00939               low_digit = *(read) - 'A' + 10;
00940            } else {
00941               low_digit = *(read) - '0';
00942            }
00943            character = (high_digit << 4) | low_digit;
00944            *write = character;
00945            ++write;
00946            ++read;
00947        }
00948        *write = '\0';
00949        len = write - first;
00950     }
00951     subjectCert->subjectKeyID.data = (unsigned char *) find_field
00952        (data,"subjectKeyIdentifier-text", PR_TRUE);
00953     subjectCert->subjectKeyID.len = len;
00954     rv = CERT_EncodeSubjectKeyID
00955        (NULL, find_field(data,"subjectKeyIdentifier-text", PR_TRUE),
00956         len, &encodedValue);
00957     if (rv) {
00958        return (rv);
00959     }
00960     return (CERT_AddExtension(extHandle,  SEC_OID_X509_SUBJECT_KEY_ID, 
00961                            &encodedValue, PR_FALSE, PR_TRUE));
00962 }
00963 
00964 
00965 static SECStatus 
00966 AddAuthKeyID (void              *extHandle,
00967              Pair              *data, 
00968              char              *issuerNameStr, 
00969              CERTCertDBHandle  *handle)
00970 {
00971     CERTAuthKeyID               *authKeyID = NULL;    
00972     PRArenaPool                 *arena = NULL;
00973     SECStatus                   rv = SECSuccess;
00974     CERTCertificate             *issuerCert = NULL;
00975     CERTGeneralName             *genNames;
00976     CERTName                    *directoryName = NULL;
00977 
00978 
00979     issuerCert = CERT_FindCertByNameString(handle, issuerNameStr);
00980     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00981     if ( !arena ) {
00982        error_allocate();
00983     }
00984 
00985     authKeyID = PORT_ArenaZAlloc (arena, sizeof (CERTAuthKeyID));
00986     if (authKeyID == NULL) {
00987        error_allocate();
00988     }
00989     if (find_field_bool(data, "authorityKeyIdentifier-radio-keyIdentifier", 
00990                      PR_TRUE)) {
00991        authKeyID->keyID.data = PORT_ArenaAlloc (arena, PORT_Strlen 
00992                                    ((char *)issuerCert->subjectKeyID.data));
00993        if (authKeyID->keyID.data == NULL) {
00994            error_allocate();
00995        }
00996        PORT_Memcpy (authKeyID->keyID.data, issuerCert->subjectKeyID.data, 
00997                    authKeyID->keyID.len = 
00998                       PORT_Strlen((char *)issuerCert->subjectKeyID.data));
00999     } else {
01000        
01001        PORT_Assert (arena);
01002        genNames = (CERTGeneralName *) PORT_ArenaZAlloc (arena, (sizeof(CERTGeneralName)));
01003        if (genNames == NULL){
01004            error_allocate();
01005        }
01006        genNames->l.next = genNames->l.prev = &(genNames->l);
01007        genNames->type = certDirectoryName;
01008 
01009        directoryName = CERT_AsciiToName(issuerCert->subjectName);
01010        if (!directoryName) {
01011            error_out("ERROR: Unable to create Directory Name");
01012        }
01013        rv = CERT_CopyName (arena, &genNames->name.directoryName, 
01014                          directoryName);
01015         CERT_DestroyName (directoryName);
01016        if (rv != SECSuccess) {
01017            error_out("ERROR: Unable to copy Directory Name");
01018        }
01019        authKeyID->authCertIssuer = genNames;
01020        if (authKeyID->authCertIssuer == NULL && SECFailure == 
01021                                                    PORT_GetError ()) {
01022            error_out("ERROR: Unable to get Issuer General Name for Authority Key ID Extension");
01023        }
01024        authKeyID->authCertSerialNumber = issuerCert->serialNumber;
01025     }
01026     rv = EncodeAndAddExtensionValue(arena, extHandle, authKeyID, PR_FALSE, 
01027                                 SEC_OID_X509_AUTH_KEY_ID, 
01028                                 (EXTEN_VALUE_ENCODER)
01029                                 CERT_EncodeAuthKeyID);
01030     if (arena) {
01031        PORT_FreeArena (arena, PR_FALSE);
01032     }
01033     return (rv);
01034 }
01035 
01036 
01037 static SECStatus 
01038 AddPrivKeyUsagePeriod(void             *extHandle, 
01039                     Pair             *data, 
01040                     CERTCertificate  *cert)
01041 {
01042     char *notBeforeStr;
01043     char *notAfterStr;
01044     PRArenaPool *arena = NULL;
01045     SECStatus rv = SECSuccess;
01046     CERTPrivKeyUsagePeriod *pkup;
01047 
01048 
01049     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01050     if ( !arena ) {
01051        error_allocate();
01052     }
01053     pkup = PORT_ArenaZNew (arena, CERTPrivKeyUsagePeriod);
01054     if (pkup == NULL) {
01055        error_allocate();
01056     }
01057     notBeforeStr = (char *) PORT_Alloc(16 );
01058     notAfterStr = (char *) PORT_Alloc(16 );
01059     *notBeforeStr = '\0';
01060     *notAfterStr = '\0';
01061     pkup->arena = arena;
01062     pkup->notBefore.len = 0;
01063     pkup->notBefore.data = NULL;
01064     pkup->notAfter.len = 0;
01065     pkup->notAfter.data = NULL;
01066     if (find_field_bool(data, "privKeyUsagePeriod-radio-notBefore", PR_TRUE) ||
01067        find_field_bool(data, "privKeyUsagePeriod-radio-both", PR_TRUE)) {
01068        pkup->notBefore.len = 15;
01069        pkup->notBefore.data = (unsigned char *)notBeforeStr;
01070        if (find_field_bool(data, "privKeyUsagePeriod-notBefore-radio-manual", 
01071                          PR_TRUE)) {
01072            PORT_Strcat(notBeforeStr,find_field(data,
01073                                       "privKeyUsagePeriod-notBefore-year",
01074                                       PR_TRUE));
01075            PORT_Strcat(notBeforeStr,find_field(data,
01076                                       "privKeyUsagePeriod-notBefore-month",
01077                                       PR_TRUE));
01078            PORT_Strcat(notBeforeStr,find_field(data,
01079                                       "privKeyUsagePeriod-notBefore-day",
01080                                       PR_TRUE));
01081            PORT_Strcat(notBeforeStr,find_field(data,
01082                                       "privKeyUsagePeriod-notBefore-hour",
01083                                       PR_TRUE));
01084            PORT_Strcat(notBeforeStr,find_field(data,
01085                                      "privKeyUsagePeriod-notBefore-minute",
01086                                       PR_TRUE));
01087            PORT_Strcat(notBeforeStr,find_field(data,
01088                                      "privKeyUsagePeriod-notBefore-second",
01089                                       PR_TRUE));
01090            if ((*(notBeforeStr + 14) != '\0') ||
01091               (!isdigit(*(notBeforeStr + 13))) ||
01092               (*(notBeforeStr + 12) >= '5' && *(notBeforeStr + 12) <= '0') ||
01093               (!isdigit(*(notBeforeStr + 11))) ||
01094               (*(notBeforeStr + 10) >= '5' && *(notBeforeStr + 10) <= '0') ||
01095               (!isdigit(*(notBeforeStr + 9))) ||
01096               (*(notBeforeStr + 8) >= '2' && *(notBeforeStr + 8) <= '0') ||
01097               (!isdigit(*(notBeforeStr + 7))) ||
01098               (*(notBeforeStr + 6) >= '3' && *(notBeforeStr + 6) <= '0') ||
01099               (!isdigit(*(notBeforeStr + 5))) ||
01100               (*(notBeforeStr + 4) >= '1' && *(notBeforeStr + 4) <= '0') ||
01101               (!isdigit(*(notBeforeStr + 3))) ||
01102               (!isdigit(*(notBeforeStr + 2))) ||
01103               (!isdigit(*(notBeforeStr + 1))) ||
01104               (!isdigit(*(notBeforeStr + 0))) ||
01105               (*(notBeforeStr + 8) == '2' && *(notBeforeStr + 9) >= '4') ||
01106               (*(notBeforeStr + 6) == '3' && *(notBeforeStr + 7) >= '1') ||
01107               (*(notBeforeStr + 4) == '1' && *(notBeforeStr + 5) >= '2')) {
01108               error_out("ERROR: Improperly formated private key usage period");
01109            }
01110            *(notBeforeStr + 14) = 'Z';
01111            *(notBeforeStr + 15) = '\0';
01112        } else {
01113            if ((*(cert->validity.notBefore.data) > '5') || 
01114               ((*(cert->validity.notBefore.data) == '5') &&
01115                (*(cert->validity.notBefore.data + 1) != '0'))) {
01116               PORT_Strcat(notBeforeStr, "19");
01117            } else {
01118               PORT_Strcat(notBeforeStr, "20");
01119            }
01120            PORT_Strcat(notBeforeStr, (char *)cert->validity.notBefore.data);
01121        }
01122     }
01123     if (find_field_bool(data, "privKeyUsagePeriod-radio-notAfter", PR_TRUE) ||
01124        find_field_bool(data, "privKeyUsagePeriod-radio-both", PR_TRUE)) {
01125        pkup->notAfter.len = 15;
01126        pkup->notAfter.data = (unsigned char *)notAfterStr;
01127        PORT_Strcat(notAfterStr,find_field(data,"privKeyUsagePeriod-notAfter-year", 
01128                                   PR_TRUE));
01129        PORT_Strcat(notAfterStr,find_field(data,"privKeyUsagePeriod-notAfter-month",
01130                                   PR_TRUE));
01131        PORT_Strcat(notAfterStr,find_field(data,"privKeyUsagePeriod-notAfter-day", 
01132                                   PR_TRUE));
01133        PORT_Strcat(notAfterStr,find_field(data,"privKeyUsagePeriod-notAfter-hour", 
01134                                   PR_TRUE));
01135        PORT_Strcat(notAfterStr,find_field(data,"privKeyUsagePeriod-notAfter-minute",
01136                                   PR_TRUE));
01137        PORT_Strcat(notAfterStr,find_field(data,"privKeyUsagePeriod-notAfter-second",
01138                                   PR_TRUE));
01139        if ((*(notAfterStr + 14) != '\0') ||
01140            (!isdigit(*(notAfterStr + 13))) ||
01141            (*(notAfterStr + 12) >= '5' && *(notAfterStr + 12) <= '0') ||
01142            (!isdigit(*(notAfterStr + 11))) ||
01143            (*(notAfterStr + 10) >= '5' && *(notAfterStr + 10) <= '0') ||
01144            (!isdigit(*(notAfterStr + 9))) ||
01145            (*(notAfterStr + 8) >= '2' && *(notAfterStr + 8) <= '0') ||
01146            (!isdigit(*(notAfterStr + 7))) ||
01147            (*(notAfterStr + 6) >= '3' && *(notAfterStr + 6) <= '0') ||
01148            (!isdigit(*(notAfterStr + 5))) ||
01149            (*(notAfterStr + 4) >= '1' && *(notAfterStr + 4) <= '0') ||
01150            (!isdigit(*(notAfterStr + 3))) ||
01151            (!isdigit(*(notAfterStr + 2))) ||
01152            (!isdigit(*(notAfterStr + 1))) ||
01153            (!isdigit(*(notAfterStr + 0))) ||
01154            (*(notAfterStr + 8) == '2' && *(notAfterStr + 9) >= '4') ||
01155            (*(notAfterStr + 6) == '3' && *(notAfterStr + 7) >= '1') ||
01156            (*(notAfterStr + 4) == '1' && *(notAfterStr + 5) >= '2')) {
01157            error_out("ERROR: Improperly formated private key usage period");
01158        }
01159        *(notAfterStr + 14) = 'Z';
01160        *(notAfterStr + 15) = '\0';
01161     }
01162        
01163     PORT_Assert (arena);
01164 
01165     rv = EncodeAndAddExtensionValue(arena, extHandle, pkup, 
01166                                 find_field_bool(data,
01167                                               "privKeyUsagePeriod-crit", 
01168                                               PR_TRUE), 
01169                                 SEC_OID_X509_PRIVATE_KEY_USAGE_PERIOD, 
01170                                 (EXTEN_VALUE_ENCODER)
01171                                 CERT_EncodePrivateKeyUsagePeriod);
01172     if (arena) {
01173        PORT_FreeArena (arena, PR_FALSE);
01174     }
01175     if (notBeforeStr != NULL) {
01176        PORT_Free(notBeforeStr);
01177     }
01178     if (notAfterStr != NULL) {
01179        PORT_Free(notAfterStr);
01180     }
01181     return (rv);
01182 }    
01183 
01184 static SECStatus 
01185 AddBasicConstraint(void   *extHandle, 
01186                  Pair   *data)
01187 {
01188     CERTBasicConstraints  basicConstraint;
01189     SECItem               encodedValue;
01190     SECStatus             rv;
01191 
01192     encodedValue.data = NULL;
01193     encodedValue.len = 0;
01194     basicConstraint.pathLenConstraint = CERT_UNLIMITED_PATH_CONSTRAINT;
01195     basicConstraint.isCA = (find_field_bool(data,"basicConstraints-cA-radio-CA",
01196                                        PR_TRUE));
01197     if (find_field_bool(data,"basicConstraints-pathLengthConstraint", PR_TRUE)){
01198        basicConstraint.pathLenConstraint = atoi 
01199            (find_field(data,"basicConstraints-pathLengthConstraint-text", 
01200                      PR_TRUE));
01201     }
01202     
01203     rv = CERT_EncodeBasicConstraintValue (NULL, &basicConstraint, 
01204                                      &encodedValue);
01205     if (rv)
01206        return (rv);
01207     rv = CERT_AddExtension(extHandle, SEC_OID_X509_BASIC_CONSTRAINTS, 
01208                         &encodedValue, 
01209                         (find_field_bool(data,"basicConstraints-crit", 
01210                                        PR_TRUE)), PR_TRUE);
01211 
01212     PORT_Free (encodedValue.data);
01213     return (rv);
01214 }
01215 
01216 
01217 
01218 static SECStatus 
01219 AddNscpCertType (void  *extHandle, 
01220                Pair  *data)
01221 {
01222     SECItem            bitStringValue;
01223     unsigned char      CertType = 0x0;
01224 
01225     if (find_field_bool(data,"netscape-cert-type-ssl-client", PR_TRUE)){
01226        CertType |= (0x80 >> 0);
01227     }
01228     if (find_field_bool(data,"netscape-cert-type-ssl-server", PR_TRUE)){
01229        CertType |= (0x80 >> 1);
01230     }
01231     if (find_field_bool(data,"netscape-cert-type-smime", PR_TRUE)){
01232        CertType |= (0x80 >> 2);
01233     }
01234     if (find_field_bool(data,"netscape-cert-type-object-signing", PR_TRUE)){
01235        CertType |= (0x80 >> 3);
01236     }
01237     if (find_field_bool(data,"netscape-cert-type-reserved", PR_TRUE)){
01238        CertType |= (0x80 >> 4);
01239     }
01240     if (find_field_bool(data,"netscape-cert-type-ssl-ca", PR_TRUE)) {
01241        CertType |= (0x80 >> 5);
01242     }
01243     if (find_field_bool(data,"netscape-cert-type-smime-ca", PR_TRUE)) {
01244        CertType |= (0x80 >> 6);
01245     }
01246     if (find_field_bool(data,"netscape-cert-type-object-signing-ca", PR_TRUE)) {
01247        CertType |= (0x80 >> 7);
01248     }
01249 
01250     bitStringValue.data = &CertType;
01251     bitStringValue.len = 1;
01252 
01253     return (CERT_EncodeAndAddBitStrExtension
01254            (extHandle, SEC_OID_NS_CERT_EXT_CERT_TYPE, &bitStringValue,
01255             (find_field_bool(data, "netscape-cert-type-crit", PR_TRUE))));
01256 }
01257 
01258 
01259 static SECStatus
01260 add_IA5StringExtension(void    *extHandle, 
01261                      char    *string, 
01262                      PRBool  crit, 
01263                      int     idtag)
01264 {
01265     SECItem                    encodedValue;
01266     SECStatus                  rv;
01267 
01268     encodedValue.data = NULL;
01269     encodedValue.len = 0;
01270 
01271     rv = CERT_EncodeIA5TypeExtension(NULL, string, &encodedValue);
01272     if (rv) {
01273        return (rv);
01274     }
01275     return (CERT_AddExtension(extHandle, idtag, &encodedValue, crit, PR_TRUE));
01276 }
01277 
01278 static SECItem *
01279 string_to_oid(char  *string)
01280 {
01281     int             i;
01282     int             length = 20;
01283     int             remaining;
01284     int             first_value;
01285     int             second_value;
01286     int             value;
01287     int             oidLength;
01288     unsigned char   *oidString;
01289     unsigned char   *write;
01290     unsigned char   *read;
01291     unsigned char   *temp;
01292     SECItem         *oid;
01293     
01294     
01295     remaining = length;
01296     i = 0;
01297     while (*string == ' ') {
01298        string++;
01299     }
01300     while (isdigit(*(string + i))) {
01301        i++;
01302     }
01303     if (*(string + i) == '.') {
01304        *(string + i) = '\0';
01305     } else {
01306        error_out("ERROR: Improperly formated OID");
01307     }
01308     first_value = atoi(string);
01309     if (first_value < 0 || first_value > 2) {
01310        error_out("ERROR: Improperly formated OID");
01311     }
01312     string += i + 1;
01313     i = 0;
01314     while (isdigit(*(string + i))) {
01315        i++;
01316     }
01317     if (*(string + i) == '.') {
01318        *(string + i) = '\0';
01319     } else {
01320        error_out("ERROR: Improperly formated OID");
01321     }
01322     second_value = atoi(string);
01323     if (second_value < 0 || second_value > 39) {
01324        error_out("ERROR: Improperly formated OID");
01325     }
01326     oidString = PORT_ZAlloc(2);
01327     *oidString = (first_value * 40) + second_value;
01328     *(oidString + 1) = '\0';
01329     oidLength = 1;
01330     string += i + 1;
01331     i = 0;
01332     temp = write = PORT_ZAlloc(length);
01333     while (*string != '\0') {
01334        value = 0;
01335        while(isdigit(*(string + i))) {
01336            i++;
01337        }
01338        if (*(string + i) == '\0') {
01339            value = atoi(string);
01340            string += i;
01341        } else {
01342            if (*(string + i) == '.') {
01343               *(string + i) = '\0';
01344               value = atoi(string);
01345               string += i + 1;
01346            } else {
01347               *(string + i) = '\0';
01348               i++;
01349               value = atoi(string);
01350               while (*(string + i) == ' ')
01351                   i++;
01352               if (*(string + i) != '\0') {
01353                   error_out("ERROR: Improperly formated OID");
01354               }
01355            }
01356        }
01357        i = 0;
01358        while (value != 0) {
01359            if (remaining < 1) {
01360               remaining += length;
01361               length = length * 2;
01362               temp = PORT_Realloc(temp, length);
01363               write = temp + length - remaining;
01364            }
01365            *write = (value & 0x7f) | (0x80);
01366            write++;
01367            remaining--;
01368            value = value >> 7;
01369        }
01370        *temp = *temp & (0x7f);
01371        oidLength += write - temp;
01372        oidString = PORT_Realloc(oidString, (oidLength + 1));
01373        read = write - 1;
01374        write = oidLength + oidString - 1;
01375        for (i = 0; i < (length - remaining); i++) {
01376            *write = *read;
01377            write--;
01378            read++;
01379        }
01380        write = temp;
01381        remaining = length;
01382     }
01383     *(oidString + oidLength) = '\0';
01384     oid = (SECItem *) PORT_ZAlloc(sizeof(SECItem));
01385     oid->data = oidString;
01386     oid->len  = oidLength;
01387     PORT_Free(temp);
01388     return oid;
01389 }
01390 
01391 static SECItem *
01392 string_to_ipaddress(char *string)
01393 {
01394     int      i = 0;
01395     int      value;
01396     int      j = 0;
01397     SECItem  *ipaddress;
01398     
01399 
01400     while (*string == ' ') {
01401        string++;
01402     }
01403     ipaddress = (SECItem *) PORT_ZAlloc(sizeof(SECItem));
01404     ipaddress->data = PORT_ZAlloc(9);
01405     while (*string != '\0' && j < 8) {
01406        while (isdigit(*(string + i))) {
01407            i++;
01408        }
01409        if (*(string + i) == '.') {
01410            *(string + i) = '\0';
01411            value = atoi(string);
01412            string = string + i + 1;
01413            i = 0;
01414        } else {
01415            if (*(string + i) == '\0') {
01416               value = atoi(string);
01417               string = string + i;
01418               i = 0;
01419            } else {
01420               *(string + i) = '\0';
01421               while (*(string + i) == ' ') {
01422                   i++;
01423               }
01424               if (*(string + i) == '\0') {
01425                   value = atoi(string);
01426                   string = string + i;
01427                   i = 0;
01428               } else {
01429                   error_out("ERROR: Improperly formated IP Address");
01430               }
01431            }
01432        }
01433        if (value >= 0 || value < 256) {
01434            *(ipaddress->data + j) = value;
01435        } else {
01436            error_out("ERROR: Improperly formated IP Address");
01437        }
01438        j++;
01439     }
01440     *(ipaddress->data + j) = '\0';
01441     if (j != 4 && j != 8) {
01442        error_out("ERROR: Improperly formated IP Address");
01443     }
01444     ipaddress->len = j;
01445     return ipaddress;
01446 }
01447 
01448 static SECItem *
01449 string_to_binary(char  *string)
01450 {
01451     SECItem            *rv;
01452     int                high_digit;
01453     int                low_digit;
01454 
01455     rv = (SECItem *) PORT_ZAlloc(sizeof(SECItem));
01456     if (rv == NULL) {
01457        error_allocate();
01458     }
01459     rv->data = (unsigned char *) PORT_ZAlloc((PORT_Strlen(string))/3 + 2);
01460     while (!isxdigit(*string)) {
01461        string++;
01462     }
01463     rv->len = 0;
01464     while (*string != '\0') {
01465        if (isxdigit(*string)) {
01466            if (*string >= '0' && *string <= '9') {
01467               high_digit = *string - '0';
01468            } else {
01469               *string = toupper(*string);
01470               high_digit = *string - 'A';
01471            }
01472            string++;
01473            if (*string >= '0' && *string <= '9') {
01474               low_digit = *string - '0';
01475            } else {
01476               *string = toupper(*string);
01477               low_digit = *string = 'A';
01478            }
01479            (rv->len)++;
01480        } else {
01481            if (*string == ':') {
01482               string++;
01483            } else {
01484               if (*string == ' ') {
01485                   while (*string == ' ') {
01486                      string++;
01487                   }
01488               }
01489               if (*string != '\0') {
01490                   error_out("ERROR: Improperly formated binary encoding");
01491               }
01492            }
01493        } 
01494     }
01495 
01496     return rv;
01497 }
01498 
01499 static SECStatus
01500 MakeGeneralName(char             *name, 
01501               CERTGeneralName  *genName,
01502               PRArenaPool      *arena)
01503 {
01504     SECItem                      *oid;
01505     SECOidData                   *oidData;
01506     SECItem                      *ipaddress;
01507     SECItem                      *temp = NULL;
01508     int                          i;
01509     int                          nameType;
01510     PRBool                       binary = PR_FALSE;
01511     SECStatus                    rv = SECSuccess;
01512     PRBool                       nickname = PR_FALSE;
01513 
01514     PORT_Assert(genName);
01515     PORT_Assert(arena);
01516     nameType = *(name + PORT_Strlen(name) - 1) - '0';
01517     if (nameType == 0  && *(name +PORT_Strlen(name) - 2) == '1') {
01518        nickname = PR_TRUE;
01519        nameType = certOtherName;
01520     }
01521     if (nameType < 1 || nameType > 9) {
01522        error_out("ERROR: Unknown General Name Type");
01523     }
01524     *(name + PORT_Strlen(name) - 4) = '\0';
01525     genName->type = nameType;
01526     
01527     switch (genName->type) {
01528       case certURI:
01529       case certRFC822Name:
01530       case certDNSName: {
01531          genName->name.other.data = (unsigned char *)name;
01532          genName->name.other.len = PORT_Strlen(name);
01533          break;
01534       }
01535       
01536       case certIPAddress: {
01537          ipaddress = string_to_ipaddress(name);
01538          genName->name.other.data = ipaddress->data;
01539          genName->name.other.len = ipaddress->len;
01540          break;
01541       }
01542       
01543       case certRegisterID: {
01544          oid = string_to_oid(name);
01545          genName->name.other.data = oid->data;
01546          genName->name.other.len = oid->len;
01547          break;
01548       }
01549       
01550       case certEDIPartyName:
01551       case certX400Address: {
01552          
01553          genName->name.other.data = PORT_ArenaAlloc (arena, 
01554                                                 PORT_Strlen (name) + 2);
01555          if (genName->name.other.data == NULL) {
01556              error_allocate();
01557          }
01558          
01559          PORT_Memcpy (genName->name.other.data + 2, name, PORT_Strlen (name));
01560          /* This may not be accurate for all cases.  
01561             For now, use this tag type */
01562          genName->name.other.data[0] = (char)(((genName->type - 1) & 
01563                                           0x1f)| 0x80);
01564          genName->name.other.data[1] = (char)PORT_Strlen (name);
01565          genName->name.other.len = PORT_Strlen (name) + 2;
01566          break;
01567       }
01568       
01569       case certOtherName: {
01570          i = 0;
01571          if (!nickname) {
01572              while (!isdigit(*(name + PORT_Strlen(name) - i))) {
01573                 i++;
01574              }
01575              if (*(name + PORT_Strlen(name) - i) == '1') {
01576                 binary = PR_TRUE;
01577              } else {
01578                 binary = PR_FALSE;
01579              }  
01580              while (*(name + PORT_Strlen(name) - i) != '-') {
01581                 i++;
01582              }
01583              *(name + PORT_Strlen(name) - i - 1) = '\0';
01584              i = 0;
01585              while (*(name + i) != '-') {
01586                 i++;
01587              }
01588              *(name + i - 1) = '\0';
01589              oid = string_to_oid(name + i + 2);
01590          } else {
01591              oidData = SECOID_FindOIDByTag(SEC_OID_NETSCAPE_NICKNAME);
01592              oid = &oidData->oid;
01593              while (*(name + PORT_Strlen(name) - i) != '-') {
01594                 i++;
01595              }
01596              *(name + PORT_Strlen(name) - i) = '\0';
01597          }
01598          genName->name.OthName.oid.data = oid->data;
01599          genName->name.OthName.oid.len  = oid->len;
01600          if (binary) {
01601              temp = string_to_binary(name);
01602              genName->name.OthName.name.data = temp->data;
01603              genName->name.OthName.name.len = temp->len;
01604          } else {
01605              temp = (SECItem *) PORT_ZAlloc(sizeof(SECItem));
01606              if (temp == NULL) {
01607                 error_allocate();
01608              }
01609              temp->data = (unsigned char *)name;
01610              temp->len = PORT_Strlen(name);
01611              SEC_ASN1EncodeItem (arena, &(genName->name.OthName.name), temp,
01612                               CERTIA5TypeTemplate);
01613          }
01614          PORT_Free(temp);
01615          break;
01616       }
01617       
01618       case certDirectoryName: {
01619          CERTName *directoryName = NULL;
01620          
01621          directoryName = CERT_AsciiToName (name);
01622          if (!directoryName) {
01623              error_out("ERROR: Improperly formated alternative name");
01624              break;
01625          }
01626          rv = CERT_CopyName (arena, &genName->name.directoryName, 
01627                            directoryName);
01628          CERT_DestroyName (directoryName);
01629          
01630          break;
01631       }
01632     }
01633     genName->l.next = &(genName->l);
01634     genName->l.prev = &(genName->l);
01635     return rv;
01636 }
01637 
01638 
01639 static CERTGeneralName *
01640 MakeAltName(Pair             *data, 
01641            char             *which, 
01642            PRArenaPool      *arena)
01643 {
01644     CERTGeneralName          *SubAltName;
01645     CERTGeneralName          *current;
01646     CERTGeneralName          *newname;
01647     char                     *name = NULL;
01648     SECStatus                rv = SECSuccess;
01649     int                      len;
01650     
01651 
01652     len = PORT_Strlen(which);
01653     name = find_field(data, which, PR_TRUE);
01654     SubAltName = current = (CERTGeneralName *) PORT_ZAlloc
01655                                                (sizeof(CERTGeneralName));
01656     if (current == NULL) {
01657        error_allocate();
01658     }
01659     while (name != NULL) {
01660 
01661        rv = MakeGeneralName(name, current, arena);
01662 
01663        if (rv != SECSuccess) {
01664            break;
01665        }
01666        if (*(which + len -1) < '9') {
01667            *(which + len - 1) = *(which + len - 1) + 1;
01668        } else {
01669            if (isdigit(*(which + len - 2) )) {
01670               *(which + len - 2) = *(which + len - 2) + 1;
01671               *(which + len - 1) = '0';
01672            } else {
01673               *(which + len - 1) = '1';
01674               *(which + len) = '0';
01675               *(which + len + 1) = '\0';
01676               len++;
01677            }
01678        }
01679        len = PORT_Strlen(which);
01680        name = find_field(data, which, PR_TRUE);
01681        if (name != NULL) {
01682            newname = (CERTGeneralName *) PORT_ZAlloc(sizeof(CERTGeneralName));
01683            if (newname == NULL) {
01684               error_allocate();
01685            }
01686            current->l.next = &(newname->l);
01687            newname->l.prev = &(current->l);
01688            current = newname;
01689             newname = NULL;
01690        } else {
01691            current->l.next = &(SubAltName->l);
01692            SubAltName->l.prev = &(current->l);
01693        }
01694     }
01695     if (rv == SECFailure) {
01696        return NULL;
01697     }
01698     return SubAltName;
01699 }
01700 
01701 static CERTNameConstraints *
01702 MakeNameConstraints(Pair             *data, 
01703                   PRArenaPool      *arena)
01704 {
01705     CERTNameConstraints      *NameConstraints;
01706     CERTNameConstraint       *current = NULL;
01707     CERTNameConstraint       *last_permited = NULL;
01708     CERTNameConstraint       *last_excluded = NULL;
01709     char                     *constraint = NULL;
01710     char                     *which;
01711     SECStatus                rv = SECSuccess;
01712     int                      len;
01713     int                      i;
01714     long                     max;
01715     long                     min;
01716     PRBool                   permited;
01717     
01718 
01719     NameConstraints = (CERTNameConstraints *) PORT_ZAlloc
01720                                    (sizeof(CERTNameConstraints));
01721     which = make_copy_string("NameConstraintSelect0", 25,'\0');
01722     len = PORT_Strlen(which);
01723     constraint = find_field(data, which, PR_TRUE);
01724     NameConstraints->permited = NameConstraints->excluded = NULL;
01725     while (constraint != NULL) {
01726        current = (CERTNameConstraint *) PORT_ZAlloc
01727                               (sizeof(CERTNameConstraint));
01728        if (current == NULL) {
01729            error_allocate();
01730        }
01731        i = 0;
01732        while (*(constraint + PORT_Strlen(constraint) - i) != '-') {
01733            i++;
01734        }
01735         *(constraint + PORT_Strlen(constraint) - i - 1) = '\0'; 
01736        max = (long) atoi(constraint + PORT_Strlen(constraint) + 3);
01737        if (max > 0) {
01738            (void) SEC_ASN1EncodeInteger(arena, &current->max, max);
01739        }
01740        i = 0;
01741        while (*(constraint + PORT_Strlen(constraint) - i) != '-') {
01742            i++;
01743        }
01744         *(constraint + PORT_Strlen(constraint) - i - 1) = '\0';
01745        min = (long) atoi(constraint + PORT_Strlen(constraint) + 3);
01746        (void) SEC_ASN1EncodeInteger(arena, &current->min, min);
01747        while (*(constraint + PORT_Strlen(constraint) - i) != '-') {
01748            i++;
01749        }
01750         *(constraint + PORT_Strlen(constraint) - i - 1) = '\0';
01751        if (*(constraint + PORT_Strlen(constraint) + 3) == 'p') {
01752            permited = PR_TRUE;
01753        } else {
01754            permited = PR_FALSE;
01755        }
01756        rv = MakeGeneralName(constraint, &(current->name), arena);
01757 
01758        if (rv != SECSuccess) {
01759            break;
01760        }
01761        if (*(which + len - 1) < '9') {
01762            *(which + len - 1) = *(which + len - 1) + 1;
01763        } else {
01764            if (isdigit(*(which + len - 2) )) {
01765               *(which + len - 2) = *(which + len - 2) + 1;
01766               *(which + len - 1) = '0';
01767            } else {
01768               *(which + len - 1) = '1';
01769               *(which + len) = '0';
01770               *(which + len + 1) = '\0';
01771               len++;
01772            }
01773        }
01774        len = PORT_Strlen(which);
01775        if (permited) {
01776            if (NameConstraints->permited == NULL) {
01777               NameConstraints->permited = last_permited = current;
01778            }
01779            last_permited->l.next = &(current->l);
01780            current->l.prev = &(last_permited->l);
01781            last_permited = current;
01782        } else {
01783            if (NameConstraints->excluded == NULL) {
01784               NameConstraints->excluded = last_excluded = current;
01785            }
01786            last_excluded->l.next = &(current->l);
01787            current->l.prev = &(last_excluded->l);
01788            last_excluded = current;
01789        }
01790        constraint = find_field(data, which, PR_TRUE);
01791        if (constraint != NULL) {
01792            current = (CERTNameConstraint *) PORT_ZAlloc(sizeof(CERTNameConstraint));
01793            if (current == NULL) {
01794               error_allocate();
01795            }
01796        }
01797     }
01798     if (NameConstraints->permited != NULL) {
01799        last_permited->l.next = &(NameConstraints->permited->l);
01800        NameConstraints->permited->l.prev = &(last_permited->l);
01801     }
01802     if (NameConstraints->excluded != NULL) {
01803        last_excluded->l.next = &(NameConstraints->excluded->l);
01804        NameConstraints->excluded->l.prev = &(last_excluded->l);
01805     }
01806     if (which != NULL) {
01807        PORT_Free(which);
01808     }
01809     if (rv == SECFailure) {
01810        return NULL;
01811     }
01812     return NameConstraints;
01813 }
01814 
01815 
01816 
01817 static SECStatus
01818 AddAltName(void              *extHandle,
01819           Pair              *data,
01820           char              *issuerNameStr, 
01821           CERTCertDBHandle  *handle,
01822           int               type)
01823 {
01824     PRBool             autoIssuer = PR_FALSE;
01825     PRArenaPool        *arena = NULL;
01826     CERTGeneralName    *genName = NULL;
01827     char               *which = NULL;
01828     char               *name = NULL;
01829     SECStatus          rv = SECSuccess;
01830     SECItem            *issuersAltName = NULL;
01831     CERTCertificate    *issuerCert = NULL;
01832 
01833     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01834     if (arena == NULL) {
01835        error_allocate();
01836     }
01837     if (type == 0) {
01838        which = make_copy_string("SubAltNameSelect0", 20,'\0');
01839        genName = MakeAltName(data, which, arena);
01840     } else {
01841        if (autoIssuer) {
01842            autoIssuer = find_field_bool(data,"IssuerAltNameSourceRadio-auto",
01843                                     PR_TRUE);
01844            issuerCert = CERT_FindCertByNameString(handle, issuerNameStr);
01845            rv = cert_FindExtension((*issuerCert).extensions, 
01846                                 SEC_OID_X509_SUBJECT_ALT_NAME, 
01847                                 issuersAltName);
01848            if (issuersAltName == NULL) {
01849               name = PORT_Alloc(PORT_Strlen((*issuerCert).subjectName) + 4);
01850               PORT_Strcpy(name, (*issuerCert).subjectName);
01851               PORT_Strcat(name, " - 5");
01852            }
01853        } else {
01854            which = make_copy_string("IssuerAltNameSelect0", 20,'\0');
01855            genName = MakeAltName(data, which, arena);
01856        }
01857     }
01858     if (type == 0) {
01859        EncodeAndAddExtensionValue(arena, extHandle, genName, 
01860                                find_field_bool(data, "SubAltName-crit", 
01861                                              PR_TRUE), 
01862                                SEC_OID_X509_SUBJECT_ALT_NAME, 
01863                                (EXTEN_VALUE_ENCODER)
01864                                CERT_EncodeAltNameExtension);
01865 
01866     } else {
01867        if (autoIssuer && (name == NULL)) {
01868            rv = CERT_AddExtension
01869               (extHandle, SEC_OID_X509_ISSUER_ALT_NAME, issuersAltName,
01870                find_field_bool(data, "IssuerAltName-crit", PR_TRUE), PR_TRUE);
01871        } else {
01872            EncodeAndAddExtensionValue(arena, extHandle, genName, 
01873                                    find_field_bool(data, 
01874                                                  "IssuerAltName-crit", 
01875                                                  PR_TRUE), 
01876                                    SEC_OID_X509_ISSUER_ALT_NAME, 
01877                                    (EXTEN_VALUE_ENCODER)
01878                                    CERT_EncodeAltNameExtension);
01879        }
01880     }
01881     if (which != NULL) {
01882        PORT_Free(which);
01883     }
01884     if (issuerCert != NULL) {
01885        CERT_DestroyCertificate(issuerCert);
01886     }
01887     return rv;
01888 }
01889 
01890 
01891 static SECStatus
01892 AddNameConstraints(void  *extHandle,
01893                  Pair  *data)
01894 {
01895     PRArenaPool         *arena = NULL;
01896     CERTNameConstraints *constraints = NULL;
01897     SECStatus           rv = SECSuccess;
01898 
01899 
01900     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01901     if (arena == NULL) {
01902        error_allocate();
01903     }
01904     constraints = MakeNameConstraints(data, arena);
01905     if (constraints != NULL) {
01906        EncodeAndAddExtensionValue(arena, extHandle, constraints, PR_TRUE, 
01907                                SEC_OID_X509_NAME_CONSTRAINTS, 
01908                                (EXTEN_VALUE_ENCODER)
01909                                CERT_EncodeNameConstraintsExtension);
01910     }
01911     if (arena != NULL) {
01912        PORT_ArenaRelease (arena, NULL);
01913     }
01914     return rv;
01915 }
01916 
01917 
01918 static SECStatus
01919 add_extensions(CERTCertificate   *subjectCert, 
01920               Pair              *data, 
01921               char              *issuerNameStr, 
01922               CERTCertDBHandle  *handle)
01923 {
01924     void                         *extHandle;
01925     SECStatus                    rv = SECSuccess;
01926 
01927 
01928     extHandle = CERT_StartCertExtensions (subjectCert);
01929     if (extHandle == NULL) {
01930        error_out("ERROR: Unable to get certificates extension handle");
01931     }
01932     if (find_field_bool(data, "keyUsage", PR_TRUE)) {
01933        rv = AddKeyUsage(extHandle, data);
01934        if (rv != SECSuccess) {
01935            error_out("ERROR: Unable to add Key Usage extension");
01936        }
01937     }
01938 
01939     if( find_field_bool(data, "extKeyUsage", PR_TRUE) ) {
01940       rv = AddExtKeyUsage(extHandle, data);
01941       if( SECSuccess != rv ) {
01942         error_out("ERROR: Unable to add Extended Key Usage extension");
01943       }
01944     }
01945 
01946     if (find_field_bool(data, "basicConstraints", PR_TRUE)) {
01947        rv = AddBasicConstraint(extHandle, data);
01948        if (rv != SECSuccess) {
01949            error_out("ERROR: Unable to add Basic Constraint extension");
01950        }
01951     }
01952     if (find_field_bool(data, "subjectKeyIdentifier", PR_TRUE)) {
01953        rv = AddSubKeyID(extHandle, data, subjectCert);
01954        if (rv != SECSuccess) {
01955            error_out("ERROR: Unable to add Subject Key Identifier Extension");
01956        }
01957     }
01958     if (find_field_bool(data, "authorityKeyIdentifier", PR_TRUE)) {
01959        rv = AddAuthKeyID (extHandle, data, issuerNameStr, handle);
01960        if (rv != SECSuccess) {
01961            error_out("ERROR: Unable to add Authority Key Identifier extension");
01962        }
01963     }
01964     if (find_field_bool(data, "privKeyUsagePeriod", PR_TRUE)) {
01965        rv = AddPrivKeyUsagePeriod (extHandle, data, subjectCert);
01966        if (rv != SECSuccess) {
01967            error_out("ERROR: Unable to add Private Key Usage Period extension");
01968        }
01969     }
01970     if (find_field_bool(data, "SubAltName", PR_TRUE)) {
01971        rv = AddAltName (extHandle, data, NULL, NULL, 0);
01972        if (rv != SECSuccess) {
01973            error_out("ERROR: Unable to add Subject Alternative Name extension");
01974        }
01975     }
01976     if (find_field_bool(data, "IssuerAltName", PR_TRUE)) {
01977        rv = AddAltName (extHandle, data, issuerNameStr, handle, 1);
01978        if (rv != SECSuccess) {
01979            error_out("ERROR: Unable to add Issuer Alternative Name Extension");
01980        }
01981     }
01982     if (find_field_bool(data, "NameConstraints", PR_TRUE)) {
01983        rv = AddNameConstraints(extHandle, data);
01984        if (rv != SECSuccess) {
01985            error_out("ERROR: Unable to add Name Constraints Extension");
01986        }
01987     }
01988     if (find_field_bool(data, "netscape-cert-type", PR_TRUE)) {
01989        rv = AddNscpCertType(extHandle, data);
01990        if (rv != SECSuccess) {
01991            error_out("ERROR: Unable to add Netscape Certificate Type Extension");
01992        }
01993     }
01994     if (find_field_bool(data, "netscape-base-url", PR_TRUE)) {
01995        rv = add_IA5StringExtension(extHandle, 
01996                                 find_field(data, "netscape-base-url-text", 
01997                                           PR_TRUE), 
01998                                 find_field_bool(data, 
01999                                               "netscape-base-url-crit", 
02000                                               PR_TRUE),
02001                                 SEC_OID_NS_CERT_EXT_BASE_URL);
02002        if (rv != SECSuccess) {
02003            error_out("ERROR: Unable to add Netscape Base URL Extension");
02004        }
02005     }
02006     if (find_field_bool(data, "netscape-revocation-url", PR_TRUE)) {
02007        rv = add_IA5StringExtension(extHandle, 
02008                                 find_field(data, 
02009                                           "netscape-revocation-url-text", 
02010                                           PR_TRUE), 
02011                                 find_field_bool
02012                                    (data, "netscape-revocation-url-crit", 
02013                                    PR_TRUE),
02014                                 SEC_OID_NS_CERT_EXT_REVOCATION_URL);
02015        if (rv != SECSuccess) {
02016            error_out("ERROR: Unable to add Netscape Revocation URL Extension");
02017        }
02018     }
02019     if (find_field_bool(data, "netscape-ca-revocation-url", PR_TRUE)) {
02020        rv = add_IA5StringExtension(extHandle, 
02021                                 find_field(data, 
02022                                          "netscape-ca-revocation-url-text",
02023                                           PR_TRUE), 
02024                                 find_field_bool
02025                                     (data, "netscape-ca-revocation-url-crit"
02026                                     , PR_TRUE),
02027                                 SEC_OID_NS_CERT_EXT_CA_REVOCATION_URL);
02028        if (rv != SECSuccess) {
02029            error_out("ERROR: Unable to add Netscape CA Revocation URL Extension");
02030        }
02031     }
02032     if (find_field_bool(data, "netscape-cert-renewal-url", PR_TRUE)) {
02033        rv = add_IA5StringExtension(extHandle, 
02034                                 find_field(data, 
02035                                           "netscape-cert-renewal-url-text",
02036                                           PR_TRUE), 
02037                                 find_field_bool
02038                                     (data, "netscape-cert-renewal-url-crit",
02039                                     PR_TRUE),
02040                                 SEC_OID_NS_CERT_EXT_CERT_RENEWAL_URL);
02041        if (rv != SECSuccess) {
02042            error_out("ERROR: Unable to add Netscape Certificate Renewal URL Extension");
02043        }
02044     }
02045     if (find_field_bool(data, "netscape-ca-policy-url", PR_TRUE)) {
02046        rv = add_IA5StringExtension(extHandle, 
02047                                 find_field(data, 
02048                                           "netscape-ca-policy-url-text", 
02049                                           PR_TRUE), 
02050                                 find_field_bool
02051                                      (data, "netscape-ca-policy-url-crit", 
02052                                      PR_TRUE),
02053                                 SEC_OID_NS_CERT_EXT_CA_POLICY_URL);
02054        if (rv != SECSuccess) {
02055            error_out("ERROR: Unable to add Netscape CA Policy URL Extension");
02056        }
02057     }
02058     if (find_field_bool(data, "netscape-ssl-server-name", PR_TRUE)) {
02059        rv = add_IA5StringExtension(extHandle, 
02060                                 find_field(data, 
02061                                           "netscape-ssl-server-name-text", 
02062                                           PR_TRUE), 
02063                                 find_field_bool
02064                                      (data, "netscape-ssl-server-name-crit",
02065                                      PR_TRUE),
02066                                 SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME);
02067        if (rv != SECSuccess) {
02068            error_out("ERROR: Unable to add Netscape SSL Server Name Extension");
02069        }
02070     }
02071     if (find_field_bool(data, "netscape-comment", PR_TRUE)) {
02072        rv = add_IA5StringExtension(extHandle, 
02073                                 find_field(data, "netscape-comment-text", 
02074                                           PR_TRUE), 
02075                                 find_field_bool(data, 
02076                                               "netscape-comment-crit", 
02077                                               PR_TRUE),
02078                                 SEC_OID_NS_CERT_EXT_COMMENT);
02079        if (rv != SECSuccess) {
02080            error_out("ERROR: Unable to add Netscape Comment Extension");
02081        }
02082     }
02083     CERT_FinishExtensions(extHandle);
02084     return (rv);
02085 }
02086 
02087 
02088 
02089 char *
02090 return_dbpasswd(PK11SlotInfo *slot, PRBool retry, void *data)
02091 {
02092     char *rv;
02093 
02094     /* don't clobber our poor smart card */
02095     if (retry == PR_TRUE) {
02096        return NULL;
02097     }
02098     rv = PORT_Alloc(4);
02099     PORT_Strcpy(rv, "foo");
02100     return rv;
02101 }
02102 
02103 
02104 SECKEYPrivateKey *
02105 FindPrivateKeyFromNameStr(char              *name, 
02106                        CERTCertDBHandle  *certHandle)
02107 {
02108     SECKEYPrivateKey                        *key;
02109     CERTCertificate                         *cert;
02110     CERTCertificate                         *p11Cert;
02111 
02112 
02113     /* We don't presently have a PK11 function to find a cert by 
02114     ** subject name.  
02115     ** We do have a function to find a cert in the internal slot's
02116     ** cert db by subject name, but it doesn't setup the slot info.
02117     ** So, this HACK works, but should be replaced as soon as we 
02118     ** have a function to search for certs accross slots by subject name.
02119     */
02120     cert = CERT_FindCertByNameString(certHandle, name);
02121     if (cert == NULL || cert->nickname == NULL) {
02122        error_out("ERROR: Unable to retrieve issuers certificate");
02123     }
02124     p11Cert = PK11_FindCertFromNickname(cert->nickname, NULL);
02125     if (p11Cert == NULL) {
02126        error_out("ERROR: Unable to retrieve issuers certificate");
02127     }
02128     key = PK11_FindKeyByAnyCert(p11Cert, NULL);
02129     return key;
02130 }
02131 
02132 static SECItem *
02133 SignCert(CERTCertificate   *cert,
02134         char              *issuerNameStr,
02135         Pair              *data,
02136         CERTCertDBHandle  *handle,
02137          int               which_key)
02138 {
02139     SECItem                der;
02140     SECKEYPrivateKey       *caPrivateKey = NULL;
02141     SECStatus              rv;
02142     PRArenaPool            *arena;
02143     SECOidTag              algID;
02144 
02145     if (which_key == 0) {
02146        caPrivateKey = FindPrivateKeyFromNameStr(issuerNameStr, handle); 
02147     } else {
02148        caPrivateKey = privkeys[which_key - 1];
02149     }
02150     if (caPrivateKey == NULL) {
02151        error_out("ERROR: unable to retrieve issuers key");
02152     }
02153        
02154     arena = cert->arena;
02155 
02156     switch(caPrivateKey->keyType) {
02157       case rsaKey:
02158        algID = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION;
02159        break;
02160       case dsaKey:
02161        algID = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST;
02162        break;
02163       default:
02164        error_out("ERROR: Unknown key type for issuer.");
02165        goto done;
02166        break;
02167     }
02168 
02169     rv = SECOID_SetAlgorithmID(arena, &cert->signature, algID, 0);
02170     if (rv != SECSuccess) {
02171        error_out("ERROR: Could not set signature algorithm id.");
02172     }
02173 
02174     if (find_field_bool(data,"ver-1", PR_TRUE)) {
02175        *(cert->version.data) = 0;
02176        cert->version.len = 1;
02177     } else {
02178        *(cert->version.data) = 2;
02179        cert->version.len = 1;
02180     }
02181     der.data = NULL;
02182     der.len = 0;
02183     (void) SEC_ASN1EncodeItem (arena, &der, cert, CERT_CertificateTemplate);
02184     if (der.data == NULL) {
02185        error_out("ERROR: Could not encode certificate.\n");
02186     }
02187     rv = SEC_DerSignData (arena, &(cert->derCert), der.data, der.len, caPrivateKey,
02188                        algID);
02189     if (rv != SECSuccess) {
02190        error_out("ERROR: Could not sign encoded certificate data.\n");
02191     }
02192 done:
02193     SECKEY_DestroyPrivateKey(caPrivateKey);
02194     return &(cert->derCert);
02195 }
02196 
02197 
02198 int
02199 main(int argc, char **argv)
02200 {
02201     int                    length = 500;
02202     int                    remaining = 500;
02203     int                    n;
02204     int                    i;
02205     int                    serial;
02206     int                    chainLen;
02207     int                    which_key;
02208     char                   *pos;
02209 #ifdef OFFLINE
02210     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";
02211 #else
02212     char                   *form_output;
02213 #endif
02214     char                   *issuerNameStr;
02215     char                   *certName;
02216     char                   *DBdir = DB_DIRECTORY;
02217     char                   *prefixs[10] = {"CA#1-", "CA#2-", "CA#3-", 
02218                                       "CA#4-", "CA#5-", "CA#6-", 
02219                                       "CA#7-", "CA#8-", "CA#9-", ""};
02220     Pair                   *form_data;
02221     CERTCertificate        *cert;
02222     CERTCertDBHandle       *handle;
02223     CERTCertificateRequest *certReq = NULL;
02224     int                    warpmonths = 0;
02225     SECItem                *certDER;
02226 #ifdef FILEOUT
02227     FILE                   *outfile;
02228 #endif
02229     SECStatus              status = SECSuccess;
02230     extern                 char prefix[PREFIX_LEN];
02231     SEC_PKCS7ContentInfo   *certChain;
02232     SECItem                *encodedCertChain;
02233     PRBool                 UChain = PR_FALSE;
02234 
02235 
02236     progName = strrchr(argv[0], '/');
02237     progName = progName ? progName+1 : argv[0];
02238 
02239 
02240 #ifdef TEST
02241     sleep(20);
02242 #endif
02243     SECU_ConfigDirectory(DBdir);
02244 
02245     PK11_SetPasswordFunc(return_dbpasswd);
02246     status = NSS_InitReadWrite(DBdir);
02247     if (status != SECSuccess) {
02248        SECU_PrintPRandOSError(progName);
02249        return -1;
02250     }
02251     handle = CERT_GetDefaultCertDB();
02252 
02253     prefix[0]= '\0';
02254 #if !defined(OFFLINE)
02255     form_output = (char*) PORT_Alloc(length);
02256     if (form_output == NULL) {
02257        error_allocate();
02258     }
02259     pos = form_output;
02260     while (feof(stdin) == 0 ) {
02261        if (remaining <= 1) {
02262            remaining += length;
02263            length = length * 2;
02264            form_output = PORT_Realloc(form_output, (length));
02265            if (form_output == NULL) {
02266               error_allocate();
02267            }
02268            pos = form_output + length - remaining;
02269        }
02270        n = fread(pos, 1, (size_t) (remaining - 1), stdin);
02271        pos += n;
02272        remaining -= n;
02273     }
02274     *pos = '&';
02275     pos++;
02276     length = pos - form_output;
02277 #else
02278     length = PORT_Strlen(form_output);
02279 #endif
02280 #ifdef FILEOUT
02281     printf("Content-type: text/plain\n\n");
02282     fwrite(form_output, 1, (size_t)length, stdout);
02283     printf("\n");
02284 #endif
02285 #ifdef FILEOUT
02286     fwrite(form_output, 1, (size_t)length, stdout);
02287     printf("\n");
02288     fflush(stdout);
02289 #endif
02290     form_data = make_datastruct(form_output, length);
02291     status = clean_input(form_data);
02292 #if !defined(OFFLINE)
02293     PORT_Free(form_output);
02294 #endif
02295 #ifdef FILEOUT
02296     i = 0;
02297     while(return_name(form_data, i) != NULL) {
02298         printf("%s",return_name(form_data,i));
02299         printf("=\n");
02300         printf("%s",return_data(form_data,i));
02301         printf("\n");
02302        i++;
02303     }
02304     printf("I got that done, woo hoo\n");
02305     fflush(stdout);
02306 #endif
02307     issuerNameStr = PORT_Alloc(200);
02308     if (find_field_bool(form_data, "caChoiceradio-SignWithSpecifiedChain",
02309                      PR_FALSE)) {
02310        UChain = PR_TRUE;
02311        chainLen = atoi(find_field(form_data, "manCAs", PR_FALSE));
02312        PORT_Strcpy(prefix, prefixs[0]);
02313        issuerNameStr = PORT_Strcpy(issuerNameStr,
02314                             "CN=Cert-O-Matic II, O=Cert-O-Matic II");
02315        if (chainLen == 0) {
02316            UChain =  PR_FALSE;
02317        }
02318     } else {
02319        if (find_field_bool(form_data, "caChoiceradio-SignWithRandomChain", 
02320                          PR_FALSE)) {
02321            PORT_Strcpy(prefix,prefixs[9]);
02322            chainLen = atoi(find_field(form_data, "autoCAs", PR_FALSE));
02323            if (chainLen < 1 || chainLen > 18) {
02324               issuerNameStr = PORT_Strcpy(issuerNameStr, 
02325                                    "CN=CA18, O=Cert-O-Matic II");
02326            }
02327            issuerNameStr = PORT_Strcpy(issuerNameStr, "CN=CA");
02328            issuerNameStr = PORT_Strcat(issuerNameStr, 
02329                                find_field(form_data,"autoCAs", PR_FALSE));
02330            issuerNameStr = PORT_Strcat(issuerNameStr,", O=Cert-O-Matic II");
02331        } else {
02332            issuerNameStr = PORT_Strcpy(issuerNameStr, 
02333                                "CN=Cert-O-Matic II, O=Cert-O-Matic II");
02334        }
02335        chainLen = 0;
02336     }
02337 
02338     i = -1;
02339     which_key = 0;
02340     do {
02341        extern SECStatus cert_GetKeyID(CERTCertificate *cert);
02342        i++;
02343        if (i != 0 && UChain) {
02344            PORT_Strcpy(prefix, prefixs[i]);
02345        }
02346        /*        find_field(form_data,"subject", PR_TRUE); */
02347        certReq = makeCertReq(form_data, which_key);
02348 #ifdef OFFLINE
02349        serial = 900;
02350 #else
02351        serial = get_serial_number(form_data);
02352 #endif
02353        cert = MakeV1Cert(handle, certReq, issuerNameStr, PR_FALSE, 
02354                        serial, warpmonths, form_data);
02355        if (certReq != NULL) {
02356            CERT_DestroyCertificateRequest(certReq);
02357        }
02358        if (find_field_bool(form_data,"ver-3", PR_TRUE)) {
02359            status = add_extensions(cert, form_data, issuerNameStr, handle);
02360            if (status != SECSuccess) {
02361               error_out("ERROR: Unable to add extensions");
02362            }
02363        }
02364        status = cert_GetKeyID(cert);
02365        if (status == SECFailure) {
02366            error_out("ERROR: Unable to get Key ID.");
02367        }
02368        certDER = SignCert(cert, issuerNameStr, form_data, handle, which_key);
02369        CERT_NewTempCertificate(handle, certDER, NULL, PR_FALSE, PR_TRUE);
02370        issuerNameStr = find_field(form_data, "subject", PR_TRUE);
02371        /*        SECITEM_FreeItem(certDER, PR_TRUE); */
02372        CERT_DestroyCertificate(cert);
02373        if (i == (chainLen - 1)) {
02374            i = 8;
02375        }
02376        ++which_key;
02377     } while (i < 9 && UChain);
02378 
02379 
02380 
02381 #ifdef FILEOUT
02382     outfile = fopen("../certout", "wb");
02383 #endif
02384     certName = find_field(form_data, "subject", PR_FALSE);
02385     cert = CERT_FindCertByNameString(handle, certName);
02386     certChain = SEC_PKCS7CreateCertsOnly (cert, PR_TRUE, handle);
02387     if (certChain == NULL) {
02388        error_out("ERROR: No certificates in cert chain");
02389     }
02390     encodedCertChain = SEC_PKCS7EncodeItem (NULL, NULL, certChain, NULL, NULL, 
02391                                        NULL);
02392     if (encodedCertChain) {
02393 #if !defined(FILEOUT)
02394        printf("Content-type: application/x-x509-user-cert\r\n");
02395        printf("Content-length: %d\r\n\r\n", encodedCertChain->len);
02396        fwrite (encodedCertChain->data, 1, encodedCertChain->len, stdout);
02397 #else
02398        fwrite (encodedCertChain->data, 1, encodedCertChain->len, outfile);
02399 #endif
02400 
02401     } else {
02402        error_out("Error: Unable to DER encode certificate");
02403     }
02404 #ifdef FILEOUT
02405     printf("\nI got here!\n");
02406     fflush(outfile);
02407     fclose(outfile);
02408 #endif
02409     fflush(stdout);
02410     if (NSS_Shutdown() != SECSuccess) {
02411         exit(1);
02412     }
02413     return 0;
02414 }
02415