📄 sslconn.c
字号:
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- *//* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is the Netscape security libraries. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable * instead of those above. If you wish to allow use of your * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL. If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. */#include "sslconn.h"#include "ctrlconn.h"#include "sslerror.h"#include "serv.h"#include "servimpl.h"#include "sslskst.h"#include "ssmerrs.h"#include "ssldlgs.h"#include "collectn.h"#include "prefs.h"/* NSS headers */#include "seccomon.h"#include "keyt.h"#include "cert.h"/* Shorthand macros for inherited classes */#define SSMRESOURCE(sslconn) (&(sslconn)->super.super.super)#define SSMCONNECTION(sslconn) (&(sslconn)->super.super)#define SSMDATACONNECTION(sslconn) (&(sslconn)->super)#define SSMCONTROLCONNECTION(sslconn) ((SSMControlConnection*)(sslconn->super.super.m_parent))/* SSM_UserCertChoice: enum for cert choice info */typedef enum {ASK, AUTO} SSM_UserCertChoice;/* persistent cert choice object we will use here */static SSM_UserCertChoice certChoice;/* strings for marking invalid user cert nicknames */#define NICKNAME_EXPIRED_STRING " (expired)"#define NICKNAME_NOT_YET_VALID_STRING " (not yet valid)"/* private function prototypes */void SSMSSLDataConnection_InitializeUIInfo(SSMSSLUIInfo* info);void SSMSSLDataConnection_DestroyUIInfo(SSMSSLUIInfo* info);SSMStatus SSMSSLDataConnection_UpdateSecurityStatus(SSMSSLDataConnection* conn);SECStatus SSM_SetupSSLSocket(PRFileDesc* socket, PRFileDesc** sslsocket, CERTCertDBHandle* handle, char* hostname, void* wincx);SSMStatus SSM_GetSSLSocket(SSMSSLDataConnection* conn);void SSM_SSLDataServiceThread(void* arg);SSMStatus SSM_SetUserCertChoice(SSMSSLDataConnection* conn);SECStatus SSM_ConvertCANamesToStrings(PRArenaPool* arena, char** caNameStrings, CERTDistNames* caNames);SSMStatus ssm_client_auth_prepare_nicknames(SSMSSLDataConnection* conn, CERTCertNicknames* nicknames);PRBool SSM_SSLErrorNeedsDialog(int error);SECStatus SSM_SSLMakeBadServerCertDialog(int error, CERTCertificate* cert, SSMSSLDataConnection* conn);SECStatus SSM_SSLVerifyServerCert(CERTCertDBHandle* handle, CERTCertificate* cert, PRBool checkSig, SSMSSLDataConnection* conn);/* callback functions */SECStatus SSM_SSLAuthCertificate(void* arg, PRFileDesc* socket, PRBool checkSig, PRBool isServer);SECStatus SSM_SSLBadCertHandler(void* arg, PRFileDesc* socket);SECStatus SSM_SSLGetClientAuthData(void* arg, PRFileDesc* socket, struct CERTDistNamesStr* caNames, struct CERTCertificateStr** pRetCert, struct SECKEYPrivateKeyStr** pRetKey);void SSM_SSLHandshakeCallback(PRFileDesc* socket, void* clientData);/* implementations *//* class functions */SSMStatus SSMSSLDataConnection_Create(void* arg, SSMControlConnection* ctrlconn, SSMResource** res){ SSMStatus rv = PR_SUCCESS; SSMSSLDataConnection* conn; /* check arguments */ if (arg == NULL || res == NULL) { goto loser; } *res = NULL; /* in case we fail */ conn = (SSMSSLDataConnection*)PR_CALLOC(sizeof(SSMSSLDataConnection)); if (!conn) { goto loser; } rv = SSMSSLDataConnection_Init(conn, (SSMInfoSSL*)arg, SSM_RESTYPE_SSL_DATA_CONNECTION); if (rv != PR_SUCCESS) { goto loser; } SSMSSLDataConnection_Invariant(conn); *res = &conn->super.super.super; return PR_SUCCESS;loser: if (rv == PR_SUCCESS) { rv = PR_FAILURE; } if (conn) { SSM_ShutdownResource(SSMRESOURCE(conn), rv); SSM_FreeResource(SSMRESOURCE(conn)); } return rv;}SSMStatus SSMSSLDataConnection_Shutdown(SSMResource* arg, SSMStatus status){ SSMStatus rv; SSMSSLDataConnection* conn = (SSMSSLDataConnection*)arg; PRBool firstTime = PR_TRUE; /* ### sjlee: firstTime doesn't seem to be set anywhere */ /* check argument */ if (arg == NULL) { return PR_FAILURE; } /*SSMSSLDataConnection_Invariant(conn); -- this could have been called from loser */ SSM_LockResource(arg); /* shut down base class */ rv = SSMDataConnection_Shutdown(arg, status); if (firstTime) { SSM_DEBUG("First time shutting down SSL connection.\n"); } /* If service threads are done, close the SSL socket */ if (SSMRESOURCE(conn)->m_threadCount == 0) { if (conn->socketSSL) { SSM_DEBUG("Closing SSL socket with linger.\n"); rv = PR_Close(conn->socketSSL); conn->socketSSL = NULL; SSM_DEBUG("Closed SSL socket (rv == %d).\n", rv); } } SSM_UnlockResource(arg); if (!firstTime) { rv = (SSMStatus)SSM_ERR_ALREADY_SHUT_DOWN; } return rv;}SSMStatus SSMSSLDataConnection_Init(SSMSSLDataConnection* conn, SSMInfoSSL* info, SSMResourceType type){ SSMStatus rv = PR_SUCCESS; SSMControlConnection* parent; /* check arguments */ if (conn == NULL || info == NULL) { goto loser; } /* fill in the information we got from the request packet */ parent = info->parent; rv = SSMDataConnection_Init(SSMDATACONNECTION(conn), parent, type); if (rv != PR_SUCCESS) { goto loser; } conn->isTLS = info->isTLS; conn->port = info->port; conn->hostIP = info->hostIP; conn->hostName = info->hostName; /* Initialize UI info */ SSMSSLDataConnection_InitializeUIInfo(&conn->m_UIInfo); if (conn->isTLS == PR_TRUE) { conn->isSecure = PR_FALSE; /* Create the step-up FD so that the control connection can wake us up */ conn->stepUpFD = PR_NewPollableEvent(); if (conn->stepUpFD == NULL) goto loser; } else { conn->isSecure = PR_TRUE; conn->forceHandshake = info->forceHandshake; /* Save the client context */ SSMRESOURCE(conn)->m_clientContext = info->clientContext; } /* Spawn the data service thread */ SSM_DEBUG("Creating SSL data service thread. Getting ref on SSL " "connection.\n"); SSM_GetResourceReference(SSMRESOURCE(conn)); SSMDATACONNECTION(conn)->m_dataServiceThread = SSM_CreateThread(SSMRESOURCE(conn), SSM_SSLDataServiceThread); if (SSMDATACONNECTION(conn)->m_dataServiceThread == NULL) { goto loser; } return PR_SUCCESS;loser: if (rv == PR_SUCCESS) { rv = PR_FAILURE; } return rv;}SSMStatus SSMSSLDataConnection_Destroy(SSMResource* res, PRBool doFree){ SSMSSLDataConnection* conn = (SSMSSLDataConnection*)res; if (res == NULL) { return PR_FAILURE; } /* We should be shut down. */ PR_ASSERT(res->m_threadCount == 0); /* Destroy our fields. */ PR_FREEIF(conn->hostIP); PR_FREEIF(conn->hostName); /* Destroy UI info. */ SSMSSLDataConnection_DestroyUIInfo(&conn->m_UIInfo); /* Destroy step-up FD if we still have one. */ if (conn->stepUpFD) PR_DestroyPollableEvent(conn->stepUpFD); /* Destroy superclass fields. */ SSMDataConnection_Destroy(SSMRESOURCE(conn), PR_FALSE); /* Free the connection object if asked. */ if (doFree) { PR_DELETE(conn); } return PR_SUCCESS;}void SSMSSLDataConnection_Invariant(SSMSSLDataConnection* conn){ SSMDataConnection_Invariant(SSMDATACONNECTION(conn)); SSM_LockResource(SSMRESOURCE(conn)); PR_ASSERT(SSM_IsAKindOf(SSMRESOURCE(conn), SSM_RESTYPE_SSL_DATA_CONNECTION)); SSM_UnlockResource(SSMRESOURCE(conn));}SSMStatus SSMSSLDataConnection_GetAttrIDs(SSMResource* res, SSMAttributeID** ids, PRIntn* count){ SSMStatus rv; if (res == NULL || ids == NULL || count == NULL) { goto loser; } rv = SSMDataConnection_GetAttrIDs(res, ids, count); if (rv != PR_SUCCESS) { goto loser; } *ids = (SSMAttributeID *) PR_REALLOC(*ids, (*count + 1)*sizeof(SSMAttributeID)); if (!*ids) { goto loser; } (*ids)[*count++] = SSM_FID_SSLDATA_SOCKET_STATUS; goto done;loser: if (rv == PR_SUCCESS) { rv = PR_FAILURE; }done: return rv;}SSMStatus SSMSSLDataConnection_GetAttr(SSMResource *res, SSMAttributeID attrID, SSMResourceAttrType attrType, SSMAttributeValue *value){ SSMSSLDataConnection* conn = (SSMSSLDataConnection*)res; SSMStatus rv = PR_SUCCESS; if (res == NULL || value == NULL) { goto loser; } /* see what it is */ switch(attrID) { case SSM_FID_SSLDATA_SOCKET_STATUS: /* if the socket status does not exist at this time (which * is very unlikely usually), we will wait until the handshake * callback creates it */ SSM_LockResource(SSMRESOURCE(conn)); while (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_INTERVAL_NO_TIMEOUT); } if (conn->m_sockStat == NULL) { SSM_DEBUG("No socket status on dead socket.\n"); SSM_UnlockResource(SSMRESOURCE(conn)); goto loser; } /* We have a socket status object, return its resource ID. */ value->u.rid = conn->m_sockStat->super.m_id; value->type = SSM_RID_ATTRIBUTE; SSM_UnlockResource(SSMRESOURCE(conn)); /* if (conn->m_sockStat) { } else { rv = SSM_ERR_ATTRIBUTE_MISSING; goto loser; } */ break; case SSM_FID_SSLDATA_ERROR_VALUE: value->type = SSM_NUMERIC_ATTRIBUTE; SSM_LockResource(SSMRESOURCE(conn)); value->u.numeric = conn->m_error; SSM_DEBUG("Reported error: %ld\n", conn->m_error); SSM_UnlockResource(SSMRESOURCE(conn)); break; default: rv = SSMConnection_GetAttr(res, attrID, attrType, value); if (rv != PR_SUCCESS) { goto loser; } } 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); /* 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));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -