diff options
author | alexei.volkov.bugs%sun.com <devnull@localhost> | 2008-02-11 22:51:01 +0000 |
---|---|---|
committer | alexei.volkov.bugs%sun.com <devnull@localhost> | 2008-02-11 22:51:01 +0000 |
commit | 5574a07b56db0988b50b1aaa125edde3f6037a38 (patch) | |
tree | e60dcfba108c359e3f05ee9480202c4800ba6718 /security/nss/cmd | |
parent | 5d0d8c8333cb06d6375432fd46807596600f27c6 (diff) | |
download | nss-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.c | 7 | ||||
-rw-r--r-- | security/nss/cmd/lib/secutil.c | 63 | ||||
-rw-r--r-- | security/nss/cmd/lib/secutil.h | 16 | ||||
-rw-r--r-- | security/nss/cmd/vfychain/vfychain.c | 166 |
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) { |