sslconn.c
来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 2,048 行 · 第 1/5 页
C
2,048 行
/* finally, check the optional port number */ if ((entries[i]->port != 0) && (port != entries[i]->port)) { /* port number does not match */ rv = PR_FALSE; continue; } /* we have a match */ PR_ASSERT(rv); break; }done: /* clean up entries */ if (arena != NULL) { PORT_FreeArena(arena, PR_FALSE); } if (hostLower != NULL) { PR_Free(hostLower); } return rv;}/* * Function: SECStatus SSM_SSLGetClientAuthData() * Purpose: this callback function is used to pull client certificate * information upon server request * * Arguments and return values * - arg: SSL data connection * - socket: SSL socket we're dealing with * - caNames: list of CA names * - pRetCert: returns a pointer to a pointer to a valid certificate if * successful; otherwise NULL * - pRetKey: returns a pointer to a pointer to the corresponding key if * successful; otherwise NULL * - returns: SECSuccess if successful; error code otherwise */SECStatus SSM_SSLGetClientAuthData(void* arg, PRFileDesc* socket, CERTDistNames* caNames, CERTCertificate** pRetCert, SECKEYPrivateKey** pRetKey){ void* wincx = NULL; SECStatus rv = SECFailure; SSMSSLDataConnection* conn; SSMControlConnection* ctrlconn; PRArenaPool* arena = NULL; char** caNameStrings = NULL; CERTCertificate* cert = NULL; SECKEYPrivateKey* privKey = NULL; CERTCertList* certList = NULL; CERTCertListNode* node; CERTCertNicknames* nicknames = NULL; char* extracted = NULL; PRIntn keyError = 0; /* used for private key retrieval error */ SSM_DEBUG("Client authentication callback function called.\n"); /* do some argument checking */ if (socket == NULL || caNames == NULL || pRetCert == NULL || pRetKey == NULL) { PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); return SECFailure; } /* get PKCS11 pin argument */ wincx = SSL_RevealPinArg(socket); if (wincx == NULL) { return SECFailure; } /* get the right connections */ conn = (SSMSSLDataConnection*)wincx; ctrlconn = (SSMControlConnection*)(SSMCONNECTION(conn)->m_parent); PR_ASSERT(ctrlconn); /* create caNameStrings */ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (arena == NULL) { goto loser; } caNameStrings = (char**)PORT_ArenaAlloc(arena, sizeof(char*)*(caNames->nnames)); if (caNameStrings == NULL) { goto loser; } rv = SSM_ConvertCANamesToStrings(arena, caNameStrings, caNames); if (rv != SECSuccess) { goto loser; } /* get the preference */ if (SSM_SetUserCertChoice(conn) != SSM_SUCCESS) { goto loser; } /* find valid user cert and key pair */ if (certChoice == AUTO) { /* automatically find the right cert */ /* find all user certs that are valid and for SSL */ certList = CERT_FindUserCertsByUsage(ctrlconn->m_certdb, certUsageSSLClient, PR_TRUE, PR_TRUE, wincx); if (certList == NULL) { goto noCert; } /* filter the list to those issued by CAs supported by the server */ rv = CERT_FilterCertListByCANames(certList, caNames->nnames, caNameStrings, certUsageSSLClient); if (rv != SECSuccess) { goto noCert; } /* make sure the list is not empty */ node = CERT_LIST_HEAD(certList); if (CERT_LIST_END(node, certList)) { goto noCert; } /* loop through the list until we find a cert with a key */ while (!CERT_LIST_END(node, certList)) { /* if the certificate has restriction and we do not satisfy it * we do not use it */ if (!CERT_MatchesScopeOfUse(node->cert, conn->hostName, conn->hostIP, conn->port)) { node = CERT_LIST_NEXT(node); continue; } privKey = PK11_FindKeyByAnyCert(node->cert, wincx); if (privKey != NULL) { /* this is a good cert to present */ cert = CERT_DupCertificate(node->cert); break; } keyError = PR_GetError(); if (keyError == SEC_ERROR_BAD_PASSWORD) { /* problem with password: bail */ goto loser; } node = CERT_LIST_NEXT(node); } if (cert == NULL) { goto noCert; } } else { /* user selects a cert to present */ int i; /* find all user certs that are valid and for SSL */ /* note that we are allowing expired certs in this list */ certList = CERT_FindUserCertsByUsage(ctrlconn->m_certdb, certUsageSSLClient, PR_TRUE, PR_FALSE, wincx); if (certList == NULL) { goto noCert; } if (caNames->nnames != 0) { /* filter the list to those issued by CAs supported by the * server */ rv = CERT_FilterCertListByCANames(certList, caNames->nnames, caNameStrings, certUsageSSLClient); if (rv != SECSuccess) { goto loser; } } if (CERT_LIST_END(CERT_LIST_HEAD(certList), certList)) { /* list is empty - no matching certs */ goto noCert; } /* filter it further for hostname restriction */ node = CERT_LIST_HEAD(certList); while (!CERT_LIST_END(node, certList)) { if (!CERT_MatchesScopeOfUse(node->cert, conn->hostName, conn->hostIP, conn->port)) { CERTCertListNode* removed = node; node = CERT_LIST_NEXT(removed); CERT_RemoveCertListNode(removed); } else { node = CERT_LIST_NEXT(node); } } if (CERT_LIST_END(CERT_LIST_HEAD(certList), certList)) { goto noCert; } nicknames = CERT_NicknameStringsFromCertList(certList, NICKNAME_EXPIRED_STRING, NICKNAME_NOT_YET_VALID_STRING); if (nicknames == NULL) { goto loser; } SSM_DEBUG("%d valid user certs found.\n", nicknames->numnicknames); conn->m_UIInfo.numFilteredCerts = nicknames->numnicknames; if (ssm_client_auth_prepare_nicknames(conn, nicknames) != SSM_SUCCESS) { goto loser; } /* create a cert selection dialog and get back the chosen nickname */ if (SSM_SSLMakeClientAuthDialog(conn) != SSM_SUCCESS) { goto loser; } PR_ASSERT(conn->m_UIInfo.chosen >= 0); i = conn->m_UIInfo.chosen; SSM_DEBUG("Cert %s was selected.\n", conn->m_UIInfo.certNicknames[i]); /* first we need to extract the real nickname in case the cert * is an expired or not a valid one yet */ extracted = CERT_ExtractNicknameString(conn->m_UIInfo.certNicknames[i], NICKNAME_EXPIRED_STRING, NICKNAME_NOT_YET_VALID_STRING); if (extracted == NULL) { goto loser; } /* find the cert under that nickname */ node = CERT_LIST_HEAD(certList); while (!CERT_LIST_END(node, certList)) { if (PL_strcmp(node->cert->nickname, extracted) == 0) { cert = CERT_DupCertificate(node->cert); break; } node = CERT_LIST_NEXT(node); } if (cert == NULL) { goto loser; } /* go get the private key */ privKey = PK11_FindKeyByAnyCert(cert, wincx); if (privKey == NULL) { keyError = PR_GetError(); if (keyError == SEC_ERROR_BAD_PASSWORD) { /* problem with password: bail */ goto loser; } else { goto noCert; } } } /* rv == SECSuccess */ SSM_DEBUG("Yahoo! Client auth complete.\n"); goto done;noCert:loser: if (rv == SECSuccess) { rv = SECFailure; } if (cert != NULL) { CERT_DestroyCertificate(cert); cert = NULL; }done: if (extracted != NULL) { PR_Free(extracted); } if (nicknames != NULL) { CERT_FreeNicknames(nicknames); } if (certList != NULL) { CERT_DestroyCertList(certList); } if (arena != NULL) { PORT_FreeArena(arena, PR_FALSE); } *pRetCert = cert; *pRetKey = privKey; return rv;}/* * Function: SSMStatus SSM_SetUserCertChoice() * Purpose: sets certChoice by reading the preference * * Arguments and return values * - conn: SSMSSLDataConnection * - returns: SSM_SUCCESS if successful; SSM_FAILURE otherwise * * Note: If done properly, this function will read the identifier strings * for ASK and AUTO modes, read the selected strings from the * preference, compare the strings, and determine in which mode it is * in. * We currently use ASK mode for UI apps and AUTO mode for UI-less * apps without really asking for preferences. */SSMStatus SSM_SetUserCertChoice(SSMSSLDataConnection* conn){ SSMStatus rv; SSMControlConnection* parent; parent = SSMCONTROLCONNECTION(conn); if (parent->m_doesUI) { char* mode = NULL; rv = PREF_GetStringPref(parent->m_prefs, "security.default_personal_cert", &mode); if (rv != PR_SUCCESS) { return SSM_FAILURE; } if (PL_strcmp(mode, "Select Automatically") == 0) { certChoice = AUTO; } else if (PL_strcmp(mode, "Ask Every Time") == 0) { certChoice = ASK; } else { return SSM_FAILURE; } } else { SSM_DEBUG("UI-less app: use auto cert selection.\n"); certChoice = AUTO; } return SSM_SUCCESS;}/* * Function: SECStatus SSM_ConvertCANamesToStrings() * Purpose: creates CA names strings from (CERTDistNames* caNames) * * Arguments and return values * - arena: arena to allocate strings on * - caNameStrings: filled with CA names strings on return * - caNames: CERTDistNames to extract strings from * - return: SECSuccess if successful; error code otherwise * * Note: copied in its entirety from Nova code */SECStatus SSM_ConvertCANamesToStrings(PRArenaPool* arena, char** caNameStrings, CERTDistNames* caNames){ SECItem* dername; SECStatus rv; int headerlen; uint32 contentlen; SECItem newitem; int n; char* namestring; for (n = 0; n < caNames->nnames; n++) { newitem.data = NULL; dername = &caNames->names[n]; rv = DER_Lengths(dername, &headerlen, &contentlen); if (rv != SECSuccess) { goto loser; } if (headerlen + contentlen != dername->len) { /* This must be from an enterprise 2.x server, which sent * incorrectly formatted der without the outer wrapper of * type and length. Fix it up by adding the top level * header. */ if (dername->len <= 127) { newitem.data = (unsigned char *) PR_Malloc(dername->len + 2); if (newitem.data == NULL) { goto loser; } newitem.data[0] = (unsigned char)0x30; newitem.data[1] = (unsigned char)dername->len; (void)memcpy(&newitem.data[2], dername->data, dername->len); } else if (dername->len <= 255) { newitem.data = (unsigned char *) PR_Malloc(dername->len + 3); if (newitem.data == NULL) { goto loser; } newitem.data[0] = (unsigned char)0x30; newitem.data[1] = (unsigned char)0x81; newitem.data[2] = (unsigned char)dername->len; (void)memcpy(&newitem.data[3], dername->data, dername->len); } else { /* greater than 256, better be less than 64k */ newitem.data = (unsigned char *) PR_Malloc(dername->len + 4); if (newitem.data == NULL) { goto loser; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?