/*
 * Class:     org_opensc_pkcs11_wrap_PKCS11Object
 * Method:    createObjectNative
 * Signature: (JJJ[Lorg/opensc/pkcs11/wrap/PKCS11Attribute;)J
 */
JNIEXPORT jlong JNICALL JNIX_FUNC_NAME(Java_org_opensc_pkcs11_wrap_PKCS11Object_createObjectNative)
  (JNIEnv *env, jclass jp11obj, jlong mh, jlong shandle, jlong hsession, jobjectArray attrs)
{
  int rv;
  CK_ULONG i;
  CK_ULONG ulAttributeCount;
  CK_ATTRIBUTE_PTR pAttributes;
  CK_OBJECT_HANDLE hObject;
  jclass clazz;
  jmethodID getKindID,getDataID;
  pkcs11_slot_t *slot;
  pkcs11_module_t *mod =  pkcs11_module_from_jhandle(env,mh);
  if (!mod) return 0;
  
  slot = pkcs11_slot_from_jhandle(env,shandle);
  if (!slot) return 0;

  clazz = (*env)->FindClass(env,"org/opensc/pkcs11/wrap/PKCS11Attribute");

  if (!clazz) return 0;

  getKindID = (*env)->GetMethodID(env,clazz,"getKind","()I");

  if (!getKindID) return 0;

   getDataID = (*env)->GetMethodID(env,clazz,"getData","()[B");

  if (!getDataID) return 0;

  ulAttributeCount = (*env)->GetArrayLength(env,attrs);
  pAttributes = alloca(ulAttributeCount * sizeof(CK_ATTRIBUTE));

  for (i=0;i<ulAttributeCount;++i)
    {
      jbyteArray data;
      jobject jattr = (*env)->GetObjectArrayElement(env,attrs,i);
      if (!jattr) return 0;

      pAttributes[i].type = (*env)->CallIntMethod(env,jattr,getKindID);

      data = (jbyteArray)(*env)->CallObjectMethod(env,jattr,getDataID);

      allocaCArrayFromJByteArray(pAttributes[i].pValue,pAttributes[i].ulValueLen,env,data);
    }


  rv = mod->method->C_CreateObject(hsession, pAttributes, ulAttributeCount, &hObject);

  if (rv  != CKR_OK)
    {
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",rv,
                          "C_CreateObject failed.");
      return 0;
    }

  return hObject;
}
/*
 * Class:     org_opensc_pkcs11_wrap_PKCS11Slot
 * Method:    enumerateSlotsNative
 * Signature: (J)[J
 */
jlongArray JNICALL JNIX_FUNC_NAME(Java_org_opensc_pkcs11_wrap_PKCS11Slot_enumerateSlotsNative)
  (JNIEnv *env, jclass clazz, jlong mh)
{
  CK_ULONG nslots=0;
  CK_ULONG i;
  CK_SLOT_ID *slot_ids;
  jlong *long_slot_ids;
  jlongArray ret;
  int rv;

  pkcs11_module_t *mod =  pkcs11_module_from_jhandle(env,mh);
  if (!mod) return 0;

  rv = mod->method->C_GetSlotList(FALSE /* tokenPresent */,(CK_SLOT_ID_PTR)0,&nslots);

  if (rv  != CKR_OK)
    {
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",rv,
                          "C_GetSlotList failed for module " PKCS11_MOD_NAME_FMT ".",
                          mod->name);
      return 0;
    }

  slot_ids = (CK_SLOT_ID *)alloca(sizeof(CK_SLOT_ID)*nslots);

  rv = mod->method->C_GetSlotList(FALSE /* tokenPresent */,slot_ids,&nslots);

  if (rv  != CKR_OK)
    {
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",rv,
                          "C_GetSlotList failed for module " PKCS11_MOD_NAME_FMT ".",mod->name);
      return 0;
    }
  
  long_slot_ids = (jlong *)alloca(sizeof(jlong)*nslots);

  for (i=0;i<nslots;++i)
    long_slot_ids[i] = slot_ids[i];

  ret = (*env)->NewLongArray(env,nslots);
  (*env)->SetLongArrayRegion(env,ret,0,nslots,long_slot_ids);

  return ret;
}
/*
 * Class:     org_opensc_pkcs11_wrap_PKCS11Session
 * Method:    signFinalNative
 * Signature: (JJJ)[B
 */
