mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-02 15:15:23 +00:00
504 lines
14 KiB
C
504 lines
14 KiB
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 "serv.h"
|
|
#include "servimpl.h"
|
|
|
|
/* Shorthand macros for inherited classes */
|
|
#define SSMRESOURCE(ss) (&(ss)->super)
|
|
|
|
/* implemented in resource.c: this should belong to resource.h! */
|
|
SSMStatus SSM_UnpickleResource(SSMResource** res, SSMResourceType type,
|
|
SSMControlConnection* connection,
|
|
PRIntn len, void* value);
|
|
|
|
SSMStatus
|
|
SSMSSLSocketStatus_Create(void *arg, SSMControlConnection * connection,
|
|
SSMResource **res)
|
|
{
|
|
SSMStatus rv = PR_SUCCESS;
|
|
SSMSSLSocketStatus *ss;
|
|
*res = NULL; /* in case we fail */
|
|
|
|
ss = (SSMSSLSocketStatus *) PR_CALLOC(sizeof(SSMSSLSocketStatus));
|
|
if (!ss) goto loser;
|
|
|
|
rv = SSMSSLSocketStatus_Init(ss, connection,
|
|
(PRFileDesc *) arg,
|
|
SSM_RESTYPE_SSL_SOCKET_STATUS);
|
|
if (rv != PR_SUCCESS) goto loser;
|
|
|
|
SSMSSLSocketStatus_Invariant(ss);
|
|
|
|
*res = &ss->super;
|
|
return PR_SUCCESS;
|
|
|
|
loser:
|
|
if (rv == PR_SUCCESS) rv = PR_FAILURE;
|
|
|
|
if (ss)
|
|
{
|
|
SSMRESOURCE(ss)->m_refCount = 1; /* force destroy */
|
|
SSM_FreeResource(SSMRESOURCE(ss));
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
SSMStatus
|
|
SSMSSLSocketStatus_Init(SSMSSLSocketStatus *ss,
|
|
SSMControlConnection * connection,
|
|
PRFileDesc *fd, SSMResourceType type)
|
|
{
|
|
SSMStatus rv = PR_SUCCESS;
|
|
int keySize, secretKeySize, level;
|
|
SSMResource *certObj;
|
|
SSMResourceID certRID;
|
|
CERTCertificate *cert;
|
|
|
|
/* Initialize superclass */
|
|
SSMResource_Init(connection, SSMRESOURCE(ss), type);
|
|
|
|
/* Get the peer cert and import it into an NSM object */
|
|
cert = SSL_PeerCertificate(fd);
|
|
if (!cert) goto loser;
|
|
rv = SSM_CreateResource(SSM_RESTYPE_CERTIFICATE, cert,
|
|
SSMRESOURCE(ss)->m_connection, &certRID,
|
|
&certObj);
|
|
if (rv != PR_SUCCESS) goto loser;
|
|
ss->m_cert = (SSMResourceCert*)certObj;
|
|
|
|
/* Get the other socket status information */
|
|
rv = SSL_SecurityStatus(fd, &level, &ss->m_cipherName,
|
|
&keySize,
|
|
&secretKeySize,
|
|
NULL, NULL);
|
|
if (rv != PR_SUCCESS) goto loser;
|
|
|
|
ss->m_keySize = keySize;
|
|
ss->m_secretKeySize = secretKeySize;
|
|
ss->m_level = level;
|
|
/* Sanity check before returning */
|
|
SSMSSLSocketStatus_Invariant(ss);
|
|
|
|
goto done;
|
|
loser:
|
|
/* member destruct, if any are allocated, will happen in the
|
|
_Destroy method */
|
|
if (rv == PR_SUCCESS) rv = PR_FAILURE;
|
|
done:
|
|
return rv;
|
|
}
|
|
|
|
SSMStatus
|
|
SSMSSLSocketStatus_Destroy(SSMResource *res, PRBool doFree)
|
|
{
|
|
SSMSSLSocketStatus *ss = (SSMSSLSocketStatus *) res;
|
|
SSMSSLSocketStatus_Invariant(ss);
|
|
/* Destroy our members. */
|
|
if (ss->m_cert)
|
|
{
|
|
SSM_FreeResource(&ss->m_cert->super);
|
|
ss->m_cert = NULL;
|
|
}
|
|
if (ss->m_cipherName)
|
|
{
|
|
PORT_Free(ss->m_cipherName);
|
|
ss->m_cipherName = NULL;
|
|
}
|
|
|
|
/* Destroy superclass. */
|
|
SSMResource_Destroy(res, PR_FALSE);
|
|
|
|
/* Free if asked. */
|
|
if (doFree)
|
|
PR_Free(res);
|
|
|
|
return PR_SUCCESS;
|
|
}
|
|
|
|
void
|
|
SSMSSLSocketStatus_Invariant(SSMSSLSocketStatus *ss)
|
|
{
|
|
/* Superclass invariant */
|
|
SSMResource_Invariant(SSMRESOURCE(ss));
|
|
|
|
/* Class check */
|
|
PR_ASSERT(SSM_IsAKindOf(SSMRESOURCE(ss), SSM_RESTYPE_SSL_SOCKET_STATUS));
|
|
|
|
/* Member check */
|
|
#if 0
|
|
/* Make sure we used a cert to initialize ourselves */
|
|
if (ss->m_cert)
|
|
PR_ASSERT(ss->m_cert != NULL);
|
|
#endif
|
|
}
|
|
|
|
SSMStatus
|
|
SSMSSLSocketStatus_GetAttrIDs(SSMResource *res,
|
|
SSMAttributeID **ids,
|
|
PRIntn *count)
|
|
{
|
|
SSMStatus rv;
|
|
|
|
rv = SSMResource_GetAttrIDs(res, ids, count);
|
|
if (rv != PR_SUCCESS)
|
|
goto loser;
|
|
|
|
*ids = (SSMAttributeID *) PR_REALLOC(*ids, (*count + 4) * sizeof(SSMAttributeID));
|
|
if (! *ids) goto loser;
|
|
|
|
(*ids)[*count++] = SSM_FID_SSS_KEYSIZE;
|
|
(*ids)[*count++] = SSM_FID_SSS_SECRET_KEYSIZE;
|
|
(*ids)[*count++] = SSM_FID_SSS_CERT_ID;
|
|
(*ids)[*count++] = SSM_FID_SSS_CIPHER_NAME;
|
|
|
|
goto done;
|
|
loser:
|
|
if (rv == PR_SUCCESS) rv = PR_FAILURE;
|
|
done:
|
|
return rv;
|
|
}
|
|
|
|
SSMStatus
|
|
SSMSSLSocketStatus_GetAttr(SSMResource *res,
|
|
SSMAttributeID attrID,
|
|
SSMResourceAttrType attrType,
|
|
SSMAttributeValue *value)
|
|
{
|
|
SSMStatus rv = PR_SUCCESS;
|
|
SSMSSLSocketStatus *ss = (SSMSSLSocketStatus *) res;
|
|
char *tmpstr = NULL;
|
|
|
|
SSM_DEBUG("socket status get attr is called.\n");
|
|
SSMSSLSocketStatus_Invariant(ss);
|
|
|
|
/* see what it is */
|
|
switch(attrID)
|
|
{
|
|
case SSM_FID_SSS_KEYSIZE:
|
|
value->type = SSM_NUMERIC_ATTRIBUTE;
|
|
value->u.numeric = ss->m_keySize;
|
|
break;
|
|
case SSM_FID_SSS_SECRET_KEYSIZE:
|
|
value->type = SSM_NUMERIC_ATTRIBUTE;
|
|
value->u.numeric = ss->m_secretKeySize;
|
|
break;
|
|
case SSM_FID_SSS_CERT_ID:
|
|
value->type = SSM_RID_ATTRIBUTE;
|
|
value->u.numeric = ss->m_cert->super.m_id;
|
|
break;
|
|
case SSM_FID_SSS_SECURITY_LEVEL:
|
|
value->type = SSM_NUMERIC_ATTRIBUTE;
|
|
value->u.numeric = ss->m_level;
|
|
break;
|
|
case SSM_FID_SSS_CIPHER_NAME:
|
|
value->type = SSM_STRING_ATTRIBUTE;
|
|
value->u.string.len = PL_strlen(ss->m_cipherName);
|
|
value->u.string.data = (unsigned char *) PL_strdup(ss->m_cipherName);
|
|
break;
|
|
|
|
case SSM_FID_SSS_HTML_STATUS:
|
|
value->type = SSM_STRING_ATTRIBUTE;
|
|
rv = (*res->m_html_func)(res, NULL, (void**)&tmpstr);
|
|
|
|
value->u.string.len = PL_strlen(tmpstr);
|
|
value->u.string.data = (unsigned char *) PL_strdup(tmpstr);
|
|
break;
|
|
|
|
default:
|
|
rv = SSMResource_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:
|
|
if (tmpstr != NULL)
|
|
PR_Free(tmpstr);
|
|
return rv;
|
|
}
|
|
|
|
SSMStatus SSMSSLSocketStatus_Pickle(SSMResource *res, PRIntn * len,
|
|
void **value)
|
|
{
|
|
int blobSize, certSize;
|
|
SSMStatus rv;
|
|
SSMSSLSocketStatus * resource = (SSMSSLSocketStatus *)res;
|
|
void * certBlob, *curptr, *tmpStr = NULL;
|
|
|
|
if (!res || !value) {
|
|
rv = PR_INVALID_ARGUMENT_ERROR;
|
|
goto loser;
|
|
}
|
|
/* in case we fail */
|
|
*value = NULL;
|
|
if (len) *len = 0;
|
|
#if 0
|
|
/* first, pickle cert */
|
|
rv = SSMControlConnection_GetResource(res->m_connection,
|
|
resource->m_certID,
|
|
(SSMResource **)&certObj);
|
|
if (rv != PR_SUCCESS) goto loser;
|
|
#endif
|
|
|
|
rv = SSM_PickleResource(&resource->m_cert->super, &certSize, &certBlob);
|
|
if (rv != PR_SUCCESS)
|
|
goto loser;
|
|
|
|
/* allocate memory for the pickled blob */
|
|
blobSize = certSize + sizeof(PRUint32)*5 +
|
|
SSMSTRING_PADDED_LENGTH(strlen(resource->m_cipherName));
|
|
curptr = PORT_ZAlloc(blobSize);
|
|
if (!curptr) {
|
|
rv = PR_OUT_OF_MEMORY_ERROR;
|
|
goto loser;
|
|
}
|
|
*value = curptr;
|
|
*(PRUint32 *)curptr = resource->m_keySize;
|
|
curptr = (PRUint32 *)curptr + 1;
|
|
*(PRUint32 *)curptr = resource->m_secretKeySize;
|
|
curptr = (PRUint32 *)curptr + 1;
|
|
*(PRInt32*)curptr = resource->m_level;
|
|
curptr = (PRInt32 *)curptr + 1;
|
|
*(PRInt32*)curptr = resource->m_error;
|
|
curptr = (PRInt32 *)curptr + 1;
|
|
rv = SSM_StringToSSMString((SSMString **)&tmpStr, 0, resource->m_cipherName);
|
|
if (rv != PR_SUCCESS)
|
|
goto loser;
|
|
memcpy(curptr, tmpStr, SSM_SIZEOF_STRING(*(SSMString *)tmpStr));
|
|
curptr = (char *)curptr + SSM_SIZEOF_STRING(*(SSMString *)tmpStr);
|
|
PR_Free(tmpStr);
|
|
tmpStr = NULL;
|
|
/* copy cert into the blob */
|
|
memcpy(curptr, certBlob, certSize);
|
|
|
|
if (len) *len = blobSize;
|
|
|
|
return rv;
|
|
|
|
loser:
|
|
if (rv == PR_SUCCESS)
|
|
rv = PR_FAILURE;
|
|
if (value && *value)
|
|
PR_Free(*value);
|
|
if (len)
|
|
*len = 0;
|
|
if (tmpStr)
|
|
PR_Free(tmpStr);
|
|
|
|
return rv;
|
|
}
|
|
|
|
SSMStatus SSMSSLSocketStatus_Unpickle(SSMResource ** res,
|
|
SSMControlConnection * connection,
|
|
PRInt32 len,
|
|
void *value)
|
|
{
|
|
SSMStatus rv = PR_SUCCESS;
|
|
SSMSSLSocketStatus *ss;
|
|
void * curptr = NULL;
|
|
PRUint32 strLength = 0, certLength = 0;
|
|
SSMResource * certResource = NULL;
|
|
|
|
if (!res || !value) {
|
|
rv = PR_INVALID_ARGUMENT_ERROR;
|
|
goto loser;
|
|
}
|
|
*res = NULL; /* in case we fail */
|
|
|
|
ss = (SSMSSLSocketStatus *) PR_CALLOC(sizeof(SSMSSLSocketStatus));
|
|
if (!ss) goto loser;
|
|
ss->m_cipherName = NULL;
|
|
ss->m_cert = NULL;
|
|
|
|
/* Initialize superclass */
|
|
SSMResource_Init(connection, SSMRESOURCE(ss),
|
|
SSM_RESTYPE_SSL_SOCKET_STATUS);
|
|
/* Unpickle socket status data */
|
|
curptr = value;
|
|
|
|
ss->m_keySize = *(PRUint32 *)curptr;
|
|
curptr =(PRUint32 *)curptr + 1;
|
|
ss->m_secretKeySize = *(PRUint32 *)curptr;
|
|
curptr =(PRUint32 *)curptr + 1;
|
|
ss->m_level = *(PRInt32 *)curptr;
|
|
curptr = (PRInt32 *)curptr + 1;
|
|
ss->m_error = *(PRInt32 *)curptr;
|
|
curptr = (PRInt32 *)curptr + 1;
|
|
|
|
/* Fix this */
|
|
rv = SSM_SSMStringToString(&ss->m_cipherName, (int *) &strLength,
|
|
(SSMString *)curptr);
|
|
if (rv != PR_SUCCESS || ss->m_cipherName == NULL || strLength == 0)
|
|
goto loser;
|
|
curptr = (char *)curptr + SSMSTRING_PADDED_LENGTH(strLength) +
|
|
sizeof(PRUint32);
|
|
|
|
/* Unpickle cert */
|
|
certLength = len - ((unsigned long)curptr - (unsigned long)value);
|
|
rv = SSM_UnpickleResource(&certResource, SSM_RESTYPE_CERTIFICATE,
|
|
connection, certLength, curptr);
|
|
if (rv != PR_SUCCESS || !certResource)
|
|
goto loser;
|
|
#if 0
|
|
ss->m_certID = certResource->m_id;
|
|
#endif
|
|
ss->m_cert = (SSMResourceCert*)certResource;
|
|
/* Sanity check before returning */
|
|
SSMSSLSocketStatus_Invariant(ss);
|
|
|
|
*res = SSMRESOURCE(ss);
|
|
goto done;
|
|
|
|
loser:
|
|
if (ss) {
|
|
if (ss->m_cipherName)
|
|
PR_Free(ss->m_cipherName);
|
|
if (ss->m_cert) {
|
|
SSM_FreeResource(&ss->m_cert->super);
|
|
#if 0
|
|
(*(certResource->m_destroy_func))(certResource, PR_TRUE);
|
|
#endif
|
|
}
|
|
PR_Free(certResource);
|
|
}
|
|
if (rv == PR_SUCCESS)
|
|
rv = PR_FAILURE;
|
|
done:
|
|
return rv;
|
|
}
|
|
|
|
SSMStatus SSMSSLSocketStatus_HTML(SSMResource *res, PRIntn *len, void ** value)
|
|
{
|
|
SSMStatus rv = PR_SUCCESS;
|
|
SSMSSLSocketStatus * resource = (SSMSSLSocketStatus *)res;
|
|
char * line = NULL;
|
|
|
|
if (!res || !value) {
|
|
rv = PR_INVALID_ARGUMENT_ERROR;
|
|
goto loser;
|
|
}
|
|
if (len) *len = 0;
|
|
*value = NULL;
|
|
|
|
switch (resource->m_level) {
|
|
case SSL_SECURITY_STATUS_ON_HIGH:
|
|
#ifdef FORTEZZA
|
|
case SSL_SECURITY_STATUS_FORTEZZA:
|
|
#endif
|
|
line = PR_smprintf("%s", SECURITY_HIGH_MESSAGE);
|
|
break;
|
|
case SSL_SECURITY_STATUS_ON_LOW:
|
|
line = PR_smprintf("%s", SECURITY_LOW_MESSAGE);
|
|
break;
|
|
default:
|
|
*value = PR_smprintf("%s", SECURITY_NO_MESSAGE);
|
|
goto done;
|
|
}
|
|
|
|
|
|
if (resource->m_keySize != resource->m_secretKeySize) {
|
|
*value = PR_smprintf("%s (%s, %d bit with %d secret).", line,
|
|
resource->m_cipherName,
|
|
resource->m_keySize,
|
|
resource->m_secretKeySize);
|
|
} else {
|
|
*value = PR_smprintf("%s (%s, %d bit).", line,
|
|
resource->m_cipherName,
|
|
resource->m_keySize);
|
|
}
|
|
|
|
goto done;
|
|
loser:
|
|
if (value && *value)
|
|
PR_Free(*value);
|
|
*value = NULL;
|
|
if (len && *len)
|
|
*len = 0;
|
|
if (rv == PR_SUCCESS)
|
|
rv = PR_FAILURE;
|
|
done:
|
|
if (value && *value && len)
|
|
*len = strlen((char *)*value)+1;
|
|
if (line)
|
|
PR_Free(line);
|
|
return rv;
|
|
}
|
|
|
|
|
|
SSMStatus SSMSSLSocketStatus_UpdateSecurityStatus(SSMSSLSocketStatus* ss,
|
|
PRFileDesc* socket)
|
|
{
|
|
SSMStatus rv = PR_SUCCESS;
|
|
int keySize, secretKeySize, level;
|
|
|
|
/* ss should not be NULL when this function is called */
|
|
PR_ASSERT(ss != NULL);
|
|
|
|
/* Get the security status information */
|
|
if (ss->m_cipherName != NULL) {
|
|
PR_Free(ss->m_cipherName);
|
|
ss->m_cipherName = NULL;
|
|
}
|
|
rv = SSL_SecurityStatus(socket, &level, &ss->m_cipherName, &keySize,
|
|
&secretKeySize, NULL, NULL);
|
|
if (rv != PR_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
|
|
ss->m_keySize = keySize;
|
|
ss->m_secretKeySize = secretKeySize;
|
|
ss->m_level = level;
|
|
|
|
/* Sanity check before returning */
|
|
SSMSSLSocketStatus_Invariant(ss);
|
|
|
|
goto done;
|
|
loser:
|
|
if (rv == PR_SUCCESS) {
|
|
rv = PR_FAILURE;
|
|
}
|
|
if (ss->m_cipherName != NULL) {
|
|
PR_Free(ss->m_cipherName);
|
|
ss->m_cipherName = NULL;
|
|
}
|
|
done:
|
|
return rv;
|
|
}
|