/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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.
*/
/**
* Signature implementation class. This class currently supports the
* following algorithms:
*
* . DSA
* . NONEwithDSA (RawDSA)
* . SHA1withDSA
* . RSA:
* . MD2withRSA
* . MD5withRSA
* . SHA1withRSA
* . SHA256withRSA
* . SHA384withRSA
* . SHA512withRSA
* . ECDSA
* . NONEwithECDSA
* . SHA1withECDSA
* . SHA256withECDSA
* . SHA384withECDSA
* . SHA512withECDSA
*
* 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
*/
// token instance
// algorithm name
// name of the key algorithm, currently either RSA or DSA
// mechanism id
private final long mechanism;
// digest algorithm OID, if we encode RSA signature ourselves
// type, one of T_* below
private final int type;
// key instance used, if init*() was called
// message digest, if we do the digesting ourselves
// associated session, if any
// 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;
// constant for signing mode
// constant for verification mode
// constant for type digesting, we do the hashing ourselves
// constant for type update, token does everything
// constant for type raw, used with RawDSA and NONEwithECDSA only
// XXX PKCS#11 v2.20 says "should not be longer than 1024 bits",
// but this is a little arbitrary
throws NoSuchAlgorithmException, PKCS11Exception {
super();
switch ((int)mechanism) {
case (int)CKM_MD2_RSA_PKCS:
case (int)CKM_MD5_RSA_PKCS:
case (int)CKM_SHA1_RSA_PKCS:
case (int)CKM_SHA256_RSA_PKCS:
case (int)CKM_SHA384_RSA_PKCS:
case (int)CKM_SHA512_RSA_PKCS:
keyAlgorithm = "RSA";
buffer = new byte[1];
break;
case (int)CKM_DSA_SHA1:
keyAlgorithm = "DSA";
buffer = new byte[1];
break;
case (int)CKM_ECDSA_SHA1:
keyAlgorithm = "EC";
buffer = new byte[1];
break;
case (int)CKM_DSA:
keyAlgorithm = "DSA";
buffer = new byte[20];
} else {
throw new ProviderException(algorithm);
}
break;
case (int)CKM_ECDSA:
keyAlgorithm = "EC";
buffer = new byte[RAW_ECDSA_MAX];
} else {
digestAlg = "SHA-1";
digestAlg = "SHA-256";
digestAlg = "SHA-384";
digestAlg = "SHA-512";
} else {
throw new ProviderException(algorithm);
}
}
break;
case (int)CKM_RSA_PKCS:
case (int)CKM_RSA_X_509:
keyAlgorithm = "RSA";
} else {
}
break;
default:
}
}
private void ensureInitialized() {
token.ensureValid();
if (initialized == false) {
initialize();
}
}
private void cancelOperation() {
token.ensureValid();
if (initialized == false) {
return;
}
initialized = false;
return;
}
if (session.hasObjects() == false) {
return;
}
// "cancel" operation by finishing it
// XXX make sure all this always works correctly
try {
} else {
byte[] digest;
} else { // T_RAW
}
}
} catch (PKCS11Exception e) {
throw new ProviderException("cancel failed", e);
}
} else { // M_VERIFY
try {
byte[] signature;
signature = new byte[40];
} else {
}
} else {
byte[] digest;
} else { // T_RAW
}
}
} catch (PKCS11Exception e) {
// will fail since the signature is incorrect
// XXX check error code
}
}
}
// assumes current state is initialized == false
private void initialize() {
try {
}
} else {
}
initialized = true;
} catch (PKCS11Exception e) {
throw new ProviderException("Initialization failed", e);
}
if (bytesProcessed != 0) {
bytesProcessed = 0;
}
}
}
try {
} catch (InvalidAlgorithmParameterException iape) {
}
int encodedLength;
encodedLength = 34;
encodedLength = 35;
encodedLength = 51;
encodedLength = 67;
encodedLength = 83;
} else {
}
if (encodedLength > maxDataSize) {
throw new InvalidKeyException
("Key is too short for this signature algorithm");
}
}
// see JCA spec
throws InvalidKeyException {
throw new InvalidKeyException("Key must not be null");
}
// Need to check RSA key length whenever a new key is set
int keyLen;
} else {
}
}
initialize();
}
// see JCA spec
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
int keyLen;
if (privateKey instanceof P11Key) {
} else {
}
}
initialize();
}
// see JCA spec
switch (type) {
case T_UPDATE:
buffer[0] = (byte)b;
break;
case T_DIGEST:
break;
case T_RAW:
return;
}
buffer[bytesProcessed++] = b;
break;
default:
throw new ProviderException("Internal error");
}
}
// see JCA spec
throws SignatureException {
if (len == 0) {
return;
}
switch (type) {
case T_UPDATE:
try {
} else {
}
bytesProcessed += len;
} catch (PKCS11Exception e) {
throw new ProviderException(e);
}
break;
case T_DIGEST:
bytesProcessed += len;
break;
case T_RAW:
return;
}
bytesProcessed += len;
break;
default:
throw new ProviderException("Internal error");
}
}
// see JCA spec
if (len <= 0) {
return;
}
switch (type) {
case T_UPDATE:
if (byteBuffer instanceof DirectBuffer == false) {
// cannot do better than default impl
super.engineUpdate(byteBuffer);
return;
}
try {
} else {
}
bytesProcessed += len;
} catch (PKCS11Exception e) {
throw new ProviderException("Update failed", e);
}
break;
case T_DIGEST:
bytesProcessed += len;
break;
case T_RAW:
return;
}
bytesProcessed += len;
break;
default:
throw new ProviderException("Internal error");
}
}
// see JCA spec
try {
byte[] signature;
} else {
byte[] digest;
} else { // T_RAW
throw new SignatureException
("Data for RawDSA must be exactly 20 bytes long");
}
} else { // CKM_ECDSA
throw new SignatureException("Data for NONEwithECDSA"
}
digest = new byte[bytesProcessed];
}
}
// DSA and ECDSA
} else { // RSA
if (mechanism == CKM_RSA_X_509) {
}
}
}
} else {
return signature;
}
} catch (PKCS11Exception e) {
throw new ProviderException(e);
} finally {
initialized = false;
}
}
// see JCA spec
try {
}
} else {
byte[] digest;
} else { // T_RAW
throw new SignatureException
("Data for RawDSA must be exactly 20 bytes long");
}
} else {
throw new SignatureException("Data for NONEwithECDSA"
}
digest = new byte[bytesProcessed];
}
}
// DSA and ECDSA
} else { // RSA
if (mechanism == CKM_RSA_X_509) {
}
}
}
return true;
} catch (PKCS11Exception e) {
long errorCode = e.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(e);
} finally {
// XXX we should not release the session if we abort above
// before calling C_Verify
initialized = false;
}
}
try {
return padded;
} catch (GeneralSecurityException e) {
throw new ProviderException(e);
}
}
try {
} 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.
try {
outseq.putInteger(r);
outseq.putInteger(s);
outseq.toByteArray());
return result.toByteArray();
throw new RuntimeException("Internal error", e);
}
}
try {
throw new SignatureException("Out of range value for R or S");
}
} catch (SignatureException e) {
throw e;
} catch (Exception e) {
throw new SignatureException("invalid encoding for signature", e);
}
}
try {
// trim leading zeroes
// r and s each occupy half the array
byte[] res = new byte[k << 1];
return res;
} catch (Exception e) {
throw new SignatureException("invalid encoding for signature", e);
}
}
byte[] b = bi.toByteArray();
int n = b.length;
if (n == len) {
return b;
}
byte[] t = new byte[len];
return t;
}
if (n > len) {
return null;
}
// must be smaller
byte[] t = new byte[len];
return t;
}
// see JCA spec
throws InvalidParameterException {
throw new UnsupportedOperationException("setParameter() not supported");
}
// see JCA spec
throws InvalidParameterException {
throw new UnsupportedOperationException("getParameter() not supported");
}
}