Open Bug 592978 Opened 14 years ago Updated 2 years ago

CERT_PKIXVerifyCert() with "certificateUsageSSLServer" returns error but still log->count is 0

Categories

(NSS :: Libraries, defect)

Sun
Solaris
defect

Tracking

(Not tracked)

UNCONFIRMED

People

(Reporter: u238590, Unassigned)

Details

Attachments

(1 file)

User-Agent: Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.9.2.6) Gecko/20100627 Firefox/3.6.6 Build Identifier: SECURITY_3.12.6_20100315 Run the program attached in this bug. You get error SEC_ERROR_INVALID_ARGS but CERTVerifyLog *log count is zero. So we do not know what the real problem is. CERT_PKIXVerifyCert(certificateUsageSSLServer) returned ERROR !!! Error = -8187 Note -8187 => SEC_ERROR_INVALID_ARGS . log->count is 0 Reproducible: Always Steps to Reproduce: 1.export LD_LIBRARY_PATH=/share/builds/components/security/SECURITY_3.12.6_20100315/SunOS5.8_DBG.OBJ/lib:$LD_LIBRARY_PATH 2. /usr/dist/share/sunstudio_sparc,v12.0/SUNWspro/bin/CC -g -I -I/share/builds/components/security/SECURITY_3.12.6_20100315/SunOS5.8_DBG.OBJ//include -L/share/builds/components/security/SECURITY_3.12.6_20100315/SunOS5.8_DBG.OBJ//lib -lnspr4 -lnss3 server.cpp 3. ./a.out Actual Results: CERT_PKIXVerifyCert(certificateUsageSSLServer) returned ERROR !!! Error = -8187 Note -8187 => SEC_ERROR_INVALID_ARGS . log->count is 0 Expected Results: log count should not be zero. And we should see a proper message why this certificate is not a valid "server" certificate. Note if arg is "certificateUsageSSLServerWithStepUp" in CERT_PKIXVerifyCert(), we get proper error message : CERT_PKIXVerifyCert(certificateUsageSSLServer) returned ERROR !!! Error = -8102 Note -8102 => SEC_ERROR_INADEQUATE_KEY_USAGE. log->count is 1 certificate=Server-Cert depth node->error=-8102 Unknown Issue Note -8102=> SEC_ERROR_INADEQUATE_KEY_USAGE $cat server.cpp #include "nspr.h" #include "ssl.h" #include "certdb.h" #include <stdarg.h> #include <stdio.h> #include <string.h> #include "cert.h" #include "nspr.h" #include "prerror.h" #include "ssl.h" #include "certt.h" #include "nss.h" #include "pk11pub.h" #include "secerr.h" #include "sslerr.h" #define NSS_DB_PATH "." #define CERT_NICKNAME "Server-Cert" void printError(void) { int e = PR_GetError(); if (e != 0) printf("\tError = %d\n", e); int ose = PR_GetOSError(); if (ose != 0) printf("\tOS Error = %d\n", PR_GetOSError()); PRInt32 len = PR_GetErrorTextLength(); if (len > 0) { char arr[1024]; memset(arr,'\0',1024); PR_GetErrorText(arr); printf("\tErrorTxt = %s\n", arr); } if (e == SEC_ERROR_INADEQUATE_KEY_USAGE) printf("\tNote %d => SEC_ERROR_INADEQUATE_KEY_USAGE.\n", e); else if (e == SEC_ERROR_INVALID_ARGS ) printf("\tNote %d => SEC_ERROR_INVALID_ARGS .\n", e); } char * parseArg(CERTVerifyLogNode *node) { char *errstr = NULL; char *issuer = NULL; unsigned int flags = 0; switch (node->error) { case SEC_ERROR_INADEQUATE_KEY_USAGE: flags = (unsigned int)((unsigned long)node->arg); switch (flags) { case KU_DIGITAL_SIGNATURE: errstr = strdup("Certificate cannot sign."); break; case KU_KEY_ENCIPHERMENT: errstr = strdup("Certificate cannot encrypt."); break; case KU_KEY_CERT_SIGN: errstr = strdup("Certificate cannot sign other certs."); break; default: errstr = strdup("[unknown usage]."); break; } case SEC_ERROR_INADEQUATE_CERT_TYPE: flags = (unsigned int)((unsigned long)node->arg); switch (flags) { case NS_CERT_TYPE_SSL_CLIENT: case NS_CERT_TYPE_SSL_SERVER: errstr = strdup("Certificate cannot be used for SSL."); break; case NS_CERT_TYPE_SSL_CA: errstr = strdup("Certificate cannot be used as an SSL CA."); break; case NS_CERT_TYPE_EMAIL: errstr = strdup("Certificate cannot be used for SMIME."); break; case NS_CERT_TYPE_EMAIL_CA: errstr = strdup("Certificate cannot be used as an SMIME CA."); break; case NS_CERT_TYPE_OBJECT_SIGNING: errstr = strdup("Certificate cannot be used for object signing."); break; case NS_CERT_TYPE_OBJECT_SIGNING_CA: errstr = strdup("Certificate cannot be used as an object signing CA."); break; default: errstr = strdup("[unknown usage]."); break; } case SEC_ERROR_UNKNOWN_ISSUER: errstr = "Unknown Issuer"; issuer = node->cert->issuerName; break; case SEC_ERROR_UNTRUSTED_ISSUER: errstr = "Untrusted Issuer"; issuer = node->cert->issuerName; break; case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: errstr = "Expired Issuer Certificate"; issuer = node->cert->issuerName; break; default: break; } int len = errstr?strlen(errstr):0 + issuer?strlen(issuer):0 + 3; char *arr = (char *)malloc(len); memset(arr,'\0',len); sprintf(arr,"%s %s", errstr?errstr:"", issuer?issuer:""); arr[len-1] = '\0'; return arr; } void displayLog(CERTVerifyLog *log) { printf("\nlog->count is %d\n", log->count); if (log->count > 0) { for (CERTVerifyLogNode *node=log->head; node; node=node->next) { printf("certificate=%s depth%s node->error=%ld %s\n", node->cert->nickname, node->depth ? "CA": "", node->error, parseArg(node)); if (node->error == SEC_ERROR_INADEQUATE_KEY_USAGE) printf("\tNote -8102=> SEC_ERROR_INADEQUATE_KEY_USAGE\n"); } // for loop } } class VerifyCert { public : VerifyCert(CERTCertificate *cert, void *pinArg); ~VerifyCert(); SECStatus checkCertUsage(SECCertificateUsage certusage) { return CERT_PKIXVerifyCert(_cert, certusage, _paramsIn, _paramsOut, _pinArg); } void log(void) { displayLog(this->_log); } private : CERTValInParam _paramsIn[1]; CERTValOutParam _paramsOut[2]; PLArenaPool *_arena; CERTVerifyLog *_log; CERTCertificate *_cert; void *_pinArg; }; VerifyCert::VerifyCert(CERTCertificate *cert, void *pinArg) { _cert = cert; _pinArg = pinArg; // Set the first input params entry to be the end of list marker. _paramsIn[0].type = cert_pi_end; _arena = PORT_NewArena(512); _log = PORT_ArenaZNew(_arena, CERTVerifyLog); _log->arena = _arena; _log->head = _log->tail = NULL; _log->count = 0; // Set the first entry to CertVerifyLog _paramsOut[0].type = cert_po_errorLog; _paramsOut[0].value.pointer.log = _log; // Set the second entry to be the end of list marker. _paramsOut[1].type = cert_po_end; } VerifyCert::~VerifyCert() { // free memory for (CERTVerifyLogNode *node = _log->head; node; node = node->next) { if (node->cert) CERT_DestroyCertificate(node->cert); } PORT_FreeArena(_log->arena, PR_FALSE); _log = NULL; _arena = NULL; } int main(int argc, char **argv) { PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); PK11_ConfigurePKCS11(NULL, NULL, NULL, "internal", NULL, NULL, NULL, NULL, 8, 1); PK11_SetPasswordFunc(NULL); SECStatus status = NSS_Initialize(NSS_DB_PATH, "", "", "secmod.db", NSS_INIT_READONLY); if (status != SECSuccess) { printf("ERROR in NSS_Initialize\n"); goto error; } CERTCertificate *cert = PK11_FindCertFromNickname(CERT_NICKNAME, NULL); if (cert == NULL) { printf("ERROR : PK11_FindCertFromNickname returned NULL cert\n"); goto error; } VerifyCert *v1 = new VerifyCert(cert, NULL); SECStatus rv = v1->checkCertUsage(certificateUsageSSLServer); if (rv == SECSuccess) { printf("CERT_PKIXVerifyCert(certificateUsageSSLServer) returned success !! \n"); } else { // print error in error log printf("CERT_PKIXVerifyCert(certificateUsageSSLServer) returned ERROR !!! \n"); printError(); v1->log(); } delete v1; return 0; error: printError(); exit(-1); }
Attached file cert8.db and key3.db are attached (deleted) —
Why we are getting PKIX_NULLARGUMENT in stdVars.aPkixErrorCode : PKIX_ForwardBuilderState state->buildConstants.revChecker is NULL. This revChecker is being passed to the function pkix_CheckChain() which is assuming revChecker is non-NULL as per the documentation http://mxr.mozilla.org/security/source/security/nss/lib/libpkix/pkix/top/pkix_validate.c#669 What is wrong revChecker is NULL or pkix_CheckChain()'s assumption that revChecker is non-NULL? Debugger info : (dbx) p state state = 0x5ddd0 (dbx) p *state *state = { status = BUILD_CHECKTRUSTED2 traversedCACerts = 0 certStoreIndex = 1U numCerts = 1U numAias = 0 certIndex = 0 aiaIndex = 0 certCheckedIndex = 0 checkerIndex = 0 hintCertIndex = 0 numFanout = 0 numDepth = 0 reasonCode = 0 revCheckDelayed = 0 canBeCached = 1 useOnlyLocal = 1 revChecking = 0 usingHintCerts = 0 certLoopingDetected = 0 validityDate = 0x5e7b0 prevCert = 0x59930 candidateCert = 0x5f770 traversedSubjNames = 0x59880 trustChain = 0x569d0 aia = (nil) candidateCerts = 0x5e518 reversedCertChain = 0x5e978 checkedCritExtOIDs = 0x66a30 checkerChain = 0x5e8d8 certSel = 0x5e1a0 verifyNode = 0x597e8 client = (nil) parentState = (nil) buildConstants = { numAnchors = 0 numCertStores = 1U numHintCerts = 0 maxDepth = 0 maxFanout = 0 maxTime = 0 procParams = 0x592b8 testDate = 0x550c8 timeLimit = (nil) targetCert = 0x59930 targetPubKey = 0x59820 certStores = 0x59538 anchors = 0x59388 userCheckers = (nil) hintCerts = (nil) revChecker = (nil) aiaMgr = (nil) useAIAForCertFetching = 0 } } (dbx) where current thread: t@1 =>[1] pkix_CheckChain(certs = 0x5e978, numCerts = 1U, anchor = 0x5e840, checkers = 0x5e8d8, revChecker = (nil), removeCheckedExtOIDs = 0x66a30, procParams = 0x592b8, pCertCheckedIndex = 0x5ddec, pCheckerIndex = 0x5ddf0, pRevChecking = 0x5de10, pReasonCode = 0x5de00, pNBIOContext = 0xffbfe930, pFinalSubjPubKey = 0xffbfe93c, pPolicyTree = 0xffbfe938, pVerifyTree = (nil), plContext = 0x55078), line 738 in "pkix_validate.c" [2] pkix_Build_ValidateEntireChain(state = 0x5ddd0, anchor = 0x5e840, pNBIOContext = 0xffbfea00, pValResult = 0xffbfea28, verifyNode = 0x5e658, plContext = 0x55078), line 1348 in "pkix_build.c" [3] pkix_BuildForwardDepthFirstSearch(pNBIOContext = 0xffbfeb9c, state = 0x5ddd0, pValResult = 0xffbfeb4c, plContext = 0x55078), line 2535 in "pkix_build.c" [4] pkix_Build_InitiateBuildChain(procParams = 0x592b8, pNBIOContext = 0xffbfec80, pState = 0xffbfec88, pBuildResult = 0xffbfec84, pVerifyNode = 0xffbfed0c, plContext = 0x55078), line 3553 in "pkix_build.c" [5] PKIX_BuildChain(procParams = 0x592b8, pNBIOContext = 0xffbfed20, pState = 0xffbfed1c, pBuildResult = 0xffbfed24, pVerifyNode = 0xffbfed0c, plContext = 0x55078), line 3726 in "pkix_build.c" [6] CERT_PKIXVerifyCert(cert = 0x56be0, usages = 2LL, paramsIn = 0x59220, paramsOut = 0x59240, wincx = (nil)), line 2150 in "certvfypkix.c" [7] VerifyCert::checkCertUsage(this = 0x59220, certusage = 2LL), line 131 in "server.cpp" [8] main(argc = 1, argv = 0xffbfee94), line 197 in "server.cpp" 738 PKIX_NULLCHECK_FOUR(certs, checkers, revChecker, pCertCheckedIndex); (dbx) p revChecker revChecker = (nil)
WORKAROUND: Add some bare minimum revocation flags (like CRL revocation flags and forbid network fetching) and it works. $./a.out CERT_PKIXVerifyCert(certificateUsageSSLServer) returned success !! $diff server.cpp server.cpp.old 135,137c135 < CERTValInParam _paramsIn[2]; < CERTRevocationFlags _rev; < --- > CERTValInParam _paramsIn[1]; 152,168d149 < // Set the first input params entry < _paramsIn[0].type = cert_pi_revocationFlags; < _paramsIn[0].value.pointer.revocation = &_rev; < _rev.leafTests.number_of_defined_methods = 1; < _rev.chainTests.number_of_defined_methods = 1; < _rev.leafTests.number_of_preferred_methods = 1; < _rev.chainTests.number_of_preferred_methods = 1; < PRUint64 flags[] = { (CERT_REV_M_TEST_USING_THIS_METHOD | CERT_REV_M_FORBID_NETWORK_FETCHING) }; < _rev.leafTests.cert_rev_flags_per_method = flags; < _rev.chainTests.cert_rev_flags_per_method = flags; < CERTRevocationMethodIndex mthds[] = { cert_revocation_method_crl }; < _rev.leafTests.preferred_methods = mthds; < _rev.chainTests.preferred_methods = mthds; < < _rev.leafTests.cert_rev_method_independent_flags = CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST; < _rev.chainTests.cert_rev_method_independent_flags = CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST; < 170c151 < _paramsIn[1].type = cert_pi_end; --- > _paramsIn[0].type = cert_pi_end;
Severity: normal → S3
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: