p7env.c (7242B)
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/. */ 4 5 /* 6 * p7env -- A command to create a pkcs7 enveloped data. 7 */ 8 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" 16 17 #if defined(XP_UNIX) 18 #include <unistd.h> 19 #endif 20 21 #include <stdio.h> 22 #include <string.h> 23 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 29 30 static void 31 Usage(char *progName) 32 { 33 fprintf(stderr, 34 "Usage: %s -r recipient [-d dbdir] [-i input] [-o output]\n", 35 progName); 36 fprintf(stderr, "%-20s Nickname of cert to use for encryption\n", 37 "-r recipient"); 38 fprintf(stderr, "%-20s Cert database directory (default is ~/.netscape)\n", 39 "-d dbdir"); 40 fprintf(stderr, "%-20s Define an input file to use (default is stdin)\n", 41 "-i input"); 42 fprintf(stderr, "%-20s Define an output file to use (default is stdout)\n", 43 "-o output"); 44 exit(-1); 45 } 46 47 struct recipient { 48 struct recipient *next; 49 char *nickname; 50 CERTCertificate *cert; 51 }; 52 53 static void 54 EncryptOut(void *arg, const char *buf, unsigned long len) 55 { 56 FILE *out; 57 58 out = arg; 59 fwrite(buf, len, 1, out); 60 } 61 62 static int 63 EncryptFile(FILE *outFile, FILE *inFile, struct recipient *recipients, 64 char *progName) 65 { 66 SEC_PKCS7ContentInfo *cinfo; 67 SEC_PKCS7EncoderContext *ecx; 68 struct recipient *rcpt; 69 SECStatus rv = SECFailure; 70 71 if (outFile == NULL || inFile == NULL || recipients == NULL) 72 return -1; 73 74 /* XXX Need a better way to handle that certUsage stuff! */ 75 /* XXX keysize? */ 76 cinfo = SEC_PKCS7CreateEnvelopedData(recipients->cert, 77 certUsageEmailRecipient, 78 NULL, SEC_OID_DES_EDE3_CBC, 0, 79 NULL, NULL); 80 if (cinfo == NULL) 81 return -1; 82 83 for (rcpt = recipients->next; rcpt != NULL; rcpt = rcpt->next) { 84 rv = SEC_PKCS7AddRecipient(cinfo, rcpt->cert, certUsageEmailRecipient, 85 NULL); 86 if (rv != SECSuccess) { 87 SECU_PrintError(progName, "error adding recipient \"%s\"", 88 rcpt->nickname); 89 return -1; 90 } 91 } 92 93 ecx = SEC_PKCS7EncoderStart(cinfo, EncryptOut, outFile, NULL); 94 if (ecx == NULL) 95 return -1; 96 97 for (;;) { 98 char ibuf[1024]; 99 int nb; 100 101 if (feof(inFile)) 102 break; 103 nb = fread(ibuf, 1, sizeof(ibuf), inFile); 104 if (nb == 0) { 105 if (ferror(inFile)) { 106 PORT_SetError(SEC_ERROR_IO); 107 rv = SECFailure; 108 } 109 break; 110 } 111 rv = SEC_PKCS7EncoderUpdate(ecx, ibuf, nb); 112 if (rv != SECSuccess) 113 break; 114 } 115 116 if (SEC_PKCS7EncoderFinish(ecx, NULL, NULL) != SECSuccess) 117 rv = SECFailure; 118 119 SEC_PKCS7DestroyContentInfo(cinfo); 120 121 if (rv != SECSuccess) 122 return -1; 123 124 return 0; 125 } 126 127 int 128 main(int argc, char **argv) 129 { 130 char *progName; 131 FILE *inFile, *outFile; 132 CERTCertDBHandle *certHandle; 133 struct recipient *recipients, *rcpt; 134 PLOptState *optstate; 135 PLOptStatus status; 136 SECStatus rv = SECFailure; 137 138 progName = strrchr(argv[0], '/'); 139 progName = progName ? progName + 1 : argv[0]; 140 141 inFile = NULL; 142 outFile = NULL; 143 recipients = NULL; 144 rcpt = NULL; 145 146 /* 147 * Parse command line arguments 148 * XXX This needs to be enhanced to allow selection of algorithms 149 * and key sizes (or to look up algorithms and key sizes for each 150 * recipient in the magic database). 151 */ 152 optstate = PL_CreateOptState(argc, argv, "d:i:o:r:"); 153 while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { 154 switch (optstate->option) { 155 case '?': 156 Usage(progName); 157 break; 158 159 case 'd': 160 SECU_ConfigDirectory(optstate->value); 161 break; 162 163 case 'i': 164 inFile = fopen(optstate->value, "r"); 165 if (!inFile) { 166 fprintf(stderr, "%s: unable to open \"%s\" for reading\n", 167 progName, optstate->value); 168 return -1; 169 } 170 break; 171 172 case 'o': 173 outFile = fopen(optstate->value, "wb"); 174 if (!outFile) { 175 fprintf(stderr, "%s: unable to open \"%s\" for writing\n", 176 progName, optstate->value); 177 return -1; 178 } 179 break; 180 181 case 'r': 182 if (rcpt == NULL) { 183 recipients = rcpt = PORT_Alloc(sizeof(struct recipient)); 184 } else { 185 rcpt->next = PORT_Alloc(sizeof(struct recipient)); 186 rcpt = rcpt->next; 187 } 188 if (rcpt == NULL) { 189 fprintf(stderr, "%s: unable to allocate recipient struct\n", 190 progName); 191 return -1; 192 } 193 rcpt->nickname = PORT_Strdup(optstate->value); 194 rcpt->cert = NULL; 195 rcpt->next = NULL; 196 break; 197 } 198 } 199 PL_DestroyOptState(optstate); 200 201 if (!recipients) 202 Usage(progName); 203 204 if (!inFile) 205 inFile = stdin; 206 if (!outFile) 207 outFile = stdout; 208 209 /* Call the NSS initialization routines */ 210 PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); 211 rv = NSS_Init(SECU_ConfigDirectory(NULL)); 212 if (rv != SECSuccess) { 213 SECU_PrintPRandOSError(progName); 214 return -1; 215 } 216 217 /* open cert database */ 218 certHandle = CERT_GetDefaultCertDB(); 219 if (certHandle == NULL) { 220 return -1; 221 } 222 223 /* find certs */ 224 for (rcpt = recipients; rcpt != NULL; rcpt = rcpt->next) { 225 rcpt->cert = CERT_FindCertByNickname(certHandle, rcpt->nickname); 226 if (rcpt->cert == NULL) { 227 SECU_PrintError(progName, 228 "the cert for name \"%s\" not found in database", 229 rcpt->nickname); 230 return -1; 231 } 232 } 233 234 if (EncryptFile(outFile, inFile, recipients, progName)) { 235 SECU_PrintError(progName, "problem encrypting data"); 236 return -1; 237 } 238 239 /* free certs */ 240 for (rcpt = recipients; rcpt != NULL;) { 241 struct recipient *next = rcpt->next; 242 CERT_DestroyCertificate(rcpt->cert); 243 PORT_Free(rcpt->nickname); 244 PORT_Free(rcpt); 245 rcpt = next; 246 } 247 248 if (inFile && inFile != stdin) { 249 fclose(inFile); 250 } 251 if (outFile && outFile != stdout) { 252 fclose(outFile); 253 } 254 255 if (NSS_Shutdown() != SECSuccess) { 256 SECU_PrintError(progName, "NSS shutdown:"); 257 return -1; 258 } 259 260 return 0; 261 }