sslconn.c

来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 2,048 行 · 第 1/5 页

C
2,048
字号
    if (PR_StringToNetAddr(conn->hostIP, &addr) != PR_SUCCESS) {        PRIntn hostIndex;        prstatus = PR_GetHostByName(conn->hostName, buffer, 256, &hostentry);	if (prstatus != PR_SUCCESS) {	    goto loser;	}  	SSM_DEBUG("SSL server port: %d / host: %s \n", conn->port, 		  conn->hostName);	do {	    hostIndex = PR_EnumerateHostEnt(0, &hostentry, 					    (PRUint16) conn->port, &addr);	    if (hostIndex < 0) {	        goto loser;	    }	} while (PR_Connect(conn->socketSSL, &addr, PR_INTERVAL_NO_TIMEOUT) != PR_SUCCESS		 && hostIndex > 0);	SSM_DEBUG("Connected to target.\n");    } else {        if (PR_InitializeNetAddr(PR_IpAddrNull, (PRUint16)conn->port, &addr) != PR_SUCCESS) {	    goto loser;	}	if (PR_Connect(conn->socketSSL, &addr, PR_INTERVAL_NO_TIMEOUT) != PR_SUCCESS) {	  goto loser;	}	SSM_DEBUG("SSL server port: %d / host: %s\n", conn->port, 		  conn->hostName);	SSM_DEBUG("connected using hostIP: %s\n", conn->hostIP);    }#ifdef _HACK_    /* ### mwelch Fix for NSPR20 connect problem under 95/NT. */    PR_Sleep(PR_INTERVAL_NO_WAIT);#endif    /* established SSL connection, ready to send data */    if (!conn->isTLS && conn->forceHandshake) {        /* if the client wants a forced handshake (e.g. SSL/IMAP),          * do it here          */        SSM_DEBUG("forcing handshake.\n");        secstatus = (SSL_ForceHandshake(conn->socketSSL) == 0)? SECSuccess:SECFailure;        if (secstatus != SECSuccess) {            goto loser;        }    }    /*	if (conn->m_sockStat) {        SSM_FreeResource(&conn->m_sockStat->super);	}    SSM_CreateResource(SSM_RESTYPE_SSL_SOCKET_STATUS, conn->socketSSL,                        SSMRESOURCE(conn)->m_connection, &statRID,                        (SSMResource**)&conn->m_sockStat);    */		/* check everything is hunky-dorey */    /*	SSMSSLSocketStatus_Invariant(conn->m_sockStat); */    /* end of the block */    /* release SSL lock. SSL connection is established. */    /*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;}/*  * Function: PRStatus SSMSSLDataConnection_TLSStepUp() * Purpose: "step up" the connection and set up an SSL socket for the  *          underlying TCP socket * Arguments and return values: * - conn: TLS connection object to be manipulated * - returns: PR_SUCCESS if successful; PR_FAILURE otherwise * * Notes: SSL handshakes are not done here; it is performed when the first *        read/write operation is done on the secure socket *        This function must be called while the underlying resource is *        locked */static 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) {        /* SSL/SMTP connections usually require a large outbound buffer */        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 Nova-specific: Nova 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, Nova 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) {                        	SSM_DEBUG("Couldn't send all data to the target socket (sent: %d read: %d)\n",                        		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");#if 0                        SSM_DumpBuffer(inbound, read);#endif                        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. */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?