Back to index

lightning-sunbird  0.9+nobinonly
p7env.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  * p7env -- A command to create a pkcs7 enveloped data.
00039  *
00040  * $Id: p7env.c,v 1.7 2004/10/07 04:12:47 julien.pierre.bugs%sun.com Exp $
00041  */
00042 
00043 #include "nspr.h"
00044 #include "secutil.h"
00045 #include "plgetopt.h"
00046 #include "secpkcs7.h"
00047 #include "cert.h"
00048 #include "certdb.h"
00049 #include "nss.h"
00050 
00051 #if defined(XP_UNIX)
00052 #include <unistd.h>
00053 #endif
00054 
00055 #include <stdio.h>
00056 #include <string.h>
00057 
00058 #if (defined(XP_WIN) && !defined(WIN32)) || (defined(__sun) && !defined(SVR4))
00059 extern int fread(char *, size_t, size_t, FILE*);
00060 extern int fwrite(char *, size_t, size_t, FILE*);
00061 extern int fprintf(FILE *, char *, ...);
00062 #endif
00063 
00064 extern void SEC_Init(void);        /* XXX */
00065 
00066 
00067 static void
00068 Usage(char *progName)
00069 {
00070     fprintf(stderr,
00071            "Usage:  %s -r recipient [-d dbdir] [-i input] [-o output]\n",
00072            progName);
00073     fprintf(stderr, "%-20s Nickname of cert to use for encryption\n",
00074            "-r recipient");
00075     fprintf(stderr, "%-20s Cert database directory (default is ~/.netscape)\n",
00076            "-d dbdir");
00077     fprintf(stderr, "%-20s Define an input file to use (default is stdin)\n",
00078            "-i input");
00079     fprintf(stderr, "%-20s Define an output file to use (default is stdout)\n",
00080            "-o output");
00081     exit(-1);
00082 }
00083 
00084 struct recipient {
00085     struct recipient *next;
00086     char *nickname;
00087     CERTCertificate *cert;
00088 };
00089 
00090 static void
00091 EncryptOut(void *arg, const char *buf, unsigned long len)
00092 {
00093    FILE *out;
00094 
00095    out = arg; 
00096    fwrite (buf, len, 1, out);
00097 }
00098 
00099 static int
00100 EncryptFile(FILE *outFile, FILE *inFile, struct recipient *recipients,
00101            char *progName)
00102 {
00103     SEC_PKCS7ContentInfo *cinfo;
00104     SEC_PKCS7EncoderContext *ecx;
00105     struct recipient *rcpt;
00106     SECStatus rv;
00107 
00108     if (outFile == NULL || inFile == NULL || recipients == NULL)
00109        return -1;
00110 
00111     /* XXX Need a better way to handle that certUsage stuff! */
00112     /* XXX keysize? */
00113     cinfo = SEC_PKCS7CreateEnvelopedData (recipients->cert,
00114                                      certUsageEmailRecipient,
00115                                      NULL, SEC_OID_DES_EDE3_CBC, 0, 
00116                                      NULL, NULL);
00117     if (cinfo == NULL)
00118        return -1;
00119 
00120     for (rcpt = recipients->next; rcpt != NULL; rcpt = rcpt->next) {
00121        rv = SEC_PKCS7AddRecipient (cinfo, rcpt->cert, certUsageEmailRecipient,
00122                                 NULL);
00123        if (rv != SECSuccess) {
00124            SECU_PrintError(progName, "error adding recipient \"%s\"",
00125                          rcpt->nickname);
00126            return -1;
00127        }
00128     }
00129 
00130     ecx = SEC_PKCS7EncoderStart (cinfo, EncryptOut, outFile, NULL);
00131     if (ecx == NULL)
00132        return -1;
00133 
00134     for (;;) {
00135        char ibuf[1024];
00136        int nb;
00137  
00138        if (feof(inFile))
00139            break;
00140        nb = fread(ibuf, 1, sizeof(ibuf), inFile);
00141        if (nb == 0) {
00142            if (ferror(inFile)) {
00143               PORT_SetError(SEC_ERROR_IO);
00144               rv = SECFailure;
00145            }
00146            break;
00147        }
00148        rv = SEC_PKCS7EncoderUpdate(ecx, ibuf, nb);
00149        if (rv != SECSuccess)
00150            break;
00151     }
00152 
00153     if (SEC_PKCS7EncoderFinish(ecx, NULL, NULL) != SECSuccess)
00154        rv = SECFailure;
00155 
00156     SEC_PKCS7DestroyContentInfo (cinfo);
00157 
00158     if (rv != SECSuccess)
00159        return -1;
00160 
00161     return 0;
00162 }
00163 
00164 int
00165 main(int argc, char **argv)
00166 {
00167     char *progName;
00168     FILE *inFile, *outFile;
00169     char *certName;
00170     CERTCertDBHandle *certHandle;
00171     struct recipient *recipients, *rcpt;
00172     PLOptState *optstate;
00173     PLOptStatus status;
00174     SECStatus rv;
00175 
00176     progName = strrchr(argv[0], '/');
00177     progName = progName ? progName+1 : argv[0];
00178 
00179     inFile = NULL;
00180     outFile = NULL;
00181     certName = NULL;
00182     recipients = NULL;
00183     rcpt = NULL;
00184 
00185     /*
00186      * Parse command line arguments
00187      * XXX This needs to be enhanced to allow selection of algorithms
00188      * and key sizes (or to look up algorithms and key sizes for each
00189      * recipient in the magic database).
00190      */
00191     optstate = PL_CreateOptState(argc, argv, "d:i:o:r:");
00192     while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
00193        switch (optstate->option) {
00194          case '?':
00195            Usage(progName);
00196            break;
00197 
00198          case 'd':
00199            SECU_ConfigDirectory(optstate->value);
00200            break;
00201 
00202          case 'i':
00203            inFile = fopen(optstate->value, "r");
00204            if (!inFile) {
00205               fprintf(stderr, "%s: unable to open \"%s\" for reading\n",
00206                      progName, optstate->value);
00207               return -1;
00208            }
00209            break;
00210 
00211          case 'o':
00212            outFile = fopen(optstate->value, "w");
00213            if (!outFile) {
00214               fprintf(stderr, "%s: unable to open \"%s\" for writing\n",
00215                      progName, optstate->value);
00216               return -1;
00217            }
00218            break;
00219 
00220          case 'r':
00221            if (rcpt == NULL) {
00222               recipients = rcpt = PORT_Alloc (sizeof(struct recipient));
00223            } else {
00224               rcpt->next = PORT_Alloc (sizeof(struct recipient));
00225               rcpt = rcpt->next;
00226            }
00227            if (rcpt == NULL) {
00228               fprintf(stderr, "%s: unable to allocate recipient struct\n",
00229                      progName);
00230               return -1;
00231            }
00232            rcpt->nickname = strdup(optstate->value);
00233            rcpt->cert = NULL;
00234            rcpt->next = NULL;
00235            break;
00236        }
00237     }
00238 
00239     if (!recipients) Usage(progName);
00240 
00241     if (!inFile) inFile = stdin;
00242     if (!outFile) outFile = stdout;
00243 
00244     /* Call the libsec initialization routines */
00245     PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
00246     rv = NSS_Init(SECU_ConfigDirectory(NULL));
00247     if (rv != SECSuccess) {
00248        SECU_PrintPRandOSError(progName);
00249        return -1;
00250     }
00251 
00252     /* open cert database */
00253     certHandle = CERT_GetDefaultCertDB();
00254     if (certHandle == NULL) {
00255        return -1;
00256     }
00257 
00258     /* find certs */
00259     for (rcpt = recipients; rcpt != NULL; rcpt = rcpt->next) {
00260        rcpt->cert = CERT_FindCertByNickname(certHandle, rcpt->nickname);
00261        if (rcpt->cert == NULL) {
00262            SECU_PrintError(progName,
00263                          "the cert for name \"%s\" not found in database",
00264                          rcpt->nickname);
00265            return -1;
00266        }
00267     }
00268 
00269     if (EncryptFile(outFile, inFile, recipients, progName)) {
00270        SECU_PrintError(progName, "problem encrypting data");
00271        return -1;
00272     }
00273 
00274     return 0;
00275 }