jdk/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11Mac.java
changeset 43248 5e15de85a1a0
parent 43247 8d242299a219
child 43249 b017b10f62ab
equal deleted inserted replaced
43247:8d242299a219 43248:5e15de85a1a0
     1 /*
       
     2  * Copyright (c) 2003, 2012, 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 import java.security.spec.AlgorithmParameterSpec;
       
    33 
       
    34 import javax.crypto.MacSpi;
       
    35 
       
    36 import sun.nio.ch.DirectBuffer;
       
    37 
       
    38 import sun.security.pkcs11.wrapper.*;
       
    39 import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
       
    40 
       
    41 /**
       
    42  * MAC implementation class. This class currently supports HMAC using
       
    43  * MD5, SHA-1, SHA-224, SHA-256, SHA-384, and SHA-512 and the SSL3 MAC
       
    44  * using MD5 and SHA-1.
       
    45  *
       
    46  * Note that unlike other classes (e.g. Signature), this does not
       
    47  * composite various operations if the token only supports part of the
       
    48  * required functionality. The MAC implementations in SunJCE already
       
    49  * do exactly that by implementing an MAC on top of MessageDigests. We
       
    50  * could not do any better than they.
       
    51  *
       
    52  * @author  Andreas Sterbenz
       
    53  * @since   1.5
       
    54  */
       
    55 final class P11Mac extends MacSpi {
       
    56 
       
    57     /* unitialized, all fields except session have arbitrary values */
       
    58     private final static int S_UNINIT   = 1;
       
    59 
       
    60     /* session initialized, no data processed yet */
       
    61     private final static int S_RESET    = 2;
       
    62 
       
    63     /* session initialized, data processed */
       
    64     private final static int S_UPDATE   = 3;
       
    65 
       
    66     /* transitional state after doFinal() before we go to S_UNINIT */
       
    67     private final static int S_DOFINAL  = 4;
       
    68 
       
    69     // token instance
       
    70     private final Token token;
       
    71 
       
    72     // algorithm name
       
    73     private final String algorithm;
       
    74 
       
    75     // mechanism id
       
    76     private final long mechanism;
       
    77 
       
    78     // mechanism object
       
    79     private final CK_MECHANISM ckMechanism;
       
    80 
       
    81     // length of the MAC in bytes
       
    82     private final int macLength;
       
    83 
       
    84     // key instance used, if operation active
       
    85     private P11Key p11Key;
       
    86 
       
    87     // associated session, if any
       
    88     private Session session;
       
    89 
       
    90     // state, one of S_* above
       
    91     private int state;
       
    92 
       
    93     // one byte buffer for the update(byte) method, initialized on demand
       
    94     private byte[] oneByte;
       
    95 
       
    96     P11Mac(Token token, String algorithm, long mechanism)
       
    97             throws PKCS11Exception {
       
    98         super();
       
    99         this.token = token;
       
   100         this.algorithm = algorithm;
       
   101         this.mechanism = mechanism;
       
   102         Long params = null;
       
   103         switch ((int)mechanism) {
       
   104         case (int)CKM_MD5_HMAC:
       
   105             macLength = 16;
       
   106             break;
       
   107         case (int)CKM_SHA_1_HMAC:
       
   108             macLength = 20;
       
   109             break;
       
   110         case (int)CKM_SHA224_HMAC:
       
   111             macLength = 28;
       
   112             break;
       
   113         case (int)CKM_SHA256_HMAC:
       
   114             macLength = 32;
       
   115             break;
       
   116         case (int)CKM_SHA384_HMAC:
       
   117             macLength = 48;
       
   118             break;
       
   119         case (int)CKM_SHA512_HMAC:
       
   120             macLength = 64;
       
   121             break;
       
   122         case (int)CKM_SSL3_MD5_MAC:
       
   123             macLength = 16;
       
   124             params = Long.valueOf(16);
       
   125             break;
       
   126         case (int)CKM_SSL3_SHA1_MAC:
       
   127             macLength = 20;
       
   128             params = Long.valueOf(20);
       
   129             break;
       
   130         default:
       
   131             throw new ProviderException("Unknown mechanism: " + mechanism);
       
   132         }
       
   133         ckMechanism = new CK_MECHANISM(mechanism, params);
       
   134         state = S_UNINIT;
       
   135         initialize();
       
   136     }
       
   137 
       
   138     private void ensureInitialized() throws PKCS11Exception {
       
   139         token.ensureValid();
       
   140         if (state == S_UNINIT) {
       
   141             initialize();
       
   142         }
       
   143     }
       
   144 
       
   145     private void cancelOperation() {
       
   146         token.ensureValid();
       
   147         if (state == S_UNINIT) {
       
   148             return;
       
   149         }
       
   150         state = S_UNINIT;
       
   151         if ((session == null) || (token.explicitCancel == false)) {
       
   152             return;
       
   153         }
       
   154         try {
       
   155             token.p11.C_SignFinal(session.id(), 0);
       
   156         } catch (PKCS11Exception e) {
       
   157             throw new ProviderException("Cancel failed", e);
       
   158         }
       
   159     }
       
   160 
       
   161     private void initialize() throws PKCS11Exception {
       
   162         if (state == S_RESET) {
       
   163             return;
       
   164         }
       
   165         if (session == null) {
       
   166             session = token.getOpSession();
       
   167         }
       
   168         if (p11Key != null) {
       
   169             token.p11.C_SignInit
       
   170                 (session.id(), ckMechanism, p11Key.keyID);
       
   171             state = S_RESET;
       
   172         } else {
       
   173             state = S_UNINIT;
       
   174         }
       
   175     }
       
   176 
       
   177     // see JCE spec
       
   178     protected int engineGetMacLength() {
       
   179         return macLength;
       
   180     }
       
   181 
       
   182     // see JCE spec
       
   183     protected void engineReset() {
       
   184         // the framework insists on calling reset() after doFinal(),
       
   185         // but we prefer to take care of reinitialization ourselves
       
   186         if (state == S_DOFINAL) {
       
   187             state = S_UNINIT;
       
   188             return;
       
   189         }
       
   190         cancelOperation();
       
   191         try {
       
   192             initialize();
       
   193         } catch (PKCS11Exception e) {
       
   194             throw new ProviderException("reset() failed, ", e);
       
   195         }
       
   196     }
       
   197 
       
   198     // see JCE spec
       
   199     protected void engineInit(Key key, AlgorithmParameterSpec params)
       
   200             throws InvalidKeyException, InvalidAlgorithmParameterException {
       
   201         if (params != null) {
       
   202             throw new InvalidAlgorithmParameterException
       
   203                 ("Parameters not supported");
       
   204         }
       
   205         cancelOperation();
       
   206         p11Key = P11SecretKeyFactory.convertKey(token, key, algorithm);
       
   207         try {
       
   208             initialize();
       
   209         } catch (PKCS11Exception e) {
       
   210             throw new InvalidKeyException("init() failed", e);
       
   211         }
       
   212     }
       
   213 
       
   214     // see JCE spec
       
   215     protected byte[] engineDoFinal() {
       
   216         try {
       
   217             ensureInitialized();
       
   218             byte[] mac = token.p11.C_SignFinal(session.id(), 0);
       
   219             state = S_DOFINAL;
       
   220             return mac;
       
   221         } catch (PKCS11Exception e) {
       
   222             throw new ProviderException("doFinal() failed", e);
       
   223         } finally {
       
   224             session = token.releaseSession(session);
       
   225         }
       
   226     }
       
   227 
       
   228     // see JCE spec
       
   229     protected void engineUpdate(byte input) {
       
   230         if (oneByte == null) {
       
   231            oneByte = new byte[1];
       
   232         }
       
   233         oneByte[0] = input;
       
   234         engineUpdate(oneByte, 0, 1);
       
   235     }
       
   236 
       
   237     // see JCE spec
       
   238     protected void engineUpdate(byte[] b, int ofs, int len) {
       
   239         try {
       
   240             ensureInitialized();
       
   241             token.p11.C_SignUpdate(session.id(), 0, b, ofs, len);
       
   242             state = S_UPDATE;
       
   243         } catch (PKCS11Exception e) {
       
   244             throw new ProviderException("update() failed", e);
       
   245         }
       
   246     }
       
   247 
       
   248     // see JCE spec
       
   249     protected void engineUpdate(ByteBuffer byteBuffer) {
       
   250         try {
       
   251             ensureInitialized();
       
   252             int len = byteBuffer.remaining();
       
   253             if (len <= 0) {
       
   254                 return;
       
   255             }
       
   256             if (byteBuffer instanceof DirectBuffer == false) {
       
   257                 super.engineUpdate(byteBuffer);
       
   258                 return;
       
   259             }
       
   260             long addr = ((DirectBuffer)byteBuffer).address();
       
   261             int ofs = byteBuffer.position();
       
   262             token.p11.C_SignUpdate(session.id(), addr + ofs, null, 0, len);
       
   263             byteBuffer.position(ofs + len);
       
   264             state = S_UPDATE;
       
   265         } catch (PKCS11Exception e) {
       
   266             throw new ProviderException("update() failed", e);
       
   267         }
       
   268     }
       
   269 }