p12d.c

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

C
2,435
字号
    }    PK11_TraverseCertsForNicknameInSlot(nickname, slot, countCertificate, 					(void *)&nCerts);    if(nCerts) return PR_TRUE;    return PR_FALSE;}/* validate cert nickname such that there is a one-to-one relation * between nicknames and dn's.  we want to enforce the case that the * nickname is non-NULL and that there is only one nickname per DN. *  * if there is a problem with a nickname or the nickname is not present,  * the user will be prompted for it. */static voidsec_pkcs12_validate_cert_nickname(sec_PKCS12SafeBag *cert,				sec_PKCS12SafeBag *key,				SEC_PKCS12NicknameCollisionCallback nicknameCb,				void *wincx){    SECItem *certNickname, *existingDNNick;    PRBool setNickname = PR_FALSE, cancel = PR_FALSE;    SECItem *newNickname = NULL;    if(!cert || !cert->hasKey) {	return;    }    if(!nicknameCb) {	cert->problem = PR_TRUE;	cert->error = SEC_ERROR_NO_MEMORY;	return;    }    if(cert->hasKey && !key) {	cert->problem = PR_TRUE;	cert->error = SEC_ERROR_NO_MEMORY;	return;    }    certNickname = sec_pkcs12_get_nickname_for_cert(cert, key, wincx);    existingDNNick = sec_pkcs12_get_existing_nick_for_dn(cert, wincx);    /* nickname is already used w/ this dn, so it is safe to return */    if(certNickname && existingDNNick &&		SECITEM_CompareItem(certNickname, existingDNNick) == SECEqual) {	goto loser;    }    /* nickname not set in pkcs 12 bags, but a nick is already used for     * this dn.  set the nicks in the p12 bags and finish.     */    if(existingDNNick) {	if(sec_pkcs12_set_nickname_for_cert(cert, key, existingDNNick, wincx)			!= SECSuccess) {	    cert->problem = PR_TRUE;	    cert->error = SEC_ERROR_NO_MEMORY;	}	goto loser;    }    /* at this point, we have a certificate for which the DN is not located     * on the token.  the nickname specified may or may not be NULL.  if it     * is not null, we need to make sure that there are no other certificates     * with this nickname in the token for it to be valid.  this imposes a      * one to one relationship between DN and nickname.       *     * if the nickname is null, we need the user to enter a nickname for     * the certificate.     *     * once we have a nickname, we make sure that the nickname is unique     * for the DN.  if it is not, the user is reprompted to enter a new      * nickname.       *     * in order to exit this loop, the nickname entered is either unique     * or the user hits cancel and the certificate is not imported.     */    setNickname = PR_FALSE;    while(1) {	if(certNickname && certNickname->data) {	    /* we will use the nickname so long as no other certs have the	     * same nickname.  and the nickname is not NULL.	     */			    if(!sec_pkcs12_certs_for_nickname_exist(certNickname, cert->slot)) {		if(setNickname) {		    if(sec_pkcs12_set_nickname_for_cert(cert, key, certNickname,					wincx) != SECSuccess) {			cert->problem = PR_TRUE;			cert->error = SEC_ERROR_NO_MEMORY;		    }		}		goto loser;	    }	}	setNickname = PR_FALSE;	newNickname = (*nicknameCb)(certNickname, &cancel, wincx);	if(cancel) {	    cert->problem = PR_TRUE;	    cert->error = SEC_ERROR_USER_CANCELLED;	    goto loser;	}	if(!newNickname) {	    cert->problem = PR_TRUE;	    cert->error = SEC_ERROR_NO_MEMORY;	    goto loser;	}	/* at this point we have a new nickname, if we have an existing	 * certNickname, we need to free it and assign the new nickname	 * to it to avoid a memory leak.  happy?	 */	if(certNickname) {	    SECITEM_ZfreeItem(certNickname, PR_TRUE);	    certNickname = NULL;	}	certNickname = newNickname;	setNickname = PR_TRUE;	/* go back and recheck the new nickname */    }loser:    if(certNickname) {	SECITEM_ZfreeItem(certNickname, PR_TRUE);    }    if(existingDNNick) {	SECITEM_ZfreeItem(existingDNNick, PR_TRUE);    }}static void sec_pkcs12_validate_cert(sec_PKCS12SafeBag *cert,			 sec_PKCS12SafeBag *key,			 SEC_PKCS12NicknameCollisionCallback nicknameCb,			 void *wincx){    CERTCertificate *leafCert, *testCert;    if(!cert) {	return;    }        cert->validated = PR_TRUE;    if(!nicknameCb) {	cert->problem = PR_TRUE;	cert->error = SEC_ERROR_NO_MEMORY;	cert->noInstall = PR_TRUE;	return;    }    if(!cert->safeBagContent.certBag) {	cert->noInstall = PR_TRUE;	cert->problem = PR_TRUE;	cert->error = SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE;	return;    }    cert->noInstall = PR_FALSE;    cert->removeExisting = PR_FALSE;    cert->problem = PR_FALSE;    cert->error = 0;    leafCert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),				&cert->safeBagContent.certBag->value.x509Cert,				NULL, PR_FALSE, PR_TRUE);    if(!leafCert) {	cert->noInstall = PR_TRUE;	cert->problem = PR_TRUE;	cert->error = SEC_ERROR_NO_MEMORY;	return;    }    testCert = PK11_FindCertFromDERCert(cert->slot, leafCert, wincx);    CERT_DestroyCertificate(leafCert);    /* if we can't find the certificate through the PKCS11 interface,     * we should check the cert database directly, if we are     * importing to an internal slot.     */    if(!testCert && PK11_IsInternal(cert->slot)) {	testCert = CERT_FindCertByDERCert(CERT_GetDefaultCertDB(),				 &cert->safeBagContent.certBag->value.x509Cert);    }    if(testCert) {	if(!testCert->nickname) {	    cert->removeExisting = PR_TRUE;	} else {	    cert->noInstall = PR_TRUE;	}	CERT_DestroyCertificate(testCert);	if(cert->noInstall && !cert->removeExisting) {	    return;	}    }    sec_pkcs12_validate_cert_nickname(cert, key, nicknameCb, wincx);}static voidsec_pkcs12_validate_key_by_cert(sec_PKCS12SafeBag *cert, sec_PKCS12SafeBag *key,				void *wincx){    CERTCertificate *leafCert;    SECKEYPrivateKey *privk;    if(!key) {	return;    }    key->validated = PR_TRUE;    if(!cert) {	key->problem = PR_TRUE;	key->noInstall = PR_TRUE;	key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;	return;    }    leafCert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),				&(cert->safeBagContent.certBag->value.x509Cert),				NULL, PR_FALSE, PR_TRUE);    if(!leafCert) {	key->problem = PR_TRUE;	key->noInstall = PR_TRUE;	key->error = SEC_ERROR_NO_MEMORY;	return;    }    privk = PK11_FindPrivateKeyFromCert(key->slot, leafCert, wincx);    if(!privk) {	privk = PK11_FindKeyByDERCert(key->slot, leafCert, wincx);    }     if(privk) {	SECKEY_DestroyPrivateKey(privk);	key->noInstall = PR_TRUE;    }     CERT_DestroyCertificate(leafCert);}static SECStatussec_pkcs12_remove_existing_cert(sec_PKCS12SafeBag *cert, 				void *wincx){    SECItem *derCert = NULL;    CERTCertificate *tempCert = NULL;    CK_OBJECT_HANDLE certObj;    PK11SlotInfo *slot = NULL;    PRBool removed = PR_FALSE;    if(!cert) {	return SECFailure;    }    PORT_Assert(cert->removeExisting);    cert->removeExisting = PR_FALSE;    derCert = &cert->safeBagContent.certBag->value.x509Cert;    tempCert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), derCert,				       NULL, PR_FALSE, PR_TRUE);    if(!tempCert) {	return SECFailure;    }    certObj = PK11_FindCertInSlot(cert->slot, tempCert, wincx);    CERT_DestroyCertificate(tempCert);    tempCert = NULL;    if(certObj != CK_INVALID_KEY) {	PK11_DestroyObject(cert->slot, certObj);	removed = PR_TRUE;    } else if(PK11_IsInternal(cert->slot)) {	tempCert = CERT_FindCertByDERCert(CERT_GetDefaultCertDB(), derCert);	if(tempCert) {	    if(SEC_DeletePermCertificate(tempCert) == SECSuccess) {		removed = PR_TRUE;	    } 	    CERT_DestroyCertificate(tempCert);	    tempCert = NULL;	}    }    if(!removed) {	cert->problem = PR_TRUE;	cert->error = SEC_ERROR_NO_MEMORY;	cert->noInstall = PR_TRUE;    }	    if(tempCert) {	CERT_DestroyCertificate(tempCert);    }    return ((removed) ? SECSuccess : SECFailure);}static SECStatussec_pkcs12_add_cert(sec_PKCS12SafeBag *cert, PRBool keyExists, void *wincx){    SECItem *derCert, *nickName;    char *nickData = NULL;    SECStatus rv;    if(!cert) {	return SECFailure;    }    if(cert->problem || cert->noInstall || cert->installed) {	return SECSuccess;    }    derCert = &cert->safeBagContent.certBag->value.x509Cert;    if(cert->removeExisting) {	if(sec_pkcs12_remove_existing_cert(cert, wincx) 			!= SECSuccess) {	    return SECFailure;	}	cert->removeExisting = PR_FALSE;    }    PORT_Assert(!cert->problem && !cert->removeExisting && !cert->noInstall);    nickName = sec_pkcs12_get_nickname(cert);    if(nickName) {	nickData = (char *)nickName->data;    }    if(keyExists) {	CERTCertificate *newCert;	newCert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),					  derCert, NULL, PR_FALSE, PR_TRUE);	if(!newCert) {	     if(nickName) SECITEM_ZfreeItem(nickName, PR_TRUE);	     cert->error = SEC_ERROR_NO_MEMORY;	     cert->problem = PR_TRUE;	     return SECFailure;	}	rv = PK11_ImportCertForKeyToSlot(cert->slot, newCert, nickData, 					 PR_TRUE, wincx);	CERT_DestroyCertificate(newCert);    } else {	SECItem *certList[2];	certList[0] = derCert;	certList[1] = NULL;	rv = CERT_ImportCerts(CERT_GetDefaultCertDB(), certUsageUserCertImport,			      1, certList, NULL, PR_TRUE, PR_FALSE, nickData);    }    cert->installed = PR_TRUE;    if(nickName) SECITEM_ZfreeItem(nickName, PR_TRUE);    return rv;}static SECStatussec_pkcs12_add_key(sec_PKCS12SafeBag *key, SECItem *publicValue, 			KeyType keyType, unsigned int keyUsage, void *wincx){    SECStatus rv;    SECItem *nickName;    if(!key) {	return SECFailure;    }    if(key->removeExisting) {	key->problem = PR_TRUE;	key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;	return SECFailure;    }    if(key->problem || key->noInstall) {	return SECSuccess;    }    nickName = sec_pkcs12_get_nickname(key);    switch(SECOID_FindOIDTag(&key->safeBagType))    {	case SEC_OID_PKCS12_V1_KEY_BAG_ID:	    rv = PK11_ImportPrivateKeyInfo(key->slot, 			  key->safeBagContent.pkcs8KeyBag, 			  nickName, publicValue, PR_TRUE, PR_TRUE,			  keyUsage,  wincx);	    break;	case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:	    rv = PK11_ImportEncryptedPrivateKeyInfo(key->slot,					key->safeBagContent.pkcs8ShroudedKeyBag,					key->pwitem, nickName, publicValue, 					PR_TRUE, PR_TRUE, keyType, keyUsage,					wincx);	    break;	default:	    key->error = SEC_ERROR_PKCS12_UNSUPPORTED_VERSION;	    key->problem = PR_TRUE;	    if(nickName) {		SECITEM_ZfreeItem(nickName, PR_TRUE);	    }	    return SECFailure;    }    key->installed = PR_TRUE;    if(nickName) {	SECITEM_ZfreeItem(nickName, PR_TRUE);    }					    if(rv != SECSuccess) {	key->error = SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY;	key->problem = PR_TRUE;    } else {	key->installed = PR_TRUE;    }    return rv;}static SECStatussec_pkcs12_add_item_to_bag_list(sec_PKCS12SafeBag ***bagList, 				sec_PKCS12SafeBag *bag){    int i = 0;    if(!bagList || !bag) {	return SECFailure;    }    if(!(*bagList)) {	(*bagList) = (sec_PKCS12SafeBag **)PORT_ArenaZAlloc(bag->arena, 				      sizeof(sec_PKCS12SafeBag *) * 2);    } else {	while((*bagList)[i]) i++;	(*bagList) = (sec_PKCS12SafeBag **)PORT_ArenaGrow(bag->arena, *bagList,				sizeof(sec_PKCS12SafeBag *) * (i + 1),				sizeof(sec_PKCS12SafeBag *) * (i + 2));    }    if(!(*bagList)) {	PORT_SetError(SEC_ERROR_NO_MEMORY);	return SECFailure;    }    (*bagList)[i] = bag;    (*bagList)[i+1] = NULL;    return SECSuccess;}static sec_PKCS12SafeBag **sec_pkcs12_find_certs_for_key(sec_PKCS12SafeBag **safeBags, sec_PKCS12SafeBag *key ) {    sec_PKCS12SafeBag **certList = NULL;    SECItem *keyId;    int i;    if(!safeBags || !safeBags[0]) {	return NULL;    }    keyId = sec_pkcs12_get_attribute_value(key, SEC_OID_PKCS9_LOCAL_KEY_ID);    if(!keyId) {	return NULL;    }    i = 0;    certList = NULL;    while(safeBags[i]) {	if(SECOID_FindOIDTag(&(safeBags[i]->safeBagType)) 				== SEC_OID_PKCS12_V1_CERT_BAG_ID) {	    SECItem *certKeyId = sec_pkcs12_get_attribute_value(safeBags[i],						SEC_OID_PKCS9_LOCAL_KEY_ID);	    if(certKeyId && (SECITEM_CompareItem(certKeyId, keyId) 				== SECEqual)) {		if(sec_pkcs12_add_item_to_bag_list(&certList, safeBags[i])				!= SECSuccess) {		    return NULL;		}	    }

⌨️ 快捷键说明

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