8011680: Re-integrate AEAD implementation of JSSE
It is a re-merge of JDK-7030966. Reviewed-by: wetmore
This commit is contained in:
parent
d0e1727ce6
commit
a973a4d533
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 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
|
||||
@ -165,6 +165,7 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi {
|
||||
// partition keyblock into individual secrets
|
||||
|
||||
int ofs = 0;
|
||||
if (macLength != 0) {
|
||||
byte[] tmp = new byte[macLength];
|
||||
|
||||
// mac keys
|
||||
@ -175,6 +176,7 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi {
|
||||
System.arraycopy(keyBlock, ofs, tmp, 0, macLength);
|
||||
ofs += macLength;
|
||||
serverMacKey = new SecretKeySpec(tmp, "Mac");
|
||||
}
|
||||
|
||||
if (keyLength == 0) { // SSL_RSA_WITH_NULL_* ciphersuites
|
||||
return new TlsKeyMaterialSpec(clientMacKey, serverMacKey);
|
||||
@ -198,7 +200,7 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi {
|
||||
|
||||
// IV keys if needed.
|
||||
if (ivLength != 0) {
|
||||
tmp = new byte[ivLength];
|
||||
byte[] tmp = new byte[ivLength];
|
||||
|
||||
System.arraycopy(keyBlock, ofs, tmp, 0, ivLength);
|
||||
ofs += ivLength;
|
||||
@ -220,8 +222,8 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi {
|
||||
// TLS 1.0
|
||||
byte[] seed = concat(clientRandom, serverRandom);
|
||||
|
||||
tmp = doTLS10PRF(clientKeyBytes, LABEL_CLIENT_WRITE_KEY, seed,
|
||||
expandedKeyLength, md5, sha);
|
||||
byte[] tmp = doTLS10PRF(clientKeyBytes,
|
||||
LABEL_CLIENT_WRITE_KEY, seed, expandedKeyLength, md5, sha);
|
||||
clientCipherKey = new SecretKeySpec(tmp, alg);
|
||||
|
||||
tmp = doTLS10PRF(serverKeyBytes, LABEL_SERVER_WRITE_KEY, seed,
|
||||
@ -239,7 +241,7 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi {
|
||||
}
|
||||
} else {
|
||||
// SSLv3
|
||||
tmp = new byte[expandedKeyLength];
|
||||
byte[] tmp = new byte[expandedKeyLength];
|
||||
|
||||
md5.update(clientKeyBytes);
|
||||
md5.update(clientRandom);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 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
|
||||
@ -212,12 +212,6 @@ public class TlsKeyMaterialParameterSpec implements AlgorithmParameterSpec {
|
||||
* generated.
|
||||
*/
|
||||
public int getIvLength() {
|
||||
// TLS v1.1 or later uses an explicit IV to protect against
|
||||
// the CBC attacks.
|
||||
if (majorVersion >= 0x03 && minorVersion >= 0x02) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ivLength;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 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
|
||||
@ -58,9 +58,8 @@ public class TlsKeyMaterialSpec implements KeySpec, SecretKey {
|
||||
* <code>new TlsKeymaterialSpec(clientMacKey, serverMacKey,
|
||||
* null, null, null, null)</code>.
|
||||
*
|
||||
* @param clientMacKey the client MAC key
|
||||
* @param serverMacKey the server MAC key
|
||||
* @throws NullPointerException if clientMacKey or serverMacKey is null
|
||||
* @param clientMacKey the client MAC key (or null)
|
||||
* @param serverMacKey the server MAC key (or null)
|
||||
*/
|
||||
public TlsKeyMaterialSpec(SecretKey clientMacKey, SecretKey serverMacKey) {
|
||||
this(clientMacKey, serverMacKey, null, null, null, null);
|
||||
@ -73,11 +72,10 @@ public class TlsKeyMaterialSpec implements KeySpec, SecretKey {
|
||||
* <code>new TlsKeymaterialSpec(clientMacKey, serverMacKey,
|
||||
* clientCipherKey, serverCipherKey, null, null)</code>.
|
||||
*
|
||||
* @param clientMacKey the client MAC key
|
||||
* @param serverMacKey the server MAC key
|
||||
* @param clientMacKey the client MAC key (or null)
|
||||
* @param serverMacKey the server MAC key (or null)
|
||||
* @param clientCipherKey the client cipher key (or null)
|
||||
* @param serverCipherKey the server cipher key (or null)
|
||||
* @throws NullPointerException if clientMacKey or serverMacKey is null
|
||||
*/
|
||||
public TlsKeyMaterialSpec(SecretKey clientMacKey, SecretKey serverMacKey,
|
||||
SecretKey clientCipherKey, SecretKey serverCipherKey) {
|
||||
@ -90,21 +88,17 @@ public class TlsKeyMaterialSpec implements KeySpec, SecretKey {
|
||||
* keys, client and server cipher keys, and client and server
|
||||
* initialization vectors.
|
||||
*
|
||||
* @param clientMacKey the client MAC key
|
||||
* @param serverMacKey the server MAC key
|
||||
* @param clientMacKey the client MAC key (or null)
|
||||
* @param serverMacKey the server MAC key (or null)
|
||||
* @param clientCipherKey the client cipher key (or null)
|
||||
* @param clientIv the client initialization vector (or null)
|
||||
* @param serverCipherKey the server cipher key (or null)
|
||||
* @param serverIv the server initialization vector (or null)
|
||||
*
|
||||
* @throws NullPointerException if clientMacKey or serverMacKey is null
|
||||
*/
|
||||
public TlsKeyMaterialSpec(SecretKey clientMacKey, SecretKey serverMacKey,
|
||||
SecretKey clientCipherKey, IvParameterSpec clientIv,
|
||||
SecretKey serverCipherKey, IvParameterSpec serverIv) {
|
||||
if ((clientMacKey == null) || (serverMacKey == null)) {
|
||||
throw new NullPointerException("MAC keys must not be null");
|
||||
}
|
||||
|
||||
this.clientMacKey = clientMacKey;
|
||||
this.serverMacKey = serverMacKey;
|
||||
this.clientCipherKey = clientCipherKey;
|
||||
@ -143,7 +137,7 @@ public class TlsKeyMaterialSpec implements KeySpec, SecretKey {
|
||||
/**
|
||||
* Returns the client MAC key.
|
||||
*
|
||||
* @return the client MAC key.
|
||||
* @return the client MAC key (or null).
|
||||
*/
|
||||
public SecretKey getClientMacKey() {
|
||||
return clientMacKey;
|
||||
@ -152,7 +146,7 @@ public class TlsKeyMaterialSpec implements KeySpec, SecretKey {
|
||||
/**
|
||||
* Return the server MAC key.
|
||||
*
|
||||
* @return the server MAC key.
|
||||
* @return the server MAC key (or null).
|
||||
*/
|
||||
public SecretKey getServerMacKey() {
|
||||
return serverMacKey;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 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,10 +168,22 @@ public final class P11TlsKeyMaterialGenerator extends KeyGeneratorSpi {
|
||||
// Note that the MAC keys do not inherit all attributes from the
|
||||
// template, but they do inherit the sensitive/extractable/token
|
||||
// flags, which is all P11Key cares about.
|
||||
SecretKey clientMacKey = P11Key.secretKey
|
||||
SecretKey clientMacKey, serverMacKey;
|
||||
|
||||
// The MAC size may be zero for GCM mode.
|
||||
//
|
||||
// PKCS11 does not support GCM mode as the author made the comment,
|
||||
// so the macBits is unlikely to be zero. It's only a place holder.
|
||||
if (macBits != 0) {
|
||||
clientMacKey = P11Key.secretKey
|
||||
(session, out.hClientMacSecret, "MAC", macBits, attributes);
|
||||
SecretKey serverMacKey = P11Key.secretKey
|
||||
serverMacKey = P11Key.secretKey
|
||||
(session, out.hServerMacSecret, "MAC", macBits, attributes);
|
||||
} else {
|
||||
clientMacKey = null;
|
||||
serverMacKey = null;
|
||||
}
|
||||
|
||||
SecretKey clientCipherKey, serverCipherKey;
|
||||
if (keyBits != 0) {
|
||||
clientCipherKey = P11Key.secretKey(session, out.hClientKey,
|
||||
|
161
jdk/src/share/classes/sun/security/ssl/Authenticator.java
Normal file
161
jdk/src/share/classes/sun/security/ssl/Authenticator.java
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* 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
|
||||
* 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 sun.security.ssl;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* This class represents an SSL/TLS message authentication token,
|
||||
* which encapsulates a sequence number and ensures that attempts to
|
||||
* delete or reorder messages can be detected.
|
||||
*
|
||||
* Each SSL/TLS connection state contains a sequence number, which
|
||||
* is maintained separately for read and write states. The sequence
|
||||
* number MUST be set to zero whenever a connection state is made the
|
||||
* active state. Sequence numbers are of type uint64 and may not
|
||||
* exceed 2^64-1. Sequence numbers do not wrap. If a SSL/TLS
|
||||
* implementation would need to wrap a sequence number, it must
|
||||
* renegotiate instead. A sequence number is incremented after each
|
||||
* record: specifically, the first record transmitted under a
|
||||
* particular connection state MUST use sequence number 0.
|
||||
*/
|
||||
class Authenticator {
|
||||
|
||||
// byte array containing the additional authentication information for
|
||||
// each record
|
||||
private final byte[] block;
|
||||
|
||||
// the block size of SSL v3.0:
|
||||
// sequence number + record type + + record length
|
||||
private static final int BLOCK_SIZE_SSL = 8 + 1 + 2;
|
||||
|
||||
// the block size of TLS v1.0 and later:
|
||||
// sequence number + record type + protocol version + record length
|
||||
private static final int BLOCK_SIZE_TLS = 8 + 1 + 2 + 2;
|
||||
|
||||
/**
|
||||
* Default construct, no message authentication token is initialized.
|
||||
*
|
||||
* Note that this construct can only be called for null MAC
|
||||
*/
|
||||
Authenticator() {
|
||||
block = new byte[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the message authentication token for the specified
|
||||
* SSL/TLS protocol.
|
||||
*/
|
||||
Authenticator(ProtocolVersion protocolVersion) {
|
||||
if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
|
||||
block = new byte[BLOCK_SIZE_TLS];
|
||||
block[9] = protocolVersion.major;
|
||||
block[10] = protocolVersion.minor;
|
||||
} else {
|
||||
block = new byte[BLOCK_SIZE_SSL];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the sequence number is close to wrap.
|
||||
*
|
||||
* Sequence numbers are of type uint64 and may not exceed 2^64-1.
|
||||
* Sequence numbers do not wrap. When the sequence number is near
|
||||
* to wrap, we need to close the connection immediately.
|
||||
*
|
||||
* @return true if the sequence number is close to wrap
|
||||
*/
|
||||
final boolean seqNumOverflow() {
|
||||
/*
|
||||
* Conservatively, we don't allow more records to be generated
|
||||
* when there are only 2^8 sequence numbers left.
|
||||
*/
|
||||
return (block.length != 0 &&
|
||||
block[0] == (byte)0xFF && block[1] == (byte)0xFF &&
|
||||
block[2] == (byte)0xFF && block[3] == (byte)0xFF &&
|
||||
block[4] == (byte)0xFF && block[5] == (byte)0xFF &&
|
||||
block[6] == (byte)0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the sequence number close to renew.
|
||||
*
|
||||
* Sequence numbers are of type uint64 and may not exceed 2^64-1.
|
||||
* Sequence numbers do not wrap. If a TLS
|
||||
* implementation would need to wrap a sequence number, it must
|
||||
* renegotiate instead.
|
||||
*
|
||||
* @return true if the sequence number is huge enough to renew
|
||||
*/
|
||||
final boolean seqNumIsHuge() {
|
||||
/*
|
||||
* Conservatively, we should ask for renegotiation when there are
|
||||
* only 2^48 sequence numbers left.
|
||||
*/
|
||||
return (block.length != 0 &&
|
||||
block[0] == (byte)0xFF && block[1] == (byte)0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current sequence number.
|
||||
*
|
||||
* @return the byte array of the current sequence number
|
||||
*/
|
||||
final byte[] sequenceNumber() {
|
||||
return Arrays.copyOf(block, 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquires the current message authentication information with the
|
||||
* specified record type and fragment length, and then increases the
|
||||
* sequence number.
|
||||
*
|
||||
* @param type the record type
|
||||
* @param length the fragment of the record
|
||||
* @return the byte array of the current message authentication information
|
||||
*/
|
||||
final byte[] acquireAuthenticationBytes(byte type, int length) {
|
||||
byte[] copy = block.clone();
|
||||
|
||||
if (block.length != 0) {
|
||||
copy[8] = type;
|
||||
copy[copy.length - 2] = (byte)(length >> 8);
|
||||
copy[copy.length - 1] = (byte)(length);
|
||||
|
||||
/*
|
||||
* Increase the sequence number in the block array
|
||||
* it is a 64-bit number stored in big-endian format
|
||||
*/
|
||||
int k = 7;
|
||||
while ((k >= 0) && (++block[k] == 0)) {
|
||||
k--;
|
||||
}
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
}
|
@ -29,15 +29,18 @@ package sun.security.ssl;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Arrays;
|
||||
|
||||
import java.security.*;
|
||||
import javax.crypto.*;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.GCMParameterSpec;
|
||||
|
||||
import java.nio.*;
|
||||
|
||||
import sun.security.ssl.CipherSuite.*;
|
||||
import static sun.security.ssl.CipherSuite.*;
|
||||
import static sun.security.ssl.CipherSuite.CipherType.*;
|
||||
|
||||
import sun.misc.HexDumpEncoder;
|
||||
|
||||
@ -101,20 +104,41 @@ final class CipherBox {
|
||||
// cipher object
|
||||
private final Cipher cipher;
|
||||
|
||||
/**
|
||||
* Cipher blocksize, 0 for stream ciphers
|
||||
*/
|
||||
private int blockSize;
|
||||
|
||||
/**
|
||||
* secure random
|
||||
*/
|
||||
private SecureRandom random;
|
||||
|
||||
/**
|
||||
* Is the cipher of CBC mode?
|
||||
* fixed IV, the implicit nonce of AEAD cipher suite, only apply to
|
||||
* AEAD cipher suites
|
||||
*/
|
||||
private final boolean isCBCMode;
|
||||
private final byte[] fixedIv;
|
||||
|
||||
/**
|
||||
* the key, reserved only for AEAD cipher initialization
|
||||
*/
|
||||
private final Key key;
|
||||
|
||||
/**
|
||||
* the operation mode, reserved for AEAD cipher initialization
|
||||
*/
|
||||
private final int mode;
|
||||
|
||||
/**
|
||||
* the authentication tag size, only apply to AEAD cipher suites
|
||||
*/
|
||||
private final int tagSize;
|
||||
|
||||
/**
|
||||
* the record IV length, only apply to AEAD cipher suites
|
||||
*/
|
||||
private final int recordIvSize;
|
||||
|
||||
/**
|
||||
* cipher type
|
||||
*/
|
||||
private final CipherType cipherType;
|
||||
|
||||
/**
|
||||
* Fixed masks of various block size, as the initial decryption IVs
|
||||
@ -132,7 +156,13 @@ final class CipherBox {
|
||||
private CipherBox() {
|
||||
this.protocolVersion = ProtocolVersion.DEFAULT;
|
||||
this.cipher = null;
|
||||
this.isCBCMode = false;
|
||||
this.cipherType = STREAM_CIPHER;
|
||||
this.fixedIv = new byte[0];
|
||||
this.key = null;
|
||||
this.mode = Cipher.ENCRYPT_MODE; // choose at random
|
||||
this.random = null;
|
||||
this.tagSize = 0;
|
||||
this.recordIvSize = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -147,13 +177,13 @@ final class CipherBox {
|
||||
try {
|
||||
this.protocolVersion = protocolVersion;
|
||||
this.cipher = JsseJce.getCipher(bulkCipher.transformation);
|
||||
int mode = encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
|
||||
this.mode = encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
|
||||
|
||||
if (random == null) {
|
||||
random = JsseJce.getSecureRandom();
|
||||
}
|
||||
this.random = random;
|
||||
this.isCBCMode = bulkCipher.isCBCMode;
|
||||
this.cipherType = bulkCipher.cipherType;
|
||||
|
||||
/*
|
||||
* RFC 4346 recommends two algorithms used to generated the
|
||||
@ -171,14 +201,40 @@ final class CipherBox {
|
||||
iv = getFixedMask(bulkCipher.ivSize);
|
||||
}
|
||||
|
||||
cipher.init(mode, key, iv, random);
|
||||
if (cipherType == AEAD_CIPHER) {
|
||||
// AEAD must completely initialize the cipher for each packet,
|
||||
// and so we save initialization parameters for packet
|
||||
// processing time.
|
||||
|
||||
// Do not call getBlockSize until after init()
|
||||
// otherwise we would disrupt JCE delayed provider selection
|
||||
blockSize = cipher.getBlockSize();
|
||||
// some providers implement getBlockSize() incorrectly
|
||||
if (blockSize == 1) {
|
||||
blockSize = 0;
|
||||
// Set the tag size for AEAD cipher
|
||||
tagSize = bulkCipher.tagSize;
|
||||
|
||||
// Reserve the key for AEAD cipher initialization
|
||||
this.key = key;
|
||||
|
||||
fixedIv = iv.getIV();
|
||||
if (fixedIv == null ||
|
||||
fixedIv.length != bulkCipher.fixedIvSize) {
|
||||
throw new RuntimeException("Improper fixed IV for AEAD");
|
||||
}
|
||||
|
||||
// Set the record IV length for AEAD cipher
|
||||
recordIvSize = bulkCipher.ivSize - bulkCipher.fixedIvSize;
|
||||
|
||||
// DON'T initialize the cipher for AEAD!
|
||||
} else {
|
||||
// CBC only requires one initialization during its lifetime
|
||||
// (future packets/IVs set the proper CBC state), so we can
|
||||
// initialize now.
|
||||
|
||||
// Zeroize the variables that only apply to AEAD cipher
|
||||
this.tagSize = 0;
|
||||
this.fixedIv = new byte[0];
|
||||
this.recordIvSize = 0;
|
||||
this.key = null;
|
||||
|
||||
// Initialize the cipher
|
||||
cipher.init(mode, key, iv, random);
|
||||
}
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw e;
|
||||
@ -235,26 +291,11 @@ final class CipherBox {
|
||||
}
|
||||
|
||||
try {
|
||||
if (blockSize != 0) {
|
||||
// TLSv1.1 needs a IV block
|
||||
if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
|
||||
// generate a random number
|
||||
byte[] prefix = new byte[blockSize];
|
||||
random.nextBytes(prefix);
|
||||
|
||||
// move forward the plaintext
|
||||
System.arraycopy(buf, offset,
|
||||
buf, offset + prefix.length, len);
|
||||
|
||||
// prefix the plaintext
|
||||
System.arraycopy(prefix, 0,
|
||||
buf, offset, prefix.length);
|
||||
|
||||
len += prefix.length;
|
||||
}
|
||||
|
||||
int blockSize = cipher.getBlockSize();
|
||||
if (cipherType == BLOCK_CIPHER) {
|
||||
len = addPadding(buf, offset, len, blockSize);
|
||||
}
|
||||
|
||||
if (debug != null && Debug.isOn("plaintext")) {
|
||||
try {
|
||||
HexDumpEncoder hd = new HexDumpEncoder();
|
||||
@ -267,6 +308,18 @@ final class CipherBox {
|
||||
System.out);
|
||||
} catch (IOException e) { }
|
||||
}
|
||||
|
||||
|
||||
if (cipherType == AEAD_CIPHER) {
|
||||
try {
|
||||
return cipher.doFinal(buf, offset, len, buf, offset);
|
||||
} catch (IllegalBlockSizeException | BadPaddingException ibe) {
|
||||
// unlikely to happen
|
||||
throw new RuntimeException(
|
||||
"Cipher error in AEAD mode in JCE provider " +
|
||||
cipher.getProvider().getName(), ibe);
|
||||
}
|
||||
} else {
|
||||
int newLen = cipher.update(buf, offset, len, buf, offset);
|
||||
if (newLen != len) {
|
||||
// catch BouncyCastle buffering error
|
||||
@ -274,7 +327,9 @@ final class CipherBox {
|
||||
"in JCE provider " + cipher.getProvider().getName());
|
||||
}
|
||||
return newLen;
|
||||
}
|
||||
} catch (ShortBufferException e) {
|
||||
// unlikely to happen, we should have enough buffer space here
|
||||
throw new ArrayIndexOutOfBoundsException(e.toString());
|
||||
}
|
||||
}
|
||||
@ -288,7 +343,7 @@ final class CipherBox {
|
||||
* set to last position padded/encrypted. The limit may have changed
|
||||
* because of the added padding bytes.
|
||||
*/
|
||||
int encrypt(ByteBuffer bb) {
|
||||
int encrypt(ByteBuffer bb, int outLimit) {
|
||||
|
||||
int len = bb.remaining();
|
||||
|
||||
@ -297,44 +352,15 @@ final class CipherBox {
|
||||
return len;
|
||||
}
|
||||
|
||||
try {
|
||||
int pos = bb.position();
|
||||
|
||||
if (blockSize != 0) {
|
||||
// TLSv1.1 needs a IV block
|
||||
if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
|
||||
// generate a random number
|
||||
byte[] prefix = new byte[blockSize];
|
||||
random.nextBytes(prefix);
|
||||
|
||||
// move forward the plaintext
|
||||
byte[] buf = null;
|
||||
int limit = bb.limit();
|
||||
if (bb.hasArray()) {
|
||||
int arrayOffset = bb.arrayOffset();
|
||||
buf = bb.array();
|
||||
System.arraycopy(buf, arrayOffset + pos,
|
||||
buf, arrayOffset + pos + prefix.length,
|
||||
limit - pos);
|
||||
bb.limit(limit + prefix.length);
|
||||
} else {
|
||||
buf = new byte[limit - pos];
|
||||
bb.get(buf, 0, limit - pos);
|
||||
bb.position(pos + prefix.length);
|
||||
bb.limit(limit + prefix.length);
|
||||
bb.put(buf);
|
||||
}
|
||||
bb.position(pos);
|
||||
|
||||
// prefix the plaintext
|
||||
bb.put(prefix);
|
||||
bb.position(pos);
|
||||
}
|
||||
|
||||
int blockSize = cipher.getBlockSize();
|
||||
if (cipherType == BLOCK_CIPHER) {
|
||||
// addPadding adjusts pos/limit
|
||||
len = addPadding(bb, blockSize);
|
||||
bb.position(pos);
|
||||
}
|
||||
|
||||
if (debug != null && Debug.isOn("plaintext")) {
|
||||
try {
|
||||
HexDumpEncoder hd = new HexDumpEncoder();
|
||||
@ -342,20 +368,54 @@ final class CipherBox {
|
||||
System.out.println(
|
||||
"Padded plaintext before ENCRYPTION: len = "
|
||||
+ len);
|
||||
hd.encodeBuffer(bb, System.out);
|
||||
hd.encodeBuffer(bb.duplicate(), System.out);
|
||||
|
||||
} catch (IOException e) { }
|
||||
/*
|
||||
* reset back to beginning
|
||||
*/
|
||||
bb.position(pos);
|
||||
}
|
||||
|
||||
/*
|
||||
* Encrypt "in-place". This does not add its own padding.
|
||||
*/
|
||||
ByteBuffer dup = bb.duplicate();
|
||||
int newLen = cipher.update(dup, bb);
|
||||
if (cipherType == AEAD_CIPHER) {
|
||||
try {
|
||||
int outputSize = cipher.getOutputSize(dup.remaining());
|
||||
if (outputSize > bb.remaining()) {
|
||||
// need to expand the limit of the output buffer for
|
||||
// the authentication tag.
|
||||
//
|
||||
// DON'T worry about the buffer's capacity, we have
|
||||
// reserved space for the authentication tag.
|
||||
if (outLimit < pos + outputSize) {
|
||||
// unlikely to happen
|
||||
throw new ShortBufferException(
|
||||
"need more space in output buffer");
|
||||
}
|
||||
bb.limit(pos + outputSize);
|
||||
}
|
||||
int newLen = cipher.doFinal(dup, bb);
|
||||
if (newLen != outputSize) {
|
||||
throw new RuntimeException(
|
||||
"Cipher buffering error in JCE provider " +
|
||||
cipher.getProvider().getName());
|
||||
}
|
||||
return newLen;
|
||||
} catch (IllegalBlockSizeException |
|
||||
BadPaddingException | ShortBufferException ibse) {
|
||||
// unlikely to happen
|
||||
throw new RuntimeException(
|
||||
"Cipher error in AEAD mode in JCE provider " +
|
||||
cipher.getProvider().getName(), ibse);
|
||||
}
|
||||
} else {
|
||||
int newLen;
|
||||
try {
|
||||
newLen = cipher.update(dup, bb);
|
||||
} catch (ShortBufferException sbe) {
|
||||
// unlikely to happen
|
||||
throw new RuntimeException("Cipher buffering error " +
|
||||
"in JCE provider " + cipher.getProvider().getName());
|
||||
}
|
||||
|
||||
if (bb.position() != dup.position()) {
|
||||
throw new RuntimeException("bytebuffer padding error");
|
||||
@ -367,10 +427,6 @@ final class CipherBox {
|
||||
"in JCE provider " + cipher.getProvider().getName());
|
||||
}
|
||||
return newLen;
|
||||
} catch (ShortBufferException e) {
|
||||
RuntimeException exc = new RuntimeException(e.toString());
|
||||
exc.initCause(e);
|
||||
throw exc;
|
||||
}
|
||||
}
|
||||
|
||||
@ -399,12 +455,24 @@ final class CipherBox {
|
||||
}
|
||||
|
||||
try {
|
||||
int newLen = cipher.update(buf, offset, len, buf, offset);
|
||||
int newLen;
|
||||
if (cipherType == AEAD_CIPHER) {
|
||||
try {
|
||||
newLen = cipher.doFinal(buf, offset, len, buf, offset);
|
||||
} catch (IllegalBlockSizeException ibse) {
|
||||
// unlikely to happen
|
||||
throw new RuntimeException(
|
||||
"Cipher error in AEAD mode in JCE provider " +
|
||||
cipher.getProvider().getName(), ibse);
|
||||
}
|
||||
} else {
|
||||
newLen = cipher.update(buf, offset, len, buf, offset);
|
||||
if (newLen != len) {
|
||||
// catch BouncyCastle buffering error
|
||||
throw new RuntimeException("Cipher buffering error " +
|
||||
"in JCE provider " + cipher.getProvider().getName());
|
||||
}
|
||||
}
|
||||
if (debug != null && Debug.isOn("plaintext")) {
|
||||
try {
|
||||
HexDumpEncoder hd = new HexDumpEncoder();
|
||||
@ -418,7 +486,8 @@ final class CipherBox {
|
||||
} catch (IOException e) { }
|
||||
}
|
||||
|
||||
if (blockSize != 0) {
|
||||
if (cipherType == BLOCK_CIPHER) {
|
||||
int blockSize = cipher.getBlockSize();
|
||||
newLen = removePadding(
|
||||
buf, offset, newLen, tagLen, blockSize, protocolVersion);
|
||||
|
||||
@ -426,16 +495,11 @@ final class CipherBox {
|
||||
if (newLen < blockSize) {
|
||||
throw new BadPaddingException("invalid explicit IV");
|
||||
}
|
||||
|
||||
// discards the first cipher block, the IV component.
|
||||
System.arraycopy(buf, offset + blockSize,
|
||||
buf, offset, newLen - blockSize);
|
||||
|
||||
newLen -= blockSize;
|
||||
}
|
||||
}
|
||||
return newLen;
|
||||
} catch (ShortBufferException e) {
|
||||
// unlikely to happen, we should have enough buffer space here
|
||||
throw new ArrayIndexOutOfBoundsException(e.toString());
|
||||
}
|
||||
}
|
||||
@ -465,12 +529,27 @@ final class CipherBox {
|
||||
*/
|
||||
int pos = bb.position();
|
||||
ByteBuffer dup = bb.duplicate();
|
||||
int newLen = cipher.update(dup, bb);
|
||||
int newLen;
|
||||
if (cipherType == AEAD_CIPHER) {
|
||||
try {
|
||||
newLen = cipher.doFinal(dup, bb);
|
||||
} catch (IllegalBlockSizeException ibse) {
|
||||
// unlikely to happen
|
||||
throw new RuntimeException(
|
||||
"Cipher error in AEAD mode \"" + ibse.getMessage() +
|
||||
" \"in JCE provider " + cipher.getProvider().getName());
|
||||
}
|
||||
} else {
|
||||
newLen = cipher.update(dup, bb);
|
||||
if (newLen != len) {
|
||||
// catch BouncyCastle buffering error
|
||||
throw new RuntimeException("Cipher buffering error " +
|
||||
"in JCE provider " + cipher.getProvider().getName());
|
||||
}
|
||||
}
|
||||
|
||||
// reset the limit to the end of the decryted data
|
||||
bb.limit(pos + newLen);
|
||||
|
||||
if (debug != null && Debug.isOn("plaintext")) {
|
||||
try {
|
||||
@ -488,44 +567,25 @@ final class CipherBox {
|
||||
/*
|
||||
* Remove the block padding.
|
||||
*/
|
||||
if (blockSize != 0) {
|
||||
if (cipherType == BLOCK_CIPHER) {
|
||||
int blockSize = cipher.getBlockSize();
|
||||
bb.position(pos);
|
||||
newLen = removePadding(
|
||||
bb, tagLen, blockSize, protocolVersion);
|
||||
newLen = removePadding(bb, tagLen, blockSize, protocolVersion);
|
||||
|
||||
// check the explicit IV of TLS v1.1 or later
|
||||
if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
|
||||
if (newLen < blockSize) {
|
||||
throw new BadPaddingException("invalid explicit IV");
|
||||
}
|
||||
|
||||
// discards the first cipher block, the IV component.
|
||||
byte[] buf = null;
|
||||
int limit = bb.limit();
|
||||
if (bb.hasArray()) {
|
||||
int arrayOffset = bb.arrayOffset();
|
||||
buf = bb.array();
|
||||
System.arraycopy(buf, arrayOffset + pos + blockSize,
|
||||
buf, arrayOffset + pos, limit - pos - blockSize);
|
||||
bb.limit(limit - blockSize);
|
||||
} else {
|
||||
buf = new byte[limit - pos - blockSize];
|
||||
bb.position(pos + blockSize);
|
||||
bb.get(buf);
|
||||
bb.position(pos);
|
||||
bb.put(buf);
|
||||
bb.limit(limit - blockSize);
|
||||
}
|
||||
|
||||
// reset the position to the end of the decrypted data
|
||||
limit = bb.limit();
|
||||
bb.position(limit);
|
||||
bb.position(bb.limit());
|
||||
}
|
||||
}
|
||||
return newLen;
|
||||
} catch (ShortBufferException e) {
|
||||
RuntimeException exc = new RuntimeException(e.toString());
|
||||
exc.initCause(e);
|
||||
throw exc;
|
||||
// unlikely to happen, we should have enough buffer space here
|
||||
throw new ArrayIndexOutOfBoundsException(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@ -766,8 +826,8 @@ final class CipherBox {
|
||||
// ignore return value.
|
||||
cipher.doFinal();
|
||||
}
|
||||
} catch (GeneralSecurityException e) {
|
||||
// swallow for now.
|
||||
} catch (Exception e) {
|
||||
// swallow all types of exceptions.
|
||||
}
|
||||
}
|
||||
|
||||
@ -777,10 +837,19 @@ final class CipherBox {
|
||||
* @return true if the cipher use CBC mode, false otherwise.
|
||||
*/
|
||||
boolean isCBCMode() {
|
||||
return isCBCMode;
|
||||
return cipherType == BLOCK_CIPHER;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Does the cipher use AEAD mode?
|
||||
*
|
||||
* @return true if the cipher use AEAD mode, false otherwise.
|
||||
*/
|
||||
boolean isAEADMode() {
|
||||
return cipherType == AEAD_CIPHER;
|
||||
}
|
||||
|
||||
/*
|
||||
* Is the cipher null?
|
||||
*
|
||||
* @return true if the cipher is null, false otherwise.
|
||||
@ -789,6 +858,226 @@ final class CipherBox {
|
||||
return cipher == null;
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets the explicit nonce/IV size of the cipher.
|
||||
*
|
||||
* The returned value is the SecurityParameters.record_iv_length in
|
||||
* RFC 4346/5246. It is the size of explicit IV for CBC mode, and the
|
||||
* size of explicit nonce for AEAD mode.
|
||||
*
|
||||
* @return the explicit nonce size of the cipher.
|
||||
*/
|
||||
int getExplicitNonceSize() {
|
||||
switch (cipherType) {
|
||||
case BLOCK_CIPHER:
|
||||
// For block ciphers, the explicit IV length is of length
|
||||
// SecurityParameters.record_iv_length, which is equal to
|
||||
// the SecurityParameters.block_size.
|
||||
if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
|
||||
return cipher.getBlockSize();
|
||||
}
|
||||
break;
|
||||
case AEAD_CIPHER:
|
||||
return recordIvSize;
|
||||
// It is also the length of sequence number, which is
|
||||
// used as the nonce_explicit for AEAD cipher suites.
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Applies the explicit nonce/IV to this cipher. This method is used to
|
||||
* decrypt an SSL/TLS input record.
|
||||
*
|
||||
* The returned value is the SecurityParameters.record_iv_length in
|
||||
* RFC 4346/5246. It is the size of explicit IV for CBC mode, and the
|
||||
* size of explicit nonce for AEAD mode.
|
||||
*
|
||||
* @param authenticator the authenticator to get the additional
|
||||
* authentication data
|
||||
* @param contentType the content type of the input record
|
||||
* @param bb the byte buffer to get the explicit nonce from
|
||||
*
|
||||
* @return the explicit nonce size of the cipher.
|
||||
*/
|
||||
int applyExplicitNonce(Authenticator authenticator, byte contentType,
|
||||
ByteBuffer bb) throws BadPaddingException {
|
||||
switch (cipherType) {
|
||||
case BLOCK_CIPHER:
|
||||
// sanity check length of the ciphertext
|
||||
int tagLen = (authenticator instanceof MAC) ?
|
||||
((MAC)authenticator).MAClen() : 0;
|
||||
if (tagLen != 0) {
|
||||
if (!sanityCheck(tagLen, bb.remaining())) {
|
||||
throw new BadPaddingException(
|
||||
"ciphertext sanity check failed");
|
||||
}
|
||||
}
|
||||
|
||||
// For block ciphers, the explicit IV length is of length
|
||||
// SecurityParameters.record_iv_length, which is equal to
|
||||
// the SecurityParameters.block_size.
|
||||
if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
|
||||
return cipher.getBlockSize();
|
||||
}
|
||||
break;
|
||||
case AEAD_CIPHER:
|
||||
if (bb.remaining() < (recordIvSize + tagSize)) {
|
||||
throw new BadPaddingException(
|
||||
"invalid AEAD cipher fragment");
|
||||
}
|
||||
|
||||
// initialize the AEAD cipher for the unique IV
|
||||
byte[] iv = Arrays.copyOf(fixedIv,
|
||||
fixedIv.length + recordIvSize);
|
||||
bb.get(iv, fixedIv.length, recordIvSize);
|
||||
bb.position(bb.position() - recordIvSize);
|
||||
GCMParameterSpec spec = new GCMParameterSpec(tagSize * 8, iv);
|
||||
try {
|
||||
cipher.init(mode, key, spec, random);
|
||||
} catch (InvalidKeyException |
|
||||
InvalidAlgorithmParameterException ikae) {
|
||||
// unlikely to happen
|
||||
throw new RuntimeException(
|
||||
"invalid key or spec in GCM mode", ikae);
|
||||
}
|
||||
|
||||
// update the additional authentication data
|
||||
byte[] aad = authenticator.acquireAuthenticationBytes(
|
||||
contentType, bb.remaining() - recordIvSize - tagSize);
|
||||
cipher.updateAAD(aad);
|
||||
|
||||
return recordIvSize;
|
||||
// It is also the length of sequence number, which is
|
||||
// used as the nonce_explicit for AEAD cipher suites.
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Applies the explicit nonce/IV to this cipher. This method is used to
|
||||
* decrypt an SSL/TLS input record.
|
||||
*
|
||||
* The returned value is the SecurityParameters.record_iv_length in
|
||||
* RFC 4346/5246. It is the size of explicit IV for CBC mode, and the
|
||||
* size of explicit nonce for AEAD mode.
|
||||
*
|
||||
* @param authenticator the authenticator to get the additional
|
||||
* authentication data
|
||||
* @param contentType the content type of the input record
|
||||
* @param buf the byte array to get the explicit nonce from
|
||||
* @param offset the offset of the byte buffer
|
||||
* @param cipheredLength the ciphered fragment length of the output
|
||||
* record, it is the TLSCiphertext.length in RFC 4346/5246.
|
||||
*
|
||||
* @return the explicit nonce size of the cipher.
|
||||
*/
|
||||
int applyExplicitNonce(Authenticator authenticator,
|
||||
byte contentType, byte[] buf, int offset,
|
||||
int cipheredLength) throws BadPaddingException {
|
||||
|
||||
ByteBuffer bb = ByteBuffer.wrap(buf, offset, cipheredLength);
|
||||
|
||||
return applyExplicitNonce(authenticator, contentType, bb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates the explicit nonce/IV to this cipher. This method is used to
|
||||
* encrypt an SSL/TLS output record.
|
||||
*
|
||||
* The size of the returned array is the SecurityParameters.record_iv_length
|
||||
* in RFC 4346/5246. It is the size of explicit IV for CBC mode, and the
|
||||
* size of explicit nonce for AEAD mode.
|
||||
*
|
||||
* @param authenticator the authenticator to get the additional
|
||||
* authentication data
|
||||
* @param contentType the content type of the input record
|
||||
* @param fragmentLength the fragment length of the output record, it is
|
||||
* the TLSCompressed.length in RFC 4346/5246.
|
||||
*
|
||||
* @return the explicit nonce of the cipher.
|
||||
*/
|
||||
byte[] createExplicitNonce(Authenticator authenticator,
|
||||
byte contentType, int fragmentLength) {
|
||||
|
||||
byte[] nonce = new byte[0];
|
||||
switch (cipherType) {
|
||||
case BLOCK_CIPHER:
|
||||
if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
|
||||
// For block ciphers, the explicit IV length is of length
|
||||
// SecurityParameters.record_iv_length, which is equal to
|
||||
// the SecurityParameters.block_size.
|
||||
//
|
||||
// Generate a random number as the explicit IV parameter.
|
||||
nonce = new byte[cipher.getBlockSize()];
|
||||
random.nextBytes(nonce);
|
||||
}
|
||||
break;
|
||||
case AEAD_CIPHER:
|
||||
// To be unique and aware of overflow-wrap, sequence number
|
||||
// is used as the nonce_explicit of AEAD cipher suites.
|
||||
nonce = authenticator.sequenceNumber();
|
||||
|
||||
// initialize the AEAD cipher for the unique IV
|
||||
byte[] iv = Arrays.copyOf(fixedIv,
|
||||
fixedIv.length + nonce.length);
|
||||
System.arraycopy(nonce, 0, iv, fixedIv.length, nonce.length);
|
||||
GCMParameterSpec spec = new GCMParameterSpec(tagSize * 8, iv);
|
||||
try {
|
||||
cipher.init(mode, key, spec, random);
|
||||
} catch (InvalidKeyException |
|
||||
InvalidAlgorithmParameterException ikae) {
|
||||
// unlikely to happen
|
||||
throw new RuntimeException(
|
||||
"invalid key or spec in GCM mode", ikae);
|
||||
}
|
||||
|
||||
// update the additional authentication data
|
||||
byte[] aad = authenticator.acquireAuthenticationBytes(
|
||||
contentType, fragmentLength);
|
||||
cipher.updateAAD(aad);
|
||||
break;
|
||||
}
|
||||
|
||||
return nonce;
|
||||
}
|
||||
|
||||
/*
|
||||
* Is this cipher available?
|
||||
*
|
||||
* This method can only be called by CipherSuite.BulkCipher.isAvailable()
|
||||
* to test the availability of a cipher suites. Please DON'T use it in
|
||||
* other places, otherwise, the behavior may be unexpected because we may
|
||||
* initialize AEAD cipher improperly in the method.
|
||||
*/
|
||||
Boolean isAvailable() {
|
||||
// We won't know whether a cipher for a particular key size is
|
||||
// available until the cipher is successfully initialized.
|
||||
//
|
||||
// We do not initialize AEAD cipher in the constructor. Need to
|
||||
// initialize the cipher to ensure that the AEAD mode for a
|
||||
// particular key size is supported.
|
||||
if (cipherType == AEAD_CIPHER) {
|
||||
try {
|
||||
Authenticator authenticator =
|
||||
new Authenticator(protocolVersion);
|
||||
byte[] nonce = authenticator.sequenceNumber();
|
||||
byte[] iv = Arrays.copyOf(fixedIv,
|
||||
fixedIv.length + nonce.length);
|
||||
System.arraycopy(nonce, 0, iv, fixedIv.length, nonce.length);
|
||||
GCMParameterSpec spec = new GCMParameterSpec(tagSize * 8, iv);
|
||||
|
||||
cipher.init(mode, key, spec, random);
|
||||
} catch (Exception e) {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
} // Otherwise, we have initialized the cipher in the constructor.
|
||||
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanity check the length of a fragment before decryption.
|
||||
*
|
||||
@ -802,11 +1091,12 @@ final class CipherBox {
|
||||
*
|
||||
* @return true if the length of a fragment matches above requirements
|
||||
*/
|
||||
boolean sanityCheck(int tagLen, int fragmentLen) {
|
||||
if (!isCBCMode) {
|
||||
private boolean sanityCheck(int tagLen, int fragmentLen) {
|
||||
if (!isCBCMode()) {
|
||||
return fragmentLen >= tagLen;
|
||||
}
|
||||
|
||||
int blockSize = cipher.getBlockSize();
|
||||
if ((fragmentLen % blockSize) == 0) {
|
||||
int minimal = tagLen + 1;
|
||||
minimal = (minimal >= blockSize) ? minimal : blockSize;
|
||||
|
@ -33,12 +33,14 @@ import java.security.InvalidKeyException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.KeyManagementException;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import static sun.security.ssl.CipherSuite.KeyExchange.*;
|
||||
import static sun.security.ssl.CipherSuite.PRF.*;
|
||||
import static sun.security.ssl.CipherSuite.CipherType.*;
|
||||
import static sun.security.ssl.JsseJce.*;
|
||||
|
||||
/**
|
||||
@ -135,7 +137,9 @@ final class CipherSuite implements Comparable<CipherSuite> {
|
||||
this.keyExchange = keyExchange;
|
||||
this.cipher = cipher;
|
||||
this.exportable = cipher.exportable;
|
||||
if (name.endsWith("_MD5")) {
|
||||
if (cipher.cipherType == CipherType.AEAD_CIPHER) {
|
||||
macAlg = M_NULL;
|
||||
} else if (name.endsWith("_MD5")) {
|
||||
macAlg = M_MD5;
|
||||
} else if (name.endsWith("_SHA")) {
|
||||
macAlg = M_SHA;
|
||||
@ -385,6 +389,12 @@ final class CipherSuite implements Comparable<CipherSuite> {
|
||||
}
|
||||
}
|
||||
|
||||
static enum CipherType {
|
||||
STREAM_CIPHER, // null or stream cipher
|
||||
BLOCK_CIPHER, // block cipher in CBC mode
|
||||
AEAD_CIPHER // AEAD cipher
|
||||
}
|
||||
|
||||
/**
|
||||
* An SSL/TLS bulk cipher algorithm. One instance per combination of
|
||||
* cipher and key length.
|
||||
@ -417,14 +427,26 @@ final class CipherSuite implements Comparable<CipherSuite> {
|
||||
// for non-exportable ciphers, this is the same as keySize
|
||||
final int expandedKeySize;
|
||||
|
||||
// size of the IV (also block size)
|
||||
// size of the IV
|
||||
final int ivSize;
|
||||
|
||||
// size of fixed IV
|
||||
//
|
||||
// record_iv_length = ivSize - fixedIvSize
|
||||
final int fixedIvSize;
|
||||
|
||||
// exportable under 512/40 bit rules
|
||||
final boolean exportable;
|
||||
|
||||
// Is the cipher algorithm of Cipher Block Chaining (CBC) mode?
|
||||
final boolean isCBCMode;
|
||||
final CipherType cipherType;
|
||||
|
||||
// size of the authentication tag, only applicable to cipher suites in
|
||||
// Galois Counter Mode (GCM)
|
||||
//
|
||||
// As far as we know, all supported GCM cipher suites use 128-bits
|
||||
// authentication tags.
|
||||
final int tagSize = 16;
|
||||
|
||||
// The secure random used to detect the cipher availability.
|
||||
private final static SecureRandom secureRandom;
|
||||
@ -437,32 +459,34 @@ final class CipherSuite implements Comparable<CipherSuite> {
|
||||
}
|
||||
}
|
||||
|
||||
BulkCipher(String transformation, int keySize,
|
||||
int expandedKeySize, int ivSize, boolean allowed) {
|
||||
BulkCipher(String transformation, CipherType cipherType, int keySize,
|
||||
int expandedKeySize, int ivSize,
|
||||
int fixedIvSize, boolean allowed) {
|
||||
|
||||
this.transformation = transformation;
|
||||
String[] splits = transformation.split("/");
|
||||
this.algorithm = splits[0];
|
||||
this.isCBCMode =
|
||||
splits.length <= 1 ? false : "CBC".equalsIgnoreCase(splits[1]);
|
||||
this.cipherType = cipherType;
|
||||
this.description = this.algorithm + "/" + (keySize << 3);
|
||||
this.keySize = keySize;
|
||||
this.ivSize = ivSize;
|
||||
this.fixedIvSize = fixedIvSize;
|
||||
this.allowed = allowed;
|
||||
|
||||
this.expandedKeySize = expandedKeySize;
|
||||
this.exportable = true;
|
||||
}
|
||||
|
||||
BulkCipher(String transformation, int keySize,
|
||||
int ivSize, boolean allowed) {
|
||||
BulkCipher(String transformation, CipherType cipherType, int keySize,
|
||||
int ivSize, int fixedIvSize, boolean allowed) {
|
||||
this.transformation = transformation;
|
||||
String[] splits = transformation.split("/");
|
||||
this.algorithm = splits[0];
|
||||
this.isCBCMode =
|
||||
splits.length <= 1 ? false : "CBC".equalsIgnoreCase(splits[1]);
|
||||
this.cipherType = cipherType;
|
||||
this.description = this.algorithm + "/" + (keySize << 3);
|
||||
this.keySize = keySize;
|
||||
this.ivSize = ivSize;
|
||||
this.fixedIvSize = fixedIvSize;
|
||||
this.allowed = allowed;
|
||||
|
||||
this.expandedKeySize = keySize;
|
||||
@ -486,16 +510,20 @@ final class CipherSuite implements Comparable<CipherSuite> {
|
||||
* Test if this bulk cipher is available. For use by CipherSuite.
|
||||
*
|
||||
* Currently all supported ciphers except AES are always available
|
||||
* via the JSSE internal implementations. We also assume AES/128
|
||||
* is always available since it is shipped with the SunJCE provider.
|
||||
* However, AES/256 is unavailable when the default JCE policy
|
||||
* jurisdiction files are installed because of key length restrictions.
|
||||
* via the JSSE internal implementations. We also assume AES/128 of
|
||||
* CBC mode is always available since it is shipped with the SunJCE
|
||||
* provider. However, AES/256 is unavailable when the default JCE
|
||||
* policy jurisdiction files are installed because of key length
|
||||
* restrictions, and AEAD is unavailable when the underlying providers
|
||||
* do not support AEAD/GCM mode.
|
||||
*/
|
||||
boolean isAvailable() {
|
||||
if (allowed == false) {
|
||||
return false;
|
||||
}
|
||||
if (this == B_AES_256) {
|
||||
|
||||
if ((this == B_AES_256) ||
|
||||
(this.cipherType == CipherType.AEAD_CIPHER)) {
|
||||
return isAvailable(this);
|
||||
}
|
||||
|
||||
@ -513,19 +541,50 @@ final class CipherSuite implements Comparable<CipherSuite> {
|
||||
private static synchronized boolean isAvailable(BulkCipher cipher) {
|
||||
Boolean b = availableCache.get(cipher);
|
||||
if (b == null) {
|
||||
int keySizeInBits = cipher.keySize * 8;
|
||||
if (keySizeInBits > 128) { // need the JCE unlimited
|
||||
// strength jurisdiction policy
|
||||
try {
|
||||
SecretKey key = new SecretKeySpec
|
||||
(new byte[cipher.expandedKeySize], cipher.algorithm);
|
||||
IvParameterSpec iv =
|
||||
new IvParameterSpec(new byte[cipher.ivSize]);
|
||||
cipher.newCipher(ProtocolVersion.DEFAULT,
|
||||
key, iv, secureRandom, true);
|
||||
b = Boolean.TRUE;
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
if (Cipher.getMaxAllowedKeyLength(
|
||||
cipher.transformation) < keySizeInBits) {
|
||||
b = Boolean.FALSE;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
b = Boolean.FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (b == null) {
|
||||
b = Boolean.FALSE; // may be reset to TRUE if
|
||||
// the cipher is available
|
||||
CipherBox temporary = null;
|
||||
try {
|
||||
SecretKey key = new SecretKeySpec(
|
||||
new byte[cipher.expandedKeySize],
|
||||
cipher.algorithm);
|
||||
IvParameterSpec iv;
|
||||
if (cipher.cipherType == CipherType.AEAD_CIPHER) {
|
||||
iv = new IvParameterSpec(
|
||||
new byte[cipher.fixedIvSize]);
|
||||
} else {
|
||||
iv = new IvParameterSpec(new byte[cipher.ivSize]);
|
||||
}
|
||||
temporary = cipher.newCipher(
|
||||
ProtocolVersion.DEFAULT,
|
||||
key, iv, secureRandom, true);
|
||||
b = temporary.isAvailable();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// not available
|
||||
} finally {
|
||||
if (temporary != null) {
|
||||
temporary.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
availableCache.put(cipher, b);
|
||||
}
|
||||
|
||||
return b.booleanValue();
|
||||
}
|
||||
|
||||
@ -582,27 +641,31 @@ final class CipherSuite implements Comparable<CipherSuite> {
|
||||
|
||||
// export strength ciphers
|
||||
final static BulkCipher B_NULL =
|
||||
new BulkCipher("NULL", 0, 0, 0, true);
|
||||
new BulkCipher("NULL", STREAM_CIPHER, 0, 0, 0, 0, true);
|
||||
final static BulkCipher B_RC4_40 =
|
||||
new BulkCipher(CIPHER_RC4, 5, 16, 0, true);
|
||||
new BulkCipher(CIPHER_RC4, STREAM_CIPHER, 5, 16, 0, 0, true);
|
||||
final static BulkCipher B_RC2_40 =
|
||||
new BulkCipher("RC2", 5, 16, 8, false);
|
||||
new BulkCipher("RC2", BLOCK_CIPHER, 5, 16, 8, 0, false);
|
||||
final static BulkCipher B_DES_40 =
|
||||
new BulkCipher(CIPHER_DES, 5, 8, 8, true);
|
||||
new BulkCipher(CIPHER_DES, BLOCK_CIPHER, 5, 8, 8, 0, true);
|
||||
|
||||
// domestic strength ciphers
|
||||
final static BulkCipher B_RC4_128 =
|
||||
new BulkCipher(CIPHER_RC4, 16, 0, true);
|
||||
new BulkCipher(CIPHER_RC4, STREAM_CIPHER, 16, 0, 0, true);
|
||||
final static BulkCipher B_DES =
|
||||
new BulkCipher(CIPHER_DES, 8, 8, true);
|
||||
new BulkCipher(CIPHER_DES, BLOCK_CIPHER, 8, 8, 0, true);
|
||||
final static BulkCipher B_3DES =
|
||||
new BulkCipher(CIPHER_3DES, 24, 8, true);
|
||||
new BulkCipher(CIPHER_3DES, BLOCK_CIPHER, 24, 8, 0, true);
|
||||
final static BulkCipher B_IDEA =
|
||||
new BulkCipher("IDEA", 16, 8, false);
|
||||
new BulkCipher("IDEA", BLOCK_CIPHER, 16, 8, 0, false);
|
||||
final static BulkCipher B_AES_128 =
|
||||
new BulkCipher(CIPHER_AES, 16, 16, true);
|
||||
new BulkCipher(CIPHER_AES, BLOCK_CIPHER, 16, 16, 0, true);
|
||||
final static BulkCipher B_AES_256 =
|
||||
new BulkCipher(CIPHER_AES, 32, 16, true);
|
||||
new BulkCipher(CIPHER_AES, BLOCK_CIPHER, 32, 16, 0, true);
|
||||
final static BulkCipher B_AES_128_GCM =
|
||||
new BulkCipher(CIPHER_AES_GCM, AEAD_CIPHER, 16, 12, 4, true);
|
||||
final static BulkCipher B_AES_256_GCM =
|
||||
new BulkCipher(CIPHER_AES_GCM, AEAD_CIPHER, 32, 12, 4, true);
|
||||
|
||||
// MACs
|
||||
final static MacAlg M_NULL = new MacAlg("NULL", 0, 0, 0);
|
||||
@ -902,11 +965,13 @@ final class CipherSuite implements Comparable<CipherSuite> {
|
||||
* Definition of the CipherSuites that are enabled by default.
|
||||
* They are listed in preference order, most preferred first, using
|
||||
* the following criteria:
|
||||
* 1. Prefer the stronger buld cipher, in the order of AES_256,
|
||||
* AES_128, RC-4, 3DES-EDE.
|
||||
* 2. Prefer the stronger MAC algorithm, in the order of SHA384,
|
||||
* 1. Prefer Suite B compliant cipher suites, see RFC6460 (To be
|
||||
* changed later, see below).
|
||||
* 2. Prefer the stronger bulk cipher, in the order of AES_256(GCM),
|
||||
* AES_128(GCM), AES_256, AES_128, RC-4, 3DES-EDE.
|
||||
* 3. Prefer the stronger MAC algorithm, in the order of SHA384,
|
||||
* SHA256, SHA, MD5.
|
||||
* 3. Prefer the better performance of key exchange and digital
|
||||
* 4. Prefer the better performance of key exchange and digital
|
||||
* signature algorithm, in the order of ECDHE-ECDSA, ECDHE-RSA,
|
||||
* RSA, ECDH-ECDSA, ECDH-RSA, DHE-RSA, DHE-DSS.
|
||||
*/
|
||||
@ -919,6 +984,16 @@ final class CipherSuite implements Comparable<CipherSuite> {
|
||||
|
||||
// ID Key Exchange Cipher A obs suprt PRF
|
||||
// ====== ============ ========= = === ===== ========
|
||||
|
||||
|
||||
// Placeholder for cipher suites in GCM mode.
|
||||
//
|
||||
// For better compatibility and interoperability, we decrease the
|
||||
// priority of cipher suites in GCM mode for a while as GCM
|
||||
// technologies mature in the industry. Eventually we'll move
|
||||
// the GCM suites here.
|
||||
|
||||
// AES_256(CBC)
|
||||
add("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
|
||||
0xc024, --p, K_ECDHE_ECDSA, B_AES_256, T, max, tls12, P_SHA384);
|
||||
add("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
|
||||
@ -949,6 +1024,7 @@ final class CipherSuite implements Comparable<CipherSuite> {
|
||||
add("TLS_DHE_DSS_WITH_AES_256_CBC_SHA",
|
||||
0x0038, --p, K_DHE_DSS, B_AES_256, T);
|
||||
|
||||
// AES_128(CBC)
|
||||
add("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
|
||||
0xc023, --p, K_ECDHE_ECDSA, B_AES_128, T, max, tls12, P_SHA256);
|
||||
add("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
|
||||
@ -979,6 +1055,7 @@ final class CipherSuite implements Comparable<CipherSuite> {
|
||||
add("TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
|
||||
0x0032, --p, K_DHE_DSS, B_AES_128, T);
|
||||
|
||||
// RC-4
|
||||
add("TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
|
||||
0xC007, --p, K_ECDHE_ECDSA, B_RC4_128, N);
|
||||
add("TLS_ECDHE_RSA_WITH_RC4_128_SHA",
|
||||
@ -990,6 +1067,51 @@ final class CipherSuite implements Comparable<CipherSuite> {
|
||||
add("TLS_ECDH_RSA_WITH_RC4_128_SHA",
|
||||
0xC00C, --p, K_ECDH_RSA, B_RC4_128, N);
|
||||
|
||||
// Cipher suites in GCM mode, see RFC 5288/5289.
|
||||
//
|
||||
// We may increase the priority of cipher suites in GCM mode when
|
||||
// GCM technologies become mature in the industry.
|
||||
|
||||
// Suite B compliant cipher suites, see RFC 6460.
|
||||
//
|
||||
// Note that, at present this provider is not Suite B compliant. The
|
||||
// preference order of the GCM cipher suites does not follow the spec
|
||||
// of RFC 6460.
|
||||
add("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
0xc02c, --p, K_ECDHE_ECDSA, B_AES_256_GCM, T, max, tls12, P_SHA384);
|
||||
add("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
0xc02b, --p, K_ECDHE_ECDSA, B_AES_128_GCM, T, max, tls12, P_SHA256);
|
||||
|
||||
// AES_256(GCM)
|
||||
add("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
0xc030, --p, K_ECDHE_RSA, B_AES_256_GCM, T, max, tls12, P_SHA384);
|
||||
add("TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||
0x009d, --p, K_RSA, B_AES_256_GCM, T, max, tls12, P_SHA384);
|
||||
add("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
0xc02e, --p, K_ECDH_ECDSA, B_AES_256_GCM, T, max, tls12, P_SHA384);
|
||||
add("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384",
|
||||
0xc032, --p, K_ECDH_RSA, B_AES_256_GCM, T, max, tls12, P_SHA384);
|
||||
add("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
0x009f, --p, K_DHE_RSA, B_AES_256_GCM, T, max, tls12, P_SHA384);
|
||||
add("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384",
|
||||
0x00a3, --p, K_DHE_DSS, B_AES_256_GCM, T, max, tls12, P_SHA384);
|
||||
|
||||
// AES_128(GCM)
|
||||
add("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
0xc02f, --p, K_ECDHE_RSA, B_AES_128_GCM, T, max, tls12, P_SHA256);
|
||||
add("TLS_RSA_WITH_AES_128_GCM_SHA256",
|
||||
0x009c, --p, K_RSA, B_AES_128_GCM, T, max, tls12, P_SHA256);
|
||||
add("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
0xc02d, --p, K_ECDH_ECDSA, B_AES_128_GCM, T, max, tls12, P_SHA256);
|
||||
add("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256",
|
||||
0xc031, --p, K_ECDH_RSA, B_AES_128_GCM, T, max, tls12, P_SHA256);
|
||||
add("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
0x009e, --p, K_DHE_RSA, B_AES_128_GCM, T, max, tls12, P_SHA256);
|
||||
add("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256",
|
||||
0x00a2, --p, K_DHE_DSS, B_AES_128_GCM, T, max, tls12, P_SHA256);
|
||||
// End of cipher suites in GCM mode.
|
||||
|
||||
// 3DES_EDE
|
||||
add("TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
|
||||
0xC008, --p, K_ECDHE_ECDSA, B_3DES, T);
|
||||
add("TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
@ -1033,17 +1155,22 @@ final class CipherSuite implements Comparable<CipherSuite> {
|
||||
*/
|
||||
p = DEFAULT_SUITES_PRIORITY;
|
||||
|
||||
add("TLS_DH_anon_WITH_AES_256_GCM_SHA384",
|
||||
0x00a7, --p, K_DH_ANON, B_AES_256_GCM, N, max, tls12, P_SHA384);
|
||||
add("TLS_DH_anon_WITH_AES_128_GCM_SHA256",
|
||||
0x00a6, --p, K_DH_ANON, B_AES_128_GCM, N, max, tls12, P_SHA256);
|
||||
|
||||
add("TLS_DH_anon_WITH_AES_256_CBC_SHA256",
|
||||
0x006d, --p, K_DH_ANON, B_AES_256, N, max, tls12, P_SHA256);
|
||||
add("TLS_ECDH_anon_WITH_AES_256_CBC_SHA",
|
||||
0xC019, --p, K_ECDH_ANON, B_AES_256, T);
|
||||
0xC019, --p, K_ECDH_ANON, B_AES_256, N);
|
||||
add("TLS_DH_anon_WITH_AES_256_CBC_SHA",
|
||||
0x003a, --p, K_DH_ANON, B_AES_256, N);
|
||||
|
||||
add("TLS_DH_anon_WITH_AES_128_CBC_SHA256",
|
||||
0x006c, --p, K_DH_ANON, B_AES_128, N, max, tls12, P_SHA256);
|
||||
add("TLS_ECDH_anon_WITH_AES_128_CBC_SHA",
|
||||
0xC018, --p, K_ECDH_ANON, B_AES_128, T);
|
||||
0xC018, --p, K_ECDH_ANON, B_AES_128, N);
|
||||
add("TLS_DH_anon_WITH_AES_128_CBC_SHA",
|
||||
0x0034, --p, K_DH_ANON, B_AES_128, N);
|
||||
|
||||
@ -1053,7 +1180,7 @@ final class CipherSuite implements Comparable<CipherSuite> {
|
||||
0x0018, --p, K_DH_ANON, B_RC4_128, N);
|
||||
|
||||
add("TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA",
|
||||
0xC017, --p, K_ECDH_ANON, B_3DES, T);
|
||||
0xC017, --p, K_ECDH_ANON, B_3DES, N);
|
||||
add("SSL_DH_anon_WITH_3DES_EDE_CBC_SHA",
|
||||
0x001b, --p, K_DH_ANON, B_3DES, N);
|
||||
|
||||
@ -1208,18 +1335,10 @@ final class CipherSuite implements Comparable<CipherSuite> {
|
||||
add("TLS_DH_RSA_WITH_AES_256_CBC_SHA256", 0x0069);
|
||||
|
||||
// Unsupported cipher suites from RFC 5288
|
||||
add("TLS_RSA_WITH_AES_128_GCM_SHA256", 0x009c);
|
||||
add("TLS_RSA_WITH_AES_256_GCM_SHA384", 0x009d);
|
||||
add("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", 0x009e);
|
||||
add("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", 0x009f);
|
||||
add("TLS_DH_RSA_WITH_AES_128_GCM_SHA256", 0x00a0);
|
||||
add("TLS_DH_RSA_WITH_AES_256_GCM_SHA384", 0x00a1);
|
||||
add("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", 0x00a2);
|
||||
add("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", 0x00a3);
|
||||
add("TLS_DH_DSS_WITH_AES_128_GCM_SHA256", 0x00a4);
|
||||
add("TLS_DH_DSS_WITH_AES_256_GCM_SHA384", 0x00a5);
|
||||
add("TLS_DH_anon_WITH_AES_128_GCM_SHA256", 0x00a6);
|
||||
add("TLS_DH_anon_WITH_AES_256_GCM_SHA384", 0x00a7);
|
||||
|
||||
// Unsupported cipher suites from RFC 5487
|
||||
add("TLS_PSK_WITH_AES_128_GCM_SHA256", 0x00a8);
|
||||
@ -1278,16 +1397,6 @@ final class CipherSuite implements Comparable<CipherSuite> {
|
||||
add("TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA", 0xc021);
|
||||
add("TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA", 0xc022);
|
||||
|
||||
// Unsupported cipher suites from RFC 5289
|
||||
add("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", 0xc02b);
|
||||
add("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", 0xc02c);
|
||||
add("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", 0xc02d);
|
||||
add("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", 0xc02e);
|
||||
add("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 0xc02f);
|
||||
add("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", 0xc030);
|
||||
add("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", 0xc031);
|
||||
add("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", 0xc032);
|
||||
|
||||
// Unsupported cipher suites from RFC 5489
|
||||
add("TLS_ECDHE_PSK_WITH_RC4_128_SHA", 0xc033);
|
||||
add("TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA", 0xc034);
|
||||
|
@ -186,29 +186,35 @@ final class EngineInputRecord extends InputRecord {
|
||||
* If external data(app), return a new ByteBuffer with data to
|
||||
* process.
|
||||
*/
|
||||
ByteBuffer decrypt(MAC signer,
|
||||
ByteBuffer decrypt(Authenticator authenticator,
|
||||
CipherBox box, ByteBuffer bb) throws BadPaddingException {
|
||||
|
||||
if (internalData) {
|
||||
decrypt(signer, box); // MAC is checked during decryption
|
||||
decrypt(authenticator, box); // MAC is checked during decryption
|
||||
return tmpBB;
|
||||
}
|
||||
|
||||
BadPaddingException reservedBPE = null;
|
||||
int tagLen = signer.MAClen();
|
||||
int tagLen =
|
||||
(authenticator instanceof MAC) ? ((MAC)authenticator).MAClen() : 0;
|
||||
int cipheredLength = bb.remaining();
|
||||
|
||||
if (!box.isNullCipher()) {
|
||||
// sanity check length of the ciphertext
|
||||
if (!box.sanityCheck(tagLen, cipheredLength)) {
|
||||
throw new BadPaddingException(
|
||||
"ciphertext sanity check failed");
|
||||
}
|
||||
|
||||
try {
|
||||
// apply explicit nonce for AEAD/CBC cipher suites if needed
|
||||
int nonceSize =
|
||||
box.applyExplicitNonce(authenticator, contentType(), bb);
|
||||
|
||||
// decrypt the content
|
||||
if (box.isAEADMode()) {
|
||||
// DON'T encrypt the nonce_explicit for AEAD mode
|
||||
bb.position(bb.position() + nonceSize);
|
||||
} // The explicit IV for CBC mode can be decrypted.
|
||||
|
||||
// Note that the CipherBox.decrypt() does not change
|
||||
// the capacity of the buffer.
|
||||
box.decrypt(bb, tagLen);
|
||||
bb.position(nonceSize); // We don't actually remove the nonce.
|
||||
} catch (BadPaddingException bpe) {
|
||||
// RFC 2246 states that decryption_failed should be used
|
||||
// for this purpose. However, that allows certain attacks,
|
||||
@ -219,12 +225,13 @@ final class EngineInputRecord extends InputRecord {
|
||||
//
|
||||
// Failover to message authentication code checking.
|
||||
reservedBPE = bpe;
|
||||
} finally {
|
||||
bb.rewind();
|
||||
}
|
||||
}
|
||||
|
||||
if (tagLen != 0) {
|
||||
// Requires message authentication code for null, stream and block
|
||||
// cipher suites.
|
||||
if ((authenticator instanceof MAC) && (tagLen != 0)) {
|
||||
MAC signer = (MAC)authenticator;
|
||||
int macOffset = bb.limit() - tagLen;
|
||||
|
||||
// Note that although it is not necessary, we run the same MAC
|
||||
@ -297,6 +304,7 @@ final class EngineInputRecord extends InputRecord {
|
||||
private static boolean checkMacTags(byte contentType, ByteBuffer bb,
|
||||
MAC signer, boolean isSimulated) {
|
||||
|
||||
int position = bb.position();
|
||||
int tagLen = signer.MAClen();
|
||||
int lim = bb.limit();
|
||||
int macData = lim - tagLen;
|
||||
@ -314,7 +322,8 @@ final class EngineInputRecord extends InputRecord {
|
||||
int[] results = compareMacTags(bb, hash);
|
||||
return (results[0] != 0);
|
||||
} finally {
|
||||
bb.rewind();
|
||||
// reset to the data
|
||||
bb.position(position);
|
||||
bb.limit(macData);
|
||||
}
|
||||
}
|
||||
@ -416,8 +425,8 @@ final class EngineInputRecord extends InputRecord {
|
||||
if (debug != null && Debug.isOn("packet")) {
|
||||
try {
|
||||
HexDumpEncoder hd = new HexDumpEncoder();
|
||||
srcBB.limit(srcPos + len);
|
||||
ByteBuffer bb = srcBB.duplicate(); // Use copy of BB
|
||||
bb.limit(srcPos + len);
|
||||
|
||||
System.out.println("[Raw read (bb)]: length = " + len);
|
||||
hd.encodeBuffer(bb, System.out);
|
||||
|
@ -29,7 +29,6 @@ package sun.security.ssl;
|
||||
import java.io.*;
|
||||
import java.nio.*;
|
||||
|
||||
|
||||
/**
|
||||
* A OutputRecord class extension which uses external ByteBuffers
|
||||
* or the internal ByteArrayOutputStream for data manipulations.
|
||||
@ -101,51 +100,6 @@ final class EngineOutputRecord extends OutputRecord {
|
||||
return finishedMsg;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculate the MAC value, storing the result either in
|
||||
* the internal buffer, or at the end of the destination
|
||||
* ByteBuffer.
|
||||
* <P>
|
||||
* We assume that the higher levels have assured us enough
|
||||
* room, otherwise we'll indirectly throw a
|
||||
* BufferOverFlowException runtime exception.
|
||||
*
|
||||
* position should equal limit, and points to the next
|
||||
* free spot.
|
||||
*/
|
||||
private void addMAC(MAC signer, ByteBuffer bb)
|
||||
throws IOException {
|
||||
|
||||
if (signer.MAClen() != 0) {
|
||||
byte[] hash = signer.compute(contentType(), bb, false);
|
||||
|
||||
/*
|
||||
* position was advanced to limit in compute above.
|
||||
*
|
||||
* Mark next area as writable (above layers should have
|
||||
* established that we have plenty of room), then write
|
||||
* out the hash.
|
||||
*/
|
||||
bb.limit(bb.limit() + hash.length);
|
||||
bb.put(hash);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Encrypt a ByteBuffer.
|
||||
*
|
||||
* We assume that the higher levels have assured us enough
|
||||
* room for the encryption (plus padding), otherwise we'll
|
||||
* indirectly throw a BufferOverFlowException runtime exception.
|
||||
*
|
||||
* position and limit will be the same, and points to the
|
||||
* next free spot.
|
||||
*/
|
||||
void encrypt(CipherBox box, ByteBuffer bb) {
|
||||
box.encrypt(bb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Override the actual write below. We do things this way to be
|
||||
* consistent with InputRecord. InputRecord may try to write out
|
||||
@ -160,7 +114,8 @@ final class EngineOutputRecord extends OutputRecord {
|
||||
* Copy data out of buffer, it's ready to go.
|
||||
*/
|
||||
ByteBuffer netBB = (ByteBuffer)
|
||||
ByteBuffer.allocate(len).put(buf, 0, len).flip();
|
||||
ByteBuffer.allocate(len).put(buf, off, len).flip();
|
||||
|
||||
writer.putOutboundData(netBB);
|
||||
}
|
||||
|
||||
@ -168,7 +123,9 @@ final class EngineOutputRecord extends OutputRecord {
|
||||
* Main method for writing non-application data.
|
||||
* We MAC/encrypt, then send down for processing.
|
||||
*/
|
||||
void write(MAC writeMAC, CipherBox writeCipher) throws IOException {
|
||||
void write(Authenticator authenticator, CipherBox writeCipher)
|
||||
throws IOException {
|
||||
|
||||
/*
|
||||
* Sanity check.
|
||||
*/
|
||||
@ -193,10 +150,10 @@ final class EngineOutputRecord extends OutputRecord {
|
||||
*/
|
||||
if (!isEmpty()) {
|
||||
// compress(); // eventually
|
||||
addMAC(writeMAC);
|
||||
encrypt(writeCipher);
|
||||
write((OutputStream)null, false, // send down for processing
|
||||
(ByteArrayOutputStream)null);
|
||||
encrypt(authenticator, writeCipher);
|
||||
|
||||
// send down for processing
|
||||
write((OutputStream)null, false, (ByteArrayOutputStream)null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -204,8 +161,8 @@ final class EngineOutputRecord extends OutputRecord {
|
||||
/**
|
||||
* Main wrap/write driver.
|
||||
*/
|
||||
void write(EngineArgs ea, MAC writeMAC, CipherBox writeCipher)
|
||||
throws IOException {
|
||||
void write(EngineArgs ea, Authenticator authenticator,
|
||||
CipherBox writeCipher) throws IOException {
|
||||
/*
|
||||
* sanity check to make sure someone didn't inadvertantly
|
||||
* send us an impossible combination we don't know how
|
||||
@ -217,7 +174,7 @@ final class EngineOutputRecord extends OutputRecord {
|
||||
* Have we set the MAC's yet? If not, we're not ready
|
||||
* to process application data yet.
|
||||
*/
|
||||
if (writeMAC == MAC.NULL) {
|
||||
if (authenticator == MAC.NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -255,7 +212,7 @@ final class EngineOutputRecord extends OutputRecord {
|
||||
*/
|
||||
int length;
|
||||
if (engine.needToSplitPayload(writeCipher, protocolVersion)) {
|
||||
write(ea, writeMAC, writeCipher, 0x01);
|
||||
write(ea, authenticator, writeCipher, 0x01);
|
||||
ea.resetLim(); // reset application data buffer limit
|
||||
length = Math.min(ea.getAppRemaining(),
|
||||
maxDataSizeMinusOneByteRecord);
|
||||
@ -265,14 +222,14 @@ final class EngineOutputRecord extends OutputRecord {
|
||||
|
||||
// Don't bother to really write empty records.
|
||||
if (length > 0) {
|
||||
write(ea, writeMAC, writeCipher, length);
|
||||
write(ea, authenticator, writeCipher, length);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void write(EngineArgs ea, MAC writeMAC, CipherBox writeCipher,
|
||||
int length) throws IOException {
|
||||
void write(EngineArgs ea, Authenticator authenticator,
|
||||
CipherBox writeCipher, int length) throws IOException {
|
||||
/*
|
||||
* Copy out existing buffer values.
|
||||
*/
|
||||
@ -286,39 +243,76 @@ final class EngineOutputRecord extends OutputRecord {
|
||||
* Don't need to worry about SSLv2 rewrites, if we're here,
|
||||
* that's long since done.
|
||||
*/
|
||||
int dstData = dstPos + headerSize;
|
||||
int dstData = dstPos + headerSize + writeCipher.getExplicitNonceSize();
|
||||
dstBB.position(dstData);
|
||||
|
||||
/*
|
||||
* transfer application data into the network data buffer
|
||||
*/
|
||||
ea.gather(length);
|
||||
dstBB.limit(dstBB.position());
|
||||
dstBB.position(dstData);
|
||||
|
||||
/*
|
||||
* "flip" but skip over header again, add MAC & encrypt
|
||||
* addMAC will expand the limit to reflect the new
|
||||
* data.
|
||||
*/
|
||||
if (authenticator instanceof MAC) {
|
||||
MAC signer = (MAC)authenticator;
|
||||
if (signer.MAClen() != 0) {
|
||||
byte[] hash = signer.compute(contentType(), dstBB, false);
|
||||
|
||||
/*
|
||||
* position was advanced to limit in compute above.
|
||||
*
|
||||
* Mark next area as writable (above layers should have
|
||||
* established that we have plenty of room), then write
|
||||
* out the hash.
|
||||
*/
|
||||
dstBB.limit(dstBB.limit() + hash.length);
|
||||
dstBB.put(hash);
|
||||
|
||||
// reset the position and limit
|
||||
dstBB.limit(dstBB.position());
|
||||
dstBB.position(dstData);
|
||||
addMAC(writeMAC, dstBB);
|
||||
}
|
||||
}
|
||||
|
||||
if (!writeCipher.isNullCipher()) {
|
||||
/*
|
||||
* Requires explicit IV/nonce for CBC/AEAD cipher suites for TLS 1.1
|
||||
* or later.
|
||||
*/
|
||||
if (protocolVersion.v >= ProtocolVersion.TLS11.v &&
|
||||
(writeCipher.isCBCMode() || writeCipher.isAEADMode())) {
|
||||
byte[] nonce = writeCipher.createExplicitNonce(
|
||||
authenticator, contentType(), dstBB.remaining());
|
||||
dstBB.position(dstPos + headerSize);
|
||||
dstBB.put(nonce);
|
||||
if (!writeCipher.isAEADMode()) {
|
||||
// The explicit IV in TLS 1.1 and later can be encrypted.
|
||||
dstBB.position(dstPos + headerSize);
|
||||
} // Otherwise, DON'T encrypt the nonce_explicit for AEAD mode
|
||||
}
|
||||
|
||||
/*
|
||||
* Encrypt may pad, so again the limit may have changed.
|
||||
*/
|
||||
dstBB.limit(dstBB.position());
|
||||
dstBB.position(dstData);
|
||||
encrypt(writeCipher, dstBB);
|
||||
writeCipher.encrypt(dstBB, dstLim);
|
||||
|
||||
if (debug != null
|
||||
&& (Debug.isOn("record") || Debug.isOn("handshake"))) {
|
||||
if ((debug != null && Debug.isOn("record"))
|
||||
|| contentType() == ct_change_cipher_spec)
|
||||
if ((debug != null) && (Debug.isOn("record") ||
|
||||
(Debug.isOn("handshake") &&
|
||||
(contentType() == ct_change_cipher_spec)))) {
|
||||
System.out.println(Thread.currentThread().getName()
|
||||
// v3.0/v3.1 ...
|
||||
+ ", WRITE: " + protocolVersion
|
||||
+ " " + InputRecord.contentName(contentType())
|
||||
+ ", length = " + length);
|
||||
}
|
||||
} else {
|
||||
dstBB.position(dstBB.limit());
|
||||
}
|
||||
|
||||
int packetLength = dstBB.limit() - dstData;
|
||||
int packetLength = dstBB.limit() - dstPos - headerSize;
|
||||
|
||||
/*
|
||||
* Finish out the record header.
|
||||
@ -333,7 +327,5 @@ final class EngineOutputRecord extends OutputRecord {
|
||||
* Position was already set by encrypt() above.
|
||||
*/
|
||||
dstBB.limit(dstLim);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
@ -99,7 +99,8 @@ final class EngineWriter {
|
||||
* other writeRecord.
|
||||
*/
|
||||
synchronized void writeRecord(EngineOutputRecord outputRecord,
|
||||
MAC writeMAC, CipherBox writeCipher) throws IOException {
|
||||
Authenticator authenticator,
|
||||
CipherBox writeCipher) throws IOException {
|
||||
|
||||
/*
|
||||
* Only output if we're still open.
|
||||
@ -108,7 +109,7 @@ final class EngineWriter {
|
||||
throw new IOException("writer side was already closed.");
|
||||
}
|
||||
|
||||
outputRecord.write(writeMAC, writeCipher);
|
||||
outputRecord.write(authenticator, writeCipher);
|
||||
|
||||
/*
|
||||
* Did our handshakers notify that we just sent the
|
||||
@ -151,7 +152,8 @@ final class EngineWriter {
|
||||
* Return any determined status.
|
||||
*/
|
||||
synchronized HandshakeStatus writeRecord(
|
||||
EngineOutputRecord outputRecord, EngineArgs ea, MAC writeMAC,
|
||||
EngineOutputRecord outputRecord, EngineArgs ea,
|
||||
Authenticator authenticator,
|
||||
CipherBox writeCipher) throws IOException {
|
||||
|
||||
/*
|
||||
@ -181,7 +183,7 @@ final class EngineWriter {
|
||||
throw new IOException("The write side was already closed");
|
||||
}
|
||||
|
||||
outputRecord.write(ea, writeMAC, writeCipher);
|
||||
outputRecord.write(ea, authenticator, writeCipher);
|
||||
|
||||
if (debug != null && Debug.isOn("packet")) {
|
||||
dumpPacket(ea, false);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 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
|
||||
@ -49,6 +49,7 @@ import sun.security.ssl.HandshakeMessage.*;
|
||||
import sun.security.ssl.CipherSuite.*;
|
||||
|
||||
import static sun.security.ssl.CipherSuite.PRF.*;
|
||||
import static sun.security.ssl.CipherSuite.CipherType.*;
|
||||
|
||||
/**
|
||||
* Handshaker ... processes handshake records from an SSL V3.0
|
||||
@ -714,33 +715,47 @@ abstract class Handshaker {
|
||||
/**
|
||||
* Create a new read MAC and return it to caller.
|
||||
*/
|
||||
MAC newReadMAC() throws NoSuchAlgorithmException, InvalidKeyException {
|
||||
Authenticator newReadAuthenticator()
|
||||
throws NoSuchAlgorithmException, InvalidKeyException {
|
||||
|
||||
Authenticator authenticator = null;
|
||||
if (cipherSuite.cipher.cipherType == AEAD_CIPHER) {
|
||||
authenticator = new Authenticator(protocolVersion);
|
||||
} else {
|
||||
MacAlg macAlg = cipherSuite.macAlg;
|
||||
MAC mac;
|
||||
if (isClient) {
|
||||
mac = macAlg.newMac(protocolVersion, svrMacSecret);
|
||||
authenticator = macAlg.newMac(protocolVersion, svrMacSecret);
|
||||
svrMacSecret = null;
|
||||
} else {
|
||||
mac = macAlg.newMac(protocolVersion, clntMacSecret);
|
||||
authenticator = macAlg.newMac(protocolVersion, clntMacSecret);
|
||||
clntMacSecret = null;
|
||||
}
|
||||
return mac;
|
||||
}
|
||||
|
||||
return authenticator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new write MAC and return it to caller.
|
||||
*/
|
||||
MAC newWriteMAC() throws NoSuchAlgorithmException, InvalidKeyException {
|
||||
Authenticator newWriteAuthenticator()
|
||||
throws NoSuchAlgorithmException, InvalidKeyException {
|
||||
|
||||
Authenticator authenticator = null;
|
||||
if (cipherSuite.cipher.cipherType == AEAD_CIPHER) {
|
||||
authenticator = new Authenticator(protocolVersion);
|
||||
} else {
|
||||
MacAlg macAlg = cipherSuite.macAlg;
|
||||
MAC mac;
|
||||
if (isClient) {
|
||||
mac = macAlg.newMac(protocolVersion, clntMacSecret);
|
||||
authenticator = macAlg.newMac(protocolVersion, clntMacSecret);
|
||||
clntMacSecret = null;
|
||||
} else {
|
||||
mac = macAlg.newMac(protocolVersion, svrMacSecret);
|
||||
authenticator = macAlg.newMac(protocolVersion, svrMacSecret);
|
||||
svrMacSecret = null;
|
||||
}
|
||||
return mac;
|
||||
}
|
||||
|
||||
return authenticator;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1189,11 +1204,23 @@ abstract class Handshaker {
|
||||
int prfHashLength = prf.getPRFHashLength();
|
||||
int prfBlockSize = prf.getPRFBlockSize();
|
||||
|
||||
// TLS v1.1 or later uses an explicit IV in CBC cipher suites to
|
||||
// protect against the CBC attacks. AEAD/GCM cipher suites in TLS
|
||||
// v1.2 or later use a fixed IV as the implicit part of the partially
|
||||
// implicit nonce technique described in RFC 5116.
|
||||
int ivSize = cipher.ivSize;
|
||||
if (cipher.cipherType == AEAD_CIPHER) {
|
||||
ivSize = cipher.fixedIvSize;
|
||||
} else if (protocolVersion.v >= ProtocolVersion.TLS11.v &&
|
||||
cipher.cipherType == BLOCK_CIPHER) {
|
||||
ivSize = 0;
|
||||
}
|
||||
|
||||
TlsKeyMaterialParameterSpec spec = new TlsKeyMaterialParameterSpec(
|
||||
masterKey, protocolVersion.major, protocolVersion.minor,
|
||||
clnt_random.random_bytes, svr_random.random_bytes,
|
||||
cipher.algorithm, cipher.keySize, expandedKeySize,
|
||||
cipher.ivSize, hashSize,
|
||||
ivSize, hashSize,
|
||||
prfHashAlg, prfHashLength, prfBlockSize);
|
||||
|
||||
try {
|
||||
@ -1201,14 +1228,15 @@ abstract class Handshaker {
|
||||
kg.init(spec);
|
||||
TlsKeyMaterialSpec keySpec = (TlsKeyMaterialSpec)kg.generateKey();
|
||||
|
||||
// Return null if cipher keys are not supposed to be generated.
|
||||
clntWriteKey = keySpec.getClientCipherKey();
|
||||
svrWriteKey = keySpec.getServerCipherKey();
|
||||
|
||||
// Return null if IVs are not supposed to be generated.
|
||||
// e.g. TLS 1.1+.
|
||||
clntWriteIV = keySpec.getClientIv();
|
||||
svrWriteIV = keySpec.getServerIv();
|
||||
|
||||
// Return null if MAC keys are not supposed to be generated.
|
||||
clntMacSecret = keySpec.getClientMacKey();
|
||||
svrMacSecret = keySpec.getServerMacKey();
|
||||
} catch (GeneralSecurityException e) {
|
||||
@ -1233,10 +1261,14 @@ abstract class Handshaker {
|
||||
printHex(dump, masterKey.getEncoded());
|
||||
|
||||
// Outputs:
|
||||
if (clntMacSecret != null) {
|
||||
System.out.println("Client MAC write Secret:");
|
||||
printHex(dump, clntMacSecret.getEncoded());
|
||||
System.out.println("Server MAC write Secret:");
|
||||
printHex(dump, svrMacSecret.getEncoded());
|
||||
} else {
|
||||
System.out.println("... no MAC keys used for this cipher");
|
||||
}
|
||||
|
||||
if (clntWriteKey != null) {
|
||||
System.out.println("Client write key:");
|
||||
|
@ -77,6 +77,17 @@ class InputRecord extends ByteArrayInputStream implements Record {
|
||||
/*
|
||||
* Construct the record to hold the maximum sized input record.
|
||||
* Data will be filled in separately.
|
||||
*
|
||||
* The structure of the byte buffer looks like:
|
||||
*
|
||||
* |--------+---------+---------------------------------|
|
||||
* | header | IV | content, MAC/TAG, padding, etc. |
|
||||
* | headerPlusIVSize |
|
||||
*
|
||||
* header: the header of an SSL records
|
||||
* IV: the optional IV/nonce field, it is only required for block
|
||||
* (TLS 1.1 or later) and AEAD cipher suites.
|
||||
*
|
||||
*/
|
||||
InputRecord() {
|
||||
super(new byte[maxRecordSize]);
|
||||
@ -133,24 +144,34 @@ class InputRecord extends ByteArrayInputStream implements Record {
|
||||
return handshakeHash;
|
||||
}
|
||||
|
||||
void decrypt(MAC signer, CipherBox box) throws BadPaddingException {
|
||||
|
||||
void decrypt(Authenticator authenticator,
|
||||
CipherBox box) throws BadPaddingException {
|
||||
BadPaddingException reservedBPE = null;
|
||||
int tagLen = signer.MAClen();
|
||||
int tagLen =
|
||||
(authenticator instanceof MAC) ? ((MAC)authenticator).MAClen() : 0;
|
||||
int cipheredLength = count - headerSize;
|
||||
|
||||
if (!box.isNullCipher()) {
|
||||
// sanity check length of the ciphertext
|
||||
if (!box.sanityCheck(tagLen, cipheredLength)) {
|
||||
throw new BadPaddingException(
|
||||
"ciphertext sanity check failed");
|
||||
}
|
||||
|
||||
try {
|
||||
// apply explicit nonce for AEAD/CBC cipher suites if needed
|
||||
int nonceSize = box.applyExplicitNonce(authenticator,
|
||||
contentType(), buf, headerSize, cipheredLength);
|
||||
pos = headerSize + nonceSize;
|
||||
lastHashed = pos; // don't digest the explicit nonce
|
||||
|
||||
// decrypt the content
|
||||
int offset = headerSize;
|
||||
if (box.isAEADMode()) {
|
||||
// DON'T encrypt the nonce_explicit for AEAD mode
|
||||
offset += nonceSize;
|
||||
} // The explicit IV for CBC mode can be decrypted.
|
||||
|
||||
// Note that the CipherBox.decrypt() does not change
|
||||
// the capacity of the buffer.
|
||||
count = headerSize +
|
||||
box.decrypt(buf, headerSize, cipheredLength, tagLen);
|
||||
count = offset +
|
||||
box.decrypt(buf, offset, count - offset, tagLen);
|
||||
|
||||
// Note that we don't remove the nonce from the buffer.
|
||||
} catch (BadPaddingException bpe) {
|
||||
// RFC 2246 states that decryption_failed should be used
|
||||
// for this purpose. However, that allows certain attacks,
|
||||
@ -164,9 +185,12 @@ class InputRecord extends ByteArrayInputStream implements Record {
|
||||
}
|
||||
}
|
||||
|
||||
if (tagLen != 0) {
|
||||
// Requires message authentication code for null, stream and block
|
||||
// cipher suites.
|
||||
if (authenticator instanceof MAC && tagLen != 0) {
|
||||
MAC signer = (MAC)authenticator;
|
||||
int macOffset = count - tagLen;
|
||||
int contentLen = macOffset - headerSize;
|
||||
int contentLen = macOffset - pos;
|
||||
|
||||
// Note that although it is not necessary, we run the same MAC
|
||||
// computation and comparison on the payload for both stream
|
||||
@ -190,7 +214,7 @@ class InputRecord extends ByteArrayInputStream implements Record {
|
||||
|
||||
// Run MAC computation and comparison on the payload.
|
||||
if (checkMacTags(contentType(),
|
||||
buf, headerSize, contentLen, signer, false)) {
|
||||
buf, pos, contentLen, signer, false)) {
|
||||
if (reservedBPE == null) {
|
||||
reservedBPE = new BadPaddingException("bad record MAC");
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 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
|
||||
@ -154,6 +154,11 @@ final class JsseJce {
|
||||
* without padding.
|
||||
*/
|
||||
final static String CIPHER_AES = "AES/CBC/NoPadding";
|
||||
/**
|
||||
* JCE transformation string for AES in GCM mode
|
||||
* without padding.
|
||||
*/
|
||||
final static String CIPHER_AES_GCM = "AES/GCM/NoPadding";
|
||||
/**
|
||||
* JCA identifier string for DSA, i.e. a DSA with SHA-1.
|
||||
*/
|
||||
|
@ -39,19 +39,15 @@ import static sun.security.ssl.CipherSuite.*;
|
||||
|
||||
/**
|
||||
* This class computes the "Message Authentication Code" (MAC) for each
|
||||
* SSL message. This is essentially a shared-secret signature, used to
|
||||
* provide integrity protection for SSL messages. The MAC is actually
|
||||
* one of several keyed hashes, as associated with the cipher suite and
|
||||
* protocol version. (SSL v3.0 uses one construct, TLS uses another.)
|
||||
* <P>
|
||||
* NOTE: MAC computation is the only place in the SSL protocol that the
|
||||
* sequence number is used. It's also reset to zero with each change of
|
||||
* a cipher spec, so this is the only place this state is needed.
|
||||
* SSL stream and block cipher message. This is essentially a shared-secret
|
||||
* signature, used to provide integrity protection for SSL messages. The
|
||||
* MAC is actually one of several keyed hashes, as associated with the cipher
|
||||
* suite and protocol version. (SSL v3.0 uses one construct, TLS uses another.)
|
||||
*
|
||||
* @author David Brownell
|
||||
* @author Andreas Sterbenz
|
||||
*/
|
||||
final class MAC {
|
||||
final class MAC extends Authenticator {
|
||||
|
||||
final static MAC NULL = new MAC();
|
||||
|
||||
@ -61,33 +57,12 @@ final class MAC {
|
||||
// internal identifier for the MAC algorithm
|
||||
private final MacAlg macAlg;
|
||||
|
||||
// stuff defined by the kind of MAC algorithm
|
||||
private final int macSize;
|
||||
|
||||
// JCE Mac object
|
||||
private final Mac mac;
|
||||
|
||||
// byte array containing the additional information we MAC in each record
|
||||
// (see below)
|
||||
private final byte[] block;
|
||||
|
||||
// sequence number + record type + + record length
|
||||
private static final int BLOCK_SIZE_SSL = 8 + 1 + 2;
|
||||
|
||||
// sequence number + record type + protocol version + record length
|
||||
private static final int BLOCK_SIZE_TLS = 8 + 1 + 2 + 2;
|
||||
|
||||
// offset of record type in block
|
||||
private static final int BLOCK_OFFSET_TYPE = 8;
|
||||
|
||||
// offset of protocol version number in block (TLS only)
|
||||
private static final int BLOCK_OFFSET_VERSION = 8 + 1;
|
||||
|
||||
private MAC() {
|
||||
macSize = 0;
|
||||
macAlg = M_NULL;
|
||||
mac = null;
|
||||
block = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -95,8 +70,8 @@ final class MAC {
|
||||
*/
|
||||
MAC(MacAlg macAlg, ProtocolVersion protocolVersion, SecretKey key)
|
||||
throws NoSuchAlgorithmException, InvalidKeyException {
|
||||
super(protocolVersion);
|
||||
this.macAlg = macAlg;
|
||||
this.macSize = macAlg.size;
|
||||
|
||||
String algorithm;
|
||||
boolean tls = (protocolVersion.v >= ProtocolVersion.TLS10.v);
|
||||
@ -115,21 +90,13 @@ final class MAC {
|
||||
|
||||
mac = JsseJce.getMac(algorithm);
|
||||
mac.init(key);
|
||||
|
||||
if (tls) {
|
||||
block = new byte[BLOCK_SIZE_TLS];
|
||||
block[BLOCK_OFFSET_VERSION] = protocolVersion.major;
|
||||
block[BLOCK_OFFSET_VERSION+1] = protocolVersion.minor;
|
||||
} else {
|
||||
block = new byte[BLOCK_SIZE_SSL];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the MAC.
|
||||
*/
|
||||
int MAClen() {
|
||||
return macSize;
|
||||
return macAlg.size;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -157,7 +124,17 @@ final class MAC {
|
||||
*/
|
||||
final byte[] compute(byte type, byte buf[],
|
||||
int offset, int len, boolean isSimulated) {
|
||||
return compute(type, null, buf, offset, len, isSimulated);
|
||||
if (macAlg.size == 0) {
|
||||
return nullMAC;
|
||||
}
|
||||
|
||||
if (!isSimulated) {
|
||||
byte[] additional = acquireAuthenticationBytes(type, len);
|
||||
mac.update(additional);
|
||||
}
|
||||
mac.update(buf, offset, len);
|
||||
|
||||
return mac.doFinal();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -173,83 +150,19 @@ final class MAC {
|
||||
* @param isSimulated if true, simulate the the MAC computation
|
||||
*/
|
||||
final byte[] compute(byte type, ByteBuffer bb, boolean isSimulated) {
|
||||
return compute(type, bb, null, 0, bb.remaining(), isSimulated);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the sequence number is close to wrap
|
||||
*
|
||||
* Sequence numbers are of type uint64 and may not exceed 2^64-1.
|
||||
* Sequence numbers do not wrap. When the sequence number is near
|
||||
* to wrap, we need to close the connection immediately.
|
||||
*/
|
||||
final boolean seqNumOverflow() {
|
||||
/*
|
||||
* Conservatively, we don't allow more records to be generated
|
||||
* when there are only 2^8 sequence numbers left.
|
||||
*/
|
||||
return (block != null && mac != null &&
|
||||
block[0] == (byte)0xFF && block[1] == (byte)0xFF &&
|
||||
block[2] == (byte)0xFF && block[3] == (byte)0xFF &&
|
||||
block[4] == (byte)0xFF && block[5] == (byte)0xFF &&
|
||||
block[6] == (byte)0xFF);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether to renew the sequence number
|
||||
*
|
||||
* Sequence numbers are of type uint64 and may not exceed 2^64-1.
|
||||
* Sequence numbers do not wrap. If a TLS
|
||||
* implementation would need to wrap a sequence number, it must
|
||||
* renegotiate instead.
|
||||
*/
|
||||
final boolean seqNumIsHuge() {
|
||||
/*
|
||||
* Conservatively, we should ask for renegotiation when there are
|
||||
* only 2^48 sequence numbers left.
|
||||
*/
|
||||
return (block != null && mac != null &&
|
||||
block[0] == (byte)0xFF && block[1] == (byte)0xFF);
|
||||
}
|
||||
|
||||
// increment the sequence number in the block array
|
||||
// it is a 64-bit number stored in big-endian format
|
||||
private void incrementSequenceNumber() {
|
||||
int k = 7;
|
||||
while ((k >= 0) && (++block[k] == 0)) {
|
||||
k--;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute based on either buffer type, either bb.position/limit
|
||||
* or buf/offset/len.
|
||||
*/
|
||||
private byte[] compute(byte type, ByteBuffer bb, byte[] buf,
|
||||
int offset, int len, boolean isSimulated) {
|
||||
|
||||
if (macSize == 0) {
|
||||
if (macAlg.size == 0) {
|
||||
return nullMAC;
|
||||
}
|
||||
|
||||
// MUST NOT increase the sequence number for a simulated computation.
|
||||
if (!isSimulated) {
|
||||
block[BLOCK_OFFSET_TYPE] = type;
|
||||
block[block.length - 2] = (byte)(len >> 8);
|
||||
block[block.length - 1] = (byte)(len );
|
||||
|
||||
mac.update(block);
|
||||
incrementSequenceNumber();
|
||||
byte[] additional =
|
||||
acquireAuthenticationBytes(type, bb.remaining());
|
||||
mac.update(additional);
|
||||
}
|
||||
|
||||
// content
|
||||
if (bb != null) {
|
||||
mac.update(bb);
|
||||
} else {
|
||||
mac.update(buf, offset, len);
|
||||
}
|
||||
|
||||
return mac.doFinal();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -54,6 +54,7 @@ class OutputRecord extends ByteArrayOutputStream implements Record {
|
||||
private int lastHashed;
|
||||
private boolean firstMessage;
|
||||
final private byte contentType;
|
||||
private int headerOffset;
|
||||
|
||||
// current protocol version, sent as record version
|
||||
ProtocolVersion protocolVersion;
|
||||
@ -70,6 +71,23 @@ class OutputRecord extends ByteArrayOutputStream implements Record {
|
||||
* Default constructor makes a record supporting the maximum
|
||||
* SSL record size. It allocates the header bytes directly.
|
||||
*
|
||||
* The structure of the byte buffer looks like:
|
||||
*
|
||||
* |---------+--------+-------+---------------------------------|
|
||||
* | unused | header | IV | content, MAC/TAG, padding, etc. |
|
||||
* | headerPlusMaxIVSize |
|
||||
*
|
||||
* unused: unused part of the buffer of size
|
||||
*
|
||||
* headerPlusMaxIVSize - header size - IV size
|
||||
*
|
||||
* When this object is created, we don't know the protocol
|
||||
* version number, IV length, etc., so reserve space in front
|
||||
* to avoid extra data movement (copies).
|
||||
* header: the header of an SSL record
|
||||
* IV: the optional IV/nonce field, it is only required for block
|
||||
* (TLS 1.1 or later) and AEAD cipher suites.
|
||||
*
|
||||
* @param type the content type for the record
|
||||
*/
|
||||
OutputRecord(byte type, int size) {
|
||||
@ -77,9 +95,10 @@ class OutputRecord extends ByteArrayOutputStream implements Record {
|
||||
this.protocolVersion = ProtocolVersion.DEFAULT;
|
||||
this.helloVersion = ProtocolVersion.DEFAULT_HELLO;
|
||||
firstMessage = true;
|
||||
count = headerSize;
|
||||
count = headerPlusMaxIVSize;
|
||||
contentType = type;
|
||||
lastHashed = count;
|
||||
headerOffset = headerPlusMaxIVSize - headerSize;
|
||||
}
|
||||
|
||||
OutputRecord(byte type) {
|
||||
@ -119,8 +138,9 @@ class OutputRecord extends ByteArrayOutputStream implements Record {
|
||||
@Override
|
||||
public synchronized void reset() {
|
||||
super.reset();
|
||||
count = headerSize;
|
||||
count = headerPlusMaxIVSize;
|
||||
lastHashed = count;
|
||||
headerOffset = headerPlusMaxIVSize - headerSize;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -173,58 +193,84 @@ class OutputRecord extends ByteArrayOutputStream implements Record {
|
||||
* of sending empty records over the network.
|
||||
*/
|
||||
boolean isEmpty() {
|
||||
return count == headerSize;
|
||||
return count == headerPlusMaxIVSize;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if the record is of a given alert.
|
||||
* Return true if the record is of an alert of the given description.
|
||||
*
|
||||
* Per SSL/TLS specifications, alert messages convey the severity of the
|
||||
* message (warning or fatal) and a description of the alert. An alert
|
||||
* is defined with a two bytes struct, {byte level, byte description},
|
||||
* following after the header bytes.
|
||||
*/
|
||||
boolean isAlert(byte description) {
|
||||
// An alert is defined with a two bytes struct,
|
||||
// {byte level, byte description}, following after the header bytes.
|
||||
if (count > (headerSize + 1) && contentType == ct_alert) {
|
||||
return buf[headerSize + 1] == description;
|
||||
if ((count > (headerPlusMaxIVSize + 1)) && (contentType == ct_alert)) {
|
||||
return buf[headerPlusMaxIVSize + 1] == description;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute the MAC and append it to this record. In case we
|
||||
* are automatically flushing a handshake stream, make sure we
|
||||
* have hashed the message first.
|
||||
* Encrypt ... length may grow due to block cipher padding, or
|
||||
* message authentication code or tag.
|
||||
*/
|
||||
void addMAC(MAC signer) throws IOException {
|
||||
void encrypt(Authenticator authenticator, CipherBox box)
|
||||
throws IOException {
|
||||
|
||||
// In case we are automatically flushing a handshake stream, make
|
||||
// sure we have hashed the message first.
|
||||
//
|
||||
// when we support compression, hashing can't go here
|
||||
// since it'll need to be done on the uncompressed data,
|
||||
// and the MAC applies to the compressed data.
|
||||
//
|
||||
if (contentType == ct_handshake) {
|
||||
doHashes();
|
||||
}
|
||||
|
||||
// Requires message authentication code for stream and block
|
||||
// cipher suites.
|
||||
if (authenticator instanceof MAC) {
|
||||
MAC signer = (MAC)authenticator;
|
||||
if (signer.MAClen() != 0) {
|
||||
byte[] hash = signer.compute(contentType, buf,
|
||||
headerSize, count - headerSize, false);
|
||||
headerPlusMaxIVSize, count - headerPlusMaxIVSize, false);
|
||||
write(hash);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Encrypt ... length may grow due to block cipher padding
|
||||
*/
|
||||
void encrypt(CipherBox box) {
|
||||
int len = count - headerSize;
|
||||
count = headerSize + box.encrypt(buf, headerSize, len);
|
||||
if (!box.isNullCipher()) {
|
||||
// Requires explicit IV/nonce for CBC/AEAD cipher suites for
|
||||
// TLS 1.1 or later.
|
||||
if ((protocolVersion.v >= ProtocolVersion.TLS11.v) &&
|
||||
(box.isCBCMode() || box.isAEADMode())) {
|
||||
byte[] nonce = box.createExplicitNonce(authenticator,
|
||||
contentType, count - headerPlusMaxIVSize);
|
||||
int offset = headerPlusMaxIVSize - nonce.length;
|
||||
System.arraycopy(nonce, 0, buf, offset, nonce.length);
|
||||
headerOffset = offset - headerSize;
|
||||
} else {
|
||||
headerOffset = headerPlusMaxIVSize - headerSize;
|
||||
}
|
||||
|
||||
// encrypt the content
|
||||
int offset = headerPlusMaxIVSize;
|
||||
if (!box.isAEADMode()) {
|
||||
// The explicit IV can be encrypted.
|
||||
offset = headerOffset + headerSize;
|
||||
} // Otherwise, DON'T encrypt the nonce_explicit for AEAD mode
|
||||
|
||||
count = offset + box.encrypt(buf, offset, count - offset);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Tell how full the buffer is ... for filling it with application or
|
||||
* handshake data.
|
||||
*/
|
||||
final int availableDataBytes() {
|
||||
int dataSize = count - headerSize;
|
||||
int dataSize = count - headerPlusMaxIVSize;
|
||||
return maxDataSize - dataSize;
|
||||
}
|
||||
|
||||
@ -270,11 +316,11 @@ class OutputRecord extends ByteArrayOutputStream implements Record {
|
||||
* Don't emit content-free records. (Even change cipher spec
|
||||
* messages have a byte of data!)
|
||||
*/
|
||||
if (count == headerSize) {
|
||||
if (count == headerPlusMaxIVSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
int length = count - headerSize;
|
||||
int length = count - headerOffset - headerSize;
|
||||
// "should" really never write more than about 14 Kb...
|
||||
if (length < 0) {
|
||||
throw new SSLException("output record size too small: "
|
||||
@ -299,7 +345,9 @@ class OutputRecord extends ByteArrayOutputStream implements Record {
|
||||
*/
|
||||
if (firstMessage && useV2Hello()) {
|
||||
byte[] v3Msg = new byte[length - 4];
|
||||
System.arraycopy(buf, headerSize + 4, v3Msg, 0, v3Msg.length);
|
||||
System.arraycopy(buf, headerPlusMaxIVSize + 4,
|
||||
v3Msg, 0, v3Msg.length);
|
||||
headerOffset = 0; // reset the header offset
|
||||
V3toV2ClientHello(v3Msg);
|
||||
handshakeHash.reset();
|
||||
lastHashed = 2;
|
||||
@ -314,11 +362,11 @@ class OutputRecord extends ByteArrayOutputStream implements Record {
|
||||
/*
|
||||
* Fill out the header, write it and the message.
|
||||
*/
|
||||
buf[0] = contentType;
|
||||
buf[1] = protocolVersion.major;
|
||||
buf[2] = protocolVersion.minor;
|
||||
buf[3] = (byte)(length >> 8);
|
||||
buf[4] = (byte)(length);
|
||||
buf[headerOffset + 0] = contentType;
|
||||
buf[headerOffset + 1] = protocolVersion.major;
|
||||
buf[headerOffset + 2] = protocolVersion.minor;
|
||||
buf[headerOffset + 3] = (byte)(length >> 8);
|
||||
buf[headerOffset + 4] = (byte)(length);
|
||||
}
|
||||
firstMessage = false;
|
||||
|
||||
@ -338,7 +386,8 @@ class OutputRecord extends ByteArrayOutputStream implements Record {
|
||||
* when holdRecord is true, the implementation in this class
|
||||
* will be used.
|
||||
*/
|
||||
writeBuffer(heldRecordBuffer, buf, 0, count, debugOffset);
|
||||
writeBuffer(heldRecordBuffer,
|
||||
buf, headerOffset, count - headerOffset, debugOffset);
|
||||
} else {
|
||||
// It's time to send, do we have buffered data?
|
||||
// May or may not have a heldRecordBuffer.
|
||||
@ -346,15 +395,18 @@ class OutputRecord extends ByteArrayOutputStream implements Record {
|
||||
int heldLen = heldRecordBuffer.size();
|
||||
|
||||
// Ensure the capacity of this buffer.
|
||||
ensureCapacity(count + heldLen);
|
||||
int newCount = count + heldLen - headerOffset;
|
||||
ensureCapacity(newCount);
|
||||
|
||||
// Slide everything in the buffer to the right.
|
||||
System.arraycopy(buf, 0, buf, heldLen, count);
|
||||
System.arraycopy(buf, headerOffset,
|
||||
buf, heldLen, count - headerOffset);
|
||||
|
||||
// Prepend the held record to the buffer.
|
||||
System.arraycopy(
|
||||
heldRecordBuffer.toByteArray(), 0, buf, 0, heldLen);
|
||||
count += heldLen;
|
||||
count = newCount;
|
||||
headerOffset = 0;
|
||||
|
||||
// Clear the held buffer.
|
||||
heldRecordBuffer.reset();
|
||||
@ -362,7 +414,8 @@ class OutputRecord extends ByteArrayOutputStream implements Record {
|
||||
// The held buffer has been dumped, set the debug dump offset.
|
||||
debugOffset = heldLen;
|
||||
}
|
||||
writeBuffer(s, buf, 0, count, debugOffset);
|
||||
writeBuffer(s, buf, headerOffset,
|
||||
count - headerOffset, debugOffset);
|
||||
}
|
||||
|
||||
reset();
|
||||
@ -382,12 +435,11 @@ class OutputRecord extends ByteArrayOutputStream implements Record {
|
||||
if (debug != null && Debug.isOn("packet")) {
|
||||
try {
|
||||
HexDumpEncoder hd = new HexDumpEncoder();
|
||||
ByteBuffer bb = ByteBuffer.wrap(
|
||||
buf, off + debugOffset, len - debugOffset);
|
||||
|
||||
System.out.println("[Raw write]: length = " +
|
||||
bb.remaining());
|
||||
hd.encodeBuffer(bb, System.out);
|
||||
(len - debugOffset));
|
||||
hd.encodeBuffer(new ByteArrayInputStream(buf,
|
||||
off + debugOffset, len - debugOffset), System.out);
|
||||
} catch (IOException e) { }
|
||||
}
|
||||
}
|
||||
@ -400,8 +452,13 @@ class OutputRecord extends ByteArrayOutputStream implements Record {
|
||||
return firstMessage
|
||||
&& (helloVersion == ProtocolVersion.SSL20Hello)
|
||||
&& (contentType == ct_handshake)
|
||||
&& (buf[5] == HandshakeMessage.ht_client_hello)
|
||||
&& (buf[headerSize + 4+2+32] == 0); // V3 session ID is empty
|
||||
&& (buf[headerOffset + 5] == HandshakeMessage.ht_client_hello)
|
||||
// 5: recode header size
|
||||
&& (buf[headerPlusMaxIVSize + 4 + 2 + 32] == 0);
|
||||
// V3 session ID is empty
|
||||
// 4: handshake header size
|
||||
// 2: client_version in ClientHello
|
||||
// 32: random in ClientHello
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 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
|
||||
@ -52,20 +52,29 @@ interface Record {
|
||||
static final int trailerSize = 20; // SHA1 hash size
|
||||
static final int maxDataSize = 16384; // 2^14 bytes of data
|
||||
static final int maxPadding = 256; // block cipher padding
|
||||
static final int maxIVLength = 256; // block length
|
||||
static final int maxIVLength = 256; // IV length
|
||||
|
||||
/*
|
||||
* The size of the header plus the max IV length
|
||||
*/
|
||||
static final int headerPlusMaxIVSize =
|
||||
headerSize // header
|
||||
+ maxIVLength; // iv
|
||||
|
||||
/*
|
||||
* SSL has a maximum record size. It's header, (compressed) data,
|
||||
* padding, and a trailer for the MAC.
|
||||
* padding, and a trailer for the message authentication information (MAC
|
||||
* for block and stream ciphers, and message authentication tag for AEAD
|
||||
* ciphers).
|
||||
*
|
||||
* Some compression algorithms have rare cases where they expand the data.
|
||||
* As we don't support compression at this time, leave that out.
|
||||
*/
|
||||
static final int maxRecordSize =
|
||||
headerSize // header
|
||||
+ maxIVLength // iv
|
||||
headerPlusMaxIVSize // header + iv
|
||||
+ maxDataSize // data
|
||||
+ maxPadding // padding
|
||||
+ trailerSize; // MAC
|
||||
+ trailerSize; // MAC or AEAD tag
|
||||
|
||||
static final boolean enableCBCProtection =
|
||||
Debug.getBooleanProperty("jsse.enableCBCProtection", true);
|
||||
@ -77,8 +86,7 @@ interface Record {
|
||||
static final int maxDataSizeMinusOneByteRecord =
|
||||
maxDataSize // max data size
|
||||
- ( // max one byte record size
|
||||
headerSize // header
|
||||
+ maxIVLength // iv
|
||||
headerPlusMaxIVSize // header + iv
|
||||
+ 1 // one byte data
|
||||
+ maxPadding // padding
|
||||
+ trailerSize // MAC
|
||||
@ -104,8 +112,7 @@ interface Record {
|
||||
* Allocate a smaller array.
|
||||
*/
|
||||
static final int maxAlertRecordSize =
|
||||
headerSize // header
|
||||
+ maxIVLength // iv
|
||||
headerPlusMaxIVSize // header + iv
|
||||
+ 2 // alert
|
||||
+ maxPadding // padding
|
||||
+ trailerSize; // MAC
|
||||
|
@ -280,7 +280,7 @@ final public class SSLEngineImpl extends SSLEngine {
|
||||
/*
|
||||
* Crypto state that's reinitialized when the session changes.
|
||||
*/
|
||||
private MAC readMAC, writeMAC;
|
||||
private Authenticator readAuthenticator, writeAuthenticator;
|
||||
private CipherBox readCipher, writeCipher;
|
||||
// NOTE: compression state would be saved here
|
||||
|
||||
@ -377,9 +377,9 @@ final public class SSLEngineImpl extends SSLEngine {
|
||||
* Note: compression support would go here too
|
||||
*/
|
||||
readCipher = CipherBox.NULL;
|
||||
readMAC = MAC.NULL;
|
||||
readAuthenticator = MAC.NULL;
|
||||
writeCipher = CipherBox.NULL;
|
||||
writeMAC = MAC.NULL;
|
||||
writeAuthenticator = MAC.NULL;
|
||||
|
||||
// default security parameters for secure renegotiation
|
||||
secureRenegotiation = false;
|
||||
@ -586,7 +586,7 @@ final public class SSLEngineImpl extends SSLEngine {
|
||||
|
||||
try {
|
||||
readCipher = handshaker.newReadCipher();
|
||||
readMAC = handshaker.newReadMAC();
|
||||
readAuthenticator = handshaker.newReadAuthenticator();
|
||||
} catch (GeneralSecurityException e) {
|
||||
// "can't happen"
|
||||
throw new SSLException("Algorithm missing: ", e);
|
||||
@ -622,7 +622,7 @@ final public class SSLEngineImpl extends SSLEngine {
|
||||
|
||||
try {
|
||||
writeCipher = handshaker.newWriteCipher();
|
||||
writeMAC = handshaker.newWriteMAC();
|
||||
writeAuthenticator = handshaker.newWriteAuthenticator();
|
||||
} catch (GeneralSecurityException e) {
|
||||
// "can't happen"
|
||||
throw new SSLException("Algorithm missing: ", e);
|
||||
@ -958,7 +958,8 @@ final public class SSLEngineImpl extends SSLEngine {
|
||||
* throw a fatal alert if the integrity check fails.
|
||||
*/
|
||||
try {
|
||||
decryptedBB = inputRecord.decrypt(readMAC, readCipher, readBB);
|
||||
decryptedBB = inputRecord.decrypt(
|
||||
readAuthenticator, readCipher, readBB);
|
||||
} catch (BadPaddingException e) {
|
||||
byte alertType = (inputRecord.contentType() ==
|
||||
Record.ct_handshake) ?
|
||||
@ -967,7 +968,6 @@ final public class SSLEngineImpl extends SSLEngine {
|
||||
fatal(alertType, e.getMessage(), e);
|
||||
}
|
||||
|
||||
|
||||
// if (!inputRecord.decompress(c))
|
||||
// fatal(Alerts.alert_decompression_failure,
|
||||
// "decompression failure");
|
||||
@ -1117,7 +1117,7 @@ final public class SSLEngineImpl extends SSLEngine {
|
||||
hsStatus = getHSStatus(hsStatus);
|
||||
if (connectionState < cs_ERROR && !isInboundDone() &&
|
||||
(hsStatus == HandshakeStatus.NOT_HANDSHAKING)) {
|
||||
if (checkSequenceNumber(readMAC,
|
||||
if (checkSequenceNumber(readAuthenticator,
|
||||
inputRecord.contentType())) {
|
||||
hsStatus = getHSStatus(null);
|
||||
}
|
||||
@ -1270,7 +1270,7 @@ final public class SSLEngineImpl extends SSLEngine {
|
||||
|
||||
// eventually compress as well.
|
||||
HandshakeStatus hsStatus =
|
||||
writer.writeRecord(eor, ea, writeMAC, writeCipher);
|
||||
writer.writeRecord(eor, ea, writeAuthenticator, writeCipher);
|
||||
|
||||
/*
|
||||
* We only need to check the sequence number state for
|
||||
@ -1287,7 +1287,7 @@ final public class SSLEngineImpl extends SSLEngine {
|
||||
hsStatus = getHSStatus(hsStatus);
|
||||
if (connectionState < cs_ERROR && !isOutboundDone() &&
|
||||
(hsStatus == HandshakeStatus.NOT_HANDSHAKING)) {
|
||||
if (checkSequenceNumber(writeMAC, eor.contentType())) {
|
||||
if (checkSequenceNumber(writeAuthenticator, eor.contentType())) {
|
||||
hsStatus = getHSStatus(null);
|
||||
}
|
||||
}
|
||||
@ -1326,7 +1326,7 @@ final public class SSLEngineImpl extends SSLEngine {
|
||||
*/
|
||||
void writeRecord(EngineOutputRecord eor) throws IOException {
|
||||
// eventually compress as well.
|
||||
writer.writeRecord(eor, writeMAC, writeCipher);
|
||||
writer.writeRecord(eor, writeAuthenticator, writeCipher);
|
||||
|
||||
/*
|
||||
* Check the sequence number state
|
||||
@ -1340,7 +1340,7 @@ final public class SSLEngineImpl extends SSLEngine {
|
||||
* of the last record cannot be wrapped.
|
||||
*/
|
||||
if ((connectionState < cs_ERROR) && !isOutboundDone()) {
|
||||
checkSequenceNumber(writeMAC, eor.contentType());
|
||||
checkSequenceNumber(writeAuthenticator, eor.contentType());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1358,14 +1358,14 @@ final public class SSLEngineImpl extends SSLEngine {
|
||||
*
|
||||
* Return true if the handshake status may be changed.
|
||||
*/
|
||||
private boolean checkSequenceNumber(MAC mac, byte type)
|
||||
private boolean checkSequenceNumber(Authenticator authenticator, byte type)
|
||||
throws IOException {
|
||||
|
||||
/*
|
||||
* Don't bother to check the sequence number for error or
|
||||
* closed connections, or NULL MAC
|
||||
*/
|
||||
if (connectionState >= cs_ERROR || mac == MAC.NULL) {
|
||||
if (connectionState >= cs_ERROR || authenticator == MAC.NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1373,7 +1373,7 @@ final public class SSLEngineImpl extends SSLEngine {
|
||||
* Conservatively, close the connection immediately when the
|
||||
* sequence number is close to overflow
|
||||
*/
|
||||
if (mac.seqNumOverflow()) {
|
||||
if (authenticator.seqNumOverflow()) {
|
||||
/*
|
||||
* TLS protocols do not define a error alert for sequence
|
||||
* number overflow. We use handshake_failure error alert
|
||||
@ -1396,7 +1396,7 @@ final public class SSLEngineImpl extends SSLEngine {
|
||||
* Don't bother to kickstart the renegotiation when the local is
|
||||
* asking for it.
|
||||
*/
|
||||
if ((type != Record.ct_handshake) && mac.seqNumIsHuge()) {
|
||||
if ((type != Record.ct_handshake) && authenticator.seqNumIsHuge()) {
|
||||
if (debug != null && Debug.isOn("ssl")) {
|
||||
System.out.println(Thread.currentThread().getName() +
|
||||
", request renegotiation " +
|
||||
|
@ -292,7 +292,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
|
||||
/*
|
||||
* Crypto state that's reinitialized when the session changes.
|
||||
*/
|
||||
private MAC readMAC, writeMAC;
|
||||
private Authenticator readAuthenticator, writeAuthenticator;
|
||||
private CipherBox readCipher, writeCipher;
|
||||
// NOTE: compression state would be saved here
|
||||
|
||||
@ -586,9 +586,9 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
|
||||
* Note: compression support would go here too
|
||||
*/
|
||||
readCipher = CipherBox.NULL;
|
||||
readMAC = MAC.NULL;
|
||||
readAuthenticator = MAC.NULL;
|
||||
writeCipher = CipherBox.NULL;
|
||||
writeMAC = MAC.NULL;
|
||||
writeAuthenticator = MAC.NULL;
|
||||
|
||||
// initial security parameters for secure renegotiation
|
||||
secureRenegotiation = false;
|
||||
@ -829,8 +829,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
|
||||
boolean holdRecord) throws IOException {
|
||||
|
||||
// r.compress(c);
|
||||
r.addMAC(writeMAC);
|
||||
r.encrypt(writeCipher);
|
||||
r.encrypt(writeAuthenticator, writeCipher);
|
||||
|
||||
if (holdRecord) {
|
||||
// If we were requested to delay the record due to possibility
|
||||
@ -861,7 +860,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
|
||||
* of the last record cannot be wrapped.
|
||||
*/
|
||||
if (connectionState < cs_ERROR) {
|
||||
checkSequenceNumber(writeMAC, r.contentType());
|
||||
checkSequenceNumber(writeAuthenticator, r.contentType());
|
||||
}
|
||||
|
||||
// turn off the flag of the first application record
|
||||
@ -986,7 +985,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
|
||||
* throw a fatal alert if the integrity check fails.
|
||||
*/
|
||||
try {
|
||||
r.decrypt(readMAC, readCipher);
|
||||
r.decrypt(readAuthenticator, readCipher);
|
||||
} catch (BadPaddingException e) {
|
||||
byte alertType = (r.contentType() == Record.ct_handshake)
|
||||
? Alerts.alert_handshake_failure
|
||||
@ -1143,7 +1142,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
|
||||
* of the last record cannot be wrapped.
|
||||
*/
|
||||
if (connectionState < cs_ERROR) {
|
||||
checkSequenceNumber(readMAC, r.contentType());
|
||||
checkSequenceNumber(readAuthenticator, r.contentType());
|
||||
}
|
||||
|
||||
return;
|
||||
@ -1166,14 +1165,14 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
|
||||
* implementation would need to wrap a sequence number, it must
|
||||
* renegotiate instead."
|
||||
*/
|
||||
private void checkSequenceNumber(MAC mac, byte type)
|
||||
private void checkSequenceNumber(Authenticator authenticator, byte type)
|
||||
throws IOException {
|
||||
|
||||
/*
|
||||
* Don't bother to check the sequence number for error or
|
||||
* closed connections, or NULL MAC.
|
||||
*/
|
||||
if (connectionState >= cs_ERROR || mac == MAC.NULL) {
|
||||
if (connectionState >= cs_ERROR || authenticator == MAC.NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1181,7 +1180,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
|
||||
* Conservatively, close the connection immediately when the
|
||||
* sequence number is close to overflow
|
||||
*/
|
||||
if (mac.seqNumOverflow()) {
|
||||
if (authenticator.seqNumOverflow()) {
|
||||
/*
|
||||
* TLS protocols do not define a error alert for sequence
|
||||
* number overflow. We use handshake_failure error alert
|
||||
@ -1203,7 +1202,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
|
||||
* Don't bother to kickstart the renegotiation when the local is
|
||||
* asking for it.
|
||||
*/
|
||||
if ((type != Record.ct_handshake) && mac.seqNumIsHuge()) {
|
||||
if ((type != Record.ct_handshake) && authenticator.seqNumIsHuge()) {
|
||||
if (debug != null && Debug.isOn("ssl")) {
|
||||
System.out.println(Thread.currentThread().getName() +
|
||||
", request renegotiation " +
|
||||
@ -2065,7 +2064,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
|
||||
|
||||
try {
|
||||
readCipher = handshaker.newReadCipher();
|
||||
readMAC = handshaker.newReadMAC();
|
||||
readAuthenticator = handshaker.newReadAuthenticator();
|
||||
} catch (GeneralSecurityException e) {
|
||||
// "can't happen"
|
||||
throw new SSLException("Algorithm missing: ", e);
|
||||
@ -2096,7 +2095,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
|
||||
|
||||
try {
|
||||
writeCipher = handshaker.newWriteCipher();
|
||||
writeMAC = handshaker.newWriteMAC();
|
||||
writeAuthenticator = handshaker.newWriteAuthenticator();
|
||||
} catch (GeneralSecurityException e) {
|
||||
// "can't happen"
|
||||
throw new SSLException("Algorithm missing: ", e);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* 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
|
||||
@ -21,6 +21,11 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
//
|
||||
// SunJSSE does not support dynamic system properties, no way to re-use
|
||||
// system properties in samevm/agentvm mode.
|
||||
//
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 6840752
|
||||
@ -30,7 +35,7 @@
|
||||
* @library ../pkcs11/sslecc
|
||||
* @library ../../../java/security/testlibrary
|
||||
* @compile -XDignore.symbol.file TestEC.java
|
||||
* @run main TestEC
|
||||
* @run main/othervm TestEC
|
||||
*/
|
||||
|
||||
import java.security.NoSuchProviderException;
|
||||
|
@ -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
|
||||
@ -147,6 +147,25 @@ public class CipherTest {
|
||||
CS_16("TLS_DH_anon_WITH_AES_128_CBC_SHA256", 0x0303, 0xFFFF),
|
||||
CS_17("TLS_RSA_WITH_NULL_SHA256", 0x0303, 0xFFFF),
|
||||
|
||||
CS_20("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF),
|
||||
CS_21("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF),
|
||||
CS_22("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF),
|
||||
CS_23("TLS_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF),
|
||||
CS_24("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF),
|
||||
CS_25("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF),
|
||||
CS_26("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF),
|
||||
CS_27("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF),
|
||||
|
||||
CS_28("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF),
|
||||
CS_29("TLS_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF),
|
||||
CS_30("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF),
|
||||
CS_31("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF),
|
||||
CS_32("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF),
|
||||
CS_33("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF),
|
||||
|
||||
CS_34("TLS_DH_anon_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF),
|
||||
CS_35("TLS_DH_anon_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF),
|
||||
|
||||
// cipher suites obsoleted since TLS 1.2
|
||||
CS_50("SSL_RSA_WITH_DES_CBC_SHA", 0x0000, 0x0303),
|
||||
CS_51("SSL_DHE_RSA_WITH_DES_CBC_SHA", 0x0000, 0x0303),
|
||||
|
@ -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
|
||||
@ -147,6 +147,25 @@ public class CipherTest {
|
||||
CS_16("TLS_DH_anon_WITH_AES_128_CBC_SHA256", 0x0303, 0xFFFF),
|
||||
CS_17("TLS_RSA_WITH_NULL_SHA256", 0x0303, 0xFFFF),
|
||||
|
||||
CS_20("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF),
|
||||
CS_21("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF),
|
||||
CS_22("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF),
|
||||
CS_23("TLS_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF),
|
||||
CS_24("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF),
|
||||
CS_25("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF),
|
||||
CS_26("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF),
|
||||
CS_27("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF),
|
||||
|
||||
CS_28("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF),
|
||||
CS_29("TLS_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF),
|
||||
CS_30("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF),
|
||||
CS_31("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF),
|
||||
CS_32("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF),
|
||||
CS_33("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF),
|
||||
|
||||
CS_34("TLS_DH_anon_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF),
|
||||
CS_35("TLS_DH_anon_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF),
|
||||
|
||||
// cipher suites obsoleted since TLS 1.2
|
||||
CS_50("SSL_RSA_WITH_DES_CBC_SHA", 0x0000, 0x0303),
|
||||
CS_51("SSL_DHE_RSA_WITH_DES_CBC_SHA", 0x0000, 0x0303),
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2012, 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
|
||||
@ -21,14 +21,16 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
//
|
||||
// SunJSSE does not support dynamic system properties, no way to re-use
|
||||
// system properties in samevm/agentvm mode.
|
||||
//
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 7031830
|
||||
* @summary bad_record_mac failure on TLSv1.2 enabled connection with SSLEngine
|
||||
* @run main/othervm SSLEngineBadBufferArrayAccess
|
||||
*
|
||||
* SunJSSE does not support dynamic system properties, no way to re-use
|
||||
* system properties in samevm/agentvm mode.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,445 @@
|
||||
/*
|
||||
* 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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// SunJSSE does not support dynamic system properties, no way to re-use
|
||||
// system properties in samevm/agentvm mode.
|
||||
//
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 7030966
|
||||
* @summary Support AEAD CipherSuites
|
||||
* @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
* @run main/othervm ShortRSAKeyGCM PKIX TLS_RSA_WITH_AES_128_GCM_SHA256
|
||||
* @run main/othervm ShortRSAKeyGCM PKIX TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
|
||||
* @run main/othervm ShortRSAKeyGCM PKIX TLS_DH_anon_WITH_AES_128_GCM_SHA256
|
||||
*/
|
||||
|
||||
/*
|
||||
* Need additional key materials to run the following cases.
|
||||
*
|
||||
* @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
|
||||
* @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
|
||||
* @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
|
||||
*
|
||||
* Need unlimited JCE Unlimited Strength Jurisdiction Policy to run the
|
||||
* following cases.
|
||||
*
|
||||
* @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
|
||||
* @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
|
||||
* @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
|
||||
* @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
|
||||
* @run main/othervm ShortRSAKeyGCM PKIX TLS_RSA_WITH_AES_256_GCM_SHA384
|
||||
* @run main/othervm ShortRSAKeyGCM PKIX TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
|
||||
* @run main/othervm ShortRSAKeyGCM PKIX TLS_DH_anon_WITH_AES_256_GCM_SHA384
|
||||
*/
|
||||
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
import javax.net.ssl.*;
|
||||
import java.security.Security;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.spec.*;
|
||||
import java.security.interfaces.*;
|
||||
import sun.misc.BASE64Decoder;
|
||||
|
||||
|
||||
public class ShortRSAKeyGCM {
|
||||
|
||||
/*
|
||||
* =============================================================
|
||||
* Set the various variables needed for the tests, then
|
||||
* specify what tests to run on each side.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Should we run the client or server in a separate thread?
|
||||
* Both sides can throw exceptions, but do you have a preference
|
||||
* as to which side should be the main thread.
|
||||
*/
|
||||
static boolean separateServerThread = true;
|
||||
|
||||
/*
|
||||
* Where do we find the keystores?
|
||||
*/
|
||||
// Certificates and key used in the test.
|
||||
static String trustedCertStr =
|
||||
"-----BEGIN CERTIFICATE-----\n" +
|
||||
"MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" +
|
||||
"MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
|
||||
"MTEwODE5MDE1MjE5WhcNMzIwNzI5MDE1MjE5WjA7MQswCQYDVQQGEwJVUzENMAsG\n" +
|
||||
"A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" +
|
||||
"KoZIhvcNAQEBBQADgY0AMIGJAoGBAM8orG08DtF98TMSscjGsidd1ZoN4jiDpi8U\n" +
|
||||
"ICz+9dMm1qM1d7O2T+KH3/mxyox7Rc2ZVSCaUD0a3CkhPMnlAx8V4u0H+E9sqso6\n" +
|
||||
"iDW3JpOyzMExvZiRgRG/3nvp55RMIUV4vEHOZ1QbhuqG4ebN0Vz2DkRft7+flthf\n" +
|
||||
"vDld6f5JAgMBAAGjgaUwgaIwHQYDVR0OBBYEFLl81dnfp0wDrv0OJ1sxlWzH83Xh\n" +
|
||||
"MGMGA1UdIwRcMFqAFLl81dnfp0wDrv0OJ1sxlWzH83XhoT+kPTA7MQswCQYDVQQG\n" +
|
||||
"EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" +
|
||||
"Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEE\n" +
|
||||
"BQADgYEALlgaH1gWtoBZ84EW8Hu6YtGLQ/L9zIFmHonUPZwn3Pr//icR9Sqhc3/l\n" +
|
||||
"pVTxOINuFHLRz4BBtEylzRIOPzK3tg8XwuLb1zd0db90x3KBCiAL6E6cklGEPwLe\n" +
|
||||
"XYMHDn9eDsaq861Tzn6ZwzMgw04zotPMoZN0mVd/3Qca8UJFucE=\n" +
|
||||
"-----END CERTIFICATE-----";
|
||||
|
||||
static String targetCertStr =
|
||||
"-----BEGIN CERTIFICATE-----\n" +
|
||||
"MIICNDCCAZ2gAwIBAgIBDDANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" +
|
||||
"MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
|
||||
"MTExMTA3MTM1NTUyWhcNMzEwNzI1MTM1NTUyWjBPMQswCQYDVQQGEwJVUzENMAsG\n" +
|
||||
"A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxEjAQBgNV\n" +
|
||||
"BAMTCWxvY2FsaG9zdDBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQC3Pb49OSPfOD2G\n" +
|
||||
"HSXFCFx1GJEZfqG9ZUf7xuIi/ra5dLjPGAaoY5QF2QOa8VnOriQCXDfyXHxsuRnE\n" +
|
||||
"OomxL7EVAgMBAAGjeDB2MAsGA1UdDwQEAwID6DAdBgNVHQ4EFgQUXNCJK3/dtCIc\n" +
|
||||
"xb+zlA/JINlvs/MwHwYDVR0jBBgwFoAUuXzV2d+nTAOu/Q4nWzGVbMfzdeEwJwYD\n" +
|
||||
"VR0lBCAwHgYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEFBQcDAzANBgkqhkiG9w0B\n" +
|
||||
"AQQFAAOBgQB2qIDUxA2caMPpGtUACZAPRUtrGssCINIfItETXJZCx/cRuZ5sP4D9\n" +
|
||||
"N1acoNDn0hCULe3lhXAeTC9NZ97680yJzregQMV5wATjo1FGsKY30Ma+sc/nfzQW\n" +
|
||||
"+h/7RhYtoG0OTsiaDCvyhI6swkNJzSzrAccPY4+ZgU8HiDLzZTmM3Q==\n" +
|
||||
"-----END CERTIFICATE-----";
|
||||
|
||||
// Private key in the format of PKCS#8, key size is 512 bits.
|
||||
static String targetPrivateKey =
|
||||
"MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAtz2+PTkj3zg9hh0l\n" +
|
||||
"xQhcdRiRGX6hvWVH+8biIv62uXS4zxgGqGOUBdkDmvFZzq4kAlw38lx8bLkZxDqJ\n" +
|
||||
"sS+xFQIDAQABAkByx/5Oo2hQ/w2q4L8z+NTRlJ3vdl8iIDtC/4XPnfYfnGptnpG6\n" +
|
||||
"ZThQRvbMZiai0xHQPQMszvAHjZVme1eDl3EBAiEA3aKJHynPVCEJhpfCLWuMwX5J\n" +
|
||||
"1LntwJO7NTOyU5m8rPECIQDTpzn5X44r2rzWBDna/Sx7HW9IWCxNgUD2Eyi2nA7W\n" +
|
||||
"ZQIgJerEorw4aCAuzQPxiGu57PB6GRamAihEAtoRTBQlH0ECIQDN08FgTtnesgCU\n" +
|
||||
"DFYLLcw1CiHvc7fZw4neBDHCrC8NtQIgA8TOUkGnpCZlQ0KaI8KfKWI+vxFcgFnH\n" +
|
||||
"3fnqsTgaUs4=";
|
||||
|
||||
static char passphrase[] = "passphrase".toCharArray();
|
||||
|
||||
/*
|
||||
* Is the server ready to serve?
|
||||
*/
|
||||
volatile static boolean serverReady = false;
|
||||
|
||||
/*
|
||||
* Turn on SSL debugging?
|
||||
*/
|
||||
static boolean debug = false;
|
||||
|
||||
/*
|
||||
* Define the server side of the test.
|
||||
*
|
||||
* If the server prematurely exits, serverReady will be set to true
|
||||
* to avoid infinite hangs.
|
||||
*/
|
||||
void doServerSide() throws Exception {
|
||||
SSLContext context = generateSSLContext(null, targetCertStr,
|
||||
targetPrivateKey);
|
||||
SSLServerSocketFactory sslssf = context.getServerSocketFactory();
|
||||
SSLServerSocket sslServerSocket =
|
||||
(SSLServerSocket)sslssf.createServerSocket(serverPort);
|
||||
serverPort = sslServerSocket.getLocalPort();
|
||||
|
||||
/*
|
||||
* Signal Client, we're ready for his connect.
|
||||
*/
|
||||
serverReady = true;
|
||||
|
||||
SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept();
|
||||
sslSocket.setEnabledCipherSuites(sslSocket.getSupportedCipherSuites());
|
||||
InputStream sslIS = sslSocket.getInputStream();
|
||||
OutputStream sslOS = sslSocket.getOutputStream();
|
||||
|
||||
sslIS.read();
|
||||
sslOS.write('A');
|
||||
sslOS.flush();
|
||||
|
||||
sslSocket.close();
|
||||
}
|
||||
|
||||
/*
|
||||
* Define the client side of the test.
|
||||
*
|
||||
* If the server prematurely exits, serverReady will be set to true
|
||||
* to avoid infinite hangs.
|
||||
*/
|
||||
void doClientSide() throws Exception {
|
||||
|
||||
/*
|
||||
* Wait for server to get started.
|
||||
*/
|
||||
while (!serverReady) {
|
||||
Thread.sleep(50);
|
||||
}
|
||||
|
||||
SSLContext context = generateSSLContext(trustedCertStr, null, null);
|
||||
SSLSocketFactory sslsf = context.getSocketFactory();
|
||||
|
||||
SSLSocket sslSocket =
|
||||
(SSLSocket)sslsf.createSocket("localhost", serverPort);
|
||||
|
||||
// enable TLSv1.2 only
|
||||
sslSocket.setEnabledProtocols(new String[] {"TLSv1.2"});
|
||||
|
||||
// enable a block cipher
|
||||
sslSocket.setEnabledCipherSuites(new String[] {cipherSuite});
|
||||
|
||||
InputStream sslIS = sslSocket.getInputStream();
|
||||
OutputStream sslOS = sslSocket.getOutputStream();
|
||||
|
||||
sslOS.write('B');
|
||||
sslOS.flush();
|
||||
sslIS.read();
|
||||
|
||||
sslSocket.close();
|
||||
}
|
||||
|
||||
/*
|
||||
* =============================================================
|
||||
* The remainder is just support stuff
|
||||
*/
|
||||
private static String tmAlgorithm; // trust manager
|
||||
private static String cipherSuite; // cipher suite
|
||||
|
||||
private static void parseArguments(String[] args) {
|
||||
tmAlgorithm = args[0];
|
||||
cipherSuite = args[1];
|
||||
}
|
||||
|
||||
private static SSLContext generateSSLContext(String trustedCertStr,
|
||||
String keyCertStr, String keySpecStr) throws Exception {
|
||||
|
||||
// generate certificate from cert string
|
||||
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||
|
||||
// create a key store
|
||||
KeyStore ks = KeyStore.getInstance("JKS");
|
||||
ks.load(null, null);
|
||||
|
||||
// import the trused cert
|
||||
Certificate trusedCert = null;
|
||||
ByteArrayInputStream is = null;
|
||||
if (trustedCertStr != null) {
|
||||
is = new ByteArrayInputStream(trustedCertStr.getBytes());
|
||||
trusedCert = cf.generateCertificate(is);
|
||||
is.close();
|
||||
|
||||
ks.setCertificateEntry("RSA Export Signer", trusedCert);
|
||||
}
|
||||
|
||||
if (keyCertStr != null) {
|
||||
// generate the private key.
|
||||
PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
|
||||
new BASE64Decoder().decodeBuffer(keySpecStr));
|
||||
KeyFactory kf = KeyFactory.getInstance("RSA");
|
||||
RSAPrivateKey priKey =
|
||||
(RSAPrivateKey)kf.generatePrivate(priKeySpec);
|
||||
|
||||
// generate certificate chain
|
||||
is = new ByteArrayInputStream(keyCertStr.getBytes());
|
||||
Certificate keyCert = cf.generateCertificate(is);
|
||||
is.close();
|
||||
|
||||
Certificate[] chain = null;
|
||||
if (trusedCert != null) {
|
||||
chain = new Certificate[2];
|
||||
chain[0] = keyCert;
|
||||
chain[1] = trusedCert;
|
||||
} else {
|
||||
chain = new Certificate[1];
|
||||
chain[0] = keyCert;
|
||||
}
|
||||
|
||||
// import the key entry.
|
||||
ks.setKeyEntry("Whatever", priKey, passphrase, chain);
|
||||
}
|
||||
|
||||
// create SSL context
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm);
|
||||
tmf.init(ks);
|
||||
|
||||
SSLContext ctx = SSLContext.getInstance("TLS");
|
||||
if (keyCertStr != null && !keyCertStr.isEmpty()) {
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
|
||||
kmf.init(ks, passphrase);
|
||||
|
||||
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
|
||||
ks = null;
|
||||
} else {
|
||||
ctx.init(null, tmf.getTrustManagers(), null);
|
||||
}
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
||||
// use any free port by default
|
||||
volatile int serverPort = 0;
|
||||
|
||||
volatile Exception serverException = null;
|
||||
volatile Exception clientException = null;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
// reset the security property to make sure that the algorithms
|
||||
// and keys used in this test are not disabled.
|
||||
Security.setProperty("jdk.certpath.disabledAlgorithms", "MD2");
|
||||
|
||||
if (debug) {
|
||||
System.setProperty("javax.net.debug", "all");
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the customized arguments.
|
||||
*/
|
||||
parseArguments(args);
|
||||
|
||||
/*
|
||||
* Start the tests.
|
||||
*/
|
||||
new ShortRSAKeyGCM();
|
||||
}
|
||||
|
||||
Thread clientThread = null;
|
||||
Thread serverThread = null;
|
||||
|
||||
/*
|
||||
* Primary constructor, used to drive remainder of the test.
|
||||
*
|
||||
* Fork off the other side, then do your work.
|
||||
*/
|
||||
ShortRSAKeyGCM() throws Exception {
|
||||
try {
|
||||
if (separateServerThread) {
|
||||
startServer(true);
|
||||
startClient(false);
|
||||
} else {
|
||||
startClient(true);
|
||||
startServer(false);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// swallow for now. Show later
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for other side to close down.
|
||||
*/
|
||||
if (separateServerThread) {
|
||||
serverThread.join();
|
||||
} else {
|
||||
clientThread.join();
|
||||
}
|
||||
|
||||
/*
|
||||
* When we get here, the test is pretty much over.
|
||||
* Which side threw the error?
|
||||
*/
|
||||
Exception local;
|
||||
Exception remote;
|
||||
String whichRemote;
|
||||
|
||||
if (separateServerThread) {
|
||||
remote = serverException;
|
||||
local = clientException;
|
||||
whichRemote = "server";
|
||||
} else {
|
||||
remote = clientException;
|
||||
local = serverException;
|
||||
whichRemote = "client";
|
||||
}
|
||||
|
||||
/*
|
||||
* If both failed, return the curthread's exception, but also
|
||||
* print the remote side Exception
|
||||
*/
|
||||
if ((local != null) && (remote != null)) {
|
||||
System.out.println(whichRemote + " also threw:");
|
||||
remote.printStackTrace();
|
||||
System.out.println();
|
||||
throw local;
|
||||
}
|
||||
|
||||
if (remote != null) {
|
||||
throw remote;
|
||||
}
|
||||
|
||||
if (local != null) {
|
||||
throw local;
|
||||
}
|
||||
}
|
||||
|
||||
void startServer(boolean newThread) throws Exception {
|
||||
if (newThread) {
|
||||
serverThread = new Thread() {
|
||||
public void run() {
|
||||
try {
|
||||
doServerSide();
|
||||
} catch (Exception e) {
|
||||
/*
|
||||
* Our server thread just died.
|
||||
*
|
||||
* Release the client, if not active already...
|
||||
*/
|
||||
System.err.println("Server died..." + e);
|
||||
serverReady = true;
|
||||
serverException = e;
|
||||
}
|
||||
}
|
||||
};
|
||||
serverThread.start();
|
||||
} else {
|
||||
try {
|
||||
doServerSide();
|
||||
} catch (Exception e) {
|
||||
serverException = e;
|
||||
} finally {
|
||||
serverReady = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void startClient(boolean newThread) throws Exception {
|
||||
if (newThread) {
|
||||
clientThread = new Thread() {
|
||||
public void run() {
|
||||
try {
|
||||
doClientSide();
|
||||
} catch (Exception e) {
|
||||
/*
|
||||
* Our client thread just died.
|
||||
*/
|
||||
System.err.println("Client died..." + e);
|
||||
clientException = e;
|
||||
}
|
||||
}
|
||||
};
|
||||
clientThread.start();
|
||||
} else {
|
||||
try {
|
||||
doClientSide();
|
||||
} catch (Exception e) {
|
||||
clientException = e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
@ -21,13 +21,15 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
//
|
||||
// SunJSSE does not support dynamic system properties, no way to re-use
|
||||
// system properties in samevm/agentvm mode.
|
||||
//
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 7174244
|
||||
* @summary NPE in Krb5ProxyImpl.getServerKeys()
|
||||
*
|
||||
* SunJSSE does not support dynamic system properties, no way to re-use
|
||||
* system properties in samevm/agentvm mode.
|
||||
* @run main/othervm CipherSuitesInOrder
|
||||
*/
|
||||
|
||||
@ -72,6 +74,22 @@ public class CipherSuitesInOrder {
|
||||
"SSL_RSA_WITH_RC4_128_SHA",
|
||||
"TLS_ECDH_ECDSA_WITH_RC4_128_SHA",
|
||||
"TLS_ECDH_RSA_WITH_RC4_128_SHA",
|
||||
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_DHE_DSS_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||
"TLS_DHE_DSS_WITH_AES_128_GCM_SHA256",
|
||||
|
||||
"TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"SSL_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
@ -83,6 +101,9 @@ public class CipherSuitesInOrder {
|
||||
|
||||
"TLS_EMPTY_RENEGOTIATION_INFO_SCSV",
|
||||
|
||||
"TLS_DH_anon_WITH_AES_256_GCM_SHA384",
|
||||
"TLS_DH_anon_WITH_AES_128_GCM_SHA256",
|
||||
|
||||
"TLS_DH_anon_WITH_AES_256_CBC_SHA256",
|
||||
"TLS_ECDH_anon_WITH_AES_256_CBC_SHA",
|
||||
"TLS_DH_anon_WITH_AES_256_CBC_SHA",
|
||||
|
@ -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
|
||||
@ -148,6 +148,25 @@ public class CipherTest {
|
||||
CS_16("TLS_DH_anon_WITH_AES_128_CBC_SHA256", 0x0303, 0xFFFF),
|
||||
CS_17("TLS_RSA_WITH_NULL_SHA256", 0x0303, 0xFFFF),
|
||||
|
||||
CS_20("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF),
|
||||
CS_21("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF),
|
||||
CS_22("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF),
|
||||
CS_23("TLS_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF),
|
||||
CS_24("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF),
|
||||
CS_25("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF),
|
||||
CS_26("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF),
|
||||
CS_27("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF),
|
||||
|
||||
CS_28("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF),
|
||||
CS_29("TLS_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF),
|
||||
CS_30("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF),
|
||||
CS_31("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF),
|
||||
CS_32("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF),
|
||||
CS_33("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF),
|
||||
|
||||
CS_34("TLS_DH_anon_WITH_AES_256_GCM_SHA384", 0x0303, 0xFFFF),
|
||||
CS_35("TLS_DH_anon_WITH_AES_128_GCM_SHA256", 0x0303, 0xFFFF),
|
||||
|
||||
// cipher suites obsoleted since TLS 1.2
|
||||
CS_50("SSL_RSA_WITH_DES_CBC_SHA", 0x0000, 0x0303),
|
||||
CS_51("SSL_DHE_RSA_WITH_DES_CBC_SHA", 0x0000, 0x0303),
|
||||
|
@ -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
|
||||
@ -21,14 +21,15 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
//
|
||||
// SunJSSE does not support dynamic system properties, no way to re-use
|
||||
// system properties in samevm/agentvm mode.
|
||||
//
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 7105780
|
||||
* @summary Add SSLSocket client/SSLEngine server to templates directory.
|
||||
*
|
||||
* SunJSSE does not support dynamic system properties, no way to re-use
|
||||
* system properties in samevm/agentvm mode.
|
||||
*
|
||||
* @run main/othervm SSLSocketSSLEngineTemplate
|
||||
*/
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user