--- a/jdk/src/share/classes/sun/net/www/protocol/http/NegotiatorImpl.java Thu Mar 27 14:15:59 2008 -0700
+++ b/jdk/src/share/classes/sun/net/www/protocol/http/NegotiatorImpl.java Fri Mar 28 12:56:34 2008 -0700
@@ -91,9 +91,10 @@
GSSManagerImpl manager = new GSSManagerImpl(
GSSUtil.CALLER_HTTP_NEGOTIATE);
- String peerName = "HTTP/" + hostname;
+ String peerName = "HTTP@" + hostname;
- GSSName serverName = manager.createName(peerName, null);
+ GSSName serverName = manager.createName(peerName,
+ GSSName.NT_HOSTBASED_SERVICE);
context = manager.createContext(serverName,
oid,
null,
--- a/jdk/src/share/classes/sun/security/pkcs11/P11Cipher.java Thu Mar 27 14:15:59 2008 -0700
+++ b/jdk/src/share/classes/sun/security/pkcs11/P11Cipher.java Fri Mar 28 12:56:34 2008 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2008 Sun Microsystems, Inc. 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
@@ -22,10 +22,10 @@
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
-
package sun.security.pkcs11;
import java.nio.ByteBuffer;
+import java.util.Arrays;
import java.security.*;
import java.security.spec.*;
@@ -34,7 +34,6 @@
import javax.crypto.spec.*;
import sun.nio.ch.DirectBuffer;
-
import sun.security.pkcs11.wrapper.*;
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
@@ -43,8 +42,8 @@
* DES, DESede, AES, ARCFOUR, and Blowfish.
*
* This class is designed to support ECB and CBC with NoPadding and
- * PKCS5Padding for both. However, currently only CBC/NoPadding (and
- * ECB/NoPadding for stream ciphers) is functional.
+ * PKCS5Padding for both. It will use its own padding impl if the
+ * native mechanism does not support padding.
*
* Note that PKCS#11 current only supports ECB and CBC. There are no
* provisions for other modes such as CFB, OFB, PCBC, or CTR mode.
@@ -62,10 +61,56 @@
private final static int MODE_CBC = 4;
// padding constant for NoPadding
- private final static int PAD_NONE = 5;
+ private final static int PAD_NONE = 5;
// padding constant for PKCS5Padding
private final static int PAD_PKCS5 = 6;
+ private static interface Padding {
+ // ENC: format the specified buffer with padding bytes and return the
+ // actual padding length
+ int setPaddingBytes(byte[] paddingBuffer, int padLen);
+
+ // DEC: return the length of trailing padding bytes given the specified
+ // padded data
+ int unpad(byte[] paddedData, int ofs, int len)
+ throws BadPaddingException;
+ }
+
+ private static class PKCS5Padding implements Padding {
+
+ private final int blockSize;
+
+ PKCS5Padding(int blockSize)
+ throws NoSuchPaddingException {
+ if (blockSize == 0) {
+ throw new NoSuchPaddingException
+ ("PKCS#5 padding not supported with stream ciphers");
+ }
+ this.blockSize = blockSize;
+ }
+
+ public int setPaddingBytes(byte[] paddingBuffer, int padLen) {
+ Arrays.fill(paddingBuffer, 0, padLen, (byte) (padLen & 0x007f));
+ return padLen;
+ }
+
+ public int unpad(byte[] paddedData, int ofs, int len)
+ throws BadPaddingException {
+ byte padValue = paddedData[ofs + len - 1];
+ if (padValue < 1 || padValue > blockSize) {
+ throw new BadPaddingException("Invalid pad value!");
+ }
+ // sanity check padding bytes
+ int padStartIndex = ofs + len - padValue;
+ for (int i = padStartIndex; i < len; i++) {
+ if (paddedData[i] != padValue) {
+ throw new BadPaddingException("Invalid pad bytes!");
+ }
+ }
+ return padValue;
+ }
+ }
+
// token instance
private final Token token;
@@ -99,65 +144,93 @@
// padding type, on of PAD_* above (PAD_NONE for stream ciphers)
private int paddingType;
+ // when the padding is requested but unsupported by the native mechanism,
+ // we use the following to do padding and necessary data buffering.
+ // padding object which generate padding and unpad the decrypted data
+ private Padding paddingObj;
+ // buffer for holding back the block which contains padding bytes
+ private byte[] padBuffer;
+ private int padBufferLen;
+
// original IV, if in MODE_CBC
private byte[] iv;
- // total number of bytes processed
- private int bytesProcessed;
+ // number of bytes buffered internally by the native mechanism and padBuffer
+ // if we do the padding
+ private int bytesBuffered;
P11Cipher(Token token, String algorithm, long mechanism)
- throws PKCS11Exception {
+ throws PKCS11Exception, NoSuchAlgorithmException {
super();
this.token = token;
this.algorithm = algorithm;
this.mechanism = mechanism;
- keyAlgorithm = algorithm.split("/")[0];
+
+ String algoParts[] = algorithm.split("/");
+ keyAlgorithm = algoParts[0];
+
if (keyAlgorithm.equals("AES")) {
blockSize = 16;
- blockMode = MODE_CBC;
- // XXX change default to PKCS5Padding
- paddingType = PAD_NONE;
- } else if (keyAlgorithm.equals("RC4") || keyAlgorithm.equals("ARCFOUR")) {
+ } else if (keyAlgorithm.equals("RC4") ||
+ keyAlgorithm.equals("ARCFOUR")) {
blockSize = 0;
- blockMode = MODE_ECB;
- paddingType = PAD_NONE;
} else { // DES, DESede, Blowfish
blockSize = 8;
- blockMode = MODE_CBC;
- // XXX change default to PKCS5Padding
- paddingType = PAD_NONE;
+ }
+ this.blockMode =
+ (algoParts.length > 1 ? parseMode(algoParts[1]) : MODE_ECB);
+
+ String defPadding = (blockSize == 0 ? "NoPadding" : "PKCS5Padding");
+ String paddingStr =
+ (algoParts.length > 2 ? algoParts[2] : defPadding);
+ try {
+ engineSetPadding(paddingStr);
+ } catch (NoSuchPaddingException nspe) {
+ // should not happen
+ throw new ProviderException(nspe);
}
session = token.getOpSession();
}
protected void engineSetMode(String mode) throws NoSuchAlgorithmException {
+ // Disallow change of mode for now since currently it's explicitly
+ // defined in transformation strings
+ throw new NoSuchAlgorithmException("Unsupported mode " + mode);
+ }
+
+ private int parseMode(String mode) throws NoSuchAlgorithmException {
mode = mode.toUpperCase();
+ int result;
if (mode.equals("ECB")) {
- this.blockMode = MODE_ECB;
+ result = MODE_ECB;
} else if (mode.equals("CBC")) {
if (blockSize == 0) {
throw new NoSuchAlgorithmException
("CBC mode not supported with stream ciphers");
}
- this.blockMode = MODE_CBC;
+ result = MODE_CBC;
} else {
throw new NoSuchAlgorithmException("Unsupported mode " + mode);
}
+ return result;
}
// see JCE spec
protected void engineSetPadding(String padding)
throws NoSuchPaddingException {
- if (padding.equalsIgnoreCase("NoPadding")) {
+ paddingObj = null;
+ padBuffer = null;
+ padding = padding.toUpperCase();
+ if (padding.equals("NOPADDING")) {
paddingType = PAD_NONE;
- } else if (padding.equalsIgnoreCase("PKCS5Padding")) {
- if (blockSize == 0) {
- throw new NoSuchPaddingException
- ("PKCS#5 padding not supported with stream ciphers");
+ } else if (padding.equals("PKCS5PADDING")) {
+ paddingType = PAD_PKCS5;
+ if (mechanism != CKM_DES_CBC_PAD && mechanism != CKM_DES3_CBC_PAD &&
+ mechanism != CKM_AES_CBC_PAD) {
+ // no native padding support; use our own padding impl
+ paddingObj = new PKCS5Padding(blockSize);
+ padBuffer = new byte[blockSize];
}
- paddingType = PAD_PKCS5;
- // XXX PKCS#5 not yet implemented
- throw new NoSuchPaddingException("pkcs5");
} else {
throw new NoSuchPaddingException("Unsupported padding " + padding);
}
@@ -175,7 +248,7 @@
// see JCE spec
protected byte[] engineGetIV() {
- return (iv == null) ? null : (byte[])iv.clone();
+ return (iv == null) ? null : (byte[]) iv.clone();
}
// see JCE spec
@@ -185,8 +258,9 @@
}
IvParameterSpec ivSpec = new IvParameterSpec(iv);
try {
- AlgorithmParameters params = AlgorithmParameters.getInstance
- (keyAlgorithm, P11Util.getSunJceProvider());
+ AlgorithmParameters params =
+ AlgorithmParameters.getInstance(keyAlgorithm,
+ P11Util.getSunJceProvider());
params.init(ivSpec);
return params;
} catch (GeneralSecurityException e) {
@@ -210,38 +284,38 @@
protected void engineInit(int opmode, Key key,
AlgorithmParameterSpec params, SecureRandom random)
throws InvalidKeyException, InvalidAlgorithmParameterException {
- byte[] iv;
+ byte[] ivValue;
if (params != null) {
if (params instanceof IvParameterSpec == false) {
throw new InvalidAlgorithmParameterException
("Only IvParameterSpec supported");
}
- IvParameterSpec ivSpec = (IvParameterSpec)params;
- iv = ivSpec.getIV();
+ IvParameterSpec ivSpec = (IvParameterSpec) params;
+ ivValue = ivSpec.getIV();
} else {
- iv = null;
+ ivValue = null;
}
- implInit(opmode, key, iv, random);
+ implInit(opmode, key, ivValue, random);
}
// see JCE spec
protected void engineInit(int opmode, Key key, AlgorithmParameters params,
SecureRandom random)
throws InvalidKeyException, InvalidAlgorithmParameterException {
- byte[] iv;
+ byte[] ivValue;
if (params != null) {
try {
IvParameterSpec ivSpec = (IvParameterSpec)
params.getParameterSpec(IvParameterSpec.class);
- iv = ivSpec.getIV();
+ ivValue = ivSpec.getIV();
} catch (InvalidParameterSpecException e) {
throw new InvalidAlgorithmParameterException
("Could not decode IV", e);
}
} else {
- iv = null;
+ ivValue = null;
}
- implInit(opmode, key, iv, random);
+ implInit(opmode, key, ivValue, random);
}
// actual init() implementation
@@ -250,31 +324,31 @@
throws InvalidKeyException, InvalidAlgorithmParameterException {
cancelOperation();
switch (opmode) {
- case Cipher.ENCRYPT_MODE:
- encrypt = true;
- break;
- case Cipher.DECRYPT_MODE:
- encrypt = false;
- break;
- default:
- throw new InvalidAlgorithmParameterException
- ("Unsupported mode: " + opmode);
+ case Cipher.ENCRYPT_MODE:
+ encrypt = true;
+ break;
+ case Cipher.DECRYPT_MODE:
+ encrypt = false;
+ break;
+ default:
+ throw new InvalidAlgorithmParameterException
+ ("Unsupported mode: " + opmode);
}
if (blockMode == MODE_ECB) { // ECB or stream cipher
if (iv != null) {
if (blockSize == 0) {
throw new InvalidAlgorithmParameterException
- ("IV not used with stream ciphers");
+ ("IV not used with stream ciphers");
} else {
throw new InvalidAlgorithmParameterException
- ("IV not used in ECB mode");
+ ("IV not used in ECB mode");
}
}
} else { // MODE_CBC
if (iv == null) {
if (encrypt == false) {
throw new InvalidAlgorithmParameterException
- ("IV must be specified for decryption in CBC mode");
+ ("IV must be specified for decryption in CBC mode");
}
// generate random IV
if (random == null) {
@@ -285,7 +359,7 @@
} else {
if (iv.length != blockSize) {
throw new InvalidAlgorithmParameterException
- ("IV length must match block size");
+ ("IV length must match block size");
}
}
}
@@ -331,63 +405,43 @@
session = token.getOpSession();
}
if (encrypt) {
- token.p11.C_EncryptInit
- (session.id(), new CK_MECHANISM(mechanism, iv), p11Key.keyID);
+ token.p11.C_EncryptInit(session.id(),
+ new CK_MECHANISM(mechanism, iv), p11Key.keyID);
} else {
- token.p11.C_DecryptInit
- (session.id(), new CK_MECHANISM(mechanism, iv), p11Key.keyID);
+ token.p11.C_DecryptInit(session.id(),
+ new CK_MECHANISM(mechanism, iv), p11Key.keyID);
}
- bytesProcessed = 0;
+ bytesBuffered = 0;
+ padBufferLen = 0;
initialized = true;
}
- // XXX the calculations below assume the PKCS#11 implementation is smart.
- // conceivably, not all implementations are and we may need to estimate
- // more conservatively
-
- private int bytesBuffered(int totalLen) {
- if (paddingType == PAD_NONE) {
- // with NoPadding, buffer only the current unfinished block
- return totalLen & (blockSize - 1);
- } else { // PKCS5
- // with PKCS5Padding in decrypt mode, the buffer must never
- // be empty. Buffer a full block instead of nothing.
- int buffered = totalLen & (blockSize - 1);
- if ((buffered == 0) && (encrypt == false)) {
- buffered = blockSize;
- }
- return buffered;
- }
- }
-
// if update(inLen) is called, how big does the output buffer have to be?
private int updateLength(int inLen) {
if (inLen <= 0) {
return 0;
}
- if (blockSize == 0) {
- return inLen;
- } else {
- // bytes that need to be buffered now
- int buffered = bytesBuffered(bytesProcessed);
- // bytes that need to be buffered after this update
- int newBuffered = bytesBuffered(bytesProcessed + inLen);
- return inLen + buffered - newBuffered;
+
+ int result = inLen + bytesBuffered;
+ if (blockSize != 0) {
+ // minus the number of bytes in the last incomplete block.
+ result -= (result & (blockSize - 1));
}
+ return result;
}
// if doFinal(inLen) is called, how big does the output buffer have to be?
private int doFinalLength(int inLen) {
- if (paddingType == PAD_NONE) {
- return updateLength(inLen);
- }
if (inLen < 0) {
return 0;
}
- int buffered = bytesBuffered(bytesProcessed);
- int newProcessed = bytesProcessed + inLen;
- int paddedProcessed = (newProcessed + blockSize) & ~(blockSize - 1);
- return paddedProcessed - bytesProcessed + buffered;
+
+ int result = inLen + bytesBuffered;
+ if (blockSize != 0 && encrypt && paddingType != PAD_NONE) {
+ // add the number of bytes to make the last block complete.
+ result += (blockSize - (result & (blockSize - 1)));
+ }
+ return result;
}
// see JCE spec
@@ -397,6 +451,7 @@
int n = engineUpdate(in, inOfs, inLen, out, 0);
return P11Util.convert(out, 0, n);
} catch (ShortBufferException e) {
+ // convert since the output length is calculated by updateLength()
throw new ProviderException(e);
}
}
@@ -409,6 +464,7 @@
}
// see JCE spec
+ @Override
protected int engineUpdate(ByteBuffer inBuffer, ByteBuffer outBuffer)
throws ShortBufferException {
return implUpdate(inBuffer, outBuffer);
@@ -422,14 +478,15 @@
int n = engineDoFinal(in, inOfs, inLen, out, 0);
return P11Util.convert(out, 0, n);
} catch (ShortBufferException e) {
+ // convert since the output length is calculated by doFinalLength()
throw new ProviderException(e);
}
}
// see JCE spec
protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out,
- int outOfs) throws ShortBufferException, IllegalBlockSizeException {
- // BadPaddingException {
+ int outOfs) throws ShortBufferException, IllegalBlockSizeException,
+ BadPaddingException {
int n = 0;
if ((inLen != 0) && (in != null)) {
n = engineUpdate(in, inOfs, inLen, out, outOfs);
@@ -440,8 +497,10 @@
}
// see JCE spec
+ @Override
protected int engineDoFinal(ByteBuffer inBuffer, ByteBuffer outBuffer)
- throws ShortBufferException, IllegalBlockSizeException, BadPaddingException {
+ throws ShortBufferException, IllegalBlockSizeException,
+ BadPaddingException {
int n = engineUpdate(inBuffer, outBuffer);
n += implDoFinal(outBuffer);
return n;
@@ -454,18 +513,55 @@
}
try {
ensureInitialized();
- int k;
+ int k = 0;
if (encrypt) {
- k = token.p11.C_EncryptUpdate
- (session.id(), 0, in, inOfs, inLen, 0, out, outOfs, outLen);
+ k = token.p11.C_EncryptUpdate(session.id(), 0, in, inOfs, inLen,
+ 0, out, outOfs, outLen);
} else {
- k = token.p11.C_DecryptUpdate
- (session.id(), 0, in, inOfs, inLen, 0, out, outOfs, outLen);
+ int newPadBufferLen = 0;
+ if (paddingObj != null) {
+ if (padBufferLen != 0) {
+ // NSS throws up when called with data not in multiple
+ // of blocks. Try to work around this by holding the
+ // extra data in padBuffer.
+ if (padBufferLen != padBuffer.length) {
+ int bufCapacity = padBuffer.length - padBufferLen;
+ if (inLen > bufCapacity) {
+ bufferInputBytes(in, inOfs, bufCapacity);
+ inOfs += bufCapacity;
+ inLen -= bufCapacity;
+ } else {
+ bufferInputBytes(in, inOfs, inLen);
+ return 0;
+ }
+ }
+ k = token.p11.C_DecryptUpdate(session.id(),
+ 0, padBuffer, 0, padBufferLen,
+ 0, out, outOfs, outLen);
+ padBufferLen = 0;
+ }
+ newPadBufferLen = inLen & (blockSize - 1);
+ if (newPadBufferLen == 0) {
+ newPadBufferLen = padBuffer.length;
+ }
+ inLen -= newPadBufferLen;
+ }
+ if (inLen > 0) {
+ k += token.p11.C_DecryptUpdate(session.id(), 0, in, inOfs,
+ inLen, 0, out, (outOfs + k), (outLen - k));
+ }
+ // update 'padBuffer' if using our own padding impl.
+ if (paddingObj != null) {
+ bufferInputBytes(in, inOfs + inLen, newPadBufferLen);
+ }
}
- bytesProcessed += inLen;
+ bytesBuffered += (inLen - k);
return k;
} catch (PKCS11Exception e) {
- // XXX throw correct exception
+ if (e.getErrorCode() == CKR_BUFFER_TOO_SMALL) {
+ throw (ShortBufferException)
+ (new ShortBufferException().initCause(e));
+ }
throw new ProviderException("update() failed", e);
}
}
@@ -481,101 +577,167 @@
if (outLen < updateLength(inLen)) {
throw new ShortBufferException();
}
- boolean inPosChanged = false;
+ int origPos = inBuffer.position();
try {
ensureInitialized();
long inAddr = 0;
- int inOfs = inBuffer.position();
+ int inOfs = 0;
byte[] inArray = null;
+
if (inBuffer instanceof DirectBuffer) {
- inAddr = ((DirectBuffer)inBuffer).address();
- } else {
- if (inBuffer.hasArray()) {
- inArray = inBuffer.array();
- inOfs += inBuffer.arrayOffset();
- } else {
- inArray = new byte[inLen];
- inBuffer.get(inArray);
- inOfs = 0;
- inPosChanged = true;
- }
+ inAddr = ((DirectBuffer) inBuffer).address();
+ inOfs = origPos;
+ } else if (inBuffer.hasArray()) {
+ inArray = inBuffer.array();
+ inOfs = (origPos + inBuffer.arrayOffset());
}
long outAddr = 0;
- int outOfs = outBuffer.position();
+ int outOfs = 0;
byte[] outArray = null;
if (outBuffer instanceof DirectBuffer) {
- outAddr = ((DirectBuffer)outBuffer).address();
+ outAddr = ((DirectBuffer) outBuffer).address();
+ outOfs = outBuffer.position();
} else {
if (outBuffer.hasArray()) {
outArray = outBuffer.array();
- outOfs += outBuffer.arrayOffset();
+ outOfs = (outBuffer.position() + outBuffer.arrayOffset());
} else {
outArray = new byte[outLen];
- outOfs = 0;
}
}
- int k;
+ int k = 0;
if (encrypt) {
- k = token.p11.C_EncryptUpdate
- (session.id(), inAddr, inArray, inOfs, inLen,
- outAddr, outArray, outOfs, outLen);
+ if (inAddr == 0 && inArray == null) {
+ inArray = new byte[inLen];
+ inBuffer.get(inArray);
+ } else {
+ inBuffer.position(origPos + inLen);
+ }
+ k = token.p11.C_EncryptUpdate(session.id(),
+ inAddr, inArray, inOfs, inLen,
+ outAddr, outArray, outOfs, outLen);
} else {
- k = token.p11.C_DecryptUpdate
- (session.id(), inAddr, inArray, inOfs, inLen,
- outAddr, outArray, outOfs, outLen);
+ int newPadBufferLen = 0;
+ if (paddingObj != null) {
+ if (padBufferLen != 0) {
+ // NSS throws up when called with data not in multiple
+ // of blocks. Try to work around this by holding the
+ // extra data in padBuffer.
+ if (padBufferLen != padBuffer.length) {
+ int bufCapacity = padBuffer.length - padBufferLen;
+ if (inLen > bufCapacity) {
+ bufferInputBytes(inBuffer, bufCapacity);
+ inOfs += bufCapacity;
+ inLen -= bufCapacity;
+ } else {
+ bufferInputBytes(inBuffer, inLen);
+ return 0;
+ }
+ }
+ k = token.p11.C_DecryptUpdate(session.id(), 0,
+ padBuffer, 0, padBufferLen, outAddr, outArray,
+ outOfs, outLen);
+ padBufferLen = 0;
+ }
+ newPadBufferLen = inLen & (blockSize - 1);
+ if (newPadBufferLen == 0) {
+ newPadBufferLen = padBuffer.length;
+ }
+ inLen -= newPadBufferLen;
+ }
+ if (inLen > 0) {
+ if (inAddr == 0 && inArray == null) {
+ inArray = new byte[inLen];
+ inBuffer.get(inArray);
+ } else {
+ inBuffer.position(inBuffer.position() + inLen);
+ }
+ k += token.p11.C_DecryptUpdate(session.id(), inAddr,
+ inArray, inOfs, inLen, outAddr, outArray,
+ (outOfs + k), (outLen - k));
+ }
+ // update 'padBuffer' if using our own padding impl.
+ if (paddingObj != null && newPadBufferLen != 0) {
+ bufferInputBytes(inBuffer, newPadBufferLen);
+ }
}
- bytesProcessed += inLen;
- if (!inPosChanged) {
- inBuffer.position(inBuffer.position() + inLen);
- }
+ bytesBuffered += (inLen - k);
if (!(outBuffer instanceof DirectBuffer) &&
- !outBuffer.hasArray()) {
+ !outBuffer.hasArray()) {
outBuffer.put(outArray, outOfs, k);
} else {
outBuffer.position(outBuffer.position() + k);
}
return k;
} catch (PKCS11Exception e) {
- // Un-read the bytes back to input buffer
- if (inPosChanged) {
- inBuffer.position(inBuffer.position() - inLen);
+ // Reset input buffer to its original position for
+ inBuffer.position(origPos);
+ if (e.getErrorCode() == CKR_BUFFER_TOO_SMALL) {
+ throw (ShortBufferException)
+ (new ShortBufferException().initCause(e));
}
- // XXX throw correct exception
throw new ProviderException("update() failed", e);
}
}
private int implDoFinal(byte[] out, int outOfs, int outLen)
- throws ShortBufferException, IllegalBlockSizeException {
- if (outLen < doFinalLength(0)) {
+ throws ShortBufferException, IllegalBlockSizeException,
+ BadPaddingException {
+ int requiredOutLen = doFinalLength(0);
+ if (outLen < requiredOutLen) {
throw new ShortBufferException();
}
try {
ensureInitialized();
+ int k = 0;
if (encrypt) {
- return token.p11.C_EncryptFinal
- (session.id(), 0, out, outOfs, outLen);
+ if (paddingObj != null) {
+ int actualPadLen = paddingObj.setPaddingBytes(padBuffer,
+ requiredOutLen - bytesBuffered);
+ k = token.p11.C_EncryptUpdate(session.id(),
+ 0, padBuffer, 0, actualPadLen,
+ 0, out, outOfs, outLen);
+ }
+ k += token.p11.C_EncryptFinal(session.id(),
+ 0, out, (outOfs + k), (outLen - k));
} else {
- return token.p11.C_DecryptFinal
- (session.id(), 0, out, outOfs, outLen);
+ if (paddingObj != null) {
+ if (padBufferLen != 0) {
+ k = token.p11.C_DecryptUpdate(session.id(), 0,
+ padBuffer, 0, padBufferLen, 0, padBuffer, 0,
+ padBuffer.length);
+ }
+ k += token.p11.C_DecryptFinal(session.id(), 0, padBuffer, k,
+ padBuffer.length - k);
+ int actualPadLen = paddingObj.unpad(padBuffer, 0, k);
+ k -= actualPadLen;
+ System.arraycopy(padBuffer, 0, out, outOfs, k);
+ } else {
+ k = token.p11.C_DecryptFinal(session.id(), 0, out, outOfs,
+ outLen);
+ }
}
+ return k;
} catch (PKCS11Exception e) {
handleException(e);
throw new ProviderException("doFinal() failed", e);
} finally {
initialized = false;
- bytesProcessed = 0;
+ bytesBuffered = 0;
+ padBufferLen = 0;
session = token.releaseSession(session);
}
}
private int implDoFinal(ByteBuffer outBuffer)
- throws ShortBufferException, IllegalBlockSizeException {
+ throws ShortBufferException, IllegalBlockSizeException,
+ BadPaddingException {
int outLen = outBuffer.remaining();
- if (outLen < doFinalLength(0)) {
+ int requiredOutLen = doFinalLength(0);
+ if (outLen < requiredOutLen) {
throw new ShortBufferException();
}
@@ -583,30 +745,54 @@
ensureInitialized();
long outAddr = 0;
- int outOfs = outBuffer.position();
byte[] outArray = null;
+ int outOfs = 0;
if (outBuffer instanceof DirectBuffer) {
- outAddr = ((DirectBuffer)outBuffer).address();
+ outAddr = ((DirectBuffer) outBuffer).address();
+ outOfs = outBuffer.position();
} else {
if (outBuffer.hasArray()) {
outArray = outBuffer.array();
- outOfs += outBuffer.arrayOffset();
+ outOfs = outBuffer.position() + outBuffer.arrayOffset();
} else {
outArray = new byte[outLen];
- outOfs = 0;
}
}
- int k;
+ int k = 0;
+
if (encrypt) {
- k = token.p11.C_EncryptFinal
- (session.id(), outAddr, outArray, outOfs, outLen);
+ if (paddingObj != null) {
+ int actualPadLen = paddingObj.setPaddingBytes(padBuffer,
+ requiredOutLen - bytesBuffered);
+ k = token.p11.C_EncryptUpdate(session.id(),
+ 0, padBuffer, 0, actualPadLen,
+ outAddr, outArray, outOfs, outLen);
+ }
+ k += token.p11.C_EncryptFinal(session.id(),
+ outAddr, outArray, (outOfs + k), (outLen - k));
} else {
- k = token.p11.C_DecryptFinal
- (session.id(), outAddr, outArray, outOfs, outLen);
+ if (paddingObj != null) {
+ if (padBufferLen != 0) {
+ k = token.p11.C_DecryptUpdate(session.id(),
+ 0, padBuffer, 0, padBufferLen,
+ 0, padBuffer, 0, padBuffer.length);
+ padBufferLen = 0;
+ }
+ k += token.p11.C_DecryptFinal(session.id(),
+ 0, padBuffer, k, padBuffer.length - k);
+ int actualPadLen = paddingObj.unpad(padBuffer, 0, k);
+ k -= actualPadLen;
+ outArray = padBuffer;
+ outOfs = 0;
+ } else {
+ k = token.p11.C_DecryptFinal(session.id(),
+ outAddr, outArray, outOfs, outLen);
+ }
}
- if (!(outBuffer instanceof DirectBuffer) &&
- !outBuffer.hasArray()) {
+ if ((!encrypt && paddingObj != null) ||
+ (!(outBuffer instanceof DirectBuffer) &&
+ !outBuffer.hasArray())) {
outBuffer.put(outArray, outOfs, k);
} else {
outBuffer.position(outBuffer.position() + k);
@@ -617,20 +803,21 @@
throw new ProviderException("doFinal() failed", e);
} finally {
initialized = false;
- bytesProcessed = 0;
+ bytesBuffered = 0;
session = token.releaseSession(session);
}
}
private void handleException(PKCS11Exception e)
- throws IllegalBlockSizeException {
+ throws ShortBufferException, IllegalBlockSizeException {
long errorCode = e.getErrorCode();
- // XXX better check
- if (errorCode == CKR_DATA_LEN_RANGE) {
- throw (IllegalBlockSizeException)new
- IllegalBlockSizeException(e.toString()).initCause(e);
+ if (errorCode == CKR_BUFFER_TOO_SMALL) {
+ throw (ShortBufferException)
+ (new ShortBufferException().initCause(e));
+ } else if (errorCode == CKR_DATA_LEN_RANGE) {
+ throw (IllegalBlockSizeException)
+ (new IllegalBlockSizeException(e.toString()).initCause(e));
}
-
}
// see JCE spec
@@ -649,12 +836,14 @@
}
// see JCE spec
+ @Override
protected int engineGetKeySize(Key key) throws InvalidKeyException {
int n = P11SecretKeyFactory.convertKey
- (token, key, keyAlgorithm).keyLength();
+ (token, key, keyAlgorithm).keyLength();
return n;
}
+ @Override
protected void finalize() throws Throwable {
try {
if ((session != null) && token.isValid()) {
@@ -666,4 +855,15 @@
}
}
+ private final void bufferInputBytes(byte[] in, int inOfs, int len) {
+ System.arraycopy(in, inOfs, padBuffer, padBufferLen, len);
+ padBufferLen += len;
+ bytesBuffered += len;
+ }
+
+ private final void bufferInputBytes(ByteBuffer inBuffer, int len) {
+ inBuffer.get(padBuffer, padBufferLen, len);
+ padBufferLen += len;
+ bytesBuffered += len;
+ }
}
--- a/jdk/src/share/classes/sun/security/pkcs11/P11KeyGenerator.java Thu Mar 27 14:15:59 2008 -0700
+++ b/jdk/src/share/classes/sun/security/pkcs11/P11KeyGenerator.java Fri Mar 28 12:56:34 2008 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2008 Sun Microsystems, Inc. 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
@@ -65,10 +65,86 @@
// are supported.
private boolean supportBothKeySizes;
- // min and max key sizes (in bits) for variable-key-length
- // algorithms, e.g. RC4 and Blowfish
- private int minKeySize;
- private int maxKeySize;
+ /**
+ * Utility method for checking if the specified key size is valid
+ * and within the supported range. Return the significant key size
+ * upon successful validation.
+ * @param keyGenMech the PKCS#11 key generation mechanism.
+ * @param keySize the to-be-checked key size for this mechanism.
+ * @param token token which provides this mechanism.
+ * @return the significant key size (in bits) corresponding to the
+ * specified key size.
+ * @throws InvalidParameterException if the specified key size is invalid.
+ * @throws ProviderException if this mechanism isn't supported by SunPKCS11
+ * or underlying native impl.
+ */
+ static int checkKeySize(long keyGenMech, int keySize, Token token)
+ throws InvalidAlgorithmParameterException, ProviderException {
+ int sigKeySize;
+ switch ((int)keyGenMech) {
+ case (int)CKM_DES_KEY_GEN:
+ if ((keySize != 64) && (keySize != 56)) {
+ throw new InvalidAlgorithmParameterException
+ ("DES key length must be 56 bits");
+ }
+ sigKeySize = 56;
+ break;
+ case (int)CKM_DES2_KEY_GEN:
+ case (int)CKM_DES3_KEY_GEN:
+ if ((keySize == 112) || (keySize == 128)) {
+ sigKeySize = 112;
+ } else if ((keySize == 168) || (keySize == 192)) {
+ sigKeySize = 168;
+ } else {
+ throw new InvalidAlgorithmParameterException
+ ("DESede key length must be 112, or 168 bits");
+ }
+ break;
+ default:
+ // Handle all variable-key-length algorithms here
+ CK_MECHANISM_INFO info = null;
+ try {
+ info = token.getMechanismInfo(keyGenMech);
+ } catch (PKCS11Exception p11e) {
+ // Should never happen
+ throw new ProviderException
+ ("Cannot retrieve mechanism info", p11e);
+ }
+ if (info == null) {
+ // XXX Unable to retrieve the supported key length from
+ // the underlying native impl. Skip the checking for now.
+ return keySize;
+ }
+ // PKCS#11 defines these to be in number of bytes except for
+ // RC4 which is in bits. However, some PKCS#11 impls still use
+ // bytes for all mechs, e.g. NSS. We try to detect this
+ // inconsistency if the minKeySize seems unreasonably small.
+ int minKeySize = (int)info.ulMinKeySize;
+ int maxKeySize = (int)info.ulMaxKeySize;
+ if (keyGenMech != CKM_RC4_KEY_GEN || minKeySize < 8) {
+ minKeySize = (int)info.ulMinKeySize << 3;
+ maxKeySize = (int)info.ulMaxKeySize << 3;
+ }
+ // Explicitly disallow keys shorter than 40-bits for security
+ if (minKeySize < 40) minKeySize = 40;
+ if (keySize < minKeySize || keySize > maxKeySize) {
+ throw new InvalidAlgorithmParameterException
+ ("Key length must be between " + minKeySize +
+ " and " + maxKeySize + " bits");
+ }
+ if (keyGenMech == CKM_AES_KEY_GEN) {
+ if ((keySize != 128) && (keySize != 192) &&
+ (keySize != 256)) {
+ throw new InvalidAlgorithmParameterException
+ ("AES key length must be " + minKeySize +
+ (maxKeySize >= 192? ", 192":"") +
+ (maxKeySize >= 256? ", or 256":"") + " bits");
+ }
+ }
+ sigKeySize = keySize;
+ }
+ return sigKeySize;
+ }
P11KeyGenerator(Token token, String algorithm, long mechanism)
throws PKCS11Exception {
@@ -85,72 +161,44 @@
supportBothKeySizes =
(token.provider.config.isEnabled(CKM_DES2_KEY_GEN) &&
(token.getMechanismInfo(CKM_DES2_KEY_GEN) != null));
- } else if (this.mechanism == CKM_RC4_KEY_GEN) {
- CK_MECHANISM_INFO info = token.getMechanismInfo(mechanism);
- // Although PKCS#11 spec documented that these are in bits,
- // NSS, for one, uses bytes. Multiple by 8 if the number seems
- // unreasonably small.
- if (info.ulMinKeySize < 8) {
- minKeySize = (int)info.ulMinKeySize << 3;
- maxKeySize = (int)info.ulMaxKeySize << 3;
- } else {
- minKeySize = (int)info.ulMinKeySize;
- maxKeySize = (int)info.ulMaxKeySize;
- }
- // Explicitly disallow keys shorter than 40-bits for security
- if (minKeySize < 40) minKeySize = 40;
- } else if (this.mechanism == CKM_BLOWFISH_KEY_GEN) {
- CK_MECHANISM_INFO info = token.getMechanismInfo(mechanism);
- maxKeySize = (int)info.ulMaxKeySize << 3;
- minKeySize = (int)info.ulMinKeySize << 3;
- // Explicitly disallow keys shorter than 40-bits for security
- if (minKeySize < 40) minKeySize = 40;
}
-
setDefaultKeySize();
}
// set default keysize and also initialize keyType
private void setDefaultKeySize() {
- // whether to check default key size against the min and max value
- boolean validateKeySize = false;
switch ((int)mechanism) {
case (int)CKM_DES_KEY_GEN:
keySize = 64;
- significantKeySize = 56;
keyType = CKK_DES;
break;
case (int)CKM_DES2_KEY_GEN:
keySize = 128;
- significantKeySize = 112;
keyType = CKK_DES2;
break;
case (int)CKM_DES3_KEY_GEN:
keySize = 192;
- significantKeySize = 168;
keyType = CKK_DES3;
break;
case (int)CKM_AES_KEY_GEN:
+ keySize = 128;
keyType = CKK_AES;
- keySize = 128;
- significantKeySize = 128;
break;
case (int)CKM_RC4_KEY_GEN:
+ keySize = 128;
keyType = CKK_RC4;
- keySize = 128;
- validateKeySize = true;
break;
case (int)CKM_BLOWFISH_KEY_GEN:
+ keySize = 128;
keyType = CKK_BLOWFISH;
- keySize = 128;
- validateKeySize = true;
break;
default:
throw new ProviderException("Unknown mechanism " + mechanism);
}
- if (validateKeySize &&
- ((keySize > maxKeySize) || (keySize < minKeySize))) {
- throw new ProviderException("Unsupported key size");
+ try {
+ significantKeySize = checkKeySize(mechanism, keySize, token);
+ } catch (InvalidAlgorithmParameterException iape) {
+ throw new ProviderException("Unsupported default key size", iape);
}
}
@@ -170,57 +218,32 @@
// see JCE spec
protected void engineInit(int keySize, SecureRandom random) {
token.ensureValid();
- switch ((int)mechanism) {
- case (int)CKM_DES_KEY_GEN:
- if ((keySize != this.keySize) &&
- (keySize != this.significantKeySize)) {
- throw new InvalidParameterException
- ("DES key length must be 56 bits");
- }
- break;
- case (int)CKM_DES2_KEY_GEN:
- case (int)CKM_DES3_KEY_GEN:
- long newMechanism;
- if ((keySize == 112) || (keySize == 128)) {
- newMechanism = CKM_DES2_KEY_GEN;
- } else if ((keySize == 168) || (keySize == 192)) {
- newMechanism = CKM_DES3_KEY_GEN;
- } else {
- throw new InvalidParameterException
- ("DESede key length must be 112, or 168 bits");
- }
+ int newSignificantKeySize;
+ try {
+ newSignificantKeySize = checkKeySize(mechanism, keySize, token);
+ } catch (InvalidAlgorithmParameterException iape) {
+ throw (InvalidParameterException)
+ (new InvalidParameterException().initCause(iape));
+ }
+ if ((mechanism == CKM_DES2_KEY_GEN) ||
+ (mechanism == CKM_DES3_KEY_GEN)) {
+ long newMechanism = (newSignificantKeySize == 112 ?
+ CKM_DES2_KEY_GEN : CKM_DES3_KEY_GEN);
if (mechanism != newMechanism) {
if (supportBothKeySizes) {
mechanism = newMechanism;
- setDefaultKeySize();
+ // Adjust keyType to reflect the mechanism change
+ keyType = (mechanism == CKM_DES2_KEY_GEN ?
+ CKK_DES2 : CKK_DES3);
} else {
throw new InvalidParameterException
- ("Only " + significantKeySize +
- "-bit DESede key length is supported");
+ ("Only " + significantKeySize +
+ "-bit DESede is supported");
}
}
- break;
- case (int)CKM_AES_KEY_GEN:
- if ((keySize != 128) && (keySize != 192) && (keySize != 256)) {
- throw new InvalidParameterException
- ("AES key length must be 128, 192, or 256 bits");
- }
- this.keySize = keySize;
- significantKeySize = keySize;
- break;
- case (int)CKM_RC4_KEY_GEN:
- case (int)CKM_BLOWFISH_KEY_GEN:
- if ((keySize < minKeySize) || (keySize > maxKeySize)) {
- throw new InvalidParameterException
- (algorithm + " key length must be between " +
- minKeySize + " and " + maxKeySize + " bits");
- }
- this.keySize = keySize;
- this.significantKeySize = keySize;
- break;
- default:
- throw new ProviderException("Unknown mechanism " + mechanism);
}
+ this.keySize = keySize;
+ this.significantKeySize = newSignificantKeySize;
}
// see JCE spec
--- a/jdk/src/share/classes/sun/security/pkcs11/P11KeyStore.java Thu Mar 27 14:15:59 2008 -0700
+++ b/jdk/src/share/classes/sun/security/pkcs11/P11KeyStore.java Fri Mar 28 12:56:34 2008 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2008 Sun Microsystems, Inc. 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
@@ -156,10 +156,10 @@
// CKA_CLASS - entry type
private CK_ATTRIBUTE type = null;
- // CKA_LABEL of cert
+ // CKA_LABEL of cert and secret key
private String label = null;
- // CKA_ID - of private key/cert
+ // CKA_ID of the private key/cert pair
private byte[] id = null;
// CKA_TRUSTED - true if cert is trusted
@@ -871,10 +871,8 @@
if ((token.tokenInfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH) == 0) {
token.provider.login(null, handler);
} else {
-
// token supports protected authentication path
// (external pin-pad, for example)
-
if (handler != null &&
!token.config.getKeyStoreCompatibilityMode()) {
throw new LoginException("can not specify password if token " +
@@ -1130,19 +1128,14 @@
SecretKey skey = ske.getSecretKey();
try {
- // first see if the key already exists.
- // if so, update the CKA_LABEL
- if (!updateSkey(alias)) {
+ // first check if the key already exists
+ AliasInfo aliasInfo = aliasMap.get(alias);
- // key entry does not exist.
- // delete existing entry for alias and
- // create new secret key entry
- // (new entry might be a secret key
- // session object converted into a token object)
+ if (aliasInfo != null) {
+ engineDeleteEntry(alias);
+ }
+ storeSkey(alias, ske);
- engineDeleteEntry(alias);
- storeSkey(alias, ske);
- }
} catch (PKCS11Exception pe) {
throw new KeyStoreException(pe);
}
@@ -1396,41 +1389,6 @@
}
}
- /**
- * return true if update occurred
- */
- private boolean updateSkey(String alias)
- throws KeyStoreException, PKCS11Exception {
-
- Session session = null;
- try {
- session = token.getOpSession();
-
- // first update existing secret key CKA_LABEL
-
- THandle h = getTokenObject(session, ATTR_CLASS_SKEY, null, alias);
- if (h.type != ATTR_CLASS_SKEY) {
- if (debug != null) {
- debug.println("did not find secret key " +
- "with CKA_LABEL [" + alias + "]");
- }
- return false;
- }
- CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] {
- new CK_ATTRIBUTE(CKA_LABEL, alias) };
- token.p11.C_SetAttributeValue(session.id(), h.handle, attrs);
-
- if (debug != null) {
- debug.println("updateSkey set new alias [" +
- alias +
- "] for secret key entry");
- }
-
- return true;
- } finally {
- token.releaseSession(session);
- }
- }
/**
* XXX On ibutton, when you C_SetAttribute(CKA_ID) for a private key
@@ -1532,30 +1490,6 @@
}
}
- private void updateP11Skey(String alias, P11Key key)
- throws PKCS11Exception {
-
- Session session = null;
- try {
- session = token.getOpSession();
-
- // session key - convert to token key and set CKA_LABEL
-
- CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] {
- ATTR_TOKEN_TRUE,
- new CK_ATTRIBUTE(CKA_LABEL, alias) };
- token.p11.C_CopyObject(session.id(), key.keyID, attrs);
- if (debug != null) {
- debug.println("updateP11Skey copied secret session key " +
- "for [" +
- alias +
- "] to token entry");
- }
- } finally {
- token.releaseSession(session);
- }
- }
-
private void updateP11Pkey(String alias, CK_ATTRIBUTE attribute, P11Key key)
throws PKCS11Exception {
@@ -1689,48 +1623,26 @@
throws PKCS11Exception, KeyStoreException {
SecretKey skey = ske.getSecretKey();
- long keyType = CKK_GENERIC_SECRET;
-
- if (skey instanceof P11Key && this.token == ((P11Key)skey).token) {
- updateP11Skey(alias, (P11Key)skey);
- return;
- }
-
- if ("AES".equalsIgnoreCase(skey.getAlgorithm())) {
- keyType = CKK_AES;
- } else if ("Blowfish".equalsIgnoreCase(skey.getAlgorithm())) {
- keyType = CKK_BLOWFISH;
- } else if ("DES".equalsIgnoreCase(skey.getAlgorithm())) {
- keyType = CKK_DES;
- } else if ("DESede".equalsIgnoreCase(skey.getAlgorithm())) {
- keyType = CKK_DES3;
- } else if ("RC4".equalsIgnoreCase(skey.getAlgorithm()) ||
- "ARCFOUR".equalsIgnoreCase(skey.getAlgorithm())) {
- keyType = CKK_RC4;
+ // No need to specify CKA_CLASS, CKA_KEY_TYPE, CKA_VALUE since
+ // they are handled in P11SecretKeyFactory.createKey() method.
+ CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] {
+ ATTR_SKEY_TOKEN_TRUE,
+ ATTR_PRIVATE_TRUE,
+ new CK_ATTRIBUTE(CKA_LABEL, alias),
+ };
+ try {
+ P11SecretKeyFactory.convertKey(token, skey, null, attrs);
+ } catch (InvalidKeyException ike) {
+ // re-throw KeyStoreException to match javadoc
+ throw new KeyStoreException("Cannot convert to PKCS11 keys", ike);
}
- CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] {
- ATTR_SKEY_TOKEN_TRUE,
- ATTR_CLASS_SKEY,
- ATTR_PRIVATE_TRUE,
- new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType),
- new CK_ATTRIBUTE(CKA_LABEL, alias),
- new CK_ATTRIBUTE(CKA_VALUE, skey.getEncoded()) };
- attrs = token.getAttributes
- (TemplateManager.O_IMPORT, CKO_SECRET_KEY, keyType, attrs);
+ // update global alias map
+ aliasMap.put(alias, new AliasInfo(alias));
- // create the new entry
- Session session = null;
- try {
- session = token.getOpSession();
- token.p11.C_CreateObject(session.id(), attrs);
- if (debug != null) {
- debug.println("storeSkey created token secret key for [" +
- alias +
- "]");
- }
- } finally {
- token.releaseSession(session);
+ if (debug != null) {
+ debug.println("storeSkey created token secret key for [" +
+ alias + "]");
}
}
@@ -2492,7 +2404,8 @@
// if there are duplicates (either between secret keys,
// or between a secret key and another object),
// throw an exception
- HashSet<String> sKeySet = new HashSet<String>();
+ HashMap<String, AliasInfo> sKeyMap =
+ new HashMap<String, AliasInfo>();
attrs = new CK_ATTRIBUTE[] {
ATTR_SKEY_TOKEN_TRUE,
@@ -2507,8 +2420,8 @@
// there is a CKA_LABEL
String cka_label = new String(attrs[0].getCharArray());
- if (!sKeySet.contains(cka_label)) {
- sKeySet.add(cka_label);
+ if (sKeyMap.get(cka_label) == null) {
+ sKeyMap.put(cka_label, new AliasInfo(cka_label));
} else {
throw new KeyStoreException("invalid KeyStore state: " +
"found multiple secret keys sharing same " +
@@ -2523,7 +2436,7 @@
ArrayList<AliasInfo> matchedCerts =
mapPrivateKeys(pkeyIDs, certMap);
boolean sharedLabel = mapCerts(matchedCerts, certMap);
- mapSecretKeys(sKeySet);
+ mapSecretKeys(sKeyMap);
return sharedLabel;
@@ -2547,7 +2460,7 @@
HashMap<String, HashSet<AliasInfo>> certMap)
throws PKCS11Exception, CertificateException {
- // global alias map
+ // reset global alias map
aliasMap = new HashMap<String, AliasInfo>();
// list of matched certs that we will return
@@ -2722,18 +2635,17 @@
* If the secret key shares a CKA_LABEL with another entry,
* throw an exception
*/
- private void mapSecretKeys(HashSet<String> sKeySet)
+ private void mapSecretKeys(HashMap<String, AliasInfo> sKeyMap)
throws KeyStoreException {
- for (String label : sKeySet) {
- if (!aliasMap.containsKey(label)) {
- aliasMap.put(label, new AliasInfo(label));
- } else {
+ for (String label : sKeyMap.keySet()) {
+ if (aliasMap.containsKey(label)) {
throw new KeyStoreException("invalid KeyStore state: " +
"found secret key sharing CKA_LABEL [" +
label +
"] with another token object");
}
}
+ aliasMap.putAll(sKeyMap);
}
private void dumpTokenMap() {
--- a/jdk/src/share/classes/sun/security/pkcs11/P11RSACipher.java Thu Mar 27 14:15:59 2008 -0700
+++ b/jdk/src/share/classes/sun/security/pkcs11/P11RSACipher.java Fri Mar 28 12:56:34 2008 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2008 Sun Microsystems, Inc. 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
@@ -98,7 +98,6 @@
this.token = token;
this.algorithm = "RSA";
this.mechanism = mechanism;
- session = token.getOpSession();
}
// modes do not make sense for RSA, but allow ECB
@@ -184,7 +183,8 @@
throw new InvalidKeyException
("Wrap has to be used with public keys");
}
- // No further setup needed for C_Wrap(). We remain uninitialized.
+ // No further setup needed for C_Wrap(). We'll initialize later if
+ // we can't use C_Wrap().
return;
} else if (opmode == Cipher.UNWRAP_MODE) {
if (p11Key.isPrivate() == false) {
@@ -383,7 +383,8 @@
return implDoFinal(out, outOfs, out.length - outOfs);
}
- private byte[] doFinal() throws BadPaddingException, IllegalBlockSizeException {
+ private byte[] doFinal() throws BadPaddingException,
+ IllegalBlockSizeException {
byte[] t = new byte[2048];
int n = implDoFinal(t, 0, t.length);
byte[] out = new byte[n];
@@ -394,20 +395,37 @@
// see JCE spec
protected byte[] engineWrap(Key key) throws InvalidKeyException,
IllegalBlockSizeException {
- // XXX Note that if we cannot convert key to a key on this token,
- // we will fail. For example, trying a wrap an AES key on a token that
- // does not support AES.
- // We could implement a fallback that just encrypts the encoding
- // (assuming the key is not sensitive). For now, we are operating under
- // the assumption that this is not necessary.
String keyAlg = key.getAlgorithm();
- P11Key secretKey = P11SecretKeyFactory.convertKey(token, key, keyAlg);
+ P11Key sKey = null;
+ try {
+ // The conversion may fail, e.g. trying to wrap an AES key on
+ // a token that does not support AES, or when the key size is
+ // not within the range supported by the token.
+ sKey = P11SecretKeyFactory.convertKey(token, key, keyAlg);
+ } catch (InvalidKeyException ike) {
+ byte[] toBeWrappedKey = key.getEncoded();
+ if (toBeWrappedKey == null) {
+ throw new InvalidKeyException
+ ("wrap() failed, no encoding available", ike);
+ }
+ // Directly encrypt the key encoding when key conversion failed
+ implInit(Cipher.ENCRYPT_MODE, p11Key);
+ implUpdate(toBeWrappedKey, 0, toBeWrappedKey.length);
+ try {
+ return doFinal();
+ } catch (BadPaddingException bpe) {
+ // should not occur
+ throw new InvalidKeyException("wrap() failed", bpe);
+ } finally {
+ // Restore original mode
+ implInit(Cipher.WRAP_MODE, p11Key);
+ }
+ }
Session s = null;
try {
s = token.getOpSession();
- byte[] b = token.p11.C_WrapKey(s.id(), new CK_MECHANISM(mechanism),
- p11Key.keyID, secretKey.keyID);
- return b;
+ return token.p11.C_WrapKey(s.id(), new CK_MECHANISM(mechanism),
+ p11Key.keyID, sKey.keyID);
} catch (PKCS11Exception e) {
throw new InvalidKeyException("wrap() failed", e);
} finally {
@@ -431,11 +449,13 @@
};
attributes = token.getAttributes
(O_IMPORT, CKO_SECRET_KEY, keyType, attributes);
- long keyID = token.p11.C_UnwrapKey(s.id(), new CK_MECHANISM(mechanism),
- p11Key.keyID, wrappedKey, attributes);
- return P11Key.secretKey(session, keyID, algorithm, 48 << 3, attributes);
+ long keyID = token.p11.C_UnwrapKey(s.id(),
+ new CK_MECHANISM(mechanism), p11Key.keyID, wrappedKey,
+ attributes);
+ return P11Key.secretKey(session, keyID, algorithm, 48 << 3,
+ attributes);
} catch (PKCS11Exception e) {
- throw new InvalidKeyException("wrap() failed", e);
+ throw new InvalidKeyException("unwrap() failed", e);
} finally {
token.releaseSession(s);
}
--- a/jdk/src/share/classes/sun/security/pkcs11/P11SecretKeyFactory.java Thu Mar 27 14:15:59 2008 -0700
+++ b/jdk/src/share/classes/sun/security/pkcs11/P11SecretKeyFactory.java Fri Mar 28 12:56:34 2008 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2008 Sun Microsystems, Inc. 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
@@ -104,9 +104,20 @@
/**
* Convert an arbitrary key of algorithm into a P11Key of provider.
- * Used engineTranslateKey(), P11Cipher.init(), and P11Mac.init().
+ * Used in engineTranslateKey(), P11Cipher.init(), and P11Mac.init().
*/
- static P11Key convertKey(Token token, Key key, String algorithm)
+ static P11Key convertKey(Token token, Key key, String algo)
+ throws InvalidKeyException {
+ return convertKey(token, key, algo, null);
+ }
+
+ /**
+ * Convert an arbitrary key of algorithm w/ custom attributes into a
+ * P11Key of provider.
+ * Used in P11KeyStore.storeSkey.
+ */
+ static P11Key convertKey(Token token, Key key, String algo,
+ CK_ATTRIBUTE[] extraAttrs)
throws InvalidKeyException {
token.ensureValid();
if (key == null) {
@@ -115,25 +126,41 @@
if (key instanceof SecretKey == false) {
throw new InvalidKeyException("Key must be a SecretKey");
}
- long algorithmType;
- if (algorithm == null) {
- algorithm = key.getAlgorithm();
- algorithmType = getKeyType(algorithm);
+ long algoType;
+ if (algo == null) {
+ algo = key.getAlgorithm();
+ algoType = getKeyType(algo);
} else {
- algorithmType = getKeyType(algorithm);
+ algoType = getKeyType(algo);
long keyAlgorithmType = getKeyType(key.getAlgorithm());
- if (algorithmType != keyAlgorithmType) {
- if ((algorithmType == PCKK_HMAC) || (algorithmType == PCKK_SSLMAC)) {
+ if (algoType != keyAlgorithmType) {
+ if ((algoType == PCKK_HMAC) || (algoType == PCKK_SSLMAC)) {
// ignore key algorithm for MACs
} else {
throw new InvalidKeyException
- ("Key algorithm must be " + algorithm);
+ ("Key algorithm must be " + algo);
}
}
}
if (key instanceof P11Key) {
P11Key p11Key = (P11Key)key;
if (p11Key.token == token) {
+ if (extraAttrs != null) {
+ Session session = null;
+ try {
+ session = token.getObjSession();
+ long newKeyID = token.p11.C_CopyObject(session.id(),
+ p11Key.keyID, extraAttrs);
+ p11Key = (P11Key) (P11Key.secretKey(p11Key.session,
+ newKeyID, p11Key.algorithm, p11Key.keyLength,
+ extraAttrs));
+ } catch (PKCS11Exception p11e) {
+ throw new InvalidKeyException
+ ("Cannot duplicate the PKCS11 key", p11e);
+ } finally {
+ token.releaseSession(session);
+ }
+ }
return p11Key;
}
}
@@ -141,11 +168,11 @@
if (p11Key != null) {
return p11Key;
}
- if ("RAW".equals(key.getFormat()) == false) {
+ if ("RAW".equalsIgnoreCase(key.getFormat()) == false) {
throw new InvalidKeyException("Encoded format must be RAW");
}
byte[] encoded = key.getEncoded();
- p11Key = createKey(token, encoded, algorithm, algorithmType);
+ p11Key = createKey(token, encoded, algo, algoType, extraAttrs);
token.secretCache.put(key, p11Key);
return p11Key;
}
@@ -159,79 +186,79 @@
}
private static P11Key createKey(Token token, byte[] encoded,
- String algorithm, long keyType) throws InvalidKeyException {
- int n = encoded.length;
- int keyLength;
- switch ((int)keyType) {
- case (int)CKK_RC4:
- if ((n < 5) || (n > 128)) {
- throw new InvalidKeyException
- ("ARCFOUR key length must be between 5 and 128 bytes");
- }
- keyLength = n << 3;
- break;
- case (int)CKK_DES:
- if (n != 8) {
- throw new InvalidKeyException
- ("DES key length must be 8 bytes");
- }
- keyLength = 56;
- fixDESParity(encoded, 0);
- break;
- case (int)CKK_DES3:
- if (n == 16) {
- keyType = CKK_DES2;
- } else if (n == 24) {
- keyType = CKK_DES3;
- fixDESParity(encoded, 16);
- } else {
- throw new InvalidKeyException
- ("DESede key length must be 16 or 24 bytes");
+ String algorithm, long keyType, CK_ATTRIBUTE[] extraAttrs)
+ throws InvalidKeyException {
+ int n = encoded.length << 3;
+ int keyLength = n;
+ try {
+ switch ((int)keyType) {
+ case (int)CKK_DES:
+ keyLength =
+ P11KeyGenerator.checkKeySize(CKM_DES_KEY_GEN, n, token);
+ fixDESParity(encoded, 0);
+ break;
+ case (int)CKK_DES3:
+ keyLength =
+ P11KeyGenerator.checkKeySize(CKM_DES3_KEY_GEN, n, token);
+ fixDESParity(encoded, 0);
+ fixDESParity(encoded, 8);
+ if (keyLength == 112) {
+ keyType = CKK_DES2;
+ } else {
+ keyType = CKK_DES3;
+ fixDESParity(encoded, 16);
+ }
+ break;
+ case (int)CKK_AES:
+ keyLength =
+ P11KeyGenerator.checkKeySize(CKM_AES_KEY_GEN, n, token);
+ break;
+ case (int)CKK_RC4:
+ keyLength =
+ P11KeyGenerator.checkKeySize(CKM_RC4_KEY_GEN, n, token);
+ break;
+ case (int)CKK_BLOWFISH:
+ keyLength =
+ P11KeyGenerator.checkKeySize(CKM_BLOWFISH_KEY_GEN, n,
+ token);
+ break;
+ case (int)CKK_GENERIC_SECRET:
+ case (int)PCKK_TLSPREMASTER:
+ case (int)PCKK_TLSRSAPREMASTER:
+ case (int)PCKK_TLSMASTER:
+ keyType = CKK_GENERIC_SECRET;
+ break;
+ case (int)PCKK_SSLMAC:
+ case (int)PCKK_HMAC:
+ if (n == 0) {
+ throw new InvalidKeyException
+ ("MAC keys must not be empty");
+ }
+ keyType = CKK_GENERIC_SECRET;
+ break;
+ default:
+ throw new InvalidKeyException("Unknown algorithm " +
+ algorithm);
}
- fixDESParity(encoded, 0);
- fixDESParity(encoded, 8);
- keyLength = n * 7;
- break;
- case (int)CKK_AES:
- if ((n != 16) && (n != 24) && (n != 32)) {
- throw new InvalidKeyException
- ("AES key length must be 16, 24, or 32 bytes");
- }
- keyLength = n << 3;
- break;
- case (int)CKK_BLOWFISH:
- if ((n < 5) || (n > 56)) {
- throw new InvalidKeyException
- ("Blowfish key length must be between 5 and 56 bytes");
- }
- keyLength = n << 3;
- break;
- case (int)CKK_GENERIC_SECRET:
- case (int)PCKK_TLSPREMASTER:
- case (int)PCKK_TLSRSAPREMASTER:
- case (int)PCKK_TLSMASTER:
- keyType = CKK_GENERIC_SECRET;
- keyLength = n << 3;
- break;
- case (int)PCKK_SSLMAC:
- case (int)PCKK_HMAC:
- if (n == 0) {
- throw new InvalidKeyException
- ("MAC keys must not be empty");
- }
- keyType = CKK_GENERIC_SECRET;
- keyLength = n << 3;
- break;
- default:
- throw new InvalidKeyException("Unknown algorithm " + algorithm);
+ } catch (InvalidAlgorithmParameterException iape) {
+ throw new InvalidKeyException("Invalid key for " + algorithm,
+ iape);
+ } catch (ProviderException pe) {
+ throw new InvalidKeyException("Could not create key", pe);
}
Session session = null;
try {
- CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
- new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY),
- new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType),
- new CK_ATTRIBUTE(CKA_VALUE, encoded),
- };
+ CK_ATTRIBUTE[] attributes;
+ if (extraAttrs != null) {
+ attributes = new CK_ATTRIBUTE[3 + extraAttrs.length];
+ System.arraycopy(extraAttrs, 0, attributes, 3,
+ extraAttrs.length);
+ } else {
+ attributes = new CK_ATTRIBUTE[3];
+ }
+ attributes[0] = new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY);
+ attributes[1] = new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType);
+ attributes[2] = new CK_ATTRIBUTE(CKA_VALUE, encoded);
attributes = token.getAttributes
(O_IMPORT, CKO_SECRET_KEY, keyType, attributes);
session = token.getObjSession();
@@ -280,7 +307,7 @@
private byte[] getKeyBytes(SecretKey key) throws InvalidKeySpecException {
try {
key = engineTranslateKey(key);
- if ("RAW".equals(key.getFormat()) == false) {
+ if ("RAW".equalsIgnoreCase(key.getFormat()) == false) {
throw new InvalidKeySpecException
("Could not obtain key bytes");
}
--- a/jdk/src/share/classes/sun/security/pkcs11/SunPKCS11.java Thu Mar 27 14:15:59 2008 -0700
+++ b/jdk/src/share/classes/sun/security/pkcs11/SunPKCS11.java Fri Mar 28 12:56:34 2008 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2008 Sun Microsystems, Inc. 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
@@ -601,14 +601,26 @@
// XXX attributes for Ciphers (supported modes, padding)
d(CIP, "ARCFOUR", P11Cipher, s("RC4"),
m(CKM_RC4));
- // XXX only CBC/NoPadding for block ciphers
d(CIP, "DES/CBC/NoPadding", P11Cipher,
m(CKM_DES_CBC));
+ d(CIP, "DES/CBC/PKCS5Padding", P11Cipher,
+ m(CKM_DES_CBC_PAD, CKM_DES_CBC));
+ d(CIP, "DES/ECB", P11Cipher, s("DES"),
+ m(CKM_DES_ECB));
+
d(CIP, "DESede/CBC/NoPadding", P11Cipher,
m(CKM_DES3_CBC));
+ d(CIP, "DESede/CBC/PKCS5Padding", P11Cipher,
+ m(CKM_DES3_CBC_PAD, CKM_DES3_CBC));
+ d(CIP, "DESede/ECB", P11Cipher, s("DESede"),
+ m(CKM_DES3_ECB));
d(CIP, "AES/CBC/NoPadding", P11Cipher,
m(CKM_AES_CBC));
- d(CIP, "Blowfish/CBC/NoPadding", P11Cipher,
+ d(CIP, "AES/CBC/PKCS5Padding", P11Cipher,
+ m(CKM_AES_CBC_PAD, CKM_AES_CBC));
+ d(CIP, "AES/ECB", P11Cipher, s("AES"),
+ m(CKM_AES_ECB));
+ d(CIP, "Blowfish/CBC", P11Cipher,
m(CKM_BLOWFISH_CBC));
// XXX RSA_X_509, RSA_OAEP not yet supported
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/pkcs11/Cipher/TestRSACipherWrap.java Fri Mar 28 12:56:34 2008 -0700
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. 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.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**
+ * @test
+ * @bug 6572331
+ * @summary basic test for RSA cipher key wrapping functionality
+ * @author Valerie Peng
+ * @library ..
+ */
+import java.io.*;
+import java.util.*;
+
+import java.security.*;
+
+import javax.crypto.*;
+import javax.crypto.spec.SecretKeySpec;
+
+public class TestRSACipherWrap extends PKCS11Test {
+
+ private static final String RSA_ALGO = "RSA/ECB/PKCS1Padding";
+
+ public void main(Provider p) throws Exception {
+ try {
+ Cipher.getInstance(RSA_ALGO, p);
+ } catch (GeneralSecurityException e) {
+ System.out.println("Not supported by provider, skipping");
+ return;
+ }
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", p);
+ kpg.initialize(1024);
+ KeyPair kp = kpg.generateKeyPair();
+ PublicKey publicKey = kp.getPublic();
+ PrivateKey privateKey = kp.getPrivate();
+
+ Cipher cipherPKCS11 = Cipher.getInstance(RSA_ALGO, p);
+ Cipher cipherJce = Cipher.getInstance(RSA_ALGO, "SunJCE");
+
+ String algos[] = {"AES", "RC2", "Blowfish"};
+ int keySizes[] = {128, 256};
+
+ for (int j = 0; j < algos.length; j++) {
+ String algorithm = algos[j];
+ KeyGenerator keygen =
+ KeyGenerator.getInstance(algorithm);
+
+ for (int i = 0; i < keySizes.length; i++) {
+ SecretKey secretKey = null;
+ System.out.print("Generate " + keySizes[i] + "-bit " +
+ algorithm + " key using ");
+ try {
+ keygen.init(keySizes[i]);
+ secretKey = keygen.generateKey();
+ System.out.println(keygen.getProvider().getName());
+ } catch (InvalidParameterException ipe) {
+ secretKey = new SecretKeySpec(new byte[32], algorithm);
+ System.out.println("SecretKeySpec class");
+ }
+ test(kp, secretKey, cipherPKCS11, cipherJce);
+ test(kp, secretKey, cipherPKCS11, cipherPKCS11);
+ test(kp, secretKey, cipherJce, cipherPKCS11);
+ }
+ }
+ }
+
+ private static void test(KeyPair kp, SecretKey secretKey,
+ Cipher wrapCipher, Cipher unwrapCipher)
+ throws Exception {
+ String algo = secretKey.getAlgorithm();
+ wrapCipher.init(Cipher.WRAP_MODE, kp.getPublic());
+ byte[] wrappedKey = wrapCipher.wrap(secretKey);
+ unwrapCipher.init(Cipher.UNWRAP_MODE, kp.getPrivate());
+ Key unwrappedKey =
+ unwrapCipher.unwrap(wrappedKey, algo, Cipher.SECRET_KEY);
+
+ System.out.println("Test " + wrapCipher.getProvider().getName() +
+ "/" + unwrapCipher.getProvider().getName() + ": ");
+ if (!Arrays.equals(secretKey.getEncoded(),
+ unwrappedKey.getEncoded())) {
+ throw new Exception("Test Failed!");
+ }
+ System.out.println("Passed");
+ }
+
+ public static void main(String[] args) throws Exception {
+ main(new TestRSACipherWrap());
+ }
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/pkcs11/Cipher/TestSymmCiphers.java Fri Mar 28 12:56:34 2008 -0700
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. 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 modi
+fy it
+ * under the terms of the GNU General Public License version 2 onl
+y, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, bu
+t WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABIL
+ITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public L
+icense
+ * version 2 for more details (a copy is included in the LICENSE f
+ile that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public Licen
+se version
+ * 2 along with this work; if not, write to the Free Software Foun
+dation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, San
+ta Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional inform
+ation or
+ * have any questions.
+ */
+
+/**
+ * @test %I% %E%
+ * @bug 4898461
+ * @summary basic test for symmetric ciphers with padding
+ * @author Valerie Peng
+ * @library ..
+ */
+import java.io.*;
+import java.nio.*;
+import java.util.*;
+
+import java.security.*;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.*;
+import javax.crypto.spec.IvParameterSpec;
+
+public class TestSymmCiphers extends PKCS11Test {
+
+ private static class CI { // class for holding Cipher Information
+
+ String transformation;
+ String keyAlgo;
+ int dataSize;
+
+ CI(String transformation, String keyAlgo, int dataSize) {
+ this.transformation = transformation;
+ this.keyAlgo = keyAlgo;
+ this.dataSize = dataSize;
+ }
+ }
+ private static final CI[] TEST_LIST = {
+ new CI("ARCFOUR", "ARCFOUR", 400),
+ new CI("RC4", "RC4", 401),
+ new CI("DES/CBC/NoPadding", "DES", 400),
+ new CI("DESede/CBC/NoPadding", "DESede", 160),
+ new CI("AES/CBC/NoPadding", "AES", 4800),
+ new CI("Blowfish/CBC/NoPadding", "Blowfish", 24),
+ new CI("DES/cbc/PKCS5Padding", "DES", 6401),
+ new CI("DESede/CBC/PKCS5Padding", "DESede", 402),
+ new CI("AES/CBC/PKCS5Padding", "AES", 30),
+ new CI("Blowfish/CBC/PKCS5Padding", "Blowfish", 19),
+ new CI("DES/ECB/NoPadding", "DES", 400),
+ new CI("DESede/ECB/NoPadding", "DESede", 160),
+ new CI("AES/ECB/NoPadding", "AES", 4800),
+ new CI("DES/ECB/PKCS5Padding", "DES", 32),
+ new CI("DES/ECB/PKCS5Padding", "DES", 6400),
+ new CI("DESede/ECB/PKCS5Padding", "DESede", 400),
+ new CI("AES/ECB/PKCS5Padding", "AES", 64),
+ new CI("DES", "DES", 6400),
+ new CI("DESede", "DESede", 408),
+ new CI("AES", "AES", 128)
+ };
+ private static StringBuffer debugBuf = new StringBuffer();
+
+ public void main(Provider p) throws Exception {
+ // NSS reports CKR_DEVICE_ERROR when the data passed to
+ // its EncryptUpdate/DecryptUpdate is not multiple of blocks
+ int firstBlkSize = 16;
+ boolean status = true;
+ Random random = new Random();
+ try {
+ for (int i = 0; i < TEST_LIST.length; i++) {
+ CI currTest = TEST_LIST[i];
+ System.out.println("===" + currTest.transformation + "===");
+ try {
+ KeyGenerator kg =
+ KeyGenerator.getInstance(currTest.keyAlgo, p);
+ SecretKey key = kg.generateKey();
+ Cipher c1 = Cipher.getInstance(currTest.transformation, p);
+ Cipher c2 = Cipher.getInstance(currTest.transformation,
+ "SunJCE");
+
+ byte[] plainTxt = new byte[currTest.dataSize];
+ random.nextBytes(plainTxt);
+ System.out.println("Testing inLen = " + plainTxt.length);
+
+ c2.init(Cipher.ENCRYPT_MODE, key);
+ AlgorithmParameters params = c2.getParameters();
+ byte[] answer = c2.doFinal(plainTxt);
+ System.out.println("Encryption tests: START");
+ test(c1, Cipher.ENCRYPT_MODE, key, params, firstBlkSize,
+ plainTxt, answer);
+ System.out.println("Encryption tests: DONE");
+ c2.init(Cipher.DECRYPT_MODE, key, params);
+ byte[] answer2 = c2.doFinal(answer);
+ System.out.println("Decryption tests: START");
+ test(c1, Cipher.DECRYPT_MODE, key, params, firstBlkSize,
+ answer, answer2);
+ System.out.println("Decryption tests: DONE");
+ } catch (NoSuchAlgorithmException nsae) {
+ System.out.println("Skipping unsupported algorithm: " +
+ nsae);
+ }
+ }
+ } catch (Exception ex) {
+ // print out debug info when exception is encountered
+ if (debugBuf != null) {
+ System.out.println(debugBuf.toString());
+ debugBuf = new StringBuffer();
+ }
+ throw ex;
+ }
+ }
+
+ private static void test(Cipher cipher, int mode, SecretKey key,
+ AlgorithmParameters params, int firstBlkSize,
+ byte[] in, byte[] answer) throws Exception {
+ // test setup
+ long startTime, endTime;
+ cipher.init(mode, key, params);
+ int outLen = cipher.getOutputSize(in.length);
+ //debugOut("Estimated output size = " + outLen + "\n");
+
+ // test data preparation
+ ByteBuffer inBuf = ByteBuffer.allocate(in.length);
+ inBuf.put(in);
+ inBuf.position(0);
+ ByteBuffer inDirectBuf = ByteBuffer.allocateDirect(in.length);
+ inDirectBuf.put(in);
+ inDirectBuf.position(0);
+ ByteBuffer outBuf = ByteBuffer.allocate(outLen);
+ ByteBuffer outDirectBuf = ByteBuffer.allocateDirect(outLen);
+
+ // test#1: byte[] in + byte[] out
+ //debugOut("Test#1:\n");
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ startTime = System.nanoTime();
+ byte[] temp = cipher.update(in, 0, firstBlkSize);
+ if (temp != null && temp.length > 0) {
+ baos.write(temp, 0, temp.length);
+ }
+ temp = cipher.doFinal(in, firstBlkSize, in.length - firstBlkSize);
+ if (temp != null && temp.length > 0) {
+ baos.write(temp, 0, temp.length);
+ }
+ byte[] testOut1 = baos.toByteArray();
+ endTime = System.nanoTime();
+ perfOut("stream InBuf + stream OutBuf: " +
+ (endTime - startTime));
+ match(testOut1, answer);
+
+ // test#2: Non-direct Buffer in + non-direct Buffer out
+ //debugOut("Test#2:\n");
+ //debugOut("inputBuf: " + inBuf + "\n");
+ //debugOut("outputBuf: " + outBuf + "\n");
+
+ startTime = System.nanoTime();
+ cipher.update(inBuf, outBuf);
+ cipher.doFinal(inBuf, outBuf);
+ endTime = System.nanoTime();
+ perfOut("non-direct InBuf + non-direct OutBuf: " +
+ (endTime - startTime));
+ match(outBuf, answer);
+
+ // test#3: Direct Buffer in + direc Buffer out
+ //debugOut("Test#3:\n");
+ //debugOut("(pre) inputBuf: " + inDirectBuf + "\n");
+ //debugOut("(pre) outputBuf: " + outDirectBuf + "\n");
+
+ startTime = System.nanoTime();
+ cipher.update(inDirectBuf, outDirectBuf);
+ cipher.doFinal(inDirectBuf, outDirectBuf);
+ endTime = System.nanoTime();
+ perfOut("direct InBuf + direct OutBuf: " +
+ (endTime - startTime));
+
+ //debugOut("(post) inputBuf: " + inDirectBuf + "\n");
+ //debugOut("(post) outputBuf: " + outDirectBuf + "\n");
+ match(outDirectBuf, answer);
+
+ // test#4: Direct Buffer in + non-direct Buffer out
+ //debugOut("Test#4:\n");
+ inDirectBuf.position(0);
+ outBuf.position(0);
+ //debugOut("inputBuf: " + inDirectBuf + "\n");
+ //debugOut("outputBuf: " + outBuf + "\n");
+
+ startTime = System.nanoTime();
+ cipher.update(inDirectBuf, outBuf);
+ cipher.doFinal(inDirectBuf, outBuf);
+ endTime = System.nanoTime();
+ perfOut("direct InBuf + non-direct OutBuf: " +
+ (endTime - startTime));
+ match(outBuf, answer);
+
+ // test#5: Non-direct Buffer in + direct Buffer out
+ //debugOut("Test#5:\n");
+ inBuf.position(0);
+ outDirectBuf.position(0);
+
+ //debugOut("(pre) inputBuf: " + inBuf + "\n");
+ //debugOut("(pre) outputBuf: " + outDirectBuf + "\n");
+
+ startTime = System.nanoTime();
+ cipher.update(inBuf, outDirectBuf);
+ cipher.doFinal(inBuf, outDirectBuf);
+ endTime = System.nanoTime();
+ perfOut("non-direct InBuf + direct OutBuf: " +
+ (endTime - startTime));
+
+ //debugOut("(post) inputBuf: " + inBuf + "\n");
+ //debugOut("(post) outputBuf: " + outDirectBuf + "\n");
+ match(outDirectBuf, answer);
+
+ debugBuf = null;
+ }
+
+ private static void perfOut(String msg) {
+ if (debugBuf != null) {
+ debugBuf.append("PERF>" + msg);
+ }
+ }
+
+ private static void debugOut(String msg) {
+ if (debugBuf != null) {
+ debugBuf.append(msg);
+ }
+ }
+
+ private static void match(byte[] b1, byte[] b2) throws Exception {
+ if (b1.length != b2.length) {
+ debugOut("got len : " + b1.length + "\n");
+ debugOut("expect len: " + b2.length + "\n");
+ throw new Exception("mismatch - different length! got: " + b1.length + ", expect: " + b2.length + "\n");
+ } else {
+ for (int i = 0; i < b1.length; i++) {
+ if (b1[i] != b2[i]) {
+ debugOut("got : " + toString(b1) + "\n");
+ debugOut("expect: " + toString(b2) + "\n");
+ throw new Exception("mismatch");
+ }
+ }
+ }
+ }
+
+ private static void match(ByteBuffer bb, byte[] answer) throws Exception {
+ byte[] bbTemp = new byte[bb.position()];
+ bb.position(0);
+ bb.get(bbTemp, 0, bbTemp.length);
+ match(bbTemp, answer);
+ }
+
+ public static void main(String[] args) throws Exception {
+ main(new TestSymmCiphers());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/pkcs11/KeyStore/SecretKeysBasic.java Fri Mar 28 12:56:34 2008 -0700
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. 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.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.io.*;
+import java.util.*;
+import java.lang.reflect.*;
+
+import java.security.*;
+import java.security.cert.*;
+import java.security.spec.*;
+import java.security.interfaces.*;
+import java.math.BigInteger;
+
+import javax.crypto.*;
+import javax.crypto.spec.*;
+
+public class SecretKeysBasic extends PKCS11Test {
+
+ private static final char SEP = File.separatorChar;
+ private static char[] tokenPwd;
+ private static final char[] nssPwd =
+ new char[]{'t', 'e', 's', 't', '1', '2'};
+ private static final char[] solarisPwd =
+ new char[]{'p', 'i', 'n'};
+ private static SecretKey sk1;
+ private static SecretKey sk2;
+ private static SecretKey softkey;
+ private static KeyStore ks;
+ private static final String KS_TYPE = "PKCS11";
+ private static Provider provider;
+
+ public static void main(String[] args) throws Exception {
+ main(new SecretKeysBasic());
+ }
+
+ public void main(Provider p) throws Exception {
+ this.provider = p;
+
+ // create secret key
+ byte[] keyVal = new byte[16];
+ (new SecureRandom()).nextBytes(keyVal);
+ // NSS will throw CKR_HOST_MEMORY if calling C_DecryptInit w/
+ // (keyVal[0] == 0)
+ if (keyVal[0] == 0) {
+ keyVal[0] = 1;
+ }
+ softkey = new SecretKeySpec(keyVal, "AES");
+ dumpKey("softkey", softkey);
+
+ KeyGenerator kg = KeyGenerator.getInstance("DESede", provider);
+ sk1 = kg.generateKey();
+ dumpKey("skey1", sk1);
+ sk2 = kg.generateKey();
+ dumpKey("skey2", sk2);
+
+ String token = System.getProperty("TOKEN");
+
+ if (token == null || token.length() == 0) {
+ System.out.println("Error: missing TOKEN system property");
+ throw new Exception("token arg required");
+ }
+
+ if ("nss".equals(token)) {
+ tokenPwd = nssPwd;
+ } else if ("solaris".equals(token)) {
+ tokenPwd = solarisPwd;
+ }
+
+ int testnum = 1;
+ doTest();
+ }
+
+ private static boolean checkSecretKeyEntry(String alias,
+ SecretKey expected,
+ boolean saveBeforeCheck)
+ throws Exception {
+ if (saveBeforeCheck) {
+ ks.setKeyEntry(alias, expected, null, null);
+ }
+ SecretKey result = (SecretKey) (ks.getKey(alias, null));
+ String keyEncFormat = result.getFormat();
+ if (keyEncFormat == null) {
+ // sensitive or un-extractable keys - verify by encrypt/decrypt
+ byte[] data = new byte[64];
+ Cipher c =
+ Cipher.getInstance(result.getAlgorithm() + "/CBC/NoPadding",
+ provider);
+ c.init(Cipher.ENCRYPT_MODE, expected);
+ byte[] encOut = c.doFinal(data);
+ c.init(Cipher.DECRYPT_MODE, result, c.getParameters());
+ byte[] decOut = c.doFinal(encOut);
+ if (!Arrays.equals(data, decOut)) {
+ return false;
+ }
+ } else if (keyEncFormat.toUpperCase().equals("RAW")) {
+ if (!Arrays.equals(result.getEncoded(), expected.getEncoded())) {
+ dumpKey("\texpected:", expected);
+ dumpKey("\treturns:", result);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static void dumpKey(String info, SecretKey key) {
+ System.out.println(info + "> " + key);
+ System.out.println("\tALGO=" + key.getAlgorithm());
+ if (key.getFormat() != null) {
+ System.out.println("\t[" + key.getFormat() + "] VALUE=" +
+ new BigInteger(key.getEncoded()));
+ } else {
+ System.out.println("\tVALUE=n/a");
+ }
+ }
+
+ private static void doTest() throws Exception {
+ if (ks == null) {
+ ks = KeyStore.getInstance(KS_TYPE, provider);
+ ks.load(null, tokenPwd);
+ }
+
+ System.out.println("Number of entries: " + ks.size());
+ if (ks.size() != 0) {
+ System.out.println("Deleting entries under aliases: ");
+ for (Enumeration<String> aliases = ks.aliases();
+ aliases.hasMoreElements();) {
+ String alias = aliases.nextElement();
+ System.out.println("\t" + alias);
+ ks.deleteEntry(alias);
+ }
+ }
+
+ String alias = "testSKey";
+
+ boolean testResult = checkSecretKeyEntry(alias, softkey, true);
+ if (!testResult) {
+ System.out.println("FAILURE: setKey() w/ softSecretKey failed");
+ }
+
+ if (!checkSecretKeyEntry(alias, sk1, true)) {
+ testResult = false;
+ System.out.println("FAILURE: setKey() w/ skey1 failed");
+ }
+ if (!checkSecretKeyEntry(alias, sk2, true)) {
+ testResult = false;
+ System.out.println("FAILURE: setKey() w/ skey2 failed");
+ }
+
+ ks.store(null);
+ System.out.println("Reloading keystore...");
+
+ ks.load(null, "whatever".toCharArray());
+ if (ks.size() != 1) {
+ System.out.println("FAILURE: reload#1 ks.size() != 1");
+ }
+ if (!checkSecretKeyEntry(alias, sk2, false)) {
+ testResult = false;
+ System.out.println("FAILURE: reload#1 ks entry check failed");
+ }
+
+ ks.deleteEntry(alias);
+ ks.store(null);
+
+ System.out.println("Reloading keystore...");
+ ks.load(null, "whatever".toCharArray());
+ if (ks.size() != 0) {
+ testResult = false;
+ System.out.println("FAILURE: reload#2 ks.size() != 0");
+ }
+ if (!testResult) {
+ throw new Exception("One or more test failed!");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/pkcs11/KeyStore/SecretKeysBasic.sh Fri Mar 28 12:56:34 2008 -0700
@@ -0,0 +1,164 @@
+#
+# Copyright 2008 Sun Microsystems, Inc. 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.
+#
+# 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+#
+
+# @test
+# @bug 6599979
+# @summary Ensure that re-assigning the alias works
+#
+# @run shell SecretKeysBasic.sh
+#
+# To run by hand:
+# %sh SecretKeysBasic.sh
+#
+# Note:
+# . test only runs on solaris at the moment
+
+# set a few environment variables so that the shell-script can run stand-alone
+# in the source directory
+
+# if running by hand on windows, change TESTSRC and TESTCLASSES to "."
+if [ "${TESTSRC}" = "" ] ; then
+ TESTSRC=`pwd`
+fi
+if [ "${TESTCLASSES}" = "" ] ; then
+ TESTCLASSES=`pwd`
+fi
+
+# if running by hand on windows, change this to appropriate value
+if [ "${TESTJAVA}" = "" ] ; then
+ TESTJAVA="/net/shimmer/export/valeriep/jdk7/build/solaris-sparc"
+fi
+echo TESTSRC=${TESTSRC}
+echo TESTCLASSES=${TESTCLASSES}
+echo TESTJAVA=${TESTJAVA}
+echo ""
+
+#DEBUG=sunpkcs11,pkcs11keystore
+
+echo DEBUG=${DEBUG}
+echo ""
+
+OS=`uname -s`
+case "$OS" in
+ SunOS )
+ FS="/"
+ PS=":"
+ SCCS="${FS}usr${FS}ccs${FS}bin${FS}sccs"
+ CP="${FS}bin${FS}cp -f"
+ RM="${FS}bin${FS}rm -rf"
+ MKDIR="${FS}bin${FS}mkdir -p"
+ CHMOD="${FS}bin${FS}chmod"
+ ;;
+ * )
+ echo "Unsupported System ${OS} - Test only runs on Solaris"
+ exit 0;
+ ;;
+esac
+
+TOKENS="nss solaris"
+STATUS=0
+for token in ${TOKENS}
+do
+
+if [ ${token} = "nss" ]
+then
+ # make cert/key DBs writable if token is NSS
+ ${CP} ${TESTSRC}${FS}..${FS}nss${FS}db${FS}cert8.db ${TESTCLASSES}
+ ${CHMOD} +w ${TESTCLASSES}${FS}cert8.db
+
+ ${CP} ${TESTSRC}${FS}..${FS}nss${FS}db${FS}key3.db ${TESTCLASSES}
+ ${CHMOD} +w ${TESTCLASSES}${FS}key3.db
+ USED_FILE_LIST="${TESTCLASSES}${FS}cert8.db ${TESTCLASSES}${FS}key3.db"
+elif [ ${token} = "solaris" ]
+then
+ OS_VERSION=`uname -r`
+ case "${OS_VERSION}" in
+ 5.1* )
+ SOFTTOKEN_DIR=${TESTCLASSES}
+ export SOFTTOKEN_DIR
+ ;;
+ * )
+ echo "Unsupported Version ${OS_VERSION} - Test only runs on Solaris"
+ exit 0;
+ ;;
+ esac
+
+ # copy keystore into write-able location
+ if [ -d ${TESTCLASSES}${FS}pkcs11_softtoken ]
+ then
+ echo "Removing old pkcs11_keystore, creating new pkcs11_keystore"
+
+ echo ${RM} ${TESTCLASSES}${FS}pkcs11_softtoken
+ ${RM} ${TESTCLASSES}${FS}pkcs11_softtoken
+ fi
+ echo ${MKDIR} ${TESTCLASSES}${FS}pkcs11_softtoken${FS}private
+ ${MKDIR} ${TESTCLASSES}${FS}pkcs11_softtoken${FS}private
+
+ echo ${MKDIR} ${TESTCLASSES}${FS}pkcs11_softtoken${FS}public
+ ${MKDIR} ${TESTCLASSES}${FS}pkcs11_softtoken${FS}public
+
+ echo ${CP} ${TESTSRC}${FS}BasicData${FS}pkcs11_softtoken${FS}objstore_info \
+ ${TESTCLASSES}${FS}pkcs11_softtoken
+ ${CP} ${TESTSRC}${FS}BasicData${FS}pkcs11_softtoken${FS}objstore_info \
+ ${TESTCLASSES}${FS}pkcs11_softtoken
+
+ echo ${CHMOD} +w ${TESTCLASSES}${FS}pkcs11_softtoken${FS}objstore_info
+ ${CHMOD} 600 ${TESTCLASSES}${FS}pkcs11_softtoken${FS}objstore_info
+ USED_FILE_LIST="${TESTCLASSES}${FS}pkcs11_softtoken"
+fi
+
+cd ${TESTCLASSES}
+${TESTJAVA}${FS}bin${FS}javac \
+ -classpath ${TESTCLASSES} \
+ -d ${TESTCLASSES} \
+ ${TESTSRC}${FS}SecretKeysBasic.java
+
+# run test
+cd ${TESTSRC}
+${TESTJAVA}${FS}bin${FS}java \
+ -DDIR=${TESTSRC}${FS}BasicData${FS} \
+ -classpath ${TESTCLASSES}${PS}${TESTSRC}${FS}loader.jar \
+ -DCUSTOM_DB_DIR=${TESTCLASSES} \
+ -DCUSTOM_P11_CONFIG=${TESTSRC}${FS}BasicData${FS}p11-${token}.txt \
+ -DNO_DEFAULT=true \
+ -DNO_DEIMOS=true \
+ -DTOKEN=${token} \
+ -Djava.security.debug=${DEBUG} \
+ SecretKeysBasic
+
+# -DCUSTOM_P11_CONFIG=${TESTSRC}${FS}BasicData${FS}p11-${token}.txt \
+
+# save error status
+if [ $? != 0 ]
+then
+ echo "Test against " ${token} " Failed!"
+ STATUS=1
+fi
+
+# clean up
+${RM} ${USED_FILE_LIST}
+
+done
+
+# return
+exit ${STATUS}