1 /*
2  * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
3  */
4 
5 /* Copyright  (c) 2002 Graz University of Technology. All rights reserved.
6  *
7  * Redistribution and use in  source and binary forms, with or without
8  * modification, are permitted  provided that the following conditions are met:
9  *
10  * 1. Redistributions of  source code must retain the above copyright notice,
11  *    this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in  binary form must reproduce the above copyright notice,
14  *    this list of conditions and the following disclaimer in the documentation
15  *    and/or other materials provided with the distribution.
16  *
17  * 3. The end-user documentation included with the redistribution, if any, must
18  *    include the following acknowledgment:
19  *
20  *    "This product includes software developed by IAIK of Graz University of
21  *     Technology."
22  *
23  *    Alternately, this acknowledgment may appear in the software itself, if
24  *    and wherever such third-party acknowledgments normally appear.
25  *
26  * 4. The names "Graz University of Technology" and "IAIK of Graz University of
27  *    Technology" must not be used to endorse or promote products derived from
28  *    this software without prior written permission.
29  *
30  * 5. Products derived from this software may not be called
31  *    "IAIK PKCS Wrapper", nor may "IAIK" appear in their name, without prior
32  *    written permission of Graz University of Technology.
33  *
34  *  THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
35  *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
36  *  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
37  *  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE
38  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
39  *  OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
40  *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
41  *  OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
42  *  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
43  *  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44  *  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
45  *  POSSIBILITY  OF SUCH DAMAGE.
46  * ===========================================================================
47  */
48 
49 #include "pkcs11wrapper.h"
50 
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <assert.h>
55 
56 #include "sun_security_pkcs11_wrapper_PKCS11.h"
57 
58 #ifdef P11_ENABLE_C_ENCRYPTINIT
59 /*
60  * Class:     sun_security_pkcs11_wrapper_PKCS11
61  * Method:    C_EncryptInit
62  * Signature: (JLsun/security/pkcs11/wrapper/CK_MECHANISM;J)V
63  * Parametermapping:                    *PKCS11*
64  * @param   jlong jSessionHandle        CK_SESSION_HANDLE hSession
65  * @param   jobject jMechanism          CK_MECHANISM_PTR pMechanism
66  * @param   jlong jKeyHandle            CK_OBJECT_HANDLE hKey
67  */
68 JNIEXPORT void JNICALL
Java_sun_security_pkcs11_wrapper_PKCS11_C_1EncryptInit(JNIEnv * env,jobject obj,jlong jSessionHandle,jobject jMechanism,jlong jKeyHandle)69 Java_sun_security_pkcs11_wrapper_PKCS11_C_1EncryptInit
70 (JNIEnv *env, jobject obj, jlong jSessionHandle,
71  jobject jMechanism, jlong jKeyHandle)
72 {
73     CK_SESSION_HANDLE ckSessionHandle;
74     CK_MECHANISM ckMechanism;
75     CK_OBJECT_HANDLE ckKeyHandle;
76     CK_RV rv;
77 
78     CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);
79     if (ckpFunctions == NULL) { return; }
80 
81     ckSessionHandle = jLongToCKULong(jSessionHandle);
82     ckKeyHandle = jLongToCKULong(jKeyHandle);
83     jMechanismToCKMechanism(env, jMechanism, &ckMechanism);
84     if ((*env)->ExceptionCheck(env)) { return; }
85 
86     rv = (*ckpFunctions->C_EncryptInit)(ckSessionHandle, &ckMechanism,
87                                         ckKeyHandle);
88 
89     if (ckMechanism.pParameter != NULL_PTR) {
90         free(ckMechanism.pParameter);
91     }
92 
93     if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; }
94 }
95 #endif
96 
97 #ifdef P11_ENABLE_C_ENCRYPT
98 /*
99  * Class:     sun_security_pkcs11_wrapper_PKCS11
100  * Method:    C_Encrypt
101  * Signature: (J[BII[BII)I
102  * Parametermapping:                    *PKCS11*
103  * @param   jlong jSessionHandle        CK_SESSION_HANDLE hSession
104  * @param   jbyteArray jData            CK_BYTE_PTR pData
105  *                                      CK_ULONG ulDataLen
106  * @return  jbyteArray jEncryptedData   CK_BYTE_PTR pEncryptedData
107  *                                      CK_ULONG_PTR pulEncryptedDataLen
108  */
109 JNIEXPORT jint JNICALL
Java_sun_security_pkcs11_wrapper_PKCS11_C_1Encrypt(JNIEnv * env,jobject obj,jlong jSessionHandle,jbyteArray jIn,jint jInOfs,jint jInLen,jbyteArray jOut,jint jOutOfs,jint jOutLen)110 Java_sun_security_pkcs11_wrapper_PKCS11_C_1Encrypt
111 (JNIEnv *env, jobject obj, jlong jSessionHandle,
112  jbyteArray jIn, jint jInOfs, jint jInLen,
113  jbyteArray jOut, jint jOutOfs, jint jOutLen)
114 {
115     CK_SESSION_HANDLE ckSessionHandle;
116     CK_RV rv;
117 
118     CK_BYTE_PTR inBufP;
119     CK_BYTE_PTR outBufP;
120     CK_ULONG ckEncryptedPartLen;
121 
122     CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);
123     if (ckpFunctions == NULL) { return 0; }
124 
125     ckSessionHandle = jLongToCKULong(jSessionHandle);
126 
127     inBufP = (*env)->GetPrimitiveArrayCritical(env, jIn, NULL);
128     if (inBufP == NULL) { return 0; }
129 
130     outBufP = (*env)->GetPrimitiveArrayCritical(env, jOut, NULL);
131     if (outBufP == NULL) {
132         // Make sure to release inBufP
133         (*env)->ReleasePrimitiveArrayCritical(env, jIn, inBufP, JNI_ABORT);
134         return 0;
135     }
136 
137     ckEncryptedPartLen = jOutLen;
138 
139     rv = (*ckpFunctions->C_Encrypt)(ckSessionHandle,
140                                     (CK_BYTE_PTR)(inBufP + jInOfs), jInLen,
141                                     (CK_BYTE_PTR)(outBufP + jOutOfs),
142                                     &ckEncryptedPartLen);
143 
144     (*env)->ReleasePrimitiveArrayCritical(env, jIn, inBufP, JNI_ABORT);
145     (*env)->ReleasePrimitiveArrayCritical(env, jOut, outBufP, JNI_COMMIT);
146 
147     ckAssertReturnValueOK(env, rv);
148     return ckEncryptedPartLen;
149 }
150 #endif
151 
152 #ifdef P11_ENABLE_C_ENCRYPTUPDATE
153 /*
154  * Class:     sun_security_pkcs11_wrapper_PKCS11
155  * Method:    C_EncryptUpdate
156  * Signature: (J[BII[BII)I
157  * Parametermapping:                    *PKCS11*
158  * @param   jlong jSessionHandle        CK_SESSION_HANDLE hSession
159  * @param   jbyteArray jPart            CK_BYTE_PTR pPart
160  *                                      CK_ULONG ulPartLen
161  * @return  jbyteArray jEncryptedPart   CK_BYTE_PTR pEncryptedPart
162  *                                      CK_ULONG_PTR pulEncryptedPartLen
163  */
164 JNIEXPORT jint JNICALL
Java_sun_security_pkcs11_wrapper_PKCS11_C_1EncryptUpdate(JNIEnv * env,jobject obj,jlong jSessionHandle,jlong directIn,jbyteArray jIn,jint jInOfs,jint jInLen,jlong directOut,jbyteArray jOut,jint jOutOfs,jint jOutLen)165 Java_sun_security_pkcs11_wrapper_PKCS11_C_1EncryptUpdate
166 (JNIEnv *env, jobject obj, jlong jSessionHandle,
167  jlong directIn, jbyteArray jIn, jint jInOfs, jint jInLen,
168  jlong directOut, jbyteArray jOut, jint jOutOfs, jint jOutLen)
169 {
170     CK_SESSION_HANDLE ckSessionHandle;
171     CK_RV rv;
172 
173     CK_BYTE_PTR inBufP;
174     CK_BYTE_PTR outBufP;
175     CK_ULONG ckEncryptedPartLen;
176 
177     CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);
178     if (ckpFunctions == NULL) { return 0; }
179 
180     ckSessionHandle = jLongToCKULong(jSessionHandle);
181 
182     if (directIn != 0) {
183       inBufP = (CK_BYTE_PTR) jlong_to_ptr(directIn);
184     } else {
185       inBufP = (*env)->GetPrimitiveArrayCritical(env, jIn, NULL);
186       if (inBufP == NULL) { return 0; }
187     }
188 
189     if (directOut != 0) {
190       outBufP = (CK_BYTE_PTR) jlong_to_ptr(directOut);
191     } else {
192       outBufP = (*env)->GetPrimitiveArrayCritical(env, jOut, NULL);
193       if (outBufP == NULL) {
194           // Make sure to release inBufP
195           (*env)->ReleasePrimitiveArrayCritical(env, jIn, inBufP, JNI_ABORT);
196           return 0;
197       }
198     }
199 
200     ckEncryptedPartLen = jOutLen;
201 
202     //printf("EU: inBufP=%i, jInOfs=%i, jInLen=%i, outBufP=%i\n",
203     //       inBufP, jInOfs, jInLen, outBufP);
204 
205     rv = (*ckpFunctions->C_EncryptUpdate)(ckSessionHandle,
206                                           (CK_BYTE_PTR)(inBufP + jInOfs), jInLen,
207                                           (CK_BYTE_PTR)(outBufP + jOutOfs),
208                                           &ckEncryptedPartLen);
209 
210     //printf("EU: ckEncryptedPartLen=%i\n", ckEncryptedPartLen);
211 
212     if (directIn == 0) {
213         (*env)->ReleasePrimitiveArrayCritical(env, jIn, inBufP, JNI_ABORT);
214     }
215 
216     if (directOut == 0) {
217         (*env)->ReleasePrimitiveArrayCritical(env, jOut, outBufP, JNI_COMMIT);
218     }
219 
220     ckAssertReturnValueOK(env, rv);
221 
222     return ckEncryptedPartLen;
223 }
224 #endif
225 
226 #ifdef P11_ENABLE_C_ENCRYPTFINAL
227 /*
228  * Class:     sun_security_pkcs11_wrapper_PKCS11
229  * Method:    C_EncryptFinal
230  * Signature: (J[BII)I
231  * Parametermapping:                        *PKCS11*
232  * @param   jlong jSessionHandle            CK_SESSION_HANDLE hSession
233  * @return  jbyteArray jLastEncryptedPart   CK_BYTE_PTR pLastEncryptedDataPart
234  *                                          CK_ULONG_PTR pulLastEncryptedDataPartLen
235  */
236 JNIEXPORT jint JNICALL
Java_sun_security_pkcs11_wrapper_PKCS11_C_1EncryptFinal(JNIEnv * env,jobject obj,jlong jSessionHandle,jlong directOut,jbyteArray jOut,jint jOutOfs,jint jOutLen)237 Java_sun_security_pkcs11_wrapper_PKCS11_C_1EncryptFinal
238 (JNIEnv *env, jobject obj, jlong jSessionHandle,
239  jlong directOut, jbyteArray jOut, jint jOutOfs, jint jOutLen)
240 {
241     CK_SESSION_HANDLE ckSessionHandle;
242     CK_RV rv;
243     CK_BYTE_PTR outBufP;
244     CK_ULONG ckLastEncryptedPartLen;
245 
246     CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);
247     if (ckpFunctions == NULL) { return 0; }
248 
249     ckSessionHandle = jLongToCKULong(jSessionHandle);
250 
251     if (directOut != 0) {
252       outBufP = (CK_BYTE_PTR) jlong_to_ptr(directOut);
253     } else {
254       outBufP = (*env)->GetPrimitiveArrayCritical(env, jOut, NULL);
255       if (outBufP == NULL) { return 0; }
256     }
257 
258     ckLastEncryptedPartLen = jOutLen;
259 
260     //printf("EF: outBufP=%i\n", outBufP);
261 
262     rv = (*ckpFunctions->C_EncryptFinal)(ckSessionHandle,
263                                          (CK_BYTE_PTR)(outBufP + jOutOfs),
264                                          &ckLastEncryptedPartLen);
265 
266     //printf("EF: ckLastEncryptedPartLen=%i", ckLastEncryptedPartLen);
267 
268     if (directOut == 0) {
269         (*env)->ReleasePrimitiveArrayCritical(env, jOut, outBufP, JNI_COMMIT);
270     }
271 
272     ckAssertReturnValueOK(env, rv);
273 
274     return ckLastEncryptedPartLen;
275 }
276 #endif
277 
278 #ifdef P11_ENABLE_C_DECRYPTINIT
279 /*
280  * Class:     sun_security_pkcs11_wrapper_PKCS11
281  * Method:    C_DecryptInit
282  * Signature: (JLsun/security/pkcs11/wrapper/CK_MECHANISM;J)V
283  * Parametermapping:                    *PKCS11*
284  * @param   jlong jSessionHandle        CK_SESSION_HANDLE hSession
285  * @param   jobject jMechanism          CK_MECHANISM_PTR pMechanism
286  * @param   jlong jKeyHandle            CK_OBJECT_HANDLE hKey
287  */
288 JNIEXPORT void JNICALL
Java_sun_security_pkcs11_wrapper_PKCS11_C_1DecryptInit(JNIEnv * env,jobject obj,jlong jSessionHandle,jobject jMechanism,jlong jKeyHandle)289 Java_sun_security_pkcs11_wrapper_PKCS11_C_1DecryptInit
290 (JNIEnv *env, jobject obj, jlong jSessionHandle,
291  jobject jMechanism, jlong jKeyHandle)
292 {
293     CK_SESSION_HANDLE ckSessionHandle;
294     CK_MECHANISM ckMechanism;
295     CK_OBJECT_HANDLE ckKeyHandle;
296     CK_RV rv;
297 
298     CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);
299     if (ckpFunctions == NULL) { return; }
300 
301     ckSessionHandle = jLongToCKULong(jSessionHandle);
302     ckKeyHandle = jLongToCKULong(jKeyHandle);
303     jMechanismToCKMechanism(env, jMechanism, &ckMechanism);
304     if ((*env)->ExceptionCheck(env)) { return; }
305 
306     rv = (*ckpFunctions->C_DecryptInit)(ckSessionHandle, &ckMechanism,
307                                         ckKeyHandle);
308 
309     if (ckMechanism.pParameter != NULL_PTR) {
310         free(ckMechanism.pParameter);
311     }
312 
313     if (ckAssertReturnValueOK(env, rv) != CK_ASSERT_OK) { return; }
314 }
315 #endif
316 
317 #ifdef P11_ENABLE_C_DECRYPT
318 /*
319  * Class:     sun_security_pkcs11_wrapper_PKCS11
320  * Method:    C_Decrypt
321  * Signature: (J[BII[BII)I
322  * Parametermapping:                    *PKCS11*
323  * @param   jlong jSessionHandle        CK_SESSION_HANDLE hSession
324  * @param   jbyteArray jEncryptedData   CK_BYTE_PTR pEncryptedData
325  *                                      CK_ULONG ulEncryptedDataLen
326  * @return  jbyteArray jData            CK_BYTE_PTR pData
327  *                                      CK_ULONG_PTR pulDataLen
328  */
329 JNIEXPORT jint JNICALL
Java_sun_security_pkcs11_wrapper_PKCS11_C_1Decrypt(JNIEnv * env,jobject obj,jlong jSessionHandle,jbyteArray jIn,jint jInOfs,jint jInLen,jbyteArray jOut,jint jOutOfs,jint jOutLen)330 Java_sun_security_pkcs11_wrapper_PKCS11_C_1Decrypt
331 (JNIEnv *env, jobject obj, jlong jSessionHandle,
332  jbyteArray jIn, jint jInOfs, jint jInLen,
333  jbyteArray jOut, jint jOutOfs, jint jOutLen)
334 {
335     CK_SESSION_HANDLE ckSessionHandle;
336     CK_RV rv;
337 
338     CK_BYTE_PTR inBufP;
339     CK_BYTE_PTR outBufP;
340     CK_ULONG ckPartLen;
341 
342     CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);
343     if (ckpFunctions == NULL) { return 0; }
344 
345     ckSessionHandle = jLongToCKULong(jSessionHandle);
346 
347     inBufP = (*env)->GetPrimitiveArrayCritical(env, jIn, NULL);
348     if (inBufP == NULL) { return 0; }
349 
350     outBufP = (*env)->GetPrimitiveArrayCritical(env, jOut, NULL);
351     if (outBufP == NULL) {
352         // Make sure to release inBufP
353         (*env)->ReleasePrimitiveArrayCritical(env, jIn, inBufP, JNI_ABORT);
354         return 0;
355     }
356 
357     ckPartLen = jOutLen;
358 
359     rv = (*ckpFunctions->C_Decrypt)(ckSessionHandle,
360                                     (CK_BYTE_PTR)(inBufP + jInOfs), jInLen,
361                                     (CK_BYTE_PTR)(outBufP + jOutOfs),
362                                     &ckPartLen);
363 
364     (*env)->ReleasePrimitiveArrayCritical(env, jIn, inBufP, JNI_ABORT);
365     (*env)->ReleasePrimitiveArrayCritical(env, jOut, outBufP, JNI_COMMIT);
366 
367     ckAssertReturnValueOK(env, rv);
368 
369     return ckPartLen;
370 }
371 #endif
372 
373 #ifdef P11_ENABLE_C_DECRYPTUPDATE
374 /*
375  * Class:     sun_security_pkcs11_wrapper_PKCS11
376  * Method:    C_DecryptUpdate
377  * Signature: (J[BII[BII)I
378  * Parametermapping:                    *PKCS11*
379  * @param   jlong jSessionHandle        CK_SESSION_HANDLE hSession
380  * @param   jbyteArray jEncryptedPart   CK_BYTE_PTR pEncryptedPart
381  *                                      CK_ULONG ulEncryptedPartLen
382  * @return  jbyteArray jPart            CK_BYTE_PTR pPart
383  *                                      CK_ULONG_PTR pulPartLen
384  */
385 JNIEXPORT jint JNICALL
Java_sun_security_pkcs11_wrapper_PKCS11_C_1DecryptUpdate(JNIEnv * env,jobject obj,jlong jSessionHandle,jlong directIn,jbyteArray jIn,jint jInOfs,jint jInLen,jlong directOut,jbyteArray jOut,jint jOutOfs,jint jOutLen)386 Java_sun_security_pkcs11_wrapper_PKCS11_C_1DecryptUpdate
387 (JNIEnv *env, jobject obj, jlong jSessionHandle,
388  jlong directIn, jbyteArray jIn, jint jInOfs, jint jInLen,
389  jlong directOut, jbyteArray jOut, jint jOutOfs, jint jOutLen)
390 {
391     CK_SESSION_HANDLE ckSessionHandle;
392     CK_RV rv;
393 
394     CK_BYTE_PTR inBufP;
395     CK_BYTE_PTR outBufP;
396     CK_ULONG ckDecryptedPartLen;
397 
398     CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);
399     if (ckpFunctions == NULL) { return 0; }
400 
401     ckSessionHandle = jLongToCKULong(jSessionHandle);
402 
403     if (directIn != 0) {
404       inBufP = (CK_BYTE_PTR) jlong_to_ptr(directIn);
405     } else {
406       inBufP = (*env)->GetPrimitiveArrayCritical(env, jIn, NULL);
407       if (inBufP == NULL) { return 0; }
408     }
409 
410     if (directOut != 0) {
411       outBufP = (CK_BYTE_PTR) jlong_to_ptr(directOut);
412     } else {
413       outBufP = (*env)->GetPrimitiveArrayCritical(env, jOut, NULL);
414       if (outBufP == NULL) {
415           // Make sure to release inBufP
416           (*env)->ReleasePrimitiveArrayCritical(env, jIn, inBufP, JNI_ABORT);
417           return 0;
418       }
419     }
420 
421     ckDecryptedPartLen = jOutLen;
422 
423     rv = (*ckpFunctions->C_DecryptUpdate)(ckSessionHandle,
424                                           (CK_BYTE_PTR)(inBufP + jInOfs), jInLen,
425                                           (CK_BYTE_PTR)(outBufP + jOutOfs),
426                                           &ckDecryptedPartLen);
427     if (directIn == 0) {
428         (*env)->ReleasePrimitiveArrayCritical(env, jIn, inBufP, JNI_ABORT);
429     }
430 
431     if (directOut == 0) {
432         (*env)->ReleasePrimitiveArrayCritical(env, jOut, outBufP, JNI_COMMIT);
433     }
434 
435     ckAssertReturnValueOK(env, rv);
436 
437     return ckDecryptedPartLen;
438 }
439 
440 #endif
441 
442 #ifdef P11_ENABLE_C_DECRYPTFINAL
443 /*
444  * Class:     sun_security_pkcs11_wrapper_PKCS11
445  * Method:    C_DecryptFinal
446  * Signature: (J[BII)I
447  * Parametermapping:                    *PKCS11*
448  * @param   jlong jSessionHandle        CK_SESSION_HANDLE hSession
449  * @return  jbyteArray jLastPart        CK_BYTE_PTR pLastPart
450  *                                      CK_ULONG_PTR pulLastPartLen
451  */
452 JNIEXPORT jint JNICALL
Java_sun_security_pkcs11_wrapper_PKCS11_C_1DecryptFinal(JNIEnv * env,jobject obj,jlong jSessionHandle,jlong directOut,jbyteArray jOut,jint jOutOfs,jint jOutLen)453 Java_sun_security_pkcs11_wrapper_PKCS11_C_1DecryptFinal
454 (JNIEnv *env, jobject obj, jlong jSessionHandle,
455  jlong directOut, jbyteArray jOut, jint jOutOfs, jint jOutLen)
456 {
457     CK_SESSION_HANDLE ckSessionHandle;
458     CK_RV rv;
459     CK_BYTE_PTR outBufP;
460     CK_ULONG ckLastPartLen;
461 
462     CK_FUNCTION_LIST_PTR ckpFunctions = getFunctionList(env, obj);
463     if (ckpFunctions == NULL) { return 0; }
464 
465     ckSessionHandle = jLongToCKULong(jSessionHandle);
466 
467     if (directOut != 0) {
468       outBufP = (CK_BYTE_PTR) jlong_to_ptr(directOut);
469     } else {
470       outBufP = (*env)->GetPrimitiveArrayCritical(env, jOut, NULL);
471       if (outBufP == NULL) { return 0; }
472     }
473 
474     ckLastPartLen = jOutLen;
475 
476     rv = (*ckpFunctions->C_DecryptFinal)(ckSessionHandle,
477                                          (CK_BYTE_PTR)(outBufP + jOutOfs),
478                                          &ckLastPartLen);
479 
480     if (directOut == 0) {
481         (*env)->ReleasePrimitiveArrayCritical(env, jOut, outBufP, JNI_COMMIT);
482 
483     }
484 
485     ckAssertReturnValueOK(env, rv);
486 
487     return ckLastPartLen;
488 }
489 #endif
490