static SECOidTag
register_oid(const SECItem *oid_item, const char *oid_name)
{
  if (!oid_item)
    return SEC_OID_UNKNOWN;

  SECOidData od;
  od.oid.len = oid_item->len;
  od.oid.data = oid_item->data;
  od.offset = SEC_OID_UNKNOWN;
  od.desc = oid_name;
  od.mechanism = CKM_INVALID_MECHANISM;
  od.supportedExtension = INVALID_CERT_EXTENSION;
  return SECOID_AddEntry(&od);
}
Пример #2
0
int
main(int argc, char *argv[], char *envp[])
{
    char *               certDir      = NULL;
    char *               progName     = NULL;
    char *               oidStr       = NULL;
    CERTCertificate *    cert;
    CERTCertificate *    firstCert    = NULL;
    CERTCertificate *    issuerCert   = NULL;
    CERTCertDBHandle *   defaultDB    = NULL;
    PRBool               isAscii      = PR_FALSE;
    PRBool               trusted      = PR_FALSE;
    SECStatus            secStatus;
    SECCertificateUsage  certUsage    = certificateUsageSSLServer;
    PLOptState *         optstate;
    PRTime               time         = 0;
    PLOptStatus          status;
    int                  usePkix      = 0;
    int                  rv           = 1;
    int                  usage;
    CERTVerifyLog        log;
    CERTCertList        *builtChain = NULL;
    PRBool               certFetching = PR_FALSE;
    int                  revDataIndex = 0;
    PRBool               ocsp_fetchingFailureIsAFailure = PR_TRUE;
    PRBool               useDefaultRevFlags = PR_TRUE;
    int                  vfyCounts = 1;

    PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);

    progName = PL_strdup(argv[0]);

    optstate = PL_CreateOptState(argc, argv, "ab:c:d:efg:h:i:m:o:prs:tu:vw:W:");
    while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
	switch(optstate->option) {
	case  0  : /* positional parameter */  goto breakout;
	case 'a' : isAscii  = PR_TRUE;                        break;
	case 'b' : secStatus = DER_AsciiToTime(&time, optstate->value);
	           if (secStatus != SECSuccess) Usage(progName); break;
	case 'd' : certDir  = PL_strdup(optstate->value);     break;
	case 'e' : ocsp_fetchingFailureIsAFailure = PR_FALSE;  break;
	case 'f' : certFetching = PR_TRUE;                    break;
	case 'g' : 
                   if (revMethodsData[revDataIndex].testTypeStr ||
                       revMethodsData[revDataIndex].methodTypeStr) {
                       revDataIndex += 1;
                       if (revDataIndex == REV_METHOD_INDEX_MAX) {
                           fprintf(stderr, "Invalid revocation configuration"
                                   "specified.\n");
                           secStatus = SECFailure;
                           break;
                       }
                   }
                   useDefaultRevFlags = PR_FALSE;
                   revMethodsData[revDataIndex].
                       testTypeStr = PL_strdup(optstate->value); break;
	case 'h' : 
                   revMethodsData[revDataIndex].
                       testFlagsStr = PL_strdup(optstate->value);break;
        case 'i' : vfyCounts = PORT_Atoi(optstate->value);       break;
                   break;
	case 'm' : 
                   if (revMethodsData[revDataIndex].methodTypeStr) {
                       revDataIndex += 1;
                       if (revDataIndex == REV_METHOD_INDEX_MAX) {
                           fprintf(stderr, "Invalid revocation configuration"
                                   "specified.\n");
                           secStatus = SECFailure;
                           break;
                       }
                   }
                   useDefaultRevFlags = PR_FALSE;
                   revMethodsData[revDataIndex].
                       methodTypeStr = PL_strdup(optstate->value); break;
	case 'o' : oidStr = PL_strdup(optstate->value);       break;
	case 'p' : usePkix += 1;                              break;
	case 'r' : isAscii  = PR_FALSE;                       break;
	case 's' : 
                   revMethodsData[revDataIndex].
                       methodFlagsStr = PL_strdup(optstate->value); break;
	case 't' : trusted  = PR_TRUE;                        break;
	case 'u' : usage    = PORT_Atoi(optstate->value);
	           if (usage < 0 || usage > 62) Usage(progName);
		   certUsage = ((SECCertificateUsage)1) << usage; 
		   if (certUsage > certificateUsageHighest) Usage(progName);
		   break;
        case 'w':
                  pwdata.source = PW_PLAINTEXT;
                  pwdata.data = PORT_Strdup(optstate->value);
                  break;

        case 'W':
                  pwdata.source = PW_FROMFILE;
                  pwdata.data = PORT_Strdup(optstate->value);
                  break;
	case 'v' : verbose++;                                 break;
	default  : Usage(progName);                           break;
	}
    }
breakout:
    if (status != PL_OPT_OK)
	Usage(progName);

    if (usePkix < 2) {
        if (oidStr) {
            fprintf(stderr, "Policy oid(-o) can be used only with"
                    " CERT_PKIXVerifyChain(-pp) function.\n");
            Usage(progName);
        }
        if (trusted) {
            fprintf(stderr, "Cert trust flag can be used only with"
                    " CERT_PKIXVerifyChain(-pp) function.\n");
            Usage(progName);
        }
    }

    if (!useDefaultRevFlags && parseRevMethodsAndFlags()) {
        fprintf(stderr, "Invalid revocation configuration specified.\n");
        goto punt;
    }

    /* Set our password function callback. */
    PK11_SetPasswordFunc(SECU_GetModulePassword);

    /* Initialize the NSS libraries. */
    if (certDir) {
	secStatus = NSS_Init(certDir);
    } else {
	secStatus = NSS_NoDB_Init(NULL);

	/* load the builtins */
	SECMOD_AddNewModule("Builtins", DLL_PREFIX"nssckbi."DLL_SUFFIX, 0, 0);
    }
    if (secStatus != SECSuccess) {
	exitErr("NSS_Init");
    }
    SECU_RegisterDynamicOids();
    if (isOCSPEnabled()) {
        CERT_EnableOCSPChecking(CERT_GetDefaultCertDB());
        CERT_DisableOCSPDefaultResponder(CERT_GetDefaultCertDB());
        if (!ocsp_fetchingFailureIsAFailure) {
            CERT_SetOCSPFailureMode(ocspMode_FailureIsNotAVerificationFailure);
        }
    }

    while (status == PL_OPT_OK) {
	switch(optstate->option) {
	default  : Usage(progName);                           break;
	case 'a' : isAscii  = PR_TRUE;                        break;
	case 'r' : isAscii  = PR_FALSE;                       break;
	case 't' : trusted  = PR_TRUE;                       break;
	case  0  : /* positional parameter */
            if (usePkix < 2 && trusted) {
                fprintf(stderr, "Cert trust flag can be used only with"
                        " CERT_PKIXVerifyChain(-pp) function.\n");
                Usage(progName);
            }
	    cert = getCert(optstate->value, isAscii, progName);
	    if (!cert) 
	        goto punt;
	    rememberCert(cert, trusted);
	    if (!firstCert)
	        firstCert = cert;
            trusted = PR_FALSE;
	}
        status = PL_GetNextOpt(optstate);
    }
    PL_DestroyOptState(optstate);
    if (status == PL_OPT_BAD || !firstCert)
	Usage(progName);

    /* Initialize log structure */
    log.arena = PORT_NewArena(512);
    log.head = log.tail = NULL;
    log.count = 0;

    do {
        if (usePkix < 2) {
            /* NOW, verify the cert chain. */
            if (usePkix) {
                /* Use old API with libpkix validation lib */
                CERT_SetUsePKIXForValidation(PR_TRUE);
            }
            if (!time)
                time = PR_Now();

            defaultDB = CERT_GetDefaultCertDB();
            secStatus = CERT_VerifyCertificate(defaultDB, firstCert, 
                                               PR_TRUE /* check sig */,
                                               certUsage, 
                                               time,
                                               &pwdata, /* wincx  */
                                               &log, /* error log */
                                           NULL);/* returned usages */
        } else do {
                static CERTValOutParam cvout[4];
                static CERTValInParam cvin[6];
                SECOidTag oidTag;
                int inParamIndex = 0;
                static PRUint64 revFlagsLeaf[2];
                static PRUint64 revFlagsChain[2];
                static CERTRevocationFlags rev;
                
                if (oidStr) {
                    PRArenaPool *arena;
                    SECOidData od;
                    memset(&od, 0, sizeof od);
                    od.offset = SEC_OID_UNKNOWN;
                    od.desc = "User Defined Policy OID";
                    od.mechanism = CKM_INVALID_MECHANISM;
                    od.supportedExtension = INVALID_CERT_EXTENSION;

                    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
                    if ( !arena ) {
                        fprintf(stderr, "out of memory");
                        goto punt;
                    }
                    
                    secStatus = SEC_StringToOID(arena, &od.oid, oidStr, 0);
                    if (secStatus != SECSuccess) {
                        PORT_FreeArena(arena, PR_FALSE);
                        fprintf(stderr, "Can not encode oid: %s(%s)\n", oidStr,
                                SECU_Strerror(PORT_GetError()));
                        break;
                    }
                    
                    oidTag = SECOID_AddEntry(&od);
                    PORT_FreeArena(arena, PR_FALSE);
                    if (oidTag == SEC_OID_UNKNOWN) {
                        fprintf(stderr, "Can not add new oid to the dynamic "
                                "table: %s\n", oidStr);
                        secStatus = SECFailure;
                        break;
                    }
                    
                    cvin[inParamIndex].type = cert_pi_policyOID;
                    cvin[inParamIndex].value.arraySize = 1;
                    cvin[inParamIndex].value.array.oids = &oidTag;
                    
                    inParamIndex++;
                }
                
                if (trustedCertList) {
                    cvin[inParamIndex].type = cert_pi_trustAnchors;
                    cvin[inParamIndex].value.pointer.chain = trustedCertList;
                    
                    inParamIndex++;
                }
                
                cvin[inParamIndex].type = cert_pi_useAIACertFetch;
                cvin[inParamIndex].value.scalar.b = certFetching;
                inParamIndex++;
                
                rev.leafTests.cert_rev_flags_per_method = revFlagsLeaf;
                rev.chainTests.cert_rev_flags_per_method = revFlagsChain;
                secStatus = configureRevocationParams(&rev);
                if (secStatus) {
                    fprintf(stderr, "Can not config revocation parameters ");
                    break;
                }
                
                cvin[inParamIndex].type = cert_pi_revocationFlags;
                cvin[inParamIndex].value.pointer.revocation = &rev;
                inParamIndex++;
                
                if (time) {
                    cvin[inParamIndex].type = cert_pi_date;
                    cvin[inParamIndex].value.scalar.time = time;
                    inParamIndex++;
                }
                
                cvin[inParamIndex].type = cert_pi_end;
                
                cvout[0].type = cert_po_trustAnchor;
                cvout[0].value.pointer.cert = NULL;
                cvout[1].type = cert_po_certList;
                cvout[1].value.pointer.chain = NULL;
                
                /* setting pointer to CERTVerifyLog. Initialized structure
                 * will be used CERT_PKIXVerifyCert */
                cvout[2].type = cert_po_errorLog;
                cvout[2].value.pointer.log = &log;
                
                cvout[3].type = cert_po_end;
                
                secStatus = CERT_PKIXVerifyCert(firstCert, certUsage,
                                                cvin, cvout, &pwdata);
                if (secStatus != SECSuccess) {
                    break;
                }
                issuerCert = cvout[0].value.pointer.cert;
                builtChain = cvout[1].value.pointer.chain;
            } while (0);
        
        /* Display validation results */
        if (secStatus != SECSuccess || log.count > 0) {
            CERTVerifyLogNode *node = NULL;
            PRIntn err = PR_GetError();
            fprintf(stderr, "Chain is bad, %d = %s\n", err, SECU_Strerror(err));
            
            SECU_displayVerifyLog(stderr, &log, verbose); 
            /* Have cert refs in the log only in case of failure.
             * Destroy them. */
            for (node = log.head; node; node = node->next) {
                if (node->cert)
                    CERT_DestroyCertificate(node->cert);
            }
            rv = 1;
        } else {
            fprintf(stderr, "Chain is good!\n");
            if (issuerCert) {
                if (verbose > 1) {
                    rv = SEC_PrintCertificateAndTrust(issuerCert, "Root Certificate",
                                                      NULL);
                    if (rv != SECSuccess) {
                        SECU_PrintError(progName, "problem printing certificate");
                    }
                } else if (verbose > 0) {
                    SECU_PrintName(stdout, &issuerCert->subject, "Root "
                                   "Certificate Subject:", 0);
                }
                CERT_DestroyCertificate(issuerCert);
            }
            if (builtChain) {
                CERTCertListNode *node;
                int count = 0;
                char buff[256];
                
                if (verbose) { 
                    for(node = CERT_LIST_HEAD(builtChain); !CERT_LIST_END(node, builtChain);
                        node = CERT_LIST_NEXT(node), count++ ) {
                        sprintf(buff, "Certificate %d Subject", count + 1);
                        SECU_PrintName(stdout, &node->cert->subject, buff, 0);
                    }
                }
                CERT_DestroyCertList(builtChain);
            }
            rv = 0;
        }
    } while (--vfyCounts > 0);

    /* Need to destroy CERTVerifyLog arena at the end */
    PORT_FreeArena(log.arena, PR_FALSE);

punt:
    forgetCerts();
    if (NSS_Shutdown() != SECSuccess) {
	SECU_PrintError(progName, "NSS_Shutdown");
	rv = 1;
    }
    PORT_Free(progName);
    PORT_Free(certDir);
    PORT_Free(oidStr);
    freeRevocationMethodData();
    if (pwdata.data) {
        PORT_Free(pwdata.data);
    }
    PR_Cleanup();
    return rv;
}