/* 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/. */
/* handle PBE v2 case */ if (algtag == SEC_OID_PKCS5_PBMAC1) {
SECOidTag hmacAlg;
SECItem utf8Pw; int keyLen;
hmacAlg = SEC_PKCS5GetCryptoAlgorithm(prfAlgid); /* make sure we are using an hmac */ if (HASH_GetHashOidTagByHMACOidTag(hmacAlg) == SEC_OID_UNKNOWN) {
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); return NULL;
} if (!SEC_PKCS12IntegrityHashAllowed(hmacAlg, isDecrypt)) {
PORT_SetError(SEC_ERROR_BAD_EXPORT_ALGORITHM); return NULL;
} /* make sure the length is valid, as well as decoding the length * from prfAlgid, SEC_PKCS5GetLength does some * fallbacks, which evenutally gets the max length of the key if * the decode fails. All HMAC keys have a max length of 128 bytes
* in softoken, so if we get a keyLen of 128 we know we hit an error. */
keyLen = SEC_PKCS5GetKeyLength(prfAlgid); if ((keyLen == 0) || (keyLen == 128)) {
PORT_SetError(SEC_ERROR_BAD_DER); return NULL;
}
*hmacMech = PK11_AlgtagToMechanism(hmacAlg); /* pkcs12v2 hmac uses UTF8 rather than unicode */ if (!sec_pkcs12_convert_item_to_unicode(NULL, &utf8Pw, pwitem,
PR_FALSE, PR_FALSE, PR_FALSE)) { return NULL;
}
symKey = PK11_PBEKeyGen(slot, prfAlgid, &utf8Pw, PR_FALSE, pwarg);
SECITEM_ZfreeItem(&utf8Pw, PR_FALSE); return symKey;
}
/* 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;
/* 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; unsignedchar *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 = (unsignedchar *)PORT_ZAlloc(sizeof(unsignedchar) * SHA1_LENGTH);
mac->len = SHA1_LENGTH; if (mac->data == NULL) goto loser;
/* 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 (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;
digest.data = (unsignedchar *)PORT_ArenaZAlloc(temparena, sizeof(unsignedchar) *
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;
/* 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;
/* 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;
/* 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++;
}
}
}
}
/* 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;
/* 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
*/ staticvoid *
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;
/* 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;
/* this function converts a password to UCS2 and ensures that the * required double 0 byte be placed at the end of the string (if zeroTerm * is set), or the 0 bytes at the end are dropped (if zeroTerm is not set). * If toUnicode is false, we convert from UCS2 to UTF8/ASCII (latter is a * proper subset of the former) depending on the state of the asciiCovert * flag)
*/
PRBool
sec_pkcs12_convert_item_to_unicode(PLArenaPool *arena, SECItem *dest,
SECItem *src, PRBool zeroTerm,
PRBool asciiConvert, PRBool toUnicode)
{
PRBool success = PR_FALSE; int bufferSize;
if (!src || !dest) {
PORT_SetError(SEC_ERROR_INVALID_ARGS); return PR_FALSE;
}
if (!success) { if (!arena) {
PORT_Free(dest->data);
dest->data = NULL;
dest->len = 0;
} return PR_FALSE;
}
/* in some cases we need to add NULL terminations and in others
* we need to drop null terminations */ if (zeroTerm) { /* unicode adds two nulls at the end */ if (toUnicode) { if ((dest->len < 2) || dest->data[dest->len - 1] || dest->data[dest->len - 2]) { /* we've already allocated space for these new NULLs */
PORT_Assert(dest->len + 2 <= bufferSize);
dest->len += 2;
dest->data[dest->len - 1] = dest->data[dest->len - 2] = 0;
} /* ascii/utf-8 adds just 1 */
} elseif (!dest->len || dest->data[dest->len - 1]) {
PORT_Assert(dest->len + 1 <= bufferSize);
dest->len++;
dest->data[dest->len - 1] = 0;
}
} else { /* handle the drop case, no need to do any allocations here. */ if (toUnicode) { while ((dest->len >= 2) && !dest->data[dest->len - 1] &&
!dest->data[dest->len - 2]) {
dest->len -= 2;
}
} else { while (dest->len && !dest->data[dest->len - 1]) {
dest->len--;
}
}
}
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. NOTE: UTF-8 strings are
* used in the PRF without the trailing NULL */
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_FALSE, PR_FALSE, PR_FALSE);
/* 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);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.