Skip to content

Commit 33f3f1c

Browse files
Yuri Nesterenkognu-andrew
Yuri Nesterenko
authored andcommittedOct 7, 2023
8284910: Buffer clean in PasswordCallback
Reviewed-by: mbalao, andrew Backport-of: 89fd6d34f859d61d9cf5a1edf9419eee7c338390
1 parent 32ec85f commit 33f3f1c

File tree

3 files changed

+145
-6
lines changed

3 files changed

+145
-6
lines changed
 

‎jdk/src/share/classes/javax/security/auth/callback/PasswordCallback.java

+32-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1999, 2022, 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
@@ -25,6 +25,9 @@
2525

2626
package javax.security.auth.callback;
2727

28+
import java.util.Arrays;
29+
import sun.misc.Cleaner;
30+
2831
/**
2932
* <p> Underlying security services instantiate and pass a
3033
* {@code PasswordCallback} to the {@code handle}
@@ -40,18 +43,22 @@ public class PasswordCallback implements Callback, java.io.Serializable {
4043
* @serial
4144
* @since 1.4
4245
*/
43-
private String prompt;
46+
private final String prompt;
47+
4448
/**
4549
* @serial
4650
* @since 1.4
4751
*/
48-
private boolean echoOn;
52+
private final boolean echoOn;
53+
4954
/**
5055
* @serial
5156
* @since 1.4
5257
*/
5358
private char[] inputPassword;
5459

60+
private transient Cleaner cleaner;
61+
5562
/**
5663
* Construct a {@code PasswordCallback} with a prompt
5764
* and a boolean specifying whether the password should be displayed
@@ -112,7 +119,18 @@ public boolean isEchoOn() {
112119
* @see #getPassword
113120
*/
114121
public void setPassword(char[] password) {
122+
// Cleanup the last buffered password copy.
123+
if (cleaner != null) {
124+
cleaner.clean();
125+
cleaner = null;
126+
}
127+
128+
// Set the retrieved password.
115129
this.inputPassword = (password == null ? null : password.clone());
130+
131+
if (this.inputPassword != null) {
132+
cleaner = Cleaner.create(this, cleanerFor(inputPassword));
133+
}
116134
}
117135

118136
/**
@@ -134,9 +152,17 @@ public char[] getPassword() {
134152
* Clear the retrieved password.
135153
*/
136154
public void clearPassword() {
137-
if (inputPassword != null) {
138-
for (int i = 0; i < inputPassword.length; i++)
139-
inputPassword[i] = ' ';
155+
// Cleanup the last retrieved password copy.
156+
if (cleaner != null) {
157+
cleaner.clean();
158+
cleaner = null;
140159
}
141160
}
161+
162+
private static Runnable cleanerFor(char[] password) {
163+
return () -> {
164+
Arrays.fill(password, ' ');
165+
};
166+
}
167+
142168
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright (C) 2022 THL A29 Limited, a Tencent company. 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.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
* @bug 8284910
27+
* @summary Check that the cleaner is not bound to the PasswordCallback object
28+
*/
29+
30+
import javax.security.auth.callback.PasswordCallback;
31+
import java.util.WeakHashMap;
32+
33+
public final class CheckCleanerBound {
34+
private final static WeakHashMap<PasswordCallback, ?> weakHashMap =
35+
new WeakHashMap<>();
36+
37+
public static void main(String[] args) throws Exception {
38+
// Create an object
39+
PasswordCallback passwordCallback =
40+
new PasswordCallback("Password: ", false);
41+
passwordCallback.setPassword("ThisIsAPassword".toCharArray());
42+
43+
weakHashMap.put(passwordCallback, null);
44+
passwordCallback = null;
45+
46+
// Check if the PasswordCallback object could be collected.
47+
// Wait to trigger the cleanup.
48+
for (int i = 0; i < 10 && weakHashMap.size() != 0; i++) {
49+
System.gc();
50+
}
51+
52+
// Check if the object has been collected. The collection will not
53+
// happen if the cleaner implementation in PasswordCallback is bound
54+
// to the PasswordCallback object.
55+
if (weakHashMap.size() > 0) {
56+
throw new RuntimeException(
57+
"PasswordCallback object is not released");
58+
}
59+
}
60+
}
61+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright (C) 2022 THL A29 Limited, a Tencent company. 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.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
* @bug 8284910
27+
* @summary Check that PasswordCallback.clearPassword() clears the password
28+
*/
29+
30+
import javax.security.auth.callback.PasswordCallback;
31+
import java.util.Arrays;
32+
33+
public final class PasswordCleanup {
34+
public static void main(String[] args) throws Exception {
35+
// Create an object
36+
PasswordCallback passwordCallback =
37+
new PasswordCallback("Password: ", false);
38+
passwordCallback.setPassword("ThisIsAPassword".toCharArray());
39+
char[] originPassword = passwordCallback.getPassword();
40+
41+
// Use password clear method.
42+
passwordCallback.clearPassword();
43+
44+
// Check that the password is cleared.
45+
char[] clearedPassword = passwordCallback.getPassword();
46+
if (Arrays.equals(originPassword, clearedPassword)) {
47+
throw new RuntimeException(
48+
"PasswordCallback.clearPassword() does not clear passwords");
49+
}
50+
}
51+
}
52+

0 commit comments

Comments
 (0)
Please sign in to comment.