Back to index

lightning-sunbird  0.9+nobinonly
shlibsign.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 /*
00038  * Test program for SDR (Secret Decoder Ring) functions.
00039  *
00040  * $Id: shlibsign.c,v 1.14 2005/11/15 00:34:39 julien.pierre.bugs%sun.com Exp $
00041  */
00042 
00043 #ifdef XP_UNIX
00044 #define USES_LINKS 1
00045 #endif
00046 
00047 #include "nspr.h"
00048 #include <stdio.h>
00049 #include "nss.h"
00050 #include "secutil.h"
00051 #include "cert.h"
00052 #include "pk11func.h"
00053 
00054 #include "plgetopt.h"
00055 #include "pk11sdr.h"
00056 #include "shsign.h"
00057 #include "pk11pqg.h"
00058 
00059 #ifdef USES_LINKS
00060 #include <unistd.h>
00061 #include <sys/param.h>
00062 #include <sys/types.h>
00063 #include <sys/stat.h>
00064 #endif
00065 
00066 static void
00067 usage (char *program_name)
00068 {
00069     PRFileDesc *pr_stderr;
00070 
00071     pr_stderr = PR_STDERR;
00072     PR_fprintf (pr_stderr, "Usage:");
00073     PR_fprintf (pr_stderr, "%s [-v] -i shared_library_name\n", program_name);
00074 }
00075 
00076 static char *
00077 mkoutput(const char *input)
00078 {
00079     int in_len = PORT_Strlen(input);
00080     char *output = PORT_Alloc(in_len+sizeof(SGN_SUFFIX));
00081     int index = in_len + 1 - sizeof("."SHLIB_SUFFIX);
00082 
00083     if ((index > 0) && 
00084        (PORT_Strncmp(&input[index],
00085                      "."SHLIB_SUFFIX,sizeof("."SHLIB_SUFFIX)) == 0)) {
00086        in_len = index;
00087     }
00088     PORT_Memcpy(output,input,in_len);
00089     PORT_Memcpy(&output[in_len],SGN_SUFFIX,sizeof(SGN_SUFFIX));
00090     return output;
00091 }
00092 
00093 
00094 static void
00095 lperror(const char *string)
00096 {
00097      int errNum = PORT_GetError();
00098      const char *error = SECU_Strerror(errNum);
00099      fprintf(stderr,"%s: %s\n",string, error);
00100 }
00101 
00102 static void
00103 encodeInt(unsigned char *buf, int val)
00104 {
00105     buf[3] = (val >> 0) & 0xff;
00106     buf[2] = (val >>  8) & 0xff;
00107     buf[1] = (val >> 16) & 0xff;
00108     buf[0] = (val >> 24) & 0xff;
00109     return;
00110 }
00111 
00112 static SECStatus 
00113 writeItem(PRFileDesc *fd, SECItem *item, char *file)
00114 {
00115     unsigned char buf[4];
00116     int bytesWritten;
00117 
00118     encodeInt(buf,item->len);
00119     bytesWritten = PR_Write(fd,buf, 4);
00120     if (bytesWritten != 4) {
00121        lperror(file);
00122        return SECFailure;
00123     }
00124     bytesWritten = PR_Write(fd, item->data, item->len);
00125     if (bytesWritten != item->len) {
00126        lperror(file);
00127        return SECFailure;
00128     }
00129     return SECSuccess;
00130 }
00131 
00132 
00133 int
00134 main (int argc, char **argv)
00135 {
00136     int               retval = 1;  /* 0 - test succeeded.  1 - test failed */
00137     SECStatus  rv;
00138     PLOptState       *optstate;
00139     char      *program_name;
00140     const char  *input_file = NULL;       /* read encrypted data from here (or create) */
00141     char  *output_file = NULL;     /* write new encrypted data here */
00142     PRBool      verbose = PR_FALSE;
00143     SECKEYPrivateKey *privk = NULL;
00144     SECKEYPublicKey *pubk = NULL;
00145     PK11SlotInfo *slot = NULL;
00146     PRFileDesc *fd;
00147     int bytesRead;
00148     int bytesWritten;
00149     unsigned char file_buf[512];
00150     unsigned char hash_buf[SHA1_LENGTH];
00151     unsigned char sign_buf[40]; /* DSA_LENGTH */
00152     SECItem hash,sign;
00153     PK11Context *hashcx = NULL;
00154     int ks, count=0;
00155     int keySize = 1024;
00156     PQGParams *pqgParams = NULL;
00157     PQGVerify *pqgVerify = NULL;
00158     char* nssDir = NULL;
00159 #ifdef USES_LINKS
00160     int ret;
00161     struct stat stat_buf;
00162     char link_buf[MAXPATHLEN+1];
00163     char *link_file = NULL;
00164 #endif
00165 
00166     hash.len = sizeof(hash_buf); hash.data = hash_buf;
00167     sign.len = sizeof(sign_buf); sign.data = sign_buf;
00168 
00169     program_name = PL_strrchr(argv[0], '/');
00170     program_name = program_name ? (program_name + 1) : argv[0];
00171 
00172     optstate = PL_CreateOptState (argc, argv, "d:i:o:v");
00173     if (optstate == NULL) {
00174        SECU_PrintError (program_name, "PL_CreateOptState failed");
00175        return 1;
00176     }
00177 
00178     while (PL_GetNextOpt (optstate) == PL_OPT_OK) {
00179        switch (optstate->option) {
00180 #ifdef notdef
00181          case '?':
00182            short_usage (program_name);
00183            return 0;
00184 
00185          case 'H':
00186            long_usage (program_name);
00187            return 0;
00188 #endif
00189 
00190          case 'd':
00191            nssDir = optstate->value;
00192            break;
00193 
00194           case 'i':
00195             input_file = optstate->value;
00196             break;
00197 
00198           case 'o':
00199             output_file = PORT_Strdup(optstate->value);
00200             break;
00201 
00202           case 'v':
00203             verbose = PR_TRUE;
00204             break;
00205        }
00206     }
00207 
00208     if (input_file == NULL) {
00209        usage(program_name);
00210        return 1;
00211     }
00212 
00213     /*
00214      * Initialize the Security libraries.
00215      */
00216     PK11_SetPasswordFunc(SECU_GetModulePassword);
00217 
00218     if (nssDir) {
00219         rv = NSS_Init(nssDir);
00220         if (rv != SECSuccess) {
00221             rv = NSS_NoDB_Init("");
00222         }
00223     } else {
00224         rv = NSS_NoDB_Init("");
00225     }
00226     
00227     if (rv != SECSuccess) {
00228        lperror("NSS_Init failed");
00229        goto prdone;
00230     }
00231     
00232     /* Generate a DSA Key pair */
00233     slot = PK11_GetBestSlot(CKM_DSA,NULL);
00234     if (slot == NULL) {
00235        lperror("CKM_DSA");
00236        goto loser;
00237        
00238     }
00239     printf("Generating DSA Key Pair...."); fflush(stdout);
00240     ks = PQG_PBITS_TO_INDEX(keySize);
00241     rv = PK11_PQG_ParamGen(ks,&pqgParams, &pqgVerify);
00242     if (rv != SECSuccess) {
00243        lperror("Generating PQG Params");
00244        goto loser;
00245     }
00246     privk = PK11_GenerateKeyPair(slot, CKM_DSA_KEY_PAIR_GEN, pqgParams, &pubk, 
00247                                           PR_FALSE, PR_TRUE, NULL);
00248     if (privk == NULL) {
00249        lperror("Generating DSA Key");
00250        goto loser;
00251     }
00252 
00253     printf("done\n");
00254 
00255     /* open the shared library */
00256     fd = PR_OpenFile(input_file,PR_RDONLY,0);
00257     if (fd == NULL ) {
00258        lperror(input_file);
00259        goto loser;
00260     }
00261 #ifdef USES_LINKS
00262     ret = lstat(input_file, &stat_buf);
00263     if (ret < 0) {
00264        perror(input_file);
00265        goto loser;
00266     }
00267     if (S_ISLNK(stat_buf.st_mode)) {
00268        char *dirpath,*dirend;
00269        ret = readlink(input_file, link_buf, sizeof(link_buf) - 1);
00270        if (ret < 0) {
00271           perror(input_file);
00272           goto loser;
00273        }
00274        link_buf[ret] = 0;
00275        link_file = mkoutput(input_file);
00276        /* get the dirname of input_file */
00277        dirpath = PORT_Strdup(input_file);
00278        dirend = PORT_Strrchr(dirpath, '/');
00279        if (dirend) {
00280            *dirend = '\0';
00281            ret = chdir(dirpath);
00282            if (ret < 0) {
00283               perror(dirpath);
00284               goto loser;
00285            }
00286        }
00287        PORT_Free(dirpath);
00288        input_file = link_buf;
00289        /* get the basename of link_file */
00290        dirend = PORT_Strrchr(link_file, '/');
00291        if (dirend) {
00292            link_file = dirend + 1;
00293        }
00294     }
00295 #endif
00296     if (output_file == NULL) {
00297        output_file = mkoutput(input_file);
00298     }
00299 
00300     hashcx = PK11_CreateDigestContext(SEC_OID_SHA1);
00301     if (hashcx == NULL) {
00302        lperror("SHA1 Digest Create");
00303        goto loser;
00304     }
00305 
00306     /* hash the file */
00307     while ((bytesRead = PR_Read(fd,file_buf,sizeof(file_buf))) > 0) {
00308        PK11_DigestOp(hashcx,file_buf,bytesRead);
00309        count += bytesRead;
00310     }
00311 
00312     PR_Close(fd);
00313     fd = NULL;
00314     if (bytesRead < 0) {
00315        lperror(input_file);
00316        goto loser;
00317     }
00318 
00319 
00320     PK11_DigestFinal(hashcx, hash.data, &hash.len, hash.len);
00321 
00322     if (hash.len != SHA1_LENGTH) {
00323        fprintf(stderr, "Digest length was not correct\n");
00324        goto loser;
00325     }
00326 
00327     /* signe the hash */
00328     rv = PK11_Sign(privk,&sign,&hash);
00329     if (rv != SECSuccess) {
00330        lperror("Signing");
00331        goto loser;
00332     }
00333 
00334     if (verbose) {
00335        int i,j;
00336        fprintf(stderr,"Library File: %s %d bytes\n",input_file, count);
00337        fprintf(stderr,"Check File: %s\n",output_file);
00338 #ifdef USES_LINKS
00339        if (link_file) {
00340            fprintf(stderr,"Link: %s\n",link_file);
00341        }
00342 #endif
00343        fprintf(stderr,"  hash: %d bytes\n", hash.len);
00344 #define STEP 10
00345        for (i=0; i < hash.len; i += STEP) {
00346           fprintf(stderr,"   ");
00347           for (j=0; j < STEP && (i+j) < hash.len; j++) {
00348               fprintf(stderr," %02x", hash.data[i+j]);
00349           }
00350           fprintf(stderr,"\n");
00351        }
00352        fprintf(stderr,"  signature: %d bytes\n", sign.len);
00353        for (i=0; i < sign.len; i += STEP) {
00354           fprintf(stderr,"   ");
00355           for (j=0; j < STEP && (i+j) < sign.len; j++) {
00356               fprintf(stderr," %02x", sign.data[i+j]);
00357           }
00358           fprintf(stderr,"\n");
00359        }
00360     }
00361 
00362     /* open the target signature file */
00363     fd = PR_OpenFile(output_file,PR_WRONLY|PR_CREATE_FILE|PR_TRUNCATE,0666);
00364     if (fd == NULL ) {
00365        lperror(output_file);
00366        goto loser;
00367     }
00368 
00369     /*
00370      * we write the key out in a straight binary format because very
00371      * low level libraries need to read an parse this file. Ideally we should
00372      * just derEncode the public key (which would be pretty simple, and be
00373      * more general), but then we'd need to link the ASN.1 decoder with the
00374      * freebl libraries.
00375      */
00376 
00377     file_buf[0] = NSS_SIGN_CHK_MAGIC1;
00378     file_buf[1] = NSS_SIGN_CHK_MAGIC2;
00379     file_buf[2] = NSS_SIGN_CHK_MAJOR_VERSION;
00380     file_buf[3] = NSS_SIGN_CHK_MINOR_VERSION;
00381     encodeInt(&file_buf[4],12);                  /* offset to data start */
00382     encodeInt(&file_buf[8],CKK_DSA);
00383     bytesWritten = PR_Write(fd,file_buf, 12);
00384     if (bytesWritten != 12) {
00385        lperror(output_file);
00386        goto loser;
00387     }
00388 
00389     rv = writeItem(fd,&pubk->u.dsa.params.prime,output_file);
00390     if (rv != SECSuccess) goto loser;
00391     rv = writeItem(fd,&pubk->u.dsa.params.subPrime,output_file);
00392     if (rv != SECSuccess) goto loser;
00393     rv = writeItem(fd,&pubk->u.dsa.params.base,output_file);
00394     if (rv != SECSuccess) goto loser;
00395     rv = writeItem(fd,&pubk->u.dsa.publicValue,output_file);
00396     if (rv != SECSuccess) goto loser;
00397     rv = writeItem(fd,&sign,output_file);
00398     if (rv != SECSuccess) goto loser;
00399 
00400     PR_Close(fd);
00401 
00402 #ifdef USES_LINKS
00403     if (link_file) {
00404        (void)unlink(link_file);
00405        ret = symlink(output_file, link_file);
00406        if (ret < 0) {
00407           perror(link_file);
00408           goto loser;
00409        }
00410     }
00411 #endif
00412 
00413     retval = 0;
00414 
00415 loser:
00416     if (hashcx) {
00417         PK11_DestroyContext(hashcx, PR_TRUE);
00418     }
00419     if (privk) {
00420         SECKEY_DestroyPrivateKey(privk);
00421     }
00422     if (pubk) {
00423         SECKEY_DestroyPublicKey(pubk);
00424     }
00425     if (slot) {
00426         PK11_FreeSlot(slot);
00427     }
00428     if (NSS_Shutdown() != SECSuccess) {
00429        exit(1);
00430     }
00431 
00432 prdone:
00433     PR_Cleanup ();
00434     return retval;
00435 }