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