summaryrefslogtreecommitdiff
path: root/security/nss/cmd
diff options
context:
space:
mode:
authoralexei.volkov.bugs%sun.com <devnull@localhost>2008-02-11 22:51:01 +0000
committeralexei.volkov.bugs%sun.com <devnull@localhost>2008-02-11 22:51:01 +0000
commit5574a07b56db0988b50b1aaa125edde3f6037a38 (patch)
treee60dcfba108c359e3f05ee9480202c4800ba6718 /security/nss/cmd
parent5d0d8c8333cb06d6375432fd46807596600f27c6 (diff)
downloadnss-hg-5574a07b56db0988b50b1aaa125edde3f6037a38.tar.gz
412468 - modify vfychain and vfyserv utilities to use CERT_PKIXVerifyCert function. r=nelson
Diffstat (limited to 'security/nss/cmd')
-rw-r--r--security/nss/cmd/certutil/certutil.c7
-rw-r--r--security/nss/cmd/lib/secutil.c63
-rw-r--r--security/nss/cmd/lib/secutil.h16
-rw-r--r--security/nss/cmd/vfychain/vfychain.c166
4 files changed, 215 insertions, 37 deletions
diff --git a/security/nss/cmd/certutil/certutil.c b/security/nss/cmd/certutil/certutil.c
index 7832ae316..9563492c8 100644
--- a/security/nss/cmd/certutil/certutil.c
+++ b/security/nss/cmd/certutil/certutil.c
@@ -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;
diff --git a/security/nss/cmd/lib/secutil.c b/security/nss/cmd/lib/secutil.c
index cd4cbaa01..f59d99a9c 100644
--- a/security/nss/cmd/lib/secutil.c
+++ b/security/nss/cmd/lib/secutil.c
@@ -3079,6 +3079,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
diff --git a/security/nss/cmd/lib/secutil.h b/security/nss/cmd/lib/secutil.h
index e3f4b955e..7eaae39bc 100644
--- a/security/nss/cmd/lib/secutil.h
+++ b/security/nss/cmd/lib/secutil.h
@@ -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
diff --git a/security/nss/cmd/vfychain/vfychain.c b/security/nss/cmd/vfychain/vfychain.c
index 53ad006a1..551684c18 100644
--- a/security/nss/cmd/vfychain/vfychain.c
+++ b/security/nss/cmd/vfychain/vfychain.c
@@ -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 */
-
- if (secStatus != SECSuccess) {
+ /* Initialize log structure */
+ log.arena = PORT_NewArena(512);
+ log.head = log.tail = NULL;
+ log.count = 0;
+
+ 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) {