在 JNA [PKCS11] 中创建对象 C_CreateObject 时发生奇怪的事情
Strange things happens when creating object C_CreateObject in JNA [PKCS11]
我正在制作 JNA PKCS11 包装器,在令牌中创建对象时发生了一件奇怪的事情(使用 CKO_DATA 和 CKO_CERTIFICATE 进行了测试)。大部分时间结果都是CKR_TEMPLATE_INCONSISTENT,多试几次就可以创建对象了。也许你知道会发生什么。
JNA接口和结构,
NativeLong C_CreateObject(final NativeLong hSession, final CK_ATTRIBUTE[] pTemplate, final NativeLong ulCount, final IntByReference phObject);
public class CK_ATTRIBUTE extends Structure {
public NativeLong type;
public Pointer pValue;
public NativeLong ulValueLen;
public static class ByReference extends CK_ATTRIBUTE implements Structure.ByReference {
}
public static class ByValue extends CK_ATTRIBUTE implements Structure.ByValue {
}
public CK_ATTRIBUTE() {
setAlignType(ALIGN_NONE);
}
@Override
protected List<String> getFieldOrder() {
return Arrays.asList(new String[] { "type", "pValue", "ulValueLen" });
}
}
包装器,
public class Attribute {
private final CKA cka;
private final byte[] data;
public Attribute(final CKA cka, final byte[] data) {
this.cka = cka;
this.data = data.clone();
}
public CKA getCKA() {
return cka;
}
public byte[] getData() {
return data;
}
}
public static CK_ATTRIBUTE[] createNativeAttributes(final List<Attribute> attributes) {
final CK_ATTRIBUTE[] nativeAttributes = (CK_ATTRIBUTE[]) new CK_ATTRIBUTE().toArray(attributes.size());
for (int i = 0; i < attributes.size(); i++) {
final Attribute attribute = attributes.get(i);
nativeAttributes[i].type = attribute.getCKA().getValue();
final int len = attribute.getData().length;
final Pointer pointer = new Memory(len);
nativeAttributes[i].pValue = pointer;
pointer.write(0, attribute.getData(), 0, len);
nativeAttributes[i].ulValueLen = new NativeLong(len);
}
return nativeAttributes;
}
public NativeLong createObject(final NativeLong hSession, final CK_ATRIBUTE[] pTemplate) throws CryptokiException {
if (hSession == null) {
throw new IllegalArgumentException("hSession cannot be null");
}
if (pTemplate == null || pTemplate.length == 0) {
throw new IllegalArgumentException("pTemplate cannot be empty");
}
final IntByReference phObject = new IntByReference(0);
generateException(cryptoki.C_CreateObject(hSession, pTemplate, new NativeLong(pTemplate.length), phObject));
return new NativeLong(phObject.getValue());
}
测试片段,
// create CKO_DATA
final List<Attribute> attributes = new ArrayList<>();
attributes.add(new Attribute(CKA.CLASS, new byte[] { CKO.DATA.getValue().byteValue() }));
attributes.add(new Attribute(CKA.TOKEN, new byte[] { Cryptoki.CK_TRUE }));
attributes.add(new Attribute(CKA.APPLICATION, "My Application".getBytes()));
attributes.add(new Attribute(CKA.VALUE, new byte[] { 0x01, 0x02, 0x03, 0x04 }));
attributes.add(new Attribute(CKA.LABEL, "Test Label".getBytes()));
final CK_ATTRIBUTE[] pTemplate = CryptokiWrapper.createNativeAttributes(attributes);
final NativeLong hObject = wrapper.createObject(hSessionRW, pTemplate);
// create CKO_CERTIFICATE
final CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
try (final InputStream inputStream = new FileInputStream("src/main/resources/test.cer")) {
final X509Certificate x509Certificate = (X509Certificate) certificateFactory.generateCertificate(inputStream);
final List<Attribute> attributes = new ArrayList<>();
attributes.add(new Attribute(CKA.CLASS, new byte[] { CKO.CERTIFICATE.getValue().byteValue() }));
attributes.add(new Attribute(CKA.CERTIFICATE_TYPE, new byte[] { CKC.X_509.getValue().byteValue() }));
attributes.add(new Attribute(CKA.TOKEN, new byte[] { Cryptoki.CK_TRUE }));
attributes.add(new Attribute(CKA.LABEL, "Test Cert".getBytes()));
attributes.add(new Attribute(CKA.SUBJECT, x509Certificate.getSubjectDN().getName().getBytes()));
attributes.add(new Attribute(CKA.ID, new byte[] { 0x01, 0x02 }));
attributes.add(new Attribute(CKA.VALUE, x509Certificate.getEncoded()));
final CK_ATTRIBUTE[] pTemplate = CryptokiWrapper.createNativeAttributes(attributes);
final NativeLong hObject = wrapper.createObject(hSessionRW, pTemplate);
}
如果运行应用程序处于调试模式并设置一些断点,成功的可能性会更高。
注意,所有代码运行在一个线程下。
终于找到问题的原因了,
attributes.add(new Attribute(CKA.CLASS, new byte[] { CKO.DATA.getValue().byteValue() }));
这一行是错误的,CKO_DATA的值为0x00000000,表示是32位整数,所以长度为4,值为字节数组;经过一些测试,该值是小端序列。
有时方法执行成功的原因是,有时内存中的序列是00 00 00 00,符合方法的要求,尤其是在调试模式下。
我正在制作 JNA PKCS11 包装器,在令牌中创建对象时发生了一件奇怪的事情(使用 CKO_DATA 和 CKO_CERTIFICATE 进行了测试)。大部分时间结果都是CKR_TEMPLATE_INCONSISTENT,多试几次就可以创建对象了。也许你知道会发生什么。
JNA接口和结构,
NativeLong C_CreateObject(final NativeLong hSession, final CK_ATTRIBUTE[] pTemplate, final NativeLong ulCount, final IntByReference phObject);
public class CK_ATTRIBUTE extends Structure {
public NativeLong type;
public Pointer pValue;
public NativeLong ulValueLen;
public static class ByReference extends CK_ATTRIBUTE implements Structure.ByReference {
}
public static class ByValue extends CK_ATTRIBUTE implements Structure.ByValue {
}
public CK_ATTRIBUTE() {
setAlignType(ALIGN_NONE);
}
@Override
protected List<String> getFieldOrder() {
return Arrays.asList(new String[] { "type", "pValue", "ulValueLen" });
}
}
包装器,
public class Attribute {
private final CKA cka;
private final byte[] data;
public Attribute(final CKA cka, final byte[] data) {
this.cka = cka;
this.data = data.clone();
}
public CKA getCKA() {
return cka;
}
public byte[] getData() {
return data;
}
}
public static CK_ATTRIBUTE[] createNativeAttributes(final List<Attribute> attributes) {
final CK_ATTRIBUTE[] nativeAttributes = (CK_ATTRIBUTE[]) new CK_ATTRIBUTE().toArray(attributes.size());
for (int i = 0; i < attributes.size(); i++) {
final Attribute attribute = attributes.get(i);
nativeAttributes[i].type = attribute.getCKA().getValue();
final int len = attribute.getData().length;
final Pointer pointer = new Memory(len);
nativeAttributes[i].pValue = pointer;
pointer.write(0, attribute.getData(), 0, len);
nativeAttributes[i].ulValueLen = new NativeLong(len);
}
return nativeAttributes;
}
public NativeLong createObject(final NativeLong hSession, final CK_ATRIBUTE[] pTemplate) throws CryptokiException {
if (hSession == null) {
throw new IllegalArgumentException("hSession cannot be null");
}
if (pTemplate == null || pTemplate.length == 0) {
throw new IllegalArgumentException("pTemplate cannot be empty");
}
final IntByReference phObject = new IntByReference(0);
generateException(cryptoki.C_CreateObject(hSession, pTemplate, new NativeLong(pTemplate.length), phObject));
return new NativeLong(phObject.getValue());
}
测试片段,
// create CKO_DATA
final List<Attribute> attributes = new ArrayList<>();
attributes.add(new Attribute(CKA.CLASS, new byte[] { CKO.DATA.getValue().byteValue() }));
attributes.add(new Attribute(CKA.TOKEN, new byte[] { Cryptoki.CK_TRUE }));
attributes.add(new Attribute(CKA.APPLICATION, "My Application".getBytes()));
attributes.add(new Attribute(CKA.VALUE, new byte[] { 0x01, 0x02, 0x03, 0x04 }));
attributes.add(new Attribute(CKA.LABEL, "Test Label".getBytes()));
final CK_ATTRIBUTE[] pTemplate = CryptokiWrapper.createNativeAttributes(attributes);
final NativeLong hObject = wrapper.createObject(hSessionRW, pTemplate);
// create CKO_CERTIFICATE
final CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
try (final InputStream inputStream = new FileInputStream("src/main/resources/test.cer")) {
final X509Certificate x509Certificate = (X509Certificate) certificateFactory.generateCertificate(inputStream);
final List<Attribute> attributes = new ArrayList<>();
attributes.add(new Attribute(CKA.CLASS, new byte[] { CKO.CERTIFICATE.getValue().byteValue() }));
attributes.add(new Attribute(CKA.CERTIFICATE_TYPE, new byte[] { CKC.X_509.getValue().byteValue() }));
attributes.add(new Attribute(CKA.TOKEN, new byte[] { Cryptoki.CK_TRUE }));
attributes.add(new Attribute(CKA.LABEL, "Test Cert".getBytes()));
attributes.add(new Attribute(CKA.SUBJECT, x509Certificate.getSubjectDN().getName().getBytes()));
attributes.add(new Attribute(CKA.ID, new byte[] { 0x01, 0x02 }));
attributes.add(new Attribute(CKA.VALUE, x509Certificate.getEncoded()));
final CK_ATTRIBUTE[] pTemplate = CryptokiWrapper.createNativeAttributes(attributes);
final NativeLong hObject = wrapper.createObject(hSessionRW, pTemplate);
}
如果运行应用程序处于调试模式并设置一些断点,成功的可能性会更高。
注意,所有代码运行在一个线程下。
终于找到问题的原因了,
attributes.add(new Attribute(CKA.CLASS, new byte[] { CKO.DATA.getValue().byteValue() }));
这一行是错误的,CKO_DATA的值为0x00000000,表示是32位整数,所以长度为4,值为字节数组;经过一些测试,该值是小端序列。
有时方法执行成功的原因是,有时内存中的序列是00 00 00 00,符合方法的要求,尤其是在调试模式下。