/* * Callback from SSL for checking certificate the peer (other end of * the socket) presents. */ SECStatus JSSL_DefaultCertAuthCallback(void *arg, PRFileDesc *fd, PRBool checkSig, PRBool isServer) { char * hostname = NULL; SECStatus rv = SECFailure; SECCertUsage certUsage; CERTCertificate *peerCert=NULL; certUsage = isServer ? certUsageSSLClient : certUsageSSLServer; /* SSL_PeerCertificate() returns a shallow copy of the cert, so we must destroy it before we exit this function */ peerCert = SSL_PeerCertificate(fd); if (peerCert) { rv = CERT_VerifyCertNow(CERT_GetDefaultCertDB(), peerCert, checkSig, certUsage, NULL /*pinarg*/); } /* if we're a server, then we don't need to check the CN of the certificate, so we can just return whatever returncode we have now */ if ( rv != SECSuccess || isServer ) { if (peerCert) CERT_DestroyCertificate(peerCert); return (int)rv; } /* cert is OK. This is the client side of an SSL connection. * Now check the name field in the cert against the desired hostname. * NB: This is our only defense against Man-In-The-Middle (MITM) attacks! */ hostname = SSL_RevealURL(fd); /* really is a hostname, not a URL */ if (hostname && hostname[0]) { rv = CERT_VerifyCertName(peerCert, hostname); PORT_Free(hostname); } else rv = SECFailure; if (peerCert) CERT_DestroyCertificate(peerCert); return rv; }
SECStatus SSL_AuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig, PRBool isServer) { SECStatus rv; CERTCertDBHandle * handle; sslSocket * ss; SECCertUsage certUsage; const char * hostname = NULL; ss = ssl_FindSocket(fd); PORT_Assert(ss != NULL); if (!ss) { return SECFailure; } handle = (CERTCertDBHandle *)arg; /* this may seem backwards, but isn't. */ certUsage = isServer ? certUsageSSLClient : certUsageSSLServer; rv = CERT_VerifyCertNow(handle, ss->sec.peerCert, checkSig, certUsage, ss->pkcs11PinArg); if ( rv != SECSuccess || isServer ) return rv; /* cert is OK. This is the client side of an SSL connection. * Now check the name field in the cert against the desired hostname. * NB: This is our only defense against Man-In-The-Middle (MITM) attacks! */ hostname = ss->url; if (hostname && hostname[0]) rv = CERT_VerifyCertName(ss->sec.peerCert, hostname); else rv = SECFailure; if (rv != SECSuccess) PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN); return rv; }
static int verify1(struct message *m, int n) { SECItem **digests; NSSCMSMessage *msg; PLArenaPool *poolp; SECAlgorithmID **algids; CERTCertDBHandle *handle; int nlevels, i; int status = 0; int foundsender = 0; char *sender; if ((m = getsig(m, n, &msg)) == NULL) return 1; sender = getsender(m); handle = CERT_GetDefaultCertDB(); nlevels = NSS_CMSMessage_ContentLevelCount(msg); for (i = 0; i < nlevels; i++) { NSSCMSContentInfo *content; SECOidTag tag; content = NSS_CMSMessage_ContentLevel(msg, i); tag = NSS_CMSContentInfo_GetContentTypeTag(content); if (tag == SEC_OID_PKCS7_SIGNED_DATA) { NSSCMSSignedData *data; int nsigners, j; if ((data = NSS_CMSContentInfo_GetContent(content)) == NULL) { fprintf(stderr, "Signed data missing for " "message %d.\n", n); status = -1; break; } if (!NSS_CMSSignedData_HasDigests(data)) { algids = NSS_CMSSignedData_GetDigestAlgs(data); if (getdig(m, n, &digests, &poolp, algids) != OKAY) { status = -1; break; } if (NSS_CMSSignedData_SetDigests(data, algids, digests) != SECSuccess) { fprintf(stderr, "Cannot set digests " "for message %d.\n", n); status = -1; break; } PORT_FreeArena(poolp, PR_FALSE); } if (NSS_CMSSignedData_ImportCerts(data, handle, certUsageEmailSigner, PR_FALSE) != SECSuccess) { fprintf(stderr, "Cannot temporarily import " "certificates for " "message %d.\n", n); status = -1; break; } nsigners = NSS_CMSSignedData_SignerInfoCount(data); if (nsigners == 0) { fprintf(stderr, "Message %d has no signers.\n", n); status = -1; break; } if (!NSS_CMSSignedData_HasDigests(data)) { fprintf(stderr, "Message %d has no digests.\n", n); status = -1; break; } for (j = 0; j < nsigners; j++) { const char *svs; NSSCMSSignerInfo *info; NSSCMSVerificationStatus vs; SECStatus bad; CERTCertificate *cert; const char *addr; int passed = 0; info = NSS_CMSSignedData_GetSignerInfo(data, j); cert = NSS_CMSSignerInfo_GetSigningCertificate (info, handle); bad = NSS_CMSSignedData_VerifySignerInfo(data, j, handle, certUsageEmailSigner); vs = NSS_CMSSignerInfo_GetVerificationStatus (info); svs = NSS_CMSUtil_VerificationStatusToString (vs); addr = CERT_GetCertEmailAddress(&cert->subject); if (sender != NULL && addr != NULL && asccasecmp(sender, addr) == 0) foundsender++; else { addr = CERT_GetFirstEmailAddress(cert); while (sender && addr) { if (!asccasecmp(sender, addr)) { foundsender++; break; } addr = CERT_GetNextEmailAddress (cert, addr); } } if (CERT_VerifyCertNow(handle, cert, PR_TRUE, certUsageEmailSigner, NULL) != SECSuccess) fprintf(stderr, "Bad certificate for " "signer <%s> of " "message %d: %s.\n", addr ? addr : "?", n, bad_cert_str()); else passed++; if (bad) fprintf(stderr, "Bad status for " "signer <%s> of " "message %d: %s.\n", addr ? addr : "?", n, svs); else passed++; if (passed < 2) status = -1; else if (status == 0) status = 1; } } } if (foundsender == 0) { if (sender) { fprintf(stderr, "Signers of message " "%d do not include the sender <%s>\n", n, sender); status = -1; } else fprintf(stderr, "Warning: Message %d has no From: " "header field.\n", n); } else if (status == 1) printf("Message %d was verified successfully.\n", n); if (status == 0) fprintf(stderr, "No verification information found in " "message %d.\n", n); NSS_CMSMessage_Destroy(msg); return status != 1; }
/******************************************************************** * * c e r t _ t r a v _ c a l l b a c k */ static SECStatus cert_trav_callback(CERTCertificate *cert, SECItem *k, void *data) { int list_certs = 1; char *name; if (data) { list_certs = *((int *)data); } #define LISTING_USER_SIGNING_CERTS (list_certs == 1) #define LISTING_ALL_CERTS (list_certs == 2) name = cert->nickname; if (name) { int isSigningCert; isSigningCert = cert->nsCertType & NS_CERT_TYPE_OBJECT_SIGNING; if (!isSigningCert && LISTING_USER_SIGNING_CERTS) return (SECSuccess); /* Display this name or email address */ num_trav_certs++; if (LISTING_ALL_CERTS) { PR_fprintf(outputFD, "%s ", isSigningCert ? "*" : " "); } PR_fprintf(outputFD, "%s\n", name); if (LISTING_USER_SIGNING_CERTS) { int rv = SECFailure; if (rv) { CERTCertificate *issuerCert; issuerCert = CERT_FindCertIssuer(cert, PR_Now(), certUsageObjectSigner); if (issuerCert) { if (issuerCert->nickname && issuerCert->nickname[0]) { PR_fprintf(outputFD, " Issued by: %s\n", issuerCert->nickname); rv = SECSuccess; } CERT_DestroyCertificate(issuerCert); } } if (rv && cert->issuerName && cert->issuerName[0]) { PR_fprintf(outputFD, " Issued by: %s \n", cert->issuerName); } { char *expires; expires = DER_TimeChoiceDayToAscii(&cert->validity.notAfter); if (expires) { PR_fprintf(outputFD, " Expires: %s\n", expires); PORT_Free(expires); } } rv = CERT_VerifyCertNow(cert->dbhandle, cert, PR_TRUE, certUsageObjectSigner, &pwdata); if (rv != SECSuccess) { rv = PORT_GetError(); PR_fprintf(outputFD, " ++ Error ++ THIS CERTIFICATE IS NOT VALID (%s)\n", secErrorString(rv)); } } } return (SECSuccess); }