Skip to content

Commit 47c7dc7

Browse files
committed
8258833: Cancel multi-part cipher operations in SunPKCS11 after failures
Reviewed-by: valeriep
1 parent ef247ab commit 47c7dc7

File tree

6 files changed

+293
-15
lines changed

6 files changed

+293
-15
lines changed

src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11AEADCipher.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -350,6 +350,13 @@ private void cancelOperation() {
350350
0, buffer, 0, bufLen);
351351
}
352352
} catch (PKCS11Exception e) {
353+
if (e.getErrorCode() == CKR_OPERATION_NOT_INITIALIZED) {
354+
// Cancel Operation may be invoked after an error on a PKCS#11
355+
// call. If the operation inside the token was already cancelled,
356+
// do not fail here. This is part of a defensive mechanism for
357+
// PKCS#11 libraries that do not strictly follow the standard.
358+
return;
359+
}
353360
if (encrypt) {
354361
throw new ProviderException("Cancel failed", e);
355362
}
@@ -616,6 +623,12 @@ private int implDoFinal(byte[] in, int inOfs, int inLen,
616623
}
617624
return k;
618625
} catch (PKCS11Exception e) {
626+
// As per the PKCS#11 standard, C_Encrypt and C_Decrypt may only
627+
// keep the operation active on CKR_BUFFER_TOO_SMALL errors or
628+
// successful calls to determine the output length. However,
629+
// these cases are not expected here because the output length
630+
// is checked in the OpenJDK side before making the PKCS#11 call.
631+
// Thus, doCancel can safely be 'false'.
619632
doCancel = false;
620633
handleException(e);
621634
throw new ProviderException("doFinal() failed", e);
@@ -702,6 +715,12 @@ private int implDoFinal(ByteBuffer inBuffer, ByteBuffer outBuffer)
702715
outBuffer.position(outBuffer.position() + k);
703716
return k;
704717
} catch (PKCS11Exception e) {
718+
// As per the PKCS#11 standard, C_Encrypt and C_Decrypt may only
719+
// keep the operation active on CKR_BUFFER_TOO_SMALL errors or
720+
// successful calls to determine the output length. However,
721+
// these cases are not expected here because the output length
722+
// is checked in the OpenJDK side before making the PKCS#11 call.
723+
// Thus, doCancel can safely be 'false'.
705724
doCancel = false;
706725
handleException(e);
707726
throw new ProviderException("doFinal() failed", e);

src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -439,6 +439,13 @@ private void cancelOperation() {
439439
token.p11.C_DecryptFinal(session.id(), 0, buffer, 0, bufLen);
440440
}
441441
} catch (PKCS11Exception e) {
442+
if (e.getErrorCode() == CKR_OPERATION_NOT_INITIALIZED) {
443+
// Cancel Operation may be invoked after an error on a PKCS#11
444+
// call. If the operation inside the token was already cancelled,
445+
// do not fail here. This is part of a defensive mechanism for
446+
// PKCS#11 libraries that do not strictly follow the standard.
447+
return;
448+
}
442449
if (encrypt) {
443450
throw new ProviderException("Cancel failed", e);
444451
}
@@ -628,7 +635,11 @@ private int implUpdate(byte[] in, int inOfs, int inLen,
628635
throw (ShortBufferException)
629636
(new ShortBufferException().initCause(e));
630637
}
631-
reset(false);
638+
// Some implementations such as the NSS Software Token do not
639+
// cancel the operation upon a C_EncryptUpdate/C_DecryptUpdate
640+
// failure (as required by the PKCS#11 standard). See JDK-8258833
641+
// for further information.
642+
reset(true);
632643
throw new ProviderException("update() failed", e);
633644
}
634645
}
@@ -746,7 +757,11 @@ private int implUpdate(ByteBuffer inBuffer, ByteBuffer outBuffer)
746757
throw (ShortBufferException)
747758
(new ShortBufferException().initCause(e));
748759
}
749-
reset(false);
760+
// Some implementations such as the NSS Software Token do not
761+
// cancel the operation upon a C_EncryptUpdate/C_DecryptUpdate
762+
// failure (as required by the PKCS#11 standard). See JDK-8258833
763+
// for further information.
764+
reset(true);
750765
throw new ProviderException("update() failed", e);
751766
}
752767
}
@@ -770,9 +785,14 @@ private int implDoFinal(byte[] out, int outOfs, int outLen)
770785
0, padBuffer, 0, actualPadLen,
771786
0, out, outOfs, outLen);
772787
}
788+
// Some implementations such as the NSS Software Token do not
789+
// cancel the operation upon a C_EncryptUpdate failure (as
790+
// required by the PKCS#11 standard). Cancel is not needed
791+
// only after this point. See JDK-8258833 for further
792+
// information.
793+
doCancel = false;
773794
k += token.p11.C_EncryptFinal(session.id(),
774795
0, out, (outOfs + k), (outLen - k));
775-
doCancel = false;
776796
} else {
777797
// Special handling to match SunJCE provider behavior
778798
if (bytesBuffered == 0 && padBufferLen == 0) {
@@ -784,22 +804,26 @@ private int implDoFinal(byte[] out, int outOfs, int outLen)
784804
padBuffer, 0, padBufferLen, 0, padBuffer, 0,
785805
padBuffer.length);
786806
}
807+
// Some implementations such as the NSS Software Token do not
808+
// cancel the operation upon a C_DecryptUpdate failure (as
809+
// required by the PKCS#11 standard). Cancel is not needed
810+
// only after this point. See JDK-8258833 for further
811+
// information.
812+
doCancel = false;
787813
k += token.p11.C_DecryptFinal(session.id(), 0, padBuffer, k,
788814
padBuffer.length - k);
789-
doCancel = false;
790815

791816
int actualPadLen = paddingObj.unpad(padBuffer, k);
792817
k -= actualPadLen;
793818
System.arraycopy(padBuffer, 0, out, outOfs, k);
794819
} else {
820+
doCancel = false;
795821
k = token.p11.C_DecryptFinal(session.id(), 0, out, outOfs,
796822
outLen);
797-
doCancel = false;
798823
}
799824
}
800825
return k;
801826
} catch (PKCS11Exception e) {
802-
doCancel = false;
803827
handleException(e);
804828
throw new ProviderException("doFinal() failed", e);
805829
} finally {
@@ -845,9 +869,14 @@ private int implDoFinal(ByteBuffer outBuffer)
845869
0, padBuffer, 0, actualPadLen,
846870
outAddr, outArray, outOfs, outLen);
847871
}
872+
// Some implementations such as the NSS Software Token do not
873+
// cancel the operation upon a C_EncryptUpdate failure (as
874+
// required by the PKCS#11 standard). Cancel is not needed
875+
// only after this point. See JDK-8258833 for further
876+
// information.
877+
doCancel = false;
848878
k += token.p11.C_EncryptFinal(session.id(),
849879
outAddr, outArray, (outOfs + k), (outLen - k));
850-
doCancel = false;
851880
} else {
852881
// Special handling to match SunJCE provider behavior
853882
if (bytesBuffered == 0 && padBufferLen == 0) {
@@ -861,18 +890,23 @@ private int implDoFinal(ByteBuffer outBuffer)
861890
0, padBuffer, 0, padBuffer.length);
862891
padBufferLen = 0;
863892
}
893+
// Some implementations such as the NSS Software Token do not
894+
// cancel the operation upon a C_DecryptUpdate failure (as
895+
// required by the PKCS#11 standard). Cancel is not needed
896+
// only after this point. See JDK-8258833 for further
897+
// information.
898+
doCancel = false;
864899
k += token.p11.C_DecryptFinal(session.id(),
865900
0, padBuffer, k, padBuffer.length - k);
866-
doCancel = false;
867901

868902
int actualPadLen = paddingObj.unpad(padBuffer, k);
869903
k -= actualPadLen;
870904
outArray = padBuffer;
871905
outOfs = 0;
872906
} else {
907+
doCancel = false;
873908
k = token.p11.C_DecryptFinal(session.id(),
874909
outAddr, outArray, outOfs, outLen);
875-
doCancel = false;
876910
}
877911
}
878912
if ((!encrypt && paddingObj != null) ||
@@ -884,7 +918,6 @@ private int implDoFinal(ByteBuffer outBuffer)
884918
}
885919
return k;
886920
} catch (PKCS11Exception e) {
887-
doCancel = false;
888921
handleException(e);
889922
throw new ProviderException("doFinal() failed", e);
890923
} finally {

src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Mac.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -151,6 +151,13 @@ private void cancelOperation() {
151151
try {
152152
token.p11.C_SignFinal(session.id(), 0);
153153
} catch (PKCS11Exception e) {
154+
if (e.getErrorCode() == CKR_OPERATION_NOT_INITIALIZED) {
155+
// Cancel Operation may be invoked after an error on a PKCS#11
156+
// call. If the operation inside the token was already cancelled,
157+
// do not fail here. This is part of a defensive mechanism for
158+
// PKCS#11 libraries that do not strictly follow the standard.
159+
return;
160+
}
154161
throw new ProviderException("Cancel failed", e);
155162
}
156163
}
@@ -213,6 +220,12 @@ protected byte[] engineDoFinal() {
213220
ensureInitialized();
214221
return token.p11.C_SignFinal(session.id(), 0);
215222
} catch (PKCS11Exception e) {
223+
// As per the PKCS#11 standard, C_SignFinal may only
224+
// keep the operation active on CKR_BUFFER_TOO_SMALL errors or
225+
// successful calls to determine the output length. However,
226+
// these cases are handled at OpenJDK's libj2pkcs11 native
227+
// library. Thus, P11Mac::reset can be called with a 'false'
228+
// doCancel argument from here.
216229
throw new ProviderException("doFinal() failed", e);
217230
} finally {
218231
reset(false);

src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11PSSSignature.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -298,6 +298,13 @@ private void cancelOperation() {
298298
}
299299
}
300300
} catch (PKCS11Exception e) {
301+
if (e.getErrorCode() == CKR_OPERATION_NOT_INITIALIZED) {
302+
// Cancel Operation may be invoked after an error on a PKCS#11
303+
// call. If the operation inside the token was already cancelled,
304+
// do not fail here. This is part of a defensive mechanism for
305+
// PKCS#11 libraries that do not strictly follow the standard.
306+
return;
307+
}
301308
if (mode == M_SIGN) {
302309
throw new ProviderException("cancel failed", e);
303310
}
@@ -662,6 +669,11 @@ protected byte[] engineSign() throws SignatureException {
662669
doCancel = false;
663670
return signature;
664671
} catch (PKCS11Exception pe) {
672+
// As per the PKCS#11 standard, C_Sign and C_SignFinal may only
673+
// keep the operation active on CKR_BUFFER_TOO_SMALL errors or
674+
// successful calls to determine the output length. However,
675+
// these cases are handled at OpenJDK's libj2pkcs11 native
676+
// library. Thus, doCancel can safely be 'false' here.
665677
doCancel = false;
666678
throw new ProviderException(pe);
667679
} catch (ProviderException e) {

src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Signature.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -314,6 +314,13 @@ private void cancelOperation() {
314314
}
315315
}
316316
} catch (PKCS11Exception e) {
317+
if (e.getErrorCode() == CKR_OPERATION_NOT_INITIALIZED) {
318+
// Cancel Operation may be invoked after an error on a PKCS#11
319+
// call. If the operation inside the token was already cancelled,
320+
// do not fail here. This is part of a defensive mechanism for
321+
// PKCS#11 libraries that do not strictly follow the standard.
322+
return;
323+
}
317324
if (mode == M_VERIFY) {
318325
long errorCode = e.getErrorCode();
319326
if ((errorCode == CKR_SIGNATURE_INVALID) ||
@@ -654,6 +661,11 @@ protected byte[] engineSign() throws SignatureException {
654661
}
655662
}
656663
} catch (PKCS11Exception pe) {
664+
// As per the PKCS#11 standard, C_Sign and C_SignFinal may only
665+
// keep the operation active on CKR_BUFFER_TOO_SMALL errors or
666+
// successful calls to determine the output length. However,
667+
// these cases are handled at OpenJDK's libj2pkcs11 native
668+
// library. Thus, doCancel can safely be 'false' here.
657669
doCancel = false;
658670
throw new ProviderException(pe);
659671
} catch (SignatureException | ProviderException e) {

0 commit comments

Comments
 (0)