Wed, 31 Dec 2014 07:16:47 +0100
Revert simplistic fix pending revisit of Mozilla integration attempt.
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 /*
6 * p7env -- A command to create a pkcs7 enveloped data.
7 */
9 #include "nspr.h"
10 #include "secutil.h"
11 #include "plgetopt.h"
12 #include "secpkcs7.h"
13 #include "cert.h"
14 #include "certdb.h"
15 #include "nss.h"
17 #if defined(XP_UNIX)
18 #include <unistd.h>
19 #endif
21 #include <stdio.h>
22 #include <string.h>
24 #if (defined(XP_WIN) && !defined(WIN32)) || (defined(__sun) && !defined(SVR4))
25 extern int fread(char *, size_t, size_t, FILE*);
26 extern int fwrite(char *, size_t, size_t, FILE*);
27 extern int fprintf(FILE *, char *, ...);
28 #endif
31 static void
32 Usage(char *progName)
33 {
34 fprintf(stderr,
35 "Usage: %s -r recipient [-d dbdir] [-i input] [-o output]\n",
36 progName);
37 fprintf(stderr, "%-20s Nickname of cert to use for encryption\n",
38 "-r recipient");
39 fprintf(stderr, "%-20s Cert database directory (default is ~/.netscape)\n",
40 "-d dbdir");
41 fprintf(stderr, "%-20s Define an input file to use (default is stdin)\n",
42 "-i input");
43 fprintf(stderr, "%-20s Define an output file to use (default is stdout)\n",
44 "-o output");
45 exit(-1);
46 }
48 struct recipient {
49 struct recipient *next;
50 char *nickname;
51 CERTCertificate *cert;
52 };
54 static void
55 EncryptOut(void *arg, const char *buf, unsigned long len)
56 {
57 FILE *out;
59 out = arg;
60 fwrite (buf, len, 1, out);
61 }
63 static int
64 EncryptFile(FILE *outFile, FILE *inFile, struct recipient *recipients,
65 char *progName)
66 {
67 SEC_PKCS7ContentInfo *cinfo;
68 SEC_PKCS7EncoderContext *ecx;
69 struct recipient *rcpt;
70 SECStatus rv;
72 if (outFile == NULL || inFile == NULL || recipients == NULL)
73 return -1;
75 /* XXX Need a better way to handle that certUsage stuff! */
76 /* XXX keysize? */
77 cinfo = SEC_PKCS7CreateEnvelopedData (recipients->cert,
78 certUsageEmailRecipient,
79 NULL, SEC_OID_DES_EDE3_CBC, 0,
80 NULL, NULL);
81 if (cinfo == NULL)
82 return -1;
84 for (rcpt = recipients->next; rcpt != NULL; rcpt = rcpt->next) {
85 rv = SEC_PKCS7AddRecipient (cinfo, rcpt->cert, certUsageEmailRecipient,
86 NULL);
87 if (rv != SECSuccess) {
88 SECU_PrintError(progName, "error adding recipient \"%s\"",
89 rcpt->nickname);
90 return -1;
91 }
92 }
94 ecx = SEC_PKCS7EncoderStart (cinfo, EncryptOut, outFile, NULL);
95 if (ecx == NULL)
96 return -1;
98 for (;;) {
99 char ibuf[1024];
100 int nb;
102 if (feof(inFile))
103 break;
104 nb = fread(ibuf, 1, sizeof(ibuf), inFile);
105 if (nb == 0) {
106 if (ferror(inFile)) {
107 PORT_SetError(SEC_ERROR_IO);
108 rv = SECFailure;
109 }
110 break;
111 }
112 rv = SEC_PKCS7EncoderUpdate(ecx, ibuf, nb);
113 if (rv != SECSuccess)
114 break;
115 }
117 if (SEC_PKCS7EncoderFinish(ecx, NULL, NULL) != SECSuccess)
118 rv = SECFailure;
120 SEC_PKCS7DestroyContentInfo (cinfo);
122 if (rv != SECSuccess)
123 return -1;
125 return 0;
126 }
128 int
129 main(int argc, char **argv)
130 {
131 char *progName;
132 FILE *inFile, *outFile;
133 char *certName;
134 CERTCertDBHandle *certHandle;
135 struct recipient *recipients, *rcpt;
136 PLOptState *optstate;
137 PLOptStatus status;
138 SECStatus rv;
140 progName = strrchr(argv[0], '/');
141 progName = progName ? progName+1 : argv[0];
143 inFile = NULL;
144 outFile = NULL;
145 certName = NULL;
146 recipients = NULL;
147 rcpt = NULL;
149 /*
150 * Parse command line arguments
151 * XXX This needs to be enhanced to allow selection of algorithms
152 * and key sizes (or to look up algorithms and key sizes for each
153 * recipient in the magic database).
154 */
155 optstate = PL_CreateOptState(argc, argv, "d:i:o:r:");
156 while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
157 switch (optstate->option) {
158 case '?':
159 Usage(progName);
160 break;
162 case 'd':
163 SECU_ConfigDirectory(optstate->value);
164 break;
166 case 'i':
167 inFile = fopen(optstate->value, "r");
168 if (!inFile) {
169 fprintf(stderr, "%s: unable to open \"%s\" for reading\n",
170 progName, optstate->value);
171 return -1;
172 }
173 break;
175 case 'o':
176 outFile = fopen(optstate->value, "wb");
177 if (!outFile) {
178 fprintf(stderr, "%s: unable to open \"%s\" for writing\n",
179 progName, optstate->value);
180 return -1;
181 }
182 break;
184 case 'r':
185 if (rcpt == NULL) {
186 recipients = rcpt = PORT_Alloc (sizeof(struct recipient));
187 } else {
188 rcpt->next = PORT_Alloc (sizeof(struct recipient));
189 rcpt = rcpt->next;
190 }
191 if (rcpt == NULL) {
192 fprintf(stderr, "%s: unable to allocate recipient struct\n",
193 progName);
194 return -1;
195 }
196 rcpt->nickname = strdup(optstate->value);
197 rcpt->cert = NULL;
198 rcpt->next = NULL;
199 break;
200 }
201 }
203 if (!recipients) Usage(progName);
205 if (!inFile) inFile = stdin;
206 if (!outFile) outFile = stdout;
208 /* Call the NSS initialization routines */
209 PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
210 rv = NSS_Init(SECU_ConfigDirectory(NULL));
211 if (rv != SECSuccess) {
212 SECU_PrintPRandOSError(progName);
213 return -1;
214 }
216 /* open cert database */
217 certHandle = CERT_GetDefaultCertDB();
218 if (certHandle == NULL) {
219 return -1;
220 }
222 /* find certs */
223 for (rcpt = recipients; rcpt != NULL; rcpt = rcpt->next) {
224 rcpt->cert = CERT_FindCertByNickname(certHandle, rcpt->nickname);
225 if (rcpt->cert == NULL) {
226 SECU_PrintError(progName,
227 "the cert for name \"%s\" not found in database",
228 rcpt->nickname);
229 return -1;
230 }
231 }
233 if (EncryptFile(outFile, inFile, recipients, progName)) {
234 SECU_PrintError(progName, "problem encrypting data");
235 return -1;
236 }
238 return 0;
239 }