Skip to content

Commit 9143593

Browse files
authored
refactor : Handling more exceptions scenario in DPoP key generation (#943)
1 parent 260dfb7 commit 9143593

2 files changed

Lines changed: 104 additions & 7 deletions

File tree

auth0/src/main/java/com/auth0/android/dpop/DPoPKeyStore.kt

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,21 @@ import android.os.Build
66
import android.security.keystore.KeyGenParameterSpec
77
import android.security.keystore.KeyProperties
88
import android.util.Log
9+
import java.io.IOException
910
import java.security.InvalidAlgorithmParameterException
1011
import java.security.KeyPairGenerator
1112
import java.security.KeyStore
1213
import java.security.KeyStoreException
1314
import java.security.NoSuchAlgorithmException
1415
import java.security.NoSuchProviderException
16+
import java.security.UnrecoverableKeyException
1517
import java.security.PrivateKey
1618
import java.security.ProviderException
1719
import java.security.PublicKey
20+
import java.security.cert.CertificateException
1821
import java.security.spec.ECGenParameterSpec
1922
import java.util.Calendar
2023
import javax.security.auth.x500.X500Principal
21-
import javax.security.cert.CertificateException
2224

2325
/**
2426
* Class to handle all DPoP related keystore operations
@@ -97,8 +99,16 @@ internal open class DPoPKeyStore {
9799
if (publicKey != null) {
98100
return Pair(privateKey, publicKey)
99101
}
100-
} catch (e: KeyStoreException) {
101-
throw DPoPException(DPoPException.Code.KEY_STORE_ERROR, e)
102+
} catch (e: Exception) {
103+
when (e) {
104+
is KeyStoreException,
105+
is NoSuchAlgorithmException,
106+
is UnrecoverableKeyException,
107+
is ClassCastException,
108+
is IOException,
109+
is CertificateException -> throw DPoPException(DPoPException.Code.KEY_STORE_ERROR, e)
110+
else -> throw DPoPException(DPoPException.Code.UNKNOWN_ERROR, e)
111+
}
102112
}
103113
Log.d(TAG, "Returning null key pair ")
104114
return null
@@ -107,16 +117,28 @@ internal open class DPoPKeyStore {
107117
fun hasKeyPair(): Boolean {
108118
try {
109119
return keyStore.containsAlias(KEY_ALIAS)
110-
} catch (e: KeyStoreException) {
111-
throw DPoPException(DPoPException.Code.KEY_STORE_ERROR, e)
120+
} catch (e: Exception) {
121+
when (e) {
122+
is KeyStoreException,
123+
is NoSuchAlgorithmException,
124+
is IOException,
125+
is CertificateException -> throw DPoPException(DPoPException.Code.KEY_STORE_ERROR, e)
126+
else -> throw DPoPException(DPoPException.Code.UNKNOWN_ERROR, e)
127+
}
112128
}
113129
}
114130

115131
fun deleteKeyPair() {
116132
try {
117133
keyStore.deleteEntry(KEY_ALIAS)
118-
} catch (e: KeyStoreException) {
119-
throw DPoPException(DPoPException.Code.KEY_STORE_ERROR, e)
134+
} catch (e: Exception) {
135+
when (e) {
136+
is KeyStoreException,
137+
is NoSuchAlgorithmException,
138+
is IOException,
139+
is CertificateException -> throw DPoPException(DPoPException.Code.KEY_STORE_ERROR, e)
140+
else -> throw DPoPException(DPoPException.Code.UNKNOWN_ERROR, e)
141+
}
120142
}
121143
}
122144

auth0/src/test/java/com/auth0/android/dpop/DPoPKeyStoreTest.kt

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,11 @@ import java.security.InvalidAlgorithmParameterException
3232
import java.security.KeyPairGenerator
3333
import java.security.KeyStore
3434
import java.security.KeyStoreException
35+
import java.security.NoSuchAlgorithmException
3536
import java.security.PrivateKey
3637
import java.security.ProviderException
3738
import java.security.PublicKey
39+
import java.security.UnrecoverableKeyException
3840
import java.security.cert.Certificate
3941
import javax.security.auth.x500.X500Principal
4042

@@ -191,6 +193,54 @@ public class DPoPKeyStoreTest {
191193
assertThat(exception.cause, `is`(cause))
192194
}
193195

196+
@Test
197+
public fun `getKeyPair should throw KEY_STORE_ERROR on NoSuchAlgorithmException`() {
198+
val cause = NoSuchAlgorithmException("Test Exception")
199+
whenever(mockKeyStore.getKey(any(), anyOrNull())).thenThrow(cause)
200+
201+
val exception = assertThrows(DPoPException::class.java) {
202+
dpopKeyStore.getKeyPair()
203+
}
204+
assertEquals(exception.message, DPoPException.KEY_STORE_ERROR.message)
205+
assertThat(exception.cause, `is`(cause))
206+
}
207+
208+
@Test
209+
public fun `getKeyPair should throw KEY_STORE_ERROR on UnrecoverableKeyException`() {
210+
val cause = UnrecoverableKeyException("Test Exception")
211+
whenever(mockKeyStore.getKey(any(), anyOrNull())).thenThrow(cause)
212+
213+
val exception = assertThrows(DPoPException::class.java) {
214+
dpopKeyStore.getKeyPair()
215+
}
216+
assertEquals(exception.message, DPoPException.KEY_STORE_ERROR.message)
217+
assertThat(exception.cause, `is`(cause))
218+
}
219+
220+
@Test
221+
public fun `getKeyPair should throw KEY_STORE_ERROR on ClassCastException`() {
222+
val cause = ClassCastException("Test Exception")
223+
whenever(mockKeyStore.getKey(any(), anyOrNull())).thenThrow(cause)
224+
225+
val exception = assertThrows(DPoPException::class.java) {
226+
dpopKeyStore.getKeyPair()
227+
}
228+
assertEquals(exception.message, DPoPException.KEY_STORE_ERROR.message)
229+
assertThat(exception.cause, `is`(cause))
230+
}
231+
232+
@Test
233+
public fun `getKeyPair should throw UNKNOWN_ERROR on unhandled exception`() {
234+
val cause = RuntimeException("Unexpected error")
235+
whenever(mockKeyStore.getKey(any(), anyOrNull())).thenThrow(cause)
236+
237+
val exception = assertThrows(DPoPException::class.java) {
238+
dpopKeyStore.getKeyPair()
239+
}
240+
assertEquals(exception.message, DPoPException.UNKNOWN_ERROR.message)
241+
assertThat(exception.cause, `is`(cause))
242+
}
243+
194244
@Test
195245
public fun `hasKeyPair should return true when alias exists`() {
196246
whenever(mockKeyStore.containsAlias(any())).thenReturn(true)
@@ -217,6 +267,18 @@ public class DPoPKeyStoreTest {
217267
assertThat(exception.cause, `is`(cause))
218268
}
219269

270+
@Test
271+
public fun `hasKeyPair should throw UNKNOWN_ERROR on unhandled exception`() {
272+
val cause = RuntimeException("Unexpected error")
273+
whenever(mockKeyStore.containsAlias(any())).thenThrow(cause)
274+
275+
val exception = assertThrows(DPoPException::class.java) {
276+
dpopKeyStore.hasKeyPair()
277+
}
278+
assertEquals(exception.message, DPoPException.UNKNOWN_ERROR.message)
279+
assertThat(exception.cause, `is`(cause))
280+
}
281+
220282
@Test
221283
public fun `deleteKeyPair should call deleteEntry`() {
222284
dpopKeyStore.deleteKeyPair()
@@ -235,6 +297,19 @@ public class DPoPKeyStoreTest {
235297
assertThat(exception.cause, `is`(cause))
236298
}
237299

300+
301+
@Test
302+
public fun `deleteKeyPair should throw UNKNOWN_ERROR on unhandled exception`() {
303+
val cause = RuntimeException("Unexpected error")
304+
whenever(mockKeyStore.deleteEntry(any())).thenThrow(cause)
305+
306+
val exception = assertThrows(DPoPException::class.java) {
307+
dpopKeyStore.deleteKeyPair()
308+
}
309+
assertEquals(exception.message, DPoPException.UNKNOWN_ERROR.message)
310+
assertThat(exception.cause, `is`(cause))
311+
}
312+
238313
@Test
239314
public fun `generateKeyPair should retry without StrongBox when ProviderException occurs with StrongBox enabled`() {
240315
val providerException = ProviderException("StrongBox attestation failed")

0 commit comments

Comments
 (0)