|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.security.ssl; |
|
|
|
import java.nio.ByteBuffer; |
|
import java.security.InvalidKeyException; |
|
import java.security.NoSuchAlgorithmException; |
|
import java.util.Arrays; |
|
import javax.crypto.Mac; |
|
import javax.crypto.SecretKey; |
|
import sun.security.ssl.CipherSuite.MacAlg; |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
abstract class Authenticator { |
|
// byte array containing the additional authentication information for |
|
// each record |
|
protected final byte[] block; |
|
|
|
private Authenticator(byte[] block) { |
|
this.block = block; |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
static Authenticator valueOf(ProtocolVersion protocolVersion) { |
|
if (protocolVersion.isDTLS) { |
|
if (protocolVersion.useTLS13PlusSpec()) { |
|
return new DTLS13Authenticator(protocolVersion); |
|
} else { |
|
return new DTLS10Authenticator(protocolVersion); |
|
} |
|
} else { |
|
if (protocolVersion.useTLS13PlusSpec()) { |
|
return new TLS13Authenticator(protocolVersion); |
|
} else if (protocolVersion.useTLS10PlusSpec()) { |
|
return new TLS10Authenticator(protocolVersion); |
|
} else { |
|
return new SSL30Authenticator(); |
|
} |
|
} |
|
} |
|
|
|
@SuppressWarnings({"unchecked"}) |
|
static <T extends Authenticator & MAC> T |
|
valueOf(ProtocolVersion protocolVersion, MacAlg macAlg, |
|
SecretKey key) throws NoSuchAlgorithmException, |
|
InvalidKeyException { |
|
if (protocolVersion.isDTLS) { |
|
if (protocolVersion.useTLS13PlusSpec()) { |
|
throw new RuntimeException("No MacAlg used in DTLS 1.3"); |
|
} else { |
|
return (T)(new DTLS10Mac(protocolVersion, macAlg, key)); |
|
} |
|
} else { |
|
if (protocolVersion.useTLS13PlusSpec()) { |
|
throw new RuntimeException("No MacAlg used in TLS 1.3"); |
|
} else if (protocolVersion.useTLS10PlusSpec()) { |
|
return (T)(new TLS10Mac(protocolVersion, macAlg, key)); |
|
} else { |
|
return (T)(new SSL30Mac(protocolVersion, macAlg, key)); |
|
} |
|
} |
|
} |
|
|
|
static Authenticator nullTlsMac() { |
|
return new SSLNullMac(); |
|
} |
|
|
|
static Authenticator nullDtlsMac() { |
|
return new DTLSNullMac(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
abstract boolean seqNumOverflow(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
abstract boolean seqNumIsHuge(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
final byte[] sequenceNumber() { |
|
return Arrays.copyOf(block, 8); |
|
} |
|
|
|
|
|
|
|
*/ |
|
void setEpochNumber(int epoch) { |
|
throw new UnsupportedOperationException( |
|
"Epoch numbers apply to DTLS protocols only"); |
|
} |
|
|
|
|
|
|
|
*/ |
|
final void increaseSequenceNumber() { |
|
|
|
|
|
|
|
*/ |
|
int k = 7; |
|
while ((k >= 0) && (++block[k] == 0)) { |
|
k--; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
byte[] acquireAuthenticationBytes( |
|
byte type, int length, byte[] sequence) { |
|
throw new UnsupportedOperationException("Used by AEAD algorithms only"); |
|
} |
|
|
|
private static class SSLAuthenticator extends Authenticator { |
|
private SSLAuthenticator(byte[] block) { |
|
super(block); |
|
} |
|
|
|
@Override |
|
boolean seqNumOverflow() { |
|
|
|
|
|
|
|
*/ |
|
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); |
|
} |
|
|
|
@Override |
|
boolean seqNumIsHuge() { |
|
return (block.length != 0 && |
|
block[0] == (byte)0xFF && block[1] == (byte)0xFF && |
|
block[2] == (byte)0xFF && block[3] == (byte)0xFF); |
|
} |
|
} |
|
|
|
|
|
private static class SSLNullAuthenticator extends SSLAuthenticator { |
|
private SSLNullAuthenticator() { |
|
super(new byte[8]); |
|
} |
|
} |
|
|
|
|
|
private static class SSL30Authenticator extends SSLAuthenticator { |
|
// Block size of SSL v3.0: |
|
// sequence number + record type + + record length |
|
private static final int BLOCK_SIZE = 11; |
|
|
|
private SSL30Authenticator() { |
|
super(new byte[BLOCK_SIZE]); |
|
} |
|
|
|
@Override |
|
byte[] acquireAuthenticationBytes( |
|
byte type, int length, byte[] sequence) { |
|
byte[] ad = block.clone(); |
|
|
|
|
|
increaseSequenceNumber(); |
|
|
|
ad[8] = type; |
|
ad[9] = (byte)(length >> 8); |
|
ad[10] = (byte)(length); |
|
|
|
return ad; |
|
} |
|
} |
|
|
|
|
|
private static class TLS10Authenticator extends SSLAuthenticator { |
|
// Block size of TLS v1.0/1.1/1.2. |
|
// sequence number + record type + protocol version + record length |
|
private static final int BLOCK_SIZE = 13; |
|
|
|
private TLS10Authenticator(ProtocolVersion protocolVersion) { |
|
super(new byte[BLOCK_SIZE]); |
|
block[9] = protocolVersion.major; |
|
block[10] = protocolVersion.minor; |
|
} |
|
|
|
@Override |
|
byte[] acquireAuthenticationBytes( |
|
byte type, int length, byte[] sequence) { |
|
byte[] ad = block.clone(); |
|
if (sequence != null) { |
|
if (sequence.length != 8) { |
|
throw new RuntimeException( |
|
"Insufficient explicit sequence number bytes"); |
|
} |
|
|
|
System.arraycopy(sequence, 0, ad, 0, sequence.length); |
|
} else { // Otherwise, use the implicit sequence number. |
|
|
|
increaseSequenceNumber(); |
|
} |
|
|
|
ad[8] = type; |
|
ad[11] = (byte)(length >> 8); |
|
ad[12] = (byte)(length); |
|
|
|
return ad; |
|
} |
|
} |
|
|
|
|
|
private static final class TLS13Authenticator extends SSLAuthenticator { |
|
// Block size of TLS v1.3: |
|
// record type + protocol version + record length + sequence number |
|
private static final int BLOCK_SIZE = 13; |
|
|
|
private TLS13Authenticator(ProtocolVersion protocolVersion) { |
|
super(new byte[BLOCK_SIZE]); |
|
block[9] = ProtocolVersion.TLS12.major; |
|
block[10] = ProtocolVersion.TLS12.minor; |
|
} |
|
|
|
@Override |
|
byte[] acquireAuthenticationBytes( |
|
byte type, int length, byte[] sequence) { |
|
byte[] ad = Arrays.copyOfRange(block, 8, 13); |
|
|
|
|
|
increaseSequenceNumber(); |
|
|
|
ad[0] = type; |
|
ad[3] = (byte)(length >> 8); |
|
ad[4] = (byte)(length & 0xFF); |
|
|
|
return ad; |
|
} |
|
} |
|
|
|
private static class DTLSAuthenticator extends Authenticator { |
|
private DTLSAuthenticator(byte[] block) { |
|
super(block); |
|
} |
|
|
|
@Override |
|
boolean seqNumOverflow() { |
|
|
|
|
|
|
|
*/ |
|
return (block.length != 0 && |
|
|
|
block[2] == (byte)0xFF && block[3] == (byte)0xFF && |
|
block[4] == (byte)0xFF && block[5] == (byte)0xFF && |
|
block[6] == (byte)0xFF); |
|
} |
|
|
|
@Override |
|
boolean seqNumIsHuge() { |
|
return (block.length != 0 && |
|
|
|
block[2] == (byte)0xFF && block[3] == (byte)0xFF); |
|
} |
|
|
|
@Override |
|
void setEpochNumber(int epoch) { |
|
block[0] = (byte)((epoch >> 8) & 0xFF); |
|
block[1] = (byte)(epoch & 0xFF); |
|
} |
|
} |
|
|
|
|
|
private static class DTLSNullAuthenticator extends DTLSAuthenticator { |
|
private DTLSNullAuthenticator() { |
|
// For DTLS protocols, plaintexts use explicit epoch and |
|
// sequence number in each record. The first 8 byte of |
|
// the block is initialized for null MAC so that the |
|
// epoch and sequence number can be acquired to generate |
|
|
|
super(new byte[8]); |
|
} |
|
} |
|
|
|
|
|
private static class DTLS10Authenticator extends DTLSAuthenticator { |
|
// Block size of DTLS v1.0 and later: |
|
// epoch + sequence number + |
|
// record type + protocol version + record length |
|
private static final int BLOCK_SIZE = 13; |
|
|
|
private DTLS10Authenticator(ProtocolVersion protocolVersion) { |
|
super(new byte[BLOCK_SIZE]); |
|
block[9] = protocolVersion.major; |
|
block[10] = protocolVersion.minor; |
|
} |
|
|
|
@Override |
|
byte[] acquireAuthenticationBytes( |
|
byte type, int length, byte[] sequence) { |
|
byte[] ad = block.clone(); |
|
if (sequence != null) { |
|
if (sequence.length != 8) { |
|
throw new RuntimeException( |
|
"Insufficient explicit sequence number bytes"); |
|
} |
|
|
|
System.arraycopy(sequence, 0, ad, 0, sequence.length); |
|
} else { // Otherwise, use the implicit sequence number. |
|
|
|
increaseSequenceNumber(); |
|
} |
|
|
|
ad[8] = type; |
|
ad[11] = (byte)(length >> 8); |
|
ad[12] = (byte)(length); |
|
|
|
return ad; |
|
} |
|
} |
|
|
|
|
|
private static final class DTLS13Authenticator extends DTLSAuthenticator { |
|
// Block size of DTLS v1.0 and later: |
|
// epoch + sequence number + |
|
// record type + protocol version + record length |
|
private static final int BLOCK_SIZE = 13; |
|
|
|
private DTLS13Authenticator(ProtocolVersion protocolVersion) { |
|
super(new byte[BLOCK_SIZE]); |
|
block[9] = ProtocolVersion.TLS12.major; |
|
block[10] = ProtocolVersion.TLS12.minor; |
|
} |
|
|
|
@Override |
|
byte[] acquireAuthenticationBytes( |
|
byte type, int length, byte[] sequence) { |
|
byte[] ad = Arrays.copyOfRange(block, 8, 13); |
|
|
|
|
|
increaseSequenceNumber(); |
|
|
|
ad[0] = type; |
|
ad[3] = (byte)(length >> 8); |
|
ad[4] = (byte)(length & 0xFF); |
|
|
|
return ad; |
|
} |
|
} |
|
|
|
interface MAC { |
|
MacAlg macAlg(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
byte[] compute(byte type, ByteBuffer bb, |
|
byte[] sequence, boolean isSimulated); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
default byte[] compute(byte type, ByteBuffer bb, boolean isSimulated) { |
|
return compute(type, bb, null, isSimulated); |
|
} |
|
} |
|
|
|
private class MacImpl implements MAC { |
|
|
|
private final MacAlg macAlg; |
|
|
|
|
|
private final Mac mac; |
|
|
|
private MacImpl() { |
|
macAlg = MacAlg.M_NULL; |
|
mac = null; |
|
} |
|
|
|
private MacImpl(ProtocolVersion protocolVersion, MacAlg macAlg, |
|
SecretKey key) throws NoSuchAlgorithmException, |
|
InvalidKeyException { |
|
if (macAlg == null) { |
|
throw new RuntimeException("Null MacAlg"); |
|
} |
|
|
|
|
|
boolean useSSLMac = (protocolVersion.id < ProtocolVersion.TLS10.id); |
|
String algorithm; |
|
switch (macAlg) { |
|
case M_MD5: |
|
algorithm = useSSLMac ? "SslMacMD5" : "HmacMD5"; |
|
break; |
|
case M_SHA: |
|
algorithm = useSSLMac ? "SslMacSHA1" : "HmacSHA1"; |
|
break; |
|
case M_SHA256: |
|
algorithm = "HmacSHA256"; |
|
break; |
|
case M_SHA384: |
|
algorithm = "HmacSHA384"; |
|
break; |
|
default: |
|
throw new RuntimeException("Unknown MacAlg " + macAlg); |
|
} |
|
|
|
Mac m = JsseJce.getMac(algorithm); |
|
m.init(key); |
|
this.macAlg = macAlg; |
|
this.mac = m; |
|
} |
|
|
|
@Override |
|
public MacAlg macAlg() { |
|
return macAlg; |
|
} |
|
|
|
@Override |
|
public byte[] compute(byte type, ByteBuffer bb, |
|
byte[] sequence, boolean isSimulated) { |
|
|
|
if (macAlg.size == 0) { |
|
return new byte[0]; |
|
} |
|
|
|
if (!isSimulated) { |
|
|
|
byte[] additional = |
|
acquireAuthenticationBytes(type, bb.remaining(), sequence); |
|
mac.update(additional); |
|
} |
|
mac.update(bb); |
|
|
|
return mac.doFinal(); |
|
} |
|
} |
|
|
|
|
|
private static final |
|
class SSLNullMac extends SSLNullAuthenticator implements MAC { |
|
private final MacImpl macImpl; |
|
public SSLNullMac() { |
|
super(); |
|
this.macImpl = new MacImpl(); |
|
} |
|
|
|
@Override |
|
public MacAlg macAlg() { |
|
return macImpl.macAlg; |
|
} |
|
|
|
@Override |
|
public byte[] compute(byte type, ByteBuffer bb, |
|
byte[] sequence, boolean isSimulated) { |
|
return macImpl.compute(type, bb, sequence, isSimulated); |
|
} |
|
} |
|
|
|
|
|
private static final |
|
class SSL30Mac extends SSL30Authenticator implements MAC { |
|
private final MacImpl macImpl; |
|
public SSL30Mac(ProtocolVersion protocolVersion, |
|
MacAlg macAlg, SecretKey key) throws NoSuchAlgorithmException, |
|
InvalidKeyException { |
|
super(); |
|
this.macImpl = new MacImpl(protocolVersion, macAlg, key); |
|
} |
|
|
|
@Override |
|
public MacAlg macAlg() { |
|
return macImpl.macAlg; |
|
} |
|
|
|
@Override |
|
public byte[] compute(byte type, ByteBuffer bb, |
|
byte[] sequence, boolean isSimulated) { |
|
return macImpl.compute(type, bb, sequence, isSimulated); |
|
} |
|
} |
|
|
|
|
|
private static final |
|
class TLS10Mac extends TLS10Authenticator implements MAC { |
|
private final MacImpl macImpl; |
|
public TLS10Mac(ProtocolVersion protocolVersion, |
|
MacAlg macAlg, SecretKey key) throws NoSuchAlgorithmException, |
|
InvalidKeyException { |
|
super(protocolVersion); |
|
this.macImpl = new MacImpl(protocolVersion, macAlg, key); |
|
} |
|
|
|
@Override |
|
public MacAlg macAlg() { |
|
return macImpl.macAlg; |
|
} |
|
|
|
@Override |
|
public byte[] compute(byte type, ByteBuffer bb, |
|
byte[] sequence, boolean isSimulated) { |
|
return macImpl.compute(type, bb, sequence, isSimulated); |
|
} |
|
} |
|
|
|
|
|
private static final |
|
class DTLSNullMac extends DTLSNullAuthenticator implements MAC { |
|
private final MacImpl macImpl; |
|
public DTLSNullMac() { |
|
super(); |
|
this.macImpl = new MacImpl(); |
|
} |
|
|
|
@Override |
|
public MacAlg macAlg() { |
|
return macImpl.macAlg; |
|
} |
|
|
|
@Override |
|
public byte[] compute(byte type, ByteBuffer bb, |
|
byte[] sequence, boolean isSimulated) { |
|
return macImpl.compute(type, bb, sequence, isSimulated); |
|
} |
|
} |
|
|
|
|
|
private static final class DTLS10Mac |
|
extends DTLS10Authenticator implements MAC { |
|
private final MacImpl macImpl; |
|
public DTLS10Mac(ProtocolVersion protocolVersion, |
|
MacAlg macAlg, SecretKey key) throws NoSuchAlgorithmException, |
|
InvalidKeyException { |
|
super(protocolVersion); |
|
this.macImpl = new MacImpl(protocolVersion, macAlg, key); |
|
} |
|
|
|
@Override |
|
public MacAlg macAlg() { |
|
return macImpl.macAlg; |
|
} |
|
|
|
@Override |
|
public byte[] compute(byte type, ByteBuffer bb, |
|
byte[] sequence, boolean isSimulated) { |
|
return macImpl.compute(type, bb, sequence, isSimulated); |
|
} |
|
} |
|
|
|
static final long toLong(byte[] recordEnS) { |
|
if (recordEnS != null && recordEnS.length == 8) { |
|
return ((recordEnS[0] & 0xFFL) << 56) | |
|
((recordEnS[1] & 0xFFL) << 48) | |
|
((recordEnS[2] & 0xFFL) << 40) | |
|
((recordEnS[3] & 0xFFL) << 32) | |
|
((recordEnS[4] & 0xFFL) << 24) | |
|
((recordEnS[5] & 0xFFL) << 16) | |
|
((recordEnS[6] & 0xFFL) << 8) | |
|
(recordEnS[7] & 0xFFL); |
|
} |
|
|
|
return -1L; |
|
} |
|
} |