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:
alexei.volkov.bugs%sun.com
2008-02-11 22:51:01 +00:00
parent 97be7a9a6f
commit f4fcd66b3e
4 changed files with 214 additions and 36 deletions

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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) {