277 lines · 10.2 KB · Java
RawDownload
/* * Copyright (c) 2005, 2010, 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 com.sun.crypto.provider; import java.security.*;import java.security.spec.AlgorithmParameterSpec; import javax.crypto.*;import javax.crypto.spec.*; import sun.security.internal.interfaces.TlsMasterSecret;import sun.security.internal.spec.*; import static com.sun.crypto.provider.TlsPrfGenerator.*; /** * KeyGenerator implementation for the SSL/TLS master secret derivation. * * @author  Andreas Sterbenz * @since   1.6 */public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi {     private final static String MSG = "TlsKeyMaterialGenerator must be "        + "initialized using a TlsKeyMaterialParameterSpec";     private TlsKeyMaterialParameterSpec spec;     private int protocolVersion;     public TlsKeyMaterialGenerator() {    }     protected void engineInit(SecureRandom random) {        throw new InvalidParameterException(MSG);    }     protected void engineInit(AlgorithmParameterSpec params,            SecureRandom random) throws InvalidAlgorithmParameterException {        if (params instanceof TlsKeyMaterialParameterSpec == false) {            throw new InvalidAlgorithmParameterException(MSG);        }        this.spec = (TlsKeyMaterialParameterSpec)params;        if ("RAW".equals(spec.getMasterSecret().getFormat()) == false) {            throw new InvalidAlgorithmParameterException(                "Key format must be RAW");        }        protocolVersion = (spec.getMajorVersion() << 8)            | spec.getMinorVersion();        if ((protocolVersion < 0x0300) || (protocolVersion > 0x0303)) {            throw new InvalidAlgorithmParameterException(                "Only SSL 3.0, TLS 1.0/1.1/1.2 supported");        }    }     protected void engineInit(int keysize, SecureRandom random) {        throw new InvalidParameterException(MSG);    }     protected SecretKey engineGenerateKey() {        if (spec == null) {            throw new IllegalStateException(                "TlsKeyMaterialGenerator must be initialized");        }        try {            return engineGenerateKey0();        } catch (GeneralSecurityException e) {            throw new ProviderException(e);        }    }     private SecretKey engineGenerateKey0() throws GeneralSecurityException {        byte[] masterSecret = spec.getMasterSecret().getEncoded();         byte[] clientRandom = spec.getClientRandom();        byte[] serverRandom = spec.getServerRandom();         SecretKey clientMacKey = null;        SecretKey serverMacKey = null;        SecretKey clientCipherKey = null;        SecretKey serverCipherKey = null;        IvParameterSpec clientIv = null;        IvParameterSpec serverIv = null;         int macLength = spec.getMacKeyLength();        int expandedKeyLength = spec.getExpandedCipherKeyLength();        boolean isExportable = (expandedKeyLength != 0);        int keyLength = spec.getCipherKeyLength();        int ivLength = spec.getIvLength();         int keyBlockLen = macLength + keyLength            + (isExportable ? 0 : ivLength);        keyBlockLen <<= 1;        byte[] keyBlock = new byte[keyBlockLen];         // These may be used again later for exportable suite calculations.        MessageDigest md5 = null;        MessageDigest sha = null;         // generate key block        if (protocolVersion >= 0x0303) {            // TLS 1.2            byte[] seed = concat(serverRandom, clientRandom);            keyBlock = doTLS12PRF(masterSecret, LABEL_KEY_EXPANSION, seed,                        keyBlockLen, spec.getPRFHashAlg(),                        spec.getPRFHashLength(), spec.getPRFBlockSize());        } else if (protocolVersion >= 0x0301) {            // TLS 1.0/1.1            md5 = MessageDigest.getInstance("MD5");            sha = MessageDigest.getInstance("SHA1");            byte[] seed = concat(serverRandom, clientRandom);            keyBlock = doTLS10PRF(masterSecret, LABEL_KEY_EXPANSION, seed,                        keyBlockLen, md5, sha);        } else {            // SSL            md5 = MessageDigest.getInstance("MD5");            sha = MessageDigest.getInstance("SHA1");            keyBlock = new byte[keyBlockLen];             byte[] tmp = new byte[20];            for (int i = 0, remaining = keyBlockLen;                 remaining > 0;                 i++, remaining -= 16) {                 sha.update(SSL3_CONST[i]);                sha.update(masterSecret);                sha.update(serverRandom);                sha.update(clientRandom);                sha.digest(tmp, 0, 20);                 md5.update(masterSecret);                md5.update(tmp);                 if (remaining >= 16) {                    md5.digest(keyBlock, i << 4, 16);                } else {                    md5.digest(tmp, 0, 16);                    System.arraycopy(tmp, 0, keyBlock, i << 4, remaining);                }            }        }         // partition keyblock into individual secrets         int ofs = 0;        byte[] tmp = new byte[macLength];         // mac keys        System.arraycopy(keyBlock, ofs, tmp, 0, macLength);        ofs += macLength;        clientMacKey = new SecretKeySpec(tmp, "Mac");         System.arraycopy(keyBlock, ofs, tmp, 0, macLength);        ofs += macLength;        serverMacKey = new SecretKeySpec(tmp, "Mac");         if (keyLength == 0) { // SSL_RSA_WITH_NULL_* ciphersuites            return new TlsKeyMaterialSpec(clientMacKey, serverMacKey);        }         String alg = spec.getCipherAlgorithm();         // cipher keys        byte[] clientKeyBytes = new byte[keyLength];        System.arraycopy(keyBlock, ofs, clientKeyBytes, 0, keyLength);        ofs += keyLength;         byte[] serverKeyBytes = new byte[keyLength];        System.arraycopy(keyBlock, ofs, serverKeyBytes, 0, keyLength);        ofs += keyLength;         if (isExportable == false) {            // cipher keys            clientCipherKey = new SecretKeySpec(clientKeyBytes, alg);            serverCipherKey = new SecretKeySpec(serverKeyBytes, alg);             // IV keys if needed.            if (ivLength != 0) {                tmp = new byte[ivLength];                 System.arraycopy(keyBlock, ofs, tmp, 0, ivLength);                ofs += ivLength;                clientIv = new IvParameterSpec(tmp);                 System.arraycopy(keyBlock, ofs, tmp, 0, ivLength);                ofs += ivLength;                serverIv = new IvParameterSpec(tmp);            }        } else {            // if exportable suites, calculate the alternate            // cipher key expansion and IV generation            if (protocolVersion >= 0x0302) {                // TLS 1.1+                throw new RuntimeException(                    "Internal Error:  TLS 1.1+ should not be negotiating" +                    "exportable ciphersuites");            } else if (protocolVersion == 0x0301) {                // TLS 1.0                byte[] seed = concat(clientRandom, serverRandom);                 tmp = doTLS10PRF(clientKeyBytes, LABEL_CLIENT_WRITE_KEY, seed,                            expandedKeyLength, md5, sha);                clientCipherKey = new SecretKeySpec(tmp, alg);                 tmp = doTLS10PRF(serverKeyBytes, LABEL_SERVER_WRITE_KEY, seed,                            expandedKeyLength, md5, sha);                serverCipherKey = new SecretKeySpec(tmp, alg);                 if (ivLength != 0) {                    tmp = new byte[ivLength];                    byte[] block = doTLS10PRF(null, LABEL_IV_BLOCK, seed,                                ivLength << 1, md5, sha);                    System.arraycopy(block, 0, tmp, 0, ivLength);                    clientIv = new IvParameterSpec(tmp);                    System.arraycopy(block, ivLength, tmp, 0, ivLength);                    serverIv = new IvParameterSpec(tmp);                }            } else {                // SSLv3                tmp = new byte[expandedKeyLength];                 md5.update(clientKeyBytes);                md5.update(clientRandom);                md5.update(serverRandom);                System.arraycopy(md5.digest(), 0, tmp, 0, expandedKeyLength);                clientCipherKey = new SecretKeySpec(tmp, alg);                 md5.update(serverKeyBytes);                md5.update(serverRandom);                md5.update(clientRandom);                System.arraycopy(md5.digest(), 0, tmp, 0, expandedKeyLength);                serverCipherKey = new SecretKeySpec(tmp, alg);                 if (ivLength != 0) {                    tmp = new byte[ivLength];                     md5.update(clientRandom);                    md5.update(serverRandom);                    System.arraycopy(md5.digest(), 0, tmp, 0, ivLength);                    clientIv = new IvParameterSpec(tmp);                     md5.update(serverRandom);                    md5.update(clientRandom);                    System.arraycopy(md5.digest(), 0, tmp, 0, ivLength);                    serverIv = new IvParameterSpec(tmp);                }            }        }         return new TlsKeyMaterialSpec(clientMacKey, serverMacKey,            clientCipherKey, clientIv, serverCipherKey, serverIv);    } }