From bb6cf23f231363f8ed565f8d9b9156e8bf619b33 Mon Sep 17 00:00:00 2001 From: "relyea%netscape.com" Date: Fri, 16 Aug 2002 23:09:02 +0000 Subject: [PATCH] use error code in secutil. Clean up the output. Print out cert chain parsing issues more completely. --- security/nss/cmd/vfyserv/manifest.mn | 2 +- security/nss/cmd/vfyserv/vfyserv.c | 43 +++++---- security/nss/cmd/vfyserv/vfyserv.h | 6 +- security/nss/cmd/vfyserv/vfyutil.c | 134 ++++++++++++++++++++++++--- 4 files changed, 156 insertions(+), 29 deletions(-) diff --git a/security/nss/cmd/vfyserv/manifest.mn b/security/nss/cmd/vfyserv/manifest.mn index f8de4dd9a5ba..b2c85fadb0c9 100644 --- a/security/nss/cmd/vfyserv/manifest.mn +++ b/security/nss/cmd/vfyserv/manifest.mn @@ -45,7 +45,7 @@ REQUIRES = seccmd dbm # DIRS = CSRCS = vfyserv.c vfyutil.c -DEFINES += -DDLL_PREFIX=\"$(DLL_PREFIX)\" -DDLL_SUFFIX=\"$(DLL_SUFFIX)\" -I../SSLSample +DEFINES += -DDLL_PREFIX=\"$(DLL_PREFIX)\" -DDLL_SUFFIX=\"$(DLL_SUFFIX)\" PROGRAM = vfyserv diff --git a/security/nss/cmd/vfyserv/vfyserv.c b/security/nss/cmd/vfyserv/vfyserv.c index bab937491602..ea4116ca9e6e 100644 --- a/security/nss/cmd/vfyserv/vfyserv.c +++ b/security/nss/cmd/vfyserv/vfyserv.c @@ -178,7 +178,7 @@ const char requestString[] = {"GET /testfile HTTP/1.0\r\n\r\n" }; SECStatus handle_connection(PRFileDesc *sslSocket, int connection) { - int countRead = 0; + int countRead = 0; PRInt32 numBytes; char *readBuffer; @@ -210,7 +210,7 @@ handle_connection(PRFileDesc *sslSocket, int connection) countRead += numBytes; } - printSecurityInfo(sslSocket); + printSecurityInfo(stderr, sslSocket); PR_Free(readBuffer); readBuffer = NULL; @@ -224,6 +224,8 @@ handle_connection(PRFileDesc *sslSocket, int connection) return SECSuccess; /* success */ } +#define BYTE(n,i) (((i)>>((n)*8))&0xff) + /* one copy of this function is launched in a separate thread for each ** connection to be made. */ @@ -236,6 +238,7 @@ do_connects(void *a, int connection) char buffer[PR_NETDB_BUF_SIZE]; PRStatus prStatus; PRIntn hostenum; + PRInt32 ip; SECStatus secStatus; /* Set up SSL secure socket. */ @@ -270,8 +273,11 @@ do_connects(void *a, int connection) return SECFailure; } -/* printf("Connecting to host %s (addr %d.%d.%d.%d) on port %d\n", - host, hostEntry,port); */ + ip = PR_ntohl(addr->inet.ip); + fprintf(stderr, + "Connecting to host %s (addr %d.%d.%d.%d) on port %d\n", + hostName, BYTE(3,ip), BYTE(2,ip), BYTE(1,ip), + BYTE(0,ip), PR_ntohs(addr->inet.port)); prStatus = PR_Connect(sslSocket, addr, PR_INTERVAL_NO_TIMEOUT); if (prStatus != PR_SUCCESS) { @@ -300,7 +306,8 @@ do_connects(void *a, int connection) secStatus = handle_connection(sslSocket, connection); if (secStatus != SECSuccess) { - errWarn("handle_connection"); + /* error already printed out in handle_connection */ + /* errWarn("handle_connection"); */ return secStatus; } @@ -356,8 +363,9 @@ client_main(unsigned short port, int main(int argc, char **argv) { + char * certDir = NULL; char * progName = NULL; - int connections = 1; + int connections = 1; char * cipherString = NULL; SECStatus secStatus; PLOptState * optstate; @@ -374,7 +382,9 @@ main(int argc, char **argv) switch(optstate->option) { case 'C' : cipherString = PL_strdup(optstate->value); break; case 'c' : connections = PORT_Atoi(optstate->value); break; + case 'd' : certDir = PL_strdup(optstate->value); break; case 'p' : port = PORT_Atoi(optstate->value); break; + case 'w' : password = PL_strdup(optstate->value); break; case '\0': hostName = PL_strdup(optstate->value); break; default : Usage(progName); } @@ -391,20 +401,21 @@ main(int argc, char **argv) PK11_SetPasswordFunc(myPasswd); /* Initialize the NSS libraries. */ - secStatus = NSS_NoDB_Init(NULL); - if (secStatus != SECSuccess) { - exitErr("Client Error NSS_Init"); - } + if (certDir) { + secStatus = NSS_Init(certDir); + } else { + secStatus = NSS_NoDB_Init(NULL); - secStatus = SECMOD_AddNewModule("Builtins", + /* load the builtins */ + SECMOD_AddNewModule("Builtins", DLL_PREFIX"nssckbi."DLL_SUFFIX, 0, 0); -#ifdef notdef - if (secStatus != SECSuccess) { - exitErr("Client Error accessing builtin roots"); } -#endif + if (secStatus != SECSuccess) { + exitErr("NSS_Init"); + } - /* All cipher suites except RSA_NULL_MD5 are enabled by Domestic Policy. */ + /* All cipher suites except RSA_NULL_MD5 are enabled by + * Domestic Policy. */ NSS_SetDomesticPolicy(); SSL_CipherPrefSetDefault(SSL_RSA_WITH_NULL_MD5, PR_TRUE); diff --git a/security/nss/cmd/vfyserv/vfyserv.h b/security/nss/cmd/vfyserv/vfyserv.h index ca6b6a489688..e23b5e779171 100644 --- a/security/nss/cmd/vfyserv/vfyserv.h +++ b/security/nss/cmd/vfyserv/vfyserv.h @@ -107,7 +107,11 @@ void errWarn(char *function); void exitErr(char *function); -void printSecurityInfo(PRFileDesc *fd); +void printSecurityInfo(FILE *outfile, PRFileDesc *fd); + +void printCertProblems(FILE *outfile, CERTCertDBHandle *handle, + CERTCertificate *cert, PRBool checksig, + SECCertUsage certUsage, void *pinArg); /* Some simple thread management routines. */ diff --git a/security/nss/cmd/vfyserv/vfyutil.c b/security/nss/cmd/vfyserv/vfyutil.c index b92a1853c1f2..db60ec13e3cd 100644 --- a/security/nss/cmd/vfyserv/vfyutil.c +++ b/security/nss/cmd/vfyserv/vfyutil.c @@ -32,7 +32,10 @@ */ #include "vfyserv.h" -#include "sslerror.h" /* go find the real one in libutil! */ +#include "secerr.h" +#include "sslerr.h" +#include "nspr.h" +#include "secutil.h" /* Declare SSL cipher suites. */ @@ -127,6 +130,8 @@ myAuthCertificate(void *arg, PRFileDesc *socket, /* If this is a server, we're finished. */ if (isServer || secStatus != SECSuccess) { + printCertProblems(stderr, (CERTCertDBHandle *)arg, cert, + checksig, certUsage, pinArg); CERT_DestroyCertificate(cert); return secStatus; } @@ -204,7 +209,7 @@ myBadCertHandler(void *arg, PRFileDesc *socket) break; } - printf("Bad certificate: %d, %s\n", err, SSL_Strerror(err)); + fprintf(stderr, "Bad certificate: %d, %s\n", err, SECU_Strerror(err)); return secStatus; } @@ -311,7 +316,7 @@ myGetClientAuthData(void *arg, SECStatus myHandshakeCallback(PRFileDesc *socket, void *arg) { - printf("Handshake has completed, ready to send data securely.\n"); + fprintf(stderr,"Handshake Complete: SERVER CONFIGURED CORRECTLY\n"); return SECSuccess; } @@ -334,7 +339,8 @@ disableAllSSLCiphers(void) PRUint16 suite = cipherSuites[i]; rv = SSL_CipherPrefSetDefault(suite, PR_FALSE); if (rv != SECSuccess) { - printf("SSL_CipherPrefSetDefault didn't like value 0x%04x (i = %d)\n", + fprintf(stderr, + "SSL_CipherPrefSetDefault didn't like value 0x%04x (i = %d)\n", suite, i); errWarn("SSL_CipherPrefSetDefault"); exit(2); @@ -352,9 +358,9 @@ void errWarn(char *function) { PRErrorCode errorNumber = PR_GetError(); - const char * errorString = SSL_Strerror(errorNumber); + const char * errorString = SECU_Strerror(errorNumber); - printf("Error in function %s: %d\n - %s\n", + fprintf(stderr, "Error in function %s: %d\n - %s\n", function, errorNumber, errorString); } @@ -369,7 +375,7 @@ exitErr(char *function) } void -printSecurityInfo(PRFileDesc *fd) +printSecurityInfo(FILE *outfile, PRFileDesc *fd) { char * cp; /* bulk cipher name */ char * ip; /* cert issuer DN */ @@ -380,17 +386,23 @@ printSecurityInfo(PRFileDesc *fd) int result; SSL3Statistics * ssl3stats = SSL_GetStatistics(); + if (!outfile) { + outfile = stdout; + } + result = SSL_SecurityStatus(fd, &op, &cp, &kp0, &kp1, &ip, &sp); if (result != SECSuccess) return; - printf("bulk cipher %s, %d secret key bits, %d key bits, status: %d\n" - "subject DN: %s\n" - "issuer DN: %s\n", cp, kp1, kp0, op, sp, ip); + fprintf(outfile, + " bulk cipher %s, %d secret key bits, %d key bits, status: %d\n" + " subject DN:\n %s\n" + " issuer DN:\n %s\n", cp, kp1, kp0, op, sp, ip); PR_Free(cp); PR_Free(ip); PR_Free(sp); - printf("%ld cache hits; %ld cache misses, %ld cache not reusable\n", + fprintf(outfile, + " %ld cache hits; %ld cache misses, %ld cache not reusable\n", ssl3stats->hch_sid_cache_hits, ssl3stats->hch_sid_cache_misses, ssl3stats->hch_sid_cache_not_ok); @@ -586,3 +598,103 @@ lockedVars_AddToCount(lockedVars * lv, int addend) PR_Unlock(lv->lock); return rv; } + +static char * +bestCertName(CERTCertificate *cert) { + if (cert->nickname) { + return cert->nickname; + } + if (cert->emailAddr) { + return cert->emailAddr; + } + return cert->subjectName; +} + +void +printCertProblems(FILE *outfile, CERTCertDBHandle *handle, + CERTCertificate *cert, PRBool checksig, + SECCertUsage certUsage, void *pinArg) +{ + CERTVerifyLog log; + CERTVerifyLogNode *node = NULL; + unsigned int depth = (unsigned int)-1; + unsigned int flags = 0; + char *errstr = NULL; + + log.arena = PORT_NewArena(512); + log.head = log.tail = NULL; + log.count = 0; + CERT_VerifyCert(handle, cert, checksig, certUsage, + PR_Now(), pinArg, &log); + + if (log.count > 0) { + fprintf(outfile,"PROBLEM WITH THE CERT CHAIN:\n"); + for (node = log.head; node; node = node->next) { + if (depth != node->depth) { + depth = node->depth; + fprintf(outfile,"CERT %d. %s %s:\n", depth, + bestCertName(node->cert), + depth ? "[Certificate Authority]": ""); + } + fprintf(outfile," ERROR %d: %s\n", node->error, + SECU_Strerror(node->error)); + errstr = NULL; + switch (node->error) { + case SEC_ERROR_INADEQUATE_KEY_USAGE: + flags = (unsigned int)node->arg; + switch (flags) { + case KU_DIGITAL_SIGNATURE: + errstr = "Cert cannot sign."; + break; + case KU_KEY_ENCIPHERMENT: + errstr = "Cert cannot encrypt."; + break; + case KU_KEY_CERT_SIGN: + errstr = "Cert cannot sign other certs."; + break; + default: + errstr = "[unknown usage]."; + break; + } + case SEC_ERROR_INADEQUATE_CERT_TYPE: + flags = (unsigned int)node->arg; + switch (flags) { + case NS_CERT_TYPE_SSL_CLIENT: + case NS_CERT_TYPE_SSL_SERVER: + errstr = "Cert cannot be used for SSL."; + break; + case NS_CERT_TYPE_SSL_CA: + errstr = "Cert cannot be used as an SSL CA."; + break; + case NS_CERT_TYPE_EMAIL: + errstr = "Cert cannot be used for SMIME."; + break; + case NS_CERT_TYPE_EMAIL_CA: + errstr = "Cert cannot be used as an SMIME CA."; + break; + case NS_CERT_TYPE_OBJECT_SIGNING: + errstr = "Cert cannot be used for object signing."; + break; + case NS_CERT_TYPE_OBJECT_SIGNING_CA: + errstr = "Cert cannot be used as an object signing CA."; + break; + default: + errstr = "[unknown usage]."; + break; + } + case SEC_ERROR_UNKNOWN_ISSUER: + case SEC_ERROR_UNTRUSTED_ISSUER: + case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: + errstr = node->cert->issuerName; + break; + default: + break; + } + if (errstr) { + fprintf(stderr," %s\n",errstr); + } + CERT_DestroyCertificate(node->cert); + } + } + return ; +}