📄 password.c
字号:
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- *//* * 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 "connect.h"#include "ssmerrs.h"#include "ctrlconn.h"#include "prinrval.h"#include "crmf.h"#include "newproto.h"#include "messages.h"#include "minihttp.h"#include "textgen.h"#include "pk11func.h"extern SSMHashTable * tokenList;extern PRMonitor * tokenLock;#define SSMRESOURCE(conn) (&(conn)->super)/* Make these into functions? */#if 0#define SSM_PARENT_CONN(x) ((((SSMConnection *)(x))->m_parent) != NULL)? \(((SSMControlConnection *)(((SSMConnection *)(x))->m_parent))):\((SSMControlConnection *)x)#define SSM_PWD_TABLE(x) (SSM_PARENT_CONN(x))->m_passwdTable #define SSM_OUT_QUEUE(x) (SSM_PARENT_CONN(x))->m_controlOutQ#endif#if 1 SSMControlConnection * SSM_PARENT_CONN (SSMConnection * x) { return (((((SSMConnection *)(x))->m_parent) != NULL)? (((SSMControlConnection *)(((SSMConnection *)(x))->m_parent))): ((SSMControlConnection *)x));}SSMHashTable * SSM_PWD_TABLE(SSMConnection * x) { return (SSM_PARENT_CONN(x)->m_passwdTable);}SSMCollection * SSM_OUT_QUEUE(SSMConnection * x){ return (SSM_PARENT_CONN(x)->m_controlOutQ);}#endifPRInt32 SSM_GetTokenKey(PK11SlotInfo * slot) { return ((PK11_GetSlotID(slot)<<16) | PK11_GetModuleID(slot));}char * SSM_GetPasswdCallback(PK11SlotInfo *slot, PRBool retry, void *arg){ return SSM_GetAuthentication(slot, retry, PR_FALSE, (SSMResource*)arg);}/* Do a couple of things in this functions: * 1) Get a password from user, and authenticate to token. * 2) Save this password encrypted in the global PSM tokenList * for future reference. * Need to save password in case other users will need to authenticate * to the same tokens, so we make sure they're using the correct * passwords. * 3) Save this password encrypted in the control connection table in * case we will need to use it again. */char * SSM_GetAuthentication(PK11SlotInfo * slot, PRBool retry, PRBool init, SSMResource * res){ PRInt32 tokenKey; SSMStatus rv = PR_SUCCESS; char * passwd = NULL, * tmp = NULL; PRBool first = PR_FALSE; SSM_TokenInfo * info = NULL, * infoLocal = NULL; SSMConnection *conn = &(res->m_connection->super); tokenKey = SSM_GetTokenKey(slot); /* register as interested in a password */ SSM_PARENT_CONN(conn)->m_waiting++; /* Get passwd table lock. */ SSM_LockPasswdTable(conn); /* Look for entry for moduleID/slotID. */ rv = SSM_HashFind(SSM_PWD_TABLE(conn), tokenKey, (void **)&passwd); SSM_UnlockPasswdTable(conn); if (rv != PR_SUCCESS) { first = PR_TRUE; /* no entry found, we are the first to authenticate to this slot */ SSM_DEBUG("%ld: creating passwd table entry for %s \n", conn, PK11_GetSlotName(slot)); SSM_LockPasswdTable(conn); rv = SSM_HashInsert(SSM_PWD_TABLE(conn),tokenKey,(void *)SSM_NO_PASSWORD); SSM_UnlockPasswdTable(conn); if (rv != PR_SUCCESS) { SSM_DEBUG("%ld: could not create entry in password table\n", conn); goto loser; } rv = SSM_AskUserPassword(res, slot, retry, init); if (rv != PR_SUCCESS) { SSM_DEBUG("%ld: error sending password request event\n", conn); goto loser; } } /* end of the we-are-first-to-request-this-passwd-clause */ /* If no password found, wait for it */ if (!passwd || passwd == (char *)SSM_NO_PASSWORD) { rv = SSMControlConnection_WaitPassword(conn, tokenKey, &passwd); if (rv != PR_SUCCESS) goto loser; } if (((int) passwd) == SSM_CANCEL_PASSWORD) { /* no password was provided or user hit "Cancel" */ SSM_LockPasswdTable(conn); rv = SSM_HashRemove(SSM_PWD_TABLE(conn), tokenKey, (void **)&passwd); SSM_UnlockPasswdTable(conn); if (rv != SSM_SUCCESS) SSM_DEBUG("SSM_GetAuthentication: user hit Cancel, can't remove password from connection table\n"); passwd = NULL; goto done; } if (first) { /* We were the first to request the password, * so we need to enter it in to the token list. */ /* encrypt the password */ if (SSM_EncryptPasswd(slot, passwd, &info) != SSM_SUCCESS) { SSM_DEBUG("%ld: could not encrypt password\n.", conn); goto loser; } /* Place encrypted passwd in PSM-wide tokenList */ PR_EnterMonitor(tokenLock); /* Remove from tokenList if already on the list - must be stale */ rv = SSM_HashRemove(tokenList, tokenKey, (void **)&tmp); if (rv == SSM_SUCCESS && tmp && tmp != (char *)SSM_NO_PASSWORD && tmp != (char *)SSM_CANCEL_PASSWORD) { /* free stale data */ PR_Free(tmp); tmp = NULL; } rv = SSM_HashInsert(tokenList, tokenKey, info); PR_ExitMonitor(tokenLock); if (rv != PR_SUCCESS) { SSM_DEBUG("%ld: can't create encr passwd entry\n", conn, tokenKey); goto loser; } /* Store encrypted password in control connection table */ infoLocal = (SSM_TokenInfo *) PORT_ZAlloc(sizeof(SSM_TokenInfo)); if (!infoLocal) goto loser; infoLocal->slot = info->slot; infoLocal->tokenID = info->tokenID; infoLocal->encryptedLen = info->encryptedLen; infoLocal->symKey = info->symKey; infoLocal->encrypted = (char *) PORT_ZAlloc(info->encryptedLen); if (!infoLocal->encrypted) goto loser; memcpy(infoLocal->encrypted, info->encrypted, info->encryptedLen); PR_EnterMonitor(SSM_PARENT_CONN(conn)->m_encrPasswdLock); rv = SSM_HashRemove(SSM_PARENT_CONN(conn)->m_encrPasswdTable, tokenKey, (void **)&tmp); if (rv == SSM_SUCCESS && tmp && tmp != (char *)SSM_NO_PASSWORD && tmp != (char *)SSM_CANCEL_PASSWORD ) {/* free stale data */ PR_Free(tmp); tmp = NULL; } rv = SSM_HashInsert(SSM_PARENT_CONN(conn)->m_encrPasswdTable, tokenKey, infoLocal); PR_ExitMonitor(SSM_PARENT_CONN(conn)->m_encrPasswdLock); if (rv != PR_SUCCESS) { SSM_DEBUG("%ld: cannot insert token %d entry in encrPasswdTable\n", conn, tokenKey); goto loser; } SSM_DEBUG("%ld: wait untill others are done with passwd, remove it\n", conn); /* while ((SSM_PARENT_CONN(conn))->m_waiting > 1) * PR_Sleep(SSM_PASSWORD_WAIT_TIME); */ SSM_LockPasswdTable(conn); rv = SSM_HashRemove(SSM_PWD_TABLE(conn), tokenKey, (void **)&passwd); if (rv != PR_SUCCESS) { SSM_DEBUG("%ld: could not remove passwd.\n", conn); goto loser; } SSM_UnlockPasswdTable(conn); } /* end of if-first clause */ goto done; loser: /* cleanup */ PR_FREEIF(passwd); passwd = NULL; if (info) { PR_FREEIF(info->encrypted); PR_Free(info); } if (infoLocal) { PR_FREEIF(infoLocal->encrypted); PR_Free(infoLocal); } done: /* We are done receiving passwd */ (SSM_PARENT_CONN(conn))->m_waiting--; return passwd ? strdup (passwd) : NULL;}/* * We get this callback if the slot is already logged-in. * Need to check client-supplied password against the password stored in * tokenList. */PRBool SSM_VerifyPasswdCallback(PK11SlotInfo * slot, void * arg){ char * passwd = NULL; PRInt32 tokenKey; SSM_TokenInfo * info = NULL; SSM_TokenInfo * tokenInfo = NULL; SSMStatus rv; PRBool result = PR_FALSE; SSMResource * res = (SSMResource*)arg; SSMConnection * conn = &(res->m_connection->super); PRInt32 doTry = 0; void * tmp = NULL; if (!slot || !arg) goto loser; tokenKey = PK11_GetSlotID(slot) ^ PK11_GetModuleID(slot); info = (SSM_TokenInfo *) PORT_ZAlloc(sizeof(SSM_TokenInfo)); if (!info) { SSM_DEBUG("Could not allocate memory in VerifyPasswdCallback.\n"); goto loser; } /* Get the password for this token. * We might have to find it in the local encrypted password table or * to request it from the client. */ rv = SSM_HashFind(SSM_PARENT_CONN(conn)->m_encrPasswdTable, tokenKey, (void **)&info); if (rv != PR_SUCCESS || info == (void *)SSM_NO_PASSWORD) { askpassword: /* ask user for a password and store it in local passwd table */ rv = SSM_AskUserPassword(res, slot, doTry?PR_TRUE:PR_FALSE, PR_FALSE); if (rv != PR_SUCCESS) goto loser; doTry++; rv = SSMControlConnection_WaitPassword(conn, tokenKey, &passwd); if (rv != PR_SUCCESS || !passwd) goto loser; rv = SSM_EncryptPasswd(slot, passwd, &info); if (rv != SSM_SUCCESS) goto loser; } /* end of no password, ask user */ /* Now get the stored password for this token */ if (!tokenInfo) { PR_EnterMonitor(tokenLock); rv = SSM_HashFind(tokenList, tokenKey, (void **)&tokenInfo); PR_ExitMonitor(tokenLock); if (rv != PR_SUCCESS || !tokenInfo) { SSM_DEBUG("Can't find token info in VerifyPasswd.\n"); goto loser; } } /* Check password against tokenList entry */ if (memcmp(tokenInfo->encrypted, info->encrypted, tokenInfo->encryptedLen) != 0 || tokenInfo->encryptedLen != info->encryptedLen) { /* Failed compare, bad password */ /* first clean up */ if (info) PR_Free(info); info = NULL; /* If not retry, ask client for password. */ if (doTry < 2 ) { /* ask user again */ PR_Free(passwd); passwd = NULL; goto askpassword; } else goto loser; } /* end of password not verified */ SSM_DEBUG("Password verified OK.\n"); /* store password for local use */ PR_EnterMonitor(SSM_PARENT_CONN(conn)->m_encrPasswdLock); SSM_HashRemove(SSM_PARENT_CONN(conn)->m_encrPasswdTable, tokenKey, (void **)&tmp); if (tmp && tmp != (char *)SSM_NO_PASSWORD ) {/* free stale data */ PR_Free(tmp); tmp = NULL; } rv = SSM_HashInsert(SSM_PARENT_CONN(conn)->m_encrPasswdTable, tokenKey, info); PR_ExitMonitor(SSM_PARENT_CONN(conn)->m_encrPasswdLock); if (rv != PR_SUCCESS) { SSM_DEBUG("%ld: cannot insert token %d entry in encrPasswdTable\n", conn, tokenKey); goto loser; } result = PR_TRUE; goto done; loser: SSM_DEBUG("Password not verified. \n"); /* log out this slot?? */ if (info) { if (info->encrypted) PR_Free(info->encrypted); PR_Free(info); } result = PR_FALSE; done: if (passwd) PR_Free(passwd); return result;}/* Encrypt password for storage */#define SSM_PAD_BLOCK_SIZE(x, y) ((((x) + ((y)-1))/(y))*(y)) SSMStatus SSM_EncryptPasswd(PK11SlotInfo * slot, char * passwd, SSM_TokenInfo ** tokenInfo){ int resultLen; char *hashResult = NULL; SSMStatus rv = SSM_SUCCESS; SECStatus srv; SSM_TokenInfo * info; /* Hash the password. */ resultLen = HASH_ResultLen(HASH_AlgSHA1); hashResult = (char *) PORT_ZAlloc(resultLen); /* because the original PORT_ZAlloc'd */ if (!hashResult) goto loser; srv = HASH_HashBuf(HASH_AlgSHA1, (unsigned char *) hashResult, (unsigned char *) passwd, strlen(passwd)); if (srv != SECSuccess) goto loser; /* fill in the tokenInfo structure */ info = (SSM_TokenInfo *) PORT_ZAlloc(sizeof(SSM_TokenInfo)); if (!info) { SSM_DEBUG("EncryptPwd: could not allocate memory to token list entry.\n"); PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); goto loser; } info->encrypted = hashResult; info->encryptedLen = resultLen; info->slot = slot; info->tokenID = SSM_GetTokenKey(slot); *tokenInfo = info; goto done; loser: if (rv == SSM_SUCCESS) rv = SSM_FAILURE; PR_FREEIF(hashResult); done: return rv;}SSMStatus SSM_NotEncryptPasswd(PK11SlotInfo * slot, char * passwd, SSM_TokenInfo * info){ CK_MECHANISM_TYPE mechanism; /* CK_SESSION_HANDLE session = CK_INVALID_SESSION; */ PRInt32 keyLength, blockSize, outlen; PRUint32 encryptedLength; PK11SymKey * symKey; SECStatus rv; char * encrypted = NULL; PK11Context * context=NULL; SECItem *params; if (!slot || !passwd || !info) { PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); goto loser; } mechanism = CRMF_GetBestWrapPadMechanism(slot); keyLength = PK11_GetBestKeyLength(slot, mechanism); /* session = PK11_GetRWSession(slot); if (session == CK_INVALID_SESSION) goto loser;*/ blockSize = PK11_GetBlockSize(mechanism, NULL); /* * A password is encrypted when we first authenticate to token. * In this case, generate a symmetric Key on the slot. * If the key is already present, it means that the password for this * slot has already been encrypted and stored, need to encrypt * new password with the same key to compare against the stored * password. */ /* If no symKey found, generate one */ if (!info->symKey) { symKey = PK11_KeyGen(slot, mechanism, NULL, keyLength, NULL); if (!symKey) { SSM_DEBUG("Failed to generate symKey to encrypt passwd.\n"); goto loser; } } else symKey = info->symKey; encryptedLength = SSM_PAD_BLOCK_SIZE(strlen(passwd)+1, blockSize); encrypted = (char *) PORT_ZAlloc(encryptedLength); if (!encrypted) { SSM_DEBUG("Could not allocate space for encrypted password. \n"); goto loser; } params = CRMF_GetIVFromMechanism(mechanism); context=PK11_CreateContextBySymKey(mechanism, CKA_ENCRYPT, symKey, params); if (params != NULL) { SECITEM_FreeItem(params, PR_TRUE); } if (!context) { SSM_DEBUG("Can't create context to encrypt password: %d.\n", PR_GetError()); goto loser; } rv = PK11_CipherOp(context, (unsigned char *) encrypted, &outlen, (int) encryptedLength, (unsigned char *) passwd, strlen(passwd)); if (rv != PR_SUCCESS) { SSM_DEBUG("Error encrypting password: %d\n", PR_GetError()); goto loser; } rv = PK11_DigestFinal(context, (unsigned char *) &encrypted[outlen], (unsigned int *) &outlen, (unsigned int) blockSize); if (rv != PR_SUCCESS) { SSM_DEBUG("Error encrypting password: %d\n", PR_GetError()); goto loser; } PK11_DestroyContext(context, PR_TRUE); /*if (session != CK_INVALID_SESSION)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -