📄 sslconn.c
字号:
/*PR_Notify(conn->sslLock); PR_ExitMonitor(conn->sslLock);*/ SSM_DEBUG("returning OK.\n"); return prstatus;loser: (void)SSMSSLDataConnection_UpdateErrorCode(conn); SSM_LockResource(SSMRESOURCE(conn)); SSM_DEBUG("error %d (%s), exiting abnormally.\n", conn->m_error, SSL_Strerror(conn->m_error)); SSM_UnlockResource(SSMRESOURCE(conn)); return PR_FAILURE;}PRStatus SSMSSLDataConnection_TLSStepUp(SSMSSLDataConnection* conn){ PRFileDesc* socket = conn->socketSSL; PRFileDesc* sslsocket = NULL; PR_ASSERT(conn->isTLS == PR_TRUE); if (conn->isSecure == PR_TRUE) { /* socket is already secure */ return PR_SUCCESS; } SSM_DEBUG("Setting up secure socket for this TLS connection.\n"); if (SSM_SetupSSLSocket(socket, &sslsocket, SSMCONTROLCONNECTION(conn)->m_certdb, conn->hostName, (void*)conn) != SECSuccess) { goto loser; } SSM_DEBUG("Resetting handshake.\n"); if (SSL_ResetHandshake(sslsocket, PR_FALSE) != SECSuccess) { goto loser; } /* XXX it is important that the SSL handshake does not take place here * because that would create a deadlock on this thread */ SSM_DEBUG("We now have a secure socket.\n"); /* secure socket is established */ conn->socketSSL = sslsocket; conn->isSecure = PR_TRUE; return PR_SUCCESS;loser: (void)SSMSSLDataConnection_UpdateErrorCode(conn); if (sslsocket == NULL) { if (socket != NULL) { PR_Close(socket); } } else { PR_Close(sslsocket); } return PR_FAILURE;}/* thread function *//* SSL connection is serviced by the data service thread that works on * the client data socket and the SSL socket. * * Our poll descriptor array contains the client data socket and the SSL * target socket in this order. */#define SSL_PDS 3#define READSSL_CHUNKSIZE 16384void SSM_SSLDataServiceThread(void* arg){ SSMStatus rv = PR_SUCCESS; SSMSSLDataConnection* conn = NULL; PRPollDesc pds[SSL_PDS]; PRIntn nSockets = 0; PRInt32 nReady; int i; PRIntn read = 0; PRIntn sent = 0; char **outbound = NULL; char **inbound = NULL; PRIntn oBufSize; SSM_RegisterNewThread("ssl data", (SSMResource *) arg); conn = (SSMSSLDataConnection*)arg; SSM_DEBUG("initializing.\n"); if (arg == NULL) { PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); goto loser; } SSMDATACONNECTION(conn)->m_dataServiceThread = PR_GetCurrentThread(); /* initialize xfer buffers */ outbound = (char **) PR_CALLOC(READSSL_CHUNKSIZE+1); if (outbound == NULL) goto loser; inbound = (char **) PR_CALLOC(READSSL_CHUNKSIZE+1); if (inbound == NULL) goto loser; /* initialize the poll descriptors */ for (i = 0; i < SSL_PDS; i++) { pds[i].fd = NULL; } /* set up sockets */ /* set up the client data socket */ rv = SSMDataConnection_SetupClientSocket(SSMDATACONNECTION(conn)); if (rv != PR_SUCCESS) { goto loser; } /* save the client data socket in the array */ pds[0].fd = SSMDATACONNECTION(conn)->m_clientSocket; pds[0].in_flags = PR_POLL_READ; nSockets++; /* set up the SSL socket */ rv = SSM_GetSSLSocket(conn); if (rv != PR_SUCCESS) { goto loser; } /* save the SSL socket in the array */ pds[1].fd = conn->socketSSL; pds[1].in_flags = PR_POLL_READ; nSockets++; if (conn->isTLS == PR_TRUE) { /* have large outbound buffer size because this is (most likely) * an SSL/SMTP connection */ oBufSize = READSSL_CHUNKSIZE; /* Add step-up FD to the list of FDs until we've been asked to encrypt */ pds[2].fd = conn->stepUpFD; pds[2].in_flags = PR_POLL_READ; nSockets++; } else { oBufSize = LINESIZE; } /* spinning mode. Exchange data between the client socket and the SSL * socket. */ while ((nSockets > 0) && (SSM_Count(SSMDATACONNECTION(conn)->m_shutdownQ) == 0)) { /* XXX The old client does not handle active close from the * server properly in case of keep-alive connections: what * happens is that although we perform a shutdown on the client * socket, the client never sends us a close. If the SSL socket * is removed, we might as well close the client socket by hand. */ /* if the outbound connection is shut down and there is no data * pending in the client socket, perhaps the client is acting up */ if (pds[1].fd == NULL) { /* don't block in polling */ nReady = PR_Poll(pds, SSL_PDS, PR_INTERVAL_NO_WAIT); if (nReady <= 0) { /* either error or the client socket is blocked. Bail. */ rv = SSMSSLDataConnection_UpdateErrorCode(conn); if (SSMDATACONNECTION(conn)->m_clientSocket != NULL) { PR_Shutdown(SSMDATACONNECTION(conn)->m_clientSocket, PR_SHUTDOWN_SEND); } nSockets--; if (nSockets > 1) { /* We were waiting for notification to step up, but that notification won't happen. So, remove stepUpFD from the list as well. */ pds[2].fd = NULL; nSockets = 1; } break; /* go to loser; */ } } SSM_DEBUG("Polling sockets for pending data.\n"); /* poll sockets for pending data */#if 0 if (conn->isTLS == PR_TRUE) { /* we require the lock for this operation and do a non-blocking * poll in case of TLS because we want to yield to the step-up * operation */ SSM_LockResource(SSMRESOURCE(conn)); nReady = PR_Poll(pds, SSL_PDS, PR_INTERVAL_NO_WAIT); SSM_UnlockResource(SSMRESOURCE(conn)); if (nReady == 0) { continue; } } else {#endif /* Poll for however many sockets we're interested in. */ nReady = PR_Poll(pds, nSockets, PR_INTERVAL_NO_TIMEOUT);#if 0 }#endif if (nReady < 0) { rv = SSMSSLDataConnection_UpdateErrorCode(conn); goto loser; } /* Wind down from SSL_PDS because the pollable event takes priority over the I/O sockets. */ for (i = (SSL_PDS-1); i >= 0; i--) { if (pds[i].fd == NULL) { continue; } /* check sockets for data */ if (pds[i].out_flags & (PR_POLL_READ | PR_POLL_EXCEPT)) { if (pds[i].fd == SSMDATACONNECTION(conn)->m_clientSocket) { /* got data at the client socket */ SSM_DEBUG("Attempting to read %ld bytes from client " "socket.\n", oBufSize); read = PR_Recv(SSMDATACONNECTION(conn)->m_clientSocket, outbound, oBufSize, 0, PR_INTERVAL_NO_TIMEOUT); if (read <= 0) { if (read < 0) { /* Got an error */ rv = SSMSSLDataConnection_UpdateErrorCode(conn); SSM_DEBUG("Error receiving data over client " "socket, status == %ld\n", (long)rv); } else { /* We got an EOF */ SSM_DEBUG("Got EOF at client socket.\n"); rv = PR_SUCCESS; } if (conn->socketSSL != NULL) { SSM_DEBUG("Shutting down the target socket.\n"); PR_Shutdown(conn->socketSSL, PR_SHUTDOWN_SEND); } /* remove the socket from the array */ pds[i].fd = NULL; nSockets--; } else { SSM_DEBUG("data: <%s>\n" "Send the data to the " "target.\n", outbound); sent = PR_Send(conn->socketSSL, outbound, read, 0, PR_INTERVAL_NO_TIMEOUT); if (sent != read) { rv = SSMSSLDataConnection_UpdateErrorCode(conn); if (SSMDATACONNECTION(conn)->m_clientSocket != NULL) { SSM_DEBUG("Shutting down the client socket.\n"); PR_Shutdown(SSMDATACONNECTION(conn)->m_clientSocket, PR_SHUTDOWN_SEND); } /* remove the socket from the array */ pds[i].fd = NULL; nSockets--; } } } else if (pds[i].fd == conn->socketSSL) { /* got data at the SSL socket */ SSM_DEBUG("Reading data from target socket.\n"); read = PR_Recv(conn->socketSSL, inbound, READSSL_CHUNKSIZE, 0, PR_INTERVAL_NO_TIMEOUT); if (read <= 0) { if (read < 0) { /* Got error */ rv = SSMSSLDataConnection_UpdateErrorCode(conn); SSM_DEBUG("Error receiving data from target " "socket, status = %ld\n", rv); } else { /* We got an EOF */ SSM_DEBUG("Got EOF at target socket.\n"); rv = PR_SUCCESS; } if (SSMDATACONNECTION(conn)->m_clientSocket != NULL) { SSM_DEBUG("Shutting down the client socket.\n"); PR_Shutdown(SSMDATACONNECTION(conn)->m_clientSocket, PR_SHUTDOWN_SEND); } /* remove the socket from the array */ pds[i].fd = NULL; nSockets--; } else { /* Got data, write it to the client socket */ SSM_DEBUG("Writing to client socket.\n"); sent = PR_Send(SSMDATACONNECTION(conn)->m_clientSocket, inbound, read, 0, PR_INTERVAL_NO_TIMEOUT); if (sent != read) { rv = SSMSSLDataConnection_UpdateErrorCode(conn); if (conn->socketSSL != NULL) { SSM_DEBUG("Shutting down the target socket.\n"); PR_Shutdown(conn->socketSSL, PR_SHUTDOWN_SEND); } /* remove the socket from the array */ pds[i].fd = NULL; nSockets--; } SSM_DEBUG("Wrote %ld bytes.\n", sent); } } else if (pds[i].fd == conn->stepUpFD) { /* We've been told to enable TLS on this connection. Clear the event, step up, and reconfigure sockets. */ PRFileDesc *stepUpFD = conn->stepUpFD; /* Make sure the control connection has settled */ SSM_LockResource(SSMRESOURCE(conn)); if ((pds[i].out_flags & PR_POLL_READ) != 0) /* it's readable, so it should return immediately */ PR_WaitForPollableEvent(stepUpFD); /* Step up to encryption. */ rv = SSMSSLDataConnection_TLSStepUp(conn); conn->m_error = rv; /* tell the control connection */ /* Remove the step-up fd */ conn->stepUpFD = NULL; pds[i].fd = NULL; nSockets--; PR_DestroyPollableEvent(stepUpFD); /* Notify ourselves to wake up the control connection */ SSM_NotifyResource(SSMRESOURCE(conn)); SSM_UnlockResource(SSMRESOURCE(conn)); } } } /* end of for loop */ } /* end of while loop */loser: SSM_DEBUG("** Closing, return value %ld. **\n", rv); if (conn != NULL) { SSM_ShutdownResource(SSMRESOURCE(conn), rv); SSM_FreeResource(SSMRESOURCE(conn)); } if (outbound != NULL) { PR_Free(outbound); } if (inbound != NULL) { PR_Free(inbound); } SSM_DEBUG("SSL data service thread terminated.\n");}/* callback functions and auxilliary functions *//* * Function: SECStatus SSM_SSLAuthCertificate() * Purpose: this callback function is used to authenticate certificates * received from the remote end of an SSL connection. * * Arguments and return values * - arg: certDB handle (cannot be NULL) * - socket: SSL socket * - checkSig: whether to check the signature (usually should be PR_TRUE) * - isServer: whether we are an SSL server (expect PR_FALSE since PSM is * an SSL client) * - returns: SECSuccess if successful; error code otherwise * * ### sjlee: this is essentially a wrapper over the default SSL callback * function. It provides minimal argument checking to the default * callback. When we're confident that the default will do the * job, we might want to drop this... */SECStatus SSM_SSLAuthCertificate(void* arg, PRFileDesc* socket, PRBool checkSig, PRBool isServer){ SSM_DEBUG("checking server cert.\n"); /* check arguments */ if (arg == NULL || socket == NULL || isServer != PR_FALSE) { return (SECStatus) SEC_ERROR_INVALID_ARGS; } /* call the default callback */ return (SECStatus) SSL_AuthCertificate(arg, socket, checkSig, isServer);}/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -