sslconn.c

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

C
2,048
字号
                    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 Cartman 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_SetError(PR_INVALID_ARGUMENT_ERROR, 0);        return SECFailure;	}	/* call the default callback */	return (SECStatus) SSL_AuthCertificate(arg, socket, checkSig, isServer);}/* * Function: SECStatus SSM_SSLBadCertHandler() * Purpose: this callback function is used to handle a situation in which  *			server certificate verification has failed. * * Arguments and return values * - arg: the SSL data connection * - socket: SSL socket * - returns: SECSuccess if the case is handled and it is authorized to *			  continue connection; otherwise SECFailure */SECStatus SSM_SSLBadCertHandler(void* arg, PRFileDesc* socket){	int error;    SSMSSLDataConnection* conn;    CERTCertificate* cert = NULL;    SECStatus rv = SECFailure;	    if (socket == NULL || arg == NULL) {        return SECFailure;    }    conn = (SSMSSLDataConnection*)arg;    if (!(SSMCONTROLCONNECTION(conn)->m_doesUI)) {        /* UI-less application.  We choose to reject the server cert. */        goto loser;    }    cert = SSL_PeerCertificate(conn->socketSSL);    if (cert == NULL) {        goto loser;    }    while (rv != SECSuccess) {        error = PR_GetError();	/* first of all, get error code */	        SSM_DEBUG("Got a bad server cert: error %d (%s).\n", error,                   SSL_Strerror(error));			/* Save error for socket status */		conn->m_sslServerError = error;        if (!SSM_SSLErrorNeedsDialog(error)) {            SSM_DEBUG("Exiting abnormally...\n");            break;        }        if (SSM_SSLMakeBadServerCertDialog(error, cert, conn) != SECSuccess) {            break;        }        /* check the server cert again for more errors */        rv = SSM_DoubleCheckServerCert(cert, conn);    }loser:    if (rv != SECSuccess) {        (void)SSMSSLDataConnection_UpdateErrorCode(conn);    }    if (cert != NULL) {        CERT_DestroyCertificate(cert);    }    return rv;}/* * structs and ASN1 templates for the limited scope-of-use extension * * CertificateScopeEntry ::= SEQUENCE { *     name GeneralName, -- pattern, as for NameConstraints *     portNumber INTEGER OPTIONAL } * * CertificateScopeOfUse ::= SEQUENCE OF CertificateScopeEntry *//* * CERTCertificateScopeEntry: struct for scope entry that can be consumed by *                            the code * certCertificateScopeOfUse: struct that represents the decoded extension data */typedef struct {    SECItem derConstraint;    SECItem derPort;    CERTGeneralName* constraint; /* decoded constraint */    PRIntn port; /* decoded port number */} CERTCertificateScopeEntry;typedef struct {    CERTCertificateScopeEntry** entries;} certCertificateScopeOfUse;/* corresponding ASN1 templates */static const SEC_ASN1Template cert_CertificateScopeEntryTemplate[] = {    { SEC_ASN1_SEQUENCE,       0, NULL, sizeof(CERTCertificateScopeEntry) },    { SEC_ASN1_ANY,      offsetof(CERTCertificateScopeEntry, derConstraint) },    { SEC_ASN1_OPTIONAL | SEC_ASN1_INTEGER,      offsetof(CERTCertificateScopeEntry, derPort) },    { 0 }};static const SEC_ASN1Template cert_CertificateScopeOfUseTemplate[] = {    { SEC_ASN1_SEQUENCE_OF, 0, cert_CertificateScopeEntryTemplate }};/*  * decodes the extension data and create CERTCertificateScopeEntry that can * be consumed by the code */staticSECStatus cert_DecodeScopeOfUseEntries(PRArenaPool* arena, SECItem* extData,                                       CERTCertificateScopeEntry*** entries,                                       int* numEntries){    certCertificateScopeOfUse* scope = NULL;    SECStatus rv = SECSuccess;    int i;    *entries = NULL; /* in case of failure */    *numEntries = 0; /* ditto */    scope = (certCertificateScopeOfUse*)        PORT_ArenaZAlloc(arena, sizeof(certCertificateScopeOfUse));    if (scope == NULL) {        goto loser;    }    rv = SEC_ASN1DecodeItem(arena, (void*)scope,                             cert_CertificateScopeOfUseTemplate, extData);    if (rv != SECSuccess) {        goto loser;    }    *entries = scope->entries;    PR_ASSERT(*entries != NULL);    /* first, let's count 'em. */    for (i = 0; (*entries)[i] != NULL; i++) ;    *numEntries = i;    /* convert certCertificateScopeEntry sequence into what we can readily     * use     */    for (i = 0; i < *numEntries; i++) {        (*entries)[i]->constraint =             cert_DecodeGeneralName(arena, &((*entries)[i]->derConstraint),                                    NULL);        if ((*entries)[i]->derPort.data != NULL) {            (*entries)[i]->port =                 (int)DER_GetInteger(&((*entries)[i]->derPort));        }        else {            (*entries)[i]->port = 0;        }    }    goto done;loser:    if (rv == SECSuccess) {        rv = SECFailure;    }done:    return rv;}static SECStatus cert_DecodeCertIPAddress(SECItem* genname,                                           PRUint32* constraint, PRUint32* mask){    /* in case of failure */    *constraint = 0;    *mask = 0;    PR_ASSERT(genname->data != NULL);    if (genname->data == NULL) {        return SECFailure;    }    if (genname->len != 8) {        /* the length must be 4 byte IP address with 4 byte subnet mask */        return SECFailure;    }    /* get them in the right order */    *constraint = PR_ntohl((PRUint32)(*genname->data));    *mask = PR_ntohl((PRUint32)(*(genname->data + 4)));    return SECSuccess;}static char* _str_to_lower(char* string){#ifdef XP_WIN    return _strlwr(string);#else    int i;    for (i = 0; string[i] != '\0'; i++) {        string[i] = tolower(string[i]);    }    return string;#endif}/* * Sees if the client certificate has a restriction in presenting the cert * to the host: returns PR_TRUE if there is no restriction or if the hostname * (and the port) satisfies the restriction, or PR_FALSE if the hostname (and * the port) does not satisfy the restriction */static PRBool CERT_MatchesScopeOfUse(CERTCertificate* cert, char* hostname,                                     char* hostIP, PRIntn port){    PRBool rv = PR_TRUE; /* whether the cert can be presented */    SECStatus srv;    SECItem extData;    PRArenaPool* arena = NULL;    CERTCertificateScopeEntry** entries = NULL;    /* arrays of decoded scope entries */    int numEntries = 0;    int i;    char* hostLower = NULL;    PRUint32 hostIPAddr = 0;    PR_ASSERT((cert != NULL) && (hostname != NULL) && (hostIP != NULL));    /* find cert extension */    srv = CERT_FindCertExtension(cert, SEC_OID_NS_CERT_EXT_SCOPE_OF_USE,                                 &extData);    if (srv != SECSuccess) {        /* most of the time, this means the extension was not found: also,         * since this is not a critical extension (as of now) we may simply         * return PR_TRUE         */        goto done;    }    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);    if (arena == NULL) {        goto done;    }    /* decode the scope of use entries into pairs of GeneralNames and     * an optional port numbers     */    srv = cert_DecodeScopeOfUseEntries(arena, &extData, &entries, &numEntries);    if (srv != SECSuccess) {        /* XXX What should we do when we failed to decode the extension?  This         *     may mean either the extension was malformed or some (unlikely)         *     fatal error on our part: my argument is that if the extension          *     was malformed the extension "disqualifies" as a valid          *     constraint and we may present the cert         */        goto done;    }    /* loop over these structures */    for (i = 0; i < numEntries; i++) {        /* determine whether the GeneralName is a DNS pattern, an IP address          * constraint, or else         */        CERTGeneralName* genname = entries[i]->constraint;        /* if constraint is NULL, don't bother looking */        if (genname == NULL) {            /* this is not a failure: just continue */            continue;        }        switch (genname->type) {        case certDNSName: {            /* we have a DNS name constraint; we should use only the host name             * information             */            char* pattern = NULL;            char* substring = NULL;            /* null-terminate the string */            genname->name.other.data[genname->name.other.len] = '\0';            pattern = _str_to_lower(genname->name.other.data);            if (hostLower == NULL) {                /* so that it's done only if necessary and only once */                hostLower = _str_to_lower(PL_strdup(hostname));            }            /* the hostname satisfies the constraint */            if (((substring = strstr(hostLower, pattern)) != NULL) &&                /* the hostname contains the pattern */                (strlen(substring) == strlen(pattern)) &&                /* the hostname ends with the pattern */                ((substring == hostLower) || (*(substring-1) == '.'))) {                /* the hostname either is identical to the pattern or                 * belongs to a subdomain                 */                rv = PR_TRUE;            }            else {                rv = PR_FALSE;            }            /* clean up strings if necessary */            break;        }        case certIPAddress: {            PRUint32 constraint;            PRUint32 mask;            PRNetAddr addr;                        if (hostIPAddr == 0) {                /* so that it's done only if necessary and only once */                PR_StringToNetAddr(hostIP, &addr);                hostIPAddr = addr.inet.ip;            }            if (cert_DecodeCertIPAddress(&(genname->name.other), &constraint,                                          &mask) != SECSuccess) {                continue;            }            if ((hostIPAddr & mask) == (constraint & mask)) {                rv = PR_TRUE;            }            else {                rv = PR_FALSE;            }            break;        }        default:            /* ill-formed entry: abort */            continue; /* go to the next entry */        }        if (!rv) {            /* we do not need to check the port: go to the next entry */            continue;        }

⌨️ 快捷键说明

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