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