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 + -
显示快捷键?