1

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.

Daniel Widdis
  • 8,424
  • 13
  • 41
  • 63
  • What are the native headers of the structure and the function? My brief searching shows `hSession` data type is eventually `CK_ULONG` which may have platform dependent mapping. It's the same type as your `Type` field in your structure which you've mapped as `NativeLong`. One of those is wrong. – Daniel Widdis Jul 07 '23 at 06:42
  • 1
    the native headers of SoftHSM pkcs11 implementation is here: [link](https://github.com/opendnssec/SoftHSMv2/blob/develop/src/lib/pkcs11/pkcs11.h) I think the issue is not around hsession because the way I use it works fine with a null template (`Pkcs11Library.INSTANCE.C_FindObjectsInit(hSession, null, 0);` allows to fill the list of objectsHandlers) – tamar_a_roulettes Jul 07 '23 at 06:58
  • 1
    I am working on a Windows x64 with OpenJDK17 and I use the x64 dll of SoftHSMv2. I also tried to use simple 'int' type for the CK_ULONG fields, and also a byte[] for the pointer... nothing works – tamar_a_roulettes Jul 07 '23 at 07:08
  • the code of C_FindObjectsInit is here: [link](https://github.com/opendnssec/SoftHSMv2/blob/develop/src/lib/SoftHSM.cpp); I think it goes well up to line 2011. Then, I don't know... – tamar_a_roulettes Jul 07 '23 at 07:15
  • Then, if I try to go on with the list of objectHandlers and C_GetAttributeValue this way: ` CK_ATTRIBUTE[] template = (CK_ATTRIBUTE[]) new CK_ATTRIBUTE().toArray(1);

    template[0].type = Pkcs11Library.CKA_LABEL; // or whatever the attribute type...
    template[0].pValue = null;
    template[0].ulValueLen = 0;

    rv = Pkcs11Library.INSTANCE.C_GetAttributeValue(hSession, objectHandle, template, template.length);
    ` template[0].ulValueLen is always 0
    – tamar_a_roulettes Jul 07 '23 at 07:22

1 Answers1

0

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);
    }
}
Daniel Widdis
  • 8,424
  • 13
  • 41
  • 63