int key_length = 0;
CK_ULONG key_length = 0;
CK_RV NSC_UnwrapKey(CK_SESSION_HANDLE hSession,    CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hUnwrappingKey,    CK_BYTE_PTR pWrappedKey, CK_ULONG ulWrappedKeyLen,    CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount,						 CK_OBJECT_HANDLE_PTR phKey){    PK11Object *key = NULL;    PK11Session *session;    int key_length = 0;    unsigned char * buf = NULL;    CK_RV crv = CKR_OK;    int i;    CK_ULONG bsize = ulWrappedKeyLen;    PK11Slot *slot = pk11_SlotFromSessionHandle(hSession);    SECItem bpki;    CK_OBJECT_CLASS target_type = CKO_SECRET_KEY;    /*     * now lets create an object to hang the attributes off of     */    key = pk11_NewObject(slot); /* fill in the handle later */    if (key == NULL) {	return CKR_HOST_MEMORY;    }    /*     * load the template values into the object     */    for (i=0; i < (int) ulAttributeCount; i++) {	if (pTemplate[i].type == CKA_VALUE_LEN) {	    key_length = *(CK_ULONG *)pTemplate[i].pValue;	    continue;	}        if (pTemplate[i].type == CKA_CLASS) {	    target_type = *(CK_OBJECT_CLASS *)pTemplate[i].pValue;	}	crv = pk11_AddAttributeType(key,pk11_attr_expand(&pTemplate[i]));	if (crv != CKR_OK) break;    }    if (crv != CKR_OK) {	pk11_FreeObject(key);	return crv;    }    crv = pk11_CryptInit(hSession,pMechanism,hUnwrappingKey,CKA_UNWRAP,							PK11_DECRYPT, PR_FALSE);    if (crv != CKR_OK) {	pk11_FreeObject(key);	return pk11_mapWrap(crv);    }    /* allocate the buffer to decrypt into      * this assumes the unwrapped key is never larger than the     * wrapped key. For all the mechanisms we support this is true */    buf = (unsigned char *)PORT_Alloc( ulWrappedKeyLen);    bsize = ulWrappedKeyLen;    crv = NSC_Decrypt(hSession, pWrappedKey, ulWrappedKeyLen, buf, &bsize);    if (crv != CKR_OK) {	pk11_FreeObject(key);	PORT_Free(buf);	return pk11_mapWrap(crv);    }    switch(target_type) {	case CKO_SECRET_KEY:	    if (!pk11_hasAttribute(key,CKA_KEY_TYPE)) {		crv = CKR_TEMPLATE_INCOMPLETE;		break;	    }	    if(key_length == 0) {		key_length = bsize;	    }	    if (key_length > MAX_KEY_LEN) {		crv = CKR_TEMPLATE_INCONSISTENT;		break;	    }    	    /* add the value */	    crv = pk11_AddAttributeType(key,CKA_VALUE,buf,key_length);	    break;	case CKO_PRIVATE_KEY:	    bpki.data = (unsigned char *)buf;	    bpki.len = bsize;	    crv = CKR_OK;	    if(pk11_unwrapPrivateKey(key, &bpki) != SECSuccess) {		crv = CKR_TEMPLATE_INCOMPLETE;	    }	    break;	default:	    crv = CKR_TEMPLATE_INCONSISTENT;	    break;    }    PORT_ZFree(buf, bsize);    if (crv != CKR_OK) { pk11_FreeObject(key); return crv; }    /* get the session */    session = pk11_SessionFromHandle(hSession);    if (session == NULL) {	pk11_FreeObject(key);        return CKR_SESSION_HANDLE_INVALID;    }    /*     * handle the base object stuff     */    crv = pk11_handleObject(key,session);    *phKey = key->handle;    pk11_FreeSession(session);    pk11_FreeObject(key);    return crv;}