1 /*
   2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.security.ssl;
  27 
  28 import java.io.IOException;
  29 import javax.net.ssl.SSLProtocolException;
  30 import java.security.MessageDigest;
  31 import java.security.SecureRandom;
  32 
  33 import sun.security.ssl.HandshakeMessage.ClientHello;
  34 
  35 /*
  36  * HelloVerifyRequest cookie manager
  37  */
  38 final class HelloCookieManager {
  39     // the cookie secret life time
  40     private static long COOKIE_TIMING_WINDOW = 3600000;     // in milliseconds
  41     private static int  COOKIE_MAX_LENGTH_DTLS10 = 32;      // 32 bytes
  42     private static int  COOKIE_MAX_LENGTH_DTLS12 = 0xFF;    // 2^8 -1 bytes
  43 
  44     private final SecureRandom          secureRandom;
  45     private final MessageDigest         cookieDigest;
  46 
  47     private int                         cookieVersion;      // allow to wrap
  48     private long                        secretLifetime;
  49     private byte[]                      cookieSecret;
  50 
  51     private int                         prevCookieVersion;
  52     private byte[]                      prevCookieSecret;
  53 
  54     HelloCookieManager(SecureRandom secureRandom) {
  55         this.secureRandom = secureRandom;
  56         this.cookieDigest = JsseJce.getMessageDigest("SHA-256");
  57 
  58         this.cookieVersion = secureRandom.nextInt();
  59         this.secretLifetime = 0;
  60         this.cookieSecret = null;
  61 
  62         this.prevCookieVersion = 0;
  63         this.prevCookieSecret = null;
  64     }
  65 
  66     // Used by server side to generate cookies in HelloVerifyRequest message.
  67     synchronized byte[] getCookie(ClientHello clientHelloMsg) {
  68         if (secretLifetime < System.currentTimeMillis()) {
  69             if (cookieSecret != null) {
  70                 prevCookieVersion = cookieVersion;
  71                 prevCookieSecret = cookieSecret.clone();
  72             } else {
  73                 cookieSecret = new byte[32];
  74             }
  75 
  76             cookieVersion++;
  77             secureRandom.nextBytes(cookieSecret);
  78             secretLifetime = System.currentTimeMillis() + COOKIE_TIMING_WINDOW;
  79         }
  80 
  81         clientHelloMsg.updateHelloCookie(cookieDigest);
  82         byte[] cookie = cookieDigest.digest(cookieSecret);      // 32 bytes
  83         cookie[0] = (byte)((cookieVersion >> 24) & 0xFF);
  84         cookie[1] = (byte)((cookieVersion >> 16) & 0xFF);
  85         cookie[2] = (byte)((cookieVersion >> 8) & 0xFF);
  86         cookie[3] = (byte)(cookieVersion & 0xFF);
  87 
  88         return cookie;
  89     }
  90 
  91     // Used by server side to check the cookie in ClientHello message.
  92     synchronized boolean isValid(ClientHello clientHelloMsg) {
  93         byte[] cookie = clientHelloMsg.cookie;
  94 
  95         // no cookie exchange or not a valid cookie length
  96         if ((cookie == null) || (cookie.length != 32)) {
  97             return false;
  98         }
  99 
 100         int version = ((cookie[0] & 0xFF) << 24) |
 101                       ((cookie[1] & 0xFF) << 16) |
 102                       ((cookie[2] & 0xFF) << 8) |
 103                        (cookie[3] & 0xFF);
 104 
 105         byte[] secret;
 106         if (version == cookieVersion) {
 107             secret = cookieSecret;
 108         } else if (version == prevCookieVersion) {
 109             secret = prevCookieSecret;
 110         } else {
 111             return false;       // may be out of the timing window
 112         }
 113 
 114         clientHelloMsg.updateHelloCookie(cookieDigest);
 115         byte[] target = cookieDigest.digest(secret);            // 32 bytes
 116 
 117         for (int i = 4; i < 32; i++) {
 118             if (cookie[i] != target[i]) {
 119                 return false;
 120             }
 121         }
 122 
 123         return true;
 124     }
 125 
 126     // Used by client side to check the cookie in HelloVerifyRequest message.
 127     static void checkCookie(ProtocolVersion protocolVersion,
 128             byte[] cookie) throws IOException {
 129         if (cookie != null && cookie.length != 0) {
 130             int limit = COOKIE_MAX_LENGTH_DTLS12;
 131             if (protocolVersion.v == ProtocolVersion.DTLS10.v) {
 132                 limit = COOKIE_MAX_LENGTH_DTLS10;
 133             }
 134 
 135             if (cookie.length > COOKIE_MAX_LENGTH_DTLS10) {
 136                 throw new SSLProtocolException(
 137                         "Invalid HelloVerifyRequest.cookie (length = " +
 138                          cookie.length + " bytes)");
 139             }
 140         }
 141 
 142         // Otherwise, no cookie exchange.
 143     }
 144 }