412468 - modify vfychain and vfyserv utilities to use CERT_PKIXVerifyCert function. r=nelson
git-svn-id: svn://10.0.0.236/trunk@245432 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -517,7 +517,12 @@ listCerts(CERTCertDBHandle *handle, char *name, PK11SlotInfo *slot,
|
||||
}
|
||||
rv = SECSuccess;
|
||||
} else {
|
||||
rv = printCertCB(the_cert, the_cert->trust);
|
||||
rv = SEC_PrintCertificateAndTrust(the_cert, the_cert->trust,
|
||||
"Certificate");
|
||||
if (rv != SECSuccess) {
|
||||
SECU_PrintError(progName, "problem printing certificate");
|
||||
}
|
||||
|
||||
}
|
||||
if (rv != SECSuccess) {
|
||||
break;
|
||||
|
||||
@@ -3078,6 +3078,37 @@ loser:
|
||||
|
||||
}
|
||||
|
||||
SECStatus
|
||||
SEC_PrintCertificateAndTrust(CERTCertificate *cert,
|
||||
const char *label,
|
||||
void *arg)
|
||||
{
|
||||
SECStatus rv;
|
||||
SECItem data;
|
||||
CERTCertTrust *trust = (CERTCertTrust *)arg;
|
||||
|
||||
data.data = cert->derCert.data;
|
||||
data.len = cert->derCert.len;
|
||||
|
||||
rv = SECU_PrintSignedData(stdout, &data, label, 0,
|
||||
SECU_PrintCertificate);
|
||||
if (rv) {
|
||||
return(SECFailure);
|
||||
}
|
||||
if (trust) {
|
||||
SECU_PrintTrustFlags(stdout, trust,
|
||||
"Certificate Trust Flags", 1);
|
||||
} else if (cert->trust) {
|
||||
SECU_PrintTrustFlags(stdout, cert->trust,
|
||||
"Certificate Trust Flags", 1);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
return(SECSuccess);
|
||||
}
|
||||
|
||||
|
||||
SECStatus
|
||||
SECU_ParseCommandLine(int argc, char **argv, char *progName,
|
||||
const secuCommand *cmd)
|
||||
@@ -3373,10 +3404,8 @@ SECU_printCertProblemsOnDate(FILE *outfile, CERTCertDBHandle *handle,
|
||||
PRTime datetime)
|
||||
{
|
||||
CERTVerifyLog log;
|
||||
CERTVerifyLogNode *node = NULL;
|
||||
unsigned int depth = (unsigned int)-1;
|
||||
unsigned int flags = 0;
|
||||
char * errstr = NULL;
|
||||
CERTVerifyLogNode *node;
|
||||
|
||||
PRErrorCode err = PORT_GetError();
|
||||
|
||||
log.arena = PORT_NewArena(512);
|
||||
@@ -3384,9 +3413,29 @@ SECU_printCertProblemsOnDate(FILE *outfile, CERTCertDBHandle *handle,
|
||||
log.count = 0;
|
||||
CERT_VerifyCertificate(handle, cert, checksig, certUsage, datetime, pinArg, &log, NULL);
|
||||
|
||||
if (log.count > 0) {
|
||||
SECU_displayVerifyLog(outfile, &log, verbose);
|
||||
|
||||
for (node = log.head; node; node = node->next) {
|
||||
if (node->cert)
|
||||
CERT_DestroyCertificate(node->cert);
|
||||
}
|
||||
PORT_FreeArena(log.arena, PR_FALSE);
|
||||
|
||||
PORT_SetError(err); /* restore original error code */
|
||||
}
|
||||
|
||||
void
|
||||
SECU_displayVerifyLog(FILE *outfile, CERTVerifyLog *log,
|
||||
PRBool verbose)
|
||||
{
|
||||
CERTVerifyLogNode *node = NULL;
|
||||
unsigned int depth = (unsigned int)-1;
|
||||
unsigned int flags = 0;
|
||||
char * errstr = NULL;
|
||||
|
||||
if (log->count > 0) {
|
||||
fprintf(outfile,"PROBLEM WITH THE CERT CHAIN:\n");
|
||||
for (node = log.head; node; node = node->next) {
|
||||
for (node = log->head; node; node = node->next) {
|
||||
if (depth != node->depth) {
|
||||
depth = node->depth;
|
||||
fprintf(outfile,"CERT %d. %s %s:\n", depth,
|
||||
@@ -3462,10 +3511,8 @@ SECU_printCertProblemsOnDate(FILE *outfile, CERTCertDBHandle *handle,
|
||||
if (errstr) {
|
||||
fprintf(stderr," %s\n",errstr);
|
||||
}
|
||||
CERT_DestroyCertificate(node->cert);
|
||||
}
|
||||
}
|
||||
PORT_SetError(err); /* restore original error code */
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -178,18 +178,25 @@ extern void SECU_PrintSystemError(char *progName, char *msg, ...);
|
||||
/* Return informative error string */
|
||||
extern const char * SECU_Strerror(PRErrorCode errNum);
|
||||
|
||||
/* print information about cert verification failure at time == now */
|
||||
/* revalidate the cert and print information about cert verification
|
||||
* failure at time == now */
|
||||
extern void
|
||||
SECU_printCertProblems(FILE *outfile, CERTCertDBHandle *handle,
|
||||
CERTCertificate *cert, PRBool checksig,
|
||||
SECCertificateUsage certUsage, void *pinArg, PRBool verbose);
|
||||
|
||||
/* print information about cert verification failure at specified time */
|
||||
/* revalidate the cert and print information about cert verification
|
||||
* failure at specified time */
|
||||
extern void
|
||||
SECU_printCertProblemsOnDate(FILE *outfile, CERTCertDBHandle *handle,
|
||||
CERTCertificate *cert, PRBool checksig, SECCertificateUsage certUsage,
|
||||
void *pinArg, PRBool verbose, PRTime datetime);
|
||||
|
||||
/* print out CERTVerifyLog info. */
|
||||
extern void
|
||||
SECU_displayVerifyLog(FILE *outfile, CERTVerifyLog *log,
|
||||
PRBool verbose);
|
||||
|
||||
/* Read the contents of a file into a SECItem */
|
||||
extern SECStatus SECU_FileToItem(SECItem *dst, PRFileDesc *src);
|
||||
extern SECStatus SECU_TextFileToItem(SECItem *dst, PRFileDesc *src);
|
||||
@@ -287,6 +294,11 @@ extern SECStatus SECU_PKCS11Init(PRBool readOnly);
|
||||
extern int SECU_PrintSignedData(FILE *out, SECItem *der, char *m, int level,
|
||||
SECU_PPFunc inner);
|
||||
|
||||
/* Print cert data and its trust flags */
|
||||
extern SECStatus SEC_PrintCertificateAndTrust(CERTCertificate *cert,
|
||||
const char *label,
|
||||
void *arg);
|
||||
|
||||
extern int SECU_PrintCrl(FILE *out, SECItem *der, char *m, int level);
|
||||
|
||||
extern void
|
||||
|
||||
@@ -101,14 +101,17 @@ Usage(const char *progName)
|
||||
fprintf(stderr,
|
||||
"Usage: %s [options] certfile [[options] certfile] ...\n"
|
||||
"\twhere options are:\n"
|
||||
"\t-a\t\t following certfile is base64 encoded\n"
|
||||
"\t-a\t\t Following certfile is base64 encoded\n"
|
||||
"\t-b YYMMDDHHMMZ\t Validate date (default: now)\n"
|
||||
"\t-d directory\t Database directory\n"
|
||||
"\t-r\t\t following certfile is raw binary DER (default)\n"
|
||||
"\t-o oid\t\t Set policy OID for cert validation(Format OID.1.2.3)\n"
|
||||
"\t-p \t\t Use PKIX Library to validate certificate\n"
|
||||
"\t-r\t\t Following certfile is raw binary DER (default)\n"
|
||||
"\t-u usage \t 0=SSL client, 1=SSL server, 2=SSL StepUp, 3=SSL CA,\n"
|
||||
"\t\t\t 4=Email signer, 5=Email recipient, 6=Object signer,\n"
|
||||
"\t\t\t 9=ProtectedObjectSigner, 10=OCSP responder, 11=Any CA\n"
|
||||
"\t-v\t\t verbose mode\n"
|
||||
"\t-v\t\t Verbose mode. Prints root cert subject(double the\n"
|
||||
"\t\t\t argument for whole root cert info)\n"
|
||||
"\t-w password\t Database password\n",
|
||||
progName);
|
||||
exit(1);
|
||||
@@ -173,7 +176,7 @@ forgetCerts(void)
|
||||
|
||||
|
||||
CERTCertificate *
|
||||
readCertFile(const char * fileName, PRBool isAscii)
|
||||
getCert(const char *name, PRBool isAscii)
|
||||
{
|
||||
unsigned char * pb;
|
||||
CERTCertificate * cert = NULL;
|
||||
@@ -185,11 +188,21 @@ readCertFile(const char * fileName, PRBool isAscii)
|
||||
SECItem item;
|
||||
static unsigned char certBuf[RD_BUF_SIZE];
|
||||
|
||||
fd = PR_Open(fileName, PR_RDONLY, 0777);
|
||||
defaultDB = CERT_GetDefaultCertDB();
|
||||
|
||||
/* First, let's try to find the cert in existing DB. */
|
||||
cert = CERT_FindCertByNicknameOrEmailAddr(defaultDB, name);
|
||||
if (cert) {
|
||||
return cert;
|
||||
}
|
||||
|
||||
/* Don't have a cert with name "name" in the DB. Try to
|
||||
* open a file with such name and get the cert from there.*/
|
||||
fd = PR_Open(name, PR_RDONLY, 0777);
|
||||
if (!fd) {
|
||||
PRIntn err = PR_GetError();
|
||||
fprintf(stderr, "open of %s failed, %d = %s\n",
|
||||
fileName, err, SECU_Strerror(err));
|
||||
name, err, SECU_Strerror(err));
|
||||
return cert;
|
||||
}
|
||||
/* read until EOF or buffer is full */
|
||||
@@ -201,7 +214,7 @@ readCertFile(const char * fileName, PRBool isAscii)
|
||||
if (cc < 0) {
|
||||
PRIntn err = PR_GetError();
|
||||
fprintf(stderr, "read of %s failed, %d = %s\n",
|
||||
fileName, err, SECU_Strerror(err));
|
||||
name, err, SECU_Strerror(err));
|
||||
break;
|
||||
}
|
||||
/* cc > 0 */
|
||||
@@ -211,12 +224,12 @@ readCertFile(const char * fileName, PRBool isAscii)
|
||||
if (cc < 0)
|
||||
return cert;
|
||||
if (!remaining || cc > 0) { /* file was too big. */
|
||||
fprintf(stderr, "cert file %s was too big.\n", fileName);
|
||||
fprintf(stderr, "cert file %s was too big.\n", name);
|
||||
return cert;
|
||||
}
|
||||
total = pb - certBuf;
|
||||
if (!total) { /* file was empty */
|
||||
fprintf(stderr, "cert file %s was empty.\n", fileName);
|
||||
fprintf(stderr, "cert file %s was empty.\n", name);
|
||||
return cert;
|
||||
}
|
||||
if (isAscii) {
|
||||
@@ -225,7 +238,6 @@ readCertFile(const char * fileName, PRBool isAscii)
|
||||
item.type = siBuffer;
|
||||
item.data = certBuf;
|
||||
item.len = total;
|
||||
defaultDB = CERT_GetDefaultCertDB();
|
||||
cert = CERT_NewTempCertificate(defaultDB, &item,
|
||||
NULL /* nickname */,
|
||||
PR_FALSE /* isPerm */,
|
||||
@@ -233,7 +245,7 @@ readCertFile(const char * fileName, PRBool isAscii)
|
||||
if (!cert) {
|
||||
PRIntn err = PR_GetError();
|
||||
fprintf(stderr, "couldn't import %s, %d = %s\n",
|
||||
fileName, err, SECU_Strerror(err));
|
||||
name, err, SECU_Strerror(err));
|
||||
}
|
||||
return cert;
|
||||
}
|
||||
@@ -243,10 +255,13 @@ 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 usePkix = PR_FALSE;
|
||||
SECStatus secStatus;
|
||||
SECCertificateUsage certUsage = certificateUsageSSLServer;
|
||||
PLOptState * optstate;
|
||||
@@ -254,12 +269,13 @@ main(int argc, char *argv[], char *envp[])
|
||||
PLOptStatus status;
|
||||
int rv = 1;
|
||||
int usage;
|
||||
CERTVerifyLog log;
|
||||
|
||||
PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
|
||||
|
||||
progName = PL_strdup(argv[0]);
|
||||
|
||||
optstate = PL_CreateOptState(argc, argv, "ab:d:ru:w:v");
|
||||
optstate = PL_CreateOptState(argc, argv, "ab:d:o:pru:w:v");
|
||||
while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
|
||||
switch(optstate->option) {
|
||||
case 0 : /* positional parameter */ goto breakout;
|
||||
@@ -267,6 +283,8 @@ main(int argc, char *argv[], char *envp[])
|
||||
case 'b' : secStatus = DER_AsciiToTime(&time, optstate->value);
|
||||
if (secStatus != SECSuccess) Usage(progName); break;
|
||||
case 'd' : certDir = PL_strdup(optstate->value); break;
|
||||
case 'o' : oidStr = PL_strdup(optstate->value); break;
|
||||
case 'p' : usePkix = PR_TRUE; break;
|
||||
case 'r' : isAscii = PR_FALSE; break;
|
||||
case 'u' : usage = PORT_Atoi(optstate->value);
|
||||
if (usage < 0 || usage > 62) Usage(progName);
|
||||
@@ -305,7 +323,7 @@ breakout:
|
||||
case 'a' : isAscii = PR_TRUE; break;
|
||||
case 'r' : isAscii = PR_FALSE; break;
|
||||
case 0 : /* positional parameter */
|
||||
cert = readCertFile(optstate->value, isAscii);
|
||||
cert = getCert(optstate->value, isAscii);
|
||||
if (!cert)
|
||||
goto punt;
|
||||
rememberCert(cert);
|
||||
@@ -322,27 +340,123 @@ breakout:
|
||||
if (!time)
|
||||
time = PR_Now();
|
||||
|
||||
/* NOW, verify the cert chain. */
|
||||
defaultDB = CERT_GetDefaultCertDB();
|
||||
secStatus = CERT_VerifyCertificate(defaultDB, firstCert,
|
||||
PR_TRUE /* check sig */,
|
||||
certUsage,
|
||||
time,
|
||||
NULL, /* wincx */
|
||||
NULL, /* error log */
|
||||
NULL); /* returned usages */
|
||||
/* Initialize log structure */
|
||||
log.arena = PORT_NewArena(512);
|
||||
log.head = log.tail = NULL;
|
||||
log.count = 0;
|
||||
|
||||
if (secStatus != SECSuccess) {
|
||||
if (!usePkix) {
|
||||
/* NOW, verify the cert chain. */
|
||||
defaultDB = CERT_GetDefaultCertDB();
|
||||
secStatus = CERT_VerifyCertificate(defaultDB, firstCert,
|
||||
PR_TRUE /* check sig */,
|
||||
certUsage,
|
||||
time,
|
||||
NULL, /* wincx */
|
||||
&log, /* error log */
|
||||
NULL);/* returned usages */
|
||||
} else do {
|
||||
CERTValOutParam cvout[3];
|
||||
CERTValInParam cvin[3];
|
||||
SECOidTag oidTag;
|
||||
int inParamIndex = 0;
|
||||
|
||||
if (oidStr) {
|
||||
PRArenaPool *arena;
|
||||
SECOidData 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[0].type = cert_pi_policyOID;
|
||||
cvin[0].value.arraySize = 1;
|
||||
cvin[0].value.array.oids = &oidTag;
|
||||
|
||||
inParamIndex = 1;
|
||||
}
|
||||
|
||||
cvin[inParamIndex].type = cert_pi_revocationFlags;
|
||||
cvin[inParamIndex].value.scalar.ul = CERT_REV_FAIL_SOFT_CRL |
|
||||
CERT_REV_FLAG_CRL;
|
||||
cvin[inParamIndex + 1].type = cert_pi_end;
|
||||
|
||||
cvout[0].type = cert_po_trustAnchor;
|
||||
|
||||
/* setting pointer to CERTVerifyLog. Initialized structure
|
||||
* will be used CERT_PKIXVerifyCert */
|
||||
cvout[1].type = cert_po_errorLog;
|
||||
cvout[1].value.pointer.log = &log;
|
||||
|
||||
cvout[2].type = cert_po_end;
|
||||
|
||||
secStatus = CERT_PKIXVerifyCert(firstCert, certUsage,
|
||||
cvin, cvout, NULL);
|
||||
if (secStatus != SECSuccess) {
|
||||
break;
|
||||
}
|
||||
issuerCert = cvout[0].value.pointer.cert;
|
||||
} 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_printCertProblemsOnDate(stderr, defaultDB, firstCert,
|
||||
PR_TRUE, certUsage, NULL, verbose, time);
|
||||
|
||||
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 && verbose) {
|
||||
if (verbose > 1) {
|
||||
rv = SEC_PrintCertificateAndTrust(issuerCert, "Root Certificate",
|
||||
NULL);
|
||||
if (rv != SECSuccess) {
|
||||
SECU_PrintError(progName, "problem printing certificate");
|
||||
}
|
||||
} else {
|
||||
SECU_PrintName(stdout, &issuerCert->subject, "Root "
|
||||
"Certificate Subject:", 0);
|
||||
}
|
||||
CERT_DestroyCertificate(issuerCert);
|
||||
}
|
||||
rv = 0;
|
||||
}
|
||||
|
||||
/* Need to destroy CERTVerifyLog arena at the end */
|
||||
PORT_FreeArena(log.arena, PR_FALSE);
|
||||
|
||||
punt:
|
||||
forgetCerts();
|
||||
if (NSS_Shutdown() != SECSuccess) {
|
||||
|
||||
Reference in New Issue
Block a user