1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/cmd/p7sign/p7sign.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,276 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +/* 1.9 + * p7sign -- A command to create a *detached* pkcs7 signature (over a given 1.10 + * input file). 1.11 + */ 1.12 + 1.13 +#include "nspr.h" 1.14 +#include "plgetopt.h" 1.15 +#include "secutil.h" 1.16 +#include "secpkcs7.h" 1.17 +#include "cert.h" 1.18 +#include "certdb.h" 1.19 +#include "sechash.h" /* for HASH_GetHashObject() */ 1.20 +#include "nss.h" 1.21 +#include "pk11func.h" 1.22 + 1.23 +#if defined(XP_UNIX) 1.24 +#include <unistd.h> 1.25 +#endif 1.26 + 1.27 +#include <stdio.h> 1.28 +#include <string.h> 1.29 + 1.30 +#if (defined(XP_WIN) && !defined(WIN32)) || (defined(__sun) && !defined(SVR4)) 1.31 +extern int fread(char *, size_t, size_t, FILE*); 1.32 +extern int fwrite(char *, size_t, size_t, FILE*); 1.33 +extern int fprintf(FILE *, char *, ...); 1.34 +#endif 1.35 + 1.36 +static secuPWData pwdata = { PW_NONE, 0 }; 1.37 + 1.38 +static void 1.39 +Usage(char *progName) 1.40 +{ 1.41 + fprintf(stderr, 1.42 + "Usage: %s -k keyname [-d keydir] [-i input] [-o output]\n", 1.43 + progName); 1.44 + fprintf(stderr, "%-20s Nickname of key to use for signature\n", 1.45 + "-k keyname"); 1.46 + fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n", 1.47 + "-d keydir"); 1.48 + fprintf(stderr, "%-20s Define an input file to use (default is stdin)\n", 1.49 + "-i input"); 1.50 + fprintf(stderr, "%-20s Define an output file to use (default is stdout)\n", 1.51 + "-o output"); 1.52 + fprintf(stderr, "%-20s Encapsulate content in signature message\n", 1.53 + "-e"); 1.54 + fprintf(stderr, "%-20s Password to the key databse\n", "-p"); 1.55 + fprintf(stderr, "%-20s password file\n", "-f"); 1.56 + exit(-1); 1.57 +} 1.58 + 1.59 +static void 1.60 +SignOut(void *arg, const char *buf, unsigned long len) 1.61 +{ 1.62 + FILE *out; 1.63 + 1.64 + out = (FILE*) arg; 1.65 + fwrite (buf, len, 1, out); 1.66 +} 1.67 + 1.68 +static int 1.69 +CreateDigest(SECItem *data, char *digestdata, unsigned int *len, unsigned int maxlen) 1.70 +{ 1.71 + const SECHashObject *hashObj; 1.72 + void *hashcx; 1.73 + 1.74 + /* XXX probably want to extend interface to allow other hash algorithms */ 1.75 + hashObj = HASH_GetHashObject(HASH_AlgSHA1); 1.76 + 1.77 + hashcx = (* hashObj->create)(); 1.78 + if (hashcx == NULL) 1.79 + return -1; 1.80 + 1.81 + (* hashObj->begin)(hashcx); 1.82 + (* hashObj->update)(hashcx, data->data, data->len); 1.83 + (* hashObj->end)(hashcx, (unsigned char *)digestdata, len, maxlen); 1.84 + (* hashObj->destroy)(hashcx, PR_TRUE); 1.85 + return 0; 1.86 +} 1.87 + 1.88 +static int 1.89 +SignFile(FILE *outFile, PRFileDesc *inFile, CERTCertificate *cert, 1.90 + PRBool encapsulated) 1.91 +{ 1.92 + char digestdata[32]; 1.93 + unsigned int len; 1.94 + SECItem digest, data2sign; 1.95 + SEC_PKCS7ContentInfo *cinfo; 1.96 + SECStatus rv; 1.97 + 1.98 + if (outFile == NULL || inFile == NULL || cert == NULL) 1.99 + return -1; 1.100 + 1.101 + /* suck the file in */ 1.102 + if (SECU_ReadDERFromFile(&data2sign, inFile, PR_FALSE, 1.103 + PR_FALSE) != SECSuccess) 1.104 + return -1; 1.105 + 1.106 + if (!encapsulated) { 1.107 + /* unfortunately, we must create the digest ourselves */ 1.108 + /* SEC_PKCS7CreateSignedData should have a flag to not include */ 1.109 + /* the content for non-encapsulated content at encode time, but */ 1.110 + /* should always compute the hash itself */ 1.111 + if (CreateDigest(&data2sign, digestdata, &len, 32) < 0) 1.112 + return -1; 1.113 + digest.data = (unsigned char *)digestdata; 1.114 + digest.len = len; 1.115 + } 1.116 + 1.117 + /* XXX Need a better way to handle that usage stuff! */ 1.118 + cinfo = SEC_PKCS7CreateSignedData (cert, certUsageEmailSigner, NULL, 1.119 + SEC_OID_SHA1, 1.120 + encapsulated ? NULL : &digest, 1.121 + NULL, NULL); 1.122 + if (cinfo == NULL) 1.123 + return -1; 1.124 + 1.125 + if (encapsulated) { 1.126 + SEC_PKCS7SetContent(cinfo, (char *)data2sign.data, data2sign.len); 1.127 + } 1.128 + 1.129 + rv = SEC_PKCS7IncludeCertChain (cinfo, NULL); 1.130 + if (rv != SECSuccess) { 1.131 + SEC_PKCS7DestroyContentInfo (cinfo); 1.132 + return -1; 1.133 + } 1.134 + 1.135 + rv = SEC_PKCS7Encode (cinfo, SignOut, outFile, NULL, 1.136 + NULL, &pwdata); 1.137 + 1.138 + SEC_PKCS7DestroyContentInfo (cinfo); 1.139 + 1.140 + if (rv != SECSuccess) 1.141 + return -1; 1.142 + 1.143 + return 0; 1.144 +} 1.145 + 1.146 +int 1.147 +main(int argc, char **argv) 1.148 +{ 1.149 + char *progName; 1.150 + FILE *outFile; 1.151 + PRFileDesc *inFile; 1.152 + char *keyName = NULL; 1.153 + CERTCertDBHandle *certHandle; 1.154 + CERTCertificate *cert = NULL; 1.155 + PRBool encapsulated = PR_FALSE; 1.156 + PLOptState *optstate; 1.157 + PLOptStatus status; 1.158 + SECStatus rv; 1.159 + 1.160 + progName = strrchr(argv[0], '/'); 1.161 + progName = progName ? progName+1 : argv[0]; 1.162 + 1.163 + inFile = NULL; 1.164 + outFile = NULL; 1.165 + keyName = NULL; 1.166 + 1.167 + /* 1.168 + * Parse command line arguments 1.169 + */ 1.170 + optstate = PL_CreateOptState(argc, argv, "ed:k:i:o:p:f:"); 1.171 + while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { 1.172 + switch (optstate->option) { 1.173 + case '?': 1.174 + Usage(progName); 1.175 + break; 1.176 + 1.177 + case 'e': 1.178 + /* create a message with the signed content encapsulated */ 1.179 + encapsulated = PR_TRUE; 1.180 + break; 1.181 + 1.182 + case 'd': 1.183 + SECU_ConfigDirectory(optstate->value); 1.184 + break; 1.185 + 1.186 + case 'i': 1.187 + inFile = PR_Open(optstate->value, PR_RDONLY, 0); 1.188 + if (!inFile) { 1.189 + fprintf(stderr, "%s: unable to open \"%s\" for reading\n", 1.190 + progName, optstate->value); 1.191 + return -1; 1.192 + } 1.193 + break; 1.194 + 1.195 + case 'k': 1.196 + keyName = strdup(optstate->value); 1.197 + break; 1.198 + 1.199 + case 'o': 1.200 + outFile = fopen(optstate->value, "wb"); 1.201 + if (!outFile) { 1.202 + fprintf(stderr, "%s: unable to open \"%s\" for writing\n", 1.203 + progName, optstate->value); 1.204 + return -1; 1.205 + } 1.206 + break; 1.207 + case 'p': 1.208 + pwdata.source = PW_PLAINTEXT; 1.209 + pwdata.data = strdup (optstate->value); 1.210 + break; 1.211 + 1.212 + case 'f': 1.213 + pwdata.source = PW_FROMFILE; 1.214 + pwdata.data = PORT_Strdup (optstate->value); 1.215 + break; 1.216 + } 1.217 + } 1.218 + 1.219 + if (!keyName) Usage(progName); 1.220 + 1.221 + if (!inFile) inFile = PR_STDIN; 1.222 + if (!outFile) outFile = stdout; 1.223 + 1.224 + /* Call the initialization routines */ 1.225 + PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); 1.226 + rv = NSS_Init(SECU_ConfigDirectory(NULL)); 1.227 + if (rv != SECSuccess) { 1.228 + SECU_PrintPRandOSError(progName); 1.229 + goto loser; 1.230 + } 1.231 + 1.232 + PK11_SetPasswordFunc(SECU_GetModulePassword); 1.233 + 1.234 + /* open cert database */ 1.235 + certHandle = CERT_GetDefaultCertDB(); 1.236 + if (certHandle == NULL) { 1.237 + rv = SECFailure; 1.238 + goto loser; 1.239 + } 1.240 + 1.241 + /* find cert */ 1.242 + cert = CERT_FindCertByNickname(certHandle, keyName); 1.243 + if (cert == NULL) { 1.244 + SECU_PrintError(progName, 1.245 + "the corresponding cert for key \"%s\" does not exist", 1.246 + keyName); 1.247 + rv = SECFailure; 1.248 + goto loser; 1.249 + } 1.250 + 1.251 + if (SignFile(outFile, inFile, cert, encapsulated)) { 1.252 + SECU_PrintError(progName, "problem signing data"); 1.253 + rv = SECFailure; 1.254 + goto loser; 1.255 + } 1.256 + 1.257 +loser: 1.258 + if (pwdata.data) { 1.259 + PORT_Free(pwdata.data); 1.260 + } 1.261 + if (keyName) { 1.262 + PORT_Free(keyName); 1.263 + } 1.264 + if (cert) { 1.265 + CERT_DestroyCertificate(cert); 1.266 + } 1.267 + if (inFile && inFile != PR_STDIN) { 1.268 + PR_Close(inFile); 1.269 + } 1.270 + if (outFile && outFile != stdout) { 1.271 + fclose(outFile); 1.272 + } 1.273 + if (NSS_Shutdown() != SECSuccess) { 1.274 + SECU_PrintError(progName, "NSS shutdown:"); 1.275 + exit(1); 1.276 + } 1.277 + 1.278 + return (rv != SECSuccess); 1.279 +}