security/nss/cmd/p7sign/p7sign.c

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 /*
michael@0 6 * p7sign -- A command to create a *detached* pkcs7 signature (over a given
michael@0 7 * input file).
michael@0 8 */
michael@0 9
michael@0 10 #include "nspr.h"
michael@0 11 #include "plgetopt.h"
michael@0 12 #include "secutil.h"
michael@0 13 #include "secpkcs7.h"
michael@0 14 #include "cert.h"
michael@0 15 #include "certdb.h"
michael@0 16 #include "sechash.h" /* for HASH_GetHashObject() */
michael@0 17 #include "nss.h"
michael@0 18 #include "pk11func.h"
michael@0 19
michael@0 20 #if defined(XP_UNIX)
michael@0 21 #include <unistd.h>
michael@0 22 #endif
michael@0 23
michael@0 24 #include <stdio.h>
michael@0 25 #include <string.h>
michael@0 26
michael@0 27 #if (defined(XP_WIN) && !defined(WIN32)) || (defined(__sun) && !defined(SVR4))
michael@0 28 extern int fread(char *, size_t, size_t, FILE*);
michael@0 29 extern int fwrite(char *, size_t, size_t, FILE*);
michael@0 30 extern int fprintf(FILE *, char *, ...);
michael@0 31 #endif
michael@0 32
michael@0 33 static secuPWData pwdata = { PW_NONE, 0 };
michael@0 34
michael@0 35 static void
michael@0 36 Usage(char *progName)
michael@0 37 {
michael@0 38 fprintf(stderr,
michael@0 39 "Usage: %s -k keyname [-d keydir] [-i input] [-o output]\n",
michael@0 40 progName);
michael@0 41 fprintf(stderr, "%-20s Nickname of key to use for signature\n",
michael@0 42 "-k keyname");
michael@0 43 fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
michael@0 44 "-d keydir");
michael@0 45 fprintf(stderr, "%-20s Define an input file to use (default is stdin)\n",
michael@0 46 "-i input");
michael@0 47 fprintf(stderr, "%-20s Define an output file to use (default is stdout)\n",
michael@0 48 "-o output");
michael@0 49 fprintf(stderr, "%-20s Encapsulate content in signature message\n",
michael@0 50 "-e");
michael@0 51 fprintf(stderr, "%-20s Password to the key databse\n", "-p");
michael@0 52 fprintf(stderr, "%-20s password file\n", "-f");
michael@0 53 exit(-1);
michael@0 54 }
michael@0 55
michael@0 56 static void
michael@0 57 SignOut(void *arg, const char *buf, unsigned long len)
michael@0 58 {
michael@0 59 FILE *out;
michael@0 60
michael@0 61 out = (FILE*) arg;
michael@0 62 fwrite (buf, len, 1, out);
michael@0 63 }
michael@0 64
michael@0 65 static int
michael@0 66 CreateDigest(SECItem *data, char *digestdata, unsigned int *len, unsigned int maxlen)
michael@0 67 {
michael@0 68 const SECHashObject *hashObj;
michael@0 69 void *hashcx;
michael@0 70
michael@0 71 /* XXX probably want to extend interface to allow other hash algorithms */
michael@0 72 hashObj = HASH_GetHashObject(HASH_AlgSHA1);
michael@0 73
michael@0 74 hashcx = (* hashObj->create)();
michael@0 75 if (hashcx == NULL)
michael@0 76 return -1;
michael@0 77
michael@0 78 (* hashObj->begin)(hashcx);
michael@0 79 (* hashObj->update)(hashcx, data->data, data->len);
michael@0 80 (* hashObj->end)(hashcx, (unsigned char *)digestdata, len, maxlen);
michael@0 81 (* hashObj->destroy)(hashcx, PR_TRUE);
michael@0 82 return 0;
michael@0 83 }
michael@0 84
michael@0 85 static int
michael@0 86 SignFile(FILE *outFile, PRFileDesc *inFile, CERTCertificate *cert,
michael@0 87 PRBool encapsulated)
michael@0 88 {
michael@0 89 char digestdata[32];
michael@0 90 unsigned int len;
michael@0 91 SECItem digest, data2sign;
michael@0 92 SEC_PKCS7ContentInfo *cinfo;
michael@0 93 SECStatus rv;
michael@0 94
michael@0 95 if (outFile == NULL || inFile == NULL || cert == NULL)
michael@0 96 return -1;
michael@0 97
michael@0 98 /* suck the file in */
michael@0 99 if (SECU_ReadDERFromFile(&data2sign, inFile, PR_FALSE,
michael@0 100 PR_FALSE) != SECSuccess)
michael@0 101 return -1;
michael@0 102
michael@0 103 if (!encapsulated) {
michael@0 104 /* unfortunately, we must create the digest ourselves */
michael@0 105 /* SEC_PKCS7CreateSignedData should have a flag to not include */
michael@0 106 /* the content for non-encapsulated content at encode time, but */
michael@0 107 /* should always compute the hash itself */
michael@0 108 if (CreateDigest(&data2sign, digestdata, &len, 32) < 0)
michael@0 109 return -1;
michael@0 110 digest.data = (unsigned char *)digestdata;
michael@0 111 digest.len = len;
michael@0 112 }
michael@0 113
michael@0 114 /* XXX Need a better way to handle that usage stuff! */
michael@0 115 cinfo = SEC_PKCS7CreateSignedData (cert, certUsageEmailSigner, NULL,
michael@0 116 SEC_OID_SHA1,
michael@0 117 encapsulated ? NULL : &digest,
michael@0 118 NULL, NULL);
michael@0 119 if (cinfo == NULL)
michael@0 120 return -1;
michael@0 121
michael@0 122 if (encapsulated) {
michael@0 123 SEC_PKCS7SetContent(cinfo, (char *)data2sign.data, data2sign.len);
michael@0 124 }
michael@0 125
michael@0 126 rv = SEC_PKCS7IncludeCertChain (cinfo, NULL);
michael@0 127 if (rv != SECSuccess) {
michael@0 128 SEC_PKCS7DestroyContentInfo (cinfo);
michael@0 129 return -1;
michael@0 130 }
michael@0 131
michael@0 132 rv = SEC_PKCS7Encode (cinfo, SignOut, outFile, NULL,
michael@0 133 NULL, &pwdata);
michael@0 134
michael@0 135 SEC_PKCS7DestroyContentInfo (cinfo);
michael@0 136
michael@0 137 if (rv != SECSuccess)
michael@0 138 return -1;
michael@0 139
michael@0 140 return 0;
michael@0 141 }
michael@0 142
michael@0 143 int
michael@0 144 main(int argc, char **argv)
michael@0 145 {
michael@0 146 char *progName;
michael@0 147 FILE *outFile;
michael@0 148 PRFileDesc *inFile;
michael@0 149 char *keyName = NULL;
michael@0 150 CERTCertDBHandle *certHandle;
michael@0 151 CERTCertificate *cert = NULL;
michael@0 152 PRBool encapsulated = PR_FALSE;
michael@0 153 PLOptState *optstate;
michael@0 154 PLOptStatus status;
michael@0 155 SECStatus rv;
michael@0 156
michael@0 157 progName = strrchr(argv[0], '/');
michael@0 158 progName = progName ? progName+1 : argv[0];
michael@0 159
michael@0 160 inFile = NULL;
michael@0 161 outFile = NULL;
michael@0 162 keyName = NULL;
michael@0 163
michael@0 164 /*
michael@0 165 * Parse command line arguments
michael@0 166 */
michael@0 167 optstate = PL_CreateOptState(argc, argv, "ed:k:i:o:p:f:");
michael@0 168 while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
michael@0 169 switch (optstate->option) {
michael@0 170 case '?':
michael@0 171 Usage(progName);
michael@0 172 break;
michael@0 173
michael@0 174 case 'e':
michael@0 175 /* create a message with the signed content encapsulated */
michael@0 176 encapsulated = PR_TRUE;
michael@0 177 break;
michael@0 178
michael@0 179 case 'd':
michael@0 180 SECU_ConfigDirectory(optstate->value);
michael@0 181 break;
michael@0 182
michael@0 183 case 'i':
michael@0 184 inFile = PR_Open(optstate->value, PR_RDONLY, 0);
michael@0 185 if (!inFile) {
michael@0 186 fprintf(stderr, "%s: unable to open \"%s\" for reading\n",
michael@0 187 progName, optstate->value);
michael@0 188 return -1;
michael@0 189 }
michael@0 190 break;
michael@0 191
michael@0 192 case 'k':
michael@0 193 keyName = strdup(optstate->value);
michael@0 194 break;
michael@0 195
michael@0 196 case 'o':
michael@0 197 outFile = fopen(optstate->value, "wb");
michael@0 198 if (!outFile) {
michael@0 199 fprintf(stderr, "%s: unable to open \"%s\" for writing\n",
michael@0 200 progName, optstate->value);
michael@0 201 return -1;
michael@0 202 }
michael@0 203 break;
michael@0 204 case 'p':
michael@0 205 pwdata.source = PW_PLAINTEXT;
michael@0 206 pwdata.data = strdup (optstate->value);
michael@0 207 break;
michael@0 208
michael@0 209 case 'f':
michael@0 210 pwdata.source = PW_FROMFILE;
michael@0 211 pwdata.data = PORT_Strdup (optstate->value);
michael@0 212 break;
michael@0 213 }
michael@0 214 }
michael@0 215
michael@0 216 if (!keyName) Usage(progName);
michael@0 217
michael@0 218 if (!inFile) inFile = PR_STDIN;
michael@0 219 if (!outFile) outFile = stdout;
michael@0 220
michael@0 221 /* Call the initialization routines */
michael@0 222 PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
michael@0 223 rv = NSS_Init(SECU_ConfigDirectory(NULL));
michael@0 224 if (rv != SECSuccess) {
michael@0 225 SECU_PrintPRandOSError(progName);
michael@0 226 goto loser;
michael@0 227 }
michael@0 228
michael@0 229 PK11_SetPasswordFunc(SECU_GetModulePassword);
michael@0 230
michael@0 231 /* open cert database */
michael@0 232 certHandle = CERT_GetDefaultCertDB();
michael@0 233 if (certHandle == NULL) {
michael@0 234 rv = SECFailure;
michael@0 235 goto loser;
michael@0 236 }
michael@0 237
michael@0 238 /* find cert */
michael@0 239 cert = CERT_FindCertByNickname(certHandle, keyName);
michael@0 240 if (cert == NULL) {
michael@0 241 SECU_PrintError(progName,
michael@0 242 "the corresponding cert for key \"%s\" does not exist",
michael@0 243 keyName);
michael@0 244 rv = SECFailure;
michael@0 245 goto loser;
michael@0 246 }
michael@0 247
michael@0 248 if (SignFile(outFile, inFile, cert, encapsulated)) {
michael@0 249 SECU_PrintError(progName, "problem signing data");
michael@0 250 rv = SECFailure;
michael@0 251 goto loser;
michael@0 252 }
michael@0 253
michael@0 254 loser:
michael@0 255 if (pwdata.data) {
michael@0 256 PORT_Free(pwdata.data);
michael@0 257 }
michael@0 258 if (keyName) {
michael@0 259 PORT_Free(keyName);
michael@0 260 }
michael@0 261 if (cert) {
michael@0 262 CERT_DestroyCertificate(cert);
michael@0 263 }
michael@0 264 if (inFile && inFile != PR_STDIN) {
michael@0 265 PR_Close(inFile);
michael@0 266 }
michael@0 267 if (outFile && outFile != stdout) {
michael@0 268 fclose(outFile);
michael@0 269 }
michael@0 270 if (NSS_Shutdown() != SECSuccess) {
michael@0 271 SECU_PrintError(progName, "NSS shutdown:");
michael@0 272 exit(1);
michael@0 273 }
michael@0 274
michael@0 275 return (rv != SECSuccess);
michael@0 276 }

mercurial