--- /dev/null Fri May 29 00:48:50 2015 +++ new/src/java.base/share/classes/sun/security/ssl/HelloCookieManager.java Fri May 29 00:48:48 2015 @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2015, 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.io.IOException; +import javax.net.ssl.SSLProtocolException; +import java.security.MessageDigest; +import java.security.SecureRandom; + +import sun.security.ssl.HandshakeMessage.ClientHello; + +/* + * HelloVerifyRequest cookie manager + */ +final class HelloCookieManager { + // the cookie secret life time + private static long COOKIE_TIMING_WINDOW = 3600000; // in milliseconds + private static int COOKIE_MAX_LENGTH_DTLS10 = 32; // 32 bytes + private static int COOKIE_MAX_LENGTH_DTLS12 = 0xFF; // 2^8 -1 bytes + + private final SecureRandom secureRandom; + private final MessageDigest cookieDigest; + + private int cookieVersion; // allow to wrap + private long secretLifetime; + private byte[] cookieSecret; + + private int prevCookieVersion; + private byte[] prevCookieSecret; + + HelloCookieManager(SecureRandom secureRandom) { + this.secureRandom = secureRandom; + this.cookieDigest = JsseJce.getMessageDigest("SHA-256"); + + this.cookieVersion = secureRandom.nextInt(); + this.secretLifetime = 0; + this.cookieSecret = null; + + this.prevCookieVersion = 0; + this.prevCookieSecret = null; + } + + // Used by server side to generate cookies in HelloVerifyRequest message. + synchronized byte[] getCookie(ClientHello clientHelloMsg) { + if (secretLifetime < System.currentTimeMillis()) { + if (cookieSecret != null) { + prevCookieVersion = cookieVersion; + prevCookieSecret = cookieSecret.clone(); + } else { + cookieSecret = new byte[32]; + } + + cookieVersion++; + secureRandom.nextBytes(cookieSecret); + secretLifetime = System.currentTimeMillis() + COOKIE_TIMING_WINDOW; + } + + clientHelloMsg.updateHelloCookie(cookieDigest); + byte[] cookie = cookieDigest.digest(cookieSecret); // 32 bytes + cookie[0] = (byte)((cookieVersion >> 24) & 0xFF); + cookie[1] = (byte)((cookieVersion >> 16) & 0xFF); + cookie[2] = (byte)((cookieVersion >> 8) & 0xFF); + cookie[3] = (byte)(cookieVersion & 0xFF); + + return cookie; + } + + // Used by server side to check the cookie in ClientHello message. + synchronized boolean isValid(ClientHello clientHelloMsg) { + byte[] cookie = clientHelloMsg.cookie; + + // no cookie exchange or not a valid cookie length + if ((cookie == null) || (cookie.length != 32)) { + return false; + } + + int version = ((cookie[0] & 0xFF) << 24) | + ((cookie[1] & 0xFF) << 16) | + ((cookie[2] & 0xFF) << 8) | + (cookie[3] & 0xFF); + + byte[] secret; + if (version == cookieVersion) { + secret = cookieSecret; + } else if (version == prevCookieVersion) { + secret = prevCookieSecret; + } else { + return false; // may be out of the timing window + } + + clientHelloMsg.updateHelloCookie(cookieDigest); + byte[] target = cookieDigest.digest(secret); // 32 bytes + + for (int i = 4; i < 32; i++) { + if (cookie[i] != target[i]) { + return false; + } + } + + return true; + } + + // Used by client side to check the cookie in HelloVerifyRequest message. + static void checkCookie(ProtocolVersion protocolVersion, + byte[] cookie) throws IOException { + if (cookie != null && cookie.length != 0) { + int limit = COOKIE_MAX_LENGTH_DTLS12; + if (protocolVersion.v == ProtocolVersion.DTLS10.v) { + limit = COOKIE_MAX_LENGTH_DTLS10; + } + + if (cookie.length > COOKIE_MAX_LENGTH_DTLS10) { + throw new SSLProtocolException( + "Invalid HelloVerifyRequest.cookie (length = " + + cookie.length + " bytes)"); + } + } + + // Otherwise, no cookie exchange. + } +}