--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11Signature.java Wed Dec 14 10:51:13 2016 -0800
@@ -0,0 +1,825 @@
+/*
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.pkcs11;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+
+import java.security.*;
+import java.security.interfaces.*;
+import sun.nio.ch.DirectBuffer;
+
+import sun.security.util.*;
+import sun.security.x509.AlgorithmId;
+
+import sun.security.rsa.RSASignature;
+import sun.security.rsa.RSAPadding;
+
+import sun.security.pkcs11.wrapper.*;
+import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
+import sun.security.util.KeyUtil;
+
+/**
+ * Signature implementation class. This class currently supports the
+ * following algorithms:
+ *
+ * . DSA
+ * . NONEwithDSA (RawDSA)
+ * . SHA1withDSA
+ * . NONEwithDSAinP1363Format (RawDSAinP1363Format)
+ * . SHA1withDSAinP1363Format
+ * . RSA:
+ * . MD2withRSA
+ * . MD5withRSA
+ * . SHA1withRSA
+ * . SHA224withRSA
+ * . SHA256withRSA
+ * . SHA384withRSA
+ * . SHA512withRSA
+ * . ECDSA
+ * . NONEwithECDSA
+ * . SHA1withECDSA
+ * . SHA224withECDSA
+ * . SHA256withECDSA
+ * . SHA384withECDSA
+ * . SHA512withECDSA
+ * . NONEwithECDSAinP1363Format
+ * . SHA1withECDSAinP1363Format
+ * . SHA224withECDSAinP1363Format
+ * . SHA256withECDSAinP1363Format
+ * . SHA384withECDSAinP1363Format
+ * . SHA512withECDSAinP1363Format
+ *
+ * Note that the underlying PKCS#11 token may support complete signature
+ * algorithm (e.g. CKM_DSA_SHA1, CKM_MD5_RSA_PKCS), or it may just
+ * implement the signature algorithm without hashing (e.g. CKM_DSA, CKM_PKCS),
+ * or it may only implement the raw public key operation (CKM_RSA_X_509).
+ * This class uses what is available and adds whatever extra processing
+ * is needed.
+ *
+ * @author Andreas Sterbenz
+ * @since 1.5
+ */
+final class P11Signature extends SignatureSpi {
+
+ // token instance
+ private final Token token;
+
+ // algorithm name
+ private final String algorithm;
+
+ // name of the key algorithm, currently either RSA or DSA
+ private final String keyAlgorithm;
+
+ // mechanism id
+ private final long mechanism;
+
+ // digest algorithm OID, if we encode RSA signature ourselves
+ private final ObjectIdentifier digestOID;
+
+ // type, one of T_* below
+ private final int type;
+
+ // key instance used, if init*() was called
+ private P11Key p11Key;
+
+ // message digest, if we do the digesting ourselves
+ private final MessageDigest md;
+
+ // associated session, if any
+ private Session session;
+
+ // mode, one of M_* below
+ private int mode;
+
+ // flag indicating whether an operation is initialized
+ private boolean initialized;
+
+ // buffer, for update(byte) or DSA
+ private final byte[] buffer;
+
+ // total number of bytes processed in current operation
+ private int bytesProcessed;
+
+ // The format, to be used for DSA and ECDSA signatures.
+ // If true, the IEEE P1363 format will be used, the concatenation of
+ // r and s. If false (default), the signature will be formatted as a
+ // DER-encoded ASN.1 sequence of r and s.
+ private boolean p1363Format = false;
+
+ // constant for signing mode
+ private final static int M_SIGN = 1;
+ // constant for verification mode
+ private final static int M_VERIFY = 2;
+
+ // constant for type digesting, we do the hashing ourselves
+ private final static int T_DIGEST = 1;
+ // constant for type update, token does everything
+ private final static int T_UPDATE = 2;
+ // constant for type raw, used with RawDSA and NONEwithECDSA only
+ private final static int T_RAW = 3;
+
+ // XXX PKCS#11 v2.20 says "should not be longer than 1024 bits",
+ // but this is a little arbitrary
+ private final static int RAW_ECDSA_MAX = 128;
+
+ P11Signature(Token token, String algorithm, long mechanism)
+ throws NoSuchAlgorithmException, PKCS11Exception {
+ super();
+ this.token = token;
+ this.algorithm = algorithm;
+ this.mechanism = mechanism;
+ byte[] buffer = null;
+ ObjectIdentifier digestOID = null;
+ MessageDigest md = null;
+ switch ((int)mechanism) {
+ case (int)CKM_MD2_RSA_PKCS:
+ case (int)CKM_MD5_RSA_PKCS:
+ case (int)CKM_SHA1_RSA_PKCS:
+ case (int)CKM_SHA224_RSA_PKCS:
+ case (int)CKM_SHA256_RSA_PKCS:
+ case (int)CKM_SHA384_RSA_PKCS:
+ case (int)CKM_SHA512_RSA_PKCS:
+ keyAlgorithm = "RSA";
+ type = T_UPDATE;
+ buffer = new byte[1];
+ break;
+ case (int)CKM_DSA_SHA1:
+ keyAlgorithm = "DSA";
+ type = T_UPDATE;
+ buffer = new byte[1];
+ break;
+ case (int)CKM_ECDSA_SHA1:
+ keyAlgorithm = "EC";
+ type = T_UPDATE;
+ buffer = new byte[1];
+ break;
+ case (int)CKM_DSA:
+ keyAlgorithm = "DSA";
+ if (algorithm.equals("DSA") ||
+ algorithm.equals("DSAinP1363Format")) {
+ type = T_DIGEST;
+ md = MessageDigest.getInstance("SHA-1");
+ } else if (algorithm.equals("RawDSA") ||
+ algorithm.equals("RawDSAinP1363Format")) {
+ type = T_RAW;
+ buffer = new byte[20];
+ } else {
+ throw new ProviderException(algorithm);
+ }
+ break;
+ case (int)CKM_ECDSA:
+ keyAlgorithm = "EC";
+ if (algorithm.equals("NONEwithECDSA") ||
+ algorithm.equals("NONEwithECDSAinP1363Format")) {
+ type = T_RAW;
+ buffer = new byte[RAW_ECDSA_MAX];
+ } else {
+ String digestAlg;
+ if (algorithm.equals("SHA1withECDSA") ||
+ algorithm.equals("SHA1withECDSAinP1363Format")) {
+ digestAlg = "SHA-1";
+ } else if (algorithm.equals("SHA224withECDSA") ||
+ algorithm.equals("SHA224withECDSAinP1363Format")) {
+ digestAlg = "SHA-224";
+ } else if (algorithm.equals("SHA256withECDSA") ||
+ algorithm.equals("SHA256withECDSAinP1363Format")) {
+ digestAlg = "SHA-256";
+ } else if (algorithm.equals("SHA384withECDSA") ||
+ algorithm.equals("SHA384withECDSAinP1363Format")) {
+ digestAlg = "SHA-384";
+ } else if (algorithm.equals("SHA512withECDSA") ||
+ algorithm.equals("SHA512withECDSAinP1363Format")) {
+ digestAlg = "SHA-512";
+ } else {
+ throw new ProviderException(algorithm);
+ }
+ type = T_DIGEST;
+ md = MessageDigest.getInstance(digestAlg);
+ }
+ break;
+ case (int)CKM_RSA_PKCS:
+ case (int)CKM_RSA_X_509:
+ keyAlgorithm = "RSA";
+ type = T_DIGEST;
+ if (algorithm.equals("MD5withRSA")) {
+ md = MessageDigest.getInstance("MD5");
+ digestOID = AlgorithmId.MD5_oid;
+ } else if (algorithm.equals("SHA1withRSA")) {
+ md = MessageDigest.getInstance("SHA-1");
+ digestOID = AlgorithmId.SHA_oid;
+ } else if (algorithm.equals("MD2withRSA")) {
+ md = MessageDigest.getInstance("MD2");
+ digestOID = AlgorithmId.MD2_oid;
+ } else if (algorithm.equals("SHA224withRSA")) {
+ md = MessageDigest.getInstance("SHA-224");
+ digestOID = AlgorithmId.SHA224_oid;
+ } else if (algorithm.equals("SHA256withRSA")) {
+ md = MessageDigest.getInstance("SHA-256");
+ digestOID = AlgorithmId.SHA256_oid;
+ } else if (algorithm.equals("SHA384withRSA")) {
+ md = MessageDigest.getInstance("SHA-384");
+ digestOID = AlgorithmId.SHA384_oid;
+ } else if (algorithm.equals("SHA512withRSA")) {
+ md = MessageDigest.getInstance("SHA-512");
+ digestOID = AlgorithmId.SHA512_oid;
+ } else {
+ throw new ProviderException("Unknown signature: " + algorithm);
+ }
+ break;
+ default:
+ throw new ProviderException("Unknown mechanism: " + mechanism);
+ }
+ this.buffer = buffer;
+ this.digestOID = digestOID;
+ this.md = md;
+ if (algorithm.endsWith("inP1363Format")) {
+ this.p1363Format = true;
+ }
+ }
+
+ private void ensureInitialized() {
+ token.ensureValid();
+ if (initialized == false) {
+ initialize();
+ }
+ }
+
+ private void cancelOperation() {
+ token.ensureValid();
+ if (initialized == false) {
+ return;
+ }
+ initialized = false;
+ if ((session == null) || (token.explicitCancel == false)) {
+ return;
+ }
+ if (session.hasObjects() == false) {
+ session = token.killSession(session);
+ return;
+ }
+ // "cancel" operation by finishing it
+ // XXX make sure all this always works correctly
+ if (mode == M_SIGN) {
+ try {
+ if (type == T_UPDATE) {
+ token.p11.C_SignFinal(session.id(), 0);
+ } else {
+ byte[] digest;
+ if (type == T_DIGEST) {
+ digest = md.digest();
+ } else { // T_RAW
+ digest = buffer;
+ }
+ token.p11.C_Sign(session.id(), digest);
+ }
+ } catch (PKCS11Exception e) {
+ throw new ProviderException("cancel failed", e);
+ }
+ } else { // M_VERIFY
+ try {
+ byte[] signature;
+ if (keyAlgorithm.equals("DSA")) {
+ signature = new byte[40];
+ } else {
+ signature = new byte[(p11Key.length() + 7) >> 3];
+ }
+ if (type == T_UPDATE) {
+ token.p11.C_VerifyFinal(session.id(), signature);
+ } else {
+ byte[] digest;
+ if (type == T_DIGEST) {
+ digest = md.digest();
+ } else { // T_RAW
+ digest = buffer;
+ }
+ token.p11.C_Verify(session.id(), digest, signature);
+ }
+ } catch (PKCS11Exception e) {
+ // will fail since the signature is incorrect
+ // XXX check error code
+ }
+ }
+ }
+
+ // assumes current state is initialized == false
+ private void initialize() {
+ try {
+ if (session == null) {
+ session = token.getOpSession();
+ }
+ if (mode == M_SIGN) {
+ token.p11.C_SignInit(session.id(),
+ new CK_MECHANISM(mechanism), p11Key.keyID);
+ } else {
+ token.p11.C_VerifyInit(session.id(),
+ new CK_MECHANISM(mechanism), p11Key.keyID);
+ }
+ initialized = true;
+ } catch (PKCS11Exception e) {
+ throw new ProviderException("Initialization failed", e);
+ }
+ if (bytesProcessed != 0) {
+ bytesProcessed = 0;
+ if (md != null) {
+ md.reset();
+ }
+ }
+ }
+
+ private void checkKeySize(String keyAlgo, Key key)
+ throws InvalidKeyException {
+ CK_MECHANISM_INFO mechInfo = null;
+ try {
+ mechInfo = token.getMechanismInfo(mechanism);
+ } catch (PKCS11Exception e) {
+ // should not happen, ignore for now.
+ }
+ if (mechInfo == null) {
+ // skip the check if no native info available
+ return;
+ }
+ int minKeySize = (int) mechInfo.ulMinKeySize;
+ int maxKeySize = (int) mechInfo.ulMaxKeySize;
+ // need to override the MAX keysize for SHA1withDSA
+ if (md != null && mechanism == CKM_DSA && maxKeySize > 1024) {
+ maxKeySize = 1024;
+ }
+ int keySize = 0;
+ if (key instanceof P11Key) {
+ keySize = ((P11Key) key).length();
+ } else {
+ if (keyAlgo.equals("RSA")) {
+ keySize = ((RSAKey) key).getModulus().bitLength();
+ } else if (keyAlgo.equals("DSA")) {
+ keySize = ((DSAKey) key).getParams().getP().bitLength();
+ } else if (keyAlgo.equals("EC")) {
+ keySize = ((ECKey) key).getParams().getCurve().getField().getFieldSize();
+ } else {
+ throw new ProviderException("Error: unsupported algo " + keyAlgo);
+ }
+ }
+ if ((minKeySize != -1) && (keySize < minKeySize)) {
+ throw new InvalidKeyException(keyAlgo +
+ " key must be at least " + minKeySize + " bits");
+ }
+ if ((maxKeySize != -1) && (keySize > maxKeySize)) {
+ throw new InvalidKeyException(keyAlgo +
+ " key must be at most " + maxKeySize + " bits");
+ }
+ if (keyAlgo.equals("RSA")) {
+ checkRSAKeyLength(keySize);
+ }
+ }
+
+ private void checkRSAKeyLength(int len) throws InvalidKeyException {
+ RSAPadding padding;
+ try {
+ padding = RSAPadding.getInstance
+ (RSAPadding.PAD_BLOCKTYPE_1, (len + 7) >> 3);
+ } catch (InvalidAlgorithmParameterException iape) {
+ throw new InvalidKeyException(iape.getMessage());
+ }
+ int maxDataSize = padding.getMaxDataSize();
+ int encodedLength;
+ if (algorithm.equals("MD5withRSA") ||
+ algorithm.equals("MD2withRSA")) {
+ encodedLength = 34;
+ } else if (algorithm.equals("SHA1withRSA")) {
+ encodedLength = 35;
+ } else if (algorithm.equals("SHA224withRSA")) {
+ encodedLength = 47;
+ } else if (algorithm.equals("SHA256withRSA")) {
+ encodedLength = 51;
+ } else if (algorithm.equals("SHA384withRSA")) {
+ encodedLength = 67;
+ } else if (algorithm.equals("SHA512withRSA")) {
+ encodedLength = 83;
+ } else {
+ throw new ProviderException("Unknown signature algo: " + algorithm);
+ }
+ if (encodedLength > maxDataSize) {
+ throw new InvalidKeyException
+ ("Key is too short for this signature algorithm");
+ }
+ }
+
+ // see JCA spec
+ protected void engineInitVerify(PublicKey publicKey)
+ throws InvalidKeyException {
+ if (publicKey == null) {
+ throw new InvalidKeyException("Key must not be null");
+ }
+ // Need to check key length whenever a new key is set
+ if (publicKey != p11Key) {
+ checkKeySize(keyAlgorithm, publicKey);
+ }
+ cancelOperation();
+ mode = M_VERIFY;
+ p11Key = P11KeyFactory.convertKey(token, publicKey, keyAlgorithm);
+ initialize();
+ }
+
+ // see JCA spec
+ protected void engineInitSign(PrivateKey privateKey)
+ throws InvalidKeyException {
+ if (privateKey == null) {
+ throw new InvalidKeyException("Key must not be null");
+ }
+ // Need to check RSA key length whenever a new key is set
+ if (privateKey != p11Key) {
+ checkKeySize(keyAlgorithm, privateKey);
+ }
+ cancelOperation();
+ mode = M_SIGN;
+ p11Key = P11KeyFactory.convertKey(token, privateKey, keyAlgorithm);
+ initialize();
+ }
+
+ // see JCA spec
+ protected void engineUpdate(byte b) throws SignatureException {
+ ensureInitialized();
+ switch (type) {
+ case T_UPDATE:
+ buffer[0] = b;
+ engineUpdate(buffer, 0, 1);
+ break;
+ case T_DIGEST:
+ md.update(b);
+ bytesProcessed++;
+ break;
+ case T_RAW:
+ if (bytesProcessed >= buffer.length) {
+ bytesProcessed = buffer.length + 1;
+ return;
+ }
+ buffer[bytesProcessed++] = b;
+ break;
+ default:
+ throw new ProviderException("Internal error");
+ }
+ }
+
+ // see JCA spec
+ protected void engineUpdate(byte[] b, int ofs, int len)
+ throws SignatureException {
+ ensureInitialized();
+ if (len == 0) {
+ return;
+ }
+ switch (type) {
+ case T_UPDATE:
+ try {
+ if (mode == M_SIGN) {
+ token.p11.C_SignUpdate(session.id(), 0, b, ofs, len);
+ } else {
+ token.p11.C_VerifyUpdate(session.id(), 0, b, ofs, len);
+ }
+ bytesProcessed += len;
+ } catch (PKCS11Exception e) {
+ throw new ProviderException(e);
+ }
+ break;
+ case T_DIGEST:
+ md.update(b, ofs, len);
+ bytesProcessed += len;
+ break;
+ case T_RAW:
+ if (bytesProcessed + len > buffer.length) {
+ bytesProcessed = buffer.length + 1;
+ return;
+ }
+ System.arraycopy(b, ofs, buffer, bytesProcessed, len);
+ bytesProcessed += len;
+ break;
+ default:
+ throw new ProviderException("Internal error");
+ }
+ }
+
+ // see JCA spec
+ protected void engineUpdate(ByteBuffer byteBuffer) {
+ ensureInitialized();
+ int len = byteBuffer.remaining();
+ if (len <= 0) {
+ return;
+ }
+ switch (type) {
+ case T_UPDATE:
+ if (byteBuffer instanceof DirectBuffer == false) {
+ // cannot do better than default impl
+ super.engineUpdate(byteBuffer);
+ return;
+ }
+ long addr = ((DirectBuffer)byteBuffer).address();
+ int ofs = byteBuffer.position();
+ try {
+ if (mode == M_SIGN) {
+ token.p11.C_SignUpdate
+ (session.id(), addr + ofs, null, 0, len);
+ } else {
+ token.p11.C_VerifyUpdate
+ (session.id(), addr + ofs, null, 0, len);
+ }
+ bytesProcessed += len;
+ byteBuffer.position(ofs + len);
+ } catch (PKCS11Exception e) {
+ throw new ProviderException("Update failed", e);
+ }
+ break;
+ case T_DIGEST:
+ md.update(byteBuffer);
+ bytesProcessed += len;
+ break;
+ case T_RAW:
+ if (bytesProcessed + len > buffer.length) {
+ bytesProcessed = buffer.length + 1;
+ return;
+ }
+ byteBuffer.get(buffer, bytesProcessed, len);
+ bytesProcessed += len;
+ break;
+ default:
+ throw new ProviderException("Internal error");
+ }
+ }
+
+ // see JCA spec
+ protected byte[] engineSign() throws SignatureException {
+ ensureInitialized();
+ try {
+ byte[] signature;
+ if (type == T_UPDATE) {
+ int len = keyAlgorithm.equals("DSA") ? 40 : 0;
+ signature = token.p11.C_SignFinal(session.id(), len);
+ } else {
+ byte[] digest;
+ if (type == T_DIGEST) {
+ digest = md.digest();
+ } else { // T_RAW
+ if (mechanism == CKM_DSA) {
+ if (bytesProcessed != buffer.length) {
+ throw new SignatureException
+ ("Data for RawDSA must be exactly 20 bytes long");
+ }
+ digest = buffer;
+ } else { // CKM_ECDSA
+ if (bytesProcessed > buffer.length) {
+ throw new SignatureException("Data for NONEwithECDSA"
+ + " must be at most " + RAW_ECDSA_MAX + " bytes long");
+ }
+ digest = new byte[bytesProcessed];
+ System.arraycopy(buffer, 0, digest, 0, bytesProcessed);
+ }
+ }
+ if (keyAlgorithm.equals("RSA") == false) {
+ // DSA and ECDSA
+ signature = token.p11.C_Sign(session.id(), digest);
+ } else { // RSA
+ byte[] data = encodeSignature(digest);
+ if (mechanism == CKM_RSA_X_509) {
+ data = pkcs1Pad(data);
+ }
+ signature = token.p11.C_Sign(session.id(), data);
+ }
+ }
+ if (keyAlgorithm.equals("RSA")) {
+ return signature;
+ } else {
+ if (p1363Format) {
+ return signature;
+ } else {
+ return dsaToASN1(signature);
+ }
+ }
+ } catch (PKCS11Exception pe) {
+ throw new ProviderException(pe);
+ } catch (SignatureException | ProviderException e) {
+ cancelOperation();
+ throw e;
+ } finally {
+ initialized = false;
+ session = token.releaseSession(session);
+ }
+ }
+
+ // see JCA spec
+ protected boolean engineVerify(byte[] signature) throws SignatureException {
+ ensureInitialized();
+ try {
+ if (!p1363Format) {
+ if (keyAlgorithm.equals("DSA")) {
+ signature = asn1ToDSA(signature);
+ } else if (keyAlgorithm.equals("EC")) {
+ signature = asn1ToECDSA(signature);
+ }
+ }
+ if (type == T_UPDATE) {
+ token.p11.C_VerifyFinal(session.id(), signature);
+ } else {
+ byte[] digest;
+ if (type == T_DIGEST) {
+ digest = md.digest();
+ } else { // T_RAW
+ if (mechanism == CKM_DSA) {
+ if (bytesProcessed != buffer.length) {
+ throw new SignatureException
+ ("Data for RawDSA must be exactly 20 bytes long");
+ }
+ digest = buffer;
+ } else {
+ if (bytesProcessed > buffer.length) {
+ throw new SignatureException("Data for NONEwithECDSA"
+ + " must be at most " + RAW_ECDSA_MAX + " bytes long");
+ }
+ digest = new byte[bytesProcessed];
+ System.arraycopy(buffer, 0, digest, 0, bytesProcessed);
+ }
+ }
+ if (keyAlgorithm.equals("RSA") == false) {
+ // DSA and ECDSA
+ token.p11.C_Verify(session.id(), digest, signature);
+ } else { // RSA
+ byte[] data = encodeSignature(digest);
+ if (mechanism == CKM_RSA_X_509) {
+ data = pkcs1Pad(data);
+ }
+ token.p11.C_Verify(session.id(), data, signature);
+ }
+ }
+ return true;
+ } catch (PKCS11Exception pe) {
+ long errorCode = pe.getErrorCode();
+ if (errorCode == CKR_SIGNATURE_INVALID) {
+ return false;
+ }
+ if (errorCode == CKR_SIGNATURE_LEN_RANGE) {
+ // return false rather than throwing an exception
+ return false;
+ }
+ // ECF bug?
+ if (errorCode == CKR_DATA_LEN_RANGE) {
+ return false;
+ }
+ throw new ProviderException(pe);
+ } catch (SignatureException | ProviderException e) {
+ cancelOperation();
+ throw e;
+ } finally {
+ initialized = false;
+ session = token.releaseSession(session);
+ }
+ }
+
+ private byte[] pkcs1Pad(byte[] data) {
+ try {
+ int len = (p11Key.length() + 7) >> 3;
+ RSAPadding padding = RSAPadding.getInstance
+ (RSAPadding.PAD_BLOCKTYPE_1, len);
+ byte[] padded = padding.pad(data);
+ return padded;
+ } catch (GeneralSecurityException e) {
+ throw new ProviderException(e);
+ }
+ }
+
+ private byte[] encodeSignature(byte[] digest) throws SignatureException {
+ try {
+ return RSASignature.encodeSignature(digestOID, digest);
+ } catch (IOException e) {
+ throw new SignatureException("Invalid encoding", e);
+ }
+ }
+
+// private static byte[] decodeSignature(byte[] signature) throws IOException {
+// return RSASignature.decodeSignature(digestOID, signature);
+// }
+
+ // For DSA and ECDSA signatures, PKCS#11 represents them as a simple
+ // byte array that contains the concatenation of r and s.
+ // For DSA, r and s are always exactly 20 bytes long.
+ // For ECDSA, r and s are of variable length, but we know that each
+ // occupies half of the array.
+ private static byte[] dsaToASN1(byte[] signature) {
+ int n = signature.length >> 1;
+ BigInteger r = new BigInteger(1, P11Util.subarray(signature, 0, n));
+ BigInteger s = new BigInteger(1, P11Util.subarray(signature, n, n));
+ try {
+ DerOutputStream outseq = new DerOutputStream(100);
+ outseq.putInteger(r);
+ outseq.putInteger(s);
+ DerValue result = new DerValue(DerValue.tag_Sequence,
+ outseq.toByteArray());
+ return result.toByteArray();
+ } catch (java.io.IOException e) {
+ throw new RuntimeException("Internal error", e);
+ }
+ }
+
+ private static byte[] asn1ToDSA(byte[] signature) throws SignatureException {
+ try {
+ DerInputStream in = new DerInputStream(signature);
+ DerValue[] values = in.getSequence(2);
+ BigInteger r = values[0].getPositiveBigInteger();
+ BigInteger s = values[1].getPositiveBigInteger();
+
+ // Check for trailing signature data
+ if (in.available() != 0) {
+ throw new IOException("Incorrect signature length");
+ }
+ byte[] br = toByteArray(r, 20);
+ byte[] bs = toByteArray(s, 20);
+ if ((br == null) || (bs == null)) {
+ throw new SignatureException("Out of range value for R or S");
+ }
+ return P11Util.concat(br, bs);
+ } catch (SignatureException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new SignatureException("invalid encoding for signature", e);
+ }
+ }
+
+ private byte[] asn1ToECDSA(byte[] signature) throws SignatureException {
+ try {
+ DerInputStream in = new DerInputStream(signature);
+ DerValue[] values = in.getSequence(2);
+ BigInteger r = values[0].getPositiveBigInteger();
+ BigInteger s = values[1].getPositiveBigInteger();
+
+ // Check for trailing signature data
+ if (in.available() != 0) {
+ throw new IOException("Incorrect signature length");
+ }
+ // trim leading zeroes
+ byte[] br = KeyUtil.trimZeroes(r.toByteArray());
+ byte[] bs = KeyUtil.trimZeroes(s.toByteArray());
+ int k = Math.max(br.length, bs.length);
+ // r and s each occupy half the array
+ byte[] res = new byte[k << 1];
+ System.arraycopy(br, 0, res, k - br.length, br.length);
+ System.arraycopy(bs, 0, res, res.length - bs.length, bs.length);
+ return res;
+ } catch (Exception e) {
+ throw new SignatureException("invalid encoding for signature", e);
+ }
+ }
+
+ private static byte[] toByteArray(BigInteger bi, int len) {
+ byte[] b = bi.toByteArray();
+ int n = b.length;
+ if (n == len) {
+ return b;
+ }
+ if ((n == len + 1) && (b[0] == 0)) {
+ byte[] t = new byte[len];
+ System.arraycopy(b, 1, t, 0, len);
+ return t;
+ }
+ if (n > len) {
+ return null;
+ }
+ // must be smaller
+ byte[] t = new byte[len];
+ System.arraycopy(b, 0, t, (len - n), n);
+ return t;
+ }
+
+ // see JCA spec
+ @SuppressWarnings("deprecation")
+ protected void engineSetParameter(String param, Object value)
+ throws InvalidParameterException {
+ throw new UnsupportedOperationException("setParameter() not supported");
+ }
+
+ // see JCA spec
+ @SuppressWarnings("deprecation")
+ protected Object engineGetParameter(String param)
+ throws InvalidParameterException {
+ throw new UnsupportedOperationException("getParameter() not supported");
+ }
+}