pk11cert.c

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

C
2,345
字号
/* * 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. *//* * This file implements the Symkey wrapper and the PKCS context * Interfaces. */#include "seccomon.h"#include "secmod.h"#include "prlock.h"#include "secmodi.h"#include "pkcs11.h"#include "pk11func.h"#include "cert.h"#include "secitem.h"#include "key.h"#include "hasht.h"#include "secoid.h"#include "pkcs7t.h"#include "cmsreclist.h"#include "certdb.h"#include "secerr.h"#include "sslerr.h"#define NSSCKT_H /* we included pkcs11t.h, so block ckt.h from including nssckt.h */#include "ckt.h"#define PK11_SEARCH_CHUNKSIZE 10CK_OBJECT_HANDLEpk11_FindPubKeyByAnyCert(CERTCertificate *cert, PK11SlotInfo **slot, void *wincx);/* * build a cert nickname based on the token name and the label of the  * certificate If the label in NULL, build a label based on the ID. */static int toHex(int x) { return (x < 10) ? (x+'0') : (x+'a'-10); }#define MAX_CERT_ID 4#define DEFAULT_STRING "Cert ID "static char *pk11_buildNickname(PK11SlotInfo *slot,CK_ATTRIBUTE *cert_label,			CK_ATTRIBUTE *key_label, CK_ATTRIBUTE *cert_id){    int prefixLen = PORT_Strlen(slot->token_name);    int suffixLen = 0;    char *suffix = NULL;    char buildNew[sizeof(DEFAULT_STRING)+MAX_CERT_ID*2];    char *next,*nickname;    if (slot->isInternal) {	return NULL;    }    if ((cert_label) && (cert_label->pValue)) {	suffixLen = cert_label->ulValueLen;	suffix = (char*)cert_label->pValue;    } else if (key_label && (key_label->pValue)) {	suffixLen = key_label->ulValueLen;	suffix = (char*)key_label->pValue;    } else if ((cert_id) && cert_id->pValue) {	int i,first = cert_id->ulValueLen - MAX_CERT_ID;	int offset = sizeof(DEFAULT_STRING);	char *idValue = (char *)cert_id->pValue;	PORT_Memcpy(buildNew,DEFAULT_STRING,sizeof(DEFAULT_STRING)-1);	next = buildNew + offset;	if (first < 0) first = 0;	for (i=first; i < (int) cert_id->ulValueLen; i++) {		*next++ = toHex((idValue[i] >> 4) & 0xf);		*next++ = toHex(idValue[i] & 0xf);	}	*next++ = 0;	suffix = buildNew;	suffixLen = PORT_Strlen(buildNew);    } else {	PORT_SetError( SEC_ERROR_LIBRARY_FAILURE );	return NULL;    }    next = nickname = (char *)PORT_Alloc(prefixLen+1+suffixLen+1);    if (nickname == NULL) return NULL;    PORT_Memcpy(next,slot->token_name,prefixLen);    next += prefixLen;    *next++ = ':';    PORT_Memcpy(next,suffix,suffixLen);    next += suffixLen;    *next++ = 0;    return nickname;}/* * return the object handle that matches the template */CK_OBJECT_HANDLEpk11_FindObjectByTemplate(PK11SlotInfo *slot,CK_ATTRIBUTE *theTemplate,int tsize){    CK_OBJECT_HANDLE object;    CK_RV crv;    CK_ULONG objectCount;    /*     * issue the find     */    PK11_EnterSlotMonitor(slot);    crv=PK11_GETTAB(slot)->C_FindObjectsInit(slot->session, theTemplate, tsize);    if (crv != CKR_OK) {        PK11_ExitSlotMonitor(slot);	PORT_SetError( PK11_MapError(crv) );	return CK_INVALID_KEY;    }    crv=PK11_GETTAB(slot)->C_FindObjects(slot->session,&object,1,&objectCount);    PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session);    PK11_ExitSlotMonitor(slot);    if ((crv != CKR_OK) || (objectCount < 1)) {	/* shouldn't use SSL_ERROR... here */	PORT_SetError( crv != CKR_OK ? PK11_MapError(crv) :						  SSL_ERROR_NO_CERTIFICATE);	return CK_INVALID_KEY;    }    /* blow up if the PKCS #11 module returns us and invalid object handle */    PORT_Assert(object != CK_INVALID_KEY);    return object;} /* * return all the object handles that matches the template */CK_OBJECT_HANDLE *pk11_FindObjectsByTemplate(PK11SlotInfo *slot,		CK_ATTRIBUTE *findTemplate,int findCount,int *object_count) {    CK_OBJECT_HANDLE *objID = NULL;    CK_ULONG returned_count = 0;    CK_RV crv;    PK11_EnterSlotMonitor(slot);    crv = PK11_GETTAB(slot)->C_FindObjectsInit(slot->session, findTemplate, 								findCount);    if (crv != CKR_OK) {	PK11_ExitSlotMonitor(slot);	PORT_SetError( PK11_MapError(crv) );	*object_count = -1;	return NULL;    }    /*     * collect all the Matching Objects     */    do {	CK_OBJECT_HANDLE *oldObjID = objID;	if (objID == NULL) {    	    objID = (CK_OBJECT_HANDLE *) PORT_Alloc(sizeof(CK_OBJECT_HANDLE)*				(*object_count+ PK11_SEARCH_CHUNKSIZE));	} else {    	    objID = (CK_OBJECT_HANDLE *) PORT_Realloc(objID,		sizeof(CK_OBJECT_HANDLE)*(*object_count+PK11_SEARCH_CHUNKSIZE));	}	if (objID == NULL) {	    if (oldObjID) PORT_Free(oldObjID);	    break;	}    	crv = PK11_GETTAB(slot)->C_FindObjects(slot->session,		&objID[*object_count],PK11_SEARCH_CHUNKSIZE,&returned_count);	if (crv != CKR_OK) {	    PORT_SetError( PK11_MapError(crv) );	    PORT_Free(objID);	    objID = NULL;	    break;    	}	*object_count += returned_count;    } while (returned_count == PK11_SEARCH_CHUNKSIZE);    PK11_GETTAB(slot)->C_FindObjectsFinal(slot->session);    PK11_ExitSlotMonitor(slot);    if (objID && (*object_count == 0)) {	PORT_Free(objID);	return NULL;    }    if (objID == NULL) *object_count = -1;    return objID;}/* * given a PKCS #11 object, match it's peer based on the KeyID. searchID * is typically a privateKey or a certificate while the peer is the opposite */CK_OBJECT_HANDLEPK11_MatchItem(PK11SlotInfo *slot, CK_OBJECT_HANDLE searchID,				 		CK_OBJECT_CLASS matchclass){    CK_ATTRIBUTE theTemplate[] = {	{ CKA_ID, NULL, 0 },	{ CKA_CLASS, NULL, 0 }    };    /* if you change the array, change the variable below as well */    CK_ATTRIBUTE *keyclass = &theTemplate[1];    int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);    /* if you change the array, change the variable below as well */    CK_OBJECT_HANDLE peerID;    CK_OBJECT_HANDLE parent;    PRArenaPool *arena;    CK_RV crv;    /* now we need to create space for the public key */    arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);    if (arena == NULL) return CK_INVALID_KEY;    crv = PK11_GetAttributes(arena,slot,searchID,theTemplate,tsize);    if (crv != CKR_OK) {	PORT_FreeArena(arena,PR_FALSE);	PORT_SetError( PK11_MapError(crv) );	return CK_INVALID_KEY;    }    /*     * issue the find     */    parent = *(CK_OBJECT_CLASS *)(keyclass->pValue);    *(CK_OBJECT_CLASS *)(keyclass->pValue) = matchclass;    peerID = pk11_FindObjectByTemplate(slot,theTemplate,tsize);    PORT_FreeArena(arena,PR_FALSE);    return peerID;}PRBoolPK11_IsUserCert(PK11SlotInfo *slot, CERTCertificate *cert,						CK_OBJECT_HANDLE certID){    CK_OBJECT_CLASS theClass;    if (slot == NULL) return PR_FALSE;    if (cert == NULL) return PR_FALSE;    theClass = CKO_PRIVATE_KEY;    if (!PK11_IsLoggedIn(slot,NULL) && PK11_NeedLogin(slot)) {	theClass = CKO_PUBLIC_KEY;    }    if (PK11_MatchItem(slot, certID , theClass) != CK_INVALID_KEY) {	return PR_TRUE;    }   if (theClass == CKO_PUBLIC_KEY) {	SECKEYPublicKey *pubKey= CERT_ExtractPublicKey(cert);	CK_ATTRIBUTE theTemplate;	if (pubKey == NULL) {	   return PR_FALSE;	}	PK11_SETATTRS(&theTemplate,0,NULL,0);	switch (pubKey->keyType) {	case rsaKey:	    PK11_SETATTRS(&theTemplate,CKA_MODULUS, pubKey->u.rsa.modulus.data,						pubKey->u.rsa.modulus.len);	    break;	case dsaKey:	    PK11_SETATTRS(&theTemplate,CKA_VALUE, pubKey->u.dsa.publicValue.data,						pubKey->u.dsa.publicValue.len);	case dhKey:	    PK11_SETATTRS(&theTemplate,CKA_VALUE, pubKey->u.dh.publicValue.data,						pubKey->u.dh.publicValue.len);	    break;	}	if (theTemplate.ulValueLen == 0) {	    SECKEY_DestroyPublicKey(pubKey);	    return PR_FALSE;	}	pk11_SignedToUnsigned(&theTemplate);	if (pk11_FindObjectByTemplate(slot,&theTemplate,1) != CK_INVALID_KEY) {	    SECKEY_DestroyPublicKey(pubKey);	    return PR_TRUE;	}	SECKEY_DestroyPublicKey(pubKey);    }    return PR_FALSE;}/* * Check out if a cert has ID of zero. This is a magic ID that tells * NSS that this cert may be an automagically trusted cert. * The Cert has to be self signed as well. That check is done elsewhere. *   */PRBoolpk11_isID0(PK11SlotInfo *slot, CK_OBJECT_HANDLE certID){    CK_ATTRIBUTE keyID = {CKA_ID, NULL, 0};    PRBool isZero = PR_FALSE;    int i;    CK_RV crv;    crv = PK11_GetAttributes(NULL,slot,certID,&keyID,1);    if (crv != CKR_OK) {	return isZero;    }    if (keyID.ulValueLen != 0) {	char *value = (char *)keyID.pValue;	isZero = PR_TRUE; /* ID exists, may be zero */	for (i=0; i < (int) keyID.ulValueLen; i++) {	    if (value[i] != 0) {		isZero = PR_FALSE; /* nope */		break;	    }	}    }    PORT_Free(keyID.pValue);    return isZero;}     CERTCertificate*pk11_fastCert(PK11SlotInfo *slot, CK_OBJECT_HANDLE certID, 			CK_ATTRIBUTE *privateLabel, char **nickptr){    CK_ATTRIBUTE certTemp[] = {	{ CKA_ID, NULL, 0 },	{ CKA_VALUE, NULL, 0 },	{ CKA_LABEL, NULL, 0 }    };    CK_ATTRIBUTE *id = &certTemp[0];    CK_ATTRIBUTE *certDER = &certTemp[1];    CK_ATTRIBUTE *label = &certTemp[2];    SECItem derCert;    int csize = sizeof(certTemp)/sizeof(certTemp[0]);    PRArenaPool *arena;    char *nickname;    CERTCertificate *cert;    CK_RV crv;    arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE);    if (arena == NULL) return NULL;    /*     * grab the der encoding     */    crv = PK11_GetAttributes(arena,slot,certID,certTemp,csize);    if (crv != CKR_OK) {	PORT_FreeArena(arena,PR_FALSE);	PORT_SetError( PK11_MapError(crv) );	return NULL;    }    /*     * build a certificate out of it     */    derCert.data = (unsigned char*)certDER->pValue;    derCert.len = certDER->ulValueLen;    /* figure out the nickname.... */    nickname = pk11_buildNickname(slot,label,privateLabel,id);    cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &derCert, nickname,							PR_FALSE, PR_TRUE);    if (nickptr) {	*nickptr = nickname;    } else {	if (nickname) PORT_Free(nickname);    }    PORT_FreeArena(arena,PR_FALSE);    return cert;}CK_TRUSTpk11_GetTrustField(PK11SlotInfo *slot, PRArenaPool *arena,                    CK_OBJECT_HANDLE id, CK_ATTRIBUTE_TYPE type){  CK_TRUST rv = 0;  SECItem item;  item.data = NULL;  item.len = 0;  if( SECSuccess == PK11_ReadAttribute(slot, id, type, arena, &item) ) {    PORT_Assert(item.len == sizeof(CK_TRUST));    PORT_Memcpy(&rv, item.data, sizeof(CK_TRUST));    /* Damn, is there an endian problem here? */    return rv;  }  return 0;}PRBoolpk11_HandleTrustObject(PK11SlotInfo *slot, CERTCertificate *cert, CERTCertTrust *trust){  PRArenaPool *arena;  CK_ATTRIBUTE tobjTemplate[] = {    { CKA_CLASS, NULL, 0 },    { CKA_CERT_SHA1_HASH, NULL, 0 },  };  CK_OBJECT_CLASS tobjc = CKO_NETSCAPE_TRUST;  CK_OBJECT_HANDLE tobjID;  unsigned char sha1_hash[SHA1_LENGTH];  CK_TRUST digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment,    keyAgreement, keyCertSign, crlSign, serverAuth, clientAuth, codeSigning,    emailProtection, ipsecEndSystem, ipsecTunnel, ipsecUser, timeStamping;  SECItem item;  PK11_HashBuf(SEC_OID_SHA1, sha1_hash, cert->derCert.data, cert->derCert.len);  PK11_SETATTRS(&tobjTemplate[0], CKA_CLASS, &tobjc, sizeof(tobjc));  PK11_SETATTRS(&tobjTemplate[1], CKA_CERT_SHA1_HASH, sha1_hash,                 SHA1_LENGTH);  tobjID = pk11_FindObjectByTemplate(slot, tobjTemplate,                                      sizeof(tobjTemplate)/sizeof(tobjTemplate[0]));  if( CK_INVALID_KEY == tobjID ) {    return PR_FALSE;  }  arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);  if( NULL == arena ) return PR_FALSE;  /* Unfortunately, it seems that PK11_GetAttributes doesn't deal   * well with nonexistant attributes.  I guess we have to check    * the trust info fields one at a time.   */  /* We could verify CKA_CERT_HASH here */  /* We could verify CKA_EXPIRES here */  /* "Usage" trust information */  /* digitalSignature = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_DIGITAL_SIGNATURE); */  /* nonRepudiation   = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_NON_REPUDIATION); */  /* keyEncipherment  = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_KEY_ENCIPHERMENT); */

⌨️ 快捷键说明

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