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