p7verify.c (7895B)
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 * p7verify -- A command to do a verification of a *detached* pkcs7 signature. 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 "secoid.h" 16 #include "sechash.h" /* for HASH_GetHashObject() */ 17 #include "nss.h" 18 19 #if defined(XP_UNIX) 20 #include <unistd.h> 21 #endif 22 23 #include <stdio.h> 24 #include <string.h> 25 26 #if (defined(XP_WIN) && !defined(WIN32)) || (defined(__sun) && !defined(SVR4)) 27 extern int fread(char *, size_t, size_t, FILE *); 28 extern int fprintf(FILE *, char *, ...); 29 #endif 30 31 static int 32 DigestFile(unsigned char *digest, unsigned int *len, unsigned int maxLen, 33 FILE *inFile, HASH_HashType hashType) 34 { 35 int nb; 36 unsigned char ibuf[4096]; 37 const SECHashObject *hashObj; 38 void *hashcx; 39 40 hashObj = HASH_GetHashObject(hashType); 41 42 hashcx = (*hashObj->create)(); 43 if (hashcx == NULL) 44 return -1; 45 46 (*hashObj->begin)(hashcx); 47 48 for (;;) { 49 if (feof(inFile)) 50 break; 51 nb = fread(ibuf, 1, sizeof(ibuf), inFile); 52 if (nb != sizeof(ibuf)) { 53 if (nb == 0) { 54 if (ferror(inFile)) { 55 PORT_SetError(SEC_ERROR_IO); 56 (*hashObj->destroy)(hashcx, PR_TRUE); 57 return -1; 58 } 59 /* eof */ 60 break; 61 } 62 } 63 (*hashObj->update)(hashcx, ibuf, nb); 64 } 65 66 (*hashObj->end)(hashcx, digest, len, maxLen); 67 (*hashObj->destroy)(hashcx, PR_TRUE); 68 69 return 0; 70 } 71 72 static void 73 Usage(char *progName) 74 { 75 fprintf(stderr, 76 "Usage: %s -c content -s signature [-d dbdir] [-u certusage]\n", 77 progName); 78 fprintf(stderr, "%-20s content file that was signed\n", 79 "-c content"); 80 fprintf(stderr, "%-20s file containing signature for that content\n", 81 "-s signature"); 82 fprintf(stderr, 83 "%-20s Key/Cert database directory (default is ~/.netscape)\n", 84 "-d dbdir"); 85 fprintf(stderr, "%-20s Define the type of certificate usage (default is certUsageEmailSigner)\n", 86 "-u certusage"); 87 fprintf(stderr, "%-25s 0 - certUsageSSLClient\n", " "); 88 fprintf(stderr, "%-25s 1 - certUsageSSLServer\n", " "); 89 fprintf(stderr, "%-25s 2 - certUsageSSLServerWithStepUp\n", " "); 90 fprintf(stderr, "%-25s 3 - certUsageSSLCA\n", " "); 91 fprintf(stderr, "%-25s 4 - certUsageEmailSigner\n", " "); 92 fprintf(stderr, "%-25s 5 - certUsageEmailRecipient\n", " "); 93 fprintf(stderr, "%-25s 6 - certUsageObjectSigner\n", " "); 94 fprintf(stderr, "%-25s 7 - certUsageUserCertImport\n", " "); 95 fprintf(stderr, "%-25s 8 - certUsageVerifyCA\n", " "); 96 fprintf(stderr, "%-25s 9 - certUsageProtectedObjectSigner\n", " "); 97 fprintf(stderr, "%-25s 10 - certUsageStatusResponder\n", " "); 98 fprintf(stderr, "%-25s 11 - certUsageAnyCA\n", " "); 99 fprintf(stderr, "%-25s 12 - certUsageIPsec\n", " "); 100 101 exit(-1); 102 } 103 104 static int 105 HashDecodeAndVerify(FILE *out, FILE *content, PRFileDesc *signature, 106 SECCertUsage usage, char *progName) 107 { 108 SECItem derdata; 109 SEC_PKCS7ContentInfo *cinfo; 110 SEC_PKCS7SignedData *signedData; 111 HASH_HashType digestType; 112 SECItem digest; 113 unsigned char buffer[32]; 114 115 if (SECU_ReadDERFromFile(&derdata, signature, PR_FALSE, 116 PR_FALSE) != SECSuccess) { 117 SECU_PrintError(progName, "error reading signature file"); 118 return -1; 119 } 120 121 cinfo = SEC_PKCS7DecodeItem(&derdata, NULL, NULL, NULL, NULL, 122 NULL, NULL, NULL); 123 if (cinfo == NULL) 124 return -1; 125 126 if (!SEC_PKCS7ContentIsSigned(cinfo)) { 127 fprintf(out, "Signature file is pkcs7 data, but not signed.\n"); 128 return -1; 129 } 130 131 signedData = cinfo->content.signedData; 132 133 /* assume that there is only one digest algorithm for now */ 134 digestType = HASH_GetHashTypeByOidTag( 135 SECOID_GetAlgorithmTag(signedData->digestAlgorithms[0])); 136 if (digestType == HASH_AlgNULL) { 137 fprintf(out, "Invalid hash algorithmID\n"); 138 return -1; 139 } 140 141 digest.data = buffer; 142 if (DigestFile(digest.data, &digest.len, 32, content, digestType)) { 143 SECU_PrintError(progName, "problem computing message digest"); 144 return -1; 145 } 146 147 fprintf(out, "Signature is "); 148 if (SEC_PKCS7VerifyDetachedSignature(cinfo, usage, &digest, digestType, 149 PR_FALSE)) 150 fprintf(out, "valid.\n"); 151 else 152 fprintf(out, "invalid (Reason: %s).\n", 153 SECU_Strerror(PORT_GetError())); 154 155 SECITEM_FreeItem(&derdata, PR_FALSE); 156 SEC_PKCS7DestroyContentInfo(cinfo); 157 return 0; 158 } 159 160 int 161 main(int argc, char **argv) 162 { 163 char *progName; 164 FILE *contentFile, *outFile; 165 PRFileDesc *signatureFile; 166 SECCertUsage certUsage = certUsageEmailSigner; 167 PLOptState *optstate; 168 PLOptStatus status; 169 SECStatus rv; 170 171 progName = strrchr(argv[0], '/'); 172 progName = progName ? progName + 1 : argv[0]; 173 174 contentFile = NULL; 175 signatureFile = NULL; 176 outFile = NULL; 177 178 /* 179 * Parse command line arguments 180 */ 181 optstate = PL_CreateOptState(argc, argv, "c:d:o:s:u:"); 182 while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { 183 switch (optstate->option) { 184 case '?': 185 Usage(progName); 186 break; 187 188 case 'c': 189 contentFile = fopen(optstate->value, "r"); 190 if (!contentFile) { 191 fprintf(stderr, "%s: unable to open \"%s\" for reading\n", 192 progName, optstate->value); 193 return -1; 194 } 195 break; 196 197 case 'd': 198 SECU_ConfigDirectory(optstate->value); 199 break; 200 201 case 'o': 202 outFile = fopen(optstate->value, "w"); 203 if (!outFile) { 204 fprintf(stderr, "%s: unable to open \"%s\" for writing\n", 205 progName, optstate->value); 206 return -1; 207 } 208 break; 209 210 case 's': 211 signatureFile = PR_Open(optstate->value, PR_RDONLY, 0); 212 if (!signatureFile) { 213 fprintf(stderr, "%s: unable to open \"%s\" for reading\n", 214 progName, optstate->value); 215 return -1; 216 } 217 break; 218 219 case 'u': { 220 int usageType; 221 222 usageType = atoi(optstate->value); 223 if (usageType < certUsageSSLClient || usageType > certUsageIPsec) 224 return -1; 225 certUsage = (SECCertUsage)usageType; 226 break; 227 } 228 } 229 } 230 PL_DestroyOptState(optstate); 231 232 if (!contentFile) 233 Usage(progName); 234 if (!signatureFile) 235 Usage(progName); 236 if (!outFile) 237 outFile = stdout; 238 239 /* Call the NSS initialization routines */ 240 PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); 241 rv = NSS_Init(SECU_ConfigDirectory(NULL)); 242 if (rv != SECSuccess) { 243 SECU_PrintPRandOSError(progName); 244 return -1; 245 } 246 247 if (HashDecodeAndVerify(outFile, contentFile, signatureFile, 248 certUsage, progName)) { 249 SECU_PrintError(progName, "problem decoding/verifying signature"); 250 return -1; 251 } 252 253 fclose(contentFile); 254 PR_Close(signatureFile); 255 if (outFile && outFile != stdout) { 256 fclose(outFile); 257 } 258 259 if (NSS_Shutdown() != SECSuccess) { 260 exit(1); 261 } 262 263 return 0; 264 }