SECStatus SSL_CertDBHandleSet(PRFileDesc *fd, CERTCertDBHandle *dbHandle) { sslSocket * ss; ss = ssl_FindSocket(fd); if (!ss) return SECFailure; if (!dbHandle) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } ss->dbHandle = dbHandle; return SECSuccess; }
SECStatus SSLInt_Set0RttAlpn(PRFileDesc *fd, PRUint8 *data, unsigned int len) { sslSocket *ss = ssl_FindSocket(fd); if (!ss) { return SECFailure; } ss->xtnData.nextProtoState = SSL_NEXT_PROTO_EARLY_VALUE; if (ss->xtnData.nextProto.data) { SECITEM_FreeItem(&ss->xtnData.nextProto, PR_FALSE); } if (!SECITEM_AllocItem(NULL, &ss->xtnData.nextProto, len)) return SECFailure; PORT_Memcpy(ss->xtnData.nextProto.data, data, len); return SECSuccess; }
/* NEED LOCKS IN HERE. */ SECStatus SSL_SetPKCS11PinArg(PRFileDesc *s, void *arg) { sslSocket *ss; ss = ssl_FindSocket(s); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in GetClientAuthDataHook", SSL_GETPID(), s)); return SECFailure; } ss->pkcs11PinArg = arg; return SECSuccess; }
void SSLInt_PrintTls13CipherSpecs(PRFileDesc *fd) { PRCList *cur_p; sslSocket *ss = ssl_FindSocket(fd); if (!ss) { return; } fprintf(stderr, "Cipher specs\n"); for (cur_p = PR_NEXT_LINK(&ss->ssl3.hs.cipherSpecs); cur_p != &ss->ssl3.hs.cipherSpecs; cur_p = PR_NEXT_LINK(cur_p)) { ssl3CipherSpec *spec = (ssl3CipherSpec *)cur_p; fprintf(stderr, " %s\n", spec->phase); } }
PRInt32 SSLInt_CountTls13CipherSpecs(PRFileDesc *fd) { PRCList *cur_p; PRInt32 ct = 0; sslSocket *ss = ssl_FindSocket(fd); if (!ss) { return -1; } for (cur_p = PR_NEXT_LINK(&ss->ssl3.hs.cipherSpecs); cur_p != &ss->ssl3.hs.cipherSpecs; cur_p = PR_NEXT_LINK(cur_p)) { ++ct; } return ct; }
PRBool SSLInt_CheckSecretsDestroyed(PRFileDesc *fd) { sslSocket *ss = ssl_FindSocket(fd); if (!ss) { return PR_FALSE; } CHECK_SECRET(currentSecret); CHECK_SECRET(resumptionMasterSecret); CHECK_SECRET(dheSecret); CHECK_SECRET(clientEarlyTrafficSecret); CHECK_SECRET(clientHsTrafficSecret); CHECK_SECRET(serverHsTrafficSecret); return PR_TRUE; }
/* given PRFileDesc, returns a copy of certificate associated with the socket * the caller should delete the cert when done with SSL_DestroyCertificate */ CERTCertificate * SSL_RevealCert(PRFileDesc * fd) { CERTCertificate * cert = NULL; sslSocket * sslsocket = NULL; sslsocket = ssl_FindSocket(fd); /* CERT_DupCertificate increases reference count and returns pointer to * the same cert */ if (sslsocket && sslsocket->sec.peerCert) cert = CERT_DupCertificate(sslsocket->sec.peerCert); return cert; }
/* ** Returns Negative number on error, zero or greater on success. ** Returns the amount of data immediately available to be read. */ int SSL_DataPending(PRFileDesc *fd) { sslSocket *ss; int rv = 0; ss = ssl_FindSocket(fd); if (ss && ss->opt.useSecurity) { ssl_GetRecvBufLock(ss); rv = ss->gs.writeOffset - ss->gs.readOffset; ssl_ReleaseRecvBufLock(ss); } return rv; }
/* NEED LOCKS IN HERE. */ CERTCertificate * SSL_PeerCertificate(PRFileDesc *fd) { sslSocket *ss; ss = ssl_FindSocket(fd); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificate", SSL_GETPID(), fd)); return 0; } if (ss->opt.useSecurity && ss->sec.peerCert) { return CERT_DupCertificate(ss->sec.peerCert); } return 0; }
/* Configure a certificate and private key. * * This function examines the certificate and key to determine which slot (or * slots) to place the information in. As long as certificates are different * (based on having different values of sslServerCertType), then this function * can be called multiple times and the certificates will all be remembered. */ SECStatus SSL_ConfigServerCert(PRFileDesc *fd, CERTCertificate *cert, SECKEYPrivateKey *key, const SSLExtraServerCertData *data, unsigned int data_len) { sslSocket *ss; SECKEYPublicKey *pubKey; sslKeyPair *keyPair; SECStatus rv; SSLExtraServerCertData dataCopy = { ssl_auth_null, NULL, NULL, NULL }; ss = ssl_FindSocket(fd); if (!ss) { return SECFailure; } if (!cert || !key) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } if (data) { if (data_len > sizeof(dataCopy)) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } PORT_Memcpy(&dataCopy, data, data_len); } pubKey = CERT_ExtractPublicKey(cert); if (!pubKey) { return SECFailure; } keyPair = ssl_MakeKeyPairForCert(key, pubKey); if (!keyPair) { /* pubKey is adopted by ssl_MakeKeyPairForCert() */ PORT_SetError(SEC_ERROR_NO_MEMORY); return SECFailure; } rv = ssl_ConfigCertByUsage(ss, cert, keyPair, &dataCopy); ssl_FreeKeyPair(keyPair); return rv; }
SECStatus SSL_HandshakeNegotiatedExtension(PRFileDesc * socket, SSLExtensionType extId, PRBool *pYes) { /* some decisions derived from SSL_GetChannelInfo */ sslSocket * sslsocket = NULL; PRBool enoughFirstHsDone = PR_FALSE; if (!pYes) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } sslsocket = ssl_FindSocket(socket); if (!sslsocket) { SSL_DBG(("%d: SSL[%d]: bad socket in HandshakeNegotiatedExtension", SSL_GETPID(), socket)); return SECFailure; } *pYes = PR_FALSE; if (sslsocket->firstHsDone) { enoughFirstHsDone = PR_TRUE; } else if (sslsocket->ssl3.initialized && ssl3_CanFalseStart(sslsocket)) { enoughFirstHsDone = PR_TRUE; } /* according to public API SSL_GetChannelInfo, this doesn't need a lock */ if (sslsocket->opt.useSecurity && enoughFirstHsDone) { if (sslsocket->ssl3.initialized) { /* SSL3 and TLS */ /* now we know this socket went through ssl3_InitState() and * ss->xtnData got initialized, which is the only member accessed by * ssl3_ExtensionNegotiated(); * Member xtnData appears to get accessed in functions that handle * the handshake (hello messages and extension sending), * therefore the handshake lock should be sufficient. */ ssl_GetSSL3HandshakeLock(sslsocket); *pYes = ssl3_ExtensionNegotiated(sslsocket, extId); ssl_ReleaseSSL3HandshakeLock(sslsocket); } } return SECSuccess; }
SECStatus SSL_GetPreliminaryChannelInfo(PRFileDesc *fd, SSLPreliminaryChannelInfo *info, PRUintn len) { sslSocket *ss; SSLPreliminaryChannelInfo inf; /* Check if we can properly return the length of data written and that * we're not asked to return more information than we know how to provide. */ if (!info || len < sizeof inf.length || len > sizeof inf) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } ss = ssl_FindSocket(fd); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in SSL_GetPreliminaryChannelInfo", SSL_GETPID(), fd)); return SECFailure; } memset(&inf, 0, sizeof(inf)); inf.length = PR_MIN(sizeof(inf), len); inf.valuesSet = ss->ssl3.hs.preliminaryInfo; inf.protocolVersion = ss->version; inf.cipherSuite = ss->ssl3.hs.cipher_suite; inf.canSendEarlyData = !ss->sec.isServer && (ss->ssl3.hs.zeroRttState == ssl_0rtt_sent || ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted); /* We shouldn't be able to send early data if the handshake is done. */ PORT_Assert(!ss->firstHsDone || !inf.canSendEarlyData); if (ss->sec.ci.sid && (ss->ssl3.hs.zeroRttState == ssl_0rtt_sent || ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted)) { inf.maxEarlyDataSize = ss->sec.ci.sid->u.ssl3.locked.sessionTicket.max_early_data_size; } else { inf.maxEarlyDataSize = 0; } memcpy(info, &inf, inf.length); return SECSuccess; }
/* NEED LOCKS IN HERE. */ SECStatus SSL_AuthCertificateHook(PRFileDesc *s, SSLAuthCertificate func, void *arg) { sslSocket *ss; ss = ssl_FindSocket(s); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in AuthCertificateHook", SSL_GETPID(), s)); return SECFailure; } ss->authCertificate = func; ss->authCertificateArg = arg; return SECSuccess; }
/* NEED LOCKS IN HERE. */ SECStatus SSL_GetClientAuthDataHook(PRFileDesc *s, SSLGetClientAuthData func, void *arg) { sslSocket *ss; ss = ssl_FindSocket(s); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in GetClientAuthDataHook", SSL_GETPID(), s)); return SECFailure; } ss->getClientAuthData = func; ss->getClientAuthDataArg = arg; return SECSuccess; }
/* For more info see ssl.h */ SECStatus SSL_SNISocketConfigHook(PRFileDesc *fd, SSLSNISocketConfig func, void *arg) { sslSocket *ss; ss = ssl_FindSocket(fd); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in SNISocketConfigHook", SSL_GETPID(), fd)); return SECFailure; } ss->sniSocketConfig = func; ss->sniSocketConfigArg = arg; return SECSuccess; }
SECStatus SSL_BadCertHook(PRFileDesc *fd, SSLBadCertHandler f, void *arg) { sslSocket *ss; ss = ssl_FindSocket(fd); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in SSLBadCertHook", SSL_GETPID(), fd)); return SECFailure; } ss->handleBadCert = f; ss->badCertArg = arg; return SECSuccess; }
SECStatus SSLInt_AdvanceWriteSeqNum(PRFileDesc *fd, PRUint64 to) { PRUint64 epoch; sslSocket *ss; ss = ssl_FindSocket(fd); if (!ss) { return SECFailure; } if (to >= (1ULL << 48)) { return SECFailure; } ssl_GetSpecWriteLock(ss); epoch = ss->ssl3.cwSpec->write_seq_num >> 48; ss->ssl3.cwSpec->write_seq_num = (epoch << 48) | to; ssl_ReleaseSpecWriteLock(ss); return SECSuccess; }
SECStatus SSL_SetClientChannelIDCallback(PRFileDesc *fd, SSLClientChannelIDCallback callback, void *arg) { sslSocket *ss = ssl_FindSocket(fd); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetClientChannelIDCallback", SSL_GETPID(), fd)); return SECFailure; } ss->getChannelID = callback; ss->getChannelIDArg = arg; return SECSuccess; }
SECStatus SSL_CacheSession(PRFileDesc *fd) { sslSocket * ss = ssl_FindSocket(fd); SECStatus rv = SECFailure; if (ss) { ssl_Get1stHandshakeLock(ss); ssl_GetSSL3HandshakeLock(ss); ssl3_CacheSessionUnlocked(ss); rv = SECSuccess; ssl_ReleaseSSL3HandshakeLock(ss); ssl_Release1stHandshakeLock(ss); } return rv; }
/* Try to make progress on an SSL handshake by attempting to read the ** next handshake from the peer, and sending any responses. ** For non-blocking sockets, returns PR_ERROR_WOULD_BLOCK if it cannot ** read the next handshake from the underlying socket. ** For SSLv2, returns when handshake is complete or fatal error occurs. ** For SSLv3, returns when handshake is complete, or application data has ** arrived that must be taken by application before handshake can continue, ** or a fatal error occurs. ** Application should use handshake completion callback to tell which. */ SECStatus SSL_ForceHandshake(PRFileDesc *fd) { sslSocket *ss; SECStatus rv = SECFailure; ss = ssl_FindSocket(fd); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in ForceHandshake", SSL_GETPID(), fd)); return rv; } /* Don't waste my time */ if (!ss->opt.useSecurity) return SECSuccess; ssl_Get1stHandshakeLock(ss); if (ss->version >= SSL_LIBRARY_VERSION_3_0) { int gatherResult; ssl_GetRecvBufLock(ss); gatherResult = ssl3_GatherCompleteHandshake(ss, 0); ssl_ReleaseRecvBufLock(ss); if (gatherResult > 0) { rv = SECSuccess; } else if (gatherResult == 0) { PORT_SetError(PR_END_OF_FILE_ERROR); } else if (gatherResult == SECWouldBlock) { PORT_SetError(PR_WOULD_BLOCK_ERROR); } } else if (!ss->firstHsDone) { rv = ssl_Do1stHandshake(ss); } else { /* tried to force handshake on an SSL 2 socket that has ** already completed the handshake. */ rv = SECSuccess; /* just pretend we did it. */ } ssl_Release1stHandshakeLock(ss); return rv; }
PRBool SSLInt_SendNewSessionTicket(PRFileDesc *fd) { sslSocket *ss = ssl_FindSocket(fd); if (!ss) { return PR_FALSE; } ssl_GetSSL3HandshakeLock(ss); ssl_GetXmitBufLock(ss); SECStatus rv = tls13_SendNewSessionTicket(ss); if (rv == SECSuccess) { rv = ssl3_FlushHandshake(ss, 0); } ssl_ReleaseXmitBufLock(ss); ssl_ReleaseSSL3HandshakeLock(ss); return rv == SECSuccess; }
/* Public deprecated function */ SECStatus SSL_SetSignedCertTimestamps(PRFileDesc *fd, const SECItem *scts, SSLKEAType certType) { sslSocket *ss; SECStatus rv; ss = ssl_FindSocket(fd); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetSignedCertTimestamps", SSL_GETPID(), fd)); return SECFailure; } switch (certType) { case ssl_kea_rsa: rv = ssl_SetSignedTimestampsInSlot(ss, ssl_auth_rsa_decrypt, scts); if (rv != SECSuccess) { return SECFailure; } return ssl_SetSignedTimestampsInSlot(ss, ssl_auth_rsa_sign, scts); case ssl_kea_dh: return ssl_SetSignedTimestampsInSlot(ss, ssl_auth_dsa, scts); case ssl_kea_ecdh: rv = ssl_SetSignedTimestampsInSlot(ss, ssl_auth_ecdsa, scts); if (rv != SECSuccess) { return SECFailure; } rv = ssl_SetSignedTimestampsInSlot(ss, ssl_auth_ecdh_rsa, scts); if (rv != SECSuccess) { return SECFailure; } return ssl_SetSignedTimestampsInSlot(ss, ssl_auth_ecdh_ecdsa, scts); default: SSL_DBG(("%d: SSL[%d]: invalid cert type in SSL_SetSignedCertTimestamps", SSL_GETPID(), fd)); PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } }
/* Public deprecated function */ SECStatus SSL_ConfigSecureServerWithCertChain(PRFileDesc *fd, CERTCertificate *cert, const CERTCertificateList *certChainOpt, SECKEYPrivateKey *key, SSLKEAType certType) { sslSocket *ss; ss = ssl_FindSocket(fd); if (!ss) { return SECFailure; } if (!cert != !key) { /* Configure both, or neither */ PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } if (!cert) { switch (certType) { case ssl_kea_rsa: ssl_RemoveCertAndKeyByAuthType(ss, ssl_auth_rsa_decrypt); ssl_RemoveCertAndKeyByAuthType(ss, ssl_auth_rsa_sign); break; case ssl_kea_dh: ssl_RemoveCertAndKeyByAuthType(ss, ssl_auth_dsa); break; case ssl_kea_ecdh: ssl_RemoveCertAndKeyByAuthType(ss, ssl_auth_ecdsa); ssl_RemoveCertAndKeyByAuthType(ss, ssl_auth_ecdh_rsa); ssl_RemoveCertAndKeyByAuthType(ss, ssl_auth_ecdh_ecdsa); break; default: PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } return SECSuccess; } return ssl_AddCertsByKEA(ss, cert, certChainOpt, key, certType); }
SECStatus SSL_InvalidateSession(PRFileDesc *fd) { sslSocket * ss = ssl_FindSocket(fd); SECStatus rv = SECFailure; if (ss) { ssl_Get1stHandshakeLock(ss); ssl_GetSSL3HandshakeLock(ss); if (ss->sec.ci.sid && ss->sec.uncache) { ss->sec.uncache(ss->sec.ci.sid); rv = SECSuccess; } ssl_ReleaseSSL3HandshakeLock(ss); ssl_Release1stHandshakeLock(ss); } return rv; }
/* NEED LOCKS IN HERE. */ CERTCertificate * SSL_LocalCertificate(PRFileDesc *fd) { sslSocket *ss; ss = ssl_FindSocket(fd); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificate", SSL_GETPID(), fd)); return NULL; } if (ss->opt.useSecurity) { if (ss->sec.localCert) { return CERT_DupCertificate(ss->sec.localCert); } if (ss->sec.ci.sid && ss->sec.ci.sid->localCert) { return CERT_DupCertificate(ss->sec.ci.sid->localCert); } } return NULL; }
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 SECStatus ssl_SetTimeout(PRFileDesc *fd, PRIntervalTime timeout) { sslSocket *ss; ss = ssl_FindSocket(fd); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in SetTimeout", SSL_GETPID(), fd)); return SECFailure; } SSL_LOCK_READER(ss); ss->rTimeout = timeout; if (ss->opt.fdx) { SSL_LOCK_WRITER(ss); } ss->wTimeout = timeout; if (ss->opt.fdx) { SSL_UNLOCK_WRITER(ss); } SSL_UNLOCK_READER(ss); return SECSuccess; }
SECItem * SSL_GetNegotiatedHostInfo(PRFileDesc *fd) { SECItem *sniName = NULL; sslSocket *ss; char *name = NULL; ss = ssl_FindSocket(fd); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in SSL_GetNegotiatedHostInfo", SSL_GETPID(), fd)); return NULL; } if (ss->sec.isServer) { if (ss->version > SSL_LIBRARY_VERSION_3_0 && ss->ssl3.initialized) { /* TLS */ SECItem *crsName; ssl_GetSpecReadLock(ss); /*********************************/ crsName = &ss->ssl3.hs.srvVirtName; if (crsName->data) { sniName = SECITEM_DupItem(crsName); } ssl_ReleaseSpecReadLock(ss); /*----------------------------*/ } return sniName; } name = SSL_RevealURL(fd); if (name) { sniName = PORT_ZNew(SECItem); if (!sniName) { PORT_Free(name); return NULL; } sniName->data = (void *)name; sniName->len = PORT_Strlen(name); } return sniName; }
/* * attempt to restart the handshake after asynchronously handling * a request for the client's certificate. * * inputs: * cert Client cert chosen by application. * Note: ssl takes this reference, and does not bump the * reference count. The caller should drop its reference * without calling CERT_DestroyCertificate after calling this * function. * * key Private key associated with cert. This function takes * ownership of the private key, so the caller should drop its * reference without destroying the private key after this * function returns. * * certChain Chain of signers for cert. * Note: ssl takes this reference, and does not copy the chain. * The caller should drop its reference without destroying the * chain. SSL will free the chain when it is done with it. * * Return value: XXX * * XXX This code only works on the initial handshake on a connection, XXX * It does not work on a subsequent handshake (redo). */ SECStatus SSL_RestartHandshakeAfterCertReq(PRFileDesc * fd, CERTCertificate * cert, SECKEYPrivateKey * key, CERTCertificateList *certChain) { sslSocket * ss = ssl_FindSocket(fd); SECStatus ret; if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in SSL_RestartHandshakeAfterCertReq", SSL_GETPID(), fd)); if (cert) { CERT_DestroyCertificate(cert); } if (key) { SECKEY_DestroyPrivateKey(key); } if (certChain) { CERT_DestroyCertificateList(certChain); } return SECFailure; } ssl_Get1stHandshakeLock(ss); /************************************/ if (ss->version >= SSL_LIBRARY_VERSION_3_0) { ret = ssl3_RestartHandshakeAfterCertReq(ss, cert, key, certChain); } else { if (certChain != NULL) { CERT_DestroyCertificateList(certChain); } PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2); ret = SECFailure; } ssl_Release1stHandshakeLock(ss); /************************************/ return ret; }
/* NEED LOCKS IN HERE. */ CERTCertList * SSL_PeerCertificateChain(PRFileDesc *fd) { sslSocket *ss; CERTCertList *chain = NULL; CERTCertificate *cert; ssl3CertNode *cur; ss = ssl_FindSocket(fd); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificateChain", SSL_GETPID(), fd)); return NULL; } if (!ss->opt.useSecurity || !ss->sec.peerCert) { PORT_SetError(SSL_ERROR_NO_CERTIFICATE); return NULL; } chain = CERT_NewCertList(); if (!chain) { return NULL; } cert = CERT_DupCertificate(ss->sec.peerCert); if (CERT_AddCertToListTail(chain, cert) != SECSuccess) { goto loser; } for (cur = ss->ssl3.peerCertChain; cur; cur = cur->next) { cert = CERT_DupCertificate(cur->cert); if (CERT_AddCertToListTail(chain, cert) != SECSuccess) { goto loser; } } return chain; loser: CERT_DestroyCertList(chain); return NULL; }