1 /* 2 * Copyright (c) 2003, 2016, 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 import java.nio.ByteBuffer; 30 31 import java.security.*; 32 33 import javax.crypto.SecretKey; 34 35 import sun.nio.ch.DirectBuffer; 36 37 import sun.security.util.MessageDigestSpi2; 38 39 import sun.security.pkcs11.wrapper.*; 40 import static sun.security.pkcs11.wrapper.PKCS11Constants.*; 41 42 /** 43 * MessageDigest implementation class. This class currently supports 44 * MD2, MD5, SHA-1, SHA-224, SHA-256, SHA-384, and SHA-512. 45 * 46 * Note that many digest operations are on fairly small amounts of data 47 * (less than 100 bytes total). For example, the 2nd hashing in HMAC or 48 * the PRF in TLS. In order to speed those up, we use some buffering to 49 * minimize number of the Java->native transitions. 50 * 51 * @author Andreas Sterbenz 52 * @since 1.5 53 */ 54 final class P11Digest extends MessageDigestSpi implements Cloneable, 55 MessageDigestSpi2 { 56 57 /* fields initialized, no session acquired */ 58 private final static int S_BLANK = 1; 59 60 /* data in buffer, session acquired, but digest not initialized */ 61 private final static int S_BUFFERED = 2; 62 63 /* session initialized for digesting */ 64 private final static int S_INIT = 3; 65 66 private final static int BUFFER_SIZE = 96; 67 68 // token instance 69 private final Token token; 70 71 // algorithm name 72 private final String algorithm; 73 74 // mechanism id object 75 private final CK_MECHANISM mechanism; 76 77 // length of the digest in bytes 78 private final int digestLength; 79 80 // associated session, if any 81 private Session session; 82 83 // current state, one of S_* above 84 private int state; 85 86 // buffer to reduce number of JNI calls 87 private byte[] buffer; 88 89 // offset into the buffer 90 private int bufOfs; 91 92 P11Digest(Token token, String algorithm, long mechanism) { 93 super(); 94 this.token = token; 95 this.algorithm = algorithm; 96 this.mechanism = new CK_MECHANISM(mechanism); 97 switch ((int)mechanism) { 98 case (int)CKM_MD2: 99 case (int)CKM_MD5: 100 digestLength = 16; 101 break; 102 case (int)CKM_SHA_1: 103 digestLength = 20; 104 break; 105 case (int)CKM_SHA224: 106 digestLength = 28; 107 break; 108 case (int)CKM_SHA256: 109 digestLength = 32; 110 break; 111 case (int)CKM_SHA384: 112 digestLength = 48; 113 break; 114 case (int)CKM_SHA512: 115 digestLength = 64; 116 break; 117 default: 118 throw new ProviderException("Unknown mechanism: " + mechanism); 119 } 120 buffer = new byte[BUFFER_SIZE]; 121 state = S_BLANK; 122 } 123 124 // see JCA spec 125 protected int engineGetDigestLength() { 126 return digestLength; 127 } 128 129 private void fetchSession() { 130 token.ensureValid(); 131 if (state == S_BLANK) { 132 try { 133 session = token.getOpSession(); 134 state = S_BUFFERED; 135 } catch (PKCS11Exception e) { 136 throw new ProviderException("No more session available", e); 137 } 138 } 139 } 140 141 // see JCA spec 142 protected void engineReset() { 143 token.ensureValid(); 144 145 if (session != null) { 146 if (state == S_INIT && token.explicitCancel == true 147 && session.hasObjects() == false) { 148 session = token.killSession(session); 149 } else { 150 session = token.releaseSession(session); 151 } 152 } 153 state = S_BLANK; 154 bufOfs = 0; 155 } 156 157 // see JCA spec 158 protected byte[] engineDigest() { 159 try { 160 byte[] digest = new byte[digestLength]; 161 int n = engineDigest(digest, 0, digestLength); 162 return digest; 163 } catch (DigestException e) { 164 throw new ProviderException("internal error", e); 165 } 166 } 167 168 // see JCA spec 169 protected int engineDigest(byte[] digest, int ofs, int len) 170 throws DigestException { 171 if (len < digestLength) { 172 throw new DigestException("Length must be at least " + 173 digestLength); 174 } 175 176 fetchSession(); 177 try { 178 int n; 179 if (state == S_BUFFERED) { 180 n = token.p11.C_DigestSingle(session.id(), mechanism, buffer, 0, 181 bufOfs, digest, ofs, len); 182 bufOfs = 0; 183 } else { 184 if (bufOfs != 0) { 185 token.p11.C_DigestUpdate(session.id(), 0, buffer, 0, 186 bufOfs); 187 bufOfs = 0; 188 } 189 n = token.p11.C_DigestFinal(session.id(), digest, ofs, len); 190 } 191 if (n != digestLength) { 192 throw new ProviderException("internal digest length error"); 193 } 194 return n; 195 } catch (PKCS11Exception e) { 196 throw new ProviderException("digest() failed", e); 197 } finally { 198 engineReset(); 199 } 200 } 201 202 // see JCA spec 203 protected void engineUpdate(byte in) { 204 byte[] temp = { in }; 205 engineUpdate(temp, 0, 1); 206 } 207 208 // see JCA spec 209 protected void engineUpdate(byte[] in, int ofs, int len) { 210 if (len <= 0) { 211 return; 212 } 213 214 fetchSession(); 215 try { 216 if (state == S_BUFFERED) { 217 token.p11.C_DigestInit(session.id(), mechanism); 218 state = S_INIT; 219 } 220 if ((bufOfs != 0) && (bufOfs + len > buffer.length)) { 221 // process the buffered data 222 token.p11.C_DigestUpdate(session.id(), 0, buffer, 0, bufOfs); 223 bufOfs = 0; 224 } 225 if (bufOfs + len > buffer.length) { 226 // process the new data 227 token.p11.C_DigestUpdate(session.id(), 0, in, ofs, len); 228 } else { 229 // buffer the new data 230 System.arraycopy(in, ofs, buffer, bufOfs, len); 231 bufOfs += len; 232 } 233 } catch (PKCS11Exception e) { 234 engineReset(); 235 throw new ProviderException("update() failed", e); 236 } 237 } 238 239 // Called by SunJSSE via reflection during the SSL 3.0 handshake if 240 // the master secret is sensitive. 241 // Note: Change to protected after this method is moved from 242 // sun.security.util.MessageSpi2 interface to 243 // java.security.MessageDigestSpi class 244 public void engineUpdate(SecretKey key) throws InvalidKeyException { 245 // SunJSSE calls this method only if the key does not have a RAW 246 // encoding, i.e. if it is sensitive. Therefore, no point in calling 247 // SecretKeyFactory to try to convert it. Just verify it ourselves. 248 if (key instanceof P11Key == false) { 249 throw new InvalidKeyException("Not a P11Key: " + key); 250 } 251 P11Key p11Key = (P11Key)key; 252 if (p11Key.token != token) { 253 throw new InvalidKeyException("Not a P11Key of this provider: " + 254 key); 255 } 256 257 fetchSession(); 258 try { 259 if (state == S_BUFFERED) { 260 token.p11.C_DigestInit(session.id(), mechanism); 261 state = S_INIT; 262 } 263 264 if (bufOfs != 0) { 265 token.p11.C_DigestUpdate(session.id(), 0, buffer, 0, bufOfs); 266 bufOfs = 0; 267 } 268 p11Key.incNativeKeyRef(); 269 try { 270 token.p11.C_DigestKey(session.id(), p11Key.keyID); 271 } finally { 272 p11Key.decNativeKeyRef(); 273 } 274 } catch (PKCS11Exception e) { 275 engineReset(); 276 throw new ProviderException("update(SecretKey) failed", e); 277 } 278 } 279 280 // see JCA spec 281 protected void engineUpdate(ByteBuffer byteBuffer) { 282 int len = byteBuffer.remaining(); 283 if (len <= 0) { 284 return; 285 } 286 287 if (byteBuffer instanceof DirectBuffer == false) { 288 super.engineUpdate(byteBuffer); 289 return; 290 } 291 292 fetchSession(); 293 long addr = ((DirectBuffer)byteBuffer).address(); 294 int ofs = byteBuffer.position(); 295 try { 296 if (state == S_BUFFERED) { 297 token.p11.C_DigestInit(session.id(), mechanism); 298 state = S_INIT; 299 } 300 if (bufOfs != 0) { 301 token.p11.C_DigestUpdate(session.id(), 0, buffer, 0, bufOfs); 302 bufOfs = 0; 303 } 304 token.p11.C_DigestUpdate(session.id(), addr + ofs, null, 0, len); 305 byteBuffer.position(ofs + len); 306 } catch (PKCS11Exception e) { 307 engineReset(); 308 throw new ProviderException("update() failed", e); 309 } 310 } 311 312 public Object clone() throws CloneNotSupportedException { 313 P11Digest copy = (P11Digest) super.clone(); 314 copy.buffer = buffer.clone(); 315 try { 316 if (session != null) { 317 copy.session = copy.token.getOpSession(); 318 } 319 if (state == S_INIT) { 320 byte[] stateValues = 321 token.p11.C_GetOperationState(session.id()); 322 token.p11.C_SetOperationState(copy.session.id(), 323 stateValues, 0, 0); 324 } 325 } catch (PKCS11Exception e) { 326 throw (CloneNotSupportedException) 327 (new CloneNotSupportedException(algorithm).initCause(e)); 328 } 329 return copy; 330 } 331 } --- EOF ---