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. 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.security.*; 29 import java.security.spec.AlgorithmParameterSpec; 30 31 import javax.crypto.*; 32 import javax.crypto.spec.*; 33 34 import static java.nio.charset.StandardCharsets.UTF_8; 35 36 import sun.security.internal.spec.TlsPrfParameterSpec; 37 38 import static sun.security.pkcs11.TemplateManager.*; 39 import sun.security.pkcs11.wrapper.*; 40 import static sun.security.pkcs11.wrapper.PKCS11Constants.*; 41 42 /** 43 * KeyGenerator for the TLS PRF. Note that although the PRF is used in a number 44 * of places during the handshake, this class is usually only used to calculate 45 * the Finished messages. The reason is that for those other uses more specific 46 * PKCS#11 mechanisms have been defined (CKM_SSL3_MASTER_KEY_DERIVE, etc.). 47 * 48 * <p>This class supports the CKM_TLS_PRF mechanism from PKCS#11 v2.20 and 49 * the older NSS private mechanism. 50 * 51 * @author Andreas Sterbenz 52 * @since 1.6 53 */ 54 final class P11TlsPrfGenerator extends KeyGeneratorSpi { 55 56 private static final String MSG = 57 "TlsPrfGenerator must be initialized using a TlsPrfParameterSpec"; 58 59 // token instance 60 private final Token token; 61 62 // algorithm name 63 private final String algorithm; 64 65 // mechanism id 66 private final long mechanism; 67 68 @SuppressWarnings("deprecation") 69 private TlsPrfParameterSpec spec; 70 71 private P11Key p11Key; 72 P11TlsPrfGenerator(Token token, String algorithm, long mechanism)73 P11TlsPrfGenerator(Token token, String algorithm, long mechanism) 74 throws PKCS11Exception { 75 super(); 76 this.token = token; 77 this.algorithm = algorithm; 78 this.mechanism = mechanism; 79 } 80 engineInit(SecureRandom random)81 protected void engineInit(SecureRandom random) { 82 throw new InvalidParameterException(MSG); 83 } 84 85 @SuppressWarnings("deprecation") engineInit(AlgorithmParameterSpec params, SecureRandom random)86 protected void engineInit(AlgorithmParameterSpec params, 87 SecureRandom random) throws InvalidAlgorithmParameterException { 88 if (params instanceof TlsPrfParameterSpec == false) { 89 throw new InvalidAlgorithmParameterException(MSG); 90 } 91 this.spec = (TlsPrfParameterSpec)params; 92 SecretKey key = spec.getSecret(); 93 if (key == null) { 94 key = NULL_KEY; 95 } 96 try { 97 p11Key = P11SecretKeyFactory.convertKey(token, key, null); 98 } catch (InvalidKeyException e) { 99 throw new InvalidAlgorithmParameterException("init() failed", e); 100 } 101 } 102 103 // SecretKeySpec does not allow zero length keys, so we define our 104 // own class. 105 // 106 // As an anonymous class cannot make any guarantees about serialization 107 // compatibility, it is nonsensical for an anonymous class to define a 108 // serialVersionUID. Suppress warnings relative to missing serialVersionUID 109 // field in the anonymous subclass of serializable SecretKey. 110 @SuppressWarnings("serial") 111 private static final SecretKey NULL_KEY = new SecretKey() { 112 public byte[] getEncoded() { 113 return new byte[0]; 114 } 115 public String getFormat() { 116 return "RAW"; 117 } 118 public String getAlgorithm() { 119 return "Generic"; 120 } 121 }; 122 engineInit(int keysize, SecureRandom random)123 protected void engineInit(int keysize, SecureRandom random) { 124 throw new InvalidParameterException(MSG); 125 } 126 engineGenerateKey()127 protected SecretKey engineGenerateKey() { 128 if (spec == null) { 129 throw new IllegalStateException("TlsPrfGenerator must be initialized"); 130 } 131 132 byte[] seed = spec.getSeed(); 133 134 // TLS 1.2 135 if (mechanism == CKM_TLS_MAC) { 136 SecretKey k = null; 137 int ulServerOrClient = 0; 138 if (spec.getLabel().equals("server finished")) { 139 ulServerOrClient = 1; 140 } 141 if (spec.getLabel().equals("client finished")) { 142 ulServerOrClient = 2; 143 } 144 145 if (ulServerOrClient != 0) { 146 // Finished message 147 CK_TLS_MAC_PARAMS params = new CK_TLS_MAC_PARAMS( 148 Functions.getHashMechId(spec.getPRFHashAlg()), 149 spec.getOutputLength(), ulServerOrClient); 150 Session session = null; 151 long keyID = p11Key.getKeyID(); 152 try { 153 session = token.getOpSession(); 154 token.p11.C_SignInit(session.id(), 155 new CK_MECHANISM(mechanism, params), keyID); 156 token.p11.C_SignUpdate(session.id(), 0, seed, 0, seed.length); 157 byte[] out = token.p11.C_SignFinal 158 (session.id(), spec.getOutputLength()); 159 return new SecretKeySpec(out, "TlsPrf"); 160 } catch (PKCS11Exception e) { 161 throw new ProviderException("Could not calculate PRF", e); 162 } finally { 163 p11Key.releaseKeyID(); 164 token.releaseSession(session); 165 } 166 } else { 167 throw new ProviderException("Only Finished message authentication code"+ 168 " generation supported for TLS 1.2."); 169 } 170 } 171 172 byte[] label = spec.getLabel().getBytes(UTF_8); 173 174 if (mechanism == CKM_NSS_TLS_PRF_GENERAL) { 175 Session session = null; 176 long keyID = p11Key.getKeyID(); 177 try { 178 session = token.getOpSession(); 179 token.p11.C_SignInit 180 (session.id(), new CK_MECHANISM(mechanism), keyID); 181 token.p11.C_SignUpdate(session.id(), 0, label, 0, label.length); 182 token.p11.C_SignUpdate(session.id(), 0, seed, 0, seed.length); 183 byte[] out = token.p11.C_SignFinal 184 (session.id(), spec.getOutputLength()); 185 return new SecretKeySpec(out, "TlsPrf"); 186 } catch (PKCS11Exception e) { 187 throw new ProviderException("Could not calculate PRF", e); 188 } finally { 189 p11Key.releaseKeyID(); 190 token.releaseSession(session); 191 } 192 } 193 194 // mechanism == CKM_TLS_PRF 195 196 byte[] out = new byte[spec.getOutputLength()]; 197 CK_TLS_PRF_PARAMS params = new CK_TLS_PRF_PARAMS(seed, label, out); 198 199 Session session = null; 200 long keyID = p11Key.getKeyID(); 201 try { 202 session = token.getOpSession(); 203 token.p11.C_DeriveKey(session.id(), 204 new CK_MECHANISM(mechanism, params), keyID, null); 205 return new SecretKeySpec(out, "TlsPrf"); 206 } catch (PKCS11Exception e) { 207 throw new ProviderException("Could not calculate PRF", e); 208 } finally { 209 p11Key.releaseKeyID(); 210 token.releaseSession(session); 211 } 212 } 213 214 } 215