1/*
2 * Copyright (c) 2005, 2017, 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 ..
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
36import java.io.BufferedReader;
37import java.nio.file.Files;
38import java.nio.file.Paths;
39import java.security.Provider;
40import java.security.InvalidAlgorithmParameterException;
41import java.util.Arrays;
42import javax.crypto.KeyGenerator;
43import javax.crypto.SecretKey;
44import javax.crypto.spec.IvParameterSpec;
45import javax.crypto.spec.SecretKeySpec;
46import sun.security.internal.spec.TlsKeyMaterialParameterSpec;
47import sun.security.internal.spec.TlsKeyMaterialSpec;
48
49public class TestKeyMaterial extends PKCS11Test {
50
51    private static final int PREFIX_LENGTH = "km-master:  ".length();
52
53    public static void main(String[] args) throws Exception {
54        main(new TestKeyMaterial(), args);
55    }
56
57    @Override
58    public void main(Provider provider) throws Exception {
59        if (provider.getService("KeyGenerator", "SunTlsKeyMaterial") == null) {
60            System.out.println("Provider does not support algorithm, skipping");
61            return;
62        }
63
64        try (BufferedReader reader = Files.newBufferedReader(
65                Paths.get(BASE, "keymatdata.txt"))) {
66
67            int n = 0;
68            int lineNumber = 0;
69
70            byte[] master = null;
71            int major = 0;
72            int minor = 0;
73            byte[] clientRandom = null;
74            byte[] serverRandom = null;
75            String cipherAlgorithm = null;
76            int keyLength = 0;
77            int expandedKeyLength = 0;
78            int ivLength = 0;
79            int macLength = 0;
80            byte[] clientCipherBytes = null;
81            byte[] serverCipherBytes = null;
82            byte[] clientIv = null;
83            byte[] serverIv = null;
84            byte[] clientMacBytes = null;
85            byte[] serverMacBytes = null;
86
87            while (true) {
88                String line = reader.readLine();
89                lineNumber++;
90                if (line == null) {
91                    break;
92                }
93                if (line.startsWith("km-") == false) {
94                    continue;
95                }
96                String data = line.substring(PREFIX_LENGTH);
97                if (line.startsWith("km-master:")) {
98                    master = parse(data);
99                } else if (line.startsWith("km-major:")) {
100                    major = Integer.parseInt(data);
101                } else if (line.startsWith("km-minor:")) {
102                    minor = Integer.parseInt(data);
103                } else if (line.startsWith("km-crandom:")) {
104                    clientRandom = parse(data);
105                } else if (line.startsWith("km-srandom:")) {
106                    serverRandom = parse(data);
107                } else if (line.startsWith("km-cipalg:")) {
108                    cipherAlgorithm = data;
109                } else if (line.startsWith("km-keylen:")) {
110                    keyLength = Integer.parseInt(data);
111                } else if (line.startsWith("km-explen:")) {
112                    expandedKeyLength = Integer.parseInt(data);
113                } else if (line.startsWith("km-ivlen:")) {
114                    ivLength = Integer.parseInt(data);
115                } else if (line.startsWith("km-maclen:")) {
116                    macLength = Integer.parseInt(data);
117                } else if (line.startsWith("km-ccipkey:")) {
118                    clientCipherBytes = parse(data);
119                } else if (line.startsWith("km-scipkey:")) {
120                    serverCipherBytes = parse(data);
121                } else if (line.startsWith("km-civ:")) {
122                    clientIv = parse(data);
123                } else if (line.startsWith("km-siv:")) {
124                    serverIv = parse(data);
125                } else if (line.startsWith("km-cmackey:")) {
126                    clientMacBytes = parse(data);
127                } else if (line.startsWith("km-smackey:")) {
128                    serverMacBytes = parse(data);
129
130                    System.out.print(".");
131                    n++;
132
133                    KeyGenerator kg =
134                        KeyGenerator.getInstance("SunTlsKeyMaterial", provider);
135                    SecretKey masterKey =
136                        new SecretKeySpec(master, "TlsMasterSecret");
137                    TlsKeyMaterialParameterSpec spec =
138                        new TlsKeyMaterialParameterSpec(masterKey, major, minor,
139                        clientRandom, serverRandom, cipherAlgorithm,
140                        keyLength, expandedKeyLength, ivLength, macLength,
141                        null, -1, -1);
142
143                    try {
144                        kg.init(spec);
145                        TlsKeyMaterialSpec result =
146                            (TlsKeyMaterialSpec)kg.generateKey();
147                        match(lineNumber, clientCipherBytes,
148                            result.getClientCipherKey(), cipherAlgorithm);
149                        match(lineNumber, serverCipherBytes,
150                            result.getServerCipherKey(), cipherAlgorithm);
151                        match(lineNumber, clientIv, result.getClientIv(), "");
152                        match(lineNumber, serverIv, result.getServerIv(), "");
153                        match(lineNumber, clientMacBytes, result.getClientMacKey(), "");
154                        match(lineNumber, serverMacBytes, result.getServerMacKey(), "");
155                    } catch (InvalidAlgorithmParameterException iape) {
156                        // SSLv3 support is removed in S12
157                        if (major == 3 && minor == 0) {
158                            System.out.println("Skip testing SSLv3");
159                            continue;
160                        }
161                    }
162               } else {
163                    throw new Exception("Unknown line: " + line);
164               }
165            }
166            if (n == 0) {
167                throw new Exception("no tests");
168            }
169            System.out.println();
170            System.out.println("OK: " + n + " tests");
171        }
172    }
173
174    private static void stripParity(byte[] b) {
175        for (int i = 0; i < b.length; i++) {
176            b[i] &= 0xfe;
177        }
178    }
179
180    private static void match(int lineNumber, byte[] out, Object res,
181            String cipherAlgorithm) throws Exception {
182        if ((out == null) || (res == null)) {
183            if (out != res) {
184                throw new Exception("null mismatch line " + lineNumber);
185            } else {
186                return;
187            }
188        }
189        byte[] b;
190        if (res instanceof SecretKey) {
191            b = ((SecretKey)res).getEncoded();
192            if (cipherAlgorithm.equalsIgnoreCase("DES") ||
193                    cipherAlgorithm.equalsIgnoreCase("DESede")) {
194                // strip DES parity bits before comparision
195                stripParity(out);
196                stripParity(b);
197            }
198        } else if (res instanceof IvParameterSpec) {
199            b = ((IvParameterSpec)res).getIV();
200        } else {
201            throw new Exception(res.getClass().getName());
202        }
203        if (Arrays.equals(out, b) == false) {
204            System.out.println();
205            System.out.println("out: " + toString(out));
206            System.out.println("b:   " + toString(b));
207            throw new Exception("mismatch line " + lineNumber);
208        }
209    }
210
211}
212