JNIEXPORT jbyteArray JNICALL JNIX_FUNC_NAME(Java_org_opensc_pkcs11_wrap_PKCS11Session_signFinalNative)
  (JNIEnv *env, jclass cls, jlong mh, jlong shandle, jlong hsession)
{
  int rv;
  CK_BYTE_PTR pSignature = NULL;
  CK_ULONG    ulSignatureLen = 0;
  jbyteArray ret;
  pkcs11_slot_t *slot;
  pkcs11_module_t *mod =  pkcs11_module_from_jhandle(env,mh);
  if (!mod) return 0;

  slot = pkcs11_slot_from_jhandle(env,shandle);
  if (!slot) return 0;

  rv = mod->method->C_SignFinal(hsession,pSignature,&ulSignatureLen);

  if (rv  != CKR_OK)
    {
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",rv,
                          "C_SignFinal failed for slot %d.",
                          (int)slot->id);
      return 0;
    }

  pSignature = (CK_BYTE_PTR)alloca(ulSignatureLen);

  rv = mod->method->C_SignFinal(hsession,pSignature,&ulSignatureLen);

  if (rv  != CKR_OK)
    {
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",rv,
                          "C_SignFinal failed for slot %d.",
                          (int)slot->id);
      return 0;
    }

  ret = (*env)->NewByteArray(env,ulSignatureLen);
  if (ret)
    (*env)->SetByteArrayRegion(env,ret,0,ulSignatureLen,(jbyte*)pSignature);

  return ret;
}
/*
 * Class:     org_opensc_pkcs11_wrap_PKCS11Slot
 * Method:    getMechanismsNative
 * Signature: (JJ)[Lorg/opensc/pkcs11/wrap/PKCS11Mechanism;
 */
jobjectArray JNICALL JNIX_FUNC_NAME(Java_org_opensc_pkcs11_wrap_PKCS11Slot_getMechanismsNative)
  (JNIEnv *env, jobject jslot, jlong mh, jlong handle)
{
  int rv;
  CK_ULONG n_mechanisms = 0;
  CK_MECHANISM_TYPE_PTR mechanisms;
  pkcs11_slot_t *slot;

  pkcs11_module_t *mod =  pkcs11_module_from_jhandle(env,mh);
  if (!mod) return 0;

  slot = pkcs11_slot_from_jhandle(env,handle);
  if (!slot) return 0;

  rv = mod->method->C_GetMechanismList(slot->id,NULL,&n_mechanisms);

  if (rv != CKR_OK)
    {
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",rv,
                          "C_GetMechanismList for PKCS11 slot %d failed.",
                          (int)slot->id);
      return 0;
    }

  mechanisms =
    (CK_MECHANISM_TYPE_PTR)alloca(n_mechanisms*sizeof(CK_MECHANISM_TYPE));

  rv = mod->method->C_GetMechanismList(slot->id,mechanisms,&n_mechanisms);

  if (rv != CKR_OK)
    {
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",rv,
                          "C_GetMechanismList for PKCS11 slot %d failed.",
                          (int)slot->id);
      return 0;
    }

  return pkcs11_slot_make_jmechanisms(env,mod,slot,mechanisms,n_mechanisms);
}
/*
 * Class:     org_opensc_pkcs11_wrap_PKCS11Object
 * Method:    getULongAttributeNative
 * Signature: (JJJJI)I
 */
jint JNICALL JNIX_FUNC_NAME(Java_org_opensc_pkcs11_wrap_PKCS11Object_getULongAttributeNative)
  (JNIEnv *env, jclass jp11obj, jlong mh, jlong shandle, jlong hsession, jlong ohandle, jint att)
{
  int rv;
  CK_ATTRIBUTE templ;
  /* default return value */
  CK_ULONG ret=~((CK_ULONG)0);
  pkcs11_slot_t *slot;

  pkcs11_module_t *mod =  pkcs11_module_from_jhandle(env,mh);
  if (!mod) return 0;

  slot = pkcs11_slot_from_jhandle(env,shandle);
  if (!slot) return 0;

  templ.type = att;
  templ.pValue = &ret;
  templ.ulValueLen = sizeof(CK_ULONG);
      
  rv = mod->method->C_GetAttributeValue(hsession,ohandle,&templ,1);
  
  if (rv  != CKR_OK)
    {
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",rv,
                          "C_GetAttributeValue failed for attribute %u.",
                          (unsigned)att);
      return 0;
    }

  if (templ.ulValueLen != sizeof(CK_ULONG))
    {
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",CKR_FUNCTION_FAILED,
                          "C_GetAttributeValue returned ulValueLen==%lu, which is not equal to sizeof(CK_ULONG) for attribute %u of type CK_ULONG but returned CKR_OK. The underlying PKCS#11 module seems to be broken.",
                          (unsigned long)templ.ulValueLen,(unsigned)att);
      return 0;
    }

  return ret;
}
Пример #6
0
jobjectArray pkcs11_slot_make_jmechanisms(JNIEnv *env, pkcs11_module_t *mod, pkcs11_slot_t *slot,
                                          CK_MECHANISM_TYPE_PTR mechanisms, CK_ULONG n_mechanisms)
{
  CK_ULONG i;
  jclass clazz;
  jmethodID ctorID;
  jobjectArray ret;
  int rv;

  clazz = (*env)->FindClass(env,"org/opensc/pkcs11/wrap/PKCS11Mechanism");

  if (!clazz) return 0;

  ctorID = (*env)->GetMethodID(env,clazz,"<init>","(IIII)V");

  if (!ctorID) return 0;

  ret = (*env)->NewObjectArray(env,n_mechanisms,clazz,NULL /* initialElement */);

  if (!ret) return 0;

  for (i=0;i<n_mechanisms;++i)
    {
      jobject m;
      CK_MECHANISM_INFO mechanismInfo;

      rv = mod->method->C_GetMechanismInfo(slot->id,mechanisms[i], &mechanismInfo);

      if (rv  != CKR_OK)
        {
          jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",rv,
                              "C_GetMechanismInfo failed for mechanism %u.",
                              (unsigned)mechanisms[i]);
          return 0;
        }

      m = (*env)->NewObject(env,clazz,ctorID,
                            (jint)mechanisms[i],
                            (jint)mechanismInfo.ulMinKeySize,
                            (jint)mechanismInfo.ulMaxKeySize,
                            (jint)mechanismInfo.flags  );

      if (!m) return 0;

      (*env)->SetObjectArrayElement(env,ret,i,m);
    }

  return ret;
}
/*
 * Class:     org_opensc_pkcs11_wrap_PKCS11Session
 * Method:    verifyUpdateNative
 * Signature: (JJJ[BII)V
 */
JNIEXPORT void JNICALL JNIX_FUNC_NAME(Java_org_opensc_pkcs11_wrap_PKCS11Session_verifyUpdateNative)
  (JNIEnv *env, jclass cls, jlong mh, jlong shandle, jlong hsession, jbyteArray data, jint off, jint len)
{
  int rv;
  CK_BYTE_PTR pPart;
  pkcs11_slot_t *slot;
  pkcs11_module_t *mod =  pkcs11_module_from_jhandle(env,mh);
  if (!mod) return;

  slot = pkcs11_slot_from_jhandle(env,shandle);
  if (!slot) return;

  if (len < 0)
    {
      jnixThrowException(env,"org/opensc/pkcs11/wrap/PKCS11Exception",
                         "Invalid data length %d.",(int)len);
      return;
    }

  if (data == NULL)
    {
      jnixThrowException(env,"org/opensc/pkcs11/wrap/PKCS11Exception",
                         "NULL input data.");
      return;
    }

  if (off < 0 || off > len)
    {
      jnixThrowException(env,"org/opensc/pkcs11/wrap/PKCS11Exception",
                         "Invalid input offset %d.",(int)off);
      return;
    }


  allocaCArrayFromJByteArrayOffLen(pPart,env,data,off,len);

  rv = mod->method->C_VerifyUpdate(hsession,pPart,len);

  if (rv  != CKR_OK)
    {
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",rv,
                          "C_VerifyUpdate failed for slot %d.",
                          (int)slot->id);
      return;
    }
}
/*
 * Class:     org_opensc_pkcs11_wrap_PKCS11Slot
 * Method:    hasTokenProtectedAuthPathNative
 * Signature: (JJ)Z
 */
jboolean JNICALL JNIX_FUNC_NAME(Java_org_opensc_pkcs11_wrap_PKCS11Slot_hasTokenProtectedAuthPathNative)
  (JNIEnv *env, jobject jslot, jlong mh, jlong handle)
{
  pkcs11_slot_t *slot;
  pkcs11_module_t *mod =  pkcs11_module_from_jhandle(env,mh);
  if (!mod) return JNI_FALSE;

  slot = pkcs11_slot_from_jhandle(env,handle);
  if (!slot) return JNI_FALSE;

  if ((slot->ck_slot_info.flags & CKF_TOKEN_PRESENT) == 0)
    jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",CKR_TOKEN_NOT_PRESENT,
                        "No token present in slot %d.",
                        (int)slot->id);

  return (slot->ck_token_info.flags & CKF_PROTECTED_AUTHENTICATION_PATH) != 0;
}
/*
 * Class:     org_opensc_pkcs11_wrap_PKCS11Slot
 * Method:    waitForSlotNative
 * Signature: (J)J
 */
JNIEXPORT jlong JNICALL JNIX_FUNC_NAME(Java_org_opensc_pkcs11_wrap_PKCS11Slot_waitForSlotNative)
  (JNIEnv *env, jclass jslot, jlong mh)
{
  CK_ULONG slotId;
  int rv;

  pkcs11_module_t *mod =  pkcs11_module_from_jhandle(env,mh);
  if (!mod) return 0;

  /* wait in blocking mode. */
  rv = mod->method->C_WaitForSlotEvent(0,&slotId,NULL);

  if (rv != CKR_OK)
    {
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",rv,
                          "C_WaitForSlotEvent failed.");
      return 0;
    }

  return slotId;
}
/*
 * Class:     org_opensc_pkcs11_wrap_PKCS11Session
 * Method:    verifyUpdateByteNative
 * Signature: (JJJB)V
 */
JNIEXPORT void JNICALL JNIX_FUNC_NAME(Java_org_opensc_pkcs11_wrap_PKCS11Session_verifyUpdateByteNative)
  (JNIEnv *env, jclass cls, jlong mh, jlong shandle, jlong hsession, jbyte b)
{ 
  int rv;
  CK_BYTE bb = (CK_BYTE)b;
  pkcs11_slot_t *slot;
  pkcs11_module_t *mod =  pkcs11_module_from_jhandle(env,mh);
  if (!mod) return;

  slot = pkcs11_slot_from_jhandle(env,shandle);
  if (!slot) return;

  rv = mod->method->C_VerifyUpdate(hsession,&bb,1);

  if (rv  != CKR_OK)
    {
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",rv,
                          "C_VerifyUpdate failed for slot %d.",
                          (int)slot->id);
      return;
    }
}
/*
 * Class:     org_opensc_pkcs11_wrap_PKCS11Session
 * Method:    verifyFinalNative
 * Signature: (JJJ[B)Z
 */
JNIEXPORT jboolean JNICALL JNIX_FUNC_NAME(Java_org_opensc_pkcs11_wrap_PKCS11Session_verifyFinalNative)
  (JNIEnv *env, jclass cls, jlong mh, jlong shandle, jlong hsession, jbyteArray data)
{
  int rv;
  CK_BYTE_PTR pSignature;
  CK_ULONG    ulSignatureLen;
  pkcs11_slot_t *slot;
  pkcs11_module_t *mod =  pkcs11_module_from_jhandle(env,mh);
  if (!mod) return JNI_FALSE;

  slot = pkcs11_slot_from_jhandle(env,shandle);
  if (!slot) return JNI_FALSE;

  if (data == NULL)
    {
      jnixThrowException(env,"org/opensc/pkcs11/wrap/PKCS11Exception",
                         "NULL input data.");
      return JNI_FALSE;
    }

  allocaCArrayFromJByteArray(pSignature,ulSignatureLen,env,data);

  rv = mod->method->C_VerifyFinal(hsession,pSignature,ulSignatureLen);

  switch (rv)
    {
    case CKR_SIGNATURE_INVALID:
      return JNI_FALSE;

    case CKR_OK:
      return JNI_TRUE;

    default:
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",rv,
                          "C_VerifyFinal failed for slot %d.",
                          (int)slot->id);
      return JNI_FALSE;
    }
}
/*
 * Class:     org_opensc_pkcs11_wrap_PKCS11Slot
 * Method:    getTokenMaxPinLenNative
 * Signature: (JJ)I
 */
jint JNICALL JNIX_FUNC_NAME(Java_org_opensc_pkcs11_wrap_PKCS11Slot_getTokenMaxPinLenNative)
  (JNIEnv *env, jobject jslot, jlong mh, jlong handle)
{
  pkcs11_slot_t *slot;
  pkcs11_module_t *mod =  pkcs11_module_from_jhandle(env,mh);
  if (!mod) return JNI_FALSE;

  slot = pkcs11_slot_from_jhandle(env,handle);
  if (!slot) return JNI_FALSE;

  if ((slot->ck_slot_info.flags & CKF_TOKEN_PRESENT) == 0)
    jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",CKR_TOKEN_NOT_PRESENT,
                        "No token present in slot %d.",
                        (int)slot->id);

  if (slot->ck_token_info.ulMaxPinLen > 0x7fffffff ||
      slot->ck_token_info.ulMinPinLen > slot->ck_token_info.ulMaxPinLen )
    jnixThrowException(env,"org/opensc/pkcs11/wrap/PKCS11Exception",
                       "Invalid value %u for ulMaxPinLen of token in slot %d.",
                       (unsigned)slot->ck_token_info.ulMaxPinLen,(int)slot->id);

  return slot->ck_token_info.ulMaxPinLen;
}
/*
 * Class:     org_opensc_pkcs11_wrap_PKCS11Object
 * Method:    deleteObjectNative
 * Signature: (JJJJ)V
 */
