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