diff --git a/.hgtags b/.hgtags index a48294ba6ceaf335fd75eae4b1186e3812707aa7..e774b097c5e65c5aa6852023a73930bc82c4f921 100644 --- a/.hgtags +++ b/.hgtags @@ -194,3 +194,4 @@ a8012d8d7e9c5035de0bdd4887dc9f7c54008f21 jdk8-b69 a996b57e554198f4592a5f3c30f2f9f4075e545d jdk8-b70 2a5af0f766d0acd68a81fb08fe11fd66795f86af jdk8-b71 32a57e645e012a1f0665c075969ca598e0dbb948 jdk8-b72 +733885f57e14cc27f5a5ff0dffe641d2fa3c704a jdk8-b73 diff --git a/make/common/Release.gmk b/make/common/Release.gmk index dc43ecf95ea87137feb1ef9030b6ef03f2ebd35e..367eab8fa7ebe669279ccfc5eee382832e14fda3 100644 --- a/make/common/Release.gmk +++ b/make/common/Release.gmk @@ -375,6 +375,7 @@ TOOLS = \ com/sun/tools/javadoc \ com/sun/tools/javah \ com/sun/tools/javap \ + com/sun/tools/jdeps \ com/sun/tools/corba \ com/sun/tools/internal/xjc \ com/sun/tools/internal/ws \ @@ -457,6 +458,7 @@ NOTJRETOOLS = \ javadoc$(EXE_SUFFIX) \ javah$(EXE_SUFFIX) \ javap$(EXE_SUFFIX) \ + jdeps$(EXE_SUFFIX) \ jcmd$(EXE_SUFFIX) \ jdb$(EXE_SUFFIX) \ jps$(EXE_SUFFIX) \ @@ -564,6 +566,7 @@ $(NOT_RT_JAR_LIST): FRC $(ECHO) "sun/tools/javac/" >> $@ $(ECHO) "com/sun/tools/classfile/" >> $@ $(ECHO) "com/sun/tools/javap/" >> $@ + $(ECHO) "com/sun/tools/jdeps/" >> $@ $(ECHO) "sun/tools/jcmd/" >> $@ $(ECHO) "sun/tools/jconsole/" >> $@ $(ECHO) "sun/tools/jps/" >> $@ diff --git a/make/docs/NON_CORE_PKGS.gmk b/make/docs/NON_CORE_PKGS.gmk index b299938e844ca8e7c6cd2e6c70d9adfaf9869df7..949637cfedac1076cb856b528f5d5bee25731066 100644 --- a/make/docs/NON_CORE_PKGS.gmk +++ b/make/docs/NON_CORE_PKGS.gmk @@ -76,7 +76,7 @@ ATTACH_PKGS = com.sun.tools.attach \ JCONSOLE_PKGS = com.sun.tools.jconsole -TREEAPI_PKGS = com.sunsource.doctree \ +TREEAPI_PKGS = com.sun.source.doctree \ com.sun.source.tree \ com.sun.source.util diff --git a/make/launchers/Makefile b/make/launchers/Makefile index 3d9511408b0766b71f4116a7346f8874d3ed9dab..be16512e478a69920406fb607f0fc2b20a65b5cc 100644 --- a/make/launchers/Makefile +++ b/make/launchers/Makefile @@ -63,6 +63,7 @@ $(call make-launcher, javac, com.sun.tools.javac.Main, , ) $(call make-launcher, javadoc, com.sun.tools.javadoc.Main, , ) $(call make-launcher, javah, com.sun.tools.javah.Main, , ) $(call make-launcher, javap, com.sun.tools.javap.Main, , ) +$(call make-launcher, jdeps, com.sun.tools.jdeps.Main, , ) $(call make-launcher, jcmd, sun.tools.jcmd.JCmd, , ) $(call make-launcher, jconsole, sun.tools.jconsole.JConsole, \ -J-Djconsole.showOutputViewer, ) diff --git a/make/launchers/Makefile.launcher b/make/launchers/Makefile.launcher index 1b3e51b6de84998b1ca9c3bf3f315318f5fbd7b1..bb06f80f7cc443b4f1ac9b9ea43b948b07186fcd 100644 --- a/make/launchers/Makefile.launcher +++ b/make/launchers/Makefile.launcher @@ -62,6 +62,10 @@ ifeq ($(PROGRAM),javap) WILDCARDS=true NEVER_ACT_AS_SERVER_CLASS_MACHINE=true endif +ifeq ($(PROGRAM),jdeps) + WILDCARDS=true + NEVER_ACT_AS_SERVER_CLASS_MACHINE=true +endif ifeq ($(PROGRAM),javah) WILDCARDS=true NEVER_ACT_AS_SERVER_CLASS_MACHINE=true diff --git a/makefiles/CompileLaunchers.gmk b/makefiles/CompileLaunchers.gmk index 7a6353426902335a1c7927ca3805cc4bdaa26e27..354fea12044a87404d7d93f96974acc30e47d2cf 100644 --- a/makefiles/CompileLaunchers.gmk +++ b/makefiles/CompileLaunchers.gmk @@ -270,6 +270,11 @@ $(eval $(call SetupLauncher,javap,\ -DNEVER_ACT_AS_SERVER_CLASS_MACHINE \ -DJAVA_ARGS='{ "-J-ms8m"$(COMMA) "com.sun.tools.javap.Main"$(COMMA) }')) +$(eval $(call SetupLauncher,jdeps,\ + -DEXPAND_CLASSPATH_WILDCARDS \ + -DNEVER_ACT_AS_SERVER_CLASS_MACHINE \ + -DJAVA_ARGS='{ "-J-ms8m"$(COMMA) "com.sun.tools.jdeps.Main"$(COMMA) }')) + BUILD_LAUNCHER_jconsole_CFLAGS_windows:=-DJAVAW BUILD_LAUNCHER_jconsole_LDFLAGS_windows:=user32.lib diff --git a/makefiles/CreateJars.gmk b/makefiles/CreateJars.gmk index 1f7096adf197047f58a0399337cfead22e318829..6250dd83fe20939516e949b478fa04fbf3be096d 100644 --- a/makefiles/CreateJars.gmk +++ b/makefiles/CreateJars.gmk @@ -747,6 +747,7 @@ TOOLS_JAR_INCLUDES := \ com/sun/tools/javadoc \ com/sun/tools/javah \ com/sun/tools/javap \ + com/sun/tools/jdeps \ com/sun/tools/jdi \ com/sun/tools/script/shell \ com/sun/xml/internal/dtdparser \ diff --git a/makefiles/Images.gmk b/makefiles/Images.gmk index 13a6d87f47365f0999cc9b7c56e3d209e08b97e5..53ea58d68ae97351d2e1d5c5bc7e5508ea16f85c 100644 --- a/makefiles/Images.gmk +++ b/makefiles/Images.gmk @@ -103,6 +103,7 @@ NOT_JRE_BIN_FILES := \ javadoc$(EXE_SUFFIX) \ javah$(EXE_SUFFIX) \ javap$(EXE_SUFFIX) \ + jdeps$(EXE_SUFFIX) \ jcmd$(EXE_SUFFIX) \ jdb$(EXE_SUFFIX) \ jps$(EXE_SUFFIX) \ diff --git a/src/share/classes/com/sun/crypto/provider/AESCipher.java b/src/share/classes/com/sun/crypto/provider/AESCipher.java index 0ae68957c43b86d46ffd7822433bce2b3af71773..32cb3e39d3dfecda66dd43b930d9afde52ef2865 100644 --- a/src/share/classes/com/sun/crypto/provider/AESCipher.java +++ b/src/share/classes/com/sun/crypto/provider/AESCipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ import java.security.spec.*; import javax.crypto.*; import javax.crypto.spec.*; import javax.crypto.BadPaddingException; +import java.nio.ByteBuffer; /** * This class implements the AES algorithm in its various modes @@ -127,6 +128,21 @@ abstract class AESCipher extends CipherSpi { super(32, "CFB", "NOPADDING"); } } + public static final class AES128_GCM_NoPadding extends OidImpl { + public AES128_GCM_NoPadding() { + super(16, "GCM", "NOPADDING"); + } + } + public static final class AES192_GCM_NoPadding extends OidImpl { + public AES192_GCM_NoPadding() { + super(24, "GCM", "NOPADDING"); + } + } + public static final class AES256_GCM_NoPadding extends OidImpl { + public AES256_GCM_NoPadding() { + super(32, "GCM", "NOPADDING"); + } + } // utility method used by AESCipher and AESWrapCipher static final void checkKeySize(Key key, int fixedKeySize) @@ -531,4 +547,79 @@ abstract class AESCipher extends CipherSpi { return core.unwrap(wrappedKey, wrappedKeyAlgorithm, wrappedKeyType); } + + /** + * Continues a multi-part update of the Additional Authentication + * Data (AAD), using a subset of the provided buffer. + *

+ * Calls to this method provide AAD to the cipher when operating in + * modes such as AEAD (GCM/CCM). If this cipher is operating in + * either GCM or CCM mode, all AAD must be supplied before beginning + * operations on the ciphertext (via the {@code update} and {@code + * doFinal} methods). + * + * @param src the buffer containing the AAD + * @param offset the offset in {@code src} where the AAD input starts + * @param len the number of AAD bytes + * + * @throws IllegalStateException if this cipher is in a wrong state + * (e.g., has not been initialized), does not accept AAD, or if + * operating in either GCM or CCM mode and one of the {@code update} + * methods has already been called for the active + * encryption/decryption operation + * @throws UnsupportedOperationException if this method + * has not been overridden by an implementation + * + * @since 1.8 + */ + @Override + protected void engineUpdateAAD(byte[] src, int offset, int len) { + core.updateAAD(src, offset, len); + } + + /** + * Continues a multi-part update of the Additional Authentication + * Data (AAD). + *

+ * Calls to this method provide AAD to the cipher when operating in + * modes such as AEAD (GCM/CCM). If this cipher is operating in + * either GCM or CCM mode, all AAD must be supplied before beginning + * operations on the ciphertext (via the {@code update} and {@code + * doFinal} methods). + *

+ * All {@code src.remaining()} bytes starting at + * {@code src.position()} are processed. + * Upon return, the input buffer's position will be equal + * to its limit; its limit will not have changed. + * + * @param src the buffer containing the AAD + * + * @throws IllegalStateException if this cipher is in a wrong state + * (e.g., has not been initialized), does not accept AAD, or if + * operating in either GCM or CCM mode and one of the {@code update} + * methods has already been called for the active + * encryption/decryption operation + * @throws UnsupportedOperationException if this method + * has not been overridden by an implementation + * + * @since 1.8 + */ + @Override + protected void engineUpdateAAD(ByteBuffer src) { + if (src != null) { + int aadLen = src.limit() - src.position(); + if (aadLen != 0) { + if (src.hasArray()) { + int aadOfs = src.arrayOffset() + src.position(); + core.updateAAD(src.array(), aadOfs, aadLen); + src.position(src.limit()); + } else { + byte[] aad = new byte[aadLen]; + src.get(aad); + core.updateAAD(aad, 0, aadLen); + } + } + } + } } + diff --git a/src/share/classes/com/sun/crypto/provider/AESKeyGenerator.java b/src/share/classes/com/sun/crypto/provider/AESKeyGenerator.java index 8d8145c0247e2efb825e2d97ab6c7de631a837b2..c58d52b55f302b40783314c40768c7a04eb1f33c 100644 --- a/src/share/classes/com/sun/crypto/provider/AESKeyGenerator.java +++ b/src/share/classes/com/sun/crypto/provider/AESKeyGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -106,7 +106,7 @@ public final class AESKeyGenerator extends KeyGeneratorSpi { SecretKeySpec aesKey = null; if (this.random == null) { - this.random = SunJCE.RANDOM; + this.random = SunJCE.getRandom(); } byte[] keyBytes = new byte[keySize]; diff --git a/src/share/classes/com/sun/crypto/provider/BlowfishKeyGenerator.java b/src/share/classes/com/sun/crypto/provider/BlowfishKeyGenerator.java index be747cbe01c9b5a74cfffbc13efaa18cc16c32f8..ceadbe339de48b675108df9a43bdf7599751d537 100644 --- a/src/share/classes/com/sun/crypto/provider/BlowfishKeyGenerator.java +++ b/src/share/classes/com/sun/crypto/provider/BlowfishKeyGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -104,7 +104,7 @@ public final class BlowfishKeyGenerator extends KeyGeneratorSpi { */ protected SecretKey engineGenerateKey() { if (this.random == null) { - this.random = SunJCE.RANDOM; + this.random = SunJCE.getRandom(); } byte[] keyBytes = new byte[this.keysize]; diff --git a/src/share/classes/com/sun/crypto/provider/CipherCore.java b/src/share/classes/com/sun/crypto/provider/CipherCore.java index eb30879b0b97666f216bcf4c7ff96ccc68efc8bc..5c35c038915d9e05c0233ac2a13450b8d4cace21 100644 --- a/src/share/classes/com/sun/crypto/provider/CipherCore.java +++ b/src/share/classes/com/sun/crypto/provider/CipherCore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ package com.sun.crypto.provider; +import java.util.Arrays; import java.util.Locale; import java.security.*; @@ -59,7 +60,7 @@ final class CipherCore { private byte[] buffer = null; /* - * internal buffer + * block size of cipher in bytes */ private int blockSize = 0; @@ -76,10 +77,12 @@ final class CipherCore { /* * minimum number of bytes in the buffer required for * FeedbackCipher.encryptFinal()/decryptFinal() call. - * update() must buffer this many bytes before before starting + * update() must buffer this many bytes before starting * to encrypt/decrypt data. - * currently, only CTS mode has a non-zero value due to its special - * handling on the last two blocks (the last one may be incomplete). + * currently, only the following cases have non-zero values: + * 1) CTS mode - due to its special handling on the last two blocks + * (the last one may be incomplete). + * 2) GCM mode + decryption - due to its trailing tag bytes */ private int minBytes = 0; @@ -121,6 +124,24 @@ final class CipherCore { private static final int PCBC_MODE = 4; private static final int CTR_MODE = 5; private static final int CTS_MODE = 6; + private static final int GCM_MODE = 7; + + /* + * variables used for performing the GCM (key+iv) uniqueness check. + * To use GCM mode safely, the cipher object must be re-initialized + * with a different combination of key + iv values for each + * encryption operation. However, checking all past key + iv values + * isn't feasible. Thus, we only do a per-instance check of the + * key + iv values used in previous encryption. + * For decryption operations, no checking is necessary. + * NOTE: this key+iv check have to be done inside CipherCore class + * since CipherCore class buffers potential tag bytes in GCM mode + * and may not call GaloisCounterMode when there isn't sufficient + * input to process. + */ + private boolean requireReinit = false; + private byte[] lastEncKey = null; + private byte[] lastEncIv = null; /** * Creates an instance of CipherCore with default ECB mode and @@ -149,7 +170,7 @@ final class CipherCore { * @param mode the cipher mode * * @exception NoSuchAlgorithmException if the requested cipher mode does - * not exist + * not exist for this cipher */ void setMode(String mode) throws NoSuchAlgorithmException { if (mode == null) @@ -165,30 +186,34 @@ final class CipherCore { if (modeUpperCase.equals("CBC")) { cipherMode = CBC_MODE; cipher = new CipherBlockChaining(rawImpl); - } - else if (modeUpperCase.equals("CTS")) { + } else if (modeUpperCase.equals("CTS")) { cipherMode = CTS_MODE; cipher = new CipherTextStealing(rawImpl); minBytes = blockSize+1; padding = null; - } - else if (modeUpperCase.equals("CTR")) { + } else if (modeUpperCase.equals("CTR")) { cipherMode = CTR_MODE; cipher = new CounterMode(rawImpl); unitBytes = 1; padding = null; - } - else if (modeUpperCase.startsWith("CFB")) { + } else if (modeUpperCase.startsWith("GCM")) { + // can only be used for block ciphers w/ 128-bit block size + if (blockSize != 16) { + throw new NoSuchAlgorithmException + ("GCM mode can only be used for AES cipher"); + } + cipherMode = GCM_MODE; + cipher = new GaloisCounterMode(rawImpl); + padding = null; + } else if (modeUpperCase.startsWith("CFB")) { cipherMode = CFB_MODE; unitBytes = getNumOfUnit(mode, "CFB".length(), blockSize); cipher = new CipherFeedback(rawImpl, unitBytes); - } - else if (modeUpperCase.startsWith("OFB")) { + } else if (modeUpperCase.startsWith("OFB")) { cipherMode = OFB_MODE; unitBytes = getNumOfUnit(mode, "OFB".length(), blockSize); cipher = new OutputFeedback(rawImpl, unitBytes); - } - else if (modeUpperCase.equals("PCBC")) { + } else if (modeUpperCase.equals("PCBC")) { cipherMode = PCBC_MODE; cipher = new PCBC(rawImpl); } @@ -219,6 +244,7 @@ final class CipherCore { return result; } + /** * Sets the padding mechanism of this cipher. * @@ -242,11 +268,27 @@ final class CipherCore { + " not implemented"); } if ((padding != null) && - ((cipherMode == CTR_MODE) || (cipherMode == CTS_MODE))) { + ((cipherMode == CTR_MODE) || (cipherMode == CTS_MODE) + || (cipherMode == GCM_MODE))) { padding = null; - throw new NoSuchPaddingException - ((cipherMode == CTR_MODE? "CTR":"CTS") + - " mode must be used with NoPadding"); + String modeStr = null; + switch (cipherMode) { + case CTR_MODE: + modeStr = "CTR"; + break; + case GCM_MODE: + modeStr = "GCM"; + break; + case CTS_MODE: + modeStr = "CTS"; + break; + default: + // should never happen + } + if (modeStr != null) { + throw new NoSuchPaddingException + (modeStr + " mode must be used with NoPadding"); + } } } @@ -257,7 +299,7 @@ final class CipherCore { * inputLen (in bytes). * *

This call takes into account any unprocessed (buffered) data from a - * previous update call, and padding. + * previous update call, padding, and AEAD tagging. * *

The actual output length of the next update or * doFinal call may be smaller than the length returned by @@ -270,23 +312,60 @@ final class CipherCore { int getOutputSize(int inputLen) { int totalLen = buffered + inputLen; - if (padding == null) + // GCM: this call may be for either update() or doFinal(), so have to + // return the larger value of both + // Encryption: based on doFinal value: inputLen + tag + // Decryption: based on update value: inputLen + if (!decrypting && (cipherMode == GCM_MODE)) { + return (totalLen + ((GaloisCounterMode) cipher).getTagLen()); + } + + if (padding == null) { return totalLen; + } - if (decrypting) + if (decrypting) { return totalLen; + } if (unitBytes != blockSize) { - if (totalLen < diffBlocksize) + if (totalLen < diffBlocksize) { return diffBlocksize; - else + } else { return (totalLen + blockSize - ((totalLen - diffBlocksize) % blockSize)); + } } else { return totalLen + padding.padLength(totalLen); } } + private int getOutputSizeByOperation(int inputLen, boolean isDoFinal) { + int totalLen = 0; + switch (cipherMode) { + case GCM_MODE: + totalLen = buffered + inputLen; + if (isDoFinal) { + int tagLen = ((GaloisCounterMode) cipher).getTagLen(); + if (decrypting) { + // need to get the actual value from cipher?? + // deduct tagLen + totalLen -= tagLen; + } else { + totalLen += tagLen; + } + } + if (totalLen < 0) { + totalLen = 0; + } + break; + default: + totalLen = getOutputSize(inputLen); + break; + } + return totalLen; + } + /** * Returns the initialization vector (IV) in a new buffer. * @@ -318,34 +397,49 @@ final class CipherCore { * does not use any parameters. */ AlgorithmParameters getParameters(String algName) { + if (cipherMode == ECB_MODE) { + return null; + } AlgorithmParameters params = null; - if (cipherMode == ECB_MODE) return null; + AlgorithmParameterSpec spec; byte[] iv = getIV(); - if (iv != null) { - AlgorithmParameterSpec ivSpec; - if (algName.equals("RC2")) { - RC2Crypt rawImpl = (RC2Crypt) cipher.getEmbeddedCipher(); - ivSpec = new RC2ParameterSpec(rawImpl.getEffectiveKeyBits(), - iv); + if (iv == null) { + // generate spec using default value + if (cipherMode == GCM_MODE) { + iv = new byte[GaloisCounterMode.DEFAULT_IV_LEN]; } else { - ivSpec = new IvParameterSpec(iv); - } - try { - params = AlgorithmParameters.getInstance(algName, "SunJCE"); - } catch (NoSuchAlgorithmException nsae) { - // should never happen - throw new RuntimeException("Cannot find " + algName + - " AlgorithmParameters implementation in SunJCE provider"); - } catch (NoSuchProviderException nspe) { - // should never happen - throw new RuntimeException("Cannot find SunJCE provider"); - } - try { - params.init(ivSpec); - } catch (InvalidParameterSpecException ipse) { - // should never happen - throw new RuntimeException("IvParameterSpec not supported"); + iv = new byte[blockSize]; } + SunJCE.getRandom().nextBytes(iv); + } + if (cipherMode == GCM_MODE) { + algName = "GCM"; + spec = new GCMParameterSpec + (((GaloisCounterMode) cipher).getTagLen()*8, iv); + } else { + if (algName.equals("RC2")) { + RC2Crypt rawImpl = (RC2Crypt) cipher.getEmbeddedCipher(); + spec = new RC2ParameterSpec + (rawImpl.getEffectiveKeyBits(), iv); + } else { + spec = new IvParameterSpec(iv); + } + } + try { + params = AlgorithmParameters.getInstance(algName, "SunJCE"); + } catch (NoSuchAlgorithmException nsae) { + // should never happen + throw new RuntimeException("Cannot find " + algName + + " AlgorithmParameters implementation in SunJCE provider"); + } catch (NoSuchProviderException nspe) { + // should never happen + throw new RuntimeException("Cannot find SunJCE provider"); + } + try { + params.init(spec); + } catch (InvalidParameterSpecException ipse) { + // should never happen + throw new RuntimeException(spec.getClass() + " not supported"); } return params; } @@ -420,44 +514,63 @@ final class CipherCore { || (opmode == Cipher.UNWRAP_MODE); byte[] keyBytes = getKeyBytes(key); - - byte[] ivBytes; - if (params == null) { - ivBytes = null; - } else if (params instanceof IvParameterSpec) { - ivBytes = ((IvParameterSpec)params).getIV(); - if ((ivBytes == null) || (ivBytes.length != blockSize)) { - throw new InvalidAlgorithmParameterException - ("Wrong IV length: must be " + blockSize + - " bytes long"); - } - } else if (params instanceof RC2ParameterSpec) { - ivBytes = ((RC2ParameterSpec)params).getIV(); - if ((ivBytes != null) && (ivBytes.length != blockSize)) { - throw new InvalidAlgorithmParameterException - ("Wrong IV length: must be " + blockSize + - " bytes long"); + int tagLen = -1; + byte[] ivBytes = null; + if (params != null) { + if (cipherMode == GCM_MODE) { + if (params instanceof GCMParameterSpec) { + tagLen = ((GCMParameterSpec)params).getTLen(); + if (tagLen < 96 || tagLen > 128 || ((tagLen & 0x07) != 0)) { + throw new InvalidAlgorithmParameterException + ("Unsupported TLen value; must be one of " + + "{128, 120, 112, 104, 96}"); + } + tagLen = tagLen >> 3; + ivBytes = ((GCMParameterSpec)params).getIV(); + } else { + throw new InvalidAlgorithmParameterException + ("Unsupported parameter: " + params); + } + } else { + if (params instanceof IvParameterSpec) { + ivBytes = ((IvParameterSpec)params).getIV(); + if ((ivBytes == null) || (ivBytes.length != blockSize)) { + throw new InvalidAlgorithmParameterException + ("Wrong IV length: must be " + blockSize + + " bytes long"); + } + } else if (params instanceof RC2ParameterSpec) { + ivBytes = ((RC2ParameterSpec)params).getIV(); + if ((ivBytes != null) && (ivBytes.length != blockSize)) { + throw new InvalidAlgorithmParameterException + ("Wrong IV length: must be " + blockSize + + " bytes long"); + } + } else { + throw new InvalidAlgorithmParameterException + ("Unsupported parameter: " + params); + } } - } else { - throw new InvalidAlgorithmParameterException("Wrong parameter " - + "type: IV " - + "expected"); } - if (cipherMode == ECB_MODE) { if (ivBytes != null) { throw new InvalidAlgorithmParameterException ("ECB mode cannot use IV"); } - } else if (ivBytes == null) { + } else if (ivBytes == null) { if (decrypting) { throw new InvalidAlgorithmParameterException("Parameters " + "missing"); } + if (random == null) { - random = SunJCE.RANDOM; + random = SunJCE.getRandom(); + } + if (cipherMode == GCM_MODE) { + ivBytes = new byte[GaloisCounterMode.DEFAULT_IV_LEN]; + } else { + ivBytes = new byte[blockSize]; } - ivBytes = new byte[blockSize]; random.nextBytes(ivBytes); } @@ -466,23 +579,57 @@ final class CipherCore { String algorithm = key.getAlgorithm(); - cipher.init(decrypting, algorithm, keyBytes, ivBytes); + // GCM mode needs additional handling + if (cipherMode == GCM_MODE) { + if(tagLen == -1) { + tagLen = GaloisCounterMode.DEFAULT_TAG_LEN; + } + if (decrypting) { + minBytes = tagLen; + } else { + // check key+iv for encryption in GCM mode + requireReinit = + Arrays.equals(ivBytes, lastEncIv) && + Arrays.equals(keyBytes, lastEncKey); + if (requireReinit) { + throw new InvalidAlgorithmParameterException + ("Cannot reuse iv for GCM encryption"); + } + lastEncIv = ivBytes; + lastEncKey = keyBytes; + } + ((GaloisCounterMode) cipher).init + (decrypting, algorithm, keyBytes, ivBytes, tagLen); + } else { + cipher.init(decrypting, algorithm, keyBytes, ivBytes); + } + // skip checking key+iv from now on until after doFinal() + requireReinit = false; } void init(int opmode, Key key, AlgorithmParameters params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { - IvParameterSpec ivSpec = null; + AlgorithmParameterSpec spec = null; + String paramType = null; if (params != null) { try { - ivSpec = params.getParameterSpec(IvParameterSpec.class); + if (cipherMode == GCM_MODE) { + paramType = "GCM"; + spec = params.getParameterSpec(GCMParameterSpec.class); + } else { + // NOTE: RC2 parameters are always handled through + // init(..., AlgorithmParameterSpec,...) method, so + // we can assume IvParameterSpec type here. + paramType = "IV"; + spec = params.getParameterSpec(IvParameterSpec.class); + } } catch (InvalidParameterSpecException ipse) { - throw new InvalidAlgorithmParameterException("Wrong parameter " - + "type: IV " - + "expected"); + throw new InvalidAlgorithmParameterException + ("Wrong parameter type: " + paramType + " expected"); } } - init(opmode, key, ivSpec, random); + init(opmode, key, spec, random); } /** @@ -504,6 +651,7 @@ final class CipherCore { return keyBytes; } + /** * Continues a multiple-part encryption or decryption operation * (depending on how this cipher was initialized), processing another data @@ -524,22 +672,25 @@ final class CipherCore { * (e.g., has not been initialized) */ byte[] update(byte[] input, int inputOffset, int inputLen) { + if (requireReinit) { + throw new IllegalStateException + ("Must use either different key or iv for GCM encryption"); + } + byte[] output = null; - byte[] out = null; try { - output = new byte[getOutputSize(inputLen)]; + output = new byte[getOutputSizeByOperation(inputLen, false)]; int len = update(input, inputOffset, inputLen, output, 0); if (len == output.length) { - out = output; + return output; } else { - out = new byte[len]; - System.arraycopy(output, 0, out, 0, len); + return Arrays.copyOf(output, len); } } catch (ShortBufferException e) { - // never thrown + // should never happen + throw new ProviderException("Unexpected exception", e); } - return out; } /** @@ -567,6 +718,11 @@ final class CipherCore { */ int update(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException { + if (requireReinit) { + throw new IllegalStateException + ("Must use either different key or iv for GCM encryption"); + } + // figure out how much can be sent to crypto function int len = buffered + inputLen - minBytes; if (padding != null && decrypting) { @@ -582,6 +738,7 @@ final class CipherCore { + "(at least) " + len + " bytes long"); } + if (len != 0) { // there is some work to do byte[] in = new byte[len]; @@ -600,7 +757,6 @@ final class CipherCore { System.arraycopy(input, inputOffset, in, bufferedConsumed, inputConsumed); } - if (decrypting) { cipher.decrypt(in, 0, len, output, outputOffset); } else { @@ -611,11 +767,12 @@ final class CipherCore { // the total input length a multiple of blocksize when // padding is applied if (unitBytes != blockSize) { - if (len < diffBlocksize) + if (len < diffBlocksize) { diffBlocksize -= len; - else + } else { diffBlocksize = blockSize - ((len - diffBlocksize) % blockSize); + } } inputLen -= inputConsumed; @@ -669,21 +826,18 @@ final class CipherCore { byte[] doFinal(byte[] input, int inputOffset, int inputLen) throws IllegalBlockSizeException, BadPaddingException { byte[] output = null; - byte[] out = null; try { - output = new byte[getOutputSize(inputLen)]; + output = new byte[getOutputSizeByOperation(inputLen, true)]; int len = doFinal(input, inputOffset, inputLen, output, 0); if (len < output.length) { - out = new byte[len]; - if (len != 0) - System.arraycopy(output, 0, out, 0, len); + return Arrays.copyOf(output, len); } else { - out = output; + return output; } } catch (ShortBufferException e) { // never thrown + throw new ProviderException("Unexpected exception", e); } - return out; } /** @@ -726,6 +880,10 @@ final class CipherCore { int outputOffset) throws IllegalBlockSizeException, ShortBufferException, BadPaddingException { + if (requireReinit) { + throw new IllegalStateException + ("Must use either different key or iv for GCM encryption"); + } // calculate the total input length int totalLen = buffered + inputLen; @@ -752,8 +910,9 @@ final class CipherCore { } // if encrypting and padding not null, add padding - if (!decrypting && padding != null) + if (!decrypting && padding != null) { paddedLen += paddingLen; + } // check output buffer capacity. // if we are decrypting with padding applied, we can perform this @@ -763,8 +922,8 @@ final class CipherCore { throw new ShortBufferException("Output buffer is null"); } int outputCapacity = output.length - outputOffset; - if (((!decrypting) || (padding == null)) && - (outputCapacity < paddedLen) || + + if (((!decrypting) && (outputCapacity < paddedLen)) || (decrypting && (outputCapacity < (paddedLen - blockSize)))) { throw new ShortBufferException("Output buffer too short: " + outputCapacity + " bytes given, " @@ -812,6 +971,7 @@ final class CipherCore { } totalLen = padStart; } + if ((output.length - outputOffset) < totalLen) { // restore so users can retry with a larger buffer cipher.restore(); @@ -824,8 +984,13 @@ final class CipherCore { output[outputOffset + i] = outWithPadding[i]; } } else { // encrypting - totalLen = finalNoPadding(finalBuf, finalOffset, output, - outputOffset, paddedLen); + try { + totalLen = finalNoPadding(finalBuf, finalOffset, output, + outputOffset, paddedLen); + } finally { + // reset after doFinal() for GCM encryption + requireReinit = (cipherMode == GCM_MODE); + } } buffered = 0; @@ -836,33 +1001,33 @@ final class CipherCore { return totalLen; } - private int finalNoPadding(byte[] in, int inOff, byte[] out, int outOff, + private int finalNoPadding(byte[] in, int inOfs, byte[] out, int outOfs, int len) - throws IllegalBlockSizeException - { - if (in == null || len == 0) - return 0; + throws IllegalBlockSizeException, AEADBadTagException { - if ((cipherMode != CFB_MODE) && (cipherMode != OFB_MODE) - && ((len % unitBytes) != 0) && (cipherMode != CTS_MODE)) { - if (padding != null) { - throw new IllegalBlockSizeException - ("Input length (with padding) not multiple of " + - unitBytes + " bytes"); - } else { - throw new IllegalBlockSizeException - ("Input length not multiple of " + unitBytes - + " bytes"); - } + if ((cipherMode != GCM_MODE) && (in == null || len == 0)) { + return 0; } - + if ((cipherMode != CFB_MODE) && (cipherMode != OFB_MODE) && + (cipherMode != GCM_MODE) && + ((len % unitBytes) != 0) && (cipherMode != CTS_MODE)) { + if (padding != null) { + throw new IllegalBlockSizeException + ("Input length (with padding) not multiple of " + + unitBytes + " bytes"); + } else { + throw new IllegalBlockSizeException + ("Input length not multiple of " + unitBytes + + " bytes"); + } + } + int outLen = 0; if (decrypting) { - cipher.decryptFinal(in, inOff, len, out, outOff); + outLen = cipher.decryptFinal(in, inOfs, len, out, outOfs); } else { - cipher.encryptFinal(in, inOff, len, out, outOff); + outLen = cipher.encryptFinal(in, inOfs, len, out, outOfs); } - - return len; + return outLen; } // Note: Wrap() and Unwrap() are the same in @@ -939,4 +1104,36 @@ final class CipherCore { return ConstructKeys.constructKey(encodedKey, wrappedKeyAlgorithm, wrappedKeyType); } + + /** + * Continues a multi-part update of the Additional Authentication + * Data (AAD), using a subset of the provided buffer. + *

+ * Calls to this method provide AAD to the cipher when operating in + * modes such as AEAD (GCM/CCM). If this cipher is operating in + * either GCM or CCM mode, all AAD must be supplied before beginning + * operations on the ciphertext (via the {@code update} and {@code + * doFinal} methods). + * + * @param src the buffer containing the AAD + * @param offset the offset in {@code src} where the AAD input starts + * @param len the number of AAD bytes + * + * @throws IllegalStateException if this cipher is in a wrong state + * (e.g., has not been initialized), does not accept AAD, or if + * operating in either GCM or CCM mode and one of the {@code update} + * methods has already been called for the active + * encryption/decryption operation + * @throws UnsupportedOperationException if this method + * has not been overridden by an implementation + * + * @since 1.8 + */ + void updateAAD(byte[] src, int offset, int len) { + if (requireReinit) { + throw new IllegalStateException + ("Must use either different key or iv for GCM encryption"); + } + cipher.updateAAD(src, offset, len); + } } diff --git a/src/share/classes/com/sun/crypto/provider/CipherTextStealing.java b/src/share/classes/com/sun/crypto/provider/CipherTextStealing.java index ef77d3e5360bfe05c3d8d3c6e80ce6d729d6f3f1..630f8707fdeb7f2c582dfaba6dab0bf7fade9d55 100644 --- a/src/share/classes/com/sun/crypto/provider/CipherTextStealing.java +++ b/src/share/classes/com/sun/crypto/provider/CipherTextStealing.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -83,9 +83,10 @@ final class CipherTextStealing extends CipherBlockChaining { * @param plainLen the length of the input data * @param cipher the buffer for the result * @param cipherOffset the offset in cipher + * @return the number of bytes placed into cipher */ - void encryptFinal(byte[] plain, int plainOffset, int plainLen, - byte[] cipher, int cipherOffset) + int encryptFinal(byte[] plain, int plainOffset, int plainLen, + byte[] cipher, int cipherOffset) throws IllegalBlockSizeException { if (plainLen < blockSize) { @@ -134,6 +135,7 @@ final class CipherTextStealing extends CipherBlockChaining { embeddedCipher.encryptBlock(tmp2, 0, cipher, cipherOffset); } } + return plainLen; } /** @@ -158,9 +160,10 @@ final class CipherTextStealing extends CipherBlockChaining { * @param cipherLen the length of the input data * @param plain the buffer for the result * @param plainOffset the offset in plain + * @return the number of bytes placed into plain */ - void decryptFinal(byte[] cipher, int cipherOffset, int cipherLen, - byte[] plain, int plainOffset) + int decryptFinal(byte[] cipher, int cipherOffset, int cipherLen, + byte[] plain, int plainOffset) throws IllegalBlockSizeException { if (cipherLen < blockSize) { throw new IllegalBlockSizeException("input is too short!"); @@ -211,5 +214,6 @@ final class CipherTextStealing extends CipherBlockChaining { } } } + return cipherLen; } } diff --git a/src/share/classes/com/sun/crypto/provider/DESKeyGenerator.java b/src/share/classes/com/sun/crypto/provider/DESKeyGenerator.java index b082a9934088467f39e7a17a85555390d5c4fe37..cca8659974fc9a1c5b8106552d9922611791e0c6 100644 --- a/src/share/classes/com/sun/crypto/provider/DESKeyGenerator.java +++ b/src/share/classes/com/sun/crypto/provider/DESKeyGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -102,7 +102,7 @@ public final class DESKeyGenerator extends KeyGeneratorSpi { DESKey desKey = null; if (this.random == null) { - this.random = SunJCE.RANDOM; + this.random = SunJCE.getRandom(); } try { diff --git a/src/share/classes/com/sun/crypto/provider/DESedeKeyGenerator.java b/src/share/classes/com/sun/crypto/provider/DESedeKeyGenerator.java index 42c09c0c2b785d791969cd2c28cc5ef775400d50..28684b0f9e7af67973122bb7d20ea9032dd8a66d 100644 --- a/src/share/classes/com/sun/crypto/provider/DESedeKeyGenerator.java +++ b/src/share/classes/com/sun/crypto/provider/DESedeKeyGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -105,7 +105,7 @@ public final class DESedeKeyGenerator extends KeyGeneratorSpi { */ protected SecretKey engineGenerateKey() { if (this.random == null) { - this.random = SunJCE.RANDOM; + this.random = SunJCE.getRandom(); } byte[] rawkey = new byte[DESedeKeySpec.DES_EDE_KEY_LEN]; diff --git a/src/share/classes/com/sun/crypto/provider/DESedeWrapCipher.java b/src/share/classes/com/sun/crypto/provider/DESedeWrapCipher.java index 07b5a778dcaa491a5575ffde0dd78df610450559..4a87b5b1faed35dedb015499e7b51490f89c30ac 100644 --- a/src/share/classes/com/sun/crypto/provider/DESedeWrapCipher.java +++ b/src/share/classes/com/sun/crypto/provider/DESedeWrapCipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -217,7 +217,7 @@ public final class DESedeWrapCipher extends CipherSpi { if (params == null) { iv = new byte[8]; if (random == null) { - random = SunJCE.RANDOM; + random = SunJCE.getRandom(); } random.nextBytes(iv); } diff --git a/src/share/classes/com/sun/crypto/provider/DHKeyPairGenerator.java b/src/share/classes/com/sun/crypto/provider/DHKeyPairGenerator.java index 533d80d49af2d5f08517e90cb37b6758e43aa223..6ae39e25e7e0b17eef23b7cc751fd22f574ec8e4 100644 --- a/src/share/classes/com/sun/crypto/provider/DHKeyPairGenerator.java +++ b/src/share/classes/com/sun/crypto/provider/DHKeyPairGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -140,7 +140,7 @@ public final class DHKeyPairGenerator extends KeyPairGeneratorSpi { */ public KeyPair generateKeyPair() { if (random == null) { - random = SunJCE.RANDOM; + random = SunJCE.getRandom(); } if (params == null) { diff --git a/src/share/classes/com/sun/crypto/provider/DHParameterGenerator.java b/src/share/classes/com/sun/crypto/provider/DHParameterGenerator.java index 0088729d27d47b7249bb160d3a530d1776312d2d..a976da099fba0f38d87e202b0edb44cf8692c27b 100644 --- a/src/share/classes/com/sun/crypto/provider/DHParameterGenerator.java +++ b/src/share/classes/com/sun/crypto/provider/DHParameterGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -131,7 +131,7 @@ extends AlgorithmParameterGeneratorSpi { } if (this.random == null) - this.random = SunJCE.RANDOM; + this.random = SunJCE.getRandom(); try { AlgorithmParameterGenerator paramGen; diff --git a/src/share/classes/com/sun/crypto/provider/FeedbackCipher.java b/src/share/classes/com/sun/crypto/provider/FeedbackCipher.java index 34b83ae928b342720f521e08901c5d01561b33b7..c27332457f3bf9ced8fd680b9c11eab890f3afe3 100644 --- a/src/share/classes/com/sun/crypto/provider/FeedbackCipher.java +++ b/src/share/classes/com/sun/crypto/provider/FeedbackCipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ package com.sun.crypto.provider; import java.security.InvalidKeyException; -import javax.crypto.IllegalBlockSizeException; +import javax.crypto.*; /** * This class represents a block cipher in one of its modes. It wraps @@ -150,11 +150,13 @@ abstract class FeedbackCipher { * @param plainLen the length of the input data * @param cipher the buffer for the encryption result * @param cipherOffset the offset in cipher + * @return the number of bytes placed into cipher */ - void encryptFinal(byte[] plain, int plainOffset, int plainLen, - byte[] cipher, int cipherOffset) + int encryptFinal(byte[] plain, int plainOffset, int plainLen, + byte[] cipher, int cipherOffset) throws IllegalBlockSizeException { encrypt(plain, plainOffset, plainLen, cipher, cipherOffset); + return plainLen; } /** * Performs decryption operation. @@ -190,10 +192,40 @@ abstract class FeedbackCipher { * @param cipherLen the length of the input data * @param plain the buffer for the decryption result * @param plainOffset the offset in plain + * @return the number of bytes placed into plain */ - void decryptFinal(byte[] cipher, int cipherOffset, int cipherLen, - byte[] plain, int plainOffset) - throws IllegalBlockSizeException { + int decryptFinal(byte[] cipher, int cipherOffset, int cipherLen, + byte[] plain, int plainOffset) + throws IllegalBlockSizeException, AEADBadTagException { decrypt(cipher, cipherOffset, cipherLen, plain, plainOffset); + return cipherLen; } + + /** + * Continues a multi-part update of the Additional Authentication + * Data (AAD), using a subset of the provided buffer. If this + * cipher is operating in either GCM or CCM mode, all AAD must be + * supplied before beginning operations on the ciphertext (via the + * {@code update} and {@code doFinal} methods). + *

+ * NOTE: Given most modes do not accept AAD, default impl for this + * method throws IllegalStateException. + * + * @param src the buffer containing the AAD + * @param offset the offset in {@code src} where the AAD input starts + * @param len the number of AAD bytes + * + * @throws IllegalStateException if this cipher is in a wrong state + * (e.g., has not been initialized), does not accept AAD, or if + * operating in either GCM or CCM mode and one of the {@code update} + * methods has already been called for the active + * encryption/decryption operation + * @throws UnsupportedOperationException if this method + * has not been overridden by an implementation + * + * @since 1.8 + */ + void updateAAD(byte[] src, int offset, int len) { + throw new IllegalStateException("No AAD accepted"); + } } diff --git a/src/share/classes/com/sun/crypto/provider/GCMParameters.java b/src/share/classes/com/sun/crypto/provider/GCMParameters.java new file mode 100644 index 0000000000000000000000000000000000000000..4ae729204a6590c16df16177c67476cca8586ef0 --- /dev/null +++ b/src/share/classes/com/sun/crypto/provider/GCMParameters.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.crypto.provider; + +import java.io.IOException; +import java.security.AlgorithmParametersSpi; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidParameterSpecException; +import javax.crypto.spec.GCMParameterSpec; +import sun.misc.HexDumpEncoder; +import sun.security.util.*; + +/** + * This class implements the parameter set used with + * GCM encryption, which is defined in RFC 5084 as follows: + * + *

+ *    GCMParameters ::= SEQUENCE {
+ *      aes-iv      OCTET STRING, -- recommended size is 12 octets
+ *      aes-tLen    AES-GCM-ICVlen DEFAULT 12 }
+ *
+ *    AES-GCM-ICVlen ::= INTEGER (12 | 13 | 14 | 15 | 16)
+ *
+ * 
+ * + * @author Valerie Peng + * @since 1.8 + */ +public final class GCMParameters extends AlgorithmParametersSpi { + + // the iv + private byte[] iv; + // the tag length in bytes + private int tLen; + + public GCMParameters() {} + + protected void engineInit(AlgorithmParameterSpec paramSpec) + throws InvalidParameterSpecException { + + if (!(paramSpec instanceof GCMParameterSpec)) { + throw new InvalidParameterSpecException + ("Inappropriate parameter specification"); + } + GCMParameterSpec gps = (GCMParameterSpec) paramSpec; + // need to convert from bits to bytes for ASN.1 encoding + this.tLen = gps.getTLen()/8; + this.iv = gps.getIV(); + } + + protected void engineInit(byte[] encoded) throws IOException { + DerValue val = new DerValue(encoded); + // check if IV or params + if (val.tag == DerValue.tag_Sequence) { + byte[] iv = val.data.getOctetString(); + int tLen; + if (val.data.available() != 0) { + tLen = val.data.getInteger(); + if (tLen < 12 || tLen > 16 ) { + throw new IOException + ("GCM parameter parsing error: unsupported tag len: " + + tLen); + } + if (val.data.available() != 0) { + throw new IOException + ("GCM parameter parsing error: extra data"); + } + } else { + tLen = 12; + } + this.iv = iv.clone(); + this.tLen = tLen; + } else { + throw new IOException("GCM parameter parsing error: no SEQ tag"); + } + } + + protected void engineInit(byte[] encoded, String decodingMethod) + throws IOException { + engineInit(encoded); + } + + protected + T engineGetParameterSpec(Class paramSpec) + throws InvalidParameterSpecException { + + if (GCMParameterSpec.class.isAssignableFrom(paramSpec)) { + return paramSpec.cast(new GCMParameterSpec(tLen * 8, iv)); + } else { + throw new InvalidParameterSpecException + ("Inappropriate parameter specification"); + } + } + + protected byte[] engineGetEncoded() throws IOException { + DerOutputStream out = new DerOutputStream(); + DerOutputStream bytes = new DerOutputStream(); + + bytes.putOctetString(iv); + bytes.putInteger(tLen); + out.write(DerValue.tag_Sequence, bytes); + return out.toByteArray(); + } + + protected byte[] engineGetEncoded(String encodingMethod) + throws IOException { + return engineGetEncoded(); + } + + /* + * Returns a formatted string describing the parameters. + */ + protected String engineToString() { + String LINE_SEP = System.getProperty("line.separator"); + HexDumpEncoder encoder = new HexDumpEncoder(); + StringBuilder sb + = new StringBuilder(LINE_SEP + " iv:" + LINE_SEP + "[" + + encoder.encodeBuffer(iv) + "]"); + + sb.append(LINE_SEP + "tLen(bits):" + LINE_SEP + tLen*8 + LINE_SEP); + return sb.toString(); + } +} diff --git a/src/share/classes/com/sun/crypto/provider/GCTR.java b/src/share/classes/com/sun/crypto/provider/GCTR.java new file mode 100644 index 0000000000000000000000000000000000000000..74d3555cc58b8a2cf33c3b620aaf8e962c30c24f --- /dev/null +++ b/src/share/classes/com/sun/crypto/provider/GCTR.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * (C) Copyright IBM Corp. 2013 + */ + +package com.sun.crypto.provider; + +import java.security.*; +import javax.crypto.*; +import static com.sun.crypto.provider.AESConstants.AES_BLOCK_SIZE; + +/** + * This class represents the GCTR function defined in NIST 800-38D + * under section 6.5. It needs to be constructed w/ an initialized + * cipher object, and initial counter block(ICB). Given an input X + * of arbitrary length, it processes and returns an output which has + * the same length as X. + * + *

This function is used in the implementation of GCM mode. + * + * @since 1.8 + */ +final class GCTR { + + // these fields should not change after the object has been constructed + private final SymmetricCipher aes; + private final byte[] icb; + + // the current counter value + private byte[] counter; + + // needed for save/restore calls + private byte[] counterSave; + + // NOTE: cipher should already be initialized + GCTR(SymmetricCipher cipher, byte[] initialCounterBlk) { + this.aes = cipher; + this.icb = initialCounterBlk; + this.counter = icb.clone(); + } + + // input must be multiples of 128-bit blocks when calling update + int update(byte[] in, int inOfs, int inLen, byte[] out, int outOfs) { + if (inLen - inOfs > in.length) { + throw new RuntimeException("input length out of bound"); + } + if (inLen < 0 || inLen % AES_BLOCK_SIZE != 0) { + throw new RuntimeException("input length unsupported"); + } + if (out.length - outOfs < inLen) { + throw new RuntimeException("output buffer too small"); + } + + byte[] encryptedCntr = new byte[AES_BLOCK_SIZE]; + + int numOfCompleteBlocks = inLen / AES_BLOCK_SIZE; + for (int i = 0; i < numOfCompleteBlocks; i++) { + aes.encryptBlock(counter, 0, encryptedCntr, 0); + for (int n = 0; n < AES_BLOCK_SIZE; n++) { + int index = (i * AES_BLOCK_SIZE + n); + out[outOfs + index] = + (byte) ((in[inOfs + index] ^ encryptedCntr[n])); + } + GaloisCounterMode.increment32(counter); + } + return inLen; + } + + // input can be arbitrary size when calling doFinal + protected int doFinal(byte[] in, int inOfs, int inLen, byte[] out, + int outOfs) throws IllegalBlockSizeException { + try { + if (inLen < 0) { + throw new IllegalBlockSizeException("Negative input size!"); + } else if (inLen > 0) { + int lastBlockSize = inLen % AES_BLOCK_SIZE; + // process the complete blocks first + update(in, inOfs, inLen - lastBlockSize, out, outOfs); + if (lastBlockSize != 0) { + // do the last partial block + byte[] encryptedCntr = new byte[AES_BLOCK_SIZE]; + aes.encryptBlock(counter, 0, encryptedCntr, 0); + + int processed = inLen - lastBlockSize; + for (int n = 0; n < lastBlockSize; n++) { + out[outOfs + processed + n] = + (byte) ((in[inOfs + processed + n] ^ + encryptedCntr[n])); + } + } + } + } finally { + reset(); + } + return inLen; + } + + /** + * Resets the current counter to its initial value. + * This is used after the doFinal() is called so this object can be + * reused w/o explicit re-initialization. + */ + void reset() { + System.arraycopy(icb, 0, counter, 0, icb.length); + } + + /** + * Save the current content of this object. + */ + void save() { + this.counterSave = this.counter.clone(); + } + + /** + * Restores the content of this object to the previous saved one. + */ + void restore() { + this.counter = this.counterSave; + } +} diff --git a/src/share/classes/com/sun/crypto/provider/GHASH.java b/src/share/classes/com/sun/crypto/provider/GHASH.java new file mode 100644 index 0000000000000000000000000000000000000000..8b0ba28e8980776eb79c60e0c2e00474aa7bce2b --- /dev/null +++ b/src/share/classes/com/sun/crypto/provider/GHASH.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + * (C) Copyright IBM Corp. 2013 + */ + +package com.sun.crypto.provider; + +import java.util.Arrays; +import java.security.*; +import static com.sun.crypto.provider.AESConstants.AES_BLOCK_SIZE; + +/** + * This class represents the GHASH function defined in NIST 800-38D + * under section 6.4. It needs to be constructed w/ a hash subkey, i.e. + * block H. Given input of 128-bit blocks, it will process and output + * a 128-bit block. + * + *

This function is used in the implementation of GCM mode. + * + * @since 1.8 + */ +final class GHASH { + + private static final byte P128 = (byte) 0xe1; //reduction polynomial + + private static boolean getBit(byte[] b, int pos) { + int p = pos / 8; + pos %= 8; + int i = (b[p] >>> (7 - pos)) & 1; + return i != 0; + } + + private static void shift(byte[] b) { + byte temp, temp2; + temp2 = 0; + for (int i = 0; i < b.length; i++) { + temp = (byte) ((b[i] & 0x01) << 7); + b[i] = (byte) ((b[i] & 0xff) >>> 1); + b[i] = (byte) (b[i] | temp2); + temp2 = temp; + } + } + + // Given block X and Y, returns the muliplication of X * Y + private static byte[] blockMult(byte[] x, byte[] y) { + if (x.length != AES_BLOCK_SIZE || y.length != AES_BLOCK_SIZE) { + throw new RuntimeException("illegal input sizes"); + } + byte[] z = new byte[AES_BLOCK_SIZE]; + byte[] v = y.clone(); + // calculate Z1-Z127 and V1-V127 + for (int i = 0; i < 127; i++) { + // Zi+1 = Zi if bit i of x is 0 + if (getBit(x, i)) { + for (int n = 0; n < z.length; n++) { + z[n] ^= v[n]; + } + } + boolean lastBitOfV = getBit(v, 127); + shift(v); + if (lastBitOfV) v[0] ^= P128; + } + // calculate Z128 + if (getBit(x, 127)) { + for (int n = 0; n < z.length; n++) { + z[n] ^= v[n]; + } + } + return z; + } + + // hash subkey H; should not change after the object has been constructed + private final byte[] subkeyH; + + // buffer for storing hash + private byte[] state; + + // variables for save/restore calls + private byte[] stateSave = null; + + /** + * Initializes the cipher in the specified mode with the given key + * and iv. + * + * @param subkeyH the hash subkey + * + * @exception ProviderException if the given key is inappropriate for + * initializing this digest + */ + GHASH(byte[] subkeyH) throws ProviderException { + if ((subkeyH == null) || subkeyH.length != AES_BLOCK_SIZE) { + throw new ProviderException("Internal error"); + } + this.subkeyH = subkeyH; + this.state = new byte[AES_BLOCK_SIZE]; + } + + /** + * Resets the GHASH object to its original state, i.e. blank w/ + * the same subkey H. Used after digest() is called and to re-use + * this object for different data w/ the same H. + */ + void reset() { + Arrays.fill(state, (byte) 0); + } + + /** + * Save the current snapshot of this GHASH object. + */ + void save() { + stateSave = state.clone(); + } + + /** + * Restores this object using the saved snapshot. + */ + void restore() { + state = stateSave; + } + + private void processBlock(byte[] data, int ofs) { + if (data.length - ofs < AES_BLOCK_SIZE) { + throw new RuntimeException("need complete block"); + } + for (int n = 0; n < state.length; n++) { + state[n] ^= data[ofs + n]; + } + state = blockMult(state, subkeyH); + } + + void update(byte[] in) { + update(in, 0, in.length); + } + + void update(byte[] in, int inOfs, int inLen) { + if (inLen - inOfs > in.length) { + throw new RuntimeException("input length out of bound"); + } + if (inLen % AES_BLOCK_SIZE != 0) { + throw new RuntimeException("input length unsupported"); + } + + for (int i = inOfs; i < (inOfs + inLen); i += AES_BLOCK_SIZE) { + processBlock(in, i); + } + } + + byte[] digest() { + try { + return state.clone(); + } finally { + reset(); + } + } +} diff --git a/src/share/classes/com/sun/crypto/provider/GaloisCounterMode.java b/src/share/classes/com/sun/crypto/provider/GaloisCounterMode.java new file mode 100644 index 0000000000000000000000000000000000000000..a2c6cfd82ef3750fecfb96ce853c7e6006ebcdd4 --- /dev/null +++ b/src/share/classes/com/sun/crypto/provider/GaloisCounterMode.java @@ -0,0 +1,501 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code.S + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.crypto.provider; + +import java.util.Arrays; +import java.io.*; +import java.security.*; +import javax.crypto.*; +import static com.sun.crypto.provider.AESConstants.AES_BLOCK_SIZE; + +/** + * This class represents ciphers in GaloisCounter (GCM) mode. + * + *

This mode currently should only be used w/ AES cipher. + * Although no checking is done here, caller should only + * pass AES Cipher to the constructor. + * + *

NOTE: This class does not deal with buffering or padding. + * + * @since 1.8 + */ +final class GaloisCounterMode extends FeedbackCipher { + + static int DEFAULT_TAG_LEN = AES_BLOCK_SIZE; + static int DEFAULT_IV_LEN = 12; // in bytes + + // buffer for AAD data; if null, meaning update has been called + private ByteArrayOutputStream aadBuffer = new ByteArrayOutputStream(); + private int sizeOfAAD = 0; + + // in bytes; need to convert to bits (default value 128) when needed + private int tagLenBytes = DEFAULT_TAG_LEN; + + // these following 2 fields can only be initialized after init() is + // called, e.g. after cipher key k is set, and STAY UNCHANGED + private byte[] subkeyH = null; + private byte[] preCounterBlock = null; + + private GCTR gctrPAndC = null; + private GHASH ghashAllToS = null; + + // length of total data, i.e. len(C) + private int processed = 0; + + // additional variables for save/restore calls + private byte[] aadBufferSave = null; + private int sizeOfAADSave = 0; + private int processedSave = 0; + + // value must be 16-byte long; used by GCTR and GHASH as well + static void increment32(byte[] value) { + if (value.length != AES_BLOCK_SIZE) { + throw new RuntimeException("Unexpected counter block length"); + } + // start from last byte and only go over 4 bytes, i.e. total 32 bits + int n = value.length - 1; + while ((n >= value.length - 4) && (++value[n] == 0)) { + n--; + } + } + + // ivLen in bits + private static byte[] getLengthBlock(int ivLen) { + byte[] out = new byte[AES_BLOCK_SIZE]; + out[12] = (byte)(ivLen >>> 24); + out[13] = (byte)(ivLen >>> 16); + out[14] = (byte)(ivLen >>> 8); + out[15] = (byte)ivLen; + return out; + } + + // aLen and cLen both in bits + private static byte[] getLengthBlock(int aLen, int cLen) { + byte[] out = new byte[AES_BLOCK_SIZE]; + out[4] = (byte)(aLen >>> 24); + out[5] = (byte)(aLen >>> 16); + out[6] = (byte)(aLen >>> 8); + out[7] = (byte)aLen; + out[12] = (byte)(cLen >>> 24); + out[13] = (byte)(cLen >>> 16); + out[14] = (byte)(cLen >>> 8); + out[15] = (byte)cLen; + return out; + } + + private static byte[] expandToOneBlock(byte[] in, int inOfs, int len) { + if (len > AES_BLOCK_SIZE) { + throw new ProviderException("input " + len + " too long"); + } + if (len == AES_BLOCK_SIZE && inOfs == 0) { + return in; + } else { + byte[] paddedIn = new byte[AES_BLOCK_SIZE]; + System.arraycopy(in, inOfs, paddedIn, 0, len); + return paddedIn; + } + } + + private static byte[] getJ0(byte[] iv, byte[] subkeyH) { + byte[] j0; + if (iv.length == 12) { // 96 bits + j0 = expandToOneBlock(iv, 0, iv.length); + j0[AES_BLOCK_SIZE - 1] = 1; + } else { + GHASH g = new GHASH(subkeyH); + int lastLen = iv.length % AES_BLOCK_SIZE; + if (lastLen != 0) { + g.update(iv, 0, iv.length - lastLen); + byte[] padded = + expandToOneBlock(iv, iv.length - lastLen, lastLen); + g.update(padded); + } else { + g.update(iv); + } + byte[] lengthBlock = getLengthBlock(iv.length*8); + g.update(lengthBlock); + j0 = g.digest(); + } + return j0; + } + + GaloisCounterMode(SymmetricCipher embeddedCipher) { + super(embeddedCipher); + aadBuffer = new ByteArrayOutputStream(); + } + + /** + * Gets the name of the feedback mechanism + * + * @return the name of the feedback mechanism + */ + String getFeedback() { + return "GCM"; + } + + /** + * Resets the cipher object to its original state. + * This is used when doFinal is called in the Cipher class, so that the + * cipher can be reused (with its original key and iv). + */ + void reset() { + if (aadBuffer == null) { + aadBuffer = new ByteArrayOutputStream(); + } else { + aadBuffer.reset(); + } + if (gctrPAndC != null) gctrPAndC.reset(); + if (ghashAllToS != null) ghashAllToS.reset(); + processed = 0; + sizeOfAAD = 0; + } + + /** + * Save the current content of this cipher. + */ + void save() { + processedSave = processed; + sizeOfAADSave = sizeOfAAD; + aadBufferSave = + ((aadBuffer == null || aadBuffer.size() == 0)? + null : aadBuffer.toByteArray()); + if (gctrPAndC != null) gctrPAndC.save(); + if (ghashAllToS != null) ghashAllToS.save(); + } + + /** + * Restores the content of this cipher to the previous saved one. + */ + void restore() { + processed = processedSave; + sizeOfAAD = sizeOfAADSave; + if (aadBuffer != null) { + aadBuffer.reset(); + if (aadBufferSave != null) { + aadBuffer.write(aadBufferSave, 0, aadBufferSave.length); + } + } + if (gctrPAndC != null) gctrPAndC.restore(); + if (ghashAllToS != null) ghashAllToS.restore(); + } + + /** + * Initializes the cipher in the specified mode with the given key + * and iv. + * + * @param decrypting flag indicating encryption or decryption + * @param algorithm the algorithm name + * @param key the key + * @param iv the iv + * @param tagLenBytes the length of tag in bytes + * + * @exception InvalidKeyException if the given key is inappropriate for + * initializing this cipher + */ + void init(boolean decrypting, String algorithm, byte[] key, byte[] iv) + throws InvalidKeyException { + init(decrypting, algorithm, key, iv, DEFAULT_TAG_LEN); + } + + /** + * Initializes the cipher in the specified mode with the given key + * and iv. + * + * @param decrypting flag indicating encryption or decryption + * @param algorithm the algorithm name + * @param key the key + * @param iv the iv + * @param tagLenBytes the length of tag in bytes + * + * @exception InvalidKeyException if the given key is inappropriate for + * initializing this cipher + */ + void init(boolean decrypting, String algorithm, byte[] keyValue, + byte[] ivValue, int tagLenBytes) + throws InvalidKeyException { + if (keyValue == null || ivValue == null) { + throw new InvalidKeyException("Internal error"); + } + + // always encrypt mode for embedded cipher + this.embeddedCipher.init(false, algorithm, keyValue); + this.subkeyH = new byte[AES_BLOCK_SIZE]; + this.embeddedCipher.encryptBlock(new byte[AES_BLOCK_SIZE], 0, + this.subkeyH, 0); + + this.iv = ivValue.clone(); + preCounterBlock = getJ0(iv, subkeyH); + byte[] j0Plus1 = preCounterBlock.clone(); + increment32(j0Plus1); + gctrPAndC = new GCTR(embeddedCipher, j0Plus1); + ghashAllToS = new GHASH(subkeyH); + + this.tagLenBytes = tagLenBytes; + if (aadBuffer == null) { + aadBuffer = new ByteArrayOutputStream(); + } else { + aadBuffer.reset(); + } + processed = 0; + sizeOfAAD = 0; + } + + /** + * Continues a multi-part update of the Additional Authentication + * Data (AAD), using a subset of the provided buffer. If this + * cipher is operating in either GCM or CCM mode, all AAD must be + * supplied before beginning operations on the ciphertext (via the + * {@code update} and {@code doFinal} methods). + *

+ * NOTE: Given most modes do not accept AAD, default impl for this + * method throws IllegalStateException. + * + * @param src the buffer containing the AAD + * @param offset the offset in {@code src} where the AAD input starts + * @param len the number of AAD bytes + * + * @throws IllegalStateException if this cipher is in a wrong state + * (e.g., has not been initialized), does not accept AAD, or if + * operating in either GCM or CCM mode and one of the {@code update} + * methods has already been called for the active + * encryption/decryption operation + * @throws UnsupportedOperationException if this method + * has not been overridden by an implementation + * + * @since 1.8 + */ + void updateAAD(byte[] src, int offset, int len) { + if (aadBuffer != null) { + aadBuffer.write(src, offset, len); + } else { + // update has already been called + throw new IllegalStateException + ("Update has been called; no more AAD data"); + } + } + + // Feed the AAD data to GHASH, pad if necessary + void processAAD() { + if (aadBuffer != null) { + byte[] aad = aadBuffer.toByteArray(); + sizeOfAAD = aad.length; + aadBuffer = null; + + int lastLen = aad.length % AES_BLOCK_SIZE; + if (lastLen != 0) { + ghashAllToS.update(aad, 0, aad.length - lastLen); + byte[] padded = expandToOneBlock(aad, aad.length - lastLen, + lastLen); + ghashAllToS.update(padded); + } else { + ghashAllToS.update(aad); + } + } + } + + // Utility to process the last block; used by encryptFinal and decryptFinal + void doLastBlock(byte[] in, int inOfs, int len, byte[] out, int outOfs, + boolean isEncrypt) throws IllegalBlockSizeException { + // process data in 'in' + gctrPAndC.doFinal(in, inOfs, len, out, outOfs); + processed += len; + + byte[] ct; + int ctOfs; + if (isEncrypt) { + ct = out; + ctOfs = outOfs; + } else { + ct = in; + ctOfs = inOfs; + } + int lastLen = len % AES_BLOCK_SIZE; + if (lastLen != 0) { + ghashAllToS.update(ct, ctOfs, len - lastLen); + byte[] padded = + expandToOneBlock(ct, (ctOfs + len - lastLen), lastLen); + ghashAllToS.update(padded); + } else { + ghashAllToS.update(ct, ctOfs, len); + } + } + + + /** + * Performs encryption operation. + * + *

The input plain text in, starting at inOff + * and ending at (inOff + len - 1), is encrypted. The result + * is stored in out, starting at outOfs. + * + *

It is the application's responsibility to make sure that + * len is a multiple of the embedded cipher's block size, + * otherwise, a ProviderException will be thrown. + * + *

It is also the application's responsibility to make sure that + * init has been called before this method is called. + * (This check is omitted here, to avoid double checking.) + * + * @param in the buffer with the input data to be encrypted + * @param inOfs the offset in in + * @param len the length of the input data + * @param out the buffer for the result + * @param outOfs the offset in out + */ + void encrypt(byte[] in, int inOfs, int len, byte[] out, int outOfs) { + processAAD(); + if (len > 0) { + gctrPAndC.update(in, inOfs, len, out, outOfs); + processed += len; + ghashAllToS.update(out, outOfs, len); + } + } + + /** + * Performs encryption operation for the last time. + * + *

NOTE: len may not be multiple of the embedded + * cipher's block size for this call. + * + * @param in the input buffer with the data to be encrypted + * @param inOfs the offset in in + * @param len the length of the input data + * @param out the buffer for the encryption result + * @param outOfs the offset in out + * @return the number of bytes placed into the out buffer + */ + int encryptFinal(byte[] in, int inOfs, int len, byte[] out, int outOfs) + throws IllegalBlockSizeException { + if (out.length - outOfs < (len + tagLenBytes)) { + throw new RuntimeException("Output buffer too small"); + } + + processAAD(); + if (len > 0) { + //ByteUtil.dumpArray(Arrays.copyOfRange(in, inOfs, inOfs + len)); + doLastBlock(in, inOfs, len, out, outOfs, true); + } + + byte[] lengthBlock = getLengthBlock(sizeOfAAD*8, processed*8); + ghashAllToS.update(lengthBlock); + byte[] s = ghashAllToS.digest(); + byte[] sOut = new byte[s.length]; + GCTR gctrForSToTag = new GCTR(embeddedCipher, this.preCounterBlock); + gctrForSToTag.doFinal(s, 0, s.length, sOut, 0); + + System.arraycopy(sOut, 0, out, (outOfs + len), tagLenBytes); + return (len + tagLenBytes); + } + + /** + * Performs decryption operation. + * + *

The input cipher text in, starting at + * inOfs and ending at (inOfs + len - 1), + * is decrypted. The result is stored in out, starting at + * outOfs. + * + *

It is the application's responsibility to make sure that + * len is a multiple of the embedded cipher's block + * size, as any excess bytes are ignored. + * + *

It is also the application's responsibility to make sure that + * init has been called before this method is called. + * (This check is omitted here, to avoid double checking.) + * + * @param in the buffer with the input data to be decrypted + * @param inOfs the offset in in + * @param len the length of the input data + * @param out the buffer for the result + * @param outOfs the offset in out + */ + void decrypt(byte[] in, int inOfs, int len, byte[] out, int outOfs) { + processAAD(); + + if (len > 0) { // must be at least AES_BLOCK_SIZE bytes long + gctrPAndC.update(in, inOfs, len, out, outOfs); + processed += len; + ghashAllToS.update(in, inOfs, len); + } + } + + /** + * Performs decryption operation for the last time. + * + *

NOTE: For cipher feedback modes which does not perform + * special handling for the last few blocks, this is essentially + * the same as encrypt(...). Given most modes do + * not do special handling, the default impl for this method is + * to simply call decrypt(...). + * + * @param in the input buffer with the data to be decrypted + * @param inOfs the offset in cipher + * @param len the length of the input data + * @param out the buffer for the decryption result + * @param outOfs the offset in plain + * @return the number of bytes placed into the out buffer + */ + int decryptFinal(byte[] in, int inOfs, int len, + byte[] out, int outOfs) + throws IllegalBlockSizeException, AEADBadTagException { + if (len < tagLenBytes) { + throw new RuntimeException("Input buffer too short - need tag"); + } + if (out.length - outOfs < (len - tagLenBytes)) { + throw new RuntimeException("Output buffer too small"); + } + processAAD(); + + int processedOld = processed; + byte[] tag = new byte[tagLenBytes]; + // get the trailing tag bytes from 'in' + System.arraycopy(in, inOfs + len - tagLenBytes, tag, 0, tagLenBytes); + len -= tagLenBytes; + + if (len > 0) { + doLastBlock(in, inOfs, len, out, outOfs, false); + } + + byte[] lengthBlock = getLengthBlock(sizeOfAAD*8, processed*8); + ghashAllToS.update(lengthBlock); + + byte[] s = ghashAllToS.digest(); + byte[] sOut = new byte[s.length]; + GCTR gctrForSToTag = new GCTR(embeddedCipher, this.preCounterBlock); + gctrForSToTag.doFinal(s, 0, s.length, sOut, 0); + for (int i = 0; i < tagLenBytes; i++) { + if (tag[i] != sOut[i]) { + throw new AEADBadTagException("Tag mismatch!"); + } + } + return len; + } + + // return tag length in bytes + int getTagLen() { + return this.tagLenBytes; + } +} diff --git a/src/share/classes/com/sun/crypto/provider/HmacMD5KeyGenerator.java b/src/share/classes/com/sun/crypto/provider/HmacMD5KeyGenerator.java index 46cc4ce080c3d1366e708aeaa316f67220626bbd..8482db8f9a840fee863354a3dd0d73045d4e6587 100644 --- a/src/share/classes/com/sun/crypto/provider/HmacMD5KeyGenerator.java +++ b/src/share/classes/com/sun/crypto/provider/HmacMD5KeyGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -98,7 +98,7 @@ public final class HmacMD5KeyGenerator extends KeyGeneratorSpi { */ protected SecretKey engineGenerateKey() { if (this.random == null) { - this.random = SunJCE.RANDOM; + this.random = SunJCE.getRandom(); } byte[] keyBytes = new byte[this.keysize]; diff --git a/src/share/classes/com/sun/crypto/provider/HmacPKCS12PBESHA1.java b/src/share/classes/com/sun/crypto/provider/HmacPKCS12PBESHA1.java index ef0ef58ee45a43544b0a2aa5ccedb3f1a8a7e26c..d41b88c7e38fbc8c37c6d9cd20c1558b9bd93c42 100644 --- a/src/share/classes/com/sun/crypto/provider/HmacPKCS12PBESHA1.java +++ b/src/share/classes/com/sun/crypto/provider/HmacPKCS12PBESHA1.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -89,7 +89,7 @@ public final class HmacPKCS12PBESHA1 extends HmacCore { // generate default for salt and iteration count if necessary if (salt == null) { salt = new byte[20]; - SunJCE.RANDOM.nextBytes(salt); + SunJCE.getRandom().nextBytes(salt); } if (iCount == 0) iCount = 100; } else if (!(params instanceof PBEParameterSpec)) { diff --git a/src/share/classes/com/sun/crypto/provider/HmacSHA1KeyGenerator.java b/src/share/classes/com/sun/crypto/provider/HmacSHA1KeyGenerator.java index 02f3554f2ab8892af596a4feb2f6e68fdefc1c2a..7a29af3889de545d73a569c7c7a92fd080cacd69 100644 --- a/src/share/classes/com/sun/crypto/provider/HmacSHA1KeyGenerator.java +++ b/src/share/classes/com/sun/crypto/provider/HmacSHA1KeyGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -98,7 +98,7 @@ public final class HmacSHA1KeyGenerator extends KeyGeneratorSpi { */ protected SecretKey engineGenerateKey() { if (this.random == null) { - this.random = SunJCE.RANDOM; + this.random = SunJCE.getRandom(); } byte[] keyBytes = new byte[this.keysize]; diff --git a/src/share/classes/com/sun/crypto/provider/ISO10126Padding.java b/src/share/classes/com/sun/crypto/provider/ISO10126Padding.java index 9b850c67d87d58ff29bda0e2e34dbb8adff495cc..7377fab0a9c114ed19b26648cf95a423b9ecfd7a 100644 --- a/src/share/classes/com/sun/crypto/provider/ISO10126Padding.java +++ b/src/share/classes/com/sun/crypto/provider/ISO10126Padding.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -69,7 +69,7 @@ final class ISO10126Padding implements Padding { byte paddingOctet = (byte) (len & 0xff); byte[] padding = new byte[len]; - SunJCE.RANDOM.nextBytes(padding); + SunJCE.getRandom().nextBytes(padding); padding[len-1] = paddingOctet; System.arraycopy(padding, 0, in, off, len); return; diff --git a/src/share/classes/com/sun/crypto/provider/KeyGeneratorCore.java b/src/share/classes/com/sun/crypto/provider/KeyGeneratorCore.java index 9593bbfe0b0012a233ee2478579a9df9052a85d1..a5fd638da5b47177fd7e83897ef80770fd8bce8a 100644 --- a/src/share/classes/com/sun/crypto/provider/KeyGeneratorCore.java +++ b/src/share/classes/com/sun/crypto/provider/KeyGeneratorCore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -98,7 +98,7 @@ final class KeyGeneratorCore { // generate the key SecretKey implGenerateKey() { if (random == null) { - random = SunJCE.RANDOM; + random = SunJCE.getRandom(); } byte[] b = new byte[(keySize + 7) >> 3]; random.nextBytes(b); diff --git a/src/share/classes/com/sun/crypto/provider/KeyProtector.java b/src/share/classes/com/sun/crypto/provider/KeyProtector.java index e30f90c1b6e0108940c67afd519feae263f49a65..0129d3d3f1015d6c95a5e0434cf48fde31e80564 100644 --- a/src/share/classes/com/sun/crypto/provider/KeyProtector.java +++ b/src/share/classes/com/sun/crypto/provider/KeyProtector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -99,7 +99,7 @@ final class KeyProtector { { // create a random salt (8 bytes) byte[] salt = new byte[8]; - SunJCE.RANDOM.nextBytes(salt); + SunJCE.getRandom().nextBytes(salt); // create PBE parameters from salt and iteration count PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, 20); @@ -284,7 +284,7 @@ final class KeyProtector { { // create a random salt (8 bytes) byte[] salt = new byte[8]; - SunJCE.RANDOM.nextBytes(salt); + SunJCE.getRandom().nextBytes(salt); // create PBE parameters from salt and iteration count PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, 20); diff --git a/src/share/classes/com/sun/crypto/provider/PBECipherCore.java b/src/share/classes/com/sun/crypto/provider/PBECipherCore.java index 7181ceeddbf6ab040f592e1f96789b00bc2b4875..c1fb9ccb7f83d02459149e927b7e9d0d1798b5b5 100644 --- a/src/share/classes/com/sun/crypto/provider/PBECipherCore.java +++ b/src/share/classes/com/sun/crypto/provider/PBECipherCore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -164,7 +164,7 @@ final class PBECipherCore { AlgorithmParameters params = null; if (salt == null) { salt = new byte[8]; - SunJCE.RANDOM.nextBytes(salt); + SunJCE.getRandom().nextBytes(salt); } PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, iCount); try { diff --git a/src/share/classes/com/sun/crypto/provider/PBES1Core.java b/src/share/classes/com/sun/crypto/provider/PBES1Core.java index 1e206a2dd661637b38861da65f6b9b81f1bdaf4d..4199173b9f096023b2a4c83dd043780b1b8971a5 100644 --- a/src/share/classes/com/sun/crypto/provider/PBES1Core.java +++ b/src/share/classes/com/sun/crypto/provider/PBES1Core.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -164,7 +164,7 @@ final class PBES1Core { AlgorithmParameters params = null; if (salt == null) { salt = new byte[8]; - SunJCE.RANDOM.nextBytes(salt); + SunJCE.getRandom().nextBytes(salt); } PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, iCount); try { diff --git a/src/share/classes/com/sun/crypto/provider/PBES2Core.java b/src/share/classes/com/sun/crypto/provider/PBES2Core.java index 4e5eb8e6dd18a14938b3c45c0f1293b8c437bdd0..4e61e1fae8dfc6892cb37b319015846c1af4350d 100644 --- a/src/share/classes/com/sun/crypto/provider/PBES2Core.java +++ b/src/share/classes/com/sun/crypto/provider/PBES2Core.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -134,13 +134,13 @@ abstract class PBES2Core extends CipherSpi { if (salt == null) { // generate random salt and use default iteration count salt = new byte[DEFAULT_SALT_LENGTH]; - SunJCE.RANDOM.nextBytes(salt); + SunJCE.getRandom().nextBytes(salt); iCount = DEFAULT_COUNT; } if (ivSpec == null) { // generate random IV byte[] ivBytes = new byte[blkSize]; - SunJCE.RANDOM.nextBytes(ivBytes); + SunJCE.getRandom().nextBytes(ivBytes); ivSpec = new IvParameterSpec(ivBytes); } PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, iCount, ivSpec); diff --git a/src/share/classes/com/sun/crypto/provider/PBMAC1Core.java b/src/share/classes/com/sun/crypto/provider/PBMAC1Core.java index fef4eda8a8b935170ad1c865e5282deff7761b03..47663943184278c0e21e30c2ca60204433c5fae2 100644 --- a/src/share/classes/com/sun/crypto/provider/PBMAC1Core.java +++ b/src/share/classes/com/sun/crypto/provider/PBMAC1Core.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -123,7 +123,7 @@ abstract class PBMAC1Core extends HmacCore { // generate default for salt and iteration count if necessary if (salt == null) { salt = new byte[DEFAULT_SALT_LENGTH]; - SunJCE.RANDOM.nextBytes(salt); + SunJCE.getRandom().nextBytes(salt); } if (iCount == 0) iCount = DEFAULT_COUNT; } else if (!(params instanceof PBEParameterSpec)) { diff --git a/src/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java b/src/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java index 45f1c304d678de2a003db31cddf87642014568a2..c76603a95de2660848ba34d072cb26367774f0c8 100644 --- a/src/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java +++ b/src/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -227,7 +227,7 @@ final class PKCS12PBECipherCore { // follow the recommendation in PKCS12 v1.0 // section B.4 to generate salt and iCount. salt = new byte[DEFAULT_SALT_LENGTH]; - SunJCE.RANDOM.nextBytes(salt); + SunJCE.getRandom().nextBytes(salt); iCount = DEFAULT_COUNT; } PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, iCount); @@ -294,7 +294,7 @@ final class PKCS12PBECipherCore { if (random != null) { random.nextBytes(salt); } else { - SunJCE.RANDOM.nextBytes(salt); + SunJCE.getRandom().nextBytes(salt); } } if (iCount == 0) iCount = DEFAULT_COUNT; diff --git a/src/share/classes/com/sun/crypto/provider/SunJCE.java b/src/share/classes/com/sun/crypto/provider/SunJCE.java index 3edac42c6badc2931a3f6d0a1acc96671ccc0f98..99a2a30ab52f53d99c31511ac1cb8e6c0531fe81 100644 --- a/src/share/classes/com/sun/crypto/provider/SunJCE.java +++ b/src/share/classes/com/sun/crypto/provider/SunJCE.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,6 +57,7 @@ import java.security.SecureRandom; * - ARCFOUR (RC4 compatible) * * - Cipher modes ECB, CBC, CFB, OFB, PCBC, CTR, and CTS for all block ciphers + * and mode GCM for AES cipher * * - Cipher padding ISO10126Padding for non-PKCS#5 block ciphers and * NoPadding and PKCS5Padding for all block ciphers @@ -90,7 +91,12 @@ public final class SunJCE extends Provider { /* Are we debugging? -- for developers */ static final boolean debug = false; - static final SecureRandom RANDOM = new SecureRandom(); + // lazy initialize SecureRandom to avoid potential recursion if Sun + // provider has not been installed yet + private static class SecureRandomHolder { + static final SecureRandom RANDOM = new SecureRandom(); + } + static SecureRandom getRandom() { return SecureRandomHolder.RANDOM; } public SunJCE() { /* We are the "SunJCE" provider */ @@ -100,7 +106,7 @@ public final class SunJCE extends Provider { "|CFB8|CFB16|CFB24|CFB32|CFB40|CFB48|CFB56|CFB64" + "|OFB8|OFB16|OFB24|OFB32|OFB40|OFB48|OFB56|OFB64"; final String BLOCK_MODES128 = BLOCK_MODES + - "|CFB72|CFB80|CFB88|CFB96|CFB104|CFB112|CFB120|CFB128" + + "|GCM|CFB72|CFB80|CFB88|CFB96|CFB104|CFB112|CFB120|CFB128" + "|OFB72|OFB80|OFB88|OFB96|OFB104|OFB112|OFB120|OFB128"; final String BLOCK_PADS = "NOPADDING|PKCS5PADDING|ISO10126PADDING"; @@ -258,6 +264,9 @@ public final class SunJCE extends Provider { put("Cipher.AES_128/CFB/NoPadding", "com.sun.crypto.provider.AESCipher$AES128_CFB_NoPadding"); put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.4", "AES_128/CFB/NoPadding"); put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.4", "AES_128/CFB/NoPadding"); + put("Cipher.AES_128/GCM/NoPadding", "com.sun.crypto.provider.AESCipher$AES128_GCM_NoPadding"); + put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.6", "AES_128/GCM/NoPadding"); + put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.6", "AES_128/GCM/NoPadding"); put("Cipher.AES_192/ECB/NoPadding", "com.sun.crypto.provider.AESCipher$AES192_ECB_NoPadding"); put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.21", "AES_192/ECB/NoPadding"); @@ -271,7 +280,9 @@ public final class SunJCE extends Provider { put("Cipher.AES_192/CFB/NoPadding", "com.sun.crypto.provider.AESCipher$AES192_CFB_NoPadding"); put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.24", "AES_192/CFB/NoPadding"); put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.24", "AES_192/CFB/NoPadding"); - + put("Cipher.AES_192/GCM/NoPadding", "com.sun.crypto.provider.AESCipher$AES192_GCM_NoPadding"); + put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.26", "AES_192/GCM/NoPadding"); + put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.26", "AES_192/GCM/NoPadding"); put("Cipher.AES_256/ECB/NoPadding", "com.sun.crypto.provider.AESCipher$AES256_ECB_NoPadding"); put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.41", "AES_256/ECB/NoPadding"); @@ -285,6 +296,9 @@ public final class SunJCE extends Provider { put("Cipher.AES_256/CFB/NoPadding", "com.sun.crypto.provider.AESCipher$AES256_CFB_NoPadding"); put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.44", "AES_256/CFB/NoPadding"); put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.44", "AES_256/CFB/NoPadding"); + put("Cipher.AES_256/GCM/NoPadding", "com.sun.crypto.provider.AESCipher$AES256_GCM_NoPadding"); + put("Alg.Alias.Cipher.2.16.840.1.101.3.4.1.46", "AES_256/GCM/NoPadding"); + put("Alg.Alias.Cipher.OID.2.16.840.1.101.3.4.1.46", "AES_256/GCM/NoPadding"); put("Cipher.AESWrap", "com.sun.crypto.provider.AESWrapCipher$General"); put("Cipher.AESWrap SupportedModes", "ECB"); @@ -509,6 +523,8 @@ public final class SunJCE extends Provider { put("AlgorithmParameters.AES", "com.sun.crypto.provider.AESParameters"); put("Alg.Alias.AlgorithmParameters.Rijndael", "AES"); + put("AlgorithmParameters.GCM", + "com.sun.crypto.provider.GCMParameters"); put("AlgorithmParameters.RC2", diff --git a/src/share/classes/java/lang/AbstractStringBuilder.java b/src/share/classes/java/lang/AbstractStringBuilder.java index fc513f55efe961811fabcccd4f9de270beb0184f..03999c445a55d0810a50e57ab9d460e03c9effe2 100644 --- a/src/share/classes/java/lang/AbstractStringBuilder.java +++ b/src/share/classes/java/lang/AbstractStringBuilder.java @@ -860,9 +860,9 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { * @return the specified subsequence. * * @throws IndexOutOfBoundsException - * if start or end are negative, - * if end is greater than length(), - * or if start is greater than end + * if {@code start} or {@code end} are negative, + * if {@code end} is greater than {@code length()}, + * or if {@code start} is greater than {@code end} * @spec JSR-51 */ @Override @@ -1292,7 +1292,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { /** * Returns the index within this string of the first occurrence of the * specified substring, starting at the specified index. The integer - * returned is the smallest value k for which: + * returned is the smallest value {@code k} for which: *

      *     k >= Math.min(fromIndex, str.length()) &&
      *                   this.toString().startsWith(str, k)
@@ -1418,7 +1418,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
     public abstract String toString();
 
     /**
-     * Needed by String for the contentEquals method.
+     * Needed by {@code String} for the contentEquals method.
      */
     final char[] getValue() {
         return value;
diff --git a/src/share/classes/java/lang/FunctionalInterface.java b/src/share/classes/java/lang/FunctionalInterface.java
new file mode 100644
index 0000000000000000000000000000000000000000..0d4ae72a697666c24c06b6556109e64ef009e472
--- /dev/null
+++ b/src/share/classes/java/lang/FunctionalInterface.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import java.lang.annotation.*;
+
+/**
+ * Indicates that an interface type declaration is intended to be a
+ * functional interface as defined by the Java Language
+ * Specification.
+ *
+ * Conceptually, a functional interface has exactly one abstract
+ * method.  Since {@linkplain java.lang.reflect.Method#isDefault()
+ * default methods} have an implementation, they are not abstract.  If
+ * an interface declares an abstract method overriding one of the
+ * public methods of {@code java.lang.Object}, that also does
+ * not count toward the interface's abstract method count
+ * since any implementation of the interface will have an
+ * implementation from {@code java.lang.Object} or elsewhere.
+ *
+ * 

Note that instances of functional interfaces can be created with + * lambda expressions, method references, or constructor references. + * + *

If a type is annotated with this annotation type, compilers are + * required to generate an error message unless: + * + *

    + *
  • The type is an interface type and not an annotation type, enum, or class. + *
  • The annotated type satisfies the requirements of a functional interface. + *
+ * + * @jls 4.3.2. The Class Object + * @jls 9.8 Functional Interfaces + * @jls 9.4.3 Interface Method Body + * @since 1.8 + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface FunctionalInterface {} diff --git a/src/share/classes/java/lang/Integer.java b/src/share/classes/java/lang/Integer.java index 6d12f880a64492506915cf3a6921b06684cff2d4..b27f46358c50ca6de041aead05dbe8eb98214c93 100644 --- a/src/share/classes/java/lang/Integer.java +++ b/src/share/classes/java/lang/Integer.java @@ -773,7 +773,7 @@ public final class Integer extends Number implements Comparable { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE - h = Math.min(i, Integer.MAX_VALUE - (-low)); + h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } high = h; diff --git a/src/share/classes/java/lang/String.java b/src/share/classes/java/lang/String.java index d73a2f7c2e9c8d4f53ad26c5a8041971ef460685..a9bc2f376481be95a1b6777f29c783b6f6c23b56 100644 --- a/src/share/classes/java/lang/String.java +++ b/src/share/classes/java/lang/String.java @@ -615,10 +615,10 @@ public final class String } /** - * Returns true if, and only if, {@link #length()} is 0. + * Returns {@code true} if, and only if, {@link #length()} is {@code 0}. * - * @return true if {@link #length()} is 0, otherwise - * false + * @return {@code true} if {@link #length()} is {@code 0}, otherwise + * {@code false} * * @since 1.6 */ @@ -1229,23 +1229,23 @@ public final class String /** * Tests if two string regions are equal. *

- * A substring of this String object is compared to a substring + * A substring of this {@code String} object is compared to a substring * of the argument other. The result is true if these substrings * represent identical character sequences. The substring of this - * String object to be compared begins at index toffset - * and has length len. The substring of other to be compared - * begins at index ooffset and has length len. The - * result is false if and only if at least one of the following + * {@code String} object to be compared begins at index {@code toffset} + * and has length {@code len}. The substring of other to be compared + * begins at index {@code ooffset} and has length {@code len}. The + * result is {@code false} if and only if at least one of the following * is true: - *

* - *

The protection domain contains CodeSource + *

The protection domain contains a CodeSource * object, which encapsulates its codebase (URL) and public key attributes. * It also contains the principals associated with the domain. * The Policy object evaluates the global policy in light of who the @@ -87,9 +88,6 @@ import sun.security.util.ResourcesMgr; public class PolicyParser { - // needs to be public for PolicyTool - public static final String REPLACE_NAME = "PolicyParser.REPLACE_NAME"; - private static final String EXTDIRS_PROPERTY = "java.ext.dirs"; private static final String OLD_EXTDIRS_EXPANSION = "${" + EXTDIRS_PROPERTY + "}"; @@ -452,7 +450,7 @@ public class PolicyParser { peekAndMatch(","); } else if (peekAndMatch("Principal")) { if (principals == null) { - principals = new LinkedList(); + principals = new LinkedList<>(); } String principalClass; @@ -461,7 +459,7 @@ public class PolicyParser { if (peek("\"")) { // both the principalClass and principalName // will be replaced later - principalClass = REPLACE_NAME; + principalClass = PrincipalEntry.REPLACE_NAME; principalName = match("principal type"); } else { // check for principalClass wildcard @@ -916,7 +914,7 @@ public class PolicyParser { out.print(",\n"); } if (principals != null && principals.size() > 0) { - ListIterator pli = principals.listIterator(); + Iterator pli = principals.iterator(); while (pli.hasNext()) { out.print(" "); PrincipalEntry pe = pli.next(); @@ -949,23 +947,22 @@ public class PolicyParser { /** * Principal info (class and name) in a grant entry */ - public static class PrincipalEntry { + public static class PrincipalEntry implements Principal { public static final String WILDCARD_CLASS = "WILDCARD_PRINCIPAL_CLASS"; public static final String WILDCARD_NAME = "WILDCARD_PRINCIPAL_NAME"; + public static final String REPLACE_NAME = "PolicyParser.REPLACE_NAME"; String principalClass; String principalName; /** - * A PrincipalEntry consists of the Principal - * class and Principal name. - * - *

- * - * @param principalClass the Principal class.

+ * A PrincipalEntry consists of the Principal class and Principal name. * - * @param principalName the Principal name.

+ * @param principalClass the Principal class + * @param principalName the Principal name + * @throws NullPointerException if principalClass or principalName + * are null */ public PrincipalEntry(String principalClass, String principalName) { if (principalClass == null || principalName == null) @@ -975,6 +972,18 @@ public class PolicyParser { this.principalName = principalName; } + boolean isWildcardName() { + return principalName.equals(WILDCARD_NAME); + } + + boolean isWildcardClass() { + return principalClass.equals(WILDCARD_CLASS); + } + + boolean isReplaceName() { + return principalClass.equals(REPLACE_NAME); + } + public String getPrincipalClass() { return principalClass; } @@ -984,9 +993,9 @@ public class PolicyParser { } public String getDisplayClass() { - if (principalClass.equals(WILDCARD_CLASS)) { + if (isWildcardClass()) { return "*"; - } else if (principalClass.equals(REPLACE_NAME)) { + } else if (isReplaceName()) { return ""; } else return principalClass; @@ -997,7 +1006,7 @@ public class PolicyParser { } public String getDisplayName(boolean addQuote) { - if (principalName.equals(WILDCARD_NAME)) { + if (isWildcardName()) { return "*"; } else { @@ -1006,8 +1015,14 @@ public class PolicyParser { } } + @Override + public String getName() { + return principalName; + } + + @Override public String toString() { - if (!principalClass.equals(REPLACE_NAME)) { + if (!isReplaceName()) { return getDisplayClass() + "/" + getDisplayName(); } else { return getDisplayName(); @@ -1016,15 +1031,13 @@ public class PolicyParser { /** * Test for equality between the specified object and this object. - * Two PrincipalEntries are equal if their PrincipalClass and - * PrincipalName values are equal. - * - *

- * - * @param obj the object to test for equality with this object. + * Two PrincipalEntries are equal if their class and name values + * are equal. * - * @return true if the objects are equal, false otherwise. + * @param obj the object to test for equality with this object + * @return true if the objects are equal, false otherwise */ + @Override public boolean equals(Object obj) { if (this == obj) return true; @@ -1033,27 +1046,23 @@ public class PolicyParser { return false; PrincipalEntry that = (PrincipalEntry)obj; - if (this.principalClass.equals(that.principalClass) && - this.principalName.equals(that.principalName)) { - return true; - } - - return false; + return (principalClass.equals(that.principalClass) && + principalName.equals(that.principalName)); } /** - * Return a hashcode for this PrincipalEntry. - * - *

+ * Return a hashcode for this PrincipalEntry. * - * @return a hashcode for this PrincipalEntry. + * @return a hashcode for this PrincipalEntry */ + @Override public int hashCode() { return principalClass.hashCode(); } + public void write(PrintWriter out) { out.print("principal " + getDisplayClass() + " " + - getDisplayName(true)); + getDisplayName(true)); } } @@ -1101,6 +1110,7 @@ public class PolicyParser { * Calculates a hash code value for the object. Objects * which are equal will also have the same hashcode. */ + @Override public int hashCode() { int retval = permission.hashCode(); if (name != null) retval ^= name.hashCode(); @@ -1108,6 +1118,7 @@ public class PolicyParser { return retval; } + @Override public boolean equals(Object obj) { if (obj == this) return true; @@ -1210,28 +1221,18 @@ public class PolicyParser { i18nMessage = form.format(source); } + @Override public String getLocalizedMessage() { return i18nMessage; } } public static void main(String arg[]) throws Exception { - FileReader fr = null; - FileWriter fw = null; - try { + try (FileReader fr = new FileReader(arg[0]); + FileWriter fw = new FileWriter(arg[1])) { PolicyParser pp = new PolicyParser(true); - fr = new FileReader(arg[0]); pp.read(fr); - fw = new FileWriter(arg[1]); pp.write(fw); - } finally { - if (fr != null) { - fr.close(); - } - - if (fw != null) { - fw.close(); - } } } } diff --git a/src/share/classes/sun/security/ssl/krb5/Krb5ProxyImpl.java b/src/share/classes/sun/security/ssl/krb5/Krb5ProxyImpl.java index bc22a77a93b1535109badbbf49af4656c1a1c22d..7f9a7984b98f70155395d243e12bf288b843db93 100644 --- a/src/share/classes/sun/security/ssl/krb5/Krb5ProxyImpl.java +++ b/src/share/classes/sun/security/ssl/krb5/Krb5ProxyImpl.java @@ -36,6 +36,7 @@ import javax.security.auth.login.LoginException; import sun.security.jgss.GSSCaller; import sun.security.jgss.krb5.Krb5Util; +import sun.security.jgss.krb5.ServiceCreds; import sun.security.krb5.PrincipalName; import sun.security.ssl.Krb5Proxy; @@ -62,7 +63,7 @@ public class Krb5ProxyImpl implements Krb5Proxy { @Override public SecretKey[] getServerKeys(AccessControlContext acc) throws LoginException { - Krb5Util.ServiceCreds serviceCreds = + ServiceCreds serviceCreds = Krb5Util.getServiceCreds(GSSCaller.CALLER_SSL_SERVER, null, acc); return serviceCreds != null ? serviceCreds.getKKeys() : new KerberosKey[0]; diff --git a/src/share/classes/sun/security/tools/policytool/PolicyTool.java b/src/share/classes/sun/security/tools/policytool/PolicyTool.java index 5835ce995bf96b8216b110a91778eb36332abda5..17f9d9c5278f61b7d310e5846fc10a0d0fc5e94b 100644 --- a/src/share/classes/sun/security/tools/policytool/PolicyTool.java +++ b/src/share/classes/sun/security/tools/policytool/PolicyTool.java @@ -604,7 +604,7 @@ public class PolicyTool { InstantiationException { if (type.equals(PolicyParser.PrincipalEntry.WILDCARD_CLASS) || - type.equals(PolicyParser.REPLACE_NAME)) { + type.equals(PolicyParser.PrincipalEntry.REPLACE_NAME)) { return; } Class PRIN = Class.forName("java.security.Principal"); @@ -2094,7 +2094,7 @@ class ToolDialog extends Dialog { } else if (pclass.equals("")) { // make this consistent with what PolicyParser does // when it sees an empty principal class - pclass = PolicyParser.REPLACE_NAME; + pclass = PolicyParser.PrincipalEntry.REPLACE_NAME; tool.warnings.addElement( "Warning: Principal name '" + pname + "' specified without a Principal class.\n" + diff --git a/src/share/native/java/lang/System.c b/src/share/native/java/lang/System.c index 84ae689b50f1569de5763ea03bd6910fa3483074..8efd95e09b7b44cf41a1b29817be8235ca50d4dc 100644 --- a/src/share/native/java/lang/System.c +++ b/src/share/native/java/lang/System.c @@ -389,11 +389,19 @@ Java_java_lang_System_initProperties(JNIEnv *env, jclass cla, jobject props) sprops->display_variant, sprops->format_variant, putID, getPropID); GETPROP(props, "file.encoding", jVMVal); if (jVMVal == NULL) { +#ifdef MACOSX + /* + * Since sun_jnu_encoding is now hard-coded to UTF-8 on Mac, we don't + * want to use it to overwrite file.encoding + */ + PUTPROP(props, "file.encoding", sprops->encoding); +#else if (fmtdefault) { PUTPROP(props, "file.encoding", sprops->encoding); } else { PUTPROP(props, "file.encoding", sprops->sun_jnu_encoding); } +#endif } else { (*env)->DeleteLocalRef(env, jVMVal); } diff --git a/src/solaris/native/java/lang/java_props_md.c b/src/solaris/native/java/lang/java_props_md.c index baba74fe8977bfafc0f23c8ce8d9251fd33b534c..c7d3ba6eff5fe768b0bc577b83ada10e09518506 100644 --- a/src/solaris/native/java/lang/java_props_md.c +++ b/src/solaris/native/java/lang/java_props_md.c @@ -538,7 +538,12 @@ GetJavaProperties(JNIEnv *env) sprops.display_script = sprops.script; sprops.display_country = sprops.country; sprops.display_variant = sprops.variant; + +#ifdef MACOSX + sprops.sun_jnu_encoding = "UTF-8"; +#else sprops.sun_jnu_encoding = sprops.encoding; +#endif #ifdef _ALLBSD_SOURCE #if BYTE_ORDER == _LITTLE_ENDIAN diff --git a/src/windows/classes/sun/nio/ch/PipeImpl.java b/src/windows/classes/sun/nio/ch/PipeImpl.java index de676544c2be06e6b6586c947d7af5dab9d446b4..6eb7dce7efd1ae130057915db46e2efdbce69f7d 100644 --- a/src/windows/classes/sun/nio/ch/PipeImpl.java +++ b/src/windows/classes/sun/nio/ch/PipeImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -72,67 +72,97 @@ class PipeImpl private final SelectorProvider sp; + private IOException ioe = null; + private Initializer(SelectorProvider sp) { this.sp = sp; } + @Override public Void run() throws IOException { - ServerSocketChannel ssc = null; - SocketChannel sc1 = null; - SocketChannel sc2 = null; - - try { - // loopback address - InetAddress lb = InetAddress.getByName("127.0.0.1"); - assert(lb.isLoopbackAddress()); - - // bind ServerSocketChannel to a port on the loopback address - ssc = ServerSocketChannel.open(); - ssc.socket().bind(new InetSocketAddress(lb, 0)); - - // Establish connection (assumes connections are eagerly - // accepted) - InetSocketAddress sa - = new InetSocketAddress(lb, ssc.socket().getLocalPort()); - sc1 = SocketChannel.open(sa); - - ByteBuffer bb = ByteBuffer.allocate(8); - long secret = rnd.nextLong(); - bb.putLong(secret).flip(); - sc1.write(bb); - - // Get a connection and verify it is legitimate + LoopbackConnector connector = new LoopbackConnector(); + connector.run(); + if (ioe instanceof ClosedByInterruptException) { + ioe = null; + Thread connThread = new Thread(connector) { + @Override + public void interrupt() {} + }; + connThread.start(); for (;;) { - sc2 = ssc.accept(); - bb.clear(); - sc2.read(bb); - bb.rewind(); - if (bb.getLong() == secret) + try { + connThread.join(); break; - sc2.close(); + } catch (InterruptedException ex) {} } + Thread.currentThread().interrupt(); + } + + if (ioe != null) + throw new IOException("Unable to establish loopback connection", ioe); + + return null; + } + + private class LoopbackConnector implements Runnable { + + @Override + public void run() { + ServerSocketChannel ssc = null; + SocketChannel sc1 = null; + SocketChannel sc2 = null; - // Create source and sink channels - source = new SourceChannelImpl(sp, sc1); - sink = new SinkChannelImpl(sp, sc2); - } catch (IOException e) { try { - if (sc1 != null) - sc1.close(); - if (sc2 != null) + // Loopback address + InetAddress lb = InetAddress.getByName("127.0.0.1"); + assert(lb.isLoopbackAddress()); + InetSocketAddress sa = null; + for(;;) { + // Bind ServerSocketChannel to a port on the loopback + // address + if (ssc == null || !ssc.isOpen()) { + ssc = ServerSocketChannel.open(); + ssc.socket().bind(new InetSocketAddress(lb, 0)); + sa = new InetSocketAddress(lb, ssc.socket().getLocalPort()); + } + + // Establish connection (assume connections are eagerly + // accepted) + sc1 = SocketChannel.open(sa); + ByteBuffer bb = ByteBuffer.allocate(8); + long secret = rnd.nextLong(); + bb.putLong(secret).flip(); + sc1.write(bb); + + // Get a connection and verify it is legitimate + sc2 = ssc.accept(); + bb.clear(); + sc2.read(bb); + bb.rewind(); + if (bb.getLong() == secret) + break; sc2.close(); - } catch (IOException e2) { } - IOException x = new IOException("Unable to establish" - + " loopback connection"); - x.initCause(e); - throw x; - } finally { - try { - if (ssc != null) - ssc.close(); - } catch (IOException e2) { } + sc1.close(); + } + + // Create source and sink channels + source = new SourceChannelImpl(sp, sc1); + sink = new SinkChannelImpl(sp, sc2); + } catch (IOException e) { + try { + if (sc1 != null) + sc1.close(); + if (sc2 != null) + sc2.close(); + } catch (IOException e2) {} + ioe = e; + } finally { + try { + if (ssc != null) + ssc.close(); + } catch (IOException e2) {} + } } - return null; } } @@ -144,7 +174,6 @@ class PipeImpl } } - public SourceChannel source() { return source; } diff --git a/test/ProblemList.txt b/test/ProblemList.txt index ec698c7ef5d7d65cf5cbf7be1505d442fc0c0d30..3aa7cfff170f3a80d03d8889ddddd09f8a30f9da 100644 --- a/test/ProblemList.txt +++ b/test/ProblemList.txt @@ -1,6 +1,6 @@ ########################################################################### # -# Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -122,9 +122,6 @@ # jdk_lang -# 7194607 -java/lang/instrument/VerifyLocalVariableTableOnRetransformTest.sh generic-all - # 6944188 java/lang/management/ThreadMXBean/ThreadStateTest.java generic-all @@ -148,6 +145,9 @@ java/lang/management/MemoryMXBean/LowMemoryTest2.sh generic-all # 6959636 javax/management/loading/LibraryLoader/LibraryLoaderTest.java windows-all +# 8005472 +com/sun/jmx/remote/NotificationMarshalVersions/TestSerializationMismatch.sh windows-all + ############################################################################ # jdk_math @@ -238,9 +238,6 @@ java/nio/channels/AsynchronousChannelGroup/Unbounded.java windows-amd64 # 7146541 java/rmi/transport/rapidExportUnexport/RapidExportUnexport.java linux-all -# 7187882 -java/rmi/activation/checkusage/CheckUsage.java generic-all - # 7190106 java/rmi/reliability/benchmark/runRmiBench.sh generic-all @@ -324,6 +321,9 @@ tools/pack200/Pack200Test.java generic-all # 7150569 tools/launcher/UnicodeTest.java macosx-all +# 8005252 +tools/pack200/AttributeTests.java generic-all + ############################################################################ # jdk_jdi diff --git a/test/com/sun/crypto/provider/Cipher/AES/Test4512524.java b/test/com/sun/crypto/provider/Cipher/AES/Test4512524.java index b8b1c9292cab0322902909b9c6e82c81f0b47141..6b751e751b31d57ac1d75368849011b422aa16fe 100644 --- a/test/com/sun/crypto/provider/Cipher/AES/Test4512524.java +++ b/test/com/sun/crypto/provider/Cipher/AES/Test4512524.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,13 +40,13 @@ import com.sun.crypto.provider.*; public class Test4512524 { private static final String ALGO = "AES"; - private static final String MODE = "CBC"; private static final String PADDING = "NoPadding"; private static final int KEYSIZE = 16; // in bytes - public boolean execute() throws Exception { + public void execute(String mode) throws Exception { - Cipher ci = Cipher.getInstance(ALGO+"/"+MODE+"/"+PADDING, "SunJCE"); + String transformation = ALGO+"/"+mode+"/"+PADDING; + Cipher ci = Cipher.getInstance(transformation, "SunJCE"); // TEST FIX 4512524 KeyGenerator kg = KeyGenerator.getInstance(ALGO, "SunJCE"); @@ -61,17 +61,14 @@ public class Test4512524 { } // passed all tests...hooray! - return true; + System.out.println(transformation + ": Passed"); } public static void main (String[] args) throws Exception { Security.addProvider(new com.sun.crypto.provider.SunJCE()); Test4512524 test = new Test4512524(); - String testName = test.getClass().getName() + "[" + ALGO + - "/" + MODE + "/" + PADDING + "]"; - if (test.execute()) { - System.out.println(testName + ": Passed!"); - } + test.execute("CBC"); + test.execute("GCM"); } } diff --git a/test/com/sun/crypto/provider/Cipher/AES/Test4512704.java b/test/com/sun/crypto/provider/Cipher/AES/Test4512704.java index 414f7e2c372ed055a4cddd4a70de2b2a2be0c43c..ad89561493d3e77bbc965b2fdf4d3cd435f44328 100644 --- a/test/com/sun/crypto/provider/Cipher/AES/Test4512704.java +++ b/test/com/sun/crypto/provider/Cipher/AES/Test4512704.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,14 +39,14 @@ import com.sun.crypto.provider.*; public class Test4512704 { private static final String ALGO = "AES"; - private static final String MODE = "CBC"; - private static final String PADDING = "PKCS5Padding"; + private static final String PADDING = "NoPadding"; private static final int KEYSIZE = 16; // in bytes - public boolean execute() throws Exception { - AlgorithmParameterSpec aps = null; + public void execute(String mode) throws Exception { - Cipher ci = Cipher.getInstance(ALGO+"/"+MODE+"/"+PADDING, "SunJCE"); + AlgorithmParameterSpec aps = null; + String transformation = ALGO + "/" + mode + "/"+PADDING; + Cipher ci = Cipher.getInstance(transformation, "SunJCE"); KeyGenerator kg = KeyGenerator.getInstance(ALGO, "SunJCE"); kg.init(KEYSIZE*8); @@ -57,19 +57,14 @@ public class Test4512704 { } catch(InvalidAlgorithmParameterException ex) { throw new Exception("parameter should be generated when null is specified!"); } - - // passed all tests...hooray! - return true; + System.out.println(transformation + ": Passed"); } public static void main (String[] args) throws Exception { Security.addProvider(new com.sun.crypto.provider.SunJCE()); Test4512704 test = new Test4512704(); - String testName = test.getClass().getName() + "[" + ALGO + - "/" + MODE + "/" + PADDING + "]"; - if (test.execute()) { - System.out.println(testName + ": Passed!"); - } + test.execute("CBC"); + test.execute("GCM"); } } diff --git a/test/com/sun/crypto/provider/Cipher/AES/Test4517355.java b/test/com/sun/crypto/provider/Cipher/AES/Test4517355.java index 3474dbd3814c87747776731da298f0d1dee5d96d..a4716482918360193374bb38a4bcfaa40f2a7dc7 100644 --- a/test/com/sun/crypto/provider/Cipher/AES/Test4517355.java +++ b/test/com/sun/crypto/provider/Cipher/AES/Test4517355.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,16 +41,14 @@ import com.sun.crypto.provider.*; public class Test4517355 { private static final String ALGO = "AES"; - private static final String MODE = "CBC"; - private static final String PADDING = "PKCS5Padding"; private static final int KEYSIZE = 16; // in bytes - public boolean execute() throws Exception { - Random rdm = new Random(); - byte[] plainText=new byte[125]; - rdm.nextBytes(plainText); + private static byte[] plainText = new byte[125]; + + public void execute(String mode, String padding) throws Exception { + String transformation = ALGO + "/" + mode + "/" + padding; - Cipher ci = Cipher.getInstance(ALGO+"/"+MODE+"/"+PADDING, "SunJCE"); + Cipher ci = Cipher.getInstance(transformation, "SunJCE"); KeyGenerator kg = KeyGenerator.getInstance(ALGO, "SunJCE"); kg.init(KEYSIZE*8); SecretKey key = kg.generateKey(); @@ -59,9 +57,14 @@ public class Test4517355 { ci.init(Cipher.ENCRYPT_MODE, key); byte[] cipherText = ci.doFinal(plainText); - byte[] iv = ci.getIV(); - AlgorithmParameterSpec aps = new IvParameterSpec(iv); - ci.init(Cipher.DECRYPT_MODE, key, aps); + if (mode.equalsIgnoreCase("GCM")) { + AlgorithmParameters params = ci.getParameters(); + ci.init(Cipher.DECRYPT_MODE, key, params); + } else { + byte[] iv = ci.getIV(); + AlgorithmParameterSpec aps = new IvParameterSpec(iv); + ci.init(Cipher.DECRYPT_MODE, key, aps); + } byte[] recoveredText = new byte[plainText.length]; try { int len = ci.doFinal(cipherText, 0, cipherText.length, @@ -80,21 +83,22 @@ public class Test4517355 { throw new Exception("encryption does not work!"); } // 3. make sure padding is working - if ((cipherText.length/16)*16 != cipherText.length) { - throw new Exception("padding does not work!"); + if (padding.equalsIgnoreCase("PKCS5Padding")) { + if ((cipherText.length/16)*16 != cipherText.length) { + throw new Exception("padding does not work!"); + } } - // passed all tests...hooray! - return true; + System.out.println(transformation + ": Passed"); } public static void main (String[] args) throws Exception { Security.addProvider(new com.sun.crypto.provider.SunJCE()); Test4517355 test = new Test4517355(); - String testName = test.getClass().getName() + "[" + ALGO + - "/" + MODE + "/" + PADDING + "]"; - if (test.execute()) { - System.out.println(testName + ": Passed!"); - } + Random rdm = new Random(); + rdm.nextBytes(test.plainText); + + test.execute("CBC", "PKCS5Padding"); + test.execute("GCM", "NoPadding"); } } diff --git a/test/com/sun/crypto/provider/Cipher/AES/Test4626070.java b/test/com/sun/crypto/provider/Cipher/AES/Test4626070.java index 093308ced69ea263321bf267a1eb682ea9b29fc6..dc32cc4a657cd3130858fb67b946a84523448836 100644 --- a/test/com/sun/crypto/provider/Cipher/AES/Test4626070.java +++ b/test/com/sun/crypto/provider/Cipher/AES/Test4626070.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,13 +34,11 @@ import java.util.*; public class Test4626070 { private static final String ALGO = "AES"; - private static final String MODE = "CBC"; - private static final String PADDING = "PKCS5Padding"; private static final int KEYSIZE = 16; // in bytes - public boolean execute() throws Exception { - - Cipher ci = Cipher.getInstance(ALGO+"/"+MODE+"/"+PADDING, "SunJCE"); + public void execute(String mode, String padding) throws Exception { + String transformation = ALGO + "/" + mode + "/" + padding; + Cipher ci = Cipher.getInstance(transformation, "SunJCE"); KeyGenerator kg = KeyGenerator.getInstance(ALGO, "SunJCE"); kg.init(KEYSIZE*8); SecretKey key = kg.generateKey(); @@ -58,18 +56,14 @@ public class Test4626070 { throw new Exception( "key after wrap/unwrap is different from the original!"); } - // passed all tests...hooray! - return true; + System.out.println(transformation + ": Passed"); } public static void main (String[] args) throws Exception { Security.addProvider(new com.sun.crypto.provider.SunJCE()); Test4626070 test = new Test4626070(); - String testName = test.getClass().getName() + "[" + ALGO + - "/" + MODE + "/" + PADDING + "]"; - if (test.execute()) { - System.out.println(testName + ": Passed!"); - } + test.execute("CBC", "PKCS5Padding"); + test.execute("GCM", "NoPadding"); } } diff --git a/test/com/sun/crypto/provider/Cipher/AES/TestGCMKeyAndIvCheck.java b/test/com/sun/crypto/provider/Cipher/AES/TestGCMKeyAndIvCheck.java new file mode 100644 index 0000000000000000000000000000000000000000..e7d6e57bef7ce0edbff7eb1af756b45508b4cb36 --- /dev/null +++ b/test/com/sun/crypto/provider/Cipher/AES/TestGCMKeyAndIvCheck.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6996769 + * @library ../UTIL + * @build TestUtil + * @run main TestGCMKeyAndIvCheck + * @summary Ensure that same key+iv can't be repeated used for encryption. + * @author Valerie Peng + */ + + +import java.security.*; +import javax.crypto.*; +import javax.crypto.spec.*; +import java.math.*; +import com.sun.crypto.provider.*; + +import java.util.*; + +public class TestGCMKeyAndIvCheck { + + private static final byte[] AAD = new byte[5]; + private static final byte[] PT = new byte[18]; + + private static void checkISE(Cipher c) throws Exception { + // Subsequent encryptions should fail + try { + c.updateAAD(AAD); + throw new Exception("Should throw ISE for updateAAD()"); + } catch (IllegalStateException ise) { + // expected + } + + try { + c.update(PT); + throw new Exception("Should throw ISE for update()"); + } catch (IllegalStateException ise) { + // expected + } + try { + c.doFinal(PT); + throw new Exception("Should throw ISE for doFinal()"); + } catch (IllegalStateException ise) { + // expected + } + } + + public void test() throws Exception { + Cipher c = Cipher.getInstance("AES/GCM/NoPadding", "SunJCE"); + + SecretKey key = new SecretKeySpec(new byte[16], "AES"); + // First try parameter-less init. + c.init(Cipher.ENCRYPT_MODE, key); + c.updateAAD(AAD); + byte[] ctPlusTag = c.doFinal(PT); + + // subsequent encryption should fail unless re-init w/ different key+iv + checkISE(c); + + // Validate the retrieved parameters against the IV and tag length. + AlgorithmParameters params = c.getParameters(); + if (params == null) { + throw new Exception("getParameters() should not return null"); + } + GCMParameterSpec spec = params.getParameterSpec(GCMParameterSpec.class); + if (spec.getTLen() != (ctPlusTag.length - PT.length)*8) { + throw new Exception("Parameters contains incorrect TLen value"); + } + if (!Arrays.equals(spec.getIV(), c.getIV())) { + throw new Exception("Parameters contains incorrect IV value"); + } + + // Should be ok to use the same key+iv for decryption + c.init(Cipher.DECRYPT_MODE, key, params); + c.updateAAD(AAD); + byte[] recovered = c.doFinal(ctPlusTag); + if (!Arrays.equals(recovered, PT)) { + throw new Exception("decryption result mismatch"); + } + + // Now try to encrypt again using the same key+iv; should fail also + try { + c.init(Cipher.ENCRYPT_MODE, key, params); + throw new Exception("Should throw exception when same key+iv is used"); + } catch (InvalidAlgorithmParameterException iape) { + // expected + } + + // Now try to encrypt again using parameter-less init; should work + c.init(Cipher.ENCRYPT_MODE, key); + c.doFinal(PT); + + // make sure a different iv is used + byte[] iv = c.getIV(); + if (Arrays.equals(spec.getIV(), iv)) { + throw new Exception("IV should be different now"); + } + + // Now try to encrypt again using a different parameter; should work + c.init(Cipher.ENCRYPT_MODE, key, new GCMParameterSpec(128, new byte[30])); + c.updateAAD(AAD); + c.doFinal(PT); + // subsequent encryption should fail unless re-init w/ different key+iv + checkISE(c); + + // Now try decryption twice in a row; no re-init required and + // same parameters is used. + c.init(Cipher.DECRYPT_MODE, key, params); + c.updateAAD(AAD); + recovered = c.doFinal(ctPlusTag); + + c.updateAAD(AAD); + recovered = c.doFinal(ctPlusTag); + if (!Arrays.equals(recovered, PT)) { + throw new Exception("decryption result mismatch"); + } + + // Now try decryption again and re-init using the same parameters + c.init(Cipher.DECRYPT_MODE, key, params); + c.updateAAD(AAD); + recovered = c.doFinal(ctPlusTag); + + // init to decrypt w/o parameters; should fail with IKE as + // javadoc specified + try { + c.init(Cipher.DECRYPT_MODE, key); + throw new Exception("Should throw IKE for dec w/o params"); + } catch (InvalidKeyException ike) { + // expected + } + + // Lastly, try encryption AND decryption w/ wrong type of parameters, + // e.g. IvParameterSpec + try { + c.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv)); + throw new Exception("Should throw IAPE"); + } catch (InvalidAlgorithmParameterException iape) { + // expected + } + try { + c.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv)); + throw new Exception("Should throw IAPE"); + } catch (InvalidAlgorithmParameterException iape) { + // expected + } + + System.out.println("Test Passed!"); + } + + public static void main (String[] args) throws Exception { + TestGCMKeyAndIvCheck t = new TestGCMKeyAndIvCheck(); + t.test(); + } +} + diff --git a/test/com/sun/crypto/provider/Cipher/AES/TestKATForGCM.java b/test/com/sun/crypto/provider/Cipher/AES/TestKATForGCM.java new file mode 100644 index 0000000000000000000000000000000000000000..360201393d27f89564585d420c84b02dc8d26882 --- /dev/null +++ b/test/com/sun/crypto/provider/Cipher/AES/TestKATForGCM.java @@ -0,0 +1,314 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 6996769 + * @library ../UTIL + * @build TestUtil + * @run main TestKATForGCM + * @summary Known Answer Test for AES cipher with GCM mode support in + * SunJCE provider. + * @author Valerie Peng + */ + + +import java.security.*; +import javax.crypto.*; +import javax.crypto.spec.*; +import java.math.*; +import com.sun.crypto.provider.*; + +import java.util.*; + +public class TestKATForGCM { + + // Utility methods + private static byte[] HexToBytes(String hexVal) { + if (hexVal == null) return new byte[0]; + byte[] result = new byte[hexVal.length()/2]; + for (int i = 0; i < result.length; i++) { + // 2 characters at a time + String byteVal = hexVal.substring(2*i, 2*i +2); + result[i] = Integer.valueOf(byteVal, 16).byteValue(); + } + return result; + } + + private static class TestVector { + SecretKey key; + byte[] plainText; + byte[] aad; + byte[] cipherText; + byte[] tag; + GCMParameterSpec spec; + String info; + + TestVector(String key, String iv, String pt, String aad, + String ct, String tag) { + this.key = new SecretKeySpec(HexToBytes(key), "AES"); + this.plainText = HexToBytes(pt); + this.aad = HexToBytes(aad); + this.cipherText = HexToBytes(ct); + this.tag = HexToBytes(tag); + this.spec = new GCMParameterSpec(this.tag.length * 8, HexToBytes(iv)); + this.info = "key=" + key + ", iv=" + iv + ", pt=" + pt + + ",aad=" + aad + ", ct=" + ct + ", tag=" + tag; + } + + public String toString() { + return info; + } + } + + // These test vectors are found off NIST's CAVP page + // http://csrc.nist.gov/groups/STM/cavp/index.html + // inside the link named "GCM Test Vectors", i.e. + // http://csrc.nist.gov/groups/STM/cavp/documents/mac/gcmtestvectors.zip + // CAVS 14.0, set of test vectors w/ count = 0, keysize = 128 + private static TestVector[] testValues = { + // 96-bit iv w/ 128/120/112/104/96-bit tags + // no plain text, no aad + new TestVector("11754cd72aec309bf52f7687212e8957", + "3c819d9a9bed087615030b65", + null, null, null, + "250327c674aaf477aef2675748cf6971"), + new TestVector("272f16edb81a7abbea887357a58c1917", + "794ec588176c703d3d2a7a07", + null, null, null, + "b6e6f197168f5049aeda32dafbdaeb"), + new TestVector("81b6844aab6a568c4556a2eb7eae752f", + "ce600f59618315a6829bef4d", + null, null, null, + "89b43e9dbc1b4f597dbbc7655bb5"), + new TestVector("cde2f9a9b1a004165ef9dc981f18651b", + "29512c29566c7322e1e33e8e", + null, null, null, + "2e58ce7dabd107c82759c66a75"), + new TestVector("b01e45cc3088aaba9fa43d81d481823f", + "5a2c4a66468713456a4bd5e1", + null, null, null, + "014280f944f53c681164b2ff"), + // 96-bit iv w/ 128/120/112/104/96-bit tags + // no plain text, 16-byte aad + new TestVector("77be63708971c4e240d1cb79e8d77feb", + "e0e00f19fed7ba0136a797f3", + null, + "7a43ec1d9c0a5a78a0b16533a6213cab", + null, + "209fcc8d3675ed938e9c7166709dd946"), + new TestVector("da0b615656135194ba6d3c851099bc48", + "d39d4b4d3cc927885090e6c3", + null, + "e7e5e6f8dac913036cb2ff29e8625e0e", + null, + "ab967711a5770461724460b07237e2"), + new TestVector("7e0986937a88eef894235aba4a2f43b2", + "92c4a631695907166b422d60", + null, + "85c185f8518f9f2cd597a8f9208fc76b", + null, + "3bb916b728df94fe9d1916736be1"), + new TestVector("c3db570d7f0c21e86b028f11465d1dc9", + "f86970f58ceef89fc7cb679e", + null, + "c095240708c0f57c288d86090ae34ee1", + null, + "e043c52160d652e82c7262fcf4"), + new TestVector("bea48ae4980d27f357611014d4486625", + "32bddb5c3aa998a08556454c", + null, + "8a50b0b8c7654bced884f7f3afda2ead", + null, + "8e0f6d8bf05ffebe6f500eb1"), + // 96-bit iv w/ 128/120/112/104/96-bit tags + // no plain text, 20-byte aad + new TestVector("2fb45e5b8f993a2bfebc4b15b533e0b4", + "5b05755f984d2b90f94b8027", + null, + "e85491b2202caf1d7dce03b97e09331c32473941", + null, + "c75b7832b2a2d9bd827412b6ef5769db"), + new TestVector("9bf406339fcef9675bbcf156aa1a0661", + "8be4a9543d40f542abacac95", + null, + "7167cbf56971793186333a6685bbd58d47d379b3", + null, + "5e7968d7bbd5ba58cfcc750e2ef8f1"), + new TestVector("a2e962fff70fd0f4d63be728b80556fc", + "1fa7103483de43d09bc23db4", + null, + "2a58edf1d53f46e4e7ee5e77ee7aeb60fc360658", + null, + "fa37f2dbbefab1451eae1d0d74ca"), + new TestVector("6bf4fdce82926dcdfc52616ed5f23695", + "cc0f5899a10615567e1193ed", + null, + "3340655592374c1da2f05aac3ee111014986107f", + null, + "8ad3385cce3b5e7c985908192c"), + new TestVector("4df7a13e43c3d7b66b1a72fac5ba398e", + "97179a3a2d417908dcf0fb28", + null, + "cbb7fc0010c255661e23b07dbd804b1e06ae70ac", + null, + "37791edae6c137ea946cfb40"), + // 96-bit iv w/ 128-bit tags, 13/16/32/51-byte plain text, no aad + new TestVector("fe9bb47deb3a61e423c2231841cfd1fb", + "4d328eb776f500a2f7fb47aa", + "f1cc3818e421876bb6b8bbd6c9", + null, + "b88c5c1977b35b517b0aeae967", + "43fd4727fe5cdb4b5b42818dea7ef8c9"), + new TestVector("7fddb57453c241d03efbed3ac44e371c", + "ee283a3fc75575e33efd4887", + "d5de42b461646c255c87bd2962d3b9a2", + null, + "2ccda4a5415cb91e135c2a0f78c9b2fd", + "b36d1df9b9d5e596f83e8b7f52971cb3"), + new TestVector("9971071059abc009e4f2bd69869db338", + "07a9a95ea3821e9c13c63251", + "f54bc3501fed4f6f6dfb5ea80106df0bd836e6826225b75c0222f6e859b35983", + null, + "0556c159f84ef36cb1602b4526b12009c775611bffb64dc0d9ca9297cd2c6a01", + "7870d9117f54811a346970f1de090c41"), + new TestVector("594157ec4693202b030f33798b07176d", + "49b12054082660803a1df3df", + +"3feef98a976a1bd634f364ac428bb59cd51fb159ec1789946918dbd50ea6c9d594a3a31a5269b0da6936c29d063a5fa2cc8a1c", + null, + +"c1b7a46a335f23d65b8db4008a49796906e225474f4fe7d39e55bf2efd97fd82d4167de082ae30fa01e465a601235d8d68bc69", + "ba92d3661ce8b04687e8788d55417dc2"), + // 96-bit iv w/ 128-bit tags, 16-byte plain text, 16/20/48/90-byte aad + new TestVector("c939cc13397c1d37de6ae0e1cb7c423c", + "b3d8cc017cbb89b39e0f67e2", + "c3b3c41f113a31b73d9a5cd432103069", + "24825602bd12a984e0092d3e448eda5f", + "93fe7d9e9bfd10348a5606e5cafa7354", + "0032a1dc85f1c9786925a2e71d8272dd"), + new TestVector("d4a22488f8dd1d5c6c19a7d6ca17964c", + "f3d5837f22ac1a0425e0d1d5", + "7b43016a16896497fb457be6d2a54122", + "f1c5d424b83f96c6ad8cb28ca0d20e475e023b5a", + "c2bd67eef5e95cac27e3b06e3031d0a8", + "f23eacf9d1cdf8737726c58648826e9c"), + new TestVector("89850dd398e1f1e28443a33d40162664", + "e462c58482fe8264aeeb7231", + "2805cdefb3ef6cc35cd1f169f98da81a", + +"d74e99d1bdaa712864eec422ac507bddbe2b0d4633cd3dff29ce5059b49fe868526c59a2a3a604457bc2afea866e7606", + "ba80e244b7fc9025cd031d0f63677e06", + "d84a8c3eac57d1bb0e890a8f461d1065"), + new TestVector("bd7c5c63b7542b56a00ebe71336a1588", + "87721f23ba9c3c8ea5571abc", + "de15ddbb1e202161e8a79af6a55ac6f3", + +"a6ec8075a0d3370eb7598918f3b93e48444751624997b899a87fa6a9939f844e008aa8b70e9f4c3b1a19d3286bf543e7127bfecba1ad17a5ec53fccc26faecacc4c75369498eaa7d706aef634d0009279b11e4ba6c993e5e9ed9", + "41eb28c0fee4d762de972361c863bc80", + "9cb567220d0b252eb97bff46e4b00ff8"), + // 8/1024-bit iv w/ 128-bit tag, no plain text, no aad + new TestVector("1672c3537afa82004c6b8a46f6f0d026", + "05", + null, null, null, + "8e2ad721f9455f74d8b53d3141f27e8e"), + new TestVector("d0f1f4defa1e8c08b4b26d576392027c", + +"42b4f01eb9f5a1ea5b1eb73b0fb0baed54f387ecaa0393c7d7dffc6af50146ecc021abf7eb9038d4303d91f8d741a11743166c0860208bcc02c6258fd9511a2fa626f96d60b72fcff773af4e88e7a923506e4916ecbd814651e9f445adef4ad6a6b6c7290cc13b956130eef5b837c939fcac0cbbcc9656cd75b13823ee5acdac", + null, null, null, + "7ab49b57ddf5f62c427950111c5c4f0d"), + // 8-bit iv w/ 128-bit tag, 13-byte plain text, 90-byte aad + new TestVector("9f79239f0904eace50784b863e723f6b", + "d9", + "bdb0bb10c87965acd34d146171", + +"44db436089327726c5f01139e1f339735c9e85514ccc2f167bad728010fb34a9072a9794c8a5e7361b1d0dbcdc9ac4091e354bb2896561f0486645252e9c78c86beece91bfa4f7cc4a8794ce1f305b1b735efdbf1ed1563c0be0", + "7e5a7c8dadb3f0c7335b4d9d8d", + "6b6ef1f53723a89f3bb7c6d043840717"), + // 1024-bit iv w/ 128-bit tag, 51-byte plain text, 48-byte aad + new TestVector("141f1ce91989b07e7eb6ae1dbd81ea5e", + +"49451da24bd6074509d3cebc2c0394c972e6934b45a1d91f3ce1d3ca69e194aa1958a7c21b6f21d530ce6d2cc5256a3f846b6f9d2f38df0102c4791e57df038f6e69085646007df999751e248e06c47245f4cd3b8004585a7470dee1690e9d2d63169a58d243c0b57b3e5b4a481a3e4e8c60007094ef3adea2e8f05dd3a1396f", + +"d384305af2388699aa302f510913fed0f2cb63ba42efa8c5c9de2922a2ec2fe87719dadf1eb0aef212b51e74c9c5b934104a43", + +"630cf18a91cc5a6481ac9eefd65c24b1a3c93396bd7294d6b8ba323951727666c947a21894a079ef061ee159c05beeb4", + +"f4c34e5fbe74c0297313268296cd561d59ccc95bbfcdfcdc71b0097dbd83240446b28dc088abd42b0fc687f208190ff24c0548", + "dbb93bbb56d0439cd09f620a57687f5d"), + }; + + public boolean execute(TestVector[] testValues) throws Exception { + boolean testFailed = false; + Cipher c = Cipher.getInstance("AES/GCM/NoPadding", "SunJCE"); + for (int i = 0; i < testValues.length; i++) { + try { + c.init(Cipher.ENCRYPT_MODE, testValues[i].key, testValues[i].spec); + c.updateAAD(testValues[i].aad); + byte[] ctPlusTag = c.doFinal(testValues[i].plainText); + + c.init(Cipher.DECRYPT_MODE, testValues[i].key, testValues[i].spec); + c.updateAAD(testValues[i].aad); + byte[] pt = c.doFinal(ctPlusTag); // should fail if tag mismatched + + // check encryption/decryption results just to be sure + if (!Arrays.equals(testValues[i].plainText, pt)) { + System.out.println("PlainText diff failed for test# " + i); + testFailed = true; + } + int ctLen = testValues[i].cipherText.length; + if (!Arrays.equals(testValues[i].cipherText, + Arrays.copyOf(ctPlusTag, ctLen))) { + System.out.println("CipherText diff failed for test# " + i); + testFailed = true; + } + int tagLen = testValues[i].tag.length; + if (!Arrays.equals + (testValues[i].tag, + Arrays.copyOfRange(ctPlusTag, ctLen, ctLen+tagLen))) { + System.out.println("Tag diff failed for test# " + i); + testFailed = true; + } + } catch (Exception ex) { + // continue testing other test vectors + System.out.println("Failed Test Vector: " + testValues[i]); + ex.printStackTrace(); + testFailed = true; + continue; + } + } + if (testFailed) { + throw new Exception("Test Failed"); + } + // passed all tests...hooray! + return true; + } + + public static void main (String[] args) throws Exception { + TestKATForGCM test = new TestKATForGCM(); + if (test.execute(testValues)) { + System.out.println("Test Passed!"); + } + } +} + diff --git a/test/java/lang/Runtime/exec/WinCommand.java b/test/java/lang/Runtime/exec/WinCommand.java index 77cfe67e40a971732e1fce1f4208cafc7789ecb1..a812bffd13566e7f6ecdedd2f0a004c022a4cae9 100644 --- a/test/java/lang/Runtime/exec/WinCommand.java +++ b/test/java/lang/Runtime/exec/WinCommand.java @@ -135,24 +135,19 @@ public class WinCommand { // Win9x systems don't have a cmd.exe if (new File(systemDirW, "cmd.exe").exists()) { - try { - out.println("Running cmd.exe tests..."); - writeFile("cdcmd.cmd", "@echo off\r\nCD\r\n"); - writeFile("cdbat.bat", "@echo off\r\nCD\r\n"); - checkCD("cmd", - "cmd.exe", - systemDirW + "\\cmd.exe", - // Only the ".exe" extension can be omitted - systemDirW + "\\cmd", - systemDirM + "/cmd.exe", - systemDirM + "/cmd", - "/" + systemDirM + "/cmd", - "cdcmd.cmd", "./cdcmd.cmd", ".\\cdcmd.cmd", - "cdbat.bat", "./cdbat.bat", ".\\cdbat.bat"); - } finally { - new File("cdcmd.cmd").delete(); - new File("cdbat.bat").delete(); - } + out.println("Running cmd.exe tests..."); + writeFile("cdcmd.cmd", "@echo off\r\nCD\r\n"); + writeFile("cdbat.bat", "@echo off\r\nCD\r\n"); + checkCD("cmd", + "cmd.exe", + systemDirW + "\\cmd.exe", + // Only the ".exe" extension can be omitted + systemDirW + "\\cmd", + systemDirM + "/cmd.exe", + systemDirM + "/cmd", + "/" + systemDirM + "/cmd", + "cdcmd.cmd", "./cdcmd.cmd", ".\\cdcmd.cmd", + "cdbat.bat", "./cdbat.bat", ".\\cdbat.bat"); } // 16-bit apps like command.com must have a console; diff --git a/test/java/lang/System/MacJNUEncoding/ExpectedEncoding.java b/test/java/lang/System/MacJNUEncoding/ExpectedEncoding.java new file mode 100644 index 0000000000000000000000000000000000000000..723d45c677f0b9109b92a2f1d4a08daf09937426 --- /dev/null +++ b/test/java/lang/System/MacJNUEncoding/ExpectedEncoding.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * Check that the value of file.encoding and sun.jnu.encoding match the expected + * values passed in on the command-line. + */ +public class ExpectedEncoding { + public static void main(String[] args) { + boolean failed = false; + if (args.length != 2) { + System.out.println("Usage:"); + System.out.println("$ java ExpectedEncoding "); + System.exit(1); + } + String expectFileEnc = args[0]; + String expectSunJnuEnc = args[1]; + + String fileEnc = System.getProperty("file.encoding"); + String jnuEnc = System.getProperty("sun.jnu.encoding"); + + if (fileEnc == null || !fileEnc.equals(expectFileEnc)) { + System.err.println("Expected file.encoding: " + expectFileEnc); + System.err.println("Actual file.encoding: " + fileEnc); + failed = true; + } + if (jnuEnc == null || !jnuEnc.equals(expectSunJnuEnc)) { + System.err.println("Expected sun.jnu.encoding: " + expectSunJnuEnc); + System.err.println("Actual sun.jnu.encoding: " + jnuEnc); + failed = true; + } + if (failed) { + throw new RuntimeException("Test Failed"); + } + } +} diff --git a/test/java/lang/System/MacJNUEncoding/MacJNUEncoding.sh b/test/java/lang/System/MacJNUEncoding/MacJNUEncoding.sh new file mode 100644 index 0000000000000000000000000000000000000000..a03bdd91f17e37d1a9f5a68226c6d32e9f6292d0 --- /dev/null +++ b/test/java/lang/System/MacJNUEncoding/MacJNUEncoding.sh @@ -0,0 +1,96 @@ +#!/bin/sh + +# +# Copyright (c) 2012 Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. + +# @test +# @bug 8003228 +# @summary Test the value of sun.jnu.encoding on Mac +# @author Brent Christian +# +# @run shell MacJNUEncoding.sh + +# Only run test on Mac +OS=`uname -s` +case "$OS" in + Darwin ) ;; + * ) + exit 0 + ;; +esac + +if [ "${TESTJAVA}" = "" ] +then + echo "TESTJAVA not set. Test cannot execute. Failed." + exit 1 +fi + +if [ "${TESTSRC}" = "" ] +then + echo "TESTSRC not set. Test cannot execute. Failed." + exit 1 +fi + +if [ "${TESTCLASSES}" = "" ] +then + echo "TESTCLASSES not set. Test cannot execute. Failed." + exit 1 +fi + +JAVAC="${TESTJAVA}"/bin/javac +JAVA="${TESTJAVA}"/bin/java + +echo "Building test classes..." +"$JAVAC" -d "${TESTCLASSES}" "${TESTSRC}"/ExpectedEncoding.java + +echo "" +echo "Running test for C locale" +export LANG=C +export LC_ALL=C +"${JAVA}" ${TESTVMOPTS} -classpath "${TESTCLASSES}" ExpectedEncoding US-ASCII UTF-8 +result1=$? + +echo "" +echo "Running test for en_US.UTF-8 locale" +export LANG=en_US.UTF-8 +export LC_ALL=en_US.UTF-8 +"${JAVA}" ${TESTVMOPTS} -classpath "${TESTCLASSES}" ExpectedEncoding UTF-8 UTF-8 +result2=$? + +echo "" +echo "Cleanup" +rm ${TESTCLASSES}/ExpectedEncoding.class + +if [ ${result1} -ne 0 ] ; then + echo "Test failed for C locale" + echo " LANG=\"${LANG}\"" + echo " LC_ALL=\"${LC_ALL}\"" + exit ${result1} +fi +if [ ${result2} -ne 0 ] ; then + echo "Test failed for en_US.UTF-8 locale" + echo " LANG=\"${LANG}\"" + echo " LC_ALL=\"${LC_ALL}\"" + exit ${result2} +fi +exit 0 + diff --git a/test/java/net/Socks/SocksV4Test.java b/test/java/net/Socks/SocksV4Test.java index b61d658a78af5ab7330bb0d6bc804801bccd86a2..cc0452e5ea4ef41a6f8976f19408568f7a065495 100644 --- a/test/java/net/Socks/SocksV4Test.java +++ b/test/java/net/Socks/SocksV4Test.java @@ -26,6 +26,7 @@ * @bug 4727547 * @summary SocksSocketImpl throws NullPointerException * @build SocksServer + * @run main SocksV4Test */ import java.net.*; diff --git a/test/java/nio/channels/Pipe/PipeInterrupt.java b/test/java/nio/channels/Pipe/PipeInterrupt.java new file mode 100644 index 0000000000000000000000000000000000000000..b00c0056d74742afcedf7e4fea47587bb6981ba6 --- /dev/null +++ b/test/java/nio/channels/Pipe/PipeInterrupt.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 8002306 + * @summary Ensure that a Pipe can open even if its thread has already + * been interrupted. + * @author Dan Xu + */ + +import java.io.IOException; +import java.nio.channels.Pipe; + + +public class PipeInterrupt { + + private Exception exc = null; + + public static void main(String[] args) throws Exception { + PipeInterrupt instance = new PipeInterrupt(); + instance.test(); + } + + public void test() throws Exception { + + Thread tester = new Thread("PipeTester") { + private Pipe testPipe = null; + + @Override + public void run() { + for (;;) { + boolean interrupted = this.isInterrupted(); + try { + testPipe = Pipe.open(); + close(); + if (interrupted) { + if (!this.isInterrupted()) + exc = new RuntimeException("interrupt status reset"); + break; + } + } catch (IOException ioe) { + exc = ioe; + } + } + } + + private void close() throws IOException { + if (testPipe != null) { + testPipe.sink().close(); + testPipe.source().close(); + } + } + }; + + tester.start(); + Thread.sleep(200); + tester.interrupt(); + tester.join(); + + if (exc != null) + throw exc; + } +} diff --git a/test/java/rmi/activation/Activatable/shutdownGracefully/ShutdownGracefully.java b/test/java/rmi/activation/Activatable/shutdownGracefully/ShutdownGracefully.java index 64233bfd6f1b446b3f283c53e11fd7a026a98464..b6ede1d316a1fe4df419205a4175c1b2d6f5292a 100644 --- a/test/java/rmi/activation/Activatable/shutdownGracefully/ShutdownGracefully.java +++ b/test/java/rmi/activation/Activatable/shutdownGracefully/ShutdownGracefully.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -168,7 +168,7 @@ public class ShutdownGracefully registering = null; // Need to make sure that rmid goes away by itself - Process rmidProcess = rmid.getVM(); + JavaVM rmidProcess = rmid; if (rmidProcess != null) { try { Runnable waitThread = @@ -205,9 +205,9 @@ public class ShutdownGracefully * class that waits for rmid to exit */ private static class ShutdownDetectThread implements Runnable { - private Process rmidProcess = null; + private JavaVM rmidProcess = null; - ShutdownDetectThread(Process rmidProcess) { + ShutdownDetectThread(JavaVM rmidProcess) { this.rmidProcess = rmidProcess; } public void run() { diff --git a/test/java/rmi/activation/checkusage/CheckUsage.java b/test/java/rmi/activation/checkusage/CheckUsage.java index 2b514e1f37076ed77f8645b7050df8734d337ac8..c114928d201ef5f29ca44525e4c9d0ae1c808c16 100644 --- a/test/java/rmi/activation/checkusage/CheckUsage.java +++ b/test/java/rmi/activation/checkusage/CheckUsage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ /* @test * @bug 4259564 + * @summary RMID's usage message is incomplete and inconsistent with other tools * * @library ../../testlibrary * @build TestLibrary JavaVM @@ -37,23 +38,16 @@ import java.io.ByteArrayOutputStream; */ public class CheckUsage { public static void main(String[] args) { - - System.err.println("\nregression test for 4259564\n"); - - JavaVM rmidVM = null; - try { - // make sure the registry exits with a proper usage statement ByteArrayOutputStream berr = new ByteArrayOutputStream(); - // run a VM to start the registry - rmidVM = new JavaVM("sun.rmi.server.Activation", "", "foo", - System.out, berr); + // create rmid with incorrect command line args + JavaVM rmidVM = new JavaVM("sun.rmi.server.Activation", "", "foo", + System.out, berr); System.err.println("starting rmid"); - rmidVM.start(); - // wait for registry exit - int rmidVMExitStatus = rmidVM.getVM().waitFor(); + // run the subprocess and wait for it to exit + int rmidVMExitStatus = rmidVM.execute(); System.err.println("rmid exited with status: " + rmidVMExitStatus); @@ -66,12 +60,8 @@ public class CheckUsage { } else { System.err.println("test passed"); } - } catch (Exception e) { TestLibrary.bomb(e); - } finally { - rmidVM.destroy(); - rmidVM = null; } } } diff --git a/test/java/rmi/registry/altSecurityManager/AltSecurityManager.java b/test/java/rmi/registry/altSecurityManager/AltSecurityManager.java index 08d030ec876ec8bf9ef4329e58edc4043b3d17cb..351042965de16286d837b1cd10e0443ac7e1df28 100644 --- a/test/java/rmi/registry/altSecurityManager/AltSecurityManager.java +++ b/test/java/rmi/registry/altSecurityManager/AltSecurityManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -76,8 +76,7 @@ public class AltSecurityManager implements Runnable { } System.err.println("starting " + utilityToStart); - vm.start(); - vm.getVM().waitFor(); + vm.execute(); } catch (Exception e) { TestLibrary.bomb(e); diff --git a/test/java/rmi/registry/checkusage/CheckUsage.java b/test/java/rmi/registry/checkusage/CheckUsage.java index 19dac5b600ab3a1db2b4df42dd2a808ef538cf9f..88d9a900cdd60d47aff3f682b1752d049d601fde 100644 --- a/test/java/rmi/registry/checkusage/CheckUsage.java +++ b/test/java/rmi/registry/checkusage/CheckUsage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,34 +35,21 @@ import java.io.ByteArrayOutputStream; /** * Make sure that the rmiregistry prints out a correct usage statement - * when run with an incorrect command line; test written to conform to - * new tighter bug fix/regression test guidelines. + * when run with an incorrect command line. */ public class CheckUsage { public static void main(String[] args) { - System.err.println("\nregression test for 4151966\n"); - - JavaVM registryVM = null; - try { - // make sure the registry exits with a proper usage statement ByteArrayOutputStream berr = new ByteArrayOutputStream(); // run a VM to start the registry - registryVM = new JavaVM("sun.rmi.registry.RegistryImpl", - "", "foo", - System.out, berr); + JavaVM registryVM = new JavaVM("sun.rmi.registry.RegistryImpl", + "", "foo", + System.out, berr); System.err.println("starting registry"); - registryVM.start(); - - // wait for registry exit System.err.println(" registry exited with status: " + - registryVM.getVM().waitFor()); - try { - Thread.sleep(7000); - } catch (InterruptedException ie) { - } + registryVM.execute()); String usage = new String(berr.toByteArray()); @@ -75,9 +62,6 @@ public class CheckUsage { } } catch (Exception e) { TestLibrary.bomb(e); - } finally { - registryVM.destroy(); - registryVM = null; } } } diff --git a/test/java/rmi/registry/reexport/Reexport.java b/test/java/rmi/registry/reexport/Reexport.java index c209f7c55b85eda6be22d64d3fa6a3b75f7652f0..3841178533e5513dee020569f550cd76fc7678e7 100644 --- a/test/java/rmi/registry/reexport/Reexport.java +++ b/test/java/rmi/registry/reexport/Reexport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -122,8 +122,7 @@ public class Reexport { try { JavaVM jvm = new JavaVM("RegistryRunner", "", Integer.toString(p)); jvm.start(); - Reexport.subreg = jvm.getVM(); - + Reexport.subreg = jvm; } catch (IOException e) { // one of these is summarily dropped, can't remember which one System.out.println ("Test setup failed - cannot run rmiregistry"); @@ -135,7 +134,8 @@ public class Reexport { } catch (Exception whatever) { } } - private static Process subreg = null; + + private static JavaVM subreg = null; public static void killRegistry(int port) { if (Reexport.subreg != null) { diff --git a/test/java/rmi/testlibrary/JavaVM.java b/test/java/rmi/testlibrary/JavaVM.java index 6ccae911a8659758be056bbdaf82b3743ec75c84..c363f8e44203a5a49cad07b260dec5e4dd4f2622 100644 --- a/test/java/rmi/testlibrary/JavaVM.java +++ b/test/java/rmi/testlibrary/JavaVM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,8 @@ public class JavaVM { private OutputStream outputStream = System.out; private OutputStream errorStream = System.err; private String policyFileName = null; + private StreamPipe outPipe; + private StreamPipe errPipe; private static void mesg(Object mesg) { System.err.println("JAVAVM: " + mesg.toString()); @@ -145,13 +147,12 @@ public class JavaVM { } mesg("command = " + Arrays.asList(javaCommand).toString()); - System.err.println(""); vm = Runtime.getRuntime().exec(javaCommand); /* output from the execed process may optionally be captured. */ - StreamPipe.plugTogether(vm.getInputStream(), this.outputStream); - StreamPipe.plugTogether(vm.getErrorStream(), this.errorStream); + outPipe = StreamPipe.plugTogether(vm.getInputStream(), this.outputStream); + errPipe = StreamPipe.plugTogether(vm.getErrorStream(), this.errorStream); } public void destroy() { @@ -161,7 +162,25 @@ public class JavaVM { vm = null; } - protected Process getVM() { - return vm; + /** + * Waits for the subprocess to exit, joins the pipe threads to ensure that + * all output is collected, and returns its exit status. + */ + public int waitFor() throws InterruptedException { + if (vm == null) + throw new IllegalStateException("can't wait for JavaVM that hasn't started"); + + int status = vm.waitFor(); + outPipe.join(); + errPipe.join(); + return status; + } + + /** + * Starts the subprocess, waits for it to exit, and returns its exit status. + */ + public int execute() throws IOException, InterruptedException { + start(); + return waitFor(); } } diff --git a/test/java/rmi/testlibrary/RMID.java b/test/java/rmi/testlibrary/RMID.java index e963c45c9766250f4526ee7260ff0f05ee32b30d..8b0f3e26bd46c1e60b4d295aacad1f6322f96a34 100644 --- a/test/java/rmi/testlibrary/RMID.java +++ b/test/java/rmi/testlibrary/RMID.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -202,8 +202,6 @@ public class RMID extends JavaVM { public void start(long waitTime) throws IOException { - if (getVM() != null) return; - // if rmid is already running, then the test will fail with // a well recognized exception (port already in use...). diff --git a/test/java/rmi/transport/checkFQDN/CheckFQDN.java b/test/java/rmi/transport/checkFQDN/CheckFQDN.java index 9660f532c39905179d9b1ea4246b0f36bc846a45..deceb2795f992f3ce0d630dc04949dca2a45fa95 100644 --- a/test/java/rmi/transport/checkFQDN/CheckFQDN.java +++ b/test/java/rmi/transport/checkFQDN/CheckFQDN.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -114,6 +114,7 @@ public class CheckFQDN extends UnicastRemoteObject equal = "="; } + // create a client to tell checkFQDN what its rmi name is. JavaVM jvm = new JavaVM("CheckFQDNClient", propOption + property + equal + @@ -125,10 +126,7 @@ public class CheckFQDN extends UnicastRemoteObject propertyBeingTested=property; propertyBeingTestedValue=propertyValue; - // create a client to tell checkFQDN what its rmi name is. */ - jvm.start(); - - if (jvm.getVM().waitFor() != 0 ) { + if (jvm.execute() != 0) { TestLibrary.bomb("Test failed, error in client."); } diff --git a/test/java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java b/test/java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java index 52fd7df9295d86d64d5be82f868b444e711da28a..b32a8a51b0ab04146f0186c9e73f7b8bf5d99a38 100644 --- a/test/java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java +++ b/test/java/rmi/transport/checkLeaseInfoLeak/CheckLeaseLeak.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -102,9 +102,8 @@ public class CheckLeaseLeak extends UnicastRemoteObject implements LeaseLeak { " -Drmi.registry.port=" + registryPort, ""); - jvm.start(); - if (jvm.getVM().waitFor() == 1 ) { + if (jvm.execute() != 0) { TestLibrary.bomb("Client process failed"); } } diff --git a/test/java/security/Principal/Implies.java b/test/java/security/Principal/Implies.java new file mode 100644 index 0000000000000000000000000000000000000000..d3cfd2493e813bac356c6fccd2259ce56edd010c --- /dev/null +++ b/test/java/security/Principal/Implies.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 7019834 + * @summary test default implementation of Principal.implies + */ + +import java.security.Principal; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import javax.security.auth.Subject; +import javax.security.auth.kerberos.KerberosPrincipal; +import javax.security.auth.x500.X500Principal; + +public class Implies { + public static void main(String[] args) throws Exception { + X500Principal duke = new X500Principal("CN=Duke"); + // should not throw NullPointerException + testImplies(duke, (Subject)null, false); + + Set principals = new HashSet<>(); + principals.add(duke); + testImplies(duke, principals, true); + + X500Principal tux = new X500Principal("CN=Tux"); + principals.add(tux); + testImplies(duke, principals, true); + + principals.add(new KerberosPrincipal("duke@java.com")); + testImplies(duke, principals, true); + + principals.clear(); + principals.add(tux); + testImplies(duke, principals, false); + + System.out.println("test passed"); + } + + private static void testImplies(Principal principal, + Set principals, + boolean result) + throws SecurityException + { + Subject subject = new Subject(true, principals, Collections.emptySet(), + Collections.emptySet()); + testImplies(principal, subject, result); + } + + private static void testImplies(Principal principal, + Subject subject, boolean result) + throws SecurityException + { + if (principal.implies(subject) != result) { + throw new SecurityException("test failed"); + } + } +} diff --git a/test/javax/crypto/Cipher/GCMAPI.java b/test/javax/crypto/Cipher/GCMAPI.java index 1ccb230d3280f39bb5ee6ccf28156664d025e4a9..f25858b67ed98a35d07b502da7fbf87a99fabba7 100644 --- a/test/javax/crypto/Cipher/GCMAPI.java +++ b/test/javax/crypto/Cipher/GCMAPI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -78,6 +78,8 @@ public class GCMAPI { c.updateAAD(src); } catch (UnsupportedOperationException e) { // swallow + } catch (IllegalStateException ise) { + // swallow }catch (Exception e) { e.printStackTrace(); failed++; @@ -99,6 +101,8 @@ public class GCMAPI { c.updateAAD(src, offset, len); } catch (UnsupportedOperationException e) { // swallow + } catch (IllegalStateException ise) { + // swallow } catch (Exception e) { e.printStackTrace(); failed++; @@ -120,6 +124,8 @@ public class GCMAPI { c.updateAAD(src); } catch (UnsupportedOperationException e) { // swallow + } catch (IllegalStateException ise) { + // swallow }catch (Exception e) { e.printStackTrace(); failed++; diff --git a/test/javax/swing/JTable/8005019/bug8005019.java b/test/javax/swing/JTable/8005019/bug8005019.java new file mode 100644 index 0000000000000000000000000000000000000000..e0849453588e2ba12e9844d7c3043d1b07cdfb8a --- /dev/null +++ b/test/javax/swing/JTable/8005019/bug8005019.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 8005019 + * @summary JTable passes row index instead of length when inserts selection interval + * @author Alexander Scherbatiy + * @run main bug8005019 + */ + +import java.util.*; +import javax.swing.*; +import javax.swing.table.*; + +public class bug8005019 { + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + + @Override + public void run() { + testSelectionWithFilterTable(); + } + }); + } + + private static void testSelectionWithFilterTable() { + DefaultTableModel model = new DefaultTableModel(0, 1); + // a model with 3 elements is the minimum to demonstrate + // the bug + int last = 2; + for (int i = 0; i <= last; i++) { + model.addRow(new Object[]{i}); + } + JTable table = new JTable(model); + table.setAutoCreateRowSorter(true); + // set selection at the end + table.setRowSelectionInterval(last, last); + // exclude rows based on identifier + RowFilter filter = new GeneralFilter(new int[]{0}); + ((DefaultRowSorter) table.getRowSorter()).setRowFilter(filter); + // insertRow _before or at_ selected model index, such that + // endIndex (in event) > 1 + model.insertRow(2, new Object[]{"x"}); + } + + private static class GeneralFilter extends RowFilter { + + private int[] columns; + List excludes = Arrays.asList(0); + + GeneralFilter(int[] columns) { + this.columns = columns; + } + + public boolean include(RowFilter.Entry value) { + int count = value.getValueCount(); + if (columns.length > 0) { + for (int i = columns.length - 1; i >= 0; i--) { + int index = columns[i]; + if (index < count) { + if (include(value, index)) { + return true; + } + } + } + } else { + while (--count >= 0) { + if (include(value, count)) { + return true; + } + } + } + return false; + } + + protected boolean include( + Entry entry, + int index) { + return !excludes.contains(entry.getIdentifier()); + } + } +} diff --git a/test/sun/rmi/runtime/Log/4504153/Test4504153.java b/test/sun/rmi/runtime/Log/4504153/Test4504153.java index 090718083d763a5e84de028edd4aed70ce2bb537..946e9a9c0acc7dbc6c5085d5f0cee39516cc0456 100644 --- a/test/sun/rmi/runtime/Log/4504153/Test4504153.java +++ b/test/sun/rmi/runtime/Log/4504153/Test4504153.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,8 +48,7 @@ public class Test4504153 { ByteArrayOutputStream err = new ByteArrayOutputStream(); JavaVM vm = new JavaVM(StartRegistry.class.getName(), "-Dsun.rmi.transport.logLevel=v", "", out, err); - vm.start(); - vm.getVM().waitFor(); + vm.execute(); String errString = err.toString(); diff --git a/test/sun/rmi/runtime/Log/6409194/NoConsoleOutput.java b/test/sun/rmi/runtime/Log/6409194/NoConsoleOutput.java index a4104f2d268997fc3c39825a59f7a96f78ec532a..70505fab6f2d048865e7e1e07408642eb7b64027 100644 --- a/test/sun/rmi/runtime/Log/6409194/NoConsoleOutput.java +++ b/test/sun/rmi/runtime/Log/6409194/NoConsoleOutput.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,8 +65,7 @@ public class NoConsoleOutput { JavaVM vm = new JavaVM(DoRMIStuff.class.getName(), "-Djava.util.logging.config.file=" + loggingPropertiesFile, "", out, err); - vm.start(); - vm.getVM().waitFor(); + vm.execute(); /* * Verify that the subprocess had no System.out or System.err diff --git a/test/sun/rmi/transport/tcp/DeadCachedConnection.java b/test/sun/rmi/transport/tcp/DeadCachedConnection.java index 7bcd5a71024e50da1bdd9f8ac1583ed6d564c43e..ebc92f61ef1588084bebb2b3e04f3da2e4248b90 100644 --- a/test/sun/rmi/transport/tcp/DeadCachedConnection.java +++ b/test/sun/rmi/transport/tcp/DeadCachedConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -104,7 +104,7 @@ public class DeadCachedConnection { JavaVM jvm = new JavaVM("sun.rmi.registry.RegistryImpl", "", Integer.toString(p)); jvm.start(); - DeadCachedConnection.subreg = jvm.getVM(); + DeadCachedConnection.subreg = jvm; } catch (IOException e) { // one of these is summarily dropped, can't remember which one @@ -117,7 +117,7 @@ public class DeadCachedConnection { } catch (Exception whatever) { } } - private static Process subreg = null; + private static JavaVM subreg = null; public static void killRegistry() { if (DeadCachedConnection.subreg != null) { diff --git a/test/sun/security/krb5/ServiceCredsCombination.java b/test/sun/security/krb5/ServiceCredsCombination.java new file mode 100644 index 0000000000000000000000000000000000000000..3208560e788c6d00e5838f9b40f9a4618c946855 --- /dev/null +++ b/test/sun/security/krb5/ServiceCredsCombination.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +/* + * @test + * @bug 8005447 + * @compile -XDignore.symbol.file ServiceCredsCombination.java + * @run main ServiceCredsCombination + * @summary default principal can act as anyone + */ + +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.Objects; +import javax.security.auth.Subject; +import javax.security.auth.kerberos.KerberosKey; +import javax.security.auth.kerberos.KerberosPrincipal; +import javax.security.auth.kerberos.KeyTab; +import org.ietf.jgss.GSSCredential; +import org.ietf.jgss.GSSException; +import org.ietf.jgss.GSSManager; +import org.ietf.jgss.GSSName; +import sun.security.jgss.GSSUtil; + +public class ServiceCredsCombination { + + public static void main(String[] args) throws Exception { + // pass + check("a", "a", princ("a"), key("a")); + check(null, "a", princ("a"), key("a")); + check("x", "NOCRED", princ("a"), key("a")); + // two pass + check("a", "a", princ("a"), key("a"), princ("b"), key("b")); + check("b", "b", princ("a"), key("a"), princ("b"), key("b")); + check(null, null, princ("a"), key("a"), princ("b"), key("b")); + check("x", "NOCRED", princ("a"), key("a"), princ("b"), key("b")); + // old ktab + check("b", "b", princ("b"), oldktab()); + check("x", "NOCRED", princ("b"), oldktab()); + check(null, "b", princ("b"), oldktab()); + // Two old ktab + check("a", "a", princ("a"), princ("b"), oldktab(), oldktab()); + check("b", "b", princ("a"), princ("b"), oldktab(), oldktab()); + check(null, null, princ("a"), princ("b"), oldktab(), oldktab()); + check("x", "NOCRED", princ("a"), princ("b"), oldktab(), oldktab()); + // pass + old ktab + check("a", "a", princ("a"), princ("b"), key("a"), oldktab()); + check("b", "b", princ("a"), princ("b"), key("a"), oldktab()); + check(null, null, princ("a"), princ("b"), key("a"), oldktab()); + check("x", "NOCRED", princ("a"), princ("b"), key("a"), oldktab()); + // Compatibility, automatically add princ for keys + check(null, "a", key("a")); + check("x", "NOCRED", key("a")); + check(null, "a", key("a"), oldktab()); + check("x", "NOCRED", key("a"), oldktab()); + // Limitation, "a" has no key, but we don't know oldktab() is for "b" + check("a", "a", princ("a"), princ("b"), oldktab()); + } + + /** + * Checks the correct bound + * @param a get a creds for this principal, null for default one + * @param b expected name, null for still unbound, "NOCRED" for no creds + * @param objs princs, keys and keytabs in the subject + */ + private static void check(final String a, String b, Object... objs) + throws Exception { + Subject subj = new Subject(); + for (Object obj: objs) { + if (obj instanceof KerberosPrincipal) { + subj.getPrincipals().add((KerberosPrincipal)obj); + } else if (obj instanceof KerberosKey || obj instanceof KeyTab) { + subj.getPrivateCredentials().add(obj); + } + } + final GSSManager man = GSSManager.getInstance(); + try { + String result = Subject.doAs( + subj, new PrivilegedExceptionAction() { + @Override + public String run() throws GSSException { + GSSCredential cred = man.createCredential( + a == null ? null : man.createName(r(a), null), + GSSCredential.INDEFINITE_LIFETIME, + GSSUtil.GSS_KRB5_MECH_OID, + GSSCredential.ACCEPT_ONLY); + GSSName name = cred.getName(); + return name == null ? null : name.toString(); + } + }); + if (!Objects.equals(result, r(b))) { + throw new Exception("Check failed: getInstance(" + a + + ") has name " + result + ", not " + b); + } + } catch (PrivilegedActionException e) { + if (!"NOCRED".equals(b)) { + throw new Exception("Check failed: getInstance(" + a + + ") is null " + ", but not one with name " + b); + } + } + } + private static String r(String s) { + return s == null ? null : (s+"@REALM"); + } + private static KerberosPrincipal princ(String s) { + return new KerberosPrincipal(r(s)); + } + private static KerberosKey key(String s) { + return new KerberosKey(princ(s), new byte[0], 0, 0); + } + private static KeyTab oldktab() { + return KeyTab.getInstance(); + } +} diff --git a/test/sun/security/krb5/auto/AcceptPermissions.java b/test/sun/security/krb5/auto/AcceptPermissions.java new file mode 100644 index 0000000000000000000000000000000000000000..3a6d422842fa2de7671340cf339e0a0bad9773ad --- /dev/null +++ b/test/sun/security/krb5/auto/AcceptPermissions.java @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 9999999 + * @summary default principal can act as anyone + * @compile -XDignore.symbol.file AcceptPermissions.java + * @run main/othervm AcceptPermissions + */ + +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.security.Permission; +import javax.security.auth.kerberos.ServicePermission; +import sun.security.jgss.GSSUtil; +import java.util.*; + +public class AcceptPermissions extends SecurityManager { + + private static Map perms = new HashMap<>(); + @Override + public void checkPermission(Permission perm) { + if (!(perm instanceof ServicePermission)) { + return; + } + ServicePermission sp = (ServicePermission)perm; + if (!sp.getActions().equals("accept")) { + return; + } + // We only care about accept ServicePermission in this test + try { + super.checkPermission(sp); + } catch (SecurityException se) { + if (perms.containsKey(sp)) { + perms.put(sp, "checked"); + } else { + throw se; // We didn't expect this is needed + } + } + } + + // Fills in permissions we are expecting + private static void initPerms(String... names) { + perms.clear(); + for (String name: names) { + perms.put(new ServicePermission( + name + "@" + OneKDC.REALM, "accept"), "expected"); + } + } + + // Checks if they are all checked + private static void checkPerms() { + for (Map.Entry entry: perms.entrySet()) { + if (entry.getValue().equals("expected")) { + throw new RuntimeException( + "Expected but not used: " + entry.getKey()); + } + } + } + + public static void main(String[] args) throws Exception { + System.setSecurityManager(new AcceptPermissions()); + new OneKDC(null).writeJAASConf(); + String two = "two {\n" + + " com.sun.security.auth.module.Krb5LoginModule required" + + " principal=\"" + OneKDC.SERVER + "\" useKeyTab=true" + + " isInitiator=false storeKey=true;\n" + + " com.sun.security.auth.module.Krb5LoginModule required" + + " principal=\"" + OneKDC.BACKEND + "\" useKeyTab=true" + + " isInitiator=false storeKey=true;\n" + + "};\n"; + Files.write(Paths.get(OneKDC.JAAS_CONF), two.getBytes(), + StandardOpenOption.APPEND); + + Context c, s; + + // In all cases, a ServicePermission on the acceptor name is needed + // for a handshake. For default principal with no predictable name, + // permission not needed (yet) for credentials creation. + + // Named principal + initPerms(OneKDC.SERVER); + c = Context.fromJAAS("client"); + s = Context.fromJAAS("server"); + c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID); + s.startAsServer(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID); + checkPerms(); + initPerms(OneKDC.SERVER); + Context.handshake(c, s); + checkPerms(); + + // Named principal (even if there are 2 JAAS modules) + initPerms(OneKDC.SERVER); + c = Context.fromJAAS("client"); + s = Context.fromJAAS("two"); + c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID); + s.startAsServer(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID); + checkPerms(); + initPerms(OneKDC.SERVER); + Context.handshake(c, s); + checkPerms(); + + // Default principal with a predictable name + initPerms(OneKDC.SERVER); + c = Context.fromJAAS("client"); + s = Context.fromJAAS("server"); + c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID); + s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); + checkPerms(); + initPerms(OneKDC.SERVER); + Context.handshake(c, s); + checkPerms(); + + // Default principal with no predictable name + initPerms(); // permission not needed for cred !!! + c = Context.fromJAAS("client"); + s = Context.fromJAAS("two"); + c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID); + s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); + checkPerms(); + initPerms(OneKDC.SERVER); // still needed for handshake !!! + Context.handshake(c, s); + checkPerms(); + } +} diff --git a/test/sun/security/krb5/auto/CleanState.java b/test/sun/security/krb5/auto/CleanState.java index fbd8785cbab2f7a07fb986a1e3fc2f2c3e9be694..d87325456e610c99900610c8497075f60e805c1e 100644 --- a/test/sun/security/krb5/auto/CleanState.java +++ b/test/sun/security/krb5/auto/CleanState.java @@ -24,6 +24,7 @@ /* * @test * @bug 6716534 + * @compile -XDignore.symbol.file CleanState.java * @run main/othervm CleanState * @summary Krb5LoginModule has not cleaned temp info between authentication attempts */ diff --git a/test/sun/security/krb5/auto/Context.java b/test/sun/security/krb5/auto/Context.java index 7eef77c61c83fe348c0137e0d4bbf9d3be037de1..aae14f46bd3a00b8c5d9b7fbc8dc308f90849795 100644 --- a/test/sun/security/krb5/auto/Context.java +++ b/test/sun/security/krb5/auto/Context.java @@ -131,21 +131,24 @@ public class Context { return out; } + /** + * Logins with username/password as a new Subject + */ public static Context fromUserPass( String user, char[] pass, boolean storeKey) throws Exception { - return fromUserPass(null, user, pass, storeKey); + return fromUserPass(new Subject(), user, pass, storeKey); } /** - * Logins with a username and a password, using Krb5LoginModule directly - * @param s existing subject, test multiple princ & creds for single subj - * @param storeKey true if key should be saved, used on acceptor side + * Logins with username/password as an existing Subject. The + * same subject can be used multiple times to simulate multiple logins. + * @param s existing subject */ public static Context fromUserPass(Subject s, String user, char[] pass, boolean storeKey) throws Exception { Context out = new Context(); out.name = user; - out.s = s == null ? new Subject() : s; + out.s = s; Krb5LoginModule krb5 = new Krb5LoginModule(); Map map = new HashMap<>(); Map shared = new HashMap<>(); @@ -172,14 +175,23 @@ public class Context { } /** - * Logins with a username and a keytab, using Krb5LoginModule directly - * @param storeKey true if key should be saved, used on acceptor side + * Logins with username/keytab as an existing Subject. The + * same subject can be used multiple times to simulate multiple logins. + * @param s existing subject */ - public static Context fromUserKtab(String user, String ktab, boolean storeKey) - throws Exception { + public static Context fromUserKtab( + String user, String ktab, boolean storeKey) throws Exception { + return fromUserKtab(new Subject(), user, ktab, storeKey); + } + + /** + * Logins with username/keytab as a new subject, + */ + public static Context fromUserKtab(Subject s, + String user, String ktab, boolean storeKey) throws Exception { Context out = new Context(); out.name = user; - out.s = new Subject(); + out.s = s; Krb5LoginModule krb5 = new Krb5LoginModule(); Map map = new HashMap<>(); diff --git a/test/sun/security/krb5/auto/DiffNameSameKey.java b/test/sun/security/krb5/auto/DiffNameSameKey.java new file mode 100644 index 0000000000000000000000000000000000000000..92c487839c0f6d9c7dccda98ba3c3c64cc63a131 --- /dev/null +++ b/test/sun/security/krb5/auto/DiffNameSameKey.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8005447 + * @summary default principal can act as anyone + * @compile -XDignore.symbol.file DiffNameSameKey.java + * @run main/othervm/fail DiffNameSameKey a + * @run main/othervm DiffNameSameKey b + */ + +import sun.security.jgss.GSSUtil; +import sun.security.krb5.PrincipalName; + +/** + * This test confirms the compatibility codes described in + * ServiceCreds.getEKeys(). If the acceptor starts as x.us.oracle.com + * but client requests for x.us, as long as the KDC supports both names + * and the keys are the same, the auth should succeed. + */ +public class DiffNameSameKey { + + static final String SERVER2 = "x" + OneKDC.SERVER; + + public static void main(String[] args) throws Exception { + + OneKDC kdc = new KDC2(); + kdc.addPrincipal(SERVER2, "samepass".toCharArray()); + kdc.addPrincipal(OneKDC.SERVER, "samepass".toCharArray()); + kdc.writeJAASConf(); + kdc.writeKtab(OneKDC.KTAB); + + Context c, s; + c = Context.fromJAAS("client"); + s = Context.fromJAAS("server"); + + switch (args[0]) { + case "a": // If server starts as another service, should fail + c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_SPNEGO_MECH_OID); + s.startAsServer(SERVER2.replace('/', '@'), + GSSUtil.GSS_SPNEGO_MECH_OID); + break; + case "b": // If client requests another server with the same keys, + // succeed to be compatible + c.startAsClient(SERVER2, GSSUtil.GSS_SPNEGO_MECH_OID); + s.startAsServer(OneKDC.SERVER.replace('/', '@'), + GSSUtil.GSS_SPNEGO_MECH_OID); + break; + } + + Context.handshake(c, s); + + s.dispose(); + c.dispose(); + } + + /** + * This KDC returns the same salt for all principals. This means same + * passwords generate same keys. + */ + static class KDC2 extends OneKDC { + KDC2() throws Exception { + super(null); + } + @Override + public String getSalt(PrincipalName pn) { + return "SAME"; + } + } +} diff --git a/test/sun/security/krb5/auto/DynamicKeytab.java b/test/sun/security/krb5/auto/DynamicKeytab.java index 6525b8fb49f314b0ef7a1be1a3f481139a870b3b..9c48fe44332be44f31eb5723d4b43592f86898b1 100644 --- a/test/sun/security/krb5/auto/DynamicKeytab.java +++ b/test/sun/security/krb5/auto/DynamicKeytab.java @@ -24,6 +24,7 @@ /* * @test * @bug 6894072 + * @compile -XDignore.symbol.file DynamicKeytab.java * @run main/othervm DynamicKeytab * @summary always refresh keytab */ diff --git a/test/sun/security/krb5/auto/KDC.java b/test/sun/security/krb5/auto/KDC.java index 409f3131fb80249cc096a7da2ad3f80889423b88..83cafe73f8f313b9ecb1de6d772b195cd77781cc 100644 --- a/test/sun/security/krb5/auto/KDC.java +++ b/test/sun/security/krb5/auto/KDC.java @@ -285,10 +285,12 @@ public class KDC { if (Character.isDigit(pass[pass.length-1])) { kvno = pass[pass.length-1] - '0'; } - ktab.addEntry(new PrincipalName(name, - name.indexOf('/') < 0 ? - PrincipalName.KRB_NT_UNKNOWN : - PrincipalName.KRB_NT_SRV_HST), + PrincipalName pn = new PrincipalName(name, + name.indexOf('/') < 0 ? + PrincipalName.KRB_NT_UNKNOWN : + PrincipalName.KRB_NT_SRV_HST); + ktab.addEntry(pn, + getSalt(pn), pass, kvno, true); @@ -534,7 +536,7 @@ public class KDC { if (pass == null) { throw new KrbException(server? Krb5.KDC_ERR_S_PRINCIPAL_UNKNOWN: - Krb5.KDC_ERR_C_PRINCIPAL_UNKNOWN); + Krb5.KDC_ERR_C_PRINCIPAL_UNKNOWN, pn.toString()); } return pass; } @@ -544,7 +546,7 @@ public class KDC { * @param p principal * @return the salt */ - private String getSalt(PrincipalName p) { + protected String getSalt(PrincipalName p) { String pn = p.toString(); if (p.getRealmString() == null) { pn = pn + "@" + getRealm(); diff --git a/test/sun/security/krb5/auto/KeyTabCompat.java b/test/sun/security/krb5/auto/KeyTabCompat.java index 87a3e7e9c787a5032bebfff55bd0fb40e80b1c6a..ebc1c75c7e478cd1345bfd3316efcaced7acc382 100644 --- a/test/sun/security/krb5/auto/KeyTabCompat.java +++ b/test/sun/security/krb5/auto/KeyTabCompat.java @@ -38,7 +38,7 @@ import sun.security.jgss.GSSUtil; * * 1. If there is only KerberosKeys in private credential set and no * KerberosPrincipal. JAAS login should go on. - * 2. Even if KeyTab is used, user can still get KerberosKeys from + * 2. If KeyTab is used, user won't get KerberosKeys from * private credentials set. */ public class KeyTabCompat { diff --git a/test/sun/security/krb5/auto/TwoOrThree.java b/test/sun/security/krb5/auto/TwoOrThree.java new file mode 100644 index 0000000000000000000000000000000000000000..77f5e21b440ebfd0ba78698076e1f3691347b55c --- /dev/null +++ b/test/sun/security/krb5/auto/TwoOrThree.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8005447 + * @summary default principal can act as anyone + * @compile -XDignore.symbol.file TwoOrThree.java + * @run main/othervm TwoOrThree first first + * @run main/othervm/fail TwoOrThree first second + * @run main/othervm TwoOrThree - first + * @run main/othervm TwoOrThree - second + * @run main/othervm/fail TwoOrThree - third + */ + +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import javax.security.auth.Subject; +import sun.security.jgss.GSSUtil; + +/* + * The JAAS login has two krb5 modules + * 1. principal is A + * 2. principal is B + * A named principal can only accept itself. The default principal can accept + * either, but not any other service even if the keytab also include its keys. + */ +public class TwoOrThree { + + public static void main(String[] args) throws Exception { + + String server = args[0].equals("-") ? null : args[0]; + String target = args[1]; + OneKDC kdc = new OneKDC(null); + kdc.addPrincipal("first", "first".toCharArray()); + kdc.addPrincipal("second", "second".toCharArray()); + kdc.addPrincipal("third", "third".toCharArray()); + kdc.writeKtab(OneKDC.KTAB); + + Context c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false); + + // Using keytabs + Subject sub4s = new Subject(); + Context.fromUserKtab(sub4s, "first", OneKDC.KTAB, true); + Context s = Context.fromUserKtab(sub4s, "second", OneKDC.KTAB, true); + c.startAsClient(target, GSSUtil.GSS_KRB5_MECH_OID); + s.startAsServer(server, GSSUtil.GSS_KRB5_MECH_OID); + Context.handshake(c, s); + + // Using keys + sub4s = new Subject(); + Context.fromUserPass(sub4s, "first", "first".toCharArray(), true); + s = Context.fromUserPass(sub4s, "second", "second".toCharArray(), true); + c.startAsClient(target, GSSUtil.GSS_KRB5_MECH_OID); + s.startAsServer(server, GSSUtil.GSS_KRB5_MECH_OID); + Context.handshake(c, s); + + s.dispose(); + c.dispose(); + } +} diff --git a/test/sun/security/provider/PolicyFile/Comparator.java b/test/sun/security/provider/PolicyFile/Comparator.java index 5f65d46416441dbe5ae9855b4ffffced283f0d7a..231d06f197e2dd83a327d86a5b18828e04946ee6 100644 --- a/test/sun/security/provider/PolicyFile/Comparator.java +++ b/test/sun/security/provider/PolicyFile/Comparator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,7 +39,6 @@ import javax.security.auth.Subject; import javax.security.auth.x500.X500Principal; import sun.security.provider.PolicyFile; -import com.sun.security.auth.PrincipalComparator; import com.sun.security.auth.UnixPrincipal; import com.sun.security.auth.NTUserPrincipal; import com.sun.security.auth.SolarisPrincipal; @@ -90,7 +89,7 @@ public class Comparator { private static final Principal[] badP = new Principal[] { new SolarisPrincipal("bad") }; - public static class PCompare1 implements PrincipalComparator { + public static class PCompare1 implements Principal { private String name; @@ -98,6 +97,12 @@ public class Comparator { this.name = name; } + @Override + public String getName() { + return name; + } + + @Override public boolean implies (Subject subject) { if (subject.getPrincipals().contains(p1[0])) { return true; @@ -106,13 +111,19 @@ public class Comparator { } } - public static class PCompare2 implements PrincipalComparator { + public static class PCompare2 implements Principal { private String name; public PCompare2(String name) { this.name = name; } + @Override + public String getName() { + return name; + } + + @Override public boolean implies (Subject subject) { if (subject.getPrincipals().contains(p2[0]) && subject.getPrincipals().contains(p2[1])) { @@ -122,13 +133,19 @@ public class Comparator { } } - public static class PCompare3 implements PrincipalComparator { + public static class PCompare3 implements Principal { private String name; public PCompare3(String name) { this.name = name; } + @Override + public String getName() { + return name; + } + + @Override public boolean implies (Subject subject) { return false; } diff --git a/test/tools/launcher/FXLauncherTest.java b/test/tools/launcher/FXLauncherTest.java index 9b58c0846c0a8ce57b3666dfc27ec27c46f9ead5..1ed251bad193d7c75daaef1f2507d72decd77823 100644 --- a/test/tools/launcher/FXLauncherTest.java +++ b/test/tools/launcher/FXLauncherTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8001533 + * @bug 8001533 8004547 * @summary Test launching FX application with java -jar * Test uses main method and blank main method, a jfx app class and an incorrest * jfx app class, a main-class for the manifest, a bogus one and none. @@ -47,6 +47,8 @@ public class FXLauncherTest extends TestHelper { /* standard main class can be used as java main for fx app class */ static final String StdMainClass = "helloworld.HelloWorld"; + static final String ExtMainClass = "helloworld.ExtHello"; + static final String NonFXMainClass = "helloworld.HelloJava"; static int testcount = 0; /* a main method and a blank. */ @@ -107,9 +109,7 @@ public class FXLauncherTest extends TestHelper { } /* - * Create class to extend fx java file for test application - * TODO: make test to create java file and this extension of the java file - * and jar them together an run app via this java class. + * Create class that extends HelloWorld instead of Application */ static void createExtJavaFile(String mainmethod) { try { @@ -125,16 +125,48 @@ public class FXLauncherTest extends TestHelper { compile("-cp", ".", "-d", ".", mainClass + JAVA_FILE_EXT); } catch (java.io.IOException ioe) { ioe.printStackTrace(); - throw new RuntimeException("Failed creating HelloWorld."); + throw new RuntimeException("Failed creating ExtHello."); + } + } + + /* + * Create non-JavaFX class for testing if jfxrt.jar is being loaded + * when it shouldn't be + */ + static void createNonFXJavaFile() { + try { + String mainClass = "HelloJava"; + List contents = new ArrayList<>(); + contents.add("package helloworld;"); + contents.add("public class HelloJava {"); + contents.add(" public static void main(String[] args) {"); + contents.add(" for(String aa : args)"); + contents.add(" System.out.println(\"arg: \" + aa);" ); + contents.add(" }"); + contents.add("}"); + // Create and compile java source. + MainJavaFile = new File(mainClass + JAVA_FILE_EXT); + createFile(MainJavaFile, contents); + compile("-cp", ".", "-d", ".", mainClass + JAVA_FILE_EXT); + } catch (java.io.IOException ioe) { + ioe.printStackTrace(); + throw new RuntimeException("Failed creating HelloJava."); } } // Create manifest for test fx application - static List createManifestContents(String mainclassentry) { + static List createManifestContents(String mainClassEntry, String fxMainEntry) { List mcontents = new ArrayList<>(); mcontents.add("Manifest-Version: 1.0"); mcontents.add("Created-By: FXLauncherTest"); - mcontents.add("Main-Class: " + mainclassentry); + if (mainClassEntry != null) { + mcontents.add("Main-Class: " + mainClassEntry); + System.out.println("Main-Class: " + mainClassEntry); + } + if (fxMainEntry != null) { + mcontents.add("JavaFX-Application-Class: " + fxMainEntry); + System.out.println("JavaFX-Application-Class: " + fxMainEntry); + } return mcontents; } @@ -175,31 +207,41 @@ public class FXLauncherTest extends TestHelper { /* * Set Main-Class and iterate main_methods. - * Try launching with both -jar and -cp methods. + * Try launching with both -jar and -cp methods, with and without FX main + * class manifest entry. * All cases should run. + * + * See sun.launcher.LauncherHelper$FXHelper for more details on how JavaFX + * applications are launched. */ @Test static void testBasicFXApp() throws Exception { - testBasicFXApp(true); - testBasicFXApp(false); + testBasicFXApp(true, false); // -cp, no JAC + testBasicFXApp(false, true); // -jar, with JAC + testBasicFXApp(false, false); // -jar, no JAC } - static void testBasicFXApp(boolean useCP) throws Exception { + static void testBasicFXApp(boolean useCP, boolean setFXMainClass) throws Exception { String testname = "testBasicFXApp"; + if (useCP) { + testname = testname.concat("_useCP"); + } + String fxMC = StdMainClass; + if (!setFXMainClass) { + testname = testname.concat("_noJAC"); + fxMC = null; + } for (String mm : MAIN_METHODS) { testcount++; line(); - System.out.println("test# " + testcount + - "- Main method: " + mm + - "; MF main class: " + StdMainClass); + System.out.println("test# " + testcount + "- Main method: " + mm); createJavaFile(mm); - createFile(ManifestFile, createManifestContents(StdMainClass)); + createFile(ManifestFile, createManifestContents(StdMainClass, fxMC)); createJar(FXtestJar, ManifestFile); String sTestJar = FXtestJar.getAbsolutePath(); TestResult tr; if (useCP) { tr = doExec(javaCmd, "-cp", sTestJar, StdMainClass, APP_PARMS[0], APP_PARMS[1]); - testname = testname.concat("_useCP"); } else { tr = doExec(javaCmd, "-jar", sTestJar, APP_PARMS[0], APP_PARMS[1]); } @@ -224,26 +266,33 @@ public class FXLauncherTest extends TestHelper { */ @Test static void testExtendFXApp() throws Exception { - testExtendFXApp(true); - testExtendFXApp(false); + testExtendFXApp(true, false); // -cp, no JAC + testExtendFXApp(false, true); // -jar, with JAC + testExtendFXApp(false, false); // -jar, no JAC } - static void testExtendFXApp(boolean useCP) throws Exception { + static void testExtendFXApp(boolean useCP, boolean setFXMainClass) throws Exception { String testname = "testExtendFXApp"; + if (useCP) { + testname = testname.concat("_useCP"); + } + String fxMC = ExtMainClass; + if (!setFXMainClass) { + testname = testname.concat("_noJAC"); + fxMC = null; + } for (String mm : MAIN_METHODS) { testcount++; line(); - System.out.println("test# " + testcount + - "- Main method: " + mm + "; MF main class: " + StdMainClass); + System.out.println("test# " + testcount + "- Main method: " + mm); createJavaFile(mm); createExtJavaFile(mm); - createFile(ManifestFile, createManifestContents(StdMainClass)); + createFile(ManifestFile, createManifestContents(ExtMainClass, fxMC)); createJar(FXtestJar, ManifestFile); String sTestJar = FXtestJar.getAbsolutePath(); TestResult tr; if (useCP) { - tr = doExec(javaCmd, "-cp", sTestJar, StdMainClass, APP_PARMS[0], APP_PARMS[1]); - testname = testname.concat("_useCP"); + tr = doExec(javaCmd, "-cp", sTestJar, ExtMainClass, APP_PARMS[0], APP_PARMS[1]); } else { tr = doExec(javaCmd, "-jar", sTestJar, APP_PARMS[0], APP_PARMS[1]); } @@ -256,27 +305,82 @@ public class FXLauncherTest extends TestHelper { } } } - checkStatus(tr, testname, testcount, StdMainClass); + checkStatus(tr, testname, testcount, ExtMainClass); + } + } + + /* + * Ensure we can NOT launch a FX app jar with no Main-Class manifest entry + */ + @Test + static void testMissingMC() throws Exception { + String testname = "testMissingMC"; + testcount++; + line(); + System.out.println("test# " + testcount + ": abort on missing Main-Class"); + createJavaFile(" "); // no main() needed + createFile(ManifestFile, createManifestContents(null, StdMainClass)); // No MC, but supply JAC + createJar(FXtestJar, ManifestFile); + String sTestJar = FXtestJar.getAbsolutePath(); + TestResult tr = doExec(javaCmd, "-jar", sTestJar, APP_PARMS[0], APP_PARMS[1]); + tr.checkNegative(); // should abort if no Main-Class + if (tr.testStatus) { + if (!tr.contains("no main manifest attribute")) { + System.err.println("ERROR: launcher did not abort properly"); + } + } else { + System.err.println("ERROR: jar executed with no Main-Class!"); } + checkStatus(tr, testname, testcount, StdMainClass); } /* * test to ensure that we don't load any extraneous fx jars when * launching a standard java application + * Test both -cp and -jar methods since they use different code paths. + * Neither case should cause jfxrt.jar to be loaded. */ @Test - static void testExtraneousJars()throws Exception { + static void testExtraneousJars() throws Exception { + testExtraneousJars(true); + testExtraneousJars(false); + } + + static void testExtraneousJars(boolean useCP) throws Exception { String testname = "testExtraneousJars"; + if (useCP) { + testname = testname.concat("_useCP"); + } testcount++; line(); - System.out.println("test# " + testcount); - TestResult tr = doExec(javacCmd, "-J-verbose:class", "-version"); - if (!tr.notContains("jfxrt.jar")) { - System.out.println("testing for extraneous jfxrt jar"); - System.out.println(tr); - throw new Exception("jfxrt.jar is being loaded by javac!!!"); + System.out.println("test# " + testcount + + ": test for erroneous jfxrt.jar loading"); + createNonFXJavaFile(); + createFile(ManifestFile, createManifestContents(NonFXMainClass, null)); + createJar(FXtestJar, ManifestFile); + String sTestJar = FXtestJar.getAbsolutePath(); + TestResult tr; + + if (useCP) { + tr = doExec(javaCmd, "-verbose:class", "-cp", sTestJar, NonFXMainClass, APP_PARMS[0], APP_PARMS[1]); + } else { + tr = doExec(javaCmd, "-verbose:class", "-jar", sTestJar, APP_PARMS[0], APP_PARMS[1]); } - checkStatus(tr, testname, testcount, StdMainClass); + tr.checkPositive(); + if (tr.testStatus) { + if (!tr.notContains("jfxrt.jar")) { + System.out.println("testing for extraneous jfxrt jar"); + System.out.println(tr); + throw new Exception("jfxrt.jar is being loaded, it should not be!"); + } + for (String p : APP_PARMS) { + if (!tr.contains(p)) { + System.err.println("ERROR: Did not find " + + p + " in output!"); + } + } + } + checkStatus(tr, testname, testcount, NonFXMainClass); } public static void main(String... args) throws Exception { diff --git a/test/tools/launcher/VersionCheck.java b/test/tools/launcher/VersionCheck.java index d801821418122eab2349b5427a5888145fab18ba..c30ef4240113924e8e8280c4e57e5c0ab4f25398 100644 --- a/test/tools/launcher/VersionCheck.java +++ b/test/tools/launcher/VersionCheck.java @@ -68,6 +68,7 @@ public class VersionCheck extends TestHelper { "jcmd", "jconsole", "jcontrol", + "jdeps", "jinfo", "jmap", "jps",