0N/A/*
2362N/A * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage sun.security.pkcs11;
0N/A
0N/Aimport java.util.*;
0N/Aimport java.nio.ByteBuffer;
0N/A
0N/Aimport java.security.*;
0N/A
0N/Aimport javax.crypto.SecretKey;
0N/A
0N/Aimport sun.nio.ch.DirectBuffer;
0N/A
0N/Aimport sun.security.pkcs11.wrapper.*;
0N/Aimport static sun.security.pkcs11.wrapper.PKCS11Constants.*;
0N/A
0N/A/**
0N/A * MessageDigest implementation class. This class currently supports
0N/A * MD2, MD5, SHA-1, SHA-256, SHA-384, and SHA-512.
0N/A *
0N/A * Note that many digest operations are on fairly small amounts of data
0N/A * (less than 100 bytes total). For example, the 2nd hashing in HMAC or
0N/A * the PRF in TLS. In order to speed those up, we use some buffering to
0N/A * minimize number of the Java->native transitions.
0N/A *
0N/A * @author Andreas Sterbenz
0N/A * @since 1.5
0N/A */
0N/Afinal class P11Digest extends MessageDigestSpi {
0N/A
0N/A /* unitialized, fields uninitialized, no session acquired */
0N/A private final static int S_BLANK = 1;
0N/A
0N/A // data in buffer, all fields valid, session acquired
0N/A // but digest not initialized
0N/A private final static int S_BUFFERED = 2;
0N/A
0N/A /* session initialized for digesting */
0N/A private final static int S_INIT = 3;
0N/A
0N/A private final static int BUFFER_SIZE = 96;
0N/A
0N/A // token instance
0N/A private final Token token;
0N/A
0N/A // algorithm name
0N/A private final String algorithm;
0N/A
0N/A // mechanism id
0N/A private final long mechanism;
0N/A
0N/A // length of the digest in bytes
0N/A private final int digestLength;
0N/A
0N/A // associated session, if any
0N/A private Session session;
0N/A
0N/A // current state, one of S_* above
0N/A private int state;
0N/A
0N/A // one byte buffer for the update(byte) method, initialized on demand
0N/A private byte[] oneByte;
0N/A
0N/A // buffer to reduce number of JNI calls
0N/A private final byte[] buffer;
0N/A
0N/A // offset into the buffer
0N/A private int bufOfs;
0N/A
0N/A P11Digest(Token token, String algorithm, long mechanism) {
0N/A super();
0N/A this.token = token;
0N/A this.algorithm = algorithm;
0N/A this.mechanism = mechanism;
0N/A switch ((int)mechanism) {
0N/A case (int)CKM_MD2:
0N/A case (int)CKM_MD5:
0N/A digestLength = 16;
0N/A break;
0N/A case (int)CKM_SHA_1:
0N/A digestLength = 20;
0N/A break;
0N/A case (int)CKM_SHA256:
0N/A digestLength = 32;
0N/A break;
0N/A case (int)CKM_SHA384:
0N/A digestLength = 48;
0N/A break;
0N/A case (int)CKM_SHA512:
0N/A digestLength = 64;
0N/A break;
0N/A default:
0N/A throw new ProviderException("Unknown mechanism: " + mechanism);
0N/A }
0N/A buffer = new byte[BUFFER_SIZE];
0N/A state = S_BLANK;
0N/A engineReset();
0N/A }
0N/A
0N/A // see JCA spec
0N/A protected int engineGetDigestLength() {
0N/A return digestLength;
0N/A }
0N/A
0N/A private void cancelOperation() {
0N/A token.ensureValid();
0N/A if (session == null) {
0N/A return;
0N/A }
0N/A if ((state != S_INIT) || (token.explicitCancel == false)) {
0N/A return;
0N/A }
0N/A // need to explicitly "cancel" active op by finishing it
0N/A try {
0N/A token.p11.C_DigestFinal(session.id(), buffer, 0, buffer.length);
0N/A } catch (PKCS11Exception e) {
0N/A throw new ProviderException("cancel() failed", e);
0N/A } finally {
0N/A state = S_BUFFERED;
0N/A }
0N/A }
0N/A
0N/A private void fetchSession() {
0N/A token.ensureValid();
0N/A if (state == S_BLANK) {
0N/A engineReset();
0N/A }
0N/A }
0N/A
0N/A // see JCA spec
0N/A protected void engineReset() {
0N/A try {
0N/A cancelOperation();
0N/A bufOfs = 0;
0N/A if (session == null) {
0N/A session = token.getOpSession();
0N/A }
0N/A state = S_BUFFERED;
0N/A } catch (PKCS11Exception e) {
0N/A state = S_BLANK;
0N/A throw new ProviderException("reset() failed, ", e);
0N/A }
0N/A }
0N/A
0N/A // see JCA spec
0N/A protected byte[] engineDigest() {
0N/A try {
0N/A byte[] digest = new byte[digestLength];
0N/A int n = engineDigest(digest, 0, digestLength);
0N/A return digest;
0N/A } catch (DigestException e) {
0N/A throw new ProviderException("internal error", e);
0N/A }
0N/A }
0N/A
0N/A // see JCA spec
0N/A protected int engineDigest(byte[] digest, int ofs, int len)
0N/A throws DigestException {
0N/A if (len < digestLength) {
0N/A throw new DigestException("Length must be at least " + digestLength);
0N/A }
0N/A fetchSession();
0N/A try {
0N/A int n;
0N/A if (state == S_BUFFERED) {
0N/A n = token.p11.C_DigestSingle(session.id(),
0N/A new CK_MECHANISM(mechanism),
0N/A buffer, 0, bufOfs, digest, ofs, len);
0N/A } else {
0N/A if (bufOfs != 0) {
0N/A doUpdate(buffer, 0, bufOfs);
0N/A }
0N/A n = token.p11.C_DigestFinal(session.id(), digest, ofs, len);
0N/A }
0N/A if (n != digestLength) {
0N/A throw new ProviderException("internal digest length error");
0N/A }
0N/A return n;
0N/A } catch (PKCS11Exception e) {
0N/A throw new ProviderException("digest() failed", e);
0N/A } finally {
0N/A state = S_BLANK;
0N/A bufOfs = 0;
0N/A session = token.releaseSession(session);
0N/A }
0N/A }
0N/A
0N/A // see JCA spec
0N/A protected void engineUpdate(byte in) {
0N/A if (oneByte == null) {
0N/A oneByte = new byte[1];
0N/A }
0N/A oneByte[0] = in;
0N/A engineUpdate(oneByte, 0, 1);
0N/A }
0N/A
0N/A // see JCA spec
0N/A protected void engineUpdate(byte[] in, int ofs, int len) {
0N/A fetchSession();
0N/A if (len <= 0) {
0N/A return;
0N/A }
0N/A if ((bufOfs != 0) && (bufOfs + len > buffer.length)) {
0N/A doUpdate(buffer, 0, bufOfs);
0N/A bufOfs = 0;
0N/A }
0N/A if (bufOfs + len > buffer.length) {
0N/A doUpdate(in, ofs, len);
0N/A } else {
0N/A System.arraycopy(in, ofs, buffer, bufOfs, len);
0N/A bufOfs += len;
0N/A }
0N/A }
0N/A
0N/A // Called by SunJSSE via reflection during the SSL 3.0 handshake if
0N/A // the master secret is sensitive. We may want to consider making this
0N/A // method public in a future release.
0N/A protected void implUpdate(SecretKey key) throws InvalidKeyException {
0N/A fetchSession();
0N/A if (bufOfs != 0) {
0N/A doUpdate(buffer, 0, bufOfs);
0N/A bufOfs = 0;
0N/A }
0N/A // SunJSSE calls this method only if the key does not have a RAW
0N/A // encoding, i.e. if it is sensitive. Therefore, no point in calling
0N/A // SecretKeyFactory to try to convert it. Just verify it ourselves.
0N/A if (key instanceof P11Key == false) {
0N/A throw new InvalidKeyException("Not a P11Key: " + key);
0N/A }
0N/A P11Key p11Key = (P11Key)key;
0N/A if (p11Key.token != token) {
0N/A throw new InvalidKeyException("Not a P11Key of this provider: " + key);
0N/A }
0N/A try {
0N/A if (state == S_BUFFERED) {
0N/A token.p11.C_DigestInit(session.id(), new CK_MECHANISM(mechanism));
0N/A state = S_INIT;
0N/A }
0N/A token.p11.C_DigestKey(session.id(), p11Key.keyID);
0N/A } catch (PKCS11Exception e) {
0N/A throw new ProviderException("update(SecretKey) failed", e);
0N/A }
0N/A }
0N/A
0N/A // see JCA spec
0N/A protected void engineUpdate(ByteBuffer byteBuffer) {
0N/A fetchSession();
0N/A int len = byteBuffer.remaining();
0N/A if (len <= 0) {
0N/A return;
0N/A }
0N/A if (byteBuffer instanceof DirectBuffer == false) {
0N/A super.engineUpdate(byteBuffer);
0N/A return;
0N/A }
0N/A long addr = ((DirectBuffer)byteBuffer).address();
0N/A int ofs = byteBuffer.position();
0N/A try {
0N/A if (state == S_BUFFERED) {
0N/A token.p11.C_DigestInit(session.id(), new CK_MECHANISM(mechanism));
0N/A state = S_INIT;
0N/A if (bufOfs != 0) {
0N/A doUpdate(buffer, 0, bufOfs);
0N/A bufOfs = 0;
0N/A }
0N/A }
0N/A token.p11.C_DigestUpdate(session.id(), addr + ofs, null, 0, len);
0N/A byteBuffer.position(ofs + len);
0N/A } catch (PKCS11Exception e) {
0N/A throw new ProviderException("update() failed", e);
0N/A }
0N/A }
0N/A
0N/A private void doUpdate(byte[] in, int ofs, int len) {
0N/A if (len <= 0) {
0N/A return;
0N/A }
0N/A try {
0N/A if (state == S_BUFFERED) {
0N/A token.p11.C_DigestInit(session.id(), new CK_MECHANISM(mechanism));
0N/A state = S_INIT;
0N/A }
0N/A token.p11.C_DigestUpdate(session.id(), 0, in, ofs, len);
0N/A } catch (PKCS11Exception e) {
0N/A throw new ProviderException("update() failed", e);
0N/A }
0N/A }
0N/A}