Search code examples
javajnapkcs#11softhsm

How to extract objects from SoftHSM with a JNA interface?


I am using SoftHSM and I have to develop a Java application to extract objects of it.

I have a "Data" object of label "MY_DATA" and I have successfully opened the session on the right token.

But even if there is no error returned code, I cannot get anything: objectHandles is always empty (and ulObjectCount = 0).

Note that I get a list of handles when I use a null template. Thus, I think the issue is around the definition of the template (types used...) But what?

I am trying to get my Object with the following Java/JNA code (my JNA interface is called Pkcs11Library).

String dataLabel = "MY_DATA";
CK_ATTRIBUTE[] searchTemplate = (CK_ATTRIBUTE[]) new CK_ATTRIBUTE().toArray(2);

searchTemplate[0].type = new NativeLong(Pkcs11Library.CKA_LABEL); // long CKA_LABEL = 0x00000003 
byte[] labelBytes = dataLabel.getBytes();
searchTemplate[0].pValue = new Memory(labelBytes.length);
searchTemplate[0].pValue.write(0, labelBytes, 0, labelBytes.length);
searchTemplate[0].ulValueLen = new NativeLong(labelBytes.length);

searchTemplate[1].type = new NativeLong(Pkcs11Library.CKA_CLASS); // long CKA_CLASS = 0x00000000
searchTemplate[1].pValue = new Memory(NativeLong.SIZE);
searchTemplate[1].pValue.setNativeLong(0, new NativeLong(Pkcs11Library.CKO_DATA)); // long CKO_DATA = 0x00000000
searchTemplate[1].ulValueLen = new NativeLong(NativeLong.SIZE);

int rv  = Pkcs11Library.INSTANCE.C_FindObjectsInit(hSession, searchTemplate, searchTemplate.length);
if (rv != Pkcs11Library.CKR_OK) {
  //TODO
}

int[] objectHandles = new int[MAX_OBJECT_COUNT]; // MAX_OBJECT_COUNT = 10
NativeLongByReference pulObjectCount = new NativeLongByReference();
rv = Pkcs11Library.INSTANCE.C_FindObjects(hSession, objectHandles, objectHandles.length, pulObjectCount);
int ulObjectCount = pulObjectCount.getValue().intValue();

My JNA interface is defined as follows:

// CK_ATTRIBUTE
public class CK_ATTRIBUTE extends Structure {
  public NativeLong type;
  public Pointer pValue;
  public NativeLong ulValueLen;

  public CK_ATTRIBUTE() {
    super();
  }

  @Override
  protected List<String> getFieldOrder() {
    return Arrays.asList("type", "pValue", "ulValueLen");
  }
}

int C_FindObjectsInit(int hSession, CK_ATTRIBUTE[] searchTemplate, int length);

int C_FindObjects(int hSession, int[] phObject, int ulMaxObjectCount, NativeLongByReference pulObjectCount);

The native definitions are defined here:

struct ck_attribute
{
  ck_attribute_type_t type;
  void *value;
  unsigned long value_len;
};

CK_RV C_FindObjectsInit(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount);
CK_RV C_FindObjects(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject, CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount);

I am on Windows x64 with OpenJDK17 and I use the x64 dll of SoftHSMv2.


Solution

  • Your problem is likely Data Structure Alignment. Third party libraries often don't use any alignment of bytes in structures.

    Since your comments indicated you are on Windows, the various types that all map to unsigned long are 4 bytes each, so int is appropriate here. (I might suggest you be consistent in always using either int or NativeLong, it is confusing when you use both.)

    However, pointer size is 8 bytes, so your structure byte width looks like:

    public NativeLong type; // 4 bytes
    public Pointer pValue; // 8 bytes
    public NativeLong ulValueLen; // 4 bytes
    

    On Windows, JNA Structures use the default alignment to field width. After assigning the first 4 bytes for type, it must assign the 8-byte value for pValue, but that must be 8-byte aligned. The variable can't cross that byte boundary so therefore JNA is sending this structure:

    ffi_type_int32 type; // 4 bytes
    ffi_type_int32 padding; // 4 bytes of padding to align pValue on 8-byte boundary
    ffi_type_int64 pValue; // 8 bytes
    ffi_type_int32 ulValueLen; // 4 bytes
    

    To resolve this, use the setAlignType() method using ALIGN_NONE which doesn't use padding:

    @FieldOrder({ "type", "pValue", "ulValueLen" })
    public class CK_ATTRIBUTE extends Structure {
        public int type;
        public Pointer pValue;
        public int ulValueLen;
    
        public CK_ATTRIBUTE() {
            super();
            setAlignType(ALIGN_NONE);
        }
    }