< prev index next >

src/java.base/share/classes/sun/security/ssl/HelloCookieManager.java

Print this page




  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 java.security.MessageDigest;
  30 import java.security.NoSuchAlgorithmException;
  31 import java.security.SecureRandom;
  32 import java.util.Arrays;
  33 import java.util.concurrent.locks.ReentrantLock;
  34 import static sun.security.ssl.ClientHello.ClientHelloMessage;
  35 
  36 /**
  37  *  (D)TLS handshake cookie manager
  38  */
  39 abstract class HelloCookieManager {
  40 
  41     static class Builder {
  42 
  43         final SecureRandom secureRandom;
  44 
  45         private volatile D10HelloCookieManager d10HelloCookieManager;
  46         private volatile D13HelloCookieManager d13HelloCookieManager;
  47         private volatile T13HelloCookieManager t13HelloCookieManager;
  48 
  49         private final ReentrantLock managerLock = new ReentrantLock();
  50 
  51         Builder(SecureRandom secureRandom) {
  52             this.secureRandom = secureRandom;
  53         }
  54 
  55         HelloCookieManager valueOf(ProtocolVersion protocolVersion) {
  56             if (protocolVersion.isDTLS) {
  57                 if (protocolVersion.useTLS13PlusSpec()) {
  58                     if (d13HelloCookieManager != null) {
  59                         return d13HelloCookieManager;
  60                     }
  61 
  62                     managerLock.lock();
  63                     try {
  64                         if (d13HelloCookieManager == null) {
  65                             d13HelloCookieManager =
  66                                     new D13HelloCookieManager(secureRandom);
  67                         }
  68                     } finally {
  69                         managerLock.unlock();
  70                     }
  71 
  72                     return d13HelloCookieManager;
  73                 } else {
  74                     if (d10HelloCookieManager != null) {
  75                         return d10HelloCookieManager;
  76                     }
  77 
  78                     managerLock.lock();
  79                     try {
  80                         if (d10HelloCookieManager == null) {
  81                             d10HelloCookieManager =
  82                                     new D10HelloCookieManager(secureRandom);
  83                         }
  84                     } finally {
  85                         managerLock.unlock();
  86                     }
  87 
  88                     return d10HelloCookieManager;
  89                 }
  90             } else {
  91                 if (protocolVersion.useTLS13PlusSpec()) {
  92                     if (t13HelloCookieManager != null) {
  93                         return t13HelloCookieManager;
  94                     }
  95 
  96                     managerLock.lock();
  97                     try {
  98                         if (t13HelloCookieManager == null) {
  99                             t13HelloCookieManager =
 100                                     new T13HelloCookieManager(secureRandom);
 101                         }
 102                     } finally {
 103                         managerLock.unlock();
 104                     }
 105 
 106                     return t13HelloCookieManager;
 107                 }
 108             }
 109 
 110             return null;
 111         }
 112     }
 113 
 114     abstract byte[] createCookie(ServerHandshakeContext context,
 115                 ClientHelloMessage clientHello) throws IOException;
 116 
 117     abstract boolean isCookieValid(ServerHandshakeContext context,
 118             ClientHelloMessage clientHello, byte[] cookie) throws IOException;
 119 
 120     // DTLS 1.0/1.2
 121     private static final
 122             class D10HelloCookieManager extends HelloCookieManager {
 123 
 124         final SecureRandom secureRandom;
 125         private int         cookieVersion;  // allow to wrap, version + sequence
 126         private byte[]      cookieSecret;
 127         private byte[]      legacySecret;
 128 
 129         private final ReentrantLock d10ManagerLock = new ReentrantLock();
 130 
 131         D10HelloCookieManager(SecureRandom secureRandom) {
 132             this.secureRandom = secureRandom;
 133 
 134             this.cookieVersion = secureRandom.nextInt();
 135             this.cookieSecret = new byte[32];
 136             this.legacySecret = new byte[32];
 137 
 138             secureRandom.nextBytes(cookieSecret);
 139             System.arraycopy(cookieSecret, 0, legacySecret, 0, 32);
 140         }
 141 
 142         @Override
 143         byte[] createCookie(ServerHandshakeContext context,
 144                 ClientHelloMessage clientHello) throws IOException {
 145             int version;
 146             byte[] secret;
 147 
 148             d10ManagerLock.lock();
 149             try {
 150                 version = cookieVersion;
 151                 secret = cookieSecret;
 152 
 153                 // the cookie secret usage limit is 2^24
 154                 if ((cookieVersion & 0xFFFFFF) == 0) {  // reset the secret
 155                     System.arraycopy(cookieSecret, 0, legacySecret, 0, 32);
 156                     secureRandom.nextBytes(cookieSecret);
 157                 }
 158 
 159                 cookieVersion++;
 160             } finally {
 161                 d10ManagerLock.unlock();
 162             }
 163 
 164             MessageDigest md;
 165             try {
 166                 md = MessageDigest.getInstance("SHA-256");
 167             } catch (NoSuchAlgorithmException nsae) {
 168                 throw new RuntimeException(
 169                     "MessageDigest algorithm SHA-256 is not available", nsae);
 170             }
 171             byte[] helloBytes = clientHello.getHelloCookieBytes();
 172             md.update(helloBytes);
 173             byte[] cookie = md.digest(secret);      // 32 bytes
 174             cookie[0] = (byte)((version >> 24) & 0xFF);
 175 
 176             return cookie;
 177         }
 178 
 179         @Override
 180         boolean isCookieValid(ServerHandshakeContext context,
 181             ClientHelloMessage clientHello, byte[] cookie) throws IOException {
 182             // no cookie exchange or not a valid cookie length
 183             if ((cookie == null) || (cookie.length != 32)) {
 184                 return false;
 185             }
 186 
 187             byte[] secret;
 188             d10ManagerLock.lock();
 189             try {
 190                 if (((cookieVersion >> 24) & 0xFF) == cookie[0]) {
 191                     secret = cookieSecret;
 192                 } else {
 193                     secret = legacySecret;  // including out of window cookies
 194                 }
 195             } finally {
 196                 d10ManagerLock.unlock();
 197             }
 198 
 199             MessageDigest md;
 200             try {
 201                 md = MessageDigest.getInstance("SHA-256");
 202             } catch (NoSuchAlgorithmException nsae) {
 203                 throw new RuntimeException(
 204                     "MessageDigest algorithm SHA-256 is not available", nsae);
 205             }
 206             byte[] helloBytes = clientHello.getHelloCookieBytes();
 207             md.update(helloBytes);
 208             byte[] target = md.digest(secret);      // 32 bytes
 209             target[0] = cookie[0];
 210 
 211             return Arrays.equals(target, cookie);
 212         }
 213     }
 214 
 215     private static final
 216             class D13HelloCookieManager extends HelloCookieManager {


 221         byte[] createCookie(ServerHandshakeContext context,
 222                 ClientHelloMessage clientHello) throws IOException {
 223             throw new UnsupportedOperationException("Not supported yet.");
 224         }
 225 
 226         @Override
 227         boolean isCookieValid(ServerHandshakeContext context,
 228             ClientHelloMessage clientHello, byte[] cookie) throws IOException {
 229             throw new UnsupportedOperationException("Not supported yet.");
 230         }
 231     }
 232 
 233     private static final
 234             class T13HelloCookieManager extends HelloCookieManager {
 235 
 236         final SecureRandom secureRandom;
 237         private int             cookieVersion;      // version + sequence
 238         private final byte[]    cookieSecret;
 239         private final byte[]    legacySecret;
 240 
 241         private final ReentrantLock t13ManagerLock = new ReentrantLock();
 242 
 243         T13HelloCookieManager(SecureRandom secureRandom) {
 244             this.secureRandom = secureRandom;
 245             this.cookieVersion = secureRandom.nextInt();
 246             this.cookieSecret = new byte[64];
 247             this.legacySecret = new byte[64];
 248 
 249             secureRandom.nextBytes(cookieSecret);
 250             System.arraycopy(cookieSecret, 0, legacySecret, 0, 64);
 251         }
 252 
 253         @Override
 254         byte[] createCookie(ServerHandshakeContext context,
 255                 ClientHelloMessage clientHello) throws IOException {
 256             int version;
 257             byte[] secret;
 258 
 259             t13ManagerLock.lock();
 260             try {
 261                 version = cookieVersion;
 262                 secret = cookieSecret;
 263 
 264                 // the cookie secret usage limit is 2^24
 265                 if ((cookieVersion & 0xFFFFFF) == 0) {  // reset the secret
 266                     System.arraycopy(cookieSecret, 0, legacySecret, 0, 64);
 267                     secureRandom.nextBytes(cookieSecret);
 268                 }
 269 
 270                 cookieVersion++;        // allow wrapped version number
 271             } finally {
 272                 t13ManagerLock.unlock();
 273             }
 274 
 275             MessageDigest md;
 276             try {
 277                 md = MessageDigest.getInstance(
 278                     context.negotiatedCipherSuite.hashAlg.name);
 279             } catch (NoSuchAlgorithmException nsae) {
 280                 throw new RuntimeException(
 281                         "MessageDigest algorithm " +
 282                         context.negotiatedCipherSuite.hashAlg.name +
 283                         " is not available", nsae);
 284             }
 285             byte[] headerBytes = clientHello.getHeaderBytes();
 286             md.update(headerBytes);
 287             byte[] headerCookie = md.digest(secret);
 288 
 289             // hash of ClientHello handshake message
 290             context.handshakeHash.update();
 291             byte[] clientHelloHash = context.handshakeHash.digest();
 292 


 321                 return false;
 322             }
 323 
 324             int csId = ((cookie[0] & 0xFF) << 8) | (cookie[1] & 0xFF);
 325             CipherSuite cs = CipherSuite.valueOf(csId);
 326             if (cs == null || cs.hashAlg == null || cs.hashAlg.hashLength == 0) {
 327                 return false;
 328             }
 329 
 330             int hashLen = cs.hashAlg.hashLength;
 331             if (cookie.length != (3 + hashLen * 2)) {
 332                 return false;
 333             }
 334 
 335             byte[] prevHeadCookie =
 336                     Arrays.copyOfRange(cookie, 3, 3 + hashLen);
 337             byte[] prevClientHelloHash =
 338                     Arrays.copyOfRange(cookie, 3 + hashLen, cookie.length);
 339 
 340             byte[] secret;
 341             t13ManagerLock.lock();
 342             try {
 343                 if ((byte)((cookieVersion >> 24) & 0xFF) == cookie[2]) {
 344                     secret = cookieSecret;
 345                 } else {
 346                     secret = legacySecret;  // including out of window cookies
 347                 }
 348             } finally {
 349                 t13ManagerLock.unlock();
 350             }
 351 
 352             MessageDigest md;
 353             try {
 354                 md = MessageDigest.getInstance(cs.hashAlg.name);
 355             } catch (NoSuchAlgorithmException nsae) {
 356                 throw new RuntimeException(
 357                         "MessageDigest algorithm " +
 358                         cs.hashAlg.name + " is not available", nsae);
 359             }
 360             byte[] headerBytes = clientHello.getHeaderBytes();
 361             md.update(headerBytes);
 362             byte[] headerCookie = md.digest(secret);
 363 
 364             if (!Arrays.equals(headerCookie, prevHeadCookie)) {
 365                 return false;
 366             }
 367 
 368             // Use the ClientHello hash in the cookie for transtript
 369             // hash calculation for stateless HelloRetryRequest.




  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 java.security.MessageDigest;
  30 import java.security.NoSuchAlgorithmException;
  31 import java.security.SecureRandom;
  32 import java.util.Arrays;

  33 import static sun.security.ssl.ClientHello.ClientHelloMessage;
  34 
  35 /**
  36  *  (D)TLS handshake cookie manager
  37  */
  38 abstract class HelloCookieManager {
  39 
  40     static class Builder {
  41 
  42         final SecureRandom secureRandom;
  43 
  44         private volatile D10HelloCookieManager d10HelloCookieManager;
  45         private volatile D13HelloCookieManager d13HelloCookieManager;
  46         private volatile T13HelloCookieManager t13HelloCookieManager;
  47 


  48         Builder(SecureRandom secureRandom) {
  49             this.secureRandom = secureRandom;
  50         }
  51 
  52         HelloCookieManager valueOf(ProtocolVersion protocolVersion) {
  53             if (protocolVersion.isDTLS) {
  54                 if (protocolVersion.useTLS13PlusSpec()) {
  55                     if (d13HelloCookieManager != null) {
  56                         return d13HelloCookieManager;
  57                     }
  58 
  59                     synchronized (this) {

  60                         if (d13HelloCookieManager == null) {
  61                             d13HelloCookieManager =
  62                                     new D13HelloCookieManager(secureRandom);
  63                         }


  64                     }
  65 
  66                     return d13HelloCookieManager;
  67                 } else {
  68                     if (d10HelloCookieManager != null) {
  69                         return d10HelloCookieManager;
  70                     }
  71 
  72                     synchronized (this) {

  73                         if (d10HelloCookieManager == null) {
  74                             d10HelloCookieManager =
  75                                     new D10HelloCookieManager(secureRandom);
  76                         }


  77                     }
  78 
  79                     return d10HelloCookieManager;
  80                 }
  81             } else {
  82                 if (protocolVersion.useTLS13PlusSpec()) {
  83                     if (t13HelloCookieManager != null) {
  84                         return t13HelloCookieManager;
  85                     }
  86 
  87                     synchronized (this) {

  88                         if (t13HelloCookieManager == null) {
  89                             t13HelloCookieManager =
  90                                     new T13HelloCookieManager(secureRandom);
  91                         }


  92                     }
  93 
  94                     return t13HelloCookieManager;
  95                 }
  96             }
  97 
  98             return null;
  99         }
 100     }
 101 
 102     abstract byte[] createCookie(ServerHandshakeContext context,
 103                 ClientHelloMessage clientHello) throws IOException;
 104 
 105     abstract boolean isCookieValid(ServerHandshakeContext context,
 106             ClientHelloMessage clientHello, byte[] cookie) throws IOException;
 107 
 108     // DTLS 1.0/1.2
 109     private static final
 110             class D10HelloCookieManager extends HelloCookieManager {
 111 
 112         final SecureRandom secureRandom;
 113         private int         cookieVersion;  // allow to wrap, version + sequence
 114         private byte[]      cookieSecret;
 115         private byte[]      legacySecret;
 116 


 117         D10HelloCookieManager(SecureRandom secureRandom) {
 118             this.secureRandom = secureRandom;
 119 
 120             this.cookieVersion = secureRandom.nextInt();
 121             this.cookieSecret = new byte[32];
 122             this.legacySecret = new byte[32];
 123 
 124             secureRandom.nextBytes(cookieSecret);
 125             System.arraycopy(cookieSecret, 0, legacySecret, 0, 32);
 126         }
 127 
 128         @Override
 129         byte[] createCookie(ServerHandshakeContext context,
 130                 ClientHelloMessage clientHello) throws IOException {
 131             int version;
 132             byte[] secret;
 133 
 134             synchronized (this) {

 135                 version = cookieVersion;
 136                 secret = cookieSecret;
 137 
 138                 // the cookie secret usage limit is 2^24
 139                 if ((cookieVersion & 0xFFFFFF) == 0) {  // reset the secret
 140                     System.arraycopy(cookieSecret, 0, legacySecret, 0, 32);
 141                     secureRandom.nextBytes(cookieSecret);
 142                 }
 143 
 144                 cookieVersion++;


 145             }
 146 
 147             MessageDigest md;
 148             try {
 149                 md = MessageDigest.getInstance("SHA-256");
 150             } catch (NoSuchAlgorithmException nsae) {
 151                 throw new RuntimeException(
 152                     "MessageDigest algorithm SHA-256 is not available", nsae);
 153             }
 154             byte[] helloBytes = clientHello.getHelloCookieBytes();
 155             md.update(helloBytes);
 156             byte[] cookie = md.digest(secret);      // 32 bytes
 157             cookie[0] = (byte)((version >> 24) & 0xFF);
 158 
 159             return cookie;
 160         }
 161 
 162         @Override
 163         boolean isCookieValid(ServerHandshakeContext context,
 164             ClientHelloMessage clientHello, byte[] cookie) throws IOException {
 165             // no cookie exchange or not a valid cookie length
 166             if ((cookie == null) || (cookie.length != 32)) {
 167                 return false;
 168             }
 169 
 170             byte[] secret;
 171             synchronized (this) {

 172                 if (((cookieVersion >> 24) & 0xFF) == cookie[0]) {
 173                     secret = cookieSecret;
 174                 } else {
 175                     secret = legacySecret;  // including out of window cookies
 176                 }


 177             }
 178 
 179             MessageDigest md;
 180             try {
 181                 md = MessageDigest.getInstance("SHA-256");
 182             } catch (NoSuchAlgorithmException nsae) {
 183                 throw new RuntimeException(
 184                     "MessageDigest algorithm SHA-256 is not available", nsae);
 185             }
 186             byte[] helloBytes = clientHello.getHelloCookieBytes();
 187             md.update(helloBytes);
 188             byte[] target = md.digest(secret);      // 32 bytes
 189             target[0] = cookie[0];
 190 
 191             return Arrays.equals(target, cookie);
 192         }
 193     }
 194 
 195     private static final
 196             class D13HelloCookieManager extends HelloCookieManager {


 201         byte[] createCookie(ServerHandshakeContext context,
 202                 ClientHelloMessage clientHello) throws IOException {
 203             throw new UnsupportedOperationException("Not supported yet.");
 204         }
 205 
 206         @Override
 207         boolean isCookieValid(ServerHandshakeContext context,
 208             ClientHelloMessage clientHello, byte[] cookie) throws IOException {
 209             throw new UnsupportedOperationException("Not supported yet.");
 210         }
 211     }
 212 
 213     private static final
 214             class T13HelloCookieManager extends HelloCookieManager {
 215 
 216         final SecureRandom secureRandom;
 217         private int             cookieVersion;      // version + sequence
 218         private final byte[]    cookieSecret;
 219         private final byte[]    legacySecret;
 220 


 221         T13HelloCookieManager(SecureRandom secureRandom) {
 222             this.secureRandom = secureRandom;
 223             this.cookieVersion = secureRandom.nextInt();
 224             this.cookieSecret = new byte[64];
 225             this.legacySecret = new byte[64];
 226 
 227             secureRandom.nextBytes(cookieSecret);
 228             System.arraycopy(cookieSecret, 0, legacySecret, 0, 64);
 229         }
 230 
 231         @Override
 232         byte[] createCookie(ServerHandshakeContext context,
 233                 ClientHelloMessage clientHello) throws IOException {
 234             int version;
 235             byte[] secret;
 236 
 237             synchronized (this) {

 238                 version = cookieVersion;
 239                 secret = cookieSecret;
 240 
 241                 // the cookie secret usage limit is 2^24
 242                 if ((cookieVersion & 0xFFFFFF) == 0) {  // reset the secret
 243                     System.arraycopy(cookieSecret, 0, legacySecret, 0, 64);
 244                     secureRandom.nextBytes(cookieSecret);
 245                 }
 246 
 247                 cookieVersion++;        // allow wrapped version number


 248             }
 249 
 250             MessageDigest md;
 251             try {
 252                 md = MessageDigest.getInstance(
 253                     context.negotiatedCipherSuite.hashAlg.name);
 254             } catch (NoSuchAlgorithmException nsae) {
 255                 throw new RuntimeException(
 256                         "MessageDigest algorithm " +
 257                         context.negotiatedCipherSuite.hashAlg.name +
 258                         " is not available", nsae);
 259             }
 260             byte[] headerBytes = clientHello.getHeaderBytes();
 261             md.update(headerBytes);
 262             byte[] headerCookie = md.digest(secret);
 263 
 264             // hash of ClientHello handshake message
 265             context.handshakeHash.update();
 266             byte[] clientHelloHash = context.handshakeHash.digest();
 267 


 296                 return false;
 297             }
 298 
 299             int csId = ((cookie[0] & 0xFF) << 8) | (cookie[1] & 0xFF);
 300             CipherSuite cs = CipherSuite.valueOf(csId);
 301             if (cs == null || cs.hashAlg == null || cs.hashAlg.hashLength == 0) {
 302                 return false;
 303             }
 304 
 305             int hashLen = cs.hashAlg.hashLength;
 306             if (cookie.length != (3 + hashLen * 2)) {
 307                 return false;
 308             }
 309 
 310             byte[] prevHeadCookie =
 311                     Arrays.copyOfRange(cookie, 3, 3 + hashLen);
 312             byte[] prevClientHelloHash =
 313                     Arrays.copyOfRange(cookie, 3 + hashLen, cookie.length);
 314 
 315             byte[] secret;
 316             synchronized (this) {

 317                 if ((byte)((cookieVersion >> 24) & 0xFF) == cookie[2]) {
 318                     secret = cookieSecret;
 319                 } else {
 320                     secret = legacySecret;  // including out of window cookies
 321                 }


 322             }
 323 
 324             MessageDigest md;
 325             try {
 326                 md = MessageDigest.getInstance(cs.hashAlg.name);
 327             } catch (NoSuchAlgorithmException nsae) {
 328                 throw new RuntimeException(
 329                         "MessageDigest algorithm " +
 330                         cs.hashAlg.name + " is not available", nsae);
 331             }
 332             byte[] headerBytes = clientHello.getHeaderBytes();
 333             md.update(headerBytes);
 334             byte[] headerCookie = md.digest(secret);
 335 
 336             if (!Arrays.equals(headerCookie, prevHeadCookie)) {
 337                 return false;
 338             }
 339 
 340             // Use the ClientHello hash in the cookie for transtript
 341             // hash calculation for stateless HelloRetryRequest.


< prev index next >