blob: ae37d696d937efc218a47d5817cb24c25b5e271a [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003-2007 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.security.pkcs11;
27
28import java.util.*;
29import java.nio.ByteBuffer;
30
31import java.security.*;
32import java.security.spec.AlgorithmParameterSpec;
33
34import javax.crypto.MacSpi;
35
36import sun.nio.ch.DirectBuffer;
37
38import sun.security.pkcs11.wrapper.*;
39import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
40
41/**
42 * MAC implementation class. This class currently supports HMAC using
43 * MD5, SHA-1, SHA-256, SHA-384, and SHA-512 and the SSL3 MAC using MD5
44 * 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 */
55final 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_SHA256_HMAC:
111 macLength = 32;
112 break;
113 case (int)CKM_SHA384_HMAC:
114 macLength = 48;
115 break;
116 case (int)CKM_SHA512_HMAC:
117 macLength = 64;
118 break;
119 case (int)CKM_SSL3_MD5_MAC:
120 macLength = 16;
121 params = Long.valueOf(16);
122 break;
123 case (int)CKM_SSL3_SHA1_MAC:
124 macLength = 20;
125 params = Long.valueOf(20);
126 break;
127 default:
128 throw new ProviderException("Unknown mechanism: " + mechanism);
129 }
130 ckMechanism = new CK_MECHANISM(mechanism, params);
131 state = S_UNINIT;
132 initialize();
133 }
134
135 private void ensureInitialized() throws PKCS11Exception {
136 token.ensureValid();
137 if (state == S_UNINIT) {
138 initialize();
139 }
140 }
141
142 private void cancelOperation() {
143 token.ensureValid();
144 if (state == S_UNINIT) {
145 return;
146 }
147 state = S_UNINIT;
148 if ((session == null) || (token.explicitCancel == false)) {
149 return;
150 }
151 try {
152 token.p11.C_SignFinal(session.id(), 0);
153 } catch (PKCS11Exception e) {
154 throw new ProviderException("Cancel failed", e);
155 }
156 }
157
158 private void initialize() throws PKCS11Exception {
159 if (state == S_RESET) {
160 return;
161 }
162 if (session == null) {
163 session = token.getOpSession();
164 }
165 if (p11Key != null) {
166 token.p11.C_SignInit
167 (session.id(), ckMechanism, p11Key.keyID);
168 state = S_RESET;
169 } else {
170 state = S_UNINIT;
171 }
172 }
173
174 // see JCE spec
175 protected int engineGetMacLength() {
176 return macLength;
177 }
178
179 // see JCE spec
180 protected void engineReset() {
181 // the framework insists on calling reset() after doFinal(),
182 // but we prefer to take care of reinitialization ourselves
183 if (state == S_DOFINAL) {
184 state = S_UNINIT;
185 return;
186 }
187 cancelOperation();
188 try {
189 initialize();
190 } catch (PKCS11Exception e) {
191 throw new ProviderException("reset() failed, ", e);
192 }
193 }
194
195 // see JCE spec
196 protected void engineInit(Key key, AlgorithmParameterSpec params)
197 throws InvalidKeyException, InvalidAlgorithmParameterException {
198 if (params != null) {
199 throw new InvalidAlgorithmParameterException
200 ("Parameters not supported");
201 }
202 cancelOperation();
203 p11Key = P11SecretKeyFactory.convertKey(token, key, algorithm);
204 try {
205 initialize();
206 } catch (PKCS11Exception e) {
207 throw new InvalidKeyException("init() failed", e);
208 }
209 }
210
211 // see JCE spec
212 protected byte[] engineDoFinal() {
213 try {
214 ensureInitialized();
215 byte[] mac = token.p11.C_SignFinal(session.id(), 0);
216 state = S_DOFINAL;
217 return mac;
218 } catch (PKCS11Exception e) {
219 throw new ProviderException("doFinal() failed", e);
220 } finally {
221 session = token.releaseSession(session);
222 }
223 }
224
225 // see JCE spec
226 protected void engineUpdate(byte input) {
227 if (oneByte == null) {
228 oneByte = new byte[1];
229 }
230 oneByte[0] = input;
231 engineUpdate(oneByte, 0, 1);
232 }
233
234 // see JCE spec
235 protected void engineUpdate(byte[] b, int ofs, int len) {
236 try {
237 ensureInitialized();
238 token.p11.C_SignUpdate(session.id(), 0, b, ofs, len);
239 state = S_UPDATE;
240 } catch (PKCS11Exception e) {
241 throw new ProviderException("update() failed", e);
242 }
243 }
244
245 // see JCE spec
246 protected void engineUpdate(ByteBuffer byteBuffer) {
247 try {
248 ensureInitialized();
249 int len = byteBuffer.remaining();
250 if (len <= 0) {
251 return;
252 }
253 if (byteBuffer instanceof DirectBuffer == false) {
254 super.engineUpdate(byteBuffer);
255 return;
256 }
257 long addr = ((DirectBuffer)byteBuffer).address();
258 int ofs = byteBuffer.position();
259 token.p11.C_SignUpdate(session.id(), addr + ofs, null, 0, len);
260 byteBuffer.position(ofs + len);
261 state = S_UPDATE;
262 } catch (PKCS11Exception e) {
263 throw new ProviderException("update() failed", e);
264 }
265 }
266
267 protected void finalize() throws Throwable {
268 try {
269 if ((session != null) && token.isValid()) {
270 cancelOperation();
271 session = token.releaseSession(session);
272 }
273 } finally {
274 super.finalize();
275 }
276 }
277
278}