Skip to content

Commit 05fb8ec

Browse files
committed
Accept password parameter as CharArray for improved security
- contents of CharArray can't be printed by accidental toString() (for instance in logs) - CharArray allows clearing the memory beven before GC runs (however dav4jvm and okhttp generates Strings with the password, so that will be of limited use yet)
1 parent ec6264d commit 05fb8ec

File tree

2 files changed

+15
-15
lines changed

2 files changed

+15
-15
lines changed

src/main/kotlin/at/bitfire/dav4jvm/BasicDigestAuthHandler.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class BasicDigestAuthHandler(
4242
val domain: String?,
4343

4444
val username: String,
45-
val password: String,
45+
val password: CharArray,
4646

4747
val insecurePreemptive: Boolean = false
4848
): Authenticator, Interceptor {
@@ -135,7 +135,7 @@ class BasicDigestAuthHandler(
135135
So, UTF-8 encoding for credentials is compatible with all RFC 7617 servers and many,
136136
but not all pre-RFC 7617 servers. */
137137
return request.newBuilder()
138-
.header(HEADER_AUTHORIZATION, Credentials.basic(username, password, Charsets.UTF_8))
138+
.header(HEADER_AUTHORIZATION, Credentials.basic(username, password.concatToString(), Charsets.UTF_8))
139139
.build()
140140
}
141141

@@ -194,9 +194,9 @@ class BasicDigestAuthHandler(
194194

195195
val a1: String? = when (algorithm) {
196196
Algorithm.MD5 ->
197-
"$username:$realm:$password"
197+
"$username:$realm:${password.concatToString()}"
198198
Algorithm.MD5_SESSION ->
199-
h("$username:$realm:$password") + ":$nonce:$clientNonce"
199+
h("$username:$realm:${password.concatToString()}") + ":$nonce:$clientNonce"
200200
else ->
201201
null
202202
}
@@ -225,7 +225,7 @@ class BasicDigestAuthHandler(
225225

226226
// legacy (backwards compatibility with RFC 2069)
227227
if (algorithm == Algorithm.MD5) {
228-
val a1 = "$username:$realm:$password"
228+
val a1 = "$username:$realm:${password.concatToString()}"
229229
val a2 = "$method:$digestURI"
230230
response = kd(h(a1), nonce + ":" + h(a2))
231231
}

src/test/kotlin/at/bitfire/dav4jvm/BasicDigestAuthHandlerTest.kt

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class BasicDigestAuthHandlerTest {
2727

2828
@Test
2929
fun testBasic() {
30-
var authenticator = BasicDigestAuthHandler(null, "user", "password")
30+
var authenticator = BasicDigestAuthHandler(null, "user", "password".toCharArray())
3131
val original = Request.Builder()
3232
.url("http://example.com")
3333
.build()
@@ -41,7 +41,7 @@ class BasicDigestAuthHandlerTest {
4141
assertEquals("Basic dXNlcjpwYXNzd29yZA==", request!!.header("Authorization"))
4242

4343
// special characters: always use UTF-8 (and don't crash on RFC 7617 charset header)
44-
authenticator = BasicDigestAuthHandler(null, "username", "paßword")
44+
authenticator = BasicDigestAuthHandler(null, "username", "paßword".toCharArray())
4545
response = response.newBuilder()
4646
.header("WWW-Authenticate", "Basic realm=\"WallyWorld\",charset=UTF-8")
4747
.build()
@@ -52,7 +52,7 @@ class BasicDigestAuthHandlerTest {
5252
@Test
5353
fun testDigestRFCExample() {
5454
// use cnonce from example
55-
val authenticator = BasicDigestAuthHandler(null, "Mufasa", "Circle Of Life")
55+
val authenticator = BasicDigestAuthHandler(null, "Mufasa", "Circle Of Life".toCharArray())
5656
BasicDigestAuthHandler.clientNonce = "0a4f113b"
5757
BasicDigestAuthHandler.nonceCount.set(1)
5858

@@ -83,7 +83,7 @@ class BasicDigestAuthHandlerTest {
8383

8484
@Test
8585
fun testDigestRealWorldExamples() {
86-
var authenticator = BasicDigestAuthHandler(null, "demo", "demo")
86+
var authenticator = BasicDigestAuthHandler(null, "demo", "demo".toCharArray())
8787
BasicDigestAuthHandler.clientNonce = "MDI0ZDgxYTNmZDk4MTA1ODM0NDNjNmJjNDllYjQ1ZTI="
8888
BasicDigestAuthHandler.nonceCount.set(1)
8989

@@ -112,7 +112,7 @@ class BasicDigestAuthHandlerTest {
112112
assertTrue(auth.contains("opaque=\"df58bdff8cf60599c939187d0b5c54de\""))
113113

114114
// example 2
115-
authenticator = BasicDigestAuthHandler(null, "test", "test")
115+
authenticator = BasicDigestAuthHandler(null, "test", "test".toCharArray())
116116
authScheme = Challenge("digest", mapOf( // lower case
117117
Pair("nonce", "87c4c2aceed9abf30dd68c71"),
118118
Pair("algorithm", "md5"),
@@ -139,7 +139,7 @@ class BasicDigestAuthHandlerTest {
139139

140140
@Test
141141
fun testDigestMD5Sess() {
142-
val authenticator = BasicDigestAuthHandler(null, "admin", "12345")
142+
val authenticator = BasicDigestAuthHandler(null, "admin", "12345".toCharArray())
143143
BasicDigestAuthHandler.clientNonce = "hxk1lu63b6c7vhk"
144144
BasicDigestAuthHandler.nonceCount.set(1)
145145

@@ -178,7 +178,7 @@ class BasicDigestAuthHandlerTest {
178178

179179
@Test
180180
fun testDigestMD5AuthInt() {
181-
val authenticator = BasicDigestAuthHandler(null, "admin", "12435")
181+
val authenticator = BasicDigestAuthHandler(null, "admin", "12435".toCharArray())
182182
BasicDigestAuthHandler.clientNonce = "hxk1lu63b6c7vhk"
183183
BasicDigestAuthHandler.nonceCount.set(1)
184184

@@ -217,7 +217,7 @@ class BasicDigestAuthHandlerTest {
217217

218218
@Test
219219
fun testDigestLegacy() {
220-
val authenticator = BasicDigestAuthHandler(null, "Mufasa", "CircleOfLife")
220+
val authenticator = BasicDigestAuthHandler(null, "Mufasa", "CircleOfLife".toCharArray())
221221

222222
// construct WWW-Authenticate
223223
val authScheme = Challenge("Digest", mapOf(
@@ -245,7 +245,7 @@ class BasicDigestAuthHandlerTest {
245245

246246
@Test
247247
fun testIncompleteAuthenticationRequests() {
248-
val authenticator = BasicDigestAuthHandler(null, "demo", "demo")
248+
val authenticator = BasicDigestAuthHandler(null, "demo", "demo".toCharArray())
249249

250250
val original = Request.Builder()
251251
.get()
@@ -272,7 +272,7 @@ class BasicDigestAuthHandlerTest {
272272

273273
@Test
274274
fun testAuthenticateNull() {
275-
val authenticator = BasicDigestAuthHandler(null, "demo", "demo")
275+
val authenticator = BasicDigestAuthHandler(null, "demo", "demo".toCharArray())
276276
// must not crash (route may be null)
277277
val request = Request.Builder()
278278
.get()

0 commit comments

Comments
 (0)