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)
Tracking
(Not tracked)
UNCONFIRMED
People
(Reporter: u238590, Unassigned)
Details
Attachments
(1 file)
(deleted),
application/octet-stream
|
Details |
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);
}
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;
Updated•14 years ago
|
Blocks: pkix-default
Updated•13 years ago
|
No longer blocks: pkix-default
Updated•2 years ago
|
Severity: normal → S3
You need to log in
before you can comment on or make changes to this bug.
Description
•