sslconn.c

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

C
2,048
字号
		}    }    goto done;loser:    value->type = SSM_NO_ATTRIBUTE;    if (rv == PR_SUCCESS) {		rv = PR_FAILURE;	}done:    return rv;}/* * Function: SSMStatus SSMSSLDataConnection_PickleSecurityStatus() * Purpose: fills in information on security status (pickled socket status *          and the security level) on PickleSecurityStatus request * * Arguments and return values: * - conn: SSL connection object * - len: length of the pickled data * - blob: pickled data * - securityLevel: security level * - returns: PR_SUCCESS if successful; error code otherwise * * Note: Note that this is not really a pickle class function.  This is *       specially designed to handle security status requests efficiently. */SSMStatus SSMSSLDataConnection_PickleSecurityStatus(SSMSSLDataConnection* conn,                                                   PRIntn* len, void** blob,                                                   PRIntn* securityLevel){    SSMStatus rv = PR_SUCCESS;    PR_ASSERT(conn != NULL);    /* in case of failure */    *len = 0;    *blob = NULL;    *securityLevel = 0;    /* the connection may not be secure yet in case of proxy connections:     * we should just return and indicate no security if that's the case     */    if (!conn->isSecure) {        return rv;    }    /* if the socket status does not exist at this time (which is usually     * very unlikely), we will wait until the handshake callback creates it     */    SSM_LockResource(SSMRESOURCE(conn));    if (conn->m_sockStat == NULL ||        conn->m_sockStat->m_cipherName == NULL) {        SSM_DEBUG("Oops, the security status has not been updated.  "                  "Waiting...\n");        SSM_WaitResource(SSMRESOURCE(conn), PR_TicksPerSecond());    }    if (conn->m_sockStat == NULL) {        SSM_DEBUG("No socket status on dead socket.\n");        SSM_UnlockResource(SSMRESOURCE(conn));        rv = PR_FAILURE;        goto loser;    }    /* it's probably OK to unlock it here */    SSM_UnlockResource(SSMRESOURCE(conn));    /* we have a socket status object. */    rv = SSMSSLSocketStatus_Pickle(&conn->m_sockStat->super, len, blob);    if (rv != PR_SUCCESS) {        SSM_DEBUG("Failed to pickle the socket status.\n");        goto loser;    }    /* get the security level */    *securityLevel = conn->m_sockStat->m_level;    /*     * The client retrieved the socket status, so we can release our     * refernce now.     */    if (!conn->m_statusFetched) {        SSM_FreeResource(SSMRESOURCE(conn));        conn->m_statusFetched = PR_TRUE;    } loser:    return rv;}/* * Function: SSMStatus SSMSSLDataConnection_FormSubmitHandler() * Purpose: handles any UI form submission that has an SSMSSLDataConnection *          object as target * Expected request: * - command: "formsubmit_handler" * - baseRef: "formsubmit_dosubmit_js" * - target: an SSMSSLDataConnection object * - formName: "cert_selection" | "bad_server_cert" * Arguments and return values * - res: SSMSSLDataConnection object * - req: the HTTPRequest object to be processed * - returns: SSM_SUCCESS if successful; error otherwise * * Note: add more handling helper functions if there are other form *       submission scenarios */SSMStatus SSMSSLDataConnection_FormSubmitHandler(SSMResource* res,                                                 HTTPRequest* req){    SSMStatus rv;    char* tmpStr = NULL;    SSMSSLDataConnection* conn;    conn = (SSMSSLDataConnection*)res;        /* make sure you got the right baseRef */    rv = SSM_HTTPParamValue(req, "baseRef", &tmpStr);    if (rv != SSM_SUCCESS ||        PL_strcmp(tmpStr, "windowclose_doclose_js") != 0) {        goto loser;    }    /* differentiate among different form submission events by looking up     * formName, and dispatch the request to the appropriate handler      */    /* cleaning up (unlocking monitors, etc.) is handled by individual     * handlers, so just go to done     */    if (res->m_formName == NULL) {        goto loser;    }    if (PL_strcmp(res->m_formName, "cert_selection") == 0) {        rv = SSM_ClientAuthCertSelectionButtonHandler(req);        goto done;    }    else if (PL_strcmp(res->m_formName, "bad_server_cert") == 0) {        /* server auth failure other than unknown issuer case */        rv = SSM_ServerAuthFailureButtonHandler(req);        goto done;    }    else {        /* unknown form name; abort */        SSM_DEBUG("don't know how to handle this form.\n");        goto loser;    }loser:    if (rv == SSM_SUCCESS) {        rv = SSM_FAILURE;    }    SSM_LockResource(req->target);    conn->m_UIInfo.chosen = -1;    conn->m_UIInfo.trustBadServerCert = BSCA_NO;    conn->m_UIInfo.UICompleted = PR_TRUE;    SSM_NotifyResource(req->target);    SSM_UnlockResource(req->target);done:    return rv;}void SSMSSLDataConnection_InitializeUIInfo(SSMSSLUIInfo* info){    info->UICompleted = PR_FALSE;    info->numFilteredCerts = 0;    info->certNicknames = NULL;    info->chosen = -1;    /* negative value denotes no cert was chosen */    info->trustBadServerCert = BSCA_NO;}void SSMSSLDataConnection_DestroyUIInfo(SSMSSLUIInfo* info){    int i;    if (info->numFilteredCerts != 0) {        for (i = 0; i < info->numFilteredCerts; i++) {            PR_FREEIF(info->certNicknames[i]);        }        PR_FREEIF(info->certNicknames);    }}SSMStatus SSMSSLDataConnection_UpdateSecurityStatus(SSMSSLDataConnection* conn){    SSMStatus rv = PR_SUCCESS;	PR_ASSERT(conn != NULL);		SSM_LockResource(SSMRESOURCE(conn));    if (conn->m_sockStat == NULL) {        /* socket status has not been created.  The security status will         * be properly populated by creating the socket status.         */        SSMResourceID statRID;        SSM_CreateResource(SSM_RESTYPE_SSL_SOCKET_STATUS, conn->socketSSL,                            SSMRESOURCE(conn)->m_connection, &statRID,                            (SSMResource**)&conn->m_sockStat);		conn->m_sockStat->m_error = conn->m_sslServerError;        /*         * Just in case someone's waiting on the resource.         */        SSM_LockResource(SSMRESOURCE(conn));        SSM_NotifyResource(SSMRESOURCE(conn));        SSM_UnlockResource(SSMRESOURCE(conn));    }    else {        /* just update the values */        rv = SSMSSLSocketStatus_UpdateSecurityStatus(conn->m_sockStat,                                                      conn->socketSSL);        if (rv != PR_SUCCESS) {            goto loser;        }    }loser:    /* in case we fail to update the security status, we still notify     * because we don't want to quit just because this failed...     */    SSM_NotifyResource(SSMRESOURCE(conn));    /* notify SSMSSLDataConnection_GetAttr() for the socket RID */	SSM_UnlockResource(SSMRESOURCE(conn));    return rv;}/* updates the error code in case of an exception: returns the current * error code (0 if no error)  */static SSMStatus SSMSSLDataConnection_UpdateErrorCode(SSMSSLDataConnection* conn){    PR_ASSERT(conn != NULL);    SSM_LockResource(SSMRESOURCE(conn));    if (conn->m_error == 0) {        /* update the error code only if it is not already set:         * otherwise preserve the initial error code         */        PRInt32 rv;        rv = PR_GetError();        if (rv != SEC_ERROR_LIBRARY_FAILURE) {            /* XXX sometimes NSS reports this error even when connection             *     terminates normally: will escape this error here so that             *     this is not reported erroneously             */            conn->m_error = rv;        }    }    SSM_UnlockResource(SSMRESOURCE(conn));    return conn->m_error;}/* functions for setting up and configuring SSL connection */SECStatus SSM_SetupSSLSocket(PRFileDesc* socket, PRFileDesc** sslsocket,                             CERTCertDBHandle* handle, char* hostname,                             void* wincx){    SECStatus rv = SECFailure;    /* check arguments */    if ((socket == NULL) || (sslsocket == NULL) || (handle == NULL) ||         (hostname == NULL) || (wincx == NULL)) {        goto loser;    }    *sslsocket = NULL;  	/* import the socket into SSL layer */    *sslsocket = SSL_ImportFD(NULL, socket);    if (*sslsocket == NULL) {        goto loser;    }    	/* set some SSL settings for the socket */    rv = SSL_Enable(*sslsocket, SSL_SECURITY, PR_TRUE);    if (rv != SECSuccess) {		goto loser;	}  	rv = SSL_Enable(*sslsocket, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE);    if (rv != SECSuccess) {		goto loser;	}	rv = SSL_Enable(*sslsocket, SSL_ENABLE_FDX, PR_TRUE);    if (rv != SECSuccess) {		goto loser;	}	  	/* set callbacks */  	/* client authentication */  	rv = SSL_GetClientAuthDataHook(*sslsocket,                                    (SSLGetClientAuthData)SSM_SSLGetClientAuthData,                                    NULL) == 0 ? SECSuccess : SECFailure;    if (rv  != SECSuccess) {		goto loser;	}    	/* server cert authentication */	rv = SSL_AuthCertificateHook(*sslsocket,                                 (SSLAuthCertificate)SSM_SSLAuthCertificate,                                 (void*)handle) == 0 ? SECSuccess : SECFailure;    if (rv != SECSuccess) {		goto loser;	}    	rv = SSL_BadCertHook(*sslsocket, (SSLBadCertHandler)SSM_SSLBadCertHandler,                          wincx) == 0 ? SECSuccess : SECFailure;    if (rv != SECSuccess) {  		goto loser;	}    rv = SSL_HandshakeCallback(*sslsocket,                                (SSLHandshakeCallback)SSM_SSLHandshakeCallback,                               wincx) == 0 ? SECSuccess : SECFailure;    if (rv != SECSuccess) {        goto loser;    }    SSM_DEBUG("setting PKCS11 pin arg.\n");    rv = SSL_SetPKCS11PinArg(*sslsocket, wincx) == 0 ? SECSuccess : SECFailure;    if (rv != SECSuccess) {        goto loser;    }    /* prepare against man-in-the-middle attacks */    rv = SSL_SetURL(*sslsocket, hostname) == 0 ? SECSuccess : SECFailure;    if (rv != SECSuccess) {        goto loser;    }  	return rv;loser:	if (*sslsocket == NULL) {		/* aborted before SSL_ImportFD() */		if (socket != NULL) {			PR_Close(socket);		}	}	else {		PR_Close(*sslsocket);        *sslsocket = NULL;	}	return rv;}SSMStatus SSM_GetSSLSocket(SSMSSLDataConnection* conn){    SECStatus secstatus = SECSuccess;    PRStatus prstatus = PR_SUCCESS;    PRFileDesc* socket = NULL;    PRSocketOptionData sockdata;    SSMControlConnection* ctrlconn;    PRNetAddr addr;    PRHostEnt hostentry;    char buffer[256];    SSM_DEBUG("SSM_GetSSLSocket entered.\n");	/* check argument first */	if (conn == NULL) {		return PR_FAILURE;	}	    /* Enter SSL lock. We will release once connection is set up.      * If GetSecurityStatus request comes in before we are done, it'll spin      * on the SSL lock. (This lock is not used anyplace else.)     */      /*PR_EnterMonitor(conn->sslLock);*/    /* set up SSL secure socket */    SSM_DEBUG("setting up secure socket.\n");    socket = PR_NewTCPSocket();    if (socket == NULL) {        goto loser;    }    /* make the socket blocking - default on some platforms is non-blocking */    sockdata.option = PR_SockOpt_Nonblocking;    sockdata.value.non_blocking = PR_FALSE;    if (PR_SetSocketOption(socket, &sockdata) != PR_SUCCESS) {        goto loser;    }    if (!conn->isTLS) {        /* set up SSL secure socket */        SSM_DEBUG("setting up secure socket.\n");        ctrlconn = SSMCONTROLCONNECTION(conn);        secstatus = SSM_SetupSSLSocket(socket, &conn->socketSSL,                                       ctrlconn->m_certdb, conn->hostName,                                        (void*)conn);        if (secstatus != SECSuccess) {            goto loser;        }    }    else {        /* do not need to create a secure socket here */        conn->socketSSL = socket;    }	    /* prepare and setup network connection */    SSM_DEBUG("preparing and setting up network connection.\n");

⌨️ 快捷键说明

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