Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/ssl/HandshakeHash.java
38830 views
/*1* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.ssl;2627import java.io.ByteArrayOutputStream;28import java.io.IOException;29import java.nio.ByteBuffer;30import java.security.MessageDigest;31import java.util.Arrays;32import java.util.LinkedList;33import javax.crypto.SecretKey;34import sun.security.util.MessageDigestSpi2;3536final class HandshakeHash {37private TranscriptHash transcriptHash;38private LinkedList<byte[]> reserves; // one handshake message per entry39private boolean hasBeenUsed;4041HandshakeHash() {42this.transcriptHash = new CacheOnlyHash();43this.reserves = new LinkedList<>();44this.hasBeenUsed = false;45}4647// fix the negotiated protocol version and cipher suite48void determine(ProtocolVersion protocolVersion,49CipherSuite cipherSuite) {50if (!(transcriptHash instanceof CacheOnlyHash)) {51throw new IllegalStateException(52"Not expected instance of transcript hash");53}5455CacheOnlyHash coh = (CacheOnlyHash)transcriptHash;56if (protocolVersion.useTLS13PlusSpec()) {57transcriptHash = new T13HandshakeHash(cipherSuite);58} else if (protocolVersion.useTLS12PlusSpec()) {59transcriptHash = new T12HandshakeHash(cipherSuite);60} else if (protocolVersion.useTLS10PlusSpec()) {61transcriptHash = new T10HandshakeHash(cipherSuite);62} else {63transcriptHash = new S30HandshakeHash(cipherSuite);64}6566byte[] reserved = coh.baos.toByteArray();67if (reserved.length != 0) {68transcriptHash.update(reserved, 0, reserved.length);69}70}7172HandshakeHash copy() {73if (transcriptHash instanceof CacheOnlyHash) {74HandshakeHash result = new HandshakeHash();75result.transcriptHash = ((CacheOnlyHash)transcriptHash).copy();76result.reserves = new LinkedList<>(reserves);77result.hasBeenUsed = hasBeenUsed;78return result;79} else {80throw new IllegalStateException("Hash does not support copying");81}82}8384void receive(byte[] input) {85reserves.add(Arrays.copyOf(input, input.length));86}8788void receive(ByteBuffer input, int length) {89if (input.hasArray()) {90int from = input.position() + input.arrayOffset();91int to = from + length;92reserves.add(Arrays.copyOfRange(input.array(), from, to));93} else {94int inPos = input.position();95byte[] holder = new byte[length];96input.get(holder);97input.position(inPos);98reserves.add(Arrays.copyOf(holder, holder.length));99}100}101void receive(ByteBuffer input) {102receive(input, input.remaining());103}104105// For HelloRetryRequest only! Please use this method very carefully!106void push(byte[] input) {107reserves.push(Arrays.copyOf(input, input.length));108}109110// For PreSharedKey to modify the state of the PSK binder hash111byte[] removeLastReceived() {112return reserves.removeLast();113}114115void deliver(byte[] input) {116update();117transcriptHash.update(input, 0, input.length);118}119120void deliver(byte[] input, int offset, int length) {121update();122transcriptHash.update(input, offset, length);123}124125void deliver(ByteBuffer input) {126update();127if (input.hasArray()) {128transcriptHash.update(input.array(),129input.position() + input.arrayOffset(), input.remaining());130} else {131int inPos = input.position();132byte[] holder = new byte[input.remaining()];133input.get(holder);134input.position(inPos);135transcriptHash.update(holder, 0, holder.length);136}137}138139// Use one handshake message if it has not been used.140void utilize() {141if (hasBeenUsed) {142return;143}144if (reserves.size() != 0) {145byte[] holder = reserves.remove();146transcriptHash.update(holder, 0, holder.length);147hasBeenUsed = true;148}149}150151// Consume one handshake message if it has not been consumed.152void consume() {153if (hasBeenUsed) {154hasBeenUsed = false;155return;156}157if (reserves.size() != 0) {158byte[] holder = reserves.remove();159transcriptHash.update(holder, 0, holder.length);160}161}162163void update() {164while (reserves.size() != 0) {165byte[] holder = reserves.remove();166transcriptHash.update(holder, 0, holder.length);167}168hasBeenUsed = false;169}170171byte[] digest() {172// Note that the reserve handshake message may be not a part of173// the expected digest.174return transcriptHash.digest();175}176177void finish() {178this.transcriptHash = new CacheOnlyHash();179this.reserves = new LinkedList<>();180this.hasBeenUsed = false;181}182183// Optional184byte[] archived() {185// Note that the reserve handshake message may be not a part of186// the expected digest.187return transcriptHash.archived();188}189190// Optional, TLS 1.0/1.1 only191byte[] digest(String algorithm) {192T10HandshakeHash hh = (T10HandshakeHash)transcriptHash;193return hh.digest(algorithm);194}195196// Optional, SSL 3.0 only197byte[] digest(String algorithm, SecretKey masterSecret) {198S30HandshakeHash hh = (S30HandshakeHash)transcriptHash;199return hh.digest(algorithm, masterSecret);200}201202// Optional, SSL 3.0 only203byte[] digest(boolean useClientLabel, SecretKey masterSecret) {204S30HandshakeHash hh = (S30HandshakeHash)transcriptHash;205return hh.digest(useClientLabel, masterSecret);206}207208public boolean isHashable(byte handshakeType) {209return handshakeType != SSLHandshake.HELLO_REQUEST.id;210}211212interface TranscriptHash {213void update(byte[] input, int offset, int length);214byte[] digest();215byte[] archived(); // optional216}217218// For cache only.219private static final class CacheOnlyHash implements TranscriptHash {220private final ByteArrayOutputStream baos;221222CacheOnlyHash() {223this.baos = new ByteArrayOutputStream();224}225226@Override227public void update(byte[] input, int offset, int length) {228baos.write(input, offset, length);229}230231@Override232public byte[] digest() {233throw new IllegalStateException(234"Not expected call to handshake hash digest");235}236237@Override238public byte[] archived() {239return baos.toByteArray();240}241242CacheOnlyHash copy() {243CacheOnlyHash result = new CacheOnlyHash();244try {245baos.writeTo(result.baos);246} catch (IOException ex) {247throw new RuntimeException("unable to to clone hash state");248}249return result;250}251}252253static final class S30HandshakeHash implements TranscriptHash {254static final byte[] MD5_pad1 = genPad(0x36, 48);255static final byte[] MD5_pad2 = genPad(0x5c, 48);256257static final byte[] SHA_pad1 = genPad(0x36, 40);258static final byte[] SHA_pad2 = genPad(0x5c, 40);259260private static final byte[] SSL_CLIENT = { 0x43, 0x4C, 0x4E, 0x54 };261private static final byte[] SSL_SERVER = { 0x53, 0x52, 0x56, 0x52 };262263private final MessageDigest mdMD5;264private final MessageDigest mdSHA;265private final TranscriptHash md5;266private final TranscriptHash sha;267private final ByteArrayOutputStream baos;268269S30HandshakeHash(CipherSuite cipherSuite) {270this.mdMD5 = JsseJce.getMessageDigest("MD5");271this.mdSHA = JsseJce.getMessageDigest("SHA");272273boolean hasArchived = false;274if (mdMD5 instanceof Cloneable) {275md5 = new CloneableHash(mdMD5);276} else {277hasArchived = true;278md5 = new NonCloneableHash(mdMD5);279}280if (mdSHA instanceof Cloneable) {281sha = new CloneableHash(mdSHA);282} else {283hasArchived = true;284sha = new NonCloneableHash(mdSHA);285}286287if (hasArchived) {288this.baos = null;289} else {290this.baos = new ByteArrayOutputStream();291}292}293294@Override295public void update(byte[] input, int offset, int length) {296md5.update(input, offset, length);297sha.update(input, offset, length);298if (baos != null) {299baos.write(input, offset, length);300}301}302303@Override304public byte[] digest() {305byte[] digest = new byte[36];306System.arraycopy(md5.digest(), 0, digest, 0, 16);307System.arraycopy(sha.digest(), 0, digest, 16, 20);308309return digest;310}311312@Override313public byte[] archived() {314if (baos != null) {315return baos.toByteArray();316} else if (md5 instanceof NonCloneableHash) {317return md5.archived();318} else {319return sha.archived();320}321}322323byte[] digest(boolean useClientLabel, SecretKey masterSecret) {324MessageDigest md5Clone = cloneMd5();325MessageDigest shaClone = cloneSha();326327if (useClientLabel) {328md5Clone.update(SSL_CLIENT);329shaClone.update(SSL_CLIENT);330} else {331md5Clone.update(SSL_SERVER);332shaClone.update(SSL_SERVER);333}334335updateDigest(md5Clone, MD5_pad1, MD5_pad2, masterSecret);336updateDigest(shaClone, SHA_pad1, SHA_pad2, masterSecret);337338byte[] digest = new byte[36];339System.arraycopy(md5Clone.digest(), 0, digest, 0, 16);340System.arraycopy(shaClone.digest(), 0, digest, 16, 20);341342return digest;343}344345byte[] digest(String algorithm, SecretKey masterSecret) {346if ("RSA".equalsIgnoreCase(algorithm)) {347MessageDigest md5Clone = cloneMd5();348MessageDigest shaClone = cloneSha();349updateDigest(md5Clone, MD5_pad1, MD5_pad2, masterSecret);350updateDigest(shaClone, SHA_pad1, SHA_pad2, masterSecret);351352byte[] digest = new byte[36];353System.arraycopy(md5Clone.digest(), 0, digest, 0, 16);354System.arraycopy(shaClone.digest(), 0, digest, 16, 20);355356return digest;357} else {358MessageDigest shaClone = cloneSha();359updateDigest(shaClone, SHA_pad1, SHA_pad2, masterSecret);360return shaClone.digest();361}362}363364private static byte[] genPad(int b, int count) {365byte[] padding = new byte[count];366Arrays.fill(padding, (byte)b);367return padding;368}369370private MessageDigest cloneMd5() {371MessageDigest md5Clone;372if (mdMD5 instanceof Cloneable) {373try {374md5Clone = (MessageDigest)mdMD5.clone();375} catch (CloneNotSupportedException ex) { // unlikely376throw new RuntimeException(377"MessageDigest does no support clone operation");378}379} else {380md5Clone = JsseJce.getMessageDigest("MD5");381md5Clone.update(md5.archived());382}383384return md5Clone;385}386387private MessageDigest cloneSha() {388MessageDigest shaClone;389if (mdSHA instanceof Cloneable) {390try {391shaClone = (MessageDigest)mdSHA.clone();392} catch (CloneNotSupportedException ex) { // unlikely393throw new RuntimeException(394"MessageDigest does no support clone operation");395}396} else {397shaClone = JsseJce.getMessageDigest("SHA");398shaClone.update(sha.archived());399}400401return shaClone;402}403404private static void updateDigest(MessageDigest md,405byte[] pad1, byte[] pad2, SecretKey masterSecret) {406byte[] keyBytes = "RAW".equals(masterSecret.getFormat())407? masterSecret.getEncoded() : null;408if (keyBytes != null) {409md.update(keyBytes);410} else {411digestKey(md, masterSecret);412}413md.update(pad1);414byte[] temp = md.digest();415416if (keyBytes != null) {417md.update(keyBytes);418} else {419digestKey(md, masterSecret);420}421md.update(pad2);422md.update(temp);423}424425private static void digestKey(MessageDigest md, SecretKey key) {426try {427if (md instanceof MessageDigestSpi2) {428((MessageDigestSpi2)md).engineUpdate(key);429} else {430throw new Exception(431"Digest does not support implUpdate(SecretKey)");432}433} catch (Exception e) {434throw new RuntimeException(435"Could not obtain encoded key and "436+ "MessageDigest cannot digest key", e);437}438}439}440441// TLS 1.0 and TLS 1.1442static final class T10HandshakeHash implements TranscriptHash {443private final TranscriptHash md5;444private final TranscriptHash sha;445private final ByteArrayOutputStream baos;446447T10HandshakeHash(CipherSuite cipherSuite) {448MessageDigest mdMD5 = JsseJce.getMessageDigest("MD5");449MessageDigest mdSHA = JsseJce.getMessageDigest("SHA");450451boolean hasArchived = false;452if (mdMD5 instanceof Cloneable) {453md5 = new CloneableHash(mdMD5);454} else {455hasArchived = true;456md5 = new NonCloneableHash(mdMD5);457}458if (mdSHA instanceof Cloneable) {459sha = new CloneableHash(mdSHA);460} else {461hasArchived = true;462sha = new NonCloneableHash(mdSHA);463}464465if (hasArchived) {466this.baos = null;467} else {468this.baos = new ByteArrayOutputStream();469}470}471472@Override473public void update(byte[] input, int offset, int length) {474md5.update(input, offset, length);475sha.update(input, offset, length);476if (baos != null) {477baos.write(input, offset, length);478}479}480481@Override482public byte[] digest() {483byte[] digest = new byte[36];484System.arraycopy(md5.digest(), 0, digest, 0, 16);485System.arraycopy(sha.digest(), 0, digest, 16, 20);486487return digest;488}489490byte[] digest(String algorithm) {491if ("RSA".equalsIgnoreCase(algorithm)) {492return digest();493} else {494return sha.digest();495}496}497498@Override499public byte[] archived() {500if (baos != null) {501return baos.toByteArray();502} else if (md5 instanceof NonCloneableHash) {503return md5.archived();504} else {505return sha.archived();506}507}508}509510static final class T12HandshakeHash implements TranscriptHash {511private final TranscriptHash transcriptHash;512private final ByteArrayOutputStream baos;513514T12HandshakeHash(CipherSuite cipherSuite) {515MessageDigest md =516JsseJce.getMessageDigest(cipherSuite.hashAlg.name);517if (md instanceof Cloneable) {518transcriptHash = new CloneableHash(md);519this.baos = new ByteArrayOutputStream();520} else {521transcriptHash = new NonCloneableHash(md);522this.baos = null;523}524}525526@Override527public void update(byte[] input, int offset, int length) {528transcriptHash.update(input, offset, length);529if (baos != null) {530baos.write(input, offset, length);531}532}533534@Override535public byte[] digest() {536return transcriptHash.digest();537}538539@Override540public byte[] archived() {541if (baos != null) {542return baos.toByteArray();543} else {544return transcriptHash.archived();545}546}547}548549static final class T13HandshakeHash implements TranscriptHash {550private final TranscriptHash transcriptHash;551552T13HandshakeHash(CipherSuite cipherSuite) {553MessageDigest md =554JsseJce.getMessageDigest(cipherSuite.hashAlg.name);555if (md instanceof Cloneable) {556transcriptHash = new CloneableHash(md);557} else {558transcriptHash = new NonCloneableHash(md);559}560}561562@Override563public void update(byte[] input, int offset, int length) {564transcriptHash.update(input, offset, length);565}566567@Override568public byte[] digest() {569return transcriptHash.digest();570}571572@Override573public byte[] archived() {574// This method is not necessary in T13575throw new UnsupportedOperationException(576"TLS 1.3 does not require archived.");577}578}579580static final class CloneableHash implements TranscriptHash {581private final MessageDigest md;582583CloneableHash(MessageDigest md) {584this.md = md;585}586587@Override588public void update(byte[] input, int offset, int length) {589md.update(input, offset, length);590}591592@Override593public byte[] digest() {594try {595return ((MessageDigest)md.clone()).digest();596} catch (CloneNotSupportedException ex) {597// unlikely598return new byte[0];599}600}601602@Override603public byte[] archived() {604throw new UnsupportedOperationException("Not supported yet.");605}606}607608static final class NonCloneableHash implements TranscriptHash {609private final MessageDigest md;610private final ByteArrayOutputStream baos = new ByteArrayOutputStream();611612NonCloneableHash(MessageDigest md) {613this.md = md;614}615616@Override617public void update(byte[] input, int offset, int length) {618baos.write(input, offset, length);619}620621@Override622public byte[] digest() {623byte[] bytes = baos.toByteArray();624md.reset();625return md.digest(bytes);626}627628@Override629public byte[] archived() {630return baos.toByteArray();631}632}633}634635636