All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xipki.pkcs11.wrapper.Session Maven / Gradle / Ivy

There is a newer version: 1.0.9
Show newest version
// Copyright (c) 2002 Graz University of Technology. All rights reserved.
// License IAIK PKCS#11 Wrapper License.
//
// Copyright (c) 2022 xipki. All rights reserved.
// License Apache License 2.0

package org.xipki.pkcs11.wrapper;

import org.xipki.pkcs11.wrapper.attrs.*;
import org.xipki.pkcs11.wrapper.params.CkParamsWithExtra;
import org.xipki.pkcs11.wrapper.params.ExtraParams;
import sun.security.pkcs11.wrapper.CK_ATTRIBUTE;
import sun.security.pkcs11.wrapper.CK_MECHANISM;
import sun.security.pkcs11.wrapper.PKCS11;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.PublicKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECPoint;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import static org.xipki.pkcs11.wrapper.PKCS11Constants.*;

/**
 * Session objects are used to perform cryptographic operations on a token. The application gets a
 * Session object by calling openSession on a certain Token object. Having the session object, the
 * application may log-in the user, if required.
 *
 * 
 * 
 *   TokenInfo tokenInfo = token.getTokenInfo();
 *   // check, if log-in of the user is required at all
 *   if (tokenInfo.isLoginRequired()) {
 *     // check, if the token has own means to authenticate the user; e.g. a PIN-pad on the reader
 *     if (tokenInfo.isProtectedAuthenticationPath()) {
 *       System.out.println("Please enter the user PIN at the PIN-pad of your reader.");
 *       session.login(CKU_USER, null); // the token prompts the PIN by other means; e.g. PIN-pad
 *     } else {
 *       System.out.print("Enter user-PIN and press [return key]: ");
 *       System.out.flush();
 *       BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
 *       String userPINString = input.readLine();
 *       session.login(CKU_USER, userPINString.toCharArray());
 *     }
 *   }
 * 
 * 
* * If the application does not need the session any longer, it should close the * session. * *
 * 
 *   session.closeSession();
 * 
 * 
* * @author Karl Scheibelhofer (SIC) * @author Lijun Liao (xipki) */ public class Session { private static final int SIGN_TYPE_ECDSA = 1; private static final int SIGN_TYPE_SM2 = 2; private static final Method encrypt0; private static final Method encrypt1; private static final Method decrypt0; private static final Method decrypt1; /** * A reference to the underlying PKCS#11 module to perform the operations. */ private final PKCS11Module module; /** * A reference to the underlying PKCS#11 module to perform the operations. */ private final PKCS11 pkcs11; /** * The session handle to perform the operations with. */ private long sessionHandle; /** * The token to perform the operations on. */ private final Token token; private int signatureType; private long signOrVerifyKeyHandle; private ExtraParams signVerifyExtraParams; static { Class clazz = PKCS11.class; decrypt0 = Util.getMethod(clazz, "C_Decrypt", long.class, byte[].class, int.class, int.class, byte[].class, int.class, int.class); encrypt0 = Util.getMethod(clazz, "C_Encrypt", long.class, byte[].class, int.class, int.class, byte[].class, int.class, int.class); decrypt1 = decrypt0 != null ? null : Util.getMethod(clazz, "C_Decrypt", long.class, long.class, byte[].class, int.class, int.class, long.class, byte[].class, int.class, int.class); encrypt1 = encrypt0 != null ? null : Util.getMethod(clazz, "C_Encrypt", long.class, long.class, byte[].class, int.class, int.class, long.class, byte[].class, int.class, int.class); } /** * Constructor taking the token and the session handle. * * @param token The token this session operates with. * @param sessionHandle The session handle to perform the operations with. */ protected Session(Token token, long sessionHandle) { this.token = Functions.requireNonNull("token", token); this.module = token.getSlot().getModule(); this.pkcs11 = module.getPKCS11(); this.sessionHandle = sessionHandle; } /** * Closes this session. * * @throws PKCS11Exception If closing the session failed. */ public void closeSession() throws PKCS11Exception { final String method = "C_CloseSession"; try { debugIn(method); pkcs11.C_CloseSession(sessionHandle); debugOut(method); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } /** * Get the handle of this session. * * @return The handle of this session. */ public long getSessionHandle() { return sessionHandle; } /** * Get information about this session. * * @return An object providing information about this session. * @throws PKCS11Exception If getting the information failed. */ public SessionInfo getSessionInfo() throws PKCS11Exception { try { return new SessionInfo(pkcs11.C_GetSessionInfo(sessionHandle)); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { throw new PKCS11Exception(ex.getErrorCode()); } } /** * Get the Module which this Session object operates with. * * @return The module of this session. */ public PKCS11Module getModule() { return module; } /** * Get the token that created this Session object. * * @return The token of this session. */ public Token getToken() { return token; } /** * Get the current operation state. This state can be used later to restore the operation to * exactly this state. * * @return The current operation state as a byte array. * @throws PKCS11Exception If saving the state fails or is not possible. */ public byte[] getOperationState() throws PKCS11Exception { try { return pkcs11.C_GetOperationState(sessionHandle); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { throw new PKCS11Exception(ex.getErrorCode()); } } /** * Sets the operation state of this session to a previously saved one. This method may need the * key used during the saved operation to continue, because it may not be possible to save a key * into the state's byte array. Refer to the PKCS#11 standard for details on this function. * * @param operationState The previously saved state as returned by getOperationState(). * @param encryptionKeyHandle An encryption or decryption key handle, if an encryption or * decryption operation was saved which should be continued, but * the keys could not be saved. * @param authenticationKeyHandle A signing, verification of MAC key handle, if a signing, * verification or MAC operation needs to be restored that could * not save the key. * @throws PKCS11Exception If restoring the state fails. * @see #getOperationState() */ public void setOperationState(byte[] operationState, long encryptionKeyHandle, long authenticationKeyHandle) throws PKCS11Exception { try { pkcs11.C_SetOperationState(sessionHandle, operationState, encryptionKeyHandle, authenticationKeyHandle); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { throw new PKCS11Exception(ex.getErrorCode()); } } public void setSessionHandle(long sessionHandle) { this.sessionHandle = sessionHandle; } /** * Logs in the user or the security officer to the session. Notice that all sessions of a token * have the same login state; i.e. if you login the user to one session all other open sessions of * this token get user rights. * * @param userType CKU_SO for the security officer or CKU_USER to login the user. * @param pin The PIN. The security officer-PIN or the user-PIN depending on the userType parameter. * @throws PKCS11Exception If login fails. */ public void login(long userType, char[] pin) throws PKCS11Exception { final String method = "C_Login"; if (StaticLogger.isDebugEnabled()) { debugIn(method, "userType={}", codeToName(Category.CKU, userType)); } try { pkcs11.C_Login(sessionHandle, userType, pin); debugOut(method); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } /** * Logs out this session. * * @throws PKCS11Exception If logging out the session fails. */ public void logout() throws PKCS11Exception { final String method = "C_Logout"; debugIn(method); try { pkcs11.C_Logout(sessionHandle); debugOut(method); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } /** * Create a new object on the token (or in the session). The application must provide a template * that holds enough information to create a certain object. For instance, if the application * wants to create a new DES key object it creates a new instance of the AttributesTemplate class to * serve as a template. The application must set all attributes of this new object which are * required for the creation of such an object on the token. Then it passes this DESSecretKey * object to this method to create the object on the token. Example: * AttributesTemplate desKeyTemplate = new AttributesTemplate().newSecretKey(CKK_DES3); * // the key type is set by the DESSecretKey's constructor, so you need not do it * desKeyTemplate.value(myDesKeyValueAs8BytesLongByteArray) * .token(true) * .private(true); * .encrypt(true); * .decrypt(true); * ... * long theCreatedDESKeyObjectHandle = userSession.createObject(desKeyTemplate); * Refer to the PKCS#11 standard to find out what attributes must be set for certain types * of objects to create them on the token. * * @param template The template object that holds all values that the new object on the token should * contain. * @return A new PKCS#11 Object that serves holds all the * (readable) attributes of the object on the token. In contrast to the templateObject, * this object might have certain attributes set to token-dependent default-values. * @throws PKCS11Exception If the creation of the new object fails. If it fails, the no new object was * created on the token. */ public long createObject(AttributeVector template) throws PKCS11Exception { final String method = "C_CreateObject"; if (StaticLogger.isDebugEnabled()) { long objClass = template.class_(); if (objClass == CKO_PRIVATE_KEY || objClass == CKO_SECRET_KEY) { AttributeVector logTemplate = template.copyWithoutByteArrayAttributes(); logTemplate.id(template.id()) .modulus(template.modulus()).publicExponent(template.publicExponent()) // RSA .ecParams(template.ecParams()).ecPoint(template.ecPoint()) // EC .prime(template.prime()).subprime(template.subprime()).base(template.base()); // DSA debugIn(method, "part of template={}", logTemplate); } else { debugIn(method, "template={}", template); } } try { long hObject = pkcs11.C_CreateObject(sessionHandle, toOutCKAttributes(template)); debugOut(method, "hObject={}", hObject); return hObject; } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } public long createPrivateKeyObject(AttributeVector template, PublicKey publicKey) throws PKCS11Exception { if (publicKey instanceof ECPublicKey && privateKeyWithEcPoint(template.keyType())) { byte[] ecParams = template.ecParams(); Integer fieldSize = Functions.getECFieldSize(ecParams); ECPoint w = ((ECPublicKey) publicKey).getW(); byte[] wx = Functions.asUnsignedByteArray(w.getAffineX()); byte[] wy = Functions.asUnsignedByteArray(w.getAffineY()); if (fieldSize == null) { fieldSize = Math.max(wx.length, wy.length); } else { if (wx.length > fieldSize || wy.length > fieldSize) { throw new IllegalStateException("should not happen, public key and ecParams do not match"); } } byte[] ecPoint = new byte[1 + 2 * fieldSize]; ecPoint[0] = 4; System.arraycopy(wx, 0, ecPoint, 1 + fieldSize - wx.length, wx.length); System.arraycopy(wy, 0, ecPoint, ecPoint.length - wy.length, wy.length); template.ecPoint(ecPoint); } return createObject(template); } public long createECPrivateKeyObject(AttributeVector template, byte[] ecPoint) throws PKCS11Exception { if (ecPoint != null && privateKeyWithEcPoint(template.keyType())) { template.ecPoint(ecPoint); } return createObject(template); } private boolean privateKeyWithEcPoint(Long keyType) { if (keyType == null) { return false; } if (PKCS11Constants.CKK_EC == keyType) { return module.hasVendorBehaviour(PKCS11Module.BEHAVIOUR_EC_PRIVATEKEY_ECPOINT); } else if (PKCS11Constants.CKK_VENDOR_SM2 == keyType) { return module.hasVendorBehaviour(PKCS11Module.BEHAVIOUR_SM2_PRIVATEKEY_ECPOINT); } else { return false; } } /** * Copy an existing object. The source object and a template object are given. Any value set in * the template object will override the corresponding value from the source object, when the new * object is created. See the PKCS#11 standard for details. * * @param sourceObjectHandle The source object of the copy operation. * @param template A template object whose attribute values are used for the new object; i.e. they have * higher priority than the attribute values from the source object. May be null; in that * case the new object is just a one-to-one copy of the sourceObject. * @return The new object that is created by copying the source object and setting attributes to * the values given by the template. * @throws PKCS11Exception If copying the object fails for some reason. */ public long copyObject(long sourceObjectHandle, AttributeVector template) throws PKCS11Exception { final String method = "C_CopyObject"; debugIn(method, "sourceObjectHandle={}, template={}", sourceObjectHandle, template); try { long hObject = pkcs11.C_CopyObject(sessionHandle, sourceObjectHandle, toOutCKAttributes(template)); debugOut(method, "hObject={}", hObject); return hObject; } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } /** * Gets all present attributes of the given template object an writes them to the object to update * on the token (or in the session). Both parameters may refer to the same Java object. This is * possible, because this method only needs the object handle of the objectToUpdate, and gets the * attributes to set from the template. This means, an application can get the object using * createObject of findObject, then modify attributes of this Java object and then call this * method passing this object as both parameters. This will update the object on the token to the * values as modified in the Java object. * * @param objectToUpdateHandle The attributes of this object get updated. * @param template This methods gets all present attributes of this template object and set this * attributes at the objectToUpdate. * @throws PKCS11Exception If updateing the attributes fails. All or no attributes are updated. */ public void setAttributeValues(long objectToUpdateHandle, AttributeVector template) throws PKCS11Exception { final String method = "C_SetAttributeValue"; debugIn(method, "objectToUpdateHandle={}, template={}", objectToUpdateHandle, template); try { pkcs11.C_SetAttributeValue(sessionHandle, objectToUpdateHandle, toOutCKAttributes(template)); debugOut(method); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } /** * Destroy a certain object on the token (or in the session). Give the object that you want to * destroy. This method uses only the internal object handle of the given object to identify the * object. * * @param objectHandle The object handle that should be destroyed. * @throws PKCS11Exception If the object could not be destroyed. */ public void destroyObject(long objectHandle) throws PKCS11Exception { final String method = "C_DestroyObject"; debugIn(method, "objectHandle={}", objectHandle); try { pkcs11.C_DestroyObject(sessionHandle, objectHandle); debugOut(method); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } /** * Initializes a find operations that provides means to find objects by passing a template object. * This method get all set attributes of the template object ans searches for all objects on the * token that match with these attributes. * * @param template The object that serves as a template for searching. If this object is null, the find * operation will find all objects that this session can see. Notice, that only a user * session will see private objects. * @throws PKCS11Exception If initializing the find operation fails. */ public void findObjectsInit(AttributeVector template) throws PKCS11Exception { final String method = "C_FindObjectsInit"; debugIn(method, "template={}", template); try { pkcs11.C_FindObjectsInit(sessionHandle, template == null ? null : toOutCKAttributes(template, true)); debugOut(method); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } /** * Finds objects that match the template object passed to findObjectsInit. The application must * call findObjectsInit before calling this method. With maxObjectCount the application can * specifay how many objects to return at once; i.e. the application can get all found objects by * susequent calls to this method like maxObjectCount(1) until it receives an empty array (this * method never returns null!). * * @param maxObjectCount Specifies how many objects to return with this call. * @return An array of found objects. The maximum size of this array is maxObjectCount, the * minimum length is 0. Never returns null. * @throws PKCS11Exception A plain PKCS11Exception if something during PKCS11 FindObject went wrong, a * PKCS11Exception with a nested PKCS11Exception if the Exception is raised during * object parsing. */ public long[] findObjects(int maxObjectCount) throws PKCS11Exception { final int countPerCall = 1000; if (maxObjectCount <= maxObjectCount) { return findObjects0(maxObjectCount); } else { List list = new LinkedList<>(); for (int i = 0; i < maxObjectCount; i+= countPerCall) { long[] handles = findObjects0(Math.min(countPerCall, maxObjectCount -i)); if (handles.length == 0) { break; } for (long handle : handles) { list.add(handle); } } long[] ret = new long[list.size()]; int idx = 0; for (Long handle : list) { ret[idx++] = handle; } return ret; } } private long[] findObjects0(int maxObjectCount) throws PKCS11Exception { final String method = "C_FindObjects"; debugIn(method, "maxObjectCount={}", maxObjectCount); try { long[] hObjects = pkcs11.C_FindObjects(sessionHandle, maxObjectCount); if (StaticLogger.isDebugEnabled()) { debugOut(method, "hObjects={}", Arrays.toString(hObjects)); } return hObjects; } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } /** * Finalizes a find operation. The application must call this method to finalize a find operation * before attempting to start any other operation. * * @throws PKCS11Exception If finalizing the current find operation was not possible. */ public void findObjectsFinal() throws PKCS11Exception { final String method = "C_FindObjectsFinal"; debugIn(method); try { pkcs11.C_FindObjectsFinal(sessionHandle); debugOut(method); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } public long[] findAllObjectsSingle(AttributeVector template) throws PKCS11Exception { return findObjectsSingle(template, Integer.MAX_VALUE); } public long[] findObjectsSingle(AttributeVector template, int maxObjectCount) throws PKCS11Exception { findObjectsInit(template); try { return findObjects(maxObjectCount); } finally { findObjectsFinal(); } } /** * Initializes a new encryption operation. The application must call this method before calling * any other encrypt* operation. Before initializing a new operation, any currently pending * operation must be finalized using the appropriate *Final method (e.g. digestFinal()). There are * exceptions for dual-function operations. This method requires the mechanism to use for * encryption and the key for this operation. The key must have set its encryption flag. For the * mechanism the application may use a constant defined in the Mechanism class. Notice that the * key and the mechanism must be compatible; i.e. you cannot use a DES key with the RSA mechanism. * * @param mechanism The mechanism to use; e.g. Mechanism.DES_CBC. * @param keyHandle The decryption key to use. * @throws PKCS11Exception If initializing this operation failed. */ public void encryptInit(Mechanism mechanism, long keyHandle) throws PKCS11Exception { final String method = "C_EncryptInit"; debugIn(method, "mechanism={}, keyHandle={}", mechanism, keyHandle); try { pkcs11.C_EncryptInit(sessionHandle, toCkMechanism(mechanism), keyHandle); debugOut(method); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } /** * Encrypts the given data with the key and mechanism given to the encryptInit method. This method * finalizes the current encryption operation; i.e. the application need (and should) not call * encryptFinal() after this call. For encrypting multiple pices of data use encryptUpdate and * encryptFinal. * * @param in the to-be-encrypted data * @param out buffer for the encrypted data * @return the length of encrypted data * @throws PKCS11Exception If encrypting failed. */ public int encrypt(byte[] in, byte[] out) throws PKCS11Exception { return encrypt(in, 0, in.length, out, 0, out.length); } public int encryptSingle(Mechanism mechanism, long keyHandle, byte[] in, byte[] out) throws PKCS11Exception { return encryptSingle(mechanism, keyHandle, in, 0, in.length, out, 0, out.length); } /** * Encrypts the given data with the key and mechanism given to the encryptInit method. This method * finalizes the current encryption operation; i.e. the application need (and should) not call * encryptFinal() after this call. For encrypting multiple pices of data use encryptUpdate and * encryptFinal. * * @param in buffer containing the to-be-encrypted data * @param inOfs buffer offset of the to-be-encrypted data * @param inLen length of the to-be-encrypted data * @param out buffer for the encrypted data * @param outOfs buffer offset for the encrypted data * @param outLen buffer size for the encrypted data * @return the length of encrypted data * @throws PKCS11Exception If encrypting failed. */ public int encrypt(byte[] in, int inOfs, int inLen, byte[] out, int outOfs, int outLen) throws PKCS11Exception { checkParams(in, inOfs, inLen, out, outOfs, outLen); final String method = "C_Encrypt"; int resLen; debugIn(method, "inOfs={}, inLen={}, outOfs={}, outLen", inOfs, inLen, outOfs, outLen); try { if (encrypt0 != null) { resLen = (int) encrypt0.invoke(pkcs11, sessionHandle, in, inOfs, inLen, out, outOfs, outLen); } else if (encrypt1 != null) { resLen = (int) encrypt1.invoke(pkcs11, sessionHandle, 0, in, inOfs, inLen, 0, out, outOfs, outLen); } else { throw new IllegalStateException("could not find C_ENCRYPT method"); } } catch (IllegalAccessException ex) { throw new IllegalStateException(ex.getMessage(), ex); } catch (InvocationTargetException ex) { Throwable cause = ex.getCause(); if (cause instanceof sun.security.pkcs11.wrapper.PKCS11Exception) { debugError(method, (sun.security.pkcs11.wrapper.PKCS11Exception) cause); long ckr = ((sun.security.pkcs11.wrapper.PKCS11Exception) cause).getErrorCode(); throw new PKCS11Exception(ckr); } else { throw new IllegalStateException(ex.getMessage(), ex); } } return logOutLen(method, resLen); } public int encryptSingle(Mechanism mechanism, long keyHandle, byte[] in, int inOfs, int inLen, byte[] out, int outOfs, int outLen) throws PKCS11Exception { encryptInit(mechanism, keyHandle); return encrypt(in, inOfs, inLen, out, outOfs, outLen); } /** * This method can be used to encrypt multiple pieces of data; e.g. buffer-size pieces when * reading the data from a stream. Encrypts the given data with the key and mechanism given to the * encryptInit method. The application must call encryptFinal to get the final result of the * encryption after feeding in all data using this method. * * @param in the to-be-encrypted data * @param out buffer for the encrypted data * @return the length of encrypted data for this update * @throws PKCS11Exception If encrypting the data failed. */ public int encryptUpdate(byte[] in, byte[] out) throws PKCS11Exception { return encryptUpdate(in, 0, in.length, out, 0, out.length); } /** * This method can be used to encrypt multiple pieces of data; e.g. buffer-size pieces when * reading the data from a stream. Encrypts the given data with the key and mechanism given to the * encryptInit method. The application must call encryptFinal to get the final result of the * encryption after feeding in all data using this method. * * @param in buffer containing the to-be-encrypted data * @param inOfs buffer offset of the to-be-encrypted data * @param inLen length of the to-be-encrypted data * @param out buffer for the encrypted data * @param outOfs buffer offset for the encrypted data * @param outLen buffer size for the encrypted data * @return the length of encrypted data for this update * @throws PKCS11Exception If encrypting the data failed. */ public int encryptUpdate(byte[] in, int inOfs, int inLen, byte[] out, int outOfs, int outLen) throws PKCS11Exception { final String method = "C_EncryptUpdate"; checkParams(in, inOfs, inLen, out, outOfs, outLen); debugIn(method, "inOfs={}, inLen={}, outOfs={}, outLen", inOfs, inLen, outOfs, outLen); try { return logOutLen(method, pkcs11.C_EncryptUpdate(sessionHandle, 0, in, inOfs, inLen, 0, out, outOfs, outLen)); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } /** * This method finalizes an encrpytion operation and returns the final result. Use this method, if * you fed in the data using encryptUpdate. If you used the encrypt(byte[]) method, you need not * (and shall not) call this method, because encrypt(byte[]) finalizes the encryption itself. * * @param out buffer for the encrypted data * @param outOfs buffer offset for the encrypted data * @param outLen buffer size for the encrypted data * @return the length of the last part of the encrypted data * @throws PKCS11Exception If calculating the final result failed. */ public int encryptFinal(byte[] out, int outOfs, int outLen) throws PKCS11Exception { final String method = "C_EncryptFinal"; checkOutParams(out, outOfs, outLen); debugIn(method, "outOfs={}, outLen", outOfs, outLen); try { return logOutLen(method, pkcs11.C_EncryptFinal(sessionHandle, 0, out, outOfs, outLen)); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } /** * Initializes a new decryption operation. The application must call this method before calling * any other decrypt* operation. Before initializing a new operation, any currently pending * operation must be finalized using the appropriate *Final method (e.g. digestFinal()). There are * exceptions for dual-function operations. This method requires the mechanism to use for * decryption and the key for this operation. The key must have set its decryption flag. For the * mechanism the application may use a constant defined in the Mechanism class. Notice that the * key and the mechanism must be compatible; i.e. you cannot use a DES key with the RSA mechanism. * * @param mechanism The mechanism to use; e.g. Mechanism.DES_CBC. * @param keyHandle The decryption key to use. * @throws PKCS11Exception If initializing this operation failed. */ public void decryptInit(Mechanism mechanism, long keyHandle) throws PKCS11Exception { final String method = "C_DecryptInit"; debugIn(method, "mechanism={}, keyHandle={}", mechanism, keyHandle); try { pkcs11.C_DecryptInit(sessionHandle, toCkMechanism(mechanism), keyHandle); debugOut(method); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } /** * Decrypts the given data with the key and mechanism given to the decryptInit method. This method * finalizes the current decryption operation; i.e. the application need (and should) not call * decryptFinal() after this call. For decrypting multiple pieces of data use decryptUpdate and * decryptFinal. * * @param in the to-be-decrypted data * @param out buffer for the decrypted data * @return the length of decrypted data * @throws PKCS11Exception If decrypting failed. */ public int decrypt(byte[] in, byte[] out) throws PKCS11Exception { return decrypt(in, 0, in.length, out, 0, out.length); } public int decryptSingle(Mechanism mechanism, long keyHandle, byte[] in, byte[] out) throws PKCS11Exception { return decryptSingle(mechanism, keyHandle, in, 0, in.length, out, 0, out.length); } /** * Decrypts the given data with the key and mechanism given to the decryptInit method. This method * finalizes the current decryption operation; i.e. the application need (and should) not call * decryptFinal() after this call. For decrypting multiple pieces of data use decryptUpdate and * decryptFinal. * * @param in buffer containing the to-be-decrypted data * @param inOfs buffer offset of the to-be-decrypted data * @param inLen length of the to-be-decrypted data * @param out buffer for the decrypted data * @param outOfs buffer offset for the decrypted data * @param outLen buffer size for the decrypted data * @return the length of decrypted data * @throws PKCS11Exception If decrypting failed. */ public int decrypt(byte[] in, int inOfs, int inLen, byte[] out, int outOfs, int outLen) throws PKCS11Exception { checkParams(in, inOfs, inLen, out, outOfs, outLen); final String method = "C_Decrypt"; debugIn(method, "inOfs={}, inLen={}, outOfs={}, outLen", inOfs, inLen, outOfs, outLen); int resLen; try { if (decrypt0 != null) { resLen = (int) decrypt0.invoke(pkcs11, sessionHandle, in, inOfs, inLen, out, outOfs, outLen); } else if (decrypt1 != null) { resLen = (int) decrypt1.invoke(pkcs11, sessionHandle, 0, in, inOfs, inLen, 0, out, outOfs, outLen); } else { throw new IllegalStateException("could not find C_DECRYPT method"); } } catch (IllegalAccessException ex) { throw new IllegalStateException(ex.getMessage(), ex); } catch (InvocationTargetException ex) { Throwable cause = ex.getCause(); if (cause instanceof sun.security.pkcs11.wrapper.PKCS11Exception) { debugError(method, (sun.security.pkcs11.wrapper.PKCS11Exception) cause); throw new PKCS11Exception(((sun.security.pkcs11.wrapper.PKCS11Exception) cause).getErrorCode()); } else { throw new IllegalStateException(ex.getMessage(), ex); } } return logOutLen(method, resLen); } public int decryptSingle(Mechanism mechanism, long keyHandle, byte[] in, int inOfs, int inLen, byte[] out, int outOfs, int outLen) throws PKCS11Exception { decryptInit(mechanism, keyHandle); return decrypt(in, inOfs, inLen, out, outOfs, outLen); } /** * This method can be used to decrypt multiple pieces of data; e.g. buffer-size pieces when * reading the data from a stream. Decrypts the given data with the key and mechanism given to the * decryptInit method. The application must call decryptFinal to get the final result of the * encryption after feeding in all data using this method. * * @param in the to-be-decrypted data * @param out buffer for the decrypted data * @return the length of decrypted data for this update * @throws PKCS11Exception If decrypting the data failed. */ public int decryptUpdate(byte[] in, byte[] out) throws PKCS11Exception { return decryptUpdate(in, 0, in.length, out, 0, out.length); } /** * This method can be used to decrypt multiple pieces of data; e.g. buffer-size pieces when * reading the data from a stream. Decrypts the given data with the key and mechanism given to the * decryptInit method. The application must call decryptFinal to get the final result of the * encryption after feeding in all data using this method. * * @param in buffer containing the to-be-decrypted data * @param inOfs buffer offset of the to-be-decrypted data * @param inLen length of the to-be-decrypted data * @param out buffer for the decrypted data * @param outOfs buffer offset for the decrypted data * @param outLen buffer size for the decrypted data * @return the length of decrypted data for this update * @throws PKCS11Exception If decrypting the data failed. */ public int decryptUpdate(byte[] in, int inOfs, int inLen, byte[] out, int outOfs, int outLen) throws PKCS11Exception { final String method = "C_DecryptUpdate"; checkParams(in, inOfs, inLen, out, outOfs, outLen); debugIn(method, "inOfs={}, inLen={}, outOfs={}, outLen", inOfs, inLen, outOfs, outLen); try { return logOutLen(method, pkcs11.C_DecryptUpdate(sessionHandle, 0, in, inOfs, inLen, 0, out, outOfs, outLen)); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } /** * This method finalizes a decryption operation and returns the final result. Use this method, if * you fed in the data using decryptUpdate. If you used the decrypt(byte[]) method, you need not * (and shall not) call this method, because decrypt(byte[]) finalizes the decryption itself. * * @param out buffer for the decrypted data * @param outOfs buffer offset for the decrypted data * @param outLen buffer size for the decrypted data * @return the length of this last part of decrypted data * @throws PKCS11Exception If calculating the final result failed. */ public int decryptFinal(byte[] out, int outOfs, int outLen) throws PKCS11Exception { final String method = "C_DecryptFinal"; checkOutParams(out, outOfs, outLen); debugIn(method, "outOfs={}, outLen", outOfs, outLen); try { return logOutLen(method, pkcs11.C_DecryptFinal(sessionHandle, 0, out, outOfs, outLen)); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } /** * Initializes a new digesting operation. The application must call this method before calling any * other digest* operation. Before initializing a new operation, any currently pending operation * must be finalized using the appropriate *Final method (e.g. digestFinal()). There are * exceptions for dual-function operations. This method requires the mechanism to use for * digesting for this operation. For the mechanism the application may use a constant defined in * the Mechanism class. * * @param mechanism The mechanism to use; e.g. Mechanism.SHA_1. * @throws PKCS11Exception If initializing this operation failed. */ public void digestInit(Mechanism mechanism) throws PKCS11Exception { final String method = "C_DigestInit"; debugIn(method, "mechanism={}", mechanism); try { pkcs11.C_DigestInit(sessionHandle, toCkMechanism(mechanism)); debugOut(method); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } /** * Digests the given data with the mechanism given to the digestInit method. * This method finalizes the current digesting operation; i.e. the * application need (and should) not call digestFinal() after this call. For * digesting multiple pieces of data use digestUpdate and digestFinal. * * @param in the to-be-digested data * @param out buffer for the digested data * @return the length of digested data for this update * @throws PKCS11Exception If digesting the data failed. */ public int digestFinal(byte[] in, byte[] out) throws PKCS11Exception { return digestFinal(in, 0, in.length, out, 0, out.length); } /** * Digests the given data with the mechanism given to the digestInit method. * This method finalizes the current digesting operation; i.e. the * application need (and should) not call digestFinal() after this call. For * digesting multiple pieces of data use digestUpdate and digestFinal. * * @param in buffer containing the to-be-digested data * @param inOfs buffer offset of the to-be-digested data * @param inLen length of the to-be-digested data * @param out buffer for the digested data * @param outOfs buffer offset for the digested data * @param outLen buffer size for the digested data * @return the length of digested data for this update * @throws PKCS11Exception If digesting the data failed. */ public int digestFinal(byte[] in, int inOfs, int inLen, byte[] out, int outOfs, int outLen) throws PKCS11Exception { checkParams(in, inOfs, inLen, out, outOfs, outLen); digestUpdate(in, inOfs, inLen); return digestFinal(out, outOfs, outLen); } /** * Digests the given data with the mechanism given to the digestInit method. This method finalizes * the current digesting operation; i.e. the application need (and should) not call digestFinal() * after this call. For digesting multiple pieces of data use digestUpdate and digestFinal. * * @param in the to-be-digested data * @param out buffer for the digested data * @return the length of digested data for this update * @throws PKCS11Exception If digesting the data failed. */ public int digest(byte[] in, byte[] out) throws PKCS11Exception { return digest(in, 0, in.length, out, 0, out.length); } public int digestSingle(Mechanism mechanism, byte[] in, byte[] out) throws PKCS11Exception { return digestSingle(mechanism, in, 0, in.length, out, 0, out.length); } /** * Digests the given data with the mechanism given to the digestInit method. This method finalizes * the current digesting operation; i.e. the application need (and should) not call digestFinal() * after this call. For digesting multiple pieces of data use digestUpdate and digestFinal. * * @param in buffer containing the to-be-digested data * @param inOfs buffer offset of the to-be-digested data * @param inLen length of the to-be-digested data * @param out buffer for the digested data * @param outOfs buffer offset for the digested data * @param outLen buffer size for the digested data * @return the length of digested data for this update * @throws PKCS11Exception If digesting the data failed. */ public int digest(byte[] in, int inOfs, int inLen, byte[] out, int outOfs, int outLen) throws PKCS11Exception { return digestFinal(in, inOfs, inLen, out, outOfs, outLen); } public int digestSingle(Mechanism mechanism, byte[] in, int inOfs, int inLen, byte[] out, int outOfs, int outLen) throws PKCS11Exception { final String method = "C_DigestSingle"; checkParams(in, inOfs, inLen, out, outOfs, outLen); debugIn(method, "mechanism={}, inOfs={}, inLen={}, outOfs={}, outLen", mechanism, inOfs, inLen, outOfs, outLen); try { return logOutLen(method, pkcs11.C_DigestSingle(sessionHandle, toCkMechanism(mechanism), in, inOfs, inLen, out, outOfs, outLen)); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } /** * This method can be used to digest multiple pieces of data; e.g. buffer-size pieces when reading * the data from a stream. Digests the given data with the mechanism given to the digestInit * method. The application must call digestFinal to get the final result of the digesting after * feeding in all data using this method. * * @param in the to-be-digested data * @throws PKCS11Exception If digesting the data failed. */ public void digestUpdate(byte[] in) throws PKCS11Exception { digestUpdate(in, 0, in.length); } /** * This method can be used to digest multiple pieces of data; e.g. buffer-size pieces when reading * the data from a stream. Digests the given data with the mechanism given to the digestInit * method. The application must call digestFinal to get the final result of the digesting after * feeding in all data using this method. * * @param in buffer containing the to-be-digested data * @param inOfs buffer offset of the to-be-digested data * @param inLen length of the to-be-digested data * @throws PKCS11Exception If digesting the data failed. */ public void digestUpdate(byte[] in, int inOfs, int inLen) throws PKCS11Exception { final String method = "C_DigestUpdate"; checkInParams(in, inOfs, inLen); debugIn(method, "inOfs={}, inLen={}", inOfs, inLen); try { pkcs11.C_DigestUpdate(sessionHandle, 0, in, inOfs, inLen); debugOut(method); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } /** * This method is similar to digestUpdate and can be combined with it during one digesting * operation. This method digests the value of the given secret key. * * @param keyHandle The key to digest the value of. * @throws PKCS11Exception If digesting the key failed. */ public void digestKey(long keyHandle) throws PKCS11Exception { final String method = "C_DigestUpdate"; debugIn(method, "keyHandle={}", keyHandle); try { pkcs11.C_DigestKey(sessionHandle, keyHandle); debugOut(method); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } /** * This method finalizes a digesting operation and returns the final result. Use this method, if * you fed in the data using digestUpdate and/or digestKey. If you used the digest(byte[]) method, * you need not (and shall not) call this method, because digest(byte[]) finalizes the digesting * itself. * * @param out buffer for the message digest * @param outOfs buffer offset for the message digest * @param outLen buffer size for the message digest * @return the length of message digest * @throws PKCS11Exception If calculating the final message digest failed. */ public int digestFinal(byte[] out, int outOfs, int outLen) throws PKCS11Exception { final String method = "C_DigestFinal"; checkOutParams(out, outOfs, outLen); debugIn(method, "outOfs={}, outLen", outOfs, outLen); try { return logOutLen(method, pkcs11.C_DigestFinal(sessionHandle, out, outOfs, outLen)); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } private void initSignVerify(Mechanism mechanism, long keyHandle) { this.signOrVerifyKeyHandle = keyHandle; long code = mechanism.getMechanismCode(); if (code == PKCS11Constants.CKM_ECDSA || code == PKCS11Constants.CKM_ECDSA_SHA1 || code == PKCS11Constants.CKM_ECDSA_SHA224 || code == PKCS11Constants.CKM_ECDSA_SHA256 || code == PKCS11Constants.CKM_ECDSA_SHA384 || code == PKCS11Constants.CKM_ECDSA_SHA512 || code == PKCS11Constants.CKM_ECDSA_SHA3_224 || code == PKCS11Constants.CKM_ECDSA_SHA3_256 || code == PKCS11Constants.CKM_ECDSA_SHA3_384 || code == PKCS11Constants.CKM_ECDSA_SHA3_512) { signatureType = SIGN_TYPE_ECDSA; } else if (code == PKCS11Constants.CKM_VENDOR_SM2 || code == PKCS11Constants.CKM_VENDOR_SM2_SM3) { signatureType = SIGN_TYPE_SM2; } else { signatureType = 0; } if (mechanism.getParameters() instanceof CkParamsWithExtra) { signVerifyExtraParams = ((CkParamsWithExtra) mechanism.getParameters()).getExtraParams(); } else { signVerifyExtraParams = null; } } /** * Initializes a new signing operation. Use it for signatures and MACs. The application must call * this method before calling any other sign* operation. Before initializing a new operation, any * currently pending operation must be finalized using the appropriate *Final method (e.g. * digestFinal()). There are exceptions for dual-function operations. This method requires the * mechanism to use for signing and the key for this operation. The key must have set its sign * flag. For the mechanism the application may use a constant defined in the Mechanism class. * Notice that the key and the mechanism must be compatible; i.e. you cannot use a DES key with * the RSA mechanism. * * @param mechanism The mechanism to use; e.g. Mechanism.RSA_PKCS. * @param keyHandle The signing key to use. * @throws PKCS11Exception If initializing this operation failed. */ public void signInit(Mechanism mechanism, long keyHandle) throws PKCS11Exception { final String method = "C_SignInit"; try { initSignVerify(mechanism, keyHandle); debugIn(method, "mechanism={}, keyHandle={}", mechanism, keyHandle); pkcs11.C_SignInit(sessionHandle, toCkMechanism(mechanism), keyHandle); debugOut(method); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } /** * Signs the given data with the key and mechanism given to the signInit method. This method * finalizes the current signing operation; i.e. the application need (and should) not call * signFinal() after this call. For signing multiple pices of data use signUpdate and signFinal. * * @param data The data to sign. * @return The signed data. * @throws PKCS11Exception If signing the data failed. */ public byte[] sign(byte[] data) throws PKCS11Exception { Functions.requireNonNull("data", data); final String method = "C_Sign"; debugIn(method, "data.length={}", len(data)); try { byte[] sigValue = pkcs11.C_Sign(sessionHandle, data); debugOut("C_Sign", "rv.length={]", len(sigValue)); return fixSignOutput(sigValue); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } public byte[] signSingle(Mechanism mechanism, long keyHandle, byte[] data) throws PKCS11Exception { signInit(mechanism, keyHandle); return sign(data); } /** * This method can be used to sign multiple pieces of data; e.g. buffer-size pieces when reading * the data from a stream. Signs the given data with the mechanism given to the signInit method. * The application must call signFinal to get the final result of the signing after feeding in all * data using this method. * * @param in buffer containing the to-be-signed data * @throws PKCS11Exception If signing the data failed. */ public void signUpdate(byte[] in) throws PKCS11Exception { signUpdate(in, 0, in.length); } /** * This method can be used to sign multiple pieces of data; e.g. buffer-size pieces when reading * the data from a stream. Signs the given data with the mechanism given to the signInit method. * The application must call signFinal to get the final result of the signing after feeding in all * data using this method. * * @param in buffer containing the to-be-signed data * @param inOfs buffer offset of the to-be-signed data * @param inLen length of the to-be-signed data * @throws PKCS11Exception If signing the data failed. */ public void signUpdate(byte[] in, int inOfs, int inLen) throws PKCS11Exception { final String method = "C_SignUpdate"; checkInParams(in, inOfs, inLen); debugIn(method, "inOfs={}, inLen={}", inOfs, inLen); try { pkcs11.C_SignUpdate(sessionHandle, 0, in, inOfs, inLen); debugOut(method); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } /** * This method finalizes a signing operation and returns the final result. Use this method, if you * fed in the data using signUpdate. If you used the sign(byte[]) method, you need not (and shall * not) call this method, because sign(byte[]) finalizes the signing operation itself. * * @return The final result of the signing operation; i.e. the signature * value. * @throws PKCS11Exception If calculating the final signature value failed. */ public byte[] signFinal() throws PKCS11Exception { final String method = "C_SignFinal"; debugIn(method); try { byte[] sigValue = pkcs11.C_SignFinal(sessionHandle, 0); debugOut(method, "rv.length={]", len(sigValue)); return fixSignOutput(sigValue); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } private byte[] fixSignOutput(byte[] signatureValue) { if (signatureType == 0) { return signatureValue; } synchronized (module) { if (signatureType == SIGN_TYPE_ECDSA) { Boolean b = module.getEcdsaSignatureFixNeeded(); if (b == null) { StaticLogger.info("EcdsaSignatureFixNeeded: null"); } else { StaticLogger.debug("EcdsaSignatureFixNeeded: {}", b); } if (b == null || b) { byte[] fixedSigValue; if (signVerifyExtraParams != null) { int rOrSLen = (signVerifyExtraParams.ecOrderBitSize() + 7) / 8; fixedSigValue = Functions.fixECDSASignature(signatureValue, rOrSLen); } else { // get the ecParams byte[] ecParams; try { ecParams = getAttrValues(signOrVerifyKeyHandle, PKCS11Constants.CKA_EC_PARAMS).ecParams(); } catch (PKCS11Exception e) { StaticLogger.debug("error getting CKA_EC_PARAMS for key {}", signOrVerifyKeyHandle); return signatureValue; } if (ecParams == null) { StaticLogger.debug("found no CKA_EC_PARAMS for key {}", signOrVerifyKeyHandle); return signatureValue; } fixedSigValue = Functions.fixECDSASignature(signatureValue, ecParams); } boolean fixed = !Arrays.equals(fixedSigValue, signatureValue); if (b == null) { StaticLogger.info("Set EcdsaSignatureFixNeeded to {}", b); module.setEcdsaSignatureFixNeeded(fixed); } return fixedSigValue; } } else if (signatureType == SIGN_TYPE_SM2) { Boolean b = module.getSm2SignatureFixNeeded(); if (b == null) { StaticLogger.info("Sm2SignatureFixNeeded: null"); } else { StaticLogger.debug("Sm2SignatureFixNeeded: {}", b); } if (b == null || b) { byte[] fixedSigValue = Functions.fixECDSASignature(signatureValue, 32); boolean fixed = !Arrays.equals(fixedSigValue, signatureValue); if (b == null) { StaticLogger.info("Set Sm2SignatureFixNeeded to {}", b); module.setSm2SignatureFixNeeded(fixed); } return fixedSigValue; } } return signatureValue; } } private byte[] fixSignatureToVerify(byte[] signatureValue) { if (signatureType == SIGN_TYPE_ECDSA) { if (module.hasVendorBehaviour(PKCS11Module.BEHAVIOUR_ECDSA_SIGNATURE_X962)) { return Functions.dsaSigPlainToX962(signatureValue); } } else if (signatureType == SIGN_TYPE_SM2) { if (module.hasVendorBehaviour(PKCS11Module.BEHAVIOUR_SM2_SIGNATURE_X962)) { return Functions.dsaSigPlainToX962(signatureValue); } } return signatureValue; } /** * Initializes a new signing operation for signing with recovery. The application must call this * method before calling signRecover. Before initializing a new operation, any currently pending * operation must be finalized using the appropriate *Final method (e.g. digestFinal()). There are * exceptions for dual-function operations. This method requires the mechanism to use for signing * and the key for this operation. The key must have set its sign-recover flag. For the mechanism * the application may use a constant defined in the Mechanism class. Notice that the key and the * mechanism must be compatible; i.e. you cannot use a DES key with the RSA mechanism. * * @param mechanism The mechanism to use; e.g. Mechanism.RSA_9796. * @param keyHandle The signing key to use. * @throws PKCS11Exception If initializing this operation failed. */ public void signRecoverInit(Mechanism mechanism, long keyHandle) throws PKCS11Exception { final String method = "C_SignRecoverInit"; debugIn(method, "mechanism={}, keyHandle={}", mechanism, keyHandle); try { pkcs11.C_SignRecoverInit(sessionHandle, toCkMechanism(mechanism), keyHandle); debugOut(method); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } /** * Signs the given data with the key and mechanism given to the signRecoverInit method. This * method finalizes the current sign-recover operation; there is no equivalent method to * signUpdate for signing with recovery. * * @param in buffer containing the to-be-signed data * @param out buffer for the signed data * @return the length of signed data * @throws PKCS11Exception If signing the data failed. */ public int signRecover(byte[] in, byte[] out) throws PKCS11Exception { return signRecover(in, 0, in.length, out, 0, out.length); } public int signRecoverSingle(Mechanism mechanism, long keyHandle, byte[] in, byte[] out) throws PKCS11Exception { signRecoverInit(mechanism, keyHandle); return signRecoverSingle(mechanism, keyHandle, in, 0, in.length, out, 0, out.length); } /** * Signs the given data with the key and mechanism given to the signRecoverInit method. This * method finalizes the current sign-recover operation; there is no equivalent method to * signUpdate for signing with recovery. * * @param in buffer containing the to-be-signed data * @param inOfs buffer offset of the to-be-signed data * @param inLen length of the to-be-signed data * @param out buffer for the signed data * @param outOfs buffer offset for the signed data * @param outLen buffer size for the signed data * @return the length of signed data * @throws PKCS11Exception If signing the data failed. */ public int signRecover(byte[] in, int inOfs, int inLen, byte[] out, int outOfs, int outLen) throws PKCS11Exception { final String method = "C_SignRecover"; checkParams(in, inOfs, inLen, out, outOfs, outLen); debugIn(method, "inOfs={}, inLen={}, outOfs={}, outLen", inOfs, inLen, outOfs, outLen); try { return logOutLen(method, pkcs11.C_SignRecover(sessionHandle, in, inOfs, inLen, out, outOfs, outLen)); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } public int signRecoverSingle(Mechanism mechanism, long keyHandle, byte[] in, int inOfs, int inLen, byte[] out, int outOfs, int outLen) throws PKCS11Exception { signRecoverInit(mechanism, keyHandle); return signRecover(in, inOfs, inLen, out, outOfs, outLen); } /** * Initializes a new verification operation. You can use it for verifying signatures and MACs. The * application must call this method before calling any other verify* operation. Before * initializing a new operation, any currently pending operation must be finalized using the * appropriate *Final method (e.g. digestFinal()). There are exceptions for dual-function * operations. This method requires the mechanism to use for verification and the key for this * operation. The key must have set its verify flag. For the mechanism the application may use a * constant defined in the Mechanism class. Notice that the key and the mechanism must be * compatible; i.e. you cannot use a DES key with the RSA mechanism. * * @param mechanism The mechanism to use; e.g. Mechanism.RSA_PKCS. * @param keyHandle The verification key to use. * @throws PKCS11Exception If initializing this operation failed. */ public void verifyInit(Mechanism mechanism, long keyHandle) throws PKCS11Exception { final String method = "C_VerifyInit"; try { initSignVerify(mechanism, keyHandle); debugIn(method, "mechanism={}, keyHandle={}", mechanism, keyHandle); pkcs11.C_VerifyInit(sessionHandle, toCkMechanism(mechanism), keyHandle); debugOut(method); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } /** * Verifies the given signature against the given data with the key and mechanism given to the * verifyInit method. This method finalizes the current verification operation; i.e. the * application need (and should) not call verifyFinal() after this call. For verifying with * multiple pices of data use verifyUpdate and verifyFinal. This method throws an exception, if * the verification of the signature fails. * * @param data The data that was signed. * @param signature The signature or MAC to verify. * @throws PKCS11Exception If verifying the signature fails. This is also the case, if the signature is * forged. */ public void verify(byte[] data, byte[] signature) throws PKCS11Exception { final String method = "C_Verify"; Functions.requireNonNull("signature", signature); debugIn(method, "data.length={}, signature.length={}", len(data), len(signature)); try { pkcs11.C_Verify(sessionHandle, data, fixSignatureToVerify(signature)); debugOut(method); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } public void verifySingle(Mechanism mechanism, long keyHandle, byte[] data, byte[] signature) throws PKCS11Exception { verifyInit(mechanism, keyHandle); verify(data, signature); } /** * This method can be used to verify a signature with multiple pieces of data; e.g. buffer-size * pieces when reading the data from a stream. To verify the signature or MAC call verifyFinal * after feeding in all data using this method. * * @param in the to-be-verified data * @throws PKCS11Exception If verifying (e.g. digesting) the data failed. */ public void verifyUpdate(byte[] in) throws PKCS11Exception { verifyUpdate(in, 0, in.length); } /** * This method can be used to verify a signature with multiple pieces of data; e.g. buffer-size * pieces when reading the data from a stream. To verify the signature or MAC call verifyFinal * after feeding in all data using this method. * * @param in buffer containing the to-be-verified data * @param inOfs buffer offset of the to-be-verified data * @param inLen length of the to-be-verified data * @throws PKCS11Exception If verifying (e.g. digesting) the data failed. */ public void verifyUpdate(byte[] in, int inOfs, int inLen) throws PKCS11Exception { final String method = "C_VerifyUpdate"; checkInParams(in, inOfs, inLen); debugIn(method, "inOfs={}, inLen={}", inOfs, inLen); try { pkcs11.C_VerifyUpdate(sessionHandle, 0, in, inOfs, inLen); debugOut(method); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } /** * This method finalizes a verification operation. Use this method, if you fed in the data using * verifyUpdate. If you used the verify(byte[]) method, you need not (and shall not) call this * method, because verify(byte[]) finalizes the verification operation itself. If this method * verified the signature successfully, it returns normally. If the verification of the signature * fails, e.g. if the signature was forged or the data was modified, this method throws an * exception. * * @param signature The signature value. * @throws PKCS11Exception If verifying the signature fails. This is also the case, if the signature is * forged. */ public void verifyFinal(byte[] signature) throws PKCS11Exception { final String method = "C_VerifyFinal"; Functions.requireNonNull("signature", signature); debugIn(method, "signature.length={}", len(signature)); try { pkcs11.C_VerifyFinal(sessionHandle, fixSignatureToVerify(signature)); debugOut(method); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } /** * Initializes a new verification operation for verification with data recovery. The application * must call this method before calling verifyRecover. Before initializing a new operation, any * currently pending operation must be finalized using the appropriate *Final method (e.g. * digestFinal()). This method requires the mechanism to use for verification and the key for this * oepration. The key must have set its verify-recover flag. For the mechanism the application may * use a constant defined in the Mechanism class. Notice that the key and the mechanism must be * compatible; i.e. you cannot use a DES key with the RSA mechanism. * * @param mechanism The mechanism to use; e.g. Mechanism.RSA_9796. * @param keyHandle The verification key to use. * @throws PKCS11Exception If initializing this operation failed. */ public void verifyRecoverInit(Mechanism mechanism, long keyHandle) throws PKCS11Exception { final String method = "C_VerifyRecoverInit"; debugIn(method, "mechanism={}, keyHandle={}", mechanism, keyHandle); try { pkcs11.C_VerifyRecoverInit(sessionHandle, toCkMechanism(mechanism), keyHandle); debugOut(method); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } /** * Verifies the given data with the key and mechanism given to the verifyRecoverInit method. This * method finalizes the current verify-recover operation; there is no equivalent method to * verifyUpdate for signing with recovery. * * @param in * the to-be-verified data * @param out * the verified data * @return the length of verified data * @exception PKCS11Exception * If signing the data failed. */ public int verifyRecover(byte[] in, byte[] out) throws PKCS11Exception { return verifyRecover(in, 0, in.length, out, 0, out.length); } public int verifyRecoverSingle(Mechanism mechanism, long keyHandle, byte[] in, byte[] out) throws PKCS11Exception { verifyRecoverInit(mechanism, keyHandle); return verifyRecoverSingle(mechanism, keyHandle, in, 0, in.length, out, 0, out.length); } /** * Verifies the given data with the key and mechanism given to the verifyRecoverInit method. This * method finalizes the current verify-recover operation; there is no equivalent method to * verifyUpdate for signing with recovery. * * @param in * buffer containing the to-be-verified data * @param inOfs * buffer offset of the to-be-verified data * @param inLen * length of the to-be-verified data * @param out * buffer for the verified data * @param outOfs * buffer offset for the verified data * @param outLen * buffer size for the verified data * @return the length of verified data * @exception PKCS11Exception * If signing the data failed. */ public int verifyRecover(byte[] in, int inOfs, int inLen, byte[] out, int outOfs, int outLen) throws PKCS11Exception { checkParams(in, inOfs, inLen, out, outOfs, outLen); final String method = "C_VerifyRecover"; debugIn(method, "inOfs={}, inLen={}, outOfs={}, outLen", inOfs, inLen, outOfs, outLen); try { return logOutLen(method, pkcs11.C_VerifyRecover(sessionHandle, in, inOfs, inLen, out, outOfs, outLen)); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } public int verifyRecoverSingle(Mechanism mechanism, long keyHandle, byte[] in, int inOfs, int inLen, byte[] out, int outOfs, int outLen) throws PKCS11Exception { verifyRecoverInit(mechanism, keyHandle); return verifyRecover(in, inOfs, inLen, out, outOfs, outLen); } /** /** * Generate a new secret key or a set of domain parameters. It uses the set attributes of the * template for setting the attributes of the new key object. As mechanism the application can use * a constant of the Mechanism class. * * @param mechanism * The mechanism to generate a key for; e.g. Mechanism.DES to generate a DES key. * @param template * The template for the new key or domain parameters; e.g. a DESSecretKey object which * has set certain attributes. * @return The newly generated secret key or domain parameters. * @exception PKCS11Exception * If generating a new secret key or domain parameters failed. */ public long generateKey(Mechanism mechanism, AttributeVector template) throws PKCS11Exception { final String method = "C_GenerateKey"; debugIn(method, "mechanism={}, template={}", mechanism, template); try { long hKey = pkcs11.C_GenerateKey(sessionHandle, toCkMechanism(mechanism), toOutCKAttributes(template)); debugOut(method, "hKey={}", hKey); return hKey; } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } /** * Generate a new public key - private key key-pair and use the set attributes of the template * objects for setting the attributes of the new public key and private key objects. As mechanism * the application can use a constant of the Mechanism class. * * @param mechanism * The mechanism to generate a key for; e.g. Mechanism.RSA to generate a new RSA * key-pair. * @param template * The template for the new key pair. * @return The newly generated key-pair. * @exception PKCS11Exception * If generating a new key-pair failed. */ public PKCS11KeyPair generateKeyPair(Mechanism mechanism, KeyPairTemplate template) throws PKCS11Exception { final String method = "C_GenerateKeyPair"; debugIn(method, "mechanism={}, template={}", mechanism, template); long[] objectHandles; try { objectHandles = pkcs11.C_GenerateKeyPair(sessionHandle, toCkMechanism(mechanism), toOutCKAttributes(template.publicKey()), toOutCKAttributes(template.privateKey())); PKCS11KeyPair rv = new PKCS11KeyPair(objectHandles[0], objectHandles[1]); debugOut("C_GenerateKeyPair", "hPublicKey={}, hPrivateKey={}", rv.getPublicKey(), rv.getPrivateKey()); return rv; } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } /** * Wraps (encrypts) the given key with the wrapping key using the given mechanism. * * @param mechanism * The mechanism to use for wrapping the key. * @param wrappingKeyHandle * The key to use for wrapping (encrypting). * @param keyHandle * The key to wrap (encrypt). * @return The wrapped key as byte array. * @exception PKCS11Exception * If wrapping the key failed. */ public byte[] wrapKey(Mechanism mechanism, long wrappingKeyHandle, long keyHandle) throws PKCS11Exception { final String method = "C_WrapKey"; debugIn(method, "mechanism={}, wrappingKeyHandle={}, keyHandle={}", mechanism, wrappingKeyHandle, keyHandle); try { return toNonNull(method, pkcs11.C_WrapKey(sessionHandle, toCkMechanism(mechanism), wrappingKeyHandle, keyHandle)); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } /** * Unwraps (decrypts) the given encrypted key with the unwrapping key using the given mechanism. * The application can also pass a template key to set certain attributes of the unwrapped key. * This creates a key object after unwrapping the key and returns an object representing this key. * * @param mechanism * The mechanism to use for unwrapping the key. * @param unwrappingKeyHandle * The key to use for unwrapping (decrypting). * @param wrappedKey * The encrypted key to unwrap (decrypt). * @param keyTemplate * The template for creating the new key object. * @return A key object representing the newly created key object. * @exception PKCS11Exception * If unwrapping the key or creating a new key object failed. */ public long unwrapKey(Mechanism mechanism, long unwrappingKeyHandle, byte[] wrappedKey, AttributeVector keyTemplate) throws PKCS11Exception { Functions.requireNonNull("wrappedKey", wrappedKey); final String method = "C_UnwrapKey"; debugIn(method, "mechanism={}, unwrappingKeyHandle={}, wrappedKey.length={}, template={}", mechanism, unwrappingKeyHandle, len(wrappedKey), keyTemplate); try { long hKey = pkcs11.C_UnwrapKey(sessionHandle, toCkMechanism(mechanism), unwrappingKeyHandle, wrappedKey, toOutCKAttributes(keyTemplate)); debugOut(method, "hKey={}", hKey); return hKey; } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } /** * Derives a new key from a specified base key using the given mechanism. * After deriving a new key from the base key, a new key object is created * and a representation of it is returned. The application can provide a * template key to set certain attributes of the new key object. * * @param mechanism * The mechanism to use for deriving the new key from the base key. * @param baseKeyHandle * The key to use as base for derivation. * @param template * The template for creating the new key object. * @return A key object representing the newly derived (created) key object * or null, if the used mechanism uses other means to return its * values; e.g. the CKM_SSL3_KEY_AND_MAC_DERIVE mechanism. * @exception PKCS11Exception * If deriving the key or creating a new key object failed. */ public long deriveKey(Mechanism mechanism, long baseKeyHandle, AttributeVector template) throws PKCS11Exception { CK_MECHANISM ckMechanism = toCkMechanism(mechanism); final String method = "C_DeriveKey"; debugIn(method, "mechanism={}, baseKeyHandle={}, template={}", mechanism, baseKeyHandle, template); try { long hKey = pkcs11.C_DeriveKey(sessionHandle, ckMechanism, baseKeyHandle, toOutCKAttributes(template)); debugOut(method, "hKey={}", hKey); return hKey; } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } } /** * Mixes additional seeding material into the random number generator. * * @param seed * The seed bytes to mix in. * @exception PKCS11Exception * If mixing in the seed failed. */ public void seedRandom(byte[] seed) throws PKCS11Exception { try { pkcs11.C_SeedRandom(sessionHandle, seed); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { throw new PKCS11Exception(ex.getErrorCode()); } } /** * Generates a certain number of random bytes. * * @param numberOfBytesToGenerate * The number of random bytes to generate. * @return An array of random bytes with length numberOfBytesToGenerate. * @exception PKCS11Exception * If generating random bytes failed. */ public byte[] generateRandom(int numberOfBytesToGenerate) throws PKCS11Exception { final String method = "C_GenerateRandom"; debugIn(method, "numberOfBytesToGenerate={}", numberOfBytesToGenerate); byte[] randomBytesBuffer = new byte[numberOfBytesToGenerate]; try { pkcs11.C_GenerateRandom(sessionHandle, randomBytesBuffer); return toNonNull("C_GenerateRandom", randomBytesBuffer); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { debugError(method, ex); throw new PKCS11Exception(ex.getErrorCode()); } // fill the buffer with random bytes } /** * Returns the string representation of this object. * * @return the string representation of this object */ @Override public String toString() { return "Session Handle: 0x" + Long.toHexString(sessionHandle) + "\nToken: " + token; } private CK_MECHANISM toCkMechanism(Mechanism mechanism) { CK_MECHANISM ckMechanism = mechanism.toCkMechanism(); long code = mechanism.getMechanismCode(); if ((code & PKCS11Constants.CKM_VENDOR_DEFINED) != 0) { ckMechanism.mechanism = module.ckmGenericToVendor(code); } return ckMechanism; } public String getStringAttrValue(long objectHandle, long attributeType) throws PKCS11Exception { CharArrayAttribute attr = new CharArrayAttribute(attributeType); doGetAttrValue(objectHandle, attr); return attr.getValue(); } public Object getAttrValue(long objectHandle, long attributeType) throws PKCS11Exception { Attribute attr = Attribute.getInstance(attributeType); doGetAttrValue(objectHandle, attr); return attr.getValue(); } public AttributeVector getAttrValues(long objectHandle, long... attributeTypes) throws PKCS11Exception { List typeList = new ArrayList<>(attributeTypes.length); for (long attrType : attributeTypes) { typeList.add(attrType); } return getAttrValues(objectHandle, typeList); } public AttributeVector getAttrValues(long objectHandle, List attributeTypes) throws PKCS11Exception { if (attributeTypes.contains(PKCS11Constants.CKA_EC_POINT) && !attributeTypes.contains(PKCS11Constants.CKA_EC_PARAMS)) { synchronized (module) { Boolean b = module.getEcPointFixNeeded(); if (b == null || b) { attributeTypes.add(PKCS11Constants.CKA_EC_PARAMS); } } } Attribute[] attrs = new Attribute[attributeTypes.size()]; int index = 0; // we need to fix attributes EC_PARAMS and EC_POINT. Where EC_POINT needs EC_PARAMS, // and EC_PARAMS needs KEY_TYPE. long[] firstTypes = {PKCS11Constants.CKA_CLASS, PKCS11Constants.CKA_KEY_TYPE, PKCS11Constants.CKA_EC_PARAMS, PKCS11Constants.CKA_EC_POINT}; for (long type : firstTypes) { if (attributeTypes.remove(type)) { attrs[index++] = Attribute.getInstance(type); } } for (long type : attributeTypes) { attrs[index++] = Attribute.getInstance(type); } doGetAttrValues(objectHandle, attrs); return new AttributeVector(attrs); } public AttributeVector getDefaultAttrValues(long objectHandle) throws PKCS11Exception { long objClass = getAttrValues(objectHandle, CKA_CLASS).class_(); List ckaTypes = new LinkedList<>(); addCkaTypes(ckaTypes, CKA_LABEL, CKA_ID, CKA_TOKEN); if (objClass == CKO_SECRET_KEY || objClass == CKO_PRIVATE_KEY) { addCkaTypes(ckaTypes, CKA_ALLOWED_MECHANISMS, CKA_DECRYPT, CKA_EXTRACTABLE, CKA_KEY_GEN_MECHANISM, CKA_NEVER_EXTRACTABLE, CKA_PRIVATE, CKA_SIGN, CKA_UNWRAP, CKA_UNWRAP_TEMPLATE, CKA_WRAP_WITH_TRUSTED); AttributeVector attrs = getAttrValues(objectHandle, CKA_KEY_TYPE, CKA_SENSITIVE, CKA_ALWAYS_SENSITIVE); long keyType = attrs.keyType(); Boolean sensitive = attrs.sensitive(); Boolean alwaysSensitive = attrs.alwaysSensitive(); boolean isSensitive = (sensitive == null) || sensitive; if (alwaysSensitive != null) { isSensitive |= alwaysSensitive; } if (objClass == CKO_SECRET_KEY) { addCkaTypes(ckaTypes, CKA_ENCRYPT, CKA_TRUSTED, CKA_VERIFY, CKA_WRAP, CKA_WRAP_TEMPLATE); if (!(keyType == CKK_DES || keyType == CKK_DES2 || keyType == CKK_DES3)) { ckaTypes.add(CKA_VALUE_LEN); } if (!isSensitive) { ckaTypes.add(CKA_VALUE); } } else { addCkaTypes(ckaTypes, CKA_ALWAYS_AUTHENTICATE, CKA_SIGN_RECOVER); if (keyType == CKK_RSA) { addCkaTypes(ckaTypes, CKA_MODULUS, CKA_PUBLIC_EXPONENT); if (!isSensitive) { addCkaTypes(ckaTypes, CKA_PRIVATE_EXPONENT, CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT); } } else if (keyType == CKK_EC || keyType == CKK_EC_EDWARDS || keyType == CKK_EC_MONTGOMERY || keyType == CKK_VENDOR_SM2) { ckaTypes.add(CKA_EC_PARAMS); if (!isSensitive) { ckaTypes.add(CKA_VALUE); } } else if (keyType == CKK_DSA) { addCkaTypes(ckaTypes, CKA_PRIME, CKA_SUBPRIME, CKA_BASE); if (!isSensitive) { ckaTypes.add(CKA_VALUE); } } } return getAttrValues(objectHandle, ckaTypes).class_(objClass).keyType(keyType) .sensitive(sensitive).alwaysSensitive(alwaysSensitive); } else if (objClass == CKO_PUBLIC_KEY) { addCkaTypes(ckaTypes, CKA_ALLOWED_MECHANISMS, CKA_ENCRYPT, CKA_KEY_GEN_MECHANISM, CKA_TRUSTED, CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_WRAP, CKA_WRAP_TEMPLATE); long keyType = getAttrValues(objectHandle, CKA_KEY_TYPE).keyType(); if (keyType == CKK_RSA) { addCkaTypes(ckaTypes, CKA_MODULUS, CKA_PUBLIC_EXPONENT); } else if (keyType == CKK_EC || keyType == CKK_EC_EDWARDS || keyType == CKK_EC_MONTGOMERY || keyType == CKK_VENDOR_SM2) { addCkaTypes(ckaTypes, CKA_EC_PARAMS, CKA_EC_POINT); } else if (keyType == CKK_DSA) { addCkaTypes(ckaTypes, CKA_PRIME, CKA_SUBPRIME, CKA_BASE); } return getAttrValues(objectHandle, ckaTypes).class_(objClass).keyType(keyType); } else if (objClass == CKO_CERTIFICATE) { addCkaTypes(ckaTypes, CKA_TRUSTED, CKA_CERTIFICATE_CATEGORY, CKA_START_DATE, CKA_END_DATE); long certType = getAttrValues(objectHandle, CKA_CERTIFICATE_TYPE).certificateType(); if (certType == CKC_X_509) { addCkaTypes(ckaTypes, CKA_VALUE, CKA_URL, CKA_ISSUER, CKA_SUBJECT, CKA_SERIAL_NUMBER, CKA_HASH_OF_ISSUER_PUBLIC_KEY, CKA_HASH_OF_SUBJECT_PUBLIC_KEY); } return getAttrValues(objectHandle, ckaTypes).class_(objClass).certificateType(certType); } else { return getAttrValues(objectHandle, ckaTypes); } } private static void addCkaTypes(List list, long... types) { for (long type : types) { list.add(type); } } /** * This method reads the attributes at once. This can lead to performance * improvements. If reading all attributes at once fails, it tries to read * each attributes individually. * * @param objectHandle * The handle of the object which contains the attributes. * @param attributes * The objects specifying the attribute types * (see {@link Attribute#getType()}) and receiving the attribute * values (see {@link Attribute#ckAttribute(CK_ATTRIBUTE)}). * @exception PKCS11Exception * If getting the attributes failed. */ private void doGetAttrValues(long objectHandle, Attribute... attributes) throws PKCS11Exception { Functions.requireNonNull("attributes", attributes); if (attributes.length == 1) { doGetAttrValue(objectHandle, attributes[0]); return; } CK_ATTRIBUTE[] attributeTemplateList = new CK_ATTRIBUTE[attributes.length]; for (int i = 0; i < attributes.length; i++) { attributeTemplateList[i] = new CK_ATTRIBUTE(); attributeTemplateList[i].type = attributes[i].getType(); } PKCS11Exception delayedEx = null; try { pkcs11.C_GetAttributeValue(sessionHandle, objectHandle, attributeTemplateList); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { delayedEx = new PKCS11Exception(ex.getErrorCode()); } for (int i = 0; i < attributes.length; i++) { Attribute attribute = attributes[i]; CK_ATTRIBUTE template = attributeTemplateList[i]; if (template != null) { attribute.present(true).sensitive(false).ckAttribute(template); } } if (delayedEx != null) { // do all failed separately again. delayedEx = null; for (Attribute attr : attributes) { if (attr.getCkAttribute() == null || attr.getCkAttribute().pValue == null) { try { doGetAttrValue0(objectHandle, attr, false); } catch (PKCS11Exception ex) { if (delayedEx == null) { delayedEx = ex; } } } } } for (Attribute attr : attributes) { postProcessGetAttribute(attr, objectHandle, attributes); } if (delayedEx != null) { throw delayedEx; } } /** * This method reads the attribute specified by attribute from * the token using the given session. * The object from which to read the attribute is specified using the * objectHandle. The attribute will contain * the results. * If the attempt to read the attribute returns * CKR_ATTRIBUTE_TYPE_INVALID, this will be indicated by * setting {@link Attribute#present(boolean)} to false. * It CKR_ATTRIBUTE_SENSITIVE is returned, the attribute object is * marked as present * (by calling {@link Attribute#present(boolean)} with * true), and in addition as sensitive by calling * {@link Attribute#sensitive(boolean)} with true. * * @param objectHandle * The handle of the object which contains the attribute. * @param attribute * The object specifying the attribute type * (see {@link Attribute#getType()}) and receiving the attribute * value (see {@link Attribute#ckAttribute(CK_ATTRIBUTE)}). * @exception PKCS11Exception * If getting the attribute failed. */ private void doGetAttrValue(long objectHandle, Attribute attribute) throws PKCS11Exception { if (attribute.getType() == PKCS11Constants.CKA_EC_POINT) { doGetAttrValues(objectHandle, new ByteArrayAttribute(PKCS11Constants.CKA_EC_PARAMS), attribute); } else { doGetAttrValue0(objectHandle, attribute, true); } } private void doGetAttrValue0(long objectHandle, Attribute attribute, boolean postProcess) throws PKCS11Exception { attribute.present(false); try { CK_ATTRIBUTE[] attributeTemplateList = new CK_ATTRIBUTE[1]; attributeTemplateList[0] = new CK_ATTRIBUTE(); attributeTemplateList[0].type = attribute.getType(); pkcs11.C_GetAttributeValue(sessionHandle, objectHandle, attributeTemplateList); attribute.ckAttribute(attributeTemplateList[0]).present(true).sensitive(false); } catch (sun.security.pkcs11.wrapper.PKCS11Exception ex) { long ec = ex.getErrorCode(); if (ec == PKCS11Constants.CKR_ATTRIBUTE_TYPE_INVALID) { if (attribute.getType() == PKCS11Constants.CKA_EC_PARAMS) { // this means, that some requested attributes are missing, but // we can ignore this and proceed; e.g. a v2.01 module won't // have the object ID attribute attribute.present(false).getCkAttribute().pValue = null; } } else if (ec == PKCS11Constants.CKR_ATTRIBUTE_SENSITIVE) { // this means, that some requested attributes are missing, but // we can ignore this and proceed; e.g. a v2.01 module won't // have the object ID attribute attribute.getCkAttribute().pValue = null; attribute.present(true).sensitive(true).getCkAttribute().pValue = null; } else if (ec == PKCS11Constants.CKR_ARGUMENTS_BAD || ec == PKCS11Constants.CKR_FUNCTION_FAILED || ec == PKCS11Constants.CKR_FUNCTION_REJECTED) { attribute.present(false).sensitive(false).getCkAttribute().pValue = null; } else { // there was a different error that we should propagate throw new PKCS11Exception(ec); } } if (postProcess) { postProcessGetAttribute(attribute, objectHandle); } } private CK_ATTRIBUTE[] toOutCKAttributes(AttributeVector template) { return toOutCKAttributes(template, false); } private CK_ATTRIBUTE[] toOutCKAttributes(AttributeVector template, boolean withoutNullValueAttr) { if (template == null) { return null; } CK_ATTRIBUTE[] ckAttrs = template.toCkAttributes(); List nonNullCkAttrs = null; if (withoutNullValueAttr) { nonNullCkAttrs = new ArrayList<>(ckAttrs.length); } for (CK_ATTRIBUTE ckAttr : ckAttrs) { if (ckAttr.pValue == null) { continue; } else { if (withoutNullValueAttr) { nonNullCkAttrs.add(ckAttr); } } if (ckAttr.type == PKCS11Constants.CKA_KEY_TYPE) { long value = (long) ckAttr.pValue; if ((value & PKCS11Constants.CKK_VENDOR_DEFINED) != 0L) { ckAttr.pValue = module.ckkGenericToVendor(value); } } else if (ckAttr.type == PKCS11Constants.CKA_EC_POINT) { ckAttr.pValue = Functions.toOctetString((byte[]) ckAttr.pValue); } } return nonNullCkAttrs != null && nonNullCkAttrs.size() != ckAttrs.length ? nonNullCkAttrs.toArray(new CK_ATTRIBUTE[0]) : ckAttrs; } private void postProcessGetAttribute(Attribute attr, long objectHandle, Attribute... otherAttrs) { long type = attr.getType(); CK_ATTRIBUTE ckAttr = attr.getCkAttribute(); if (type == PKCS11Constants.CKA_EC_PARAMS) { if (ckAttr.pValue == null) { // Some HSMs do not return EC_PARAMS Long keyType = null; if (otherAttrs != null) { for (Attribute otherAttr : otherAttrs) { if (otherAttr.type() == PKCS11Constants.CKA_KEY_TYPE) { keyType = ((LongAttribute) otherAttr).getValue(); } } } if (keyType == null) { try { keyType = getAttrValues(objectHandle, CKA_KEY_TYPE).keyType(); } catch (PKCS11Exception e2) { } } if (keyType != null && keyType == PKCS11Constants.CKK_VENDOR_SM2) { attr.present(false).getCkAttribute().pValue = Functions.decodeHex("06082a811ccf5501822d"); } } else { byte[] ecParams = (byte[]) ckAttr.pValue; if (ecParams[0] != 0x06) { // 06: OBJECT IDENTIFIER ckAttr.pValue = Functions.fixECParams((byte[]) ckAttr.pValue); } } return; } if (ckAttr == null || ckAttr.pValue == null) { return; } if (type == PKCS11Constants.CKA_KEY_TYPE) { long value = (long) ckAttr.pValue; if ((value & PKCS11Constants.CKK_VENDOR_DEFINED) != 0L && !PKCS11Constants.isUnavailableInformation(value)) { ckAttr.pValue = module.ckkVendorToGeneric(value); } } else if (type == PKCS11Constants.CKA_KEY_GEN_MECHANISM) { long value = (long) ckAttr.pValue; if ((value & PKCS11Constants.CKM_VENDOR_DEFINED) != 0L && !PKCS11Constants.isUnavailableInformation(value)) { ckAttr.pValue = module.ckmVendorToGeneric(value); } } else if (type == PKCS11Constants.CKA_ALLOWED_MECHANISMS) { long[] mechs = ((MechanismArrayAttribute) attr).getValue(); for (long mech : mechs) { if ((mech & PKCS11Constants.CKM_VENDOR_DEFINED) != 0L) { ckAttr.pValue = module.ckmVendorToGeneric(mech); } } } else if (type == PKCS11Constants.CKA_EC_POINT) { Boolean b = module.getEcPointFixNeeded(); byte[] pValue = (byte[]) ckAttr.pValue; if (b == null || b) { byte[] ecParams = null; if (otherAttrs != null) { for (Attribute otherAttr : otherAttrs) { if (otherAttr.getType() == PKCS11Constants.CKA_EC_PARAMS) { ecParams = ((ByteArrayAttribute) otherAttr).getValue(); break; } } } byte[] fixedCoreEcPoint = Functions.getCoreECPoint(pValue, ecParams); if (b == null) { byte[] coreEcPoint = Functions.getCoreECPoint(pValue); module.setEcPointFixNeeded(!Arrays.equals(coreEcPoint, fixedCoreEcPoint)); } ckAttr.pValue = fixedCoreEcPoint; } else { ckAttr.pValue = Functions.getCoreECPoint(pValue); } } else if (attr instanceof BooleanAttribute) { if (ckAttr.pValue instanceof byte[]) { byte[] value = (byte[]) ckAttr.pValue; boolean allZeros = true; for (byte b : value) { if (b != 0) { allZeros = false; break; } } ckAttr.pValue = !allZeros; } } } private static void checkParams(byte[] in, int inOfs, int inLen, byte[] out, int outOfs, int outLen) { checkInParams(in, inOfs, inLen); checkOutParams(out, outOfs, outLen); } private static void checkInParams(byte[] in, int inOfs, int inLen) { Functions.requireNonNull("in", in); if (inOfs < 0 || inLen <= 0) { throw new IllegalArgumentException("inOfs or inLen is invalid"); } if (in.length < inOfs + inLen) { throw new IllegalArgumentException("inOfs + inLen > in.length"); } } private static void checkOutParams(byte[] out, int outOfs, int outLen) { Functions.requireNonNull("out", out); if (outOfs < 0 || outLen <= 0) { throw new IllegalArgumentException("outOfs or outLen is invalid"); } if (out.length < outOfs + outLen) { throw new IllegalArgumentException("outOfs + outLen > out.length"); } } private void debugIn(String cMethod) { if (StaticLogger.isDebugEnabled()) { StaticLogger.debug("IN " + cMethod + ": hSession=" + sessionHandle); } } private void debugIn(String method, String format, Object... arguments) { if (StaticLogger.isDebugEnabled()) { StaticLogger.debug("IN " + method + ": hSession=" + sessionHandle + ", " + format, arguments); } } private void debugError(String method) { if (StaticLogger.isDebugEnabled()) { StaticLogger.debug(method + ": hSession=" + sessionHandle); } } private void debugError(String method, sun.security.pkcs11.wrapper.PKCS11Exception e) { if (StaticLogger.isDebugEnabled()) { StaticLogger.debug("ERR " + method + ": " + ckrCodeToName(e.getErrorCode())); } } private void debugOut(String method) { if (StaticLogger.isDebugEnabled()) { StaticLogger.debug("OUT " + method + ": hSession=" + sessionHandle); } } private void debugOut(String method, String format, Object... arguments) { if (StaticLogger.isDebugEnabled()) { StaticLogger.debug("OUT " + method + ": hSession=" + sessionHandle + ", " + format, arguments); } } private static int len(byte[] bytes) { return bytes == null ? 0 : bytes.length; } private byte[] toNonNull(String method, byte[] bytes) { if (bytes == null) { debugOut(method, "rv=null"); } else { debugOut(method, "rv.length={}", bytes.length); } return (bytes == null) ? new byte[0] : bytes; } private int logOutLen(String method, int outLen) { debugOut(method, "outLen={}", outLen); return outLen; } private byte[] toNonNull(byte[] bytes) { return (bytes == null) ? new byte[0] : bytes; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy