sslSessionID * ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port, const char *peerID, const char * urlSvrName) { sslSessionID **sidp; sslSessionID * sid; PRUint32 now; if (!urlSvrName) return NULL; now = ssl_Time(); LOCK_CACHE; sidp = &cache; while ((sid = *sidp) != 0) { PORT_Assert(sid->cached == in_client_cache); PORT_Assert(sid->references >= 1); SSL_TRC(8, ("SSL: Lookup1: sid=0x%x", sid)); if (sid->expirationTime < now || !sid->references) { /* ** This session-id timed out, or was orphaned. ** Don't even care who it belongs to, blow it out of our cache. */ SSL_TRC(7, ("SSL: lookup1, throwing sid out, age=%d refs=%d", now - sid->creationTime, sid->references)); *sidp = sid->next; /* delink it from the list. */ sid->cached = invalid_cache; /* mark not on list. */ if (!sid->references) ssl_DestroySID(sid); else ssl_FreeLockedSID(sid); /* drop ref count, free. */ } else if (!memcmp(&sid->addr, addr, sizeof(PRIPv6Addr)) && /* server IP addr matches */ (sid->port == port) && /* server port matches */ /* proxy (peerID) matches */ (((peerID == NULL) && (sid->peerID == NULL)) || ((peerID != NULL) && (sid->peerID != NULL) && PORT_Strcmp(sid->peerID, peerID) == 0)) && /* is cacheable */ (sid->version < SSL_LIBRARY_VERSION_3_0 || sid->u.ssl3.keys.resumable) && /* server hostname matches. */ (sid->urlSvrName != NULL) && ((0 == PORT_Strcmp(urlSvrName, sid->urlSvrName)) || ((sid->peerCert != NULL) && (SECSuccess == CERT_VerifyCertName(sid->peerCert, urlSvrName))) ) ) { /* Hit */ sid->lastAccessTime = now; sid->references++; break; } else { sidp = &sid->next; } } UNLOCK_CACHE; return sid; }
/* This is the "default" authCert callback function. It is called when a * certificate message is received from the peer and the local application * has not registered an authCert callback function. */ SECStatus SSL_AuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig, PRBool isServer) { SECStatus rv; CERTCertDBHandle * handle; sslSocket * ss; SECCertUsage certUsage; const char * hostname = NULL; PRTime now = PR_Now(); SECItemArray * certStatusArray; ss = ssl_FindSocket(fd); PORT_Assert(ss != NULL); if (!ss) { return SECFailure; } handle = (CERTCertDBHandle *)arg; certStatusArray = &ss->sec.ci.sid->peerCertStatus; if (certStatusArray->len) { PORT_SetError(0); if (CERT_CacheOCSPResponseFromSideChannel(handle, ss->sec.peerCert, now, &certStatusArray->items[0], ss->pkcs11PinArg) != SECSuccess) { PRErrorCode error = PR_GetError(); PORT_Assert(error != 0); } } /* this may seem backwards, but isn't. */ certUsage = isServer ? certUsageSSLClient : certUsageSSLServer; rv = CERT_VerifyCert(handle, ss->sec.peerCert, checkSig, certUsage, now, ss->pkcs11PinArg, NULL); 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; }
SECStatus CertVerifier::VerifySSLServerCert(CERTCertificate* peerCert, /*optional*/ const SECItem* stapledOCSPResponse, Time time, /*optional*/ void* pinarg, const char* hostname, bool saveIntermediatesInPermanentDatabase, Flags flags, /*optional out*/ ScopedCERTCertList* builtChain, /*optional out*/ SECOidTag* evOidPolicy) { PR_ASSERT(peerCert); // XXX: PR_ASSERT(pinarg) PR_ASSERT(hostname); PR_ASSERT(hostname[0]); if (builtChain) { *builtChain = nullptr; } if (evOidPolicy) { *evOidPolicy = SEC_OID_UNKNOWN; } if (!hostname || !hostname[0]) { PR_SetError(SSL_ERROR_BAD_CERT_DOMAIN, 0); return SECFailure; } ScopedCERTCertList builtChainTemp; // CreateCertErrorRunnable assumes that CERT_VerifyCertName is only called // if VerifyCert succeeded. SECStatus rv = VerifyCert(peerCert, certificateUsageSSLServer, time, pinarg, hostname, flags, stapledOCSPResponse, &builtChainTemp, evOidPolicy); if (rv != SECSuccess) { return rv; } rv = CERT_VerifyCertName(peerCert, hostname); if (rv != SECSuccess) { return rv; } if (saveIntermediatesInPermanentDatabase) { SaveIntermediateCerts(builtChainTemp); } if (builtChain) { *builtChain = builtChainTemp.forget(); } return SECSuccess; }
/* * Callback from SSL for checking a (possibly) expired * certificate the peer presents. */ SECStatus JSSL_ConfirmExpiredPeerCert(void *arg, PRFileDesc *fd, PRBool checkSig, PRBool isServer) { SECStatus rv=SECFailure; SECCertUsage certUsage; CERTCertificate* peerCert=NULL; int64 notAfter, notBefore; certUsage = isServer ? certUsageSSLClient : certUsageSSLServer; peerCert = SSL_PeerCertificate(fd); if (peerCert) { rv = CERT_GetCertTimes(peerCert, ¬Before, ¬After); if (rv != SECSuccess) goto finish; /* * Verify the certificate based on it's expiry date. This should * always succeed, if the cert is trusted. It doesn't care if * the cert has expired. */ rv = CERT_VerifyCert(CERT_GetDefaultCertDB(), peerCert, checkSig, certUsage, notAfter, NULL /*pinarg*/, NULL /* log */); } if ( rv != SECSuccess ) goto finish; if( ! isServer ) { /* 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! */ if( peerCert == NULL ) { rv = SECFailure; } else { char* hostname = NULL; 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; } } } finish: if (peerCert!=NULL) CERT_DestroyCertificate(peerCert); return rv; }
/* * 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; }
int sxi_sslctxfun(sxc_client_t *sx, curlev_t *ev, const struct curl_tlssessioninfo *info) { CERTCertificate *cert; int rc = cert_from_sessioninfo(sx, info, &cert); if (rc) return rc; sxi_conns_t *conns = sxi_curlev_get_conns(ev); const char *hostname = sxi_conns_get_sslname(conns); SECStatus ret = CERT_VerifyCertName(cert, hostname); if (ret == SECSuccess) { sxi_curlev_set_verified(ev, 1); } else { PRInt32 err = PR_GetError(); sxi_seterr(sx, SXE_ECOMM, "Certificate is not valid for cluster '%s': %s", hostname, PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT)); sxi_curlev_set_verified(ev, -1); return -1; } return 0; }
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; }
/* * Callback from SSL for checking a (possibly) expired * certificate the peer presents. * * obj - a jobject -> instance of a class implementing * the SSLCertificateApprovalCallback interface */ SECStatus JSSL_JavaCertAuthCallback(void *arg, PRFileDesc *fd, PRBool checkSig, PRBool isServer) { CERTCertificate *peerCert=NULL; CERTVerifyLog log; JNIEnv *env; jobject validityStatus; jmethodID addReasonMethod; int certUsage; int checkcn_rv; jmethodID approveMethod; jboolean result; char *hostname=NULL; SECStatus retval = SECFailure; SECStatus verificationResult; PR_ASSERT(arg != NULL); PR_ASSERT(fd != NULL); /* initialize logging structures */ log.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if( log.arena == NULL ) return SECFailure; log.head = NULL; log.tail = NULL; log.count = 0; /* get the JNI environment */ if((*JSS_javaVM)->AttachCurrentThread(JSS_javaVM, (void**)&env, NULL) != 0){ PR_ASSERT(PR_FALSE); goto finish; } /* First, get a handle on the cert that the peer presented */ peerCert = SSL_PeerCertificate(fd); /* if peer didn't present a cert, why am I called? */ if (peerCert == NULL) goto finish; certUsage = isServer ? certUsageSSLClient : certUsageSSLServer; /* * verify it against current time - (can't use * CERT_VerifyCertNow() since it doesn't allow passing of * logging parameter) */ verificationResult = CERT_VerifyCert( CERT_GetDefaultCertDB(), peerCert, checkSig, certUsage, PR_Now(), NULL /*pinarg*/, &log); if (verificationResult == SECSuccess && log.count > 0) { verificationResult = SECFailure; } /* * Verify the domain name of the cert. */ hostname = SSL_RevealURL(fd); /* really is a hostname, not a URL */ if (hostname && hostname[0]) { checkcn_rv = CERT_VerifyCertName(peerCert, hostname); PORT_Free(hostname); } else { checkcn_rv = SECFailure; } if (checkcn_rv != SECSuccess) { addToVerifyLog(env, &log,peerCert,SSL_ERROR_BAD_CERT_DOMAIN,0); if((*env)->ExceptionOccurred(env) != NULL) goto finish; verificationResult = SECFailure; } /* * create a new ValidityStatus object */ { jclass clazz; jmethodID cons; clazz = (*env)->FindClass(env, SSLCERT_APP_CB_VALIDITY_STATUS_CLASS); if( clazz == NULL ) goto finish; cons = (*env)->GetMethodID(env, clazz, PLAIN_CONSTRUCTOR, PLAIN_CONSTRUCTOR_SIG); if( cons == NULL ) goto finish; validityStatus = (*env)->NewObject(env, clazz, cons); if( validityStatus == NULL ) { goto finish; } /* get the addReason methodID while we're at it */ addReasonMethod = (*env)->GetMethodID(env, clazz, SSLCERT_APP_CB_VALIDITY_STATUS_ADD_REASON_NAME, SSLCERT_APP_CB_VALIDITY_STATUS_ADD_REASON_SIG); if( addReasonMethod == NULL ) { goto finish; } } /* * Load up the ValidityStatus object with all the reasons for failure */ if (verificationResult == SECFailure) { CERTVerifyLogNode *node; int error; CERTCertificate *errorcert=NULL; int depth; jobject ninjacert; node = log.head; while (node) { error = node->error; errorcert = node->cert; node->cert = NULL; depth = node->depth; ninjacert = JSS_PK11_wrapCert(env,&errorcert); (*env)->CallVoidMethod(env, validityStatus, addReasonMethod, error, ninjacert, depth ); node = node->next; } } /* * Call the approval callback */ { jobject approvalCallbackObj; jclass approvalCallbackClass; jobject peerninjacert; approvalCallbackObj = (jobject) arg; approvalCallbackClass = (*env)->GetObjectClass(env,approvalCallbackObj); approveMethod = (*env)->GetMethodID( env, approvalCallbackClass, SSLCERT_APP_CB_APPROVE_NAME, SSLCERT_APP_CB_APPROVE_SIG); if( approveMethod == NULL ) { PR_ASSERT(PR_FALSE); goto finish; } peerninjacert = JSS_PK11_wrapCert(env,&peerCert); if( peerninjacert == NULL) { PR_ASSERT(PR_FALSE); goto finish; } result = (*env)->CallBooleanMethod(env, approvalCallbackObj, approveMethod, peerninjacert, validityStatus); if( result == JNI_TRUE ) { retval = SECSuccess; } } finish: if( peerCert != NULL ) { CERT_DestroyCertificate(peerCert); } PORT_FreeArena(log.arena, PR_FALSE); return retval; }
/* Function: SECStatus myAuthCertificate() * * Purpose: This function is our custom certificate authentication handler. * * Note: This implementation is essentially the same as the default * SSL_AuthCertificate(). */ SECStatus myAuthCertificate(void *arg, PRFileDesc *socket, PRBool checksig, PRBool isServer) { SECCertificateUsage certUsage; CERTCertificate * cert; void * pinArg; char * hostName; SECStatus secStatus; if (!arg || !socket) { errWarn("myAuthCertificate"); return SECFailure; } /* Define how the cert is being used based upon the isServer flag. */ certUsage = isServer ? certificateUsageSSLClient : certificateUsageSSLServer; cert = SSL_PeerCertificate(socket); pinArg = SSL_RevealPinArg(socket); if (dumpChain == PR_TRUE) { dumpCertChain(cert, certUsage); } secStatus = CERT_VerifyCertificateNow((CERTCertDBHandle *)arg, cert, checksig, certUsage, pinArg, NULL); /* If this is a server, we're finished. */ if (isServer || secStatus != SECSuccess) { SECU_printCertProblems(stderr, (CERTCertDBHandle *)arg, cert, checksig, certUsage, pinArg, PR_FALSE); CERT_DestroyCertificate(cert); return secStatus; } /* Certificate is OK. Since this is the client side of an SSL * connection, we need to verify that the name field in the cert * matches the desired hostname. This is our defense against * man-in-the-middle attacks. */ /* SSL_RevealURL returns a hostName, not an URL. */ hostName = SSL_RevealURL(socket); if (hostName && hostName[0]) { secStatus = CERT_VerifyCertName(cert, hostName); } else { PR_SetError(SSL_ERROR_BAD_CERT_DOMAIN, 0); secStatus = SECFailure; } if (hostName) PR_Free(hostName); CERT_DestroyCertificate(cert); return secStatus; }