JNIEXPORT void JNICALL JNIX_FUNC_NAME(Java_org_opensc_pkcs11_wrap_PKCS11Object_deleteObjectNative)
  (JNIEnv *env, jclass jp11obj, jlong mh, jlong shandle, jlong hsession, jlong ohandle)
{
  int rv;
  CK_ATTRIBUTE templ;
  CK_MECHANISM_TYPE_PTR mechanisms;
  CK_ULONG n_mechanisms;
  pkcs11_slot_t *slot;

  pkcs11_module_t *mod =  pkcs11_module_from_jhandle(env,mh);
  if (!mod) return;

  slot = pkcs11_slot_from_jhandle(env,shandle);
  if (!slot) return;

  rv = mod->method->C_DestroyObject(hsession,ohandle);
  
  if (rv  != CKR_OK)
    {
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",rv,
                          "C_DestroyObject failed.");
      return;
    }
}
Пример #14
0
pkcs11_slot_t *new_pkcs11_slot(JNIEnv *env,  pkcs11_module_t *mod, CK_SLOT_ID id)
{
  int rv;
  pkcs11_slot_t *slot = (pkcs11_slot_t *) malloc(sizeof(pkcs11_slot_t));

  if (!slot)
    {
      jnixThrowException(env,"org/opensc/pkcs11/wrap/PKCS11Exception",
                         "Out of memory allocating PKCS11 slot.");
      return 0;
    }

  memset(slot, 0, sizeof(pkcs11_slot_t));

  slot->_magic = PKCS11_SLOT_MAGIC;
  slot->id = id;

  rv = mod->method->C_GetSlotInfo(id,&slot->ck_slot_info);
  if (rv != CKR_OK)
    {
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",rv,
                          "C_GetSlotInfo for PKCS11 slot %d failed.",(int)id);
      goto failed;
    }

#ifdef DEBUG_PKCS11_SLOT
  fprintf(stderr,"Loaded slot: %d.\n",(int)id);
  fprintf(stderr,"handle= %p.\n",slot);
  fprintf(stderr,"description= %.64s.\n",slot->ck_slot_info.slotDescription);
  fprintf(stderr,"manufacturer= %.32s.\n",slot->ck_slot_info.manufacturerID);
  fprintf(stderr,"flags= %x.\n",(unsigned)slot->ck_slot_info.flags);
  fprintf(stderr,"hardwareVersion= %d.%d.\n",
          (int)slot->ck_slot_info.hardwareVersion.major,
          (int)slot->ck_slot_info.hardwareVersion.minor );
  fprintf(stderr,"firmwareVersion= %d.%d.\n",
          (int)slot->ck_slot_info.firmwareVersion.major,
          (int)slot->ck_slot_info.firmwareVersion.minor );
#endif

  if (slot->ck_slot_info.flags & CKF_TOKEN_PRESENT)
    {
      rv = mod->method->C_GetTokenInfo(id,&slot->ck_token_info);
      if (rv != CKR_OK)
        {
          jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",rv,
                              "C_GetTokenInfo for PKCS11 slot %d failed.",(int)id);
          goto failed;
        }

#ifdef DEBUG_PKCS11_SLOT
      fprintf(stderr,"token.label= %.32s.\n",slot->ck_token_info.label);
      fprintf(stderr,"token.manufacturer= %.32s.\n",slot->ck_token_info.manufacturerID);
      fprintf(stderr,"token.model= %.16s.\n",slot->ck_token_info.model);
      fprintf(stderr,"token.serialNumber= %.16s.\n",slot->ck_token_info.serialNumber);
      fprintf(stderr,"token.flags= %x.\n",(unsigned)slot->ck_token_info.flags);
      fprintf(stderr,"token.ulMaxSessionCount= %u.\n",
              (unsigned)slot->ck_token_info.ulMaxSessionCount);
      fprintf(stderr,"token.ulMaxPinLen= %u.\n",
              (unsigned)slot->ck_token_info.ulMaxPinLen);
      fprintf(stderr,"token.ulMinPinLen= %u.\n",
              (unsigned)slot->ck_token_info.ulMinPinLen);
#endif
    }
    
  return slot;

failed:
  free(slot);
  return 0;
}
/*
 * Class:     org_opensc_pkcs11_wrap_PKCS11Session
 * Method:    signNative
 * Signature: (JJJ[BII)[B
 */
JNIEXPORT jbyteArray JNICALL JNIX_FUNC_NAME(Java_org_opensc_pkcs11_wrap_PKCS11Session_signNative)
  (JNIEnv *env, jclass cls, jlong mh, jlong shandle, jlong hsession, jbyteArray ba, jint off, jint len)
{
  int rv;
  CK_BYTE_PTR pMessage = NULL;
  CK_BYTE_PTR pSignature = NULL;
  CK_ULONG    ulSignatureLen = 0;
  jbyteArray ret;
  pkcs11_slot_t *slot;
  pkcs11_module_t *mod =  pkcs11_module_from_jhandle(env,mh);
  if (!mod) return 0;

  slot = pkcs11_slot_from_jhandle(env,shandle);
  if (!slot) return 0;

  if (len < 0)
    {
      jnixThrowException(env,"org/opensc/pkcs11/wrap/PKCS11Exception",
                         "Invalid data length %d.",(int)len);
      return NULL;
    }

  if (ba == NULL)
    {
      jnixThrowException(env,"org/opensc/pkcs11/wrap/PKCS11Exception",
                         "NULL input data.");
      return NULL;
    }

  if (off < 0)
    {
      jnixThrowException(env,"org/opensc/pkcs11/wrap/PKCS11Exception",
                         "Invalid input offset %d.",(int)off);
      return NULL;
    }

  allocaCArrayFromJByteArrayOffLen(pMessage,env,ba,off,len);

  rv = mod->method->C_Sign(hsession,pMessage,len,pSignature,&ulSignatureLen);

  if (rv  != CKR_OK)
    {
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",rv,
                          "C_Sign failed for slot %d.",
                          (int)slot->id);
      return NULL;
    }

  pSignature = (CK_BYTE_PTR)alloca(ulSignatureLen);

  rv = mod->method->C_Sign(hsession,pMessage,len,pSignature,&ulSignatureLen);

  if (rv  != CKR_OK)
    {
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",rv,
                          "C_SignFinal failed for slot %d.",
                          (int)slot->id);
      return NULL;
    }

  ret = (*env)->NewByteArray(env,ulSignatureLen);
  if (ret)
    (*env)->SetByteArrayRegion(env,ret,0,ulSignatureLen,(jbyte*)pSignature);

  return ret;
}
/*
 * Class:     org_opensc_pkcs11_wrap_PKCS11Object
 * Method:    enumObjectsNative
 * Signature: (JJJ[Lorg/opensc/pkcs11/wrap/PKCS11Attribute;)[J
 */
JNIEXPORT jlongArray JNICALL JNIX_FUNC_NAME(Java_org_opensc_pkcs11_wrap_PKCS11Object_enumObjectsNative)
  (JNIEnv *env, jclass jp11obj, jlong mh, jlong shandle, jlong hsession, jobjectArray attrs)
{
  jclass clazz;
  jmethodID getKindID,getDataID;
  CK_ULONG ulAttributeCount;
  CK_ATTRIBUTE_PTR pAttributes;
  CK_ULONG i,count;
  int nobjs,rv;
  CK_ULONG obj_ids[ENUM_HANDLES_BLOCK_SZ];
  size_t ret_obj_ids_sz;
  jlong *ret_obj_ids;
  jlongArray ret;
  pkcs11_slot_t *slot;

  pkcs11_module_t *mod =  pkcs11_module_from_jhandle(env,mh);
  if (!mod) return 0;

  slot = pkcs11_slot_from_jhandle(env,shandle);
  if (!slot) return 0;

  clazz = (*env)->FindClass(env,"org/opensc/pkcs11/wrap/PKCS11Attribute");

  if (!clazz) return 0;

  getKindID = (*env)->GetMethodID(env,clazz,"getKind","()I");

  if (!getKindID) return 0;

  getDataID = (*env)->GetMethodID(env,clazz,"getData","()[B");

  if (!getDataID) return 0;

  ulAttributeCount = (*env)->GetArrayLength(env,attrs);
  pAttributes = alloca(ulAttributeCount * sizeof(CK_ATTRIBUTE));

  for (i=0;i<ulAttributeCount;++i)
    {
      jbyteArray data;
      jobject jattr = (*env)->GetObjectArrayElement(env,attrs,i);
      if (!jattr) return 0;

      pAttributes[i].type = (*env)->CallIntMethod(env,jattr,getKindID);

      data = (jbyteArray)(*env)->CallObjectMethod(env,jattr,getDataID);

      allocaCArrayFromJByteArray(pAttributes[i].pValue,pAttributes[i].ulValueLen,env,data);
    }

  ret_obj_ids_sz = ENUM_HANDLES_BLOCK_SZ;
  nobjs = 0;
  ret_obj_ids=(jlong*)malloc(ret_obj_ids_sz * sizeof(jlong));

  if (!ret_obj_ids)
    {
      jnixThrowException(env,"org/opensc/pkcs11/wrap/PKCS11Exception",
                         "Out of memory during object enumeration for slot number %d.",
                         (int)slot->id);
      goto failed;
    }

  rv = mod->method->C_FindObjectsInit(hsession,pAttributes,ulAttributeCount);

  if (rv  != CKR_OK)
    {
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",rv,
                          "C_FindObjectsInit failed for slot number %d.",
                          (int)slot->id);
      goto failed;
    }

  count = 0;

  rv = mod->method->C_FindObjects(hsession,obj_ids, ENUM_HANDLES_BLOCK_SZ, &count);

  if (rv  != CKR_OK)
    {
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",rv,
                          "C_FindObjects failed for slot number %d.",
                          (int)slot->id);
      goto failed;
    }

  for (i=0; i<count ;++i)
    {
      jlong id = (jlong)obj_ids[i];
      ret_obj_ids[nobjs] = id;
      ++nobjs;
    }

  while (count == ENUM_HANDLES_BLOCK_SZ)
    {
      jlong *new_obj_ids;
      ret_obj_ids_sz += ENUM_HANDLES_BLOCK_SZ;

      new_obj_ids=(jlong*)realloc(ret_obj_ids,ret_obj_ids_sz * sizeof(jlong));
     
      if (!new_obj_ids)
        {
          jnixThrowException(env,"org/opensc/pkcs11/wrap/PKCS11Exception",
                             "Out of memory during object enumeration for slot number %d.",
                             (int)slot->id);
          goto failed;
        }

      ret_obj_ids=new_obj_ids;

      rv = mod->method->C_FindObjects(hsession,obj_ids,ENUM_HANDLES_BLOCK_SZ, &count);
      
      if (rv  != CKR_OK)
        {
          jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",rv,
                              "C_FindObjects failed for slot number %d.",
                              (int)slot->id);
          goto failed;
        }

      for (i=0; i<count ;++i)
        {
          jlong id = (jlong)obj_ids[i];
          ret_obj_ids[nobjs] = id;
          ++nobjs;
        }
    }

  rv = mod->method->C_FindObjectsFinal(hsession);
  if (rv  != CKR_OK)
    {
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",rv,
                          "C_FindObjectsFinal failed for slot number %d.",
                          (int)slot->id);
      goto failed;
    }

  /* OK, akc it into JAVA's realm. */
  ret = (*env)->NewLongArray(env,nobjs);
  (*env)->SetLongArrayRegion(env,ret,0,nobjs,ret_obj_ids);

  free(ret_obj_ids);
  return ret;

 failed:
  free(ret_obj_ids);
  return 0;
}
/*
 * Class:     org_opensc_pkcs11_spi_PKCS11CipherSpi
 * Method:    doFinalEncryptNativeOff
 * Signature: (JJJJ[BII[BI)I
 */
JNIEXPORT jint JNICALL JNIX_FUNC_NAME(Java_org_opensc_pkcs11_spi_PKCS11CipherSpi_doFinalEncryptNativeOff)
  (JNIEnv *env, jobject jciph, jlong mh, jlong shandle, jlong hsession, jlong hkey, jbyteArray input, jint off, jint len, jbyteArray output, jint output_off)
{
  int rv;
  CK_BYTE_PTR pOutputPart;
  CK_ULONG ulOutputLen,ulOutputLen0,ulOutputLen1;
  CK_BYTE_PTR pInputPart;
  pkcs11_slot_t *slot;
  pkcs11_module_t *mod =  pkcs11_module_from_jhandle(env,mh);

  if (!mod) return 0;

  slot = pkcs11_slot_from_jhandle(env,shandle);
  if (!slot) return 0;

  if (len < 0)
    {
      jnixThrowException(env,"org/opensc/pkcs11/wrap/PKCS11Exception",
                         "Invalid data length %d.",(int)len);
      return 0;
    }

  if (input == NULL)
    {
      jnixThrowException(env,"org/opensc/pkcs11/wrap/PKCS11Exception",
                         "NULL input data.");
      return 0;
    }

  if (off < 0 || off > len)
    {
      jnixThrowException(env,"org/opensc/pkcs11/wrap/PKCS11Exception",
                         "Invalid input offset %d.",(int)off);
      return 0;
    }

  ulOutputLen = (*env)->GetArrayLength(env,output);
  
  if (output_off < 0 || output_off > ulOutputLen)
    {
      jnixThrowException(env,"org/opensc/pkcs11/wrap/PKCS11Exception",
                         "Invalid output offset %d.",(int)output_off);
      return 0;
    }
 
  ulOutputLen -= output_off;
  pOutputPart = alloca(ulOutputLen);
  ulOutputLen0 = ulOutputLen;

  allocaCArrayFromJByteArrayOffLen(pInputPart,env,input,off,len);

  rv = mod->method->C_EncryptUpdate(hsession,pInputPart,len,pOutputPart,&ulOutputLen0);

  if (rv  != CKR_OK)
    {
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",rv,
                          "C_EncryptUpdate failed for slot %d.",
                          (int)slot->id);
      return 0;
    }

  ulOutputLen1 = ulOutputLen - ulOutputLen0;

  rv = mod->method->C_EncryptFinal(hsession,pOutputPart+ulOutputLen0,&ulOutputLen1);

  if (rv  != CKR_OK)
    {
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",rv,
                          "C_EncryptFinal failed for slot %d.",
                          (int)slot->id);
      return 0;
    }

  ulOutputLen = ulOutputLen0+ulOutputLen1;

  (*env)->SetByteArrayRegion(env,output,output_off,ulOutputLen,(jbyte*)pOutputPart);
  
  return ulOutputLen;
}
/*
 * Class:     org_opensc_pkcs11_wrap_PKCS11Object
 * Method:    getAttributeNative
 * Signature: (JJJI)[B
 */
JNIEXPORT jbyteArray JNICALL JNIX_FUNC_NAME(Java_org_opensc_pkcs11_wrap_PKCS11Object_getAttributeNative)
  (JNIEnv *env, jclass jp11obj, jlong mh, jlong shandle, jlong hsession, jlong ohandle, jint att)
{
  int rv;
  CK_ATTRIBUTE templ;
  jbyteArray ret;
  pkcs11_slot_t *slot;

  pkcs11_module_t *mod =  pkcs11_module_from_jhandle(env,mh);
  if (!mod) return 0;

  slot = pkcs11_slot_from_jhandle(env,shandle);
  if (!slot) return 0;

  templ.type = att;
  templ.pValue = NULL;
  templ.ulValueLen = 0;
      
  rv = mod->method->C_GetAttributeValue(hsession,ohandle,&templ,1);
  
  if (rv  != CKR_OK)
    {
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",rv,
                          "C_GetAttributeValue failed for attribute %u.",
                          (unsigned)att);
      return 0;
    }

  if (templ.ulValueLen == ~((CK_ULONG)0))
    {
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",CKR_FUNCTION_FAILED,
                          "C_GetAttributeValue returned ulValueLen -1 for attribute %u but returned CKR_OK. The underlying PKCS#11 module seems to be broken.",
                          (unsigned)att);
      return 0;
    }

  templ.pValue = alloca(templ.ulValueLen);

  rv = mod->method->C_GetAttributeValue(hsession,ohandle,&templ,1);
  
  if (rv  != CKR_OK)
    {
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",rv,
                          "C_GetAttributeValue failed for attribute %u.",
                          (unsigned)att);
      return 0;
    }
  
  if (templ.ulValueLen == ~((CK_ULONG)0))
    {
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",CKR_FUNCTION_FAILED,
                          "C_GetAttributeValue returned ulValueLen -1 for attribute %u but returned CKR_OK. The underlying PKCS#11 module seems to be broken.",
                          (unsigned)att);
      return 0;
    }

  ret = (*env)->NewByteArray(env,templ.ulValueLen);
  (*env)->SetByteArrayRegion(env,ret,0,templ.ulValueLen,(jbyte*)templ.pValue);
  
  return ret;
}
/*
 * Class:     org_opensc_pkcs11_spi_PKCS11CipherSpi
 * Method:    updateDecryptNative
 * Signature: (JJJJ[BII)[B
 */
JNIEXPORT jbyteArray JNICALL JNIX_FUNC_NAME(Java_org_opensc_pkcs11_spi_PKCS11CipherSpi_updateDecryptNative)
  (JNIEnv *env, jobject jciph, jlong mh, jlong shandle, jlong hsession, jlong hkey, jbyteArray input, jint off, jint len)
{
  int rv;
  CK_BYTE_PTR pInputPart;
  CK_BYTE_PTR pOutputPart = 0;
  CK_ULONG ulOutputLen = 0;
  jbyteArray ret;
  pkcs11_slot_t *slot;

  pkcs11_module_t *mod =  pkcs11_module_from_jhandle(env,mh);
  if (!mod) return 0;

  slot = pkcs11_slot_from_jhandle(env,shandle);
  if (!slot) return 0;

  if (len < 0)
    {
      jnixThrowException(env,"org/opensc/pkcs11/wrap/PKCS11Exception",
                         "Invalid data length %d.",(int)len);
      return 0;
    }

  if (input == NULL)
    {
      jnixThrowException(env,"org/opensc/pkcs11/wrap/PKCS11Exception",
                         "NULL input data.");
      return 0;
    }

  if (off < 0 || off > len)
    {
      jnixThrowException(env,"org/opensc/pkcs11/wrap/PKCS11Exception",
                         "Invalid input offset %d.",(int)off);
      return 0;
    }

  allocaCArrayFromJByteArrayOffLen(pInputPart,env,input,off,len);

  rv = mod->method->C_DecryptUpdate(hsession,pInputPart,len,pOutputPart,&ulOutputLen);

  if (rv  != CKR_OK)
    {
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",rv,
                          "C_DecryptUpdate failed for slot %d.",
                          (int)slot->id);
      return 0;
    }

  pOutputPart=alloca(ulOutputLen);

  rv = mod->method->C_DecryptUpdate(hsession,pInputPart,len,pOutputPart,&ulOutputLen);

  if (rv  != CKR_OK)
    {
      jnixThrowExceptionI(env,"org/opensc/pkcs11/wrap/PKCS11Exception",rv,
                          "C_DecryptUpdate failed for slot %d.",
                          (int)slot->id);
      return 0;
    }

  ret = (*env)->NewByteArray(env,ulOutputLen);
  if (ret)
    (*env)->SetByteArrayRegion(env,ret,0,ulOutputLen,(jbyte*)pOutputPart);
  
  return ret;
}