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