1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/cmd/signver/signver.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,315 @@ 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 +#include "secutil.h" 1.9 +#include "secmod.h" 1.10 +#include "cert.h" 1.11 +#include "secoid.h" 1.12 +#include "nss.h" 1.13 + 1.14 +/* NSPR 2.0 header files */ 1.15 +#include "prinit.h" 1.16 +#include "prprf.h" 1.17 +#include "prsystem.h" 1.18 +#include "prmem.h" 1.19 +/* Portable layer header files */ 1.20 +#include "plstr.h" 1.21 +#include "sechash.h" /* for HASH_GetHashObject() */ 1.22 + 1.23 +static PRBool debugInfo; 1.24 +static PRBool verbose; 1.25 +static PRBool doVerify; 1.26 +static PRBool displayAll; 1.27 + 1.28 +static const char * const usageInfo[] = { 1.29 + "signver - verify a detached PKCS7 signature - Version " NSS_VERSION, 1.30 + "Commands:", 1.31 + " -A display all information from pkcs #7", 1.32 + " -V verify the signed object and display result", 1.33 + "Options:", 1.34 + " -a signature file is ASCII", 1.35 + " -d certdir directory containing cert database", 1.36 + " -i dataFileName input file containing signed data (default stdin)", 1.37 + " -o outputFileName output file name, default stdout", 1.38 + " -s signatureFileName input file for signature (default stdin)", 1.39 + " -v display verbose reason for failure" 1.40 +}; 1.41 +static int nUsageInfo = sizeof(usageInfo)/sizeof(char *); 1.42 + 1.43 +extern int SV_PrintPKCS7ContentInfo(FILE *, SECItem *); 1.44 + 1.45 +static void Usage(char *progName, FILE *outFile) 1.46 +{ 1.47 + int i; 1.48 + fprintf(outFile, "Usage: %s [ commands ] options\n", progName); 1.49 + for (i = 0; i < nUsageInfo; i++) 1.50 + fprintf(outFile, "%s\n", usageInfo[i]); 1.51 + exit(-1); 1.52 +} 1.53 + 1.54 +static HASH_HashType 1.55 +AlgorithmToHashType(SECAlgorithmID *digestAlgorithms) 1.56 +{ 1.57 + SECOidTag tag = SECOID_GetAlgorithmTag(digestAlgorithms); 1.58 + HASH_HashType hash = HASH_GetHashTypeByOidTag(tag); 1.59 + return hash; 1.60 +} 1.61 + 1.62 + 1.63 +static SECStatus 1.64 +DigestContent (SECItem * digest, SECItem * content, HASH_HashType hashType) 1.65 +{ 1.66 + unsigned int maxLen = digest->len; 1.67 + unsigned int len = HASH_ResultLen(hashType); 1.68 + SECStatus rv; 1.69 + 1.70 + if (len > maxLen) { 1.71 + PORT_SetError(SEC_ERROR_OUTPUT_LEN); 1.72 + return SECFailure; 1.73 + } 1.74 + 1.75 + rv = HASH_HashBuf(hashType, digest->data, content->data, content->len); 1.76 + if (rv == SECSuccess) 1.77 + digest->len = len; 1.78 + return rv; 1.79 +} 1.80 + 1.81 +enum { 1.82 + cmd_DisplayAllPCKS7Info = 0, 1.83 + cmd_VerifySignedObj 1.84 +}; 1.85 + 1.86 +enum { 1.87 + opt_ASCII, 1.88 + opt_CertDir, 1.89 + opt_InputDataFile, 1.90 + opt_ItemNumber, 1.91 + opt_OutputFile, 1.92 + opt_InputSigFile, 1.93 + opt_PrintWhyFailure, 1.94 + opt_DebugInfo 1.95 +}; 1.96 + 1.97 +static secuCommandFlag signver_commands[] = 1.98 +{ 1.99 + { /* cmd_DisplayAllPCKS7Info*/ 'A', PR_FALSE, 0, PR_FALSE }, 1.100 + { /* cmd_VerifySignedObj */ 'V', PR_FALSE, 0, PR_FALSE } 1.101 +}; 1.102 + 1.103 +static secuCommandFlag signver_options[] = 1.104 +{ 1.105 + { /* opt_ASCII */ 'a', PR_FALSE, 0, PR_FALSE }, 1.106 + { /* opt_CertDir */ 'd', PR_TRUE, 0, PR_FALSE }, 1.107 + { /* opt_InputDataFile */ 'i', PR_TRUE, 0, PR_FALSE }, 1.108 + { /* opt_OutputFile */ 'o', PR_TRUE, 0, PR_FALSE }, 1.109 + { /* opt_InputSigFile */ 's', PR_TRUE, 0, PR_FALSE }, 1.110 + { /* opt_PrintWhyFailure */ 'v', PR_FALSE, 0, PR_FALSE }, 1.111 + { /* opt_DebugInfo */ 0, PR_FALSE, 0, PR_FALSE, "debug" } 1.112 +}; 1.113 + 1.114 +int main(int argc, char **argv) 1.115 +{ 1.116 + PRFileDesc *contentFile = NULL; 1.117 + PRFileDesc *signFile = PR_STDIN; 1.118 + FILE * outFile = stdout; 1.119 + char * progName; 1.120 + SECStatus rv; 1.121 + int result = 1; 1.122 + SECItem pkcs7der, content; 1.123 + secuCommand signver; 1.124 + 1.125 + pkcs7der.data = NULL; 1.126 + content.data = NULL; 1.127 + 1.128 + signver.numCommands = sizeof(signver_commands) /sizeof(secuCommandFlag); 1.129 + signver.numOptions = sizeof(signver_options) / sizeof(secuCommandFlag); 1.130 + signver.commands = signver_commands; 1.131 + signver.options = signver_options; 1.132 + 1.133 +#ifdef XP_PC 1.134 + progName = strrchr(argv[0], '\\'); 1.135 +#else 1.136 + progName = strrchr(argv[0], '/'); 1.137 +#endif 1.138 + progName = progName ? progName+1 : argv[0]; 1.139 + 1.140 + rv = SECU_ParseCommandLine(argc, argv, progName, &signver); 1.141 + if (SECSuccess != rv) { 1.142 + Usage(progName, outFile); 1.143 + } 1.144 + debugInfo = signver.options[opt_DebugInfo ].activated; 1.145 + verbose = signver.options[opt_PrintWhyFailure ].activated; 1.146 + doVerify = signver.commands[cmd_VerifySignedObj].activated; 1.147 + displayAll= signver.commands[cmd_DisplayAllPCKS7Info].activated; 1.148 + if (!doVerify && !displayAll) 1.149 + doVerify = PR_TRUE; 1.150 + 1.151 + /* Set the certdb directory (default is ~/.netscape) */ 1.152 + rv = NSS_Init(SECU_ConfigDirectory(signver.options[opt_CertDir].arg)); 1.153 + if (rv != SECSuccess) { 1.154 + SECU_PrintPRandOSError(progName); 1.155 + return result; 1.156 + } 1.157 + /* below here, goto cleanup */ 1.158 + SECU_RegisterDynamicOids(); 1.159 + 1.160 + /* Open the input content file. */ 1.161 + if (signver.options[opt_InputDataFile].activated && 1.162 + signver.options[opt_InputDataFile].arg) { 1.163 + if (PL_strcmp("-", signver.options[opt_InputDataFile].arg)) { 1.164 + contentFile = PR_Open(signver.options[opt_InputDataFile].arg, 1.165 + PR_RDONLY, 0); 1.166 + if (!contentFile) { 1.167 + PR_fprintf(PR_STDERR, 1.168 + "%s: unable to open \"%s\" for reading.\n", 1.169 + progName, signver.options[opt_InputDataFile].arg); 1.170 + goto cleanup; 1.171 + } 1.172 + } else 1.173 + contentFile = PR_STDIN; 1.174 + } 1.175 + 1.176 + /* Open the input signature file. */ 1.177 + if (signver.options[opt_InputSigFile].activated && 1.178 + signver.options[opt_InputSigFile].arg) { 1.179 + if (PL_strcmp("-", signver.options[opt_InputSigFile].arg)) { 1.180 + signFile = PR_Open(signver.options[opt_InputSigFile].arg, 1.181 + PR_RDONLY, 0); 1.182 + if (!signFile) { 1.183 + PR_fprintf(PR_STDERR, 1.184 + "%s: unable to open \"%s\" for reading.\n", 1.185 + progName, signver.options[opt_InputSigFile].arg); 1.186 + goto cleanup; 1.187 + } 1.188 + } 1.189 + } 1.190 + 1.191 + if (contentFile == PR_STDIN && signFile == PR_STDIN && doVerify) { 1.192 + PR_fprintf(PR_STDERR, 1.193 + "%s: cannot read both content and signature from standard input\n", 1.194 + progName); 1.195 + goto cleanup; 1.196 + } 1.197 + 1.198 + /* Open|Create the output file. */ 1.199 + if (signver.options[opt_OutputFile].activated) { 1.200 + outFile = fopen(signver.options[opt_OutputFile].arg, "w"); 1.201 + if (!outFile) { 1.202 + PR_fprintf(PR_STDERR, "%s: unable to open \"%s\" for writing.\n", 1.203 + progName, signver.options[opt_OutputFile].arg); 1.204 + goto cleanup; 1.205 + } 1.206 + } 1.207 + 1.208 + /* read in the input files' contents */ 1.209 + rv = SECU_ReadDERFromFile(&pkcs7der, signFile, 1.210 + signver.options[opt_ASCII].activated, PR_FALSE); 1.211 + if (signFile != PR_STDIN) 1.212 + PR_Close(signFile); 1.213 + if (rv != SECSuccess) { 1.214 + SECU_PrintError(progName, "problem reading PKCS7 input"); 1.215 + goto cleanup; 1.216 + } 1.217 + if (contentFile) { 1.218 + rv = SECU_FileToItem(&content, contentFile); 1.219 + if (contentFile != PR_STDIN) 1.220 + PR_Close(contentFile); 1.221 + if (rv != SECSuccess) 1.222 + content.data = NULL; 1.223 + } 1.224 + 1.225 + /* Signature Verification */ 1.226 + if (doVerify) { 1.227 + SEC_PKCS7ContentInfo *cinfo; 1.228 + SEC_PKCS7SignedData *signedData; 1.229 + HASH_HashType digestType; 1.230 + PRBool contentIsSigned; 1.231 + 1.232 + cinfo = SEC_PKCS7DecodeItem(&pkcs7der, NULL, NULL, NULL, NULL, 1.233 + NULL, NULL, NULL); 1.234 + if (cinfo == NULL) { 1.235 + PR_fprintf(PR_STDERR, "Unable to decode PKCS7 data\n"); 1.236 + goto cleanup; 1.237 + } 1.238 + /* below here, goto done */ 1.239 + 1.240 + contentIsSigned = SEC_PKCS7ContentIsSigned(cinfo); 1.241 + if (debugInfo) { 1.242 + PR_fprintf(PR_STDERR, "Content is%s encrypted.\n", 1.243 + SEC_PKCS7ContentIsEncrypted(cinfo) ? "" : " not"); 1.244 + } 1.245 + if (debugInfo || !contentIsSigned) { 1.246 + PR_fprintf(PR_STDERR, "Content is%s signed.\n", 1.247 + contentIsSigned ? "" : " not"); 1.248 + } 1.249 + 1.250 + if (!contentIsSigned) 1.251 + goto done; 1.252 + 1.253 + signedData = cinfo->content.signedData; 1.254 + 1.255 + /* assume that there is only one digest algorithm for now */ 1.256 + digestType = AlgorithmToHashType(signedData->digestAlgorithms[0]); 1.257 + if (digestType == HASH_AlgNULL) { 1.258 + PR_fprintf(PR_STDERR, "Invalid hash algorithmID\n"); 1.259 + goto done; 1.260 + } 1.261 + if (content.data) { 1.262 + SECCertUsage usage = certUsageEmailSigner; 1.263 + SECItem digest; 1.264 + unsigned char digestBuffer[HASH_LENGTH_MAX]; 1.265 + 1.266 + if (debugInfo) 1.267 + PR_fprintf(PR_STDERR, "contentToVerify=%s\n", content.data); 1.268 + 1.269 + digest.data = digestBuffer; 1.270 + digest.len = sizeof digestBuffer; 1.271 + 1.272 + if (DigestContent(&digest, &content, digestType)) { 1.273 + SECU_PrintError(progName, "Message digest computation failure"); 1.274 + goto done; 1.275 + } 1.276 + 1.277 + if (debugInfo) { 1.278 + unsigned int i; 1.279 + PR_fprintf(PR_STDERR, "Data Digest=:"); 1.280 + for (i = 0; i < digest.len; i++) 1.281 + PR_fprintf(PR_STDERR, "%02x:", digest.data[i]); 1.282 + PR_fprintf(PR_STDERR, "\n"); 1.283 + } 1.284 + 1.285 + fprintf(outFile, "signatureValid="); 1.286 + PORT_SetError(0); 1.287 + if (SEC_PKCS7VerifyDetachedSignature (cinfo, usage, 1.288 + &digest, digestType, PR_FALSE)) { 1.289 + fprintf(outFile, "yes"); 1.290 + } else { 1.291 + fprintf(outFile, "no"); 1.292 + if (verbose) { 1.293 + fprintf(outFile, ":%s", 1.294 + SECU_Strerror(PORT_GetError())); 1.295 + } 1.296 + } 1.297 + fprintf(outFile, "\n"); 1.298 + result = 0; 1.299 + } 1.300 +done: 1.301 + SEC_PKCS7DestroyContentInfo(cinfo); 1.302 + } 1.303 + 1.304 + if (displayAll) { 1.305 + if (SV_PrintPKCS7ContentInfo(outFile, &pkcs7der)) 1.306 + result = 1; 1.307 + } 1.308 + 1.309 +cleanup: 1.310 + SECITEM_FreeItem(&pkcs7der, PR_FALSE); 1.311 + SECITEM_FreeItem(&content, PR_FALSE); 1.312 + 1.313 + if (NSS_Shutdown() != SECSuccess) { 1.314 + result = 1; 1.315 + } 1.316 + 1.317 + return result; 1.318 +}