1 /*
   2  * Copyright (c) 2005, 2019, 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @bug 6316539 8136355
  27  * @summary Known-answer-test for TlsKeyMaterial generator
  28  * @author Andreas Sterbenz
  29  * @library /test/lib ..
  30  * @modules java.base/sun.security.internal.spec
  31  *          jdk.crypto.cryptoki
  32  * @run main/othervm TestKeyMaterial
  33  * @run main/othervm TestKeyMaterial sm policy
  34  */
  35 
  36 import java.io.BufferedReader;
  37 import java.nio.file.Files;
  38 import java.nio.file.Paths;
  39 import java.security.InvalidAlgorithmParameterException;
  40 import java.security.Provider;
  41 import java.security.ProviderException;
  42 import java.util.Arrays;
  43 
  44 import javax.crypto.KeyGenerator;
  45 import javax.crypto.SecretKey;
  46 import javax.crypto.spec.IvParameterSpec;
  47 import javax.crypto.spec.SecretKeySpec;
  48 
  49 import sun.security.internal.spec.TlsKeyMaterialParameterSpec;
  50 import sun.security.internal.spec.TlsKeyMaterialSpec;
  51 
  52 public class TestKeyMaterial extends PKCS11Test {
  53 
  54     private static final int PREFIX_LENGTH = "km-master:  ".length();
  55 
  56     public static void main(String[] args) throws Exception {
  57         System.out.println("NSS Version: " + getNSSVersion());
  58         main(new TestKeyMaterial(), args);
  59     }
  60 
  61     @Override
  62     public void main(Provider provider) throws Exception {
  63         if (provider.getService("KeyGenerator", "SunTlsKeyMaterial") == null) {
  64             System.out.println("Provider does not support algorithm, skipping");
  65             return;
  66         }
  67 
  68         try (BufferedReader reader = Files.newBufferedReader(
  69                 Paths.get(BASE, "keymatdata.txt"))) {
  70 
  71             int n = 0;
  72             int lineNumber = 0;
  73 
  74             byte[] master = null;
  75             int major = 0;
  76             int minor = 0;
  77             byte[] clientRandom = null;
  78             byte[] serverRandom = null;
  79             String cipherAlgorithm = null;
  80             int keyLength = 0;
  81             int expandedKeyLength = 0;
  82             int ivLength = 0;
  83             int macLength = 0;
  84             byte[] clientCipherBytes = null;
  85             byte[] serverCipherBytes = null;
  86             byte[] clientIv = null;
  87             byte[] serverIv = null;
  88             byte[] clientMacBytes = null;
  89             byte[] serverMacBytes = null;
  90 
  91             while (true) {
  92                 String line = reader.readLine();
  93                 lineNumber++;
  94                 if (line == null) {
  95                     break;
  96                 }
  97                 if (line.startsWith("km-") == false) {
  98                     continue;
  99                 }
 100                 String data = line.substring(PREFIX_LENGTH);
 101                 if (line.startsWith("km-master:")) {
 102                     master = parse(data);
 103                 } else if (line.startsWith("km-major:")) {
 104                     major = Integer.parseInt(data);
 105                 } else if (line.startsWith("km-minor:")) {
 106                     minor = Integer.parseInt(data);
 107                 } else if (line.startsWith("km-crandom:")) {
 108                     clientRandom = parse(data);
 109                 } else if (line.startsWith("km-srandom:")) {
 110                     serverRandom = parse(data);
 111                 } else if (line.startsWith("km-cipalg:")) {
 112                     cipherAlgorithm = data;
 113                 } else if (line.startsWith("km-keylen:")) {
 114                     keyLength = Integer.parseInt(data);
 115                 } else if (line.startsWith("km-explen:")) {
 116                     expandedKeyLength = Integer.parseInt(data);
 117                 } else if (line.startsWith("km-ivlen:")) {
 118                     ivLength = Integer.parseInt(data);
 119                 } else if (line.startsWith("km-maclen:")) {
 120                     macLength = Integer.parseInt(data);
 121                 } else if (line.startsWith("km-ccipkey:")) {
 122                     clientCipherBytes = parse(data);
 123                 } else if (line.startsWith("km-scipkey:")) {
 124                     serverCipherBytes = parse(data);
 125                 } else if (line.startsWith("km-civ:")) {
 126                     clientIv = parse(data);
 127                 } else if (line.startsWith("km-siv:")) {
 128                     serverIv = parse(data);
 129                 } else if (line.startsWith("km-cmackey:")) {
 130                     clientMacBytes = parse(data);
 131                 } else if (line.startsWith("km-smackey:")) {
 132                     serverMacBytes = parse(data);
 133 
 134                     System.out.print(".");
 135                     n++;
 136 
 137                     KeyGenerator kg =
 138                         KeyGenerator.getInstance("SunTlsKeyMaterial", provider);
 139                     SecretKey masterKey =
 140                         new SecretKeySpec(master, "TlsMasterSecret");
 141                     TlsKeyMaterialParameterSpec spec =
 142                         new TlsKeyMaterialParameterSpec(masterKey, major, minor,
 143                         clientRandom, serverRandom, cipherAlgorithm,
 144                         keyLength, expandedKeyLength, ivLength, macLength,
 145                         null, -1, -1);
 146 
 147                     try {
 148                         kg.init(spec);
 149                         TlsKeyMaterialSpec result =
 150                             (TlsKeyMaterialSpec)kg.generateKey();
 151                         match(lineNumber, clientCipherBytes,
 152                             result.getClientCipherKey(), cipherAlgorithm);
 153                         match(lineNumber, serverCipherBytes,
 154                             result.getServerCipherKey(), cipherAlgorithm);
 155                         match(lineNumber, clientIv, result.getClientIv(), "");
 156                         match(lineNumber, serverIv, result.getServerIv(), "");
 157                         match(lineNumber, clientMacBytes, result.getClientMacKey(), "");
 158                         match(lineNumber, serverMacBytes, result.getServerMacKey(), "");
 159                     } catch (InvalidAlgorithmParameterException iape) {
 160                         // SSLv3 support is removed in S12
 161                         if (provider.getName().indexOf("Solaris") != -1) {
 162                             if (major == 3 && minor == 0) {
 163                                 System.out.println("Skip testing SSLv3 on Solaris");
 164                                 continue;
 165                             }
 166                         }
 167                         throw iape;
 168                     } catch (ProviderException pe) {
 169                         if (provider.getName().indexOf("NSS") != -1) {
 170                             Throwable t = pe.getCause();
 171                             if (expandedKeyLength != 0
 172                                     && t.getMessage().indexOf(
 173                                             "CKR_MECHANISM_PARAM_INVALID") != -1) {
 174                                 // NSS removed support for export-grade cipher suites in 3.28,
 175                                 // see https://bugzilla.mozilla.org/show_bug.cgi?id=1252849
 176                                 System.out.println("Ignore known NSS failure on CKR_MECHANISM_PARAM_INVALID");
 177                                 continue;
 178                             }
 179                         }
 180                         throw pe;
 181                     }
 182                } else {
 183                     throw new Exception("Unknown line: " + line);
 184                }
 185             }
 186             if (n == 0) {
 187                 throw new Exception("no tests");
 188             }
 189             System.out.println();
 190             System.out.println("OK: " + n + " tests");
 191         }
 192     }
 193 
 194     private static void stripParity(byte[] b) {
 195         for (int i = 0; i < b.length; i++) {
 196             b[i] &= 0xfe;
 197         }
 198     }
 199 
 200     private static void match(int lineNumber, byte[] out, Object res,
 201             String cipherAlgorithm) throws Exception {
 202         if ((out == null) || (res == null)) {
 203             if (out != res) {
 204                 throw new Exception("null mismatch line " + lineNumber);
 205             } else {
 206                 return;
 207             }
 208         }
 209         byte[] b;
 210         if (res instanceof SecretKey) {
 211             b = ((SecretKey)res).getEncoded();
 212             if (cipherAlgorithm.equalsIgnoreCase("DES") ||
 213                     cipherAlgorithm.equalsIgnoreCase("DESede")) {
 214                 // strip DES parity bits before comparision
 215                 stripParity(out);
 216                 stripParity(b);
 217             }
 218         } else if (res instanceof IvParameterSpec) {
 219             b = ((IvParameterSpec)res).getIV();
 220         } else {
 221             throw new Exception(res.getClass().getName());
 222         }
 223         if (Arrays.equals(out, b) == false) {
 224             System.out.println();
 225             System.out.println("out: " + toString(out));
 226             System.out.println("b:   " + toString(b));
 227             throw new Exception("mismatch line " + lineNumber);
 228         }
 229     }
 230 
 231 }