Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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 | #include "secutil.h" |
michael@0 | 6 | #include "plgetopt.h" |
michael@0 | 7 | #include "cert.h" |
michael@0 | 8 | #include "secoid.h" |
michael@0 | 9 | #include "cryptohi.h" |
michael@0 | 10 | |
michael@0 | 11 | /* maximum supported modulus length in bits (indicate problem if over this) */ |
michael@0 | 12 | #define MAX_MODULUS (1024) |
michael@0 | 13 | |
michael@0 | 14 | |
michael@0 | 15 | static void Usage(char *progName) |
michael@0 | 16 | { |
michael@0 | 17 | fprintf(stderr, "Usage: %s [aAvf] [certtocheck] [issuingcert]\n", |
michael@0 | 18 | progName); |
michael@0 | 19 | fprintf(stderr, "%-20s Cert to check is base64 encoded\n", |
michael@0 | 20 | "-a"); |
michael@0 | 21 | fprintf(stderr, "%-20s Issuer's cert is base64 encoded\n", |
michael@0 | 22 | "-A"); |
michael@0 | 23 | fprintf(stderr, "%-20s Verbose (indicate decoding progress etc.)\n", |
michael@0 | 24 | "-v"); |
michael@0 | 25 | fprintf(stderr, "%-20s Force sanity checks even if pretty print fails.\n", |
michael@0 | 26 | "-f"); |
michael@0 | 27 | fprintf(stderr, "%-20s Define an output file to use (default is stdout)\n", |
michael@0 | 28 | "-o output"); |
michael@0 | 29 | fprintf(stderr, "%-20s Specify the input type (no default)\n", |
michael@0 | 30 | "-t type"); |
michael@0 | 31 | exit(-1); |
michael@0 | 32 | } |
michael@0 | 33 | |
michael@0 | 34 | |
michael@0 | 35 | /* |
michael@0 | 36 | * Check integer field named fieldName, printing out results and |
michael@0 | 37 | * returning the length of the integer in bits |
michael@0 | 38 | */ |
michael@0 | 39 | |
michael@0 | 40 | static |
michael@0 | 41 | int checkInteger(SECItem *intItem, char *fieldName, int verbose) |
michael@0 | 42 | { |
michael@0 | 43 | int len, bitlen; |
michael@0 | 44 | if (verbose) { |
michael@0 | 45 | printf("Checking %s\n", fieldName); |
michael@0 | 46 | } |
michael@0 | 47 | |
michael@0 | 48 | len = intItem->len; |
michael@0 | 49 | |
michael@0 | 50 | if (len && (intItem->data[0] & 0x80)) { |
michael@0 | 51 | printf("PROBLEM: %s is NEGATIVE 2's-complement integer.\n", |
michael@0 | 52 | fieldName); |
michael@0 | 53 | } |
michael@0 | 54 | |
michael@0 | 55 | |
michael@0 | 56 | /* calculate bit length and check for unnecessary leading zeros */ |
michael@0 | 57 | bitlen = len << 3; |
michael@0 | 58 | if (len > 1 && intItem->data[0] == 0) { |
michael@0 | 59 | /* leading zero byte(s) */ |
michael@0 | 60 | if (!(intItem->data[1] & 0x80)) { |
michael@0 | 61 | printf("PROBLEM: %s has unneeded leading zeros. Violates DER.\n", |
michael@0 | 62 | fieldName); |
michael@0 | 63 | } |
michael@0 | 64 | /* strip leading zeros in length calculation */ |
michael@0 | 65 | { |
michael@0 | 66 | int i=0; |
michael@0 | 67 | while (bitlen > 8 && intItem->data[i] == 0) { |
michael@0 | 68 | bitlen -= 8; |
michael@0 | 69 | i++; |
michael@0 | 70 | } |
michael@0 | 71 | } |
michael@0 | 72 | } |
michael@0 | 73 | return bitlen; |
michael@0 | 74 | } |
michael@0 | 75 | |
michael@0 | 76 | |
michael@0 | 77 | |
michael@0 | 78 | |
michael@0 | 79 | static |
michael@0 | 80 | void checkName(CERTName *n, char *fieldName, int verbose) |
michael@0 | 81 | { |
michael@0 | 82 | char *v=0; |
michael@0 | 83 | if (verbose) { |
michael@0 | 84 | printf("Checking %s\n", fieldName); |
michael@0 | 85 | } |
michael@0 | 86 | |
michael@0 | 87 | v = CERT_GetCountryName(n); |
michael@0 | 88 | if (!v) { |
michael@0 | 89 | printf("PROBLEM: %s lacks Country Name (C)\n", |
michael@0 | 90 | fieldName); |
michael@0 | 91 | } |
michael@0 | 92 | PORT_Free(v); |
michael@0 | 93 | |
michael@0 | 94 | v = CERT_GetOrgName(n); |
michael@0 | 95 | if (!v) { |
michael@0 | 96 | printf("PROBLEM: %s lacks Organization Name (O)\n", |
michael@0 | 97 | fieldName); |
michael@0 | 98 | } |
michael@0 | 99 | PORT_Free(v); |
michael@0 | 100 | |
michael@0 | 101 | v = CERT_GetOrgUnitName(n); |
michael@0 | 102 | if (!v) { |
michael@0 | 103 | printf("WARNING: %s lacks Organization Unit Name (OU)\n", |
michael@0 | 104 | fieldName); |
michael@0 | 105 | } |
michael@0 | 106 | PORT_Free(v); |
michael@0 | 107 | |
michael@0 | 108 | v = CERT_GetCommonName(n); |
michael@0 | 109 | if (!v) { |
michael@0 | 110 | printf("PROBLEM: %s lacks Common Name (CN)\n", |
michael@0 | 111 | fieldName); |
michael@0 | 112 | } |
michael@0 | 113 | PORT_Free(v); |
michael@0 | 114 | } |
michael@0 | 115 | |
michael@0 | 116 | |
michael@0 | 117 | static |
michael@0 | 118 | SECStatus |
michael@0 | 119 | OurVerifyData(unsigned char *buf, int len, SECKEYPublicKey *key, |
michael@0 | 120 | SECItem *sig, SECAlgorithmID *sigAlgorithm) |
michael@0 | 121 | { |
michael@0 | 122 | SECStatus rv; |
michael@0 | 123 | VFYContext *cx; |
michael@0 | 124 | SECOidData *sigAlgOid, *oiddata; |
michael@0 | 125 | SECOidTag sigAlgTag; |
michael@0 | 126 | SECOidTag hashAlgTag; |
michael@0 | 127 | int showDigestOid=0; |
michael@0 | 128 | |
michael@0 | 129 | cx = VFY_CreateContextWithAlgorithmID(key, sig, sigAlgorithm, &hashAlgTag, |
michael@0 | 130 | NULL); |
michael@0 | 131 | if (cx == NULL) |
michael@0 | 132 | return SECFailure; |
michael@0 | 133 | |
michael@0 | 134 | sigAlgOid = SECOID_FindOID(&sigAlgorithm->algorithm); |
michael@0 | 135 | if (sigAlgOid == 0) |
michael@0 | 136 | return SECFailure; |
michael@0 | 137 | sigAlgTag = sigAlgOid->offset; |
michael@0 | 138 | |
michael@0 | 139 | |
michael@0 | 140 | if (showDigestOid) { |
michael@0 | 141 | oiddata = SECOID_FindOIDByTag(hashAlgTag); |
michael@0 | 142 | if ( oiddata ) { |
michael@0 | 143 | printf("PROBLEM: (cont) Digest OID is %s\n", oiddata->desc); |
michael@0 | 144 | } else { |
michael@0 | 145 | SECU_PrintAsHex(stdout, |
michael@0 | 146 | &oiddata->oid, "PROBLEM: UNKNOWN OID", 0); |
michael@0 | 147 | } |
michael@0 | 148 | } |
michael@0 | 149 | |
michael@0 | 150 | rv = VFY_Begin(cx); |
michael@0 | 151 | if (rv == SECSuccess) { |
michael@0 | 152 | rv = VFY_Update(cx, buf, len); |
michael@0 | 153 | if (rv == SECSuccess) |
michael@0 | 154 | rv = VFY_End(cx); |
michael@0 | 155 | } |
michael@0 | 156 | |
michael@0 | 157 | VFY_DestroyContext(cx, PR_TRUE); |
michael@0 | 158 | return rv; |
michael@0 | 159 | } |
michael@0 | 160 | |
michael@0 | 161 | |
michael@0 | 162 | |
michael@0 | 163 | static |
michael@0 | 164 | SECStatus |
michael@0 | 165 | OurVerifySignedData(CERTSignedData *sd, CERTCertificate *cert) |
michael@0 | 166 | { |
michael@0 | 167 | SECItem sig; |
michael@0 | 168 | SECKEYPublicKey *pubKey = 0; |
michael@0 | 169 | SECStatus rv; |
michael@0 | 170 | |
michael@0 | 171 | /* check the certificate's validity */ |
michael@0 | 172 | rv = CERT_CertTimesValid(cert); |
michael@0 | 173 | if ( rv ) { |
michael@0 | 174 | return(SECFailure); |
michael@0 | 175 | } |
michael@0 | 176 | |
michael@0 | 177 | /* get cert's public key */ |
michael@0 | 178 | pubKey = CERT_ExtractPublicKey(cert); |
michael@0 | 179 | if ( !pubKey ) { |
michael@0 | 180 | return(SECFailure); |
michael@0 | 181 | } |
michael@0 | 182 | |
michael@0 | 183 | /* check the signature */ |
michael@0 | 184 | sig = sd->signature; |
michael@0 | 185 | DER_ConvertBitString(&sig); |
michael@0 | 186 | rv = OurVerifyData(sd->data.data, sd->data.len, pubKey, &sig, |
michael@0 | 187 | &sd->signatureAlgorithm); |
michael@0 | 188 | |
michael@0 | 189 | SECKEY_DestroyPublicKey(pubKey); |
michael@0 | 190 | |
michael@0 | 191 | if ( rv ) { |
michael@0 | 192 | return(SECFailure); |
michael@0 | 193 | } |
michael@0 | 194 | |
michael@0 | 195 | return(SECSuccess); |
michael@0 | 196 | } |
michael@0 | 197 | |
michael@0 | 198 | |
michael@0 | 199 | |
michael@0 | 200 | |
michael@0 | 201 | static |
michael@0 | 202 | CERTCertificate *createEmptyCertificate(void) |
michael@0 | 203 | { |
michael@0 | 204 | PLArenaPool *arena = 0; |
michael@0 | 205 | CERTCertificate *c = 0; |
michael@0 | 206 | |
michael@0 | 207 | arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
michael@0 | 208 | if ( !arena ) { |
michael@0 | 209 | return 0; |
michael@0 | 210 | } |
michael@0 | 211 | |
michael@0 | 212 | |
michael@0 | 213 | c = (CERTCertificate *) PORT_ArenaZAlloc(arena, sizeof(CERTCertificate)); |
michael@0 | 214 | |
michael@0 | 215 | if (c) { |
michael@0 | 216 | c->referenceCount = 1; |
michael@0 | 217 | c->arena = arena; |
michael@0 | 218 | } else { |
michael@0 | 219 | PORT_FreeArena(arena,PR_TRUE); |
michael@0 | 220 | } |
michael@0 | 221 | |
michael@0 | 222 | return c; |
michael@0 | 223 | } |
michael@0 | 224 | |
michael@0 | 225 | |
michael@0 | 226 | |
michael@0 | 227 | |
michael@0 | 228 | int main(int argc, char **argv) |
michael@0 | 229 | { |
michael@0 | 230 | int rv, verbose=0, force=0; |
michael@0 | 231 | int ascii=0, issuerAscii=0; |
michael@0 | 232 | char *progName=0; |
michael@0 | 233 | PRFileDesc *inFile=0, *issuerCertFile=0; |
michael@0 | 234 | SECItem derCert, derIssuerCert; |
michael@0 | 235 | PLArenaPool *arena=0; |
michael@0 | 236 | CERTSignedData *signedData=0; |
michael@0 | 237 | CERTCertificate *cert=0, *issuerCert=0; |
michael@0 | 238 | SECKEYPublicKey *rsapubkey=0; |
michael@0 | 239 | SECAlgorithmID md5WithRSAEncryption, md2WithRSAEncryption; |
michael@0 | 240 | SECAlgorithmID sha1WithRSAEncryption, rsaEncryption; |
michael@0 | 241 | SECItem spk; |
michael@0 | 242 | int selfSigned=0; |
michael@0 | 243 | int invalid=0; |
michael@0 | 244 | char *inFileName = NULL, *issuerCertFileName = NULL; |
michael@0 | 245 | PLOptState *optstate; |
michael@0 | 246 | PLOptStatus status; |
michael@0 | 247 | |
michael@0 | 248 | PORT_Memset(&md5WithRSAEncryption, 0, sizeof(md5WithRSAEncryption)); |
michael@0 | 249 | PORT_Memset(&md2WithRSAEncryption, 0, sizeof(md2WithRSAEncryption)); |
michael@0 | 250 | PORT_Memset(&sha1WithRSAEncryption, 0, sizeof(sha1WithRSAEncryption)); |
michael@0 | 251 | PORT_Memset(&rsaEncryption, 0, sizeof(rsaEncryption)); |
michael@0 | 252 | |
michael@0 | 253 | progName = strrchr(argv[0], '/'); |
michael@0 | 254 | progName = progName ? progName+1 : argv[0]; |
michael@0 | 255 | |
michael@0 | 256 | optstate = PL_CreateOptState(argc, argv, "aAvf"); |
michael@0 | 257 | while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { |
michael@0 | 258 | switch (optstate->option) { |
michael@0 | 259 | case 'v': |
michael@0 | 260 | verbose = 1; |
michael@0 | 261 | break; |
michael@0 | 262 | |
michael@0 | 263 | case 'f': |
michael@0 | 264 | force = 1; |
michael@0 | 265 | break; |
michael@0 | 266 | |
michael@0 | 267 | case 'a': |
michael@0 | 268 | ascii = 1; |
michael@0 | 269 | break; |
michael@0 | 270 | |
michael@0 | 271 | case 'A': |
michael@0 | 272 | issuerAscii = 1; |
michael@0 | 273 | break; |
michael@0 | 274 | |
michael@0 | 275 | case '\0': |
michael@0 | 276 | if (!inFileName) |
michael@0 | 277 | inFileName = PL_strdup(optstate->value); |
michael@0 | 278 | else if (!issuerCertFileName) |
michael@0 | 279 | issuerCertFileName = PL_strdup(optstate->value); |
michael@0 | 280 | else |
michael@0 | 281 | Usage(progName); |
michael@0 | 282 | break; |
michael@0 | 283 | } |
michael@0 | 284 | } |
michael@0 | 285 | |
michael@0 | 286 | if (!inFileName || !issuerCertFileName || status == PL_OPT_BAD) { |
michael@0 | 287 | /* insufficient or excess args */ |
michael@0 | 288 | Usage(progName); |
michael@0 | 289 | } |
michael@0 | 290 | |
michael@0 | 291 | inFile = PR_Open(inFileName, PR_RDONLY, 0); |
michael@0 | 292 | if (!inFile) { |
michael@0 | 293 | fprintf(stderr, "%s: unable to open \"%s\" for reading\n", |
michael@0 | 294 | progName, inFileName); |
michael@0 | 295 | exit(1); |
michael@0 | 296 | } |
michael@0 | 297 | |
michael@0 | 298 | issuerCertFile = PR_Open(issuerCertFileName, PR_RDONLY, 0); |
michael@0 | 299 | if (!issuerCertFile) { |
michael@0 | 300 | fprintf(stderr, "%s: unable to open \"%s\" for reading\n", |
michael@0 | 301 | progName, issuerCertFileName); |
michael@0 | 302 | exit(1); |
michael@0 | 303 | } |
michael@0 | 304 | |
michael@0 | 305 | if (SECU_ReadDERFromFile(&derCert, inFile, ascii, PR_FALSE) != SECSuccess) { |
michael@0 | 306 | printf("Couldn't read input certificate as DER binary or base64\n"); |
michael@0 | 307 | exit(1); |
michael@0 | 308 | } |
michael@0 | 309 | |
michael@0 | 310 | arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
michael@0 | 311 | if (arena == 0) { |
michael@0 | 312 | fprintf(stderr,"%s: can't allocate scratch arena!", progName); |
michael@0 | 313 | exit(1); |
michael@0 | 314 | } |
michael@0 | 315 | |
michael@0 | 316 | if (issuerCertFile) { |
michael@0 | 317 | CERTSignedData *issuerCertSD=0; |
michael@0 | 318 | if (SECU_ReadDERFromFile(&derIssuerCert, issuerCertFile, issuerAscii, |
michael@0 | 319 | PR_FALSE) != SECSuccess) { |
michael@0 | 320 | printf("Couldn't read issuer certificate as DER binary or base64.\n"); |
michael@0 | 321 | exit(1); |
michael@0 | 322 | } |
michael@0 | 323 | issuerCertSD = PORT_ArenaZNew(arena, CERTSignedData); |
michael@0 | 324 | if (!issuerCertSD) { |
michael@0 | 325 | fprintf(stderr,"%s: can't allocate issuer signed data!", progName); |
michael@0 | 326 | exit(1); |
michael@0 | 327 | } |
michael@0 | 328 | rv = SEC_ASN1DecodeItem(arena, issuerCertSD, |
michael@0 | 329 | SEC_ASN1_GET(CERT_SignedDataTemplate), |
michael@0 | 330 | &derIssuerCert); |
michael@0 | 331 | if (rv) { |
michael@0 | 332 | fprintf(stderr, "%s: Issuer cert isn't X509 SIGNED Data?\n", |
michael@0 | 333 | progName); |
michael@0 | 334 | exit(1); |
michael@0 | 335 | } |
michael@0 | 336 | issuerCert = createEmptyCertificate(); |
michael@0 | 337 | if (!issuerCert) { |
michael@0 | 338 | printf("%s: can't allocate space for issuer cert.", progName); |
michael@0 | 339 | exit(1); |
michael@0 | 340 | } |
michael@0 | 341 | rv = SEC_ASN1DecodeItem(arena, issuerCert, |
michael@0 | 342 | SEC_ASN1_GET(CERT_CertificateTemplate), |
michael@0 | 343 | &issuerCertSD->data); |
michael@0 | 344 | if (rv) { |
michael@0 | 345 | printf("%s: Does not appear to be an X509 Certificate.\n", |
michael@0 | 346 | progName); |
michael@0 | 347 | exit(1); |
michael@0 | 348 | } |
michael@0 | 349 | } |
michael@0 | 350 | |
michael@0 | 351 | signedData = PORT_ArenaZNew(arena,CERTSignedData); |
michael@0 | 352 | if (!signedData) { |
michael@0 | 353 | fprintf(stderr,"%s: can't allocate signedData!", progName); |
michael@0 | 354 | exit(1); |
michael@0 | 355 | } |
michael@0 | 356 | |
michael@0 | 357 | rv = SEC_ASN1DecodeItem(arena, signedData, |
michael@0 | 358 | SEC_ASN1_GET(CERT_SignedDataTemplate), |
michael@0 | 359 | &derCert); |
michael@0 | 360 | if (rv) { |
michael@0 | 361 | fprintf(stderr, "%s: Does not appear to be X509 SIGNED Data.\n", |
michael@0 | 362 | progName); |
michael@0 | 363 | exit(1); |
michael@0 | 364 | } |
michael@0 | 365 | |
michael@0 | 366 | if (verbose) { |
michael@0 | 367 | printf("Decoded ok as X509 SIGNED data.\n"); |
michael@0 | 368 | } |
michael@0 | 369 | |
michael@0 | 370 | cert = createEmptyCertificate(); |
michael@0 | 371 | if (!cert) { |
michael@0 | 372 | fprintf(stderr, "%s: can't allocate cert", progName); |
michael@0 | 373 | exit(1); |
michael@0 | 374 | } |
michael@0 | 375 | |
michael@0 | 376 | rv = SEC_ASN1DecodeItem(arena, cert, |
michael@0 | 377 | SEC_ASN1_GET(CERT_CertificateTemplate), |
michael@0 | 378 | &signedData->data); |
michael@0 | 379 | if (rv) { |
michael@0 | 380 | fprintf(stderr, "%s: Does not appear to be an X509 Certificate.\n", |
michael@0 | 381 | progName); |
michael@0 | 382 | exit(1); |
michael@0 | 383 | } |
michael@0 | 384 | |
michael@0 | 385 | |
michael@0 | 386 | if (verbose) { |
michael@0 | 387 | printf("Decoded ok as an X509 certificate.\n"); |
michael@0 | 388 | } |
michael@0 | 389 | |
michael@0 | 390 | SECU_RegisterDynamicOids(); |
michael@0 | 391 | rv = SECU_PrintSignedData(stdout, &derCert, "Certificate", 0, |
michael@0 | 392 | SECU_PrintCertificate); |
michael@0 | 393 | |
michael@0 | 394 | if (rv) { |
michael@0 | 395 | fprintf(stderr, "%s: Unable to pretty print cert. Error: %d\n", |
michael@0 | 396 | progName, PORT_GetError()); |
michael@0 | 397 | if (!force) { |
michael@0 | 398 | exit(1); |
michael@0 | 399 | } |
michael@0 | 400 | } |
michael@0 | 401 | |
michael@0 | 402 | |
michael@0 | 403 | /* Do various checks on the cert */ |
michael@0 | 404 | |
michael@0 | 405 | printf("\n"); |
michael@0 | 406 | |
michael@0 | 407 | /* Check algorithms */ |
michael@0 | 408 | SECOID_SetAlgorithmID(arena, &md5WithRSAEncryption, |
michael@0 | 409 | SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION, NULL); |
michael@0 | 410 | |
michael@0 | 411 | SECOID_SetAlgorithmID(arena, &md2WithRSAEncryption, |
michael@0 | 412 | SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION, NULL); |
michael@0 | 413 | |
michael@0 | 414 | SECOID_SetAlgorithmID(arena, &sha1WithRSAEncryption, |
michael@0 | 415 | SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION, NULL); |
michael@0 | 416 | |
michael@0 | 417 | SECOID_SetAlgorithmID(arena, &rsaEncryption, |
michael@0 | 418 | SEC_OID_PKCS1_RSA_ENCRYPTION, NULL); |
michael@0 | 419 | |
michael@0 | 420 | { |
michael@0 | 421 | int isMD5RSA = (SECOID_CompareAlgorithmID(&cert->signature, |
michael@0 | 422 | &md5WithRSAEncryption) == 0); |
michael@0 | 423 | int isMD2RSA = (SECOID_CompareAlgorithmID(&cert->signature, |
michael@0 | 424 | &md2WithRSAEncryption) == 0); |
michael@0 | 425 | int isSHA1RSA = (SECOID_CompareAlgorithmID(&cert->signature, |
michael@0 | 426 | &sha1WithRSAEncryption) == 0); |
michael@0 | 427 | |
michael@0 | 428 | if (verbose) { |
michael@0 | 429 | printf("\nDoing algorithm checks.\n"); |
michael@0 | 430 | } |
michael@0 | 431 | |
michael@0 | 432 | if (!(isMD5RSA || isMD2RSA || isSHA1RSA)) { |
michael@0 | 433 | printf("PROBLEM: Signature not PKCS1 MD5, MD2, or SHA1 + RSA.\n"); |
michael@0 | 434 | } else if (!isMD5RSA) { |
michael@0 | 435 | printf("WARNING: Signature not PKCS1 MD5 with RSA Encryption\n"); |
michael@0 | 436 | } |
michael@0 | 437 | |
michael@0 | 438 | if (SECOID_CompareAlgorithmID(&cert->signature, |
michael@0 | 439 | &signedData->signatureAlgorithm)) { |
michael@0 | 440 | printf("PROBLEM: Algorithm in sig and certInfo don't match.\n"); |
michael@0 | 441 | } |
michael@0 | 442 | } |
michael@0 | 443 | |
michael@0 | 444 | if (SECOID_CompareAlgorithmID(&cert->subjectPublicKeyInfo.algorithm, |
michael@0 | 445 | &rsaEncryption)) { |
michael@0 | 446 | printf("PROBLEM: Public key algorithm is not PKCS1 RSA Encryption.\n"); |
michael@0 | 447 | } |
michael@0 | 448 | |
michael@0 | 449 | /* Check further public key properties */ |
michael@0 | 450 | spk = cert->subjectPublicKeyInfo.subjectPublicKey; |
michael@0 | 451 | DER_ConvertBitString(&spk); |
michael@0 | 452 | |
michael@0 | 453 | if (verbose) { |
michael@0 | 454 | printf("\nsubjectPublicKey DER\n"); |
michael@0 | 455 | rv = DER_PrettyPrint(stdout, &spk, PR_FALSE); |
michael@0 | 456 | printf("\n"); |
michael@0 | 457 | } |
michael@0 | 458 | |
michael@0 | 459 | rsapubkey = (SECKEYPublicKey *) |
michael@0 | 460 | PORT_ArenaZAlloc(arena,sizeof(SECKEYPublicKey)); |
michael@0 | 461 | if (!rsapubkey) { |
michael@0 | 462 | fprintf(stderr, "%s: rsapubkey allocation failed.\n", progName); |
michael@0 | 463 | exit(1); |
michael@0 | 464 | } |
michael@0 | 465 | |
michael@0 | 466 | rv = SEC_ASN1DecodeItem(arena, rsapubkey, |
michael@0 | 467 | SEC_ASN1_GET(SECKEY_RSAPublicKeyTemplate), &spk); |
michael@0 | 468 | if (rv) { |
michael@0 | 469 | printf("PROBLEM: subjectPublicKey is not a DER PKCS1 RSAPublicKey.\n"); |
michael@0 | 470 | } else { |
michael@0 | 471 | int mlen; |
michael@0 | 472 | int pubexp; |
michael@0 | 473 | if (verbose) { |
michael@0 | 474 | printf("Decoded RSA Public Key ok. Doing key checks.\n"); |
michael@0 | 475 | } |
michael@0 | 476 | PORT_Assert(rsapubkey->keyType == rsaKey); /* XXX RSA */ |
michael@0 | 477 | mlen = checkInteger(&rsapubkey->u.rsa.modulus, "Modulus", verbose); |
michael@0 | 478 | printf("INFO: Public Key modulus length in bits: %d\n", mlen); |
michael@0 | 479 | if (mlen > MAX_MODULUS) { |
michael@0 | 480 | printf("PROBLEM: Modulus length exceeds %d bits.\n", |
michael@0 | 481 | MAX_MODULUS); |
michael@0 | 482 | } |
michael@0 | 483 | if (mlen < 512) { |
michael@0 | 484 | printf("WARNING: Short modulus.\n"); |
michael@0 | 485 | } |
michael@0 | 486 | if (mlen != (1 << (ffs(mlen)-1))) { |
michael@0 | 487 | printf("WARNING: Unusual modulus length (not a power of two).\n"); |
michael@0 | 488 | } |
michael@0 | 489 | checkInteger(&rsapubkey->u.rsa.publicExponent, "Public Exponent", |
michael@0 | 490 | verbose); |
michael@0 | 491 | pubexp = DER_GetInteger(&rsapubkey->u.rsa.publicExponent); |
michael@0 | 492 | if (pubexp != 17 && pubexp != 3 && pubexp != 65537) { |
michael@0 | 493 | printf("WARNING: Public exponent not any of: 3, 17, 65537\n"); |
michael@0 | 494 | } |
michael@0 | 495 | } |
michael@0 | 496 | |
michael@0 | 497 | |
michael@0 | 498 | /* Name checks */ |
michael@0 | 499 | checkName(&cert->issuer, "Issuer Name", verbose); |
michael@0 | 500 | checkName(&cert->subject, "Subject Name", verbose); |
michael@0 | 501 | |
michael@0 | 502 | if (issuerCert) { |
michael@0 | 503 | SECComparison c = |
michael@0 | 504 | CERT_CompareName(&cert->issuer, &issuerCert->subject); |
michael@0 | 505 | if (c) { |
michael@0 | 506 | printf("PROBLEM: Issuer Name and Subject in Issuing Cert differ\n"); |
michael@0 | 507 | } |
michael@0 | 508 | } |
michael@0 | 509 | |
michael@0 | 510 | /* Check if self-signed */ |
michael@0 | 511 | selfSigned = (CERT_CompareName(&cert->issuer, &cert->subject) == 0); |
michael@0 | 512 | if (selfSigned) { |
michael@0 | 513 | printf("INFO: Certificate is self signed.\n"); |
michael@0 | 514 | } else { |
michael@0 | 515 | printf("INFO: Certificate is NOT self-signed.\n"); |
michael@0 | 516 | } |
michael@0 | 517 | |
michael@0 | 518 | |
michael@0 | 519 | /* Validity time check */ |
michael@0 | 520 | if (CERT_CertTimesValid(cert) == SECSuccess) { |
michael@0 | 521 | printf("INFO: Inside validity period of certificate.\n"); |
michael@0 | 522 | } else { |
michael@0 | 523 | printf("PROBLEM: Not in validity period of certificate.\n"); |
michael@0 | 524 | invalid = 1; |
michael@0 | 525 | } |
michael@0 | 526 | |
michael@0 | 527 | /* Signature check if self-signed */ |
michael@0 | 528 | if (selfSigned && !invalid) { |
michael@0 | 529 | if (rsapubkey->u.rsa.modulus.len) { |
michael@0 | 530 | SECStatus ver; |
michael@0 | 531 | if (verbose) { |
michael@0 | 532 | printf("Checking self signature.\n"); |
michael@0 | 533 | } |
michael@0 | 534 | ver = OurVerifySignedData(signedData, cert); |
michael@0 | 535 | if (ver != SECSuccess) { |
michael@0 | 536 | printf("PROBLEM: Verification of self-signature failed!\n"); |
michael@0 | 537 | } else { |
michael@0 | 538 | printf("INFO: Self-signature verifies ok.\n"); |
michael@0 | 539 | } |
michael@0 | 540 | } else { |
michael@0 | 541 | printf("INFO: Not checking signature due to key problems.\n"); |
michael@0 | 542 | } |
michael@0 | 543 | } else if (!selfSigned && !invalid && issuerCert) { |
michael@0 | 544 | SECStatus ver; |
michael@0 | 545 | ver = OurVerifySignedData(signedData, issuerCert); |
michael@0 | 546 | if (ver != SECSuccess) { |
michael@0 | 547 | printf("PROBLEM: Verification of issuer's signature failed!\n"); |
michael@0 | 548 | } else { |
michael@0 | 549 | printf("INFO: Issuer's signature verifies ok.\n"); |
michael@0 | 550 | } |
michael@0 | 551 | } else { |
michael@0 | 552 | printf("INFO: Not checking signature.\n"); |
michael@0 | 553 | } |
michael@0 | 554 | |
michael@0 | 555 | return 0; |
michael@0 | 556 | } |
michael@0 | 557 | |
michael@0 | 558 | |
michael@0 | 559 |