1 /*
2  * Copyright (c) 2005, 2018, 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.pkcs11;
27 
28 import java.util.*;
29 
30 import java.security.*;
31 import java.security.spec.AlgorithmParameterSpec;
32 
33 import javax.crypto.*;
34 import javax.crypto.spec.*;
35 
36 import sun.security.internal.spec.*;
37 import sun.security.internal.interfaces.TlsMasterSecret;
38 
39 import static sun.security.pkcs11.TemplateManager.*;
40 import sun.security.pkcs11.wrapper.*;
41 
42 import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
43 
44 /**
45  * KeyGenerator to calculate the SSL/TLS key material (cipher keys and ivs,
46  * mac keys) from the master secret.
47  *
48  * @author  Andreas Sterbenz
49  * @since   1.6
50  */
51 public final class P11TlsKeyMaterialGenerator extends KeyGeneratorSpi {
52 
53     private static final String MSG = "TlsKeyMaterialGenerator must be "
54         + "initialized using a TlsKeyMaterialParameterSpec";
55 
56     // token instance
57     private final Token token;
58 
59     // algorithm name
60     private final String algorithm;
61 
62     // mechanism id
63     private long mechanism;
64 
65     private int tlsVersion;
66 
67     // parameter spec
68     @SuppressWarnings("deprecation")
69     private TlsKeyMaterialParameterSpec spec;
70 
71     // master secret as a P11Key
72     private P11Key p11Key;
73 
74     // whether SSLv3 is supported
75     private final boolean supportSSLv3;
76 
P11TlsKeyMaterialGenerator(Token token, String algorithm, long mechanism)77     P11TlsKeyMaterialGenerator(Token token, String algorithm, long mechanism)
78             throws PKCS11Exception {
79         super();
80         this.token = token;
81         this.algorithm = algorithm;
82         this.mechanism = mechanism;
83 
84         // Given the current lookup order specified in SunPKCS11.java,
85         // if CKM_SSL3_KEY_AND_MAC_DERIVE is not used to construct this object,
86         // it means that this mech is disabled or unsupported.
87         this.supportSSLv3 = (mechanism == CKM_SSL3_KEY_AND_MAC_DERIVE);
88     }
89 
engineInit(SecureRandom random)90     protected void engineInit(SecureRandom random) {
91         throw new InvalidParameterException(MSG);
92     }
93 
94     @SuppressWarnings("deprecation")
engineInit(AlgorithmParameterSpec params, SecureRandom random)95     protected void engineInit(AlgorithmParameterSpec params,
96             SecureRandom random) throws InvalidAlgorithmParameterException {
97         if (params instanceof TlsKeyMaterialParameterSpec == false) {
98             throw new InvalidAlgorithmParameterException(MSG);
99         }
100 
101         TlsKeyMaterialParameterSpec spec = (TlsKeyMaterialParameterSpec)params;
102         tlsVersion = (spec.getMajorVersion() << 8) | spec.getMinorVersion();
103 
104         if ((tlsVersion == 0x0300 && !supportSSLv3) ||
105                 (tlsVersion < 0x0300) || (tlsVersion > 0x0303)) {
106              throw new InvalidAlgorithmParameterException
107                     ("Only" + (supportSSLv3? " SSL 3.0,": "") +
108                      " TLS 1.0, TLS 1.1 and TLS 1.2 are supported (" +
109                      tlsVersion + ")");
110         }
111         try {
112             p11Key = P11SecretKeyFactory.convertKey
113                             (token, spec.getMasterSecret(), "TlsMasterSecret");
114         } catch (InvalidKeyException e) {
115             throw new InvalidAlgorithmParameterException("init() failed", e);
116         }
117         this.spec = spec;
118         if (tlsVersion == 0x0300) {
119             mechanism = CKM_SSL3_KEY_AND_MAC_DERIVE;
120         } else if (tlsVersion == 0x0301 || tlsVersion == 0x0302) {
121             mechanism = CKM_TLS_KEY_AND_MAC_DERIVE;
122         }
123     }
124 
engineInit(int keysize, SecureRandom random)125     protected void engineInit(int keysize, SecureRandom random) {
126         throw new InvalidParameterException(MSG);
127     }
128 
129     @SuppressWarnings("deprecation")
engineGenerateKey()130     protected SecretKey engineGenerateKey() {
131         if (spec == null) {
132             throw new IllegalStateException
133                 ("TlsKeyMaterialGenerator must be initialized");
134         }
135         int macBits = spec.getMacKeyLength() << 3;
136         int ivBits = spec.getIvLength() << 3;
137 
138         int expandedKeyBits = spec.getExpandedCipherKeyLength() << 3;
139         int keyBits = spec.getCipherKeyLength() << 3;
140         boolean isExportable;
141         if (expandedKeyBits != 0) {
142             isExportable = true;
143         } else {
144             isExportable = false;
145             expandedKeyBits = keyBits;
146         }
147 
148         CK_SSL3_RANDOM_DATA random = new CK_SSL3_RANDOM_DATA
149                             (spec.getClientRandom(), spec.getServerRandom());
150         Object params = null;
151         CK_MECHANISM ckMechanism = null;
152         if (tlsVersion < 0x0303) {
153             params = new CK_SSL3_KEY_MAT_PARAMS
154                     (macBits, keyBits, ivBits, isExportable, random);
155             ckMechanism = new CK_MECHANISM(mechanism, (CK_SSL3_KEY_MAT_PARAMS)params);
156         } else if (tlsVersion == 0x0303) {
157             params = new CK_TLS12_KEY_MAT_PARAMS
158                     (macBits, keyBits, ivBits, isExportable, random,
159                     Functions.getHashMechId(spec.getPRFHashAlg()));
160             ckMechanism = new CK_MECHANISM(mechanism, (CK_TLS12_KEY_MAT_PARAMS)params);
161         }
162 
163         String cipherAlgorithm = spec.getCipherAlgorithm();
164         long keyType = P11SecretKeyFactory.getKeyType(cipherAlgorithm);
165         if (keyType < 0) {
166             if (keyBits != 0) {
167                 throw new ProviderException
168                             ("Unknown algorithm: " + spec.getCipherAlgorithm());
169             } else {
170                 // NULL encryption ciphersuites
171                 keyType = CKK_GENERIC_SECRET;
172             }
173         }
174 
175         Session session = null;
176         try {
177             session = token.getObjSession();
178             CK_ATTRIBUTE[] attributes;
179             if (keyBits != 0) {
180                 attributes = new CK_ATTRIBUTE[] {
181                     new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY),
182                     new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType),
183                     new CK_ATTRIBUTE(CKA_VALUE_LEN, expandedKeyBits >> 3),
184                 };
185             } else {
186                 // ciphersuites with NULL ciphers
187                 attributes = new CK_ATTRIBUTE[0];
188             }
189             attributes = token.getAttributes
190                 (O_GENERATE, CKO_SECRET_KEY, keyType, attributes);
191             // the returned keyID is a dummy, ignore
192             long p11KeyID = p11Key.getKeyID();
193             try {
194                 token.p11.C_DeriveKey(session.id(),
195                         ckMechanism, p11KeyID, attributes);
196             } finally {
197                 p11Key.releaseKeyID();
198             }
199 
200             CK_SSL3_KEY_MAT_OUT out = null;
201             if (params instanceof CK_SSL3_KEY_MAT_PARAMS) {
202                 out = ((CK_SSL3_KEY_MAT_PARAMS)params).pReturnedKeyMaterial;
203             } else if (params instanceof CK_TLS12_KEY_MAT_PARAMS) {
204                 out = ((CK_TLS12_KEY_MAT_PARAMS)params).pReturnedKeyMaterial;
205             }
206             // Note that the MAC keys do not inherit all attributes from the
207             // template, but they do inherit the sensitive/extractable/token
208             // flags, which is all P11Key cares about.
209             SecretKey clientMacKey, serverMacKey;
210 
211             // The MAC size may be zero for GCM mode.
212             //
213             // PKCS11 does not support GCM mode as the author made the comment,
214             // so the macBits is unlikely to be zero. It's only a place holder.
215             if (macBits != 0) {
216                 clientMacKey = P11Key.secretKey
217                     (session, out.hClientMacSecret, "MAC", macBits, attributes);
218                 serverMacKey = P11Key.secretKey
219                     (session, out.hServerMacSecret, "MAC", macBits, attributes);
220             } else {
221                 clientMacKey = null;
222                 serverMacKey = null;
223             }
224 
225             SecretKey clientCipherKey, serverCipherKey;
226             if (keyBits != 0) {
227                 clientCipherKey = P11Key.secretKey(session, out.hClientKey,
228                         cipherAlgorithm, expandedKeyBits, attributes);
229                 serverCipherKey = P11Key.secretKey(session, out.hServerKey,
230                         cipherAlgorithm, expandedKeyBits, attributes);
231             } else {
232                 clientCipherKey = null;
233                 serverCipherKey = null;
234             }
235             IvParameterSpec clientIv = (out.pIVClient == null)
236                                     ? null : new IvParameterSpec(out.pIVClient);
237             IvParameterSpec serverIv = (out.pIVServer == null)
238                                     ? null : new IvParameterSpec(out.pIVServer);
239 
240             return new TlsKeyMaterialSpec(clientMacKey, serverMacKey,
241                     clientCipherKey, clientIv, serverCipherKey, serverIv);
242 
243         } catch (Exception e) {
244             throw new ProviderException("Could not generate key", e);
245         } finally {
246             token.releaseSession(session);
247         }
248     }
249 
250 }
251