| /* This Source Code Form is subject to the terms of the Mozilla Public |
| * License, v. 2.0. If a copy of the MPL was not distributed with this |
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| |
| #include "nssrenam.h" |
| #include "pkcs12.h" |
| #include "secpkcs7.h" |
| #include "secasn1.h" |
| #include "seccomon.h" |
| #include "secoid.h" |
| #include "sechash.h" |
| #include "secitem.h" |
| #include "secerr.h" |
| #include "pk11func.h" |
| #include "p12local.h" |
| #include "p12.h" |
| |
| #define SALT_LENGTH 16 |
| |
| SEC_ASN1_MKSUB(SECKEY_PrivateKeyInfoTemplate) |
| SEC_ASN1_MKSUB(sgn_DigestInfoTemplate) |
| |
| CK_MECHANISM_TYPE |
| sec_pkcs12_algtag_to_mech(SECOidTag algtag) |
| { |
| switch (algtag) { |
| case SEC_OID_MD2: |
| return CKM_MD2_HMAC; |
| case SEC_OID_MD5: |
| return CKM_MD5_HMAC; |
| case SEC_OID_SHA1: |
| return CKM_SHA_1_HMAC; |
| case SEC_OID_SHA224: |
| return CKM_SHA224_HMAC; |
| case SEC_OID_SHA256: |
| return CKM_SHA256_HMAC; |
| case SEC_OID_SHA384: |
| return CKM_SHA384_HMAC; |
| case SEC_OID_SHA512: |
| return CKM_SHA512_HMAC; |
| default: |
| break; |
| } |
| return CKM_INVALID_MECHANISM; |
| } |
| |
| /* helper functions */ |
| /* returns proper bag type template based upon object type tag */ |
| const SEC_ASN1Template * |
| sec_pkcs12_choose_bag_type_old(void *src_or_dest, PRBool encoding) |
| { |
| const SEC_ASN1Template *theTemplate; |
| SEC_PKCS12SafeBag *safebag; |
| SECOidData *oiddata; |
| |
| if (src_or_dest == NULL) { |
| return NULL; |
| } |
| |
| safebag = (SEC_PKCS12SafeBag *)src_or_dest; |
| |
| oiddata = safebag->safeBagTypeTag; |
| if (oiddata == NULL) { |
| oiddata = SECOID_FindOID(&safebag->safeBagType); |
| safebag->safeBagTypeTag = oiddata; |
| } |
| |
| switch (oiddata->offset) { |
| default: |
| theTemplate = SEC_ASN1_GET(SEC_PointerToAnyTemplate); |
| break; |
| case SEC_OID_PKCS12_KEY_BAG_ID: |
| theTemplate = SEC_PointerToPKCS12KeyBagTemplate; |
| break; |
| case SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID: |
| theTemplate = SEC_PointerToPKCS12CertAndCRLBagTemplate_OLD; |
| break; |
| case SEC_OID_PKCS12_SECRET_BAG_ID: |
| theTemplate = SEC_PointerToPKCS12SecretBagTemplate; |
| break; |
| } |
| return theTemplate; |
| } |
| |
| const SEC_ASN1Template * |
| sec_pkcs12_choose_bag_type(void *src_or_dest, PRBool encoding) |
| { |
| const SEC_ASN1Template *theTemplate; |
| SEC_PKCS12SafeBag *safebag; |
| SECOidData *oiddata; |
| |
| if (src_or_dest == NULL) { |
| return NULL; |
| } |
| |
| safebag = (SEC_PKCS12SafeBag *)src_or_dest; |
| |
| oiddata = safebag->safeBagTypeTag; |
| if (oiddata == NULL) { |
| oiddata = SECOID_FindOID(&safebag->safeBagType); |
| safebag->safeBagTypeTag = oiddata; |
| } |
| |
| switch (oiddata->offset) { |
| default: |
| theTemplate = SEC_ASN1_GET(SEC_AnyTemplate); |
| break; |
| case SEC_OID_PKCS12_KEY_BAG_ID: |
| theTemplate = SEC_PKCS12PrivateKeyBagTemplate; |
| break; |
| case SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID: |
| theTemplate = SEC_PKCS12CertAndCRLBagTemplate; |
| break; |
| case SEC_OID_PKCS12_SECRET_BAG_ID: |
| theTemplate = SEC_PKCS12SecretBagTemplate; |
| break; |
| } |
| return theTemplate; |
| } |
| |
| /* returns proper cert crl template based upon type tag */ |
| const SEC_ASN1Template * |
| sec_pkcs12_choose_cert_crl_type_old(void *src_or_dest, PRBool encoding) |
| { |
| const SEC_ASN1Template *theTemplate; |
| SEC_PKCS12CertAndCRL *certbag; |
| SECOidData *oiddata; |
| |
| if (src_or_dest == NULL) { |
| return NULL; |
| } |
| |
| certbag = (SEC_PKCS12CertAndCRL *)src_or_dest; |
| oiddata = certbag->BagTypeTag; |
| if (oiddata == NULL) { |
| oiddata = SECOID_FindOID(&certbag->BagID); |
| certbag->BagTypeTag = oiddata; |
| } |
| |
| switch (oiddata->offset) { |
| default: |
| theTemplate = SEC_ASN1_GET(SEC_PointerToAnyTemplate); |
| break; |
| case SEC_OID_PKCS12_X509_CERT_CRL_BAG: |
| theTemplate = SEC_PointerToPKCS12X509CertCRLTemplate_OLD; |
| break; |
| case SEC_OID_PKCS12_SDSI_CERT_BAG: |
| theTemplate = SEC_PointerToPKCS12SDSICertTemplate; |
| break; |
| } |
| return theTemplate; |
| } |
| |
| const SEC_ASN1Template * |
| sec_pkcs12_choose_cert_crl_type(void *src_or_dest, PRBool encoding) |
| { |
| const SEC_ASN1Template *theTemplate; |
| SEC_PKCS12CertAndCRL *certbag; |
| SECOidData *oiddata; |
| |
| if (src_or_dest == NULL) { |
| return NULL; |
| } |
| |
| certbag = (SEC_PKCS12CertAndCRL *)src_or_dest; |
| oiddata = certbag->BagTypeTag; |
| if (oiddata == NULL) { |
| oiddata = SECOID_FindOID(&certbag->BagID); |
| certbag->BagTypeTag = oiddata; |
| } |
| |
| switch (oiddata->offset) { |
| default: |
| theTemplate = SEC_ASN1_GET(SEC_PointerToAnyTemplate); |
| break; |
| case SEC_OID_PKCS12_X509_CERT_CRL_BAG: |
| theTemplate = SEC_PointerToPKCS12X509CertCRLTemplate; |
| break; |
| case SEC_OID_PKCS12_SDSI_CERT_BAG: |
| theTemplate = SEC_PointerToPKCS12SDSICertTemplate; |
| break; |
| } |
| return theTemplate; |
| } |
| |
| /* returns appropriate shroud template based on object type tag */ |
| const SEC_ASN1Template * |
| sec_pkcs12_choose_shroud_type(void *src_or_dest, PRBool encoding) |
| { |
| const SEC_ASN1Template *theTemplate; |
| SEC_PKCS12ESPVKItem *espvk; |
| SECOidData *oiddata; |
| |
| if (src_or_dest == NULL) { |
| return NULL; |
| } |
| |
| espvk = (SEC_PKCS12ESPVKItem *)src_or_dest; |
| oiddata = espvk->espvkTag; |
| if (oiddata == NULL) { |
| oiddata = SECOID_FindOID(&espvk->espvkOID); |
| espvk->espvkTag = oiddata; |
| } |
| |
| switch (oiddata->offset) { |
| default: |
| theTemplate = SEC_ASN1_GET(SEC_PointerToAnyTemplate); |
| break; |
| case SEC_OID_PKCS12_PKCS8_KEY_SHROUDING: |
| theTemplate = |
| SEC_ASN1_GET(SECKEY_PointerToEncryptedPrivateKeyInfoTemplate); |
| break; |
| } |
| return theTemplate; |
| } |
| |
| /* generate SALT placing it into the character array passed in. |
| * it is assumed that salt_dest is an array of appropriate size |
| * XXX We might want to generate our own random context |
| */ |
| SECItem * |
| sec_pkcs12_generate_salt(void) |
| { |
| SECItem *salt; |
| |
| salt = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); |
| if (salt == NULL) { |
| PORT_SetError(SEC_ERROR_NO_MEMORY); |
| return NULL; |
| } |
| salt->data = (unsigned char *)PORT_ZAlloc(sizeof(unsigned char) * |
| SALT_LENGTH); |
| salt->len = SALT_LENGTH; |
| if (salt->data == NULL) { |
| PORT_SetError(SEC_ERROR_NO_MEMORY); |
| SECITEM_ZfreeItem(salt, PR_TRUE); |
| return NULL; |
| } |
| |
| PK11_GenerateRandom(salt->data, salt->len); |
| |
| return salt; |
| } |
| |
| /* generate KEYS -- as per PKCS12 section 7. |
| * only used for MAC |
| */ |
| SECItem * |
| sec_pkcs12_generate_key_from_password(SECOidTag algorithm, |
| SECItem *salt, |
| SECItem *password) |
| { |
| unsigned char *pre_hash = NULL; |
| unsigned char *hash_dest = NULL; |
| SECStatus res; |
| PLArenaPool *poolp; |
| SECItem *key = NULL; |
| int key_len = 0; |
| |
| if ((salt == NULL) || (password == NULL)) { |
| return NULL; |
| } |
| |
| poolp = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
| if (poolp == NULL) { |
| PORT_SetError(SEC_ERROR_NO_MEMORY); |
| return NULL; |
| } |
| |
| pre_hash = (unsigned char *)PORT_ArenaZAlloc(poolp, sizeof(char) * (salt->len + password->len)); |
| if (pre_hash == NULL) { |
| PORT_SetError(SEC_ERROR_NO_MEMORY); |
| goto loser; |
| } |
| |
| hash_dest = (unsigned char *)PORT_ArenaZAlloc(poolp, |
| sizeof(unsigned char) * SHA1_LENGTH); |
| if (hash_dest == NULL) { |
| PORT_SetError(SEC_ERROR_NO_MEMORY); |
| goto loser; |
| } |
| |
| PORT_Memcpy(pre_hash, salt->data, salt->len); |
| /* handle password of 0 length case */ |
| if (password->len > 0) { |
| PORT_Memcpy(&(pre_hash[salt->len]), password->data, password->len); |
| } |
| |
| res = PK11_HashBuf(SEC_OID_SHA1, hash_dest, pre_hash, |
| (salt->len + password->len)); |
| if (res == SECFailure) { |
| PORT_SetError(SEC_ERROR_NO_MEMORY); |
| goto loser; |
| } |
| |
| switch (algorithm) { |
| case SEC_OID_SHA1: |
| if (key_len == 0) |
| key_len = 16; |
| key = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); |
| if (key == NULL) { |
| PORT_SetError(SEC_ERROR_NO_MEMORY); |
| goto loser; |
| } |
| key->data = (unsigned char *)PORT_ZAlloc(sizeof(unsigned char) * key_len); |
| if (key->data == NULL) { |
| PORT_SetError(SEC_ERROR_NO_MEMORY); |
| goto loser; |
| } |
| key->len = key_len; |
| PORT_Memcpy(key->data, &hash_dest[SHA1_LENGTH - key->len], key->len); |
| break; |
| default: |
| goto loser; |
| break; |
| } |
| |
| PORT_FreeArena(poolp, PR_TRUE); |
| return key; |
| |
| loser: |
| PORT_FreeArena(poolp, PR_TRUE); |
| if (key != NULL) { |
| SECITEM_ZfreeItem(key, PR_TRUE); |
| } |
| return NULL; |
| } |
| |
| /* MAC is generated per PKCS 12 section 6. It is expected that key, msg |
| * and mac_dest are pre allocated, non-NULL arrays. msg_len is passed in |
| * because it is not known how long the message actually is. String |
| * manipulation routines will not necessarily work because msg may have |
| * imbedded NULLs |
| */ |
| static SECItem * |
| sec_pkcs12_generate_old_mac(SECItem *key, |
| SECItem *msg) |
| { |
| SECStatus res; |
| PLArenaPool *temparena = NULL; |
| unsigned char *hash_dest = NULL, *hash_src1 = NULL, *hash_src2 = NULL; |
| int i; |
| SECItem *mac = NULL; |
| |
| if ((key == NULL) || (msg == NULL)) |
| goto loser; |
| |
| /* allocate return item */ |
| mac = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); |
| if (mac == NULL) |
| return NULL; |
| mac->data = (unsigned char *)PORT_ZAlloc(sizeof(unsigned char) * SHA1_LENGTH); |
| mac->len = SHA1_LENGTH; |
| if (mac->data == NULL) |
| goto loser; |
| |
| /* allocate temporary items */ |
| temparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
| if (temparena == NULL) |
| goto loser; |
| |
| hash_src1 = (unsigned char *)PORT_ArenaZAlloc(temparena, |
| sizeof(unsigned char) * (16 + msg->len)); |
| if (hash_src1 == NULL) |
| goto loser; |
| |
| hash_src2 = (unsigned char *)PORT_ArenaZAlloc(temparena, |
| sizeof(unsigned char) * (SHA1_LENGTH + 16)); |
| if (hash_src2 == NULL) |
| goto loser; |
| |
| hash_dest = (unsigned char *)PORT_ArenaZAlloc(temparena, |
| sizeof(unsigned char) * SHA1_LENGTH); |
| if (hash_dest == NULL) |
| goto loser; |
| |
| /* perform mac'ing as per PKCS 12 */ |
| |
| /* first round of hashing */ |
| for (i = 0; i < 16; i++) |
| hash_src1[i] = key->data[i] ^ 0x36; |
| PORT_Memcpy(&(hash_src1[16]), msg->data, msg->len); |
| res = PK11_HashBuf(SEC_OID_SHA1, hash_dest, hash_src1, (16 + msg->len)); |
| if (res == SECFailure) |
| goto loser; |
| |
| /* second round of hashing */ |
| for (i = 0; i < 16; i++) |
| hash_src2[i] = key->data[i] ^ 0x5c; |
| PORT_Memcpy(&(hash_src2[16]), hash_dest, SHA1_LENGTH); |
| res = PK11_HashBuf(SEC_OID_SHA1, mac->data, hash_src2, SHA1_LENGTH + 16); |
| if (res == SECFailure) |
| goto loser; |
| |
| PORT_FreeArena(temparena, PR_TRUE); |
| return mac; |
| |
| loser: |
| if (temparena != NULL) |
| PORT_FreeArena(temparena, PR_TRUE); |
| if (mac != NULL) |
| SECITEM_ZfreeItem(mac, PR_TRUE); |
| return NULL; |
| } |
| |
| /* MAC is generated per PKCS 12 section 6. It is expected that key, msg |
| * and mac_dest are pre allocated, non-NULL arrays. msg_len is passed in |
| * because it is not known how long the message actually is. String |
| * manipulation routines will not necessarily work because msg may have |
| * imbedded NULLs |
| */ |
| SECItem * |
| sec_pkcs12_generate_mac(SECItem *key, |
| SECItem *msg, |
| PRBool old_method) |
| { |
| SECStatus res = SECFailure; |
| SECItem *mac = NULL; |
| PK11Context *pk11cx = NULL; |
| SECItem ignore = { 0 }; |
| |
| if ((key == NULL) || (msg == NULL)) { |
| return NULL; |
| } |
| |
| if (old_method == PR_TRUE) { |
| return sec_pkcs12_generate_old_mac(key, msg); |
| } |
| |
| /* allocate return item */ |
| mac = SECITEM_AllocItem(NULL, NULL, SHA1_LENGTH); |
| if (mac == NULL) { |
| return NULL; |
| } |
| |
| pk11cx = PK11_CreateContextByRawKey(NULL, CKM_SHA_1_HMAC, PK11_OriginDerive, |
| CKA_SIGN, key, &ignore, NULL); |
| if (pk11cx == NULL) { |
| goto loser; |
| } |
| |
| res = PK11_DigestBegin(pk11cx); |
| if (res == SECFailure) { |
| goto loser; |
| } |
| |
| res = PK11_DigestOp(pk11cx, msg->data, msg->len); |
| if (res == SECFailure) { |
| goto loser; |
| } |
| |
| res = PK11_DigestFinal(pk11cx, mac->data, &mac->len, SHA1_LENGTH); |
| if (res == SECFailure) { |
| goto loser; |
| } |
| |
| PK11_DestroyContext(pk11cx, PR_TRUE); |
| pk11cx = NULL; |
| |
| loser: |
| |
| if (res != SECSuccess) { |
| SECITEM_ZfreeItem(mac, PR_TRUE); |
| mac = NULL; |
| if (pk11cx) { |
| PK11_DestroyContext(pk11cx, PR_TRUE); |
| } |
| } |
| |
| return mac; |
| } |
| |
| /* compute the thumbprint of the DER cert and create a digest info |
| * to store it in and return the digest info. |
| * a return of NULL indicates an error. |
| */ |
| SGNDigestInfo * |
| sec_pkcs12_compute_thumbprint(SECItem *der_cert) |
| { |
| SGNDigestInfo *thumb = NULL; |
| SECItem digest; |
| PLArenaPool *temparena = NULL; |
| SECStatus rv = SECFailure; |
| |
| if (der_cert == NULL) |
| return NULL; |
| |
| temparena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); |
| if (temparena == NULL) { |
| return NULL; |
| } |
| |
| digest.data = (unsigned char *)PORT_ArenaZAlloc(temparena, |
| sizeof(unsigned char) * |
| SHA1_LENGTH); |
| /* digest data and create digest info */ |
| if (digest.data != NULL) { |
| digest.len = SHA1_LENGTH; |
| rv = PK11_HashBuf(SEC_OID_SHA1, digest.data, der_cert->data, |
| der_cert->len); |
| if (rv == SECSuccess) { |
| thumb = SGN_CreateDigestInfo(SEC_OID_SHA1, |
| digest.data, |
| digest.len); |
| } else { |
| PORT_SetError(SEC_ERROR_NO_MEMORY); |
| } |
| } else { |
| PORT_SetError(SEC_ERROR_NO_MEMORY); |
| } |
| |
| PORT_FreeArena(temparena, PR_TRUE); |
| |
| return thumb; |
| } |
| |
| /* create a virtual password per PKCS 12, the password is converted |
| * to unicode, the salt is prepended to it, and then the whole thing |
| * is returned */ |
| SECItem * |
| sec_pkcs12_create_virtual_password(SECItem *password, SECItem *salt, |
| PRBool swap) |
| { |
| SECItem uniPwd = { siBuffer, NULL, 0 }, *retPwd = NULL; |
| |
| if ((password == NULL) || (salt == NULL)) { |
| return NULL; |
| } |
| |
| if (password->len == 0) { |
| uniPwd.data = (unsigned char *)PORT_ZAlloc(2); |
| uniPwd.len = 2; |
| if (!uniPwd.data) { |
| return NULL; |
| } |
| } else { |
| uniPwd.data = (unsigned char *)PORT_ZAlloc(password->len * 3); |
| uniPwd.len = password->len * 3; |
| if (!PORT_UCS2_ASCIIConversion(PR_TRUE, password->data, password->len, |
| uniPwd.data, uniPwd.len, &uniPwd.len, swap)) { |
| SECITEM_ZfreeItem(&uniPwd, PR_FALSE); |
| return NULL; |
| } |
| } |
| |
| retPwd = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); |
| if (retPwd == NULL) { |
| goto loser; |
| } |
| |
| /* allocate space and copy proper data */ |
| retPwd->len = uniPwd.len + salt->len; |
| retPwd->data = (unsigned char *)PORT_Alloc(retPwd->len); |
| if (retPwd->data == NULL) { |
| PORT_Free(retPwd); |
| goto loser; |
| } |
| |
| PORT_Memcpy(retPwd->data, salt->data, salt->len); |
| PORT_Memcpy((retPwd->data + salt->len), uniPwd.data, uniPwd.len); |
| |
| SECITEM_ZfreeItem(&uniPwd, PR_FALSE); |
| |
| return retPwd; |
| |
| loser: |
| PORT_SetError(SEC_ERROR_NO_MEMORY); |
| SECITEM_ZfreeItem(&uniPwd, PR_FALSE); |
| return NULL; |
| } |
| |
| /* appends a shrouded key to a key bag. this is used for exporting |
| * to store externally wrapped keys. it is used when importing to convert |
| * old items to new |
| */ |
| SECStatus |
| sec_pkcs12_append_shrouded_key(SEC_PKCS12BaggageItem *bag, |
| SEC_PKCS12ESPVKItem *espvk) |
| { |
| int size; |
| void *mark = NULL, *dummy = NULL; |
| |
| if ((bag == NULL) || (espvk == NULL)) |
| return SECFailure; |
| |
| mark = PORT_ArenaMark(bag->poolp); |
| |
| /* grow the list */ |
| size = (bag->nEspvks + 1) * sizeof(SEC_PKCS12ESPVKItem *); |
| dummy = (SEC_PKCS12ESPVKItem **)PORT_ArenaGrow(bag->poolp, |
| bag->espvks, size, |
| size + sizeof(SEC_PKCS12ESPVKItem *)); |
| bag->espvks = (SEC_PKCS12ESPVKItem **)dummy; |
| if (dummy == NULL) { |
| PORT_SetError(SEC_ERROR_NO_MEMORY); |
| goto loser; |
| } |
| |
| bag->espvks[bag->nEspvks] = espvk; |
| bag->nEspvks++; |
| bag->espvks[bag->nEspvks] = NULL; |
| |
| PORT_ArenaUnmark(bag->poolp, mark); |
| return SECSuccess; |
| |
| loser: |
| PORT_ArenaRelease(bag->poolp, mark); |
| return SECFailure; |
| } |
| |
| /* search a certificate list for a nickname, a thumbprint, or both |
| * within a certificate bag. if the certificate could not be |
| * found or an error occurs, NULL is returned; |
| */ |
| static SEC_PKCS12CertAndCRL * |
| sec_pkcs12_find_cert_in_certbag(SEC_PKCS12CertAndCRLBag *certbag, |
| SECItem *nickname, SGNDigestInfo *thumbprint) |
| { |
| PRBool search_both = PR_FALSE, search_nickname = PR_FALSE; |
| int i, j; |
| |
| if ((certbag == NULL) || ((nickname == NULL) && (thumbprint == NULL))) { |
| return NULL; |
| } |
| |
| if (thumbprint && nickname) { |
| search_both = PR_TRUE; |
| } |
| |
| if (nickname) { |
| search_nickname = PR_TRUE; |
| } |
| |
| search_again: |
| i = 0; |
| while (certbag->certAndCRLs[i] != NULL) { |
| SEC_PKCS12CertAndCRL *cert = certbag->certAndCRLs[i]; |
| |
| if (SECOID_FindOIDTag(&cert->BagID) == SEC_OID_PKCS12_X509_CERT_CRL_BAG) { |
| |
| /* check nicknames */ |
| if (search_nickname) { |
| if (SECITEM_CompareItem(nickname, &cert->nickname) == SECEqual) { |
| return cert; |
| } |
| } else { |
| /* check thumbprints */ |
| SECItem **derCertList; |
| |
| /* get pointer to certificate list, does not need to |
| * be freed since it is within the arena which will |
| * be freed later. |
| */ |
| derCertList = SEC_PKCS7GetCertificateList(&cert->value.x509->certOrCRL); |
| j = 0; |
| if (derCertList != NULL) { |
| while (derCertList[j] != NULL) { |
| SECComparison eq; |
| SGNDigestInfo *di; |
| di = sec_pkcs12_compute_thumbprint(derCertList[j]); |
| if (di) { |
| eq = SGN_CompareDigestInfo(thumbprint, di); |
| SGN_DestroyDigestInfo(di); |
| if (eq == SECEqual) { |
| /* copy the derCert for later reference */ |
| cert->value.x509->derLeafCert = derCertList[j]; |
| return cert; |
| } |
| } else { |
| /* an error occurred */ |
| return NULL; |
| } |
| j++; |
| } |
| } |
| } |
| } |
| |
| i++; |
| } |
| |
| if (search_both) { |
| search_both = PR_FALSE; |
| search_nickname = PR_FALSE; |
| goto search_again; |
| } |
| |
| return NULL; |
| } |
| |
| /* search a key list for a nickname, a thumbprint, or both |
| * within a key bag. if the key could not be |
| * found or an error occurs, NULL is returned; |
| */ |
| static SEC_PKCS12PrivateKey * |
| sec_pkcs12_find_key_in_keybag(SEC_PKCS12PrivateKeyBag *keybag, |
| SECItem *nickname, SGNDigestInfo *thumbprint) |
| { |
| PRBool search_both = PR_FALSE, search_nickname = PR_FALSE; |
| int i, j; |
| |
| if ((keybag == NULL) || ((nickname == NULL) && (thumbprint == NULL))) { |
| return NULL; |
| } |
| |
| if (keybag->privateKeys == NULL) { |
| return NULL; |
| } |
| |
| if (thumbprint && nickname) { |
| search_both = PR_TRUE; |
| } |
| |
| if (nickname) { |
| search_nickname = PR_TRUE; |
| } |
| |
| search_again: |
| i = 0; |
| while (keybag->privateKeys[i] != NULL) { |
| SEC_PKCS12PrivateKey *key = keybag->privateKeys[i]; |
| |
| /* check nicknames */ |
| if (search_nickname) { |
| if (SECITEM_CompareItem(nickname, &key->pvkData.nickname) == SECEqual) { |
| return key; |
| } |
| } else { |
| /* check digests */ |
| SGNDigestInfo **assocCerts = key->pvkData.assocCerts; |
| if ((assocCerts == NULL) || (assocCerts[0] == NULL)) { |
| return NULL; |
| } |
| |
| j = 0; |
| while (assocCerts[j] != NULL) { |
| SECComparison eq; |
| eq = SGN_CompareDigestInfo(thumbprint, assocCerts[j]); |
| if (eq == SECEqual) { |
| return key; |
| } |
| j++; |
| } |
| } |
| i++; |
| } |
| |
| if (search_both) { |
| search_both = PR_FALSE; |
| search_nickname = PR_FALSE; |
| goto search_again; |
| } |
| |
| return NULL; |
| } |
| |
| /* seach the safe first then try the baggage bag |
| * safe and bag contain certs and keys to search |
| * objType is the object type to look for |
| * bagType is the type of bag that was found by sec_pkcs12_find_object |
| * index is the entity in safe->safeContents or bag->unencSecrets which |
| * is being searched |
| * nickname and thumbprint are the search criteria |
| * |
| * a return of null indicates no match |
| */ |
| static void * |
| sec_pkcs12_try_find(SEC_PKCS12SafeContents *safe, |
| SEC_PKCS12BaggageItem *bag, |
| SECOidTag objType, SECOidTag bagType, int index, |
| SECItem *nickname, SGNDigestInfo *thumbprint) |
| { |
| PRBool searchSafe; |
| int i = index; |
| |
| if ((safe == NULL) && (bag == NULL)) { |
| return NULL; |
| } |
| |
| searchSafe = (safe == NULL ? PR_FALSE : PR_TRUE); |
| switch (objType) { |
| case SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID: |
| if (objType == bagType) { |
| SEC_PKCS12CertAndCRLBag *certBag; |
| |
| if (searchSafe) { |
| certBag = safe->contents[i]->safeContent.certAndCRLBag; |
| } else { |
| certBag = bag->unencSecrets[i]->safeContent.certAndCRLBag; |
| } |
| return sec_pkcs12_find_cert_in_certbag(certBag, nickname, |
| thumbprint); |
| } |
| break; |
| case SEC_OID_PKCS12_KEY_BAG_ID: |
| if (objType == bagType) { |
| SEC_PKCS12PrivateKeyBag *keyBag; |
| |
| if (searchSafe) { |
| keyBag = safe->contents[i]->safeContent.keyBag; |
| } else { |
| keyBag = bag->unencSecrets[i]->safeContent.keyBag; |
| } |
| return sec_pkcs12_find_key_in_keybag(keyBag, nickname, |
| thumbprint); |
| } |
| break; |
| default: |
| break; |
| } |
| |
| return NULL; |
| } |
| |
| /* searches both the baggage and the safe areas looking for |
| * object of specified type matching either the nickname or the |
| * thumbprint specified. |
| * |
| * safe and baggage store certs and keys |
| * objType is the OID for the bag type to be searched: |
| * SEC_OID_PKCS12_KEY_BAG_ID, or |
| * SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID |
| * nickname and thumbprint are the search criteria |
| * |
| * if no match found, NULL returned and error set |
| */ |
| void * |
| sec_pkcs12_find_object(SEC_PKCS12SafeContents *safe, |
| SEC_PKCS12Baggage *baggage, |
| SECOidTag objType, |
| SECItem *nickname, |
| SGNDigestInfo *thumbprint) |
| { |
| int i, j; |
| void *retItem; |
| |
| if (((safe == NULL) && (thumbprint == NULL)) || |
| ((nickname == NULL) && (thumbprint == NULL))) { |
| return NULL; |
| } |
| |
| i = 0; |
| if ((safe != NULL) && (safe->contents != NULL)) { |
| while (safe->contents[i] != NULL) { |
| SECOidTag bagType = SECOID_FindOIDTag(&safe->contents[i]->safeBagType); |
| retItem = sec_pkcs12_try_find(safe, NULL, objType, bagType, i, |
| nickname, thumbprint); |
| if (retItem != NULL) { |
| return retItem; |
| } |
| i++; |
| } |
| } |
| |
| if ((baggage != NULL) && (baggage->bags != NULL)) { |
| i = 0; |
| while (baggage->bags[i] != NULL) { |
| SEC_PKCS12BaggageItem *xbag = baggage->bags[i]; |
| j = 0; |
| if (xbag->unencSecrets != NULL) { |
| while (xbag->unencSecrets[j] != NULL) { |
| SECOidTag bagType; |
| bagType = SECOID_FindOIDTag(&xbag->unencSecrets[j]->safeBagType); |
| retItem = sec_pkcs12_try_find(NULL, xbag, objType, bagType, |
| j, nickname, thumbprint); |
| if (retItem != NULL) { |
| return retItem; |
| } |
| j++; |
| } |
| } |
| i++; |
| } |
| } |
| |
| PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME); |
| return NULL; |
| } |
| |
| /* this function converts a password to unicode and encures that the |
| * required double 0 byte be placed at the end of the string |
| */ |
| PRBool |
| sec_pkcs12_convert_item_to_unicode(PLArenaPool *arena, SECItem *dest, |
| SECItem *src, PRBool zeroTerm, |
| PRBool asciiConvert, PRBool toUnicode) |
| { |
| PRBool success = PR_FALSE; |
| if (!src || !dest) { |
| PORT_SetError(SEC_ERROR_INVALID_ARGS); |
| return PR_FALSE; |
| } |
| |
| dest->len = src->len * 3 + 2; |
| if (arena) { |
| dest->data = (unsigned char *)PORT_ArenaZAlloc(arena, dest->len); |
| } else { |
| dest->data = (unsigned char *)PORT_ZAlloc(dest->len); |
| } |
| |
| if (!dest->data) { |
| dest->len = 0; |
| return PR_FALSE; |
| } |
| |
| if (!asciiConvert) { |
| success = PORT_UCS2_UTF8Conversion(toUnicode, src->data, src->len, dest->data, |
| dest->len, &dest->len); |
| } else { |
| #ifndef IS_LITTLE_ENDIAN |
| PRBool swapUnicode = PR_FALSE; |
| #else |
| PRBool swapUnicode = PR_TRUE; |
| #endif |
| success = PORT_UCS2_ASCIIConversion(toUnicode, src->data, src->len, dest->data, |
| dest->len, &dest->len, swapUnicode); |
| } |
| |
| if (!success) { |
| if (!arena) { |
| PORT_Free(dest->data); |
| dest->data = NULL; |
| dest->len = 0; |
| } |
| return PR_FALSE; |
| } |
| |
| if ((dest->len >= 2) && |
| (dest->data[dest->len - 1] || dest->data[dest->len - 2]) && zeroTerm) { |
| if (dest->len + 2 > 3 * src->len) { |
| if (arena) { |
| dest->data = (unsigned char *)PORT_ArenaGrow(arena, |
| dest->data, dest->len, |
| dest->len + 2); |
| } else { |
| dest->data = (unsigned char *)PORT_Realloc(dest->data, |
| dest->len + 2); |
| } |
| |
| if (!dest->data) { |
| return PR_FALSE; |
| } |
| } |
| dest->len += 2; |
| dest->data[dest->len - 1] = dest->data[dest->len - 2] = 0; |
| } |
| |
| return PR_TRUE; |
| } |
| |
| PRBool |
| sec_pkcs12_is_pkcs12_pbe_algorithm(SECOidTag algorithm) |
| { |
| switch (algorithm) { |
| case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC: |
| case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC: |
| case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC: |
| case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC: |
| case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC: |
| case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC: |
| case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC: |
| case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC4: |
| case SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC4: |
| case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4: |
| case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4: |
| /* those are actually PKCS #5 v1.5 PBEs, but we |
| * historically treat them in the same way as PKCS #12 |
| * PBEs */ |
| case SEC_OID_PKCS5_PBE_WITH_MD2_AND_DES_CBC: |
| case SEC_OID_PKCS5_PBE_WITH_SHA1_AND_DES_CBC: |
| case SEC_OID_PKCS5_PBE_WITH_MD5_AND_DES_CBC: |
| return PR_TRUE; |
| default: |
| return PR_FALSE; |
| } |
| } |
| |
| /* this function decodes a password from Unicode if necessary, |
| * according to the PBE algorithm. |
| * |
| * we assume that the pwitem is already encoded in Unicode by the |
| * caller. if the encryption scheme is not the one defined in PKCS |
| * #12, decode the pwitem back into UTF-8. */ |
| PRBool |
| sec_pkcs12_decode_password(PLArenaPool *arena, |
| SECItem *result, |
| SECOidTag algorithm, |
| const SECItem *pwitem) |
| { |
| if (!sec_pkcs12_is_pkcs12_pbe_algorithm(algorithm)) |
| return sec_pkcs12_convert_item_to_unicode(arena, result, |
| (SECItem *)pwitem, |
| PR_TRUE, PR_FALSE, PR_FALSE); |
| |
| return SECITEM_CopyItem(arena, result, pwitem) == SECSuccess; |
| } |
| |
| /* this function encodes a password into Unicode if necessary, |
| * according to the PBE algorithm. |
| * |
| * we assume that the pwitem holds a raw password. if the encryption |
| * scheme is the one defined in PKCS #12, encode the password into |
| * BMPString. */ |
| PRBool |
| sec_pkcs12_encode_password(PLArenaPool *arena, |
| SECItem *result, |
| SECOidTag algorithm, |
| const SECItem *pwitem) |
| { |
| if (sec_pkcs12_is_pkcs12_pbe_algorithm(algorithm)) |
| return sec_pkcs12_convert_item_to_unicode(arena, result, |
| (SECItem *)pwitem, |
| PR_TRUE, PR_TRUE, PR_TRUE); |
| |
| return SECITEM_CopyItem(arena, result, pwitem) == SECSuccess; |
| } |
| |
| /* pkcs 12 templates */ |
| static const SEC_ASN1TemplateChooserPtr sec_pkcs12_shroud_chooser = |
| sec_pkcs12_choose_shroud_type; |
| |
| const SEC_ASN1Template SEC_PKCS12CodedSafeBagTemplate[] = |
| { |
| { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS12SafeBag) }, |
| { SEC_ASN1_OBJECT_ID, offsetof(SEC_PKCS12SafeBag, safeBagType) }, |
| { SEC_ASN1_ANY, offsetof(SEC_PKCS12SafeBag, derSafeContent) }, |
| { 0 } |
| }; |
| |
| const SEC_ASN1Template SEC_PKCS12CodedCertBagTemplate[] = |
| { |
| { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS12CertAndCRL) }, |
| { SEC_ASN1_OBJECT_ID, offsetof(SEC_PKCS12CertAndCRL, BagID) }, |
| { SEC_ASN1_ANY, offsetof(SEC_PKCS12CertAndCRL, derValue) }, |
| { 0 } |
| }; |
| |
| const SEC_ASN1Template SEC_PKCS12CodedCertAndCRLBagTemplate[] = |
| { |
| { SEC_ASN1_SET_OF, offsetof(SEC_PKCS12CertAndCRLBag, certAndCRLs), |
| SEC_PKCS12CodedCertBagTemplate }, |
| }; |
| |
| const SEC_ASN1Template SEC_PKCS12ESPVKItemTemplate_OLD[] = |
| { |
| { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS12ESPVKItem) }, |
| { SEC_ASN1_OBJECT_ID, offsetof(SEC_PKCS12ESPVKItem, espvkOID) }, |
| { SEC_ASN1_INLINE, offsetof(SEC_PKCS12ESPVKItem, espvkData), |
| SEC_PKCS12PVKSupportingDataTemplate_OLD }, |
| { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | |
| SEC_ASN1_DYNAMIC | 0, |
| offsetof(SEC_PKCS12ESPVKItem, espvkCipherText), |
| &sec_pkcs12_shroud_chooser }, |
| { 0 } |
| }; |
| |
| const SEC_ASN1Template SEC_PKCS12ESPVKItemTemplate[] = |
| { |
| { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS12ESPVKItem) }, |
| { SEC_ASN1_OBJECT_ID, offsetof(SEC_PKCS12ESPVKItem, espvkOID) }, |
| { SEC_ASN1_INLINE, offsetof(SEC_PKCS12ESPVKItem, espvkData), |
| SEC_PKCS12PVKSupportingDataTemplate }, |
| { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | |
| SEC_ASN1_DYNAMIC | 0, |
| offsetof(SEC_PKCS12ESPVKItem, espvkCipherText), |
| &sec_pkcs12_shroud_chooser }, |
| { 0 } |
| }; |
| |
| const SEC_ASN1Template SEC_PKCS12PVKAdditionalDataTemplate[] = |
| { |
| { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS12PVKAdditionalData) }, |
| { SEC_ASN1_OBJECT_ID, |
| offsetof(SEC_PKCS12PVKAdditionalData, pvkAdditionalType) }, |
| { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, |
| offsetof(SEC_PKCS12PVKAdditionalData, pvkAdditionalContent) }, |
| { 0 } |
| }; |
| |
| const SEC_ASN1Template SEC_PKCS12PVKSupportingDataTemplate_OLD[] = |
| { |
| { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS12PVKSupportingData) }, |
| { SEC_ASN1_SET_OF | SEC_ASN1_XTRN, |
| offsetof(SEC_PKCS12PVKSupportingData, assocCerts), |
| SEC_ASN1_SUB(sgn_DigestInfoTemplate) }, |
| { SEC_ASN1_OPTIONAL | SEC_ASN1_BOOLEAN, |
| offsetof(SEC_PKCS12PVKSupportingData, regenerable) }, |
| { SEC_ASN1_PRINTABLE_STRING, |
| offsetof(SEC_PKCS12PVKSupportingData, nickname) }, |
| { SEC_ASN1_ANY | SEC_ASN1_OPTIONAL, |
| offsetof(SEC_PKCS12PVKSupportingData, pvkAdditionalDER) }, |
| { 0 } |
| }; |
| |
| const SEC_ASN1Template SEC_PKCS12PVKSupportingDataTemplate[] = |
| { |
| { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS12PVKSupportingData) }, |
| { SEC_ASN1_SET_OF | SEC_ASN1_XTRN, |
| offsetof(SEC_PKCS12PVKSupportingData, assocCerts), |
| SEC_ASN1_SUB(sgn_DigestInfoTemplate) }, |
| { SEC_ASN1_OPTIONAL | SEC_ASN1_BOOLEAN, |
| offsetof(SEC_PKCS12PVKSupportingData, regenerable) }, |
| { SEC_ASN1_BMP_STRING, |
| offsetof(SEC_PKCS12PVKSupportingData, uniNickName) }, |
| { SEC_ASN1_ANY | SEC_ASN1_OPTIONAL, |
| offsetof(SEC_PKCS12PVKSupportingData, pvkAdditionalDER) }, |
| { 0 } |
| }; |
| |
| const SEC_ASN1Template SEC_PKCS12BaggageItemTemplate[] = |
| { |
| { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS12BaggageItem) }, |
| { SEC_ASN1_SET_OF, offsetof(SEC_PKCS12BaggageItem, espvks), |
| SEC_PKCS12ESPVKItemTemplate }, |
| { SEC_ASN1_SET_OF, offsetof(SEC_PKCS12BaggageItem, unencSecrets), |
| SEC_PKCS12SafeBagTemplate }, |
| /*{ SEC_ASN1_SET_OF, offsetof(SEC_PKCS12BaggageItem, unencSecrets), |
| SEC_PKCS12CodedSafeBagTemplate }, */ |
| { 0 } |
| }; |
| |
| const SEC_ASN1Template SEC_PKCS12BaggageTemplate[] = |
| { |
| { SEC_ASN1_SET_OF, offsetof(SEC_PKCS12Baggage, bags), |
| SEC_PKCS12BaggageItemTemplate }, |
| }; |
| |
| const SEC_ASN1Template SEC_PKCS12BaggageTemplate_OLD[] = |
| { |
| { SEC_ASN1_SET_OF, offsetof(SEC_PKCS12Baggage_OLD, espvks), |
| SEC_PKCS12ESPVKItemTemplate_OLD }, |
| }; |
| |
| static const SEC_ASN1TemplateChooserPtr sec_pkcs12_bag_chooser = |
| sec_pkcs12_choose_bag_type; |
| |
| static const SEC_ASN1TemplateChooserPtr sec_pkcs12_bag_chooser_old = |
| sec_pkcs12_choose_bag_type_old; |
| |
| const SEC_ASN1Template SEC_PKCS12SafeBagTemplate_OLD[] = |
| { |
| { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS12SafeBag) }, |
| { SEC_ASN1_OBJECT_ID, offsetof(SEC_PKCS12SafeBag, safeBagType) }, |
| { SEC_ASN1_DYNAMIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | |
| SEC_ASN1_CONTEXT_SPECIFIC | 0, |
| offsetof(SEC_PKCS12SafeBag, safeContent), |
| &sec_pkcs12_bag_chooser_old }, |
| { 0 } |
| }; |
| |
| const SEC_ASN1Template SEC_PKCS12SafeBagTemplate[] = |
| { |
| { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS12SafeBag) }, |
| { SEC_ASN1_OBJECT_ID, offsetof(SEC_PKCS12SafeBag, safeBagType) }, |
| { SEC_ASN1_DYNAMIC | SEC_ASN1_POINTER, |
| offsetof(SEC_PKCS12SafeBag, safeContent), |
| &sec_pkcs12_bag_chooser }, |
| { SEC_ASN1_OPTIONAL | SEC_ASN1_BMP_STRING, |
| offsetof(SEC_PKCS12SafeBag, uniSafeBagName) }, |
| { 0 } |
| }; |
| |
| const SEC_ASN1Template SEC_PKCS12SafeContentsTemplate_OLD[] = |
| { |
| { SEC_ASN1_SET_OF, |
| offsetof(SEC_PKCS12SafeContents, contents), |
| SEC_PKCS12SafeBagTemplate_OLD } |
| }; |
| |
| const SEC_ASN1Template SEC_PKCS12SafeContentsTemplate[] = |
| { |
| { SEC_ASN1_SET_OF, |
| offsetof(SEC_PKCS12SafeContents, contents), |
| SEC_PKCS12SafeBagTemplate } /* here */ |
| }; |
| |
| const SEC_ASN1Template SEC_PKCS12PrivateKeyTemplate[] = |
| { |
| { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS12PrivateKey) }, |
| { SEC_ASN1_INLINE, offsetof(SEC_PKCS12PrivateKey, pvkData), |
| SEC_PKCS12PVKSupportingDataTemplate }, |
| { SEC_ASN1_INLINE | SEC_ASN1_XTRN, |
| offsetof(SEC_PKCS12PrivateKey, pkcs8data), |
| SEC_ASN1_SUB(SECKEY_PrivateKeyInfoTemplate) }, |
| { 0 } |
| }; |
| |
| const SEC_ASN1Template SEC_PKCS12PrivateKeyBagTemplate[] = |
| { |
| { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS12PrivateKeyBag) }, |
| { SEC_ASN1_SET_OF, offsetof(SEC_PKCS12PrivateKeyBag, privateKeys), |
| SEC_PKCS12PrivateKeyTemplate }, |
| { 0 } |
| }; |
| |
| const SEC_ASN1Template SEC_PKCS12X509CertCRLTemplate_OLD[] = |
| { |
| { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS12X509CertCRL) }, |
| { SEC_ASN1_INLINE, offsetof(SEC_PKCS12X509CertCRL, certOrCRL), |
| sec_PKCS7ContentInfoTemplate }, |
| { SEC_ASN1_INLINE | SEC_ASN1_XTRN, |
| offsetof(SEC_PKCS12X509CertCRL, thumbprint), |
| SEC_ASN1_SUB(sgn_DigestInfoTemplate) }, |
| { 0 } |
| }; |
| |
| const SEC_ASN1Template SEC_PKCS12X509CertCRLTemplate[] = |
| { |
| { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS12X509CertCRL) }, |
| { SEC_ASN1_INLINE, offsetof(SEC_PKCS12X509CertCRL, certOrCRL), |
| sec_PKCS7ContentInfoTemplate }, |
| { 0 } |
| }; |
| |
| const SEC_ASN1Template SEC_PKCS12SDSICertTemplate[] = |
| { |
| { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS12X509CertCRL) }, |
| { SEC_ASN1_IA5_STRING, offsetof(SEC_PKCS12SDSICert, value) }, |
| { 0 } |
| }; |
| |
| static const SEC_ASN1TemplateChooserPtr sec_pkcs12_cert_crl_chooser_old = |
| sec_pkcs12_choose_cert_crl_type_old; |
| |
| static const SEC_ASN1TemplateChooserPtr sec_pkcs12_cert_crl_chooser = |
| sec_pkcs12_choose_cert_crl_type; |
| |
| const SEC_ASN1Template SEC_PKCS12CertAndCRLTemplate_OLD[] = |
| { |
| { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS12CertAndCRL) }, |
| { SEC_ASN1_OBJECT_ID, offsetof(SEC_PKCS12CertAndCRL, BagID) }, |
| { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_EXPLICIT | |
| SEC_ASN1_DYNAMIC | SEC_ASN1_CONSTRUCTED | 0, |
| offsetof(SEC_PKCS12CertAndCRL, value), |
| &sec_pkcs12_cert_crl_chooser_old }, |
| { 0 } |
| }; |
| |
| const SEC_ASN1Template SEC_PKCS12CertAndCRLTemplate[] = |
| { |
| { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS12CertAndCRL) }, |
| { SEC_ASN1_OBJECT_ID, offsetof(SEC_PKCS12CertAndCRL, BagID) }, |
| { SEC_ASN1_DYNAMIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | |
| SEC_ASN1_CONTEXT_SPECIFIC | 0, |
| offsetof(SEC_PKCS12CertAndCRL, value), |
| &sec_pkcs12_cert_crl_chooser }, |
| { 0 } |
| }; |
| |
| const SEC_ASN1Template SEC_PKCS12CertAndCRLBagTemplate[] = |
| { |
| { SEC_ASN1_SET_OF, offsetof(SEC_PKCS12CertAndCRLBag, certAndCRLs), |
| SEC_PKCS12CertAndCRLTemplate }, |
| }; |
| |
| const SEC_ASN1Template SEC_PKCS12CertAndCRLBagTemplate_OLD[] = |
| { |
| { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS12CertAndCRLBag) }, |
| { SEC_ASN1_SET_OF, offsetof(SEC_PKCS12CertAndCRLBag, certAndCRLs), |
| SEC_PKCS12CertAndCRLTemplate_OLD }, |
| { 0 } |
| }; |
| |
| const SEC_ASN1Template SEC_PKCS12SecretAdditionalTemplate[] = |
| { |
| { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS12SecretAdditional) }, |
| { SEC_ASN1_OBJECT_ID, |
| offsetof(SEC_PKCS12SecretAdditional, secretAdditionalType) }, |
| { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_EXPLICIT, |
| offsetof(SEC_PKCS12SecretAdditional, secretAdditionalContent) }, |
| { 0 } |
| }; |
| |
| const SEC_ASN1Template SEC_PKCS12SecretTemplate[] = |
| { |
| { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS12Secret) }, |
| { SEC_ASN1_BMP_STRING, offsetof(SEC_PKCS12Secret, uniSecretName) }, |
| { SEC_ASN1_ANY, offsetof(SEC_PKCS12Secret, value) }, |
| { SEC_ASN1_INLINE | SEC_ASN1_OPTIONAL, |
| offsetof(SEC_PKCS12Secret, secretAdditional), |
| SEC_PKCS12SecretAdditionalTemplate }, |
| { 0 } |
| }; |
| |
| const SEC_ASN1Template SEC_PKCS12SecretItemTemplate[] = |
| { |
| { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS12Secret) }, |
| { SEC_ASN1_INLINE | SEC_ASN1_CONTEXT_SPECIFIC | 0, |
| offsetof(SEC_PKCS12SecretItem, secret), SEC_PKCS12SecretTemplate }, |
| { SEC_ASN1_INLINE | SEC_ASN1_CONTEXT_SPECIFIC | 1, |
| offsetof(SEC_PKCS12SecretItem, subFolder), SEC_PKCS12SafeBagTemplate }, |
| { 0 } |
| }; |
| |
| const SEC_ASN1Template SEC_PKCS12SecretBagTemplate[] = |
| { |
| { SEC_ASN1_SET_OF, offsetof(SEC_PKCS12SecretBag, secrets), |
| SEC_PKCS12SecretItemTemplate }, |
| }; |
| |
| const SEC_ASN1Template SEC_PKCS12MacDataTemplate[] = |
| { |
| { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS12PFXItem) }, |
| { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(SEC_PKCS12MacData, safeMac), |
| SEC_ASN1_SUB(sgn_DigestInfoTemplate) }, |
| { SEC_ASN1_BIT_STRING, offsetof(SEC_PKCS12MacData, macSalt) }, |
| { 0 } |
| }; |
| |
| const SEC_ASN1Template SEC_PKCS12PFXItemTemplate[] = |
| { |
| { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS12PFXItem) }, |
| { SEC_ASN1_OPTIONAL | |
| SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, |
| offsetof(SEC_PKCS12PFXItem, macData), SEC_PKCS12MacDataTemplate }, |
| { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1, |
| offsetof(SEC_PKCS12PFXItem, authSafe), |
| sec_PKCS7ContentInfoTemplate }, |
| { 0 } |
| }; |
| |
| const SEC_ASN1Template SEC_PKCS12PFXItemTemplate_OLD[] = |
| { |
| { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS12PFXItem) }, |
| { SEC_ASN1_OPTIONAL | |
| SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0, |
| offsetof(SEC_PKCS12PFXItem, old_safeMac), |
| SEC_ASN1_SUB(sgn_DigestInfoTemplate) }, |
| { SEC_ASN1_OPTIONAL | SEC_ASN1_BIT_STRING, |
| offsetof(SEC_PKCS12PFXItem, old_macSalt) }, |
| { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1, |
| offsetof(SEC_PKCS12PFXItem, authSafe), |
| sec_PKCS7ContentInfoTemplate }, |
| { 0 } |
| }; |
| |
| const SEC_ASN1Template SEC_PKCS12AuthenticatedSafeTemplate[] = |
| { |
| { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS12AuthenticatedSafe) }, |
| { SEC_ASN1_OPTIONAL | SEC_ASN1_INTEGER, |
| offsetof(SEC_PKCS12AuthenticatedSafe, version) }, |
| { SEC_ASN1_OPTIONAL | SEC_ASN1_OBJECT_ID, |
| offsetof(SEC_PKCS12AuthenticatedSafe, transportMode) }, |
| { SEC_ASN1_BIT_STRING | SEC_ASN1_OPTIONAL, |
| offsetof(SEC_PKCS12AuthenticatedSafe, privacySalt) }, |
| { SEC_ASN1_OPTIONAL | SEC_ASN1_SET_OF, |
| offsetof(SEC_PKCS12AuthenticatedSafe, baggage.bags), |
| SEC_PKCS12BaggageItemTemplate }, |
| { SEC_ASN1_POINTER, |
| offsetof(SEC_PKCS12AuthenticatedSafe, safe), |
| sec_PKCS7ContentInfoTemplate }, |
| { 0 } |
| }; |
| |
| const SEC_ASN1Template SEC_PKCS12AuthenticatedSafeTemplate_OLD[] = |
| { |
| { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SEC_PKCS12AuthenticatedSafe) }, |
| { SEC_ASN1_OPTIONAL | SEC_ASN1_INTEGER, |
| offsetof(SEC_PKCS12AuthenticatedSafe, version) }, |
| { SEC_ASN1_OPTIONAL | SEC_ASN1_INTEGER, |
| offsetof(SEC_PKCS12AuthenticatedSafe, transportMode) }, |
| { SEC_ASN1_BIT_STRING, |
| offsetof(SEC_PKCS12AuthenticatedSafe, privacySalt) }, |
| { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | |
| SEC_ASN1_CONTEXT_SPECIFIC | 0, |
| offsetof(SEC_PKCS12AuthenticatedSafe, old_baggage), |
| SEC_PKCS12BaggageTemplate_OLD }, |
| { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1, |
| offsetof(SEC_PKCS12AuthenticatedSafe, old_safe), |
| sec_PKCS7ContentInfoTemplate }, |
| { 0 } |
| }; |
| |
| const SEC_ASN1Template SEC_PointerToPKCS12KeyBagTemplate[] = |
| { |
| { SEC_ASN1_POINTER, 0, SEC_PKCS12PrivateKeyBagTemplate } |
| }; |
| |
| const SEC_ASN1Template SEC_PointerToPKCS12CertAndCRLBagTemplate_OLD[] = |
| { |
| { SEC_ASN1_POINTER, 0, SEC_PKCS12CertAndCRLBagTemplate_OLD } |
| }; |
| |
| const SEC_ASN1Template SEC_PointerToPKCS12CertAndCRLBagTemplate[] = |
| { |
| { SEC_ASN1_POINTER, 0, SEC_PKCS12CertAndCRLBagTemplate } |
| }; |
| |
| const SEC_ASN1Template SEC_PointerToPKCS12SecretBagTemplate[] = |
| { |
| { SEC_ASN1_POINTER, 0, SEC_PKCS12SecretBagTemplate } |
| }; |
| |
| const SEC_ASN1Template SEC_PointerToPKCS12X509CertCRLTemplate_OLD[] = |
| { |
| { SEC_ASN1_POINTER, 0, SEC_PKCS12X509CertCRLTemplate_OLD } |
| }; |
| |
| const SEC_ASN1Template SEC_PointerToPKCS12X509CertCRLTemplate[] = |
| { |
| { SEC_ASN1_POINTER, 0, SEC_PKCS12X509CertCRLTemplate } |
| }; |
| |
| const SEC_ASN1Template SEC_PointerToPKCS12SDSICertTemplate[] = |
| { |
| { SEC_ASN1_POINTER, 0, SEC_PKCS12SDSICertTemplate } |
| }; |