|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.security.pkcs11; |
|
|
|
import java.io.IOException; |
|
import java.math.BigInteger; |
|
import java.nio.ByteBuffer; |
|
|
|
import java.security.*; |
|
import java.security.interfaces.*; |
|
import java.security.spec.AlgorithmParameterSpec; |
|
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; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
final class P11Signature extends SignatureSpi { |
|
|
|
|
|
private final Token token; |
|
|
|
|
|
private final String algorithm; |
|
|
|
|
|
private final String keyAlgorithm; |
|
|
|
|
|
private final long mechanism; |
|
|
|
|
|
private final ObjectIdentifier digestOID; |
|
|
|
|
|
private final int type; |
|
|
|
|
|
private P11Key p11Key; |
|
|
|
|
|
private final MessageDigest md; |
|
|
|
|
|
private Session session; |
|
|
|
|
|
private int mode; |
|
|
|
|
|
private boolean initialized; |
|
|
|
|
|
private final byte[] buffer; |
|
|
|
|
|
private int bytesProcessed; |
|
|
|
|
|
private final static int M_SIGN = 1; |
|
|
|
private final static int M_VERIFY = 2; |
|
|
|
|
|
private final static int T_DIGEST = 1; |
|
|
|
private final static int T_UPDATE = 2; |
|
|
|
private final static int T_RAW = 3; |
|
|
|
// XXX PKCS#11 v2.20 says "should not be longer than 1024 bits", |
|
|
|
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")) { |
|
type = T_DIGEST; |
|
md = MessageDigest.getInstance("SHA-1"); |
|
} else if (algorithm.equals("RawDSA")) { |
|
type = T_RAW; |
|
buffer = new byte[20]; |
|
} else { |
|
throw new ProviderException(algorithm); |
|
} |
|
break; |
|
case (int)CKM_ECDSA: |
|
keyAlgorithm = "EC"; |
|
if (algorithm.equals("NONEwithECDSA")) { |
|
type = T_RAW; |
|
buffer = new byte[RAW_ECDSA_MAX]; |
|
} else { |
|
String digestAlg; |
|
if (algorithm.equals("SHA1withECDSA")) { |
|
digestAlg = "SHA-1"; |
|
} else if (algorithm.equals("SHA224withECDSA")) { |
|
digestAlg = "SHA-224"; |
|
} else if (algorithm.equals("SHA256withECDSA")) { |
|
digestAlg = "SHA-256"; |
|
} else if (algorithm.equals("SHA384withECDSA")) { |
|
digestAlg = "SHA-384"; |
|
} else if (algorithm.equals("SHA512withECDSA")) { |
|
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; |
|
} |
|
|
|
|
|
private void reset(boolean doCancel) { |
|
|
|
if (!initialized) { |
|
return; |
|
} |
|
initialized = false; |
|
|
|
try { |
|
if (session == null) { |
|
return; |
|
} |
|
|
|
if (doCancel && token.explicitCancel) { |
|
cancelOperation(); |
|
} |
|
} finally { |
|
p11Key.releaseKeyID(); |
|
session = token.releaseSession(session); |
|
} |
|
} |
|
|
|
private void cancelOperation() { |
|
token.ensureValid(); |
|
// cancel operation by finishing it; avoid killSession as some |
|
|
|
try { |
|
if (mode == M_SIGN) { |
|
if (type == T_UPDATE) { |
|
token.p11.C_SignFinal(session.id(), 0); |
|
} else { |
|
byte[] digest; |
|
if (type == T_DIGEST) { |
|
digest = md.digest(); |
|
} else { |
|
digest = buffer; |
|
} |
|
token.p11.C_Sign(session.id(), digest); |
|
} |
|
} else { |
|
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 { |
|
digest = buffer; |
|
} |
|
token.p11.C_Verify(session.id(), digest, signature); |
|
} |
|
} |
|
} catch (PKCS11Exception e) { |
|
if (e.getErrorCode() == CKR_OPERATION_NOT_INITIALIZED) { |
|
// Cancel Operation may be invoked after an error on a PKCS#11 |
|
// call. If the operation inside the token was already cancelled, |
|
// do not fail here. This is part of a defensive mechanism for |
|
|
|
return; |
|
} |
|
if (mode == M_VERIFY) { |
|
long errorCode = e.getErrorCode(); |
|
if ((errorCode == CKR_SIGNATURE_INVALID) || |
|
(errorCode == CKR_SIGNATURE_LEN_RANGE)) { |
|
|
|
return; |
|
} |
|
} |
|
throw new ProviderException("cancel failed", e); |
|
} |
|
} |
|
|
|
private void ensureInitialized() { |
|
|
|
if (!initialized) { |
|
initialize(); |
|
} |
|
} |
|
|
|
|
|
private void initialize() { |
|
|
|
if (p11Key == null) { |
|
throw new ProviderException( |
|
"Operation cannot be performed without " + |
|
"calling engineInit first"); |
|
} |
|
long keyID = p11Key.getKeyID(); |
|
try { |
|
token.ensureValid(); |
|
if (session == null) { |
|
session = token.getOpSession(); |
|
} |
|
if (mode == M_SIGN) { |
|
token.p11.C_SignInit(session.id(), |
|
new CK_MECHANISM(mechanism), keyID); |
|
} else { |
|
token.p11.C_VerifyInit(session.id(), |
|
new CK_MECHANISM(mechanism), keyID); |
|
} |
|
} catch (PKCS11Exception e) { |
|
p11Key.releaseKeyID(); |
|
session = token.releaseSession(session); |
|
throw new ProviderException("Initialization failed", e); |
|
} |
|
if (bytesProcessed != 0) { |
|
bytesProcessed = 0; |
|
if (md != null) { |
|
md.reset(); |
|
} |
|
} |
|
initialized = true; |
|
} |
|
|
|
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) { |
|
|
|
return; |
|
} |
|
int minKeySize = (int) mechInfo.ulMinKeySize; |
|
int maxKeySize = (int) mechInfo.ulMaxKeySize; |
|
|
|
if (md != null && mechanism == CKM_DSA && maxKeySize > 1024) { |
|
maxKeySize = 1024; |
|
} |
|
int keySize = 0; |
|
if (key instanceof P11Key) { |
|
keySize = ((P11Key) key).length(); |
|
} else { |
|
try { |
|
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); |
|
} |
|
} catch (ClassCastException cce) { |
|
throw new InvalidKeyException(keyAlgo + |
|
" key must be the right type", cce); |
|
} |
|
} |
|
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"); |
|
} |
|
} |
|
|
|
|
|
@Override |
|
protected void engineInitVerify(PublicKey publicKey) |
|
throws InvalidKeyException { |
|
if (publicKey == null) { |
|
throw new InvalidKeyException("Key must not be null"); |
|
} |
|
|
|
if (publicKey != p11Key) { |
|
checkKeySize(keyAlgorithm, publicKey); |
|
} |
|
reset(true); |
|
mode = M_VERIFY; |
|
p11Key = P11KeyFactory.convertKey(token, publicKey, keyAlgorithm); |
|
initialize(); |
|
} |
|
|
|
|
|
@Override |
|
protected void engineInitSign(PrivateKey privateKey) |
|
throws InvalidKeyException { |
|
if (privateKey == null) { |
|
throw new InvalidKeyException("Key must not be null"); |
|
} |
|
|
|
if (privateKey != p11Key) { |
|
checkKeySize(keyAlgorithm, privateKey); |
|
} |
|
reset(true); |
|
mode = M_SIGN; |
|
p11Key = P11KeyFactory.convertKey(token, privateKey, keyAlgorithm); |
|
initialize(); |
|
} |
|
|
|
|
|
@Override |
|
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"); |
|
} |
|
} |
|
|
|
|
|
@Override |
|
protected void engineUpdate(byte[] b, int ofs, int len) |
|
throws SignatureException { |
|
|
|
ensureInitialized(); |
|
if (len == 0) { |
|
return; |
|
} |
|
|
|
if (len + bytesProcessed < 0) { |
|
throw new ProviderException("Processed bytes limits exceeded."); |
|
} |
|
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) { |
|
reset(false); |
|
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"); |
|
} |
|
} |
|
|
|
|
|
@Override |
|
protected void engineUpdate(ByteBuffer byteBuffer) { |
|
|
|
ensureInitialized(); |
|
int len = byteBuffer.remaining(); |
|
if (len <= 0) { |
|
return; |
|
} |
|
switch (type) { |
|
case T_UPDATE: |
|
if (byteBuffer instanceof DirectBuffer == false) { |
|
|
|
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) { |
|
reset(false); |
|
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: |
|
reset(false); |
|
throw new ProviderException("Internal error"); |
|
} |
|
} |
|
|
|
|
|
@Override |
|
protected byte[] engineSign() throws SignatureException { |
|
|
|
ensureInitialized(); |
|
boolean doCancel = true; |
|
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 { |
|
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) { |
|
|
|
signature = token.p11.C_Sign(session.id(), digest); |
|
} else { |
|
byte[] data = encodeSignature(digest); |
|
if (mechanism == CKM_RSA_X_509) { |
|
data = pkcs1Pad(data); |
|
} |
|
signature = token.p11.C_Sign(session.id(), data); |
|
} |
|
} |
|
doCancel = false; |
|
|
|
if (keyAlgorithm.equals("RSA") == false) { |
|
return dsaToASN1(signature); |
|
} else { |
|
return signature; |
|
} |
|
} catch (PKCS11Exception e) { |
|
// As per the PKCS#11 standard, C_Sign and C_SignFinal may only |
|
// keep the operation active on CKR_BUFFER_TOO_SMALL errors or |
|
// successful calls to determine the output length. However, |
|
// these cases are handled at OpenJDK's libj2pkcs11 native |
|
|
|
doCancel = false; |
|
throw new ProviderException(e); |
|
} finally { |
|
reset(doCancel); |
|
} |
|
} |
|
|
|
|
|
@Override |
|
protected boolean engineVerify(byte[] signature) throws SignatureException { |
|
ensureInitialized(); |
|
boolean doCancel = true; |
|
try { |
|
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 { |
|
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) { |
|
|
|
token.p11.C_Verify(session.id(), digest, signature); |
|
} else { |
|
byte[] data = encodeSignature(digest); |
|
if (mechanism == CKM_RSA_X_509) { |
|
data = pkcs1Pad(data); |
|
} |
|
token.p11.C_Verify(session.id(), data, signature); |
|
} |
|
} |
|
doCancel = false; |
|
return true; |
|
} catch (PKCS11Exception e) { |
|
doCancel = false; |
|
long errorCode = e.getErrorCode(); |
|
if (errorCode == CKR_SIGNATURE_INVALID) { |
|
return false; |
|
} |
|
if (errorCode == CKR_SIGNATURE_LEN_RANGE) { |
|
|
|
return false; |
|
} |
|
|
|
if (errorCode == CKR_DATA_LEN_RANGE) { |
|
return false; |
|
} |
|
throw new ProviderException(e); |
|
} finally { |
|
reset(doCancel); |
|
} |
|
} |
|
|
|
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 |
|
|
|
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[] sig) throws SignatureException { |
|
try { |
|
|
|
DerInputStream in = new DerInputStream(sig, 0, sig.length, false); |
|
DerValue[] values = in.getSequence(2); |
|
|
|
// check number of components in the read sequence |
|
|
|
if ((values.length != 2) || (in.available() != 0)) { |
|
throw new IOException("Invalid encoding for signature"); |
|
} |
|
|
|
BigInteger r = values[0].getPositiveBigInteger(); |
|
BigInteger s = values[1].getPositiveBigInteger(); |
|
|
|
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[] sig) throws SignatureException { |
|
try { |
|
|
|
DerInputStream in = new DerInputStream(sig, 0, sig.length, false); |
|
DerValue[] values = in.getSequence(2); |
|
|
|
// check number of components in the read sequence |
|
|
|
if ((values.length != 2) || (in.available() != 0)) { |
|
throw new IOException("Invalid encoding for signature"); |
|
} |
|
|
|
BigInteger r = values[0].getPositiveBigInteger(); |
|
BigInteger s = values[1].getPositiveBigInteger(); |
|
|
|
|
|
byte[] br = KeyUtil.trimZeroes(r.toByteArray()); |
|
byte[] bs = KeyUtil.trimZeroes(s.toByteArray()); |
|
int k = Math.max(br.length, bs.length); |
|
|
|
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; |
|
} |
|
|
|
byte[] t = new byte[len]; |
|
System.arraycopy(b, 0, t, (len - n), n); |
|
return t; |
|
} |
|
|
|
|
|
@Override |
|
protected void engineSetParameter(String param, Object value) |
|
throws InvalidParameterException { |
|
throw new UnsupportedOperationException("setParameter() not supported"); |
|
} |
|
|
|
|
|
@Override |
|
protected void engineSetParameter(AlgorithmParameterSpec params) |
|
throws InvalidAlgorithmParameterException { |
|
if (params != null) { |
|
throw new InvalidAlgorithmParameterException("No parameter accepted"); |
|
} |
|
} |
|
|
|
|
|
@Override |
|
protected Object engineGetParameter(String param) |
|
throws InvalidParameterException { |
|
throw new UnsupportedOperationException("getParameter() not supported"); |
|
} |
|
|
|
|
|
@Override |
|
protected AlgorithmParameters engineGetParameters() { |
|
return null; |
|
} |
|
} |