Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/pkcs11/P11Mac.java
38919 views
/*1* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.pkcs11;2627import java.nio.ByteBuffer;2829import java.security.*;30import java.security.spec.AlgorithmParameterSpec;3132import javax.crypto.MacSpi;3334import sun.nio.ch.DirectBuffer;3536import sun.security.pkcs11.wrapper.*;37import static sun.security.pkcs11.wrapper.PKCS11Constants.*;3839/**40* MAC implementation class. This class currently supports HMAC using41* MD5, SHA-1, SHA-224, SHA-256, SHA-384, and SHA-512 and the SSL3 MAC42* using MD5 and SHA-1.43*44* Note that unlike other classes (e.g. Signature), this does not45* composite various operations if the token only supports part of the46* required functionality. The MAC implementations in SunJCE already47* do exactly that by implementing an MAC on top of MessageDigests. We48* could not do any better than they.49*50* @author Andreas Sterbenz51* @since 1.552*/53final class P11Mac extends MacSpi {5455// token instance56private final Token token;5758// algorithm name59private final String algorithm;6061// mechanism object62private final CK_MECHANISM ckMechanism;6364// length of the MAC in bytes65private final int macLength;6667// key instance used, if operation active68private P11Key p11Key;6970// associated session, if any71private Session session;7273// initialization status74private boolean initialized;7576// one byte buffer for the update(byte) method, initialized on demand77private byte[] oneByte;7879P11Mac(Token token, String algorithm, long mechanism)80throws PKCS11Exception {81super();82this.token = token;83this.algorithm = algorithm;84Long params = null;85switch ((int)mechanism) {86case (int)CKM_MD5_HMAC:87macLength = 16;88break;89case (int)CKM_SHA_1_HMAC:90macLength = 20;91break;92case (int)CKM_SHA224_HMAC:93macLength = 28;94break;95case (int)CKM_SHA256_HMAC:96macLength = 32;97break;98case (int)CKM_SHA384_HMAC:99macLength = 48;100break;101case (int)CKM_SHA512_HMAC:102macLength = 64;103break;104case (int)CKM_SSL3_MD5_MAC:105macLength = 16;106params = Long.valueOf(16);107break;108case (int)CKM_SSL3_SHA1_MAC:109macLength = 20;110params = Long.valueOf(20);111break;112default:113throw new ProviderException("Unknown mechanism: " + mechanism);114}115ckMechanism = new CK_MECHANISM(mechanism, params);116}117118// reset the states to the pre-initialized values119private void reset(boolean doCancel) {120if (!initialized) {121return;122}123initialized = false;124125try {126if (session == null) {127return;128}129130if (doCancel && token.explicitCancel) {131cancelOperation();132}133} finally {134p11Key.releaseKeyID();135session = token.releaseSession(session);136}137}138139private void cancelOperation() {140token.ensureValid();141// cancel operation by finishing it; avoid killSession as some142// hardware vendors may require re-login143try {144token.p11.C_SignFinal(session.id(), 0);145} catch (PKCS11Exception e) {146if (e.getErrorCode() == CKR_OPERATION_NOT_INITIALIZED) {147// Cancel Operation may be invoked after an error on a PKCS#11148// call. If the operation inside the token was already cancelled,149// do not fail here. This is part of a defensive mechanism for150// PKCS#11 libraries that do not strictly follow the standard.151return;152}153throw new ProviderException("Cancel failed", e);154}155}156157private void ensureInitialized() throws PKCS11Exception {158if (!initialized) {159initialize();160}161}162163private void initialize() throws PKCS11Exception {164if (p11Key == null) {165throw new ProviderException(166"Operation cannot be performed without calling engineInit first");167}168token.ensureValid();169long p11KeyID = p11Key.getKeyID();170try {171if (session == null) {172session = token.getOpSession();173}174token.p11.C_SignInit(session.id(), ckMechanism, p11KeyID);175} catch (PKCS11Exception e) {176p11Key.releaseKeyID();177session = token.releaseSession(session);178throw e;179}180initialized = true;181}182183// see JCE spec184protected int engineGetMacLength() {185return macLength;186}187188// see JCE spec189protected void engineReset() {190reset(true);191}192193// see JCE spec194protected void engineInit(Key key, AlgorithmParameterSpec params)195throws InvalidKeyException, InvalidAlgorithmParameterException {196if (params != null) {197throw new InvalidAlgorithmParameterException198("Parameters not supported");199}200reset(true);201p11Key = P11SecretKeyFactory.convertKey(token, key, algorithm);202try {203initialize();204} catch (PKCS11Exception e) {205throw new InvalidKeyException("init() failed", e);206}207}208209// see JCE spec210protected byte[] engineDoFinal() {211try {212ensureInitialized();213return token.p11.C_SignFinal(session.id(), 0);214} catch (PKCS11Exception e) {215// As per the PKCS#11 standard, C_SignFinal may only216// keep the operation active on CKR_BUFFER_TOO_SMALL errors or217// successful calls to determine the output length. However,218// these cases are handled at OpenJDK's libj2pkcs11 native219// library. Thus, P11Mac::reset can be called with a 'false'220// doCancel argument from here.221throw new ProviderException("doFinal() failed", e);222} finally {223reset(false);224}225}226227// see JCE spec228protected void engineUpdate(byte input) {229if (oneByte == null) {230oneByte = new byte[1];231}232oneByte[0] = input;233engineUpdate(oneByte, 0, 1);234}235236// see JCE spec237protected void engineUpdate(byte[] b, int ofs, int len) {238try {239ensureInitialized();240token.p11.C_SignUpdate(session.id(), 0, b, ofs, len);241} catch (PKCS11Exception e) {242throw new ProviderException("update() failed", e);243}244}245246// see JCE spec247protected void engineUpdate(ByteBuffer byteBuffer) {248try {249ensureInitialized();250int len = byteBuffer.remaining();251if (len <= 0) {252return;253}254if (byteBuffer instanceof DirectBuffer == false) {255super.engineUpdate(byteBuffer);256return;257}258long addr = ((DirectBuffer)byteBuffer).address();259int ofs = byteBuffer.position();260token.p11.C_SignUpdate(session.id(), addr + ofs, null, 0, len);261byteBuffer.position(ofs + len);262} catch (PKCS11Exception e) {263throw new ProviderException("update() failed", e);264}265}266}267268269