Skip to content

Commit 04acdaa

Browse files
committed
Exception cleanup.
1 parent 9a14d78 commit 04acdaa

26 files changed

Lines changed: 146 additions & 160 deletions

paseto/src/main/kotlin/net/aholbrook/paseto/crypto/Ecdsa.kt

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package net.aholbrook.paseto.crypto
22

33
import net.aholbrook.paseto.exception.ByteArrayLengthException
4-
import net.aholbrook.paseto.exception.KeyV3Exception
4+
import net.aholbrook.paseto.exception.EcKeyException
55
import org.bouncycastle.asn1.ASN1ObjectIdentifier
66
import org.bouncycastle.asn1.ASN1Primitive
77
import org.bouncycastle.asn1.DERBitString
@@ -11,16 +11,13 @@ import org.bouncycastle.asn1.sec.SECObjectIdentifiers
1111
import org.bouncycastle.asn1.x509.AlgorithmIdentifier
1212
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo
1313
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers
14-
import org.bouncycastle.crypto.CryptoException
1514
import org.bouncycastle.crypto.digests.SHA384Digest
1615
import org.bouncycastle.crypto.ec.CustomNamedCurves
1716
import org.bouncycastle.crypto.generators.ECKeyPairGenerator
1817
import org.bouncycastle.crypto.params.ECDomainParameters
1918
import org.bouncycastle.crypto.params.ECKeyGenerationParameters
2019
import org.bouncycastle.crypto.params.ECPrivateKeyParameters
2120
import org.bouncycastle.crypto.params.ECPublicKeyParameters
22-
import org.bouncycastle.crypto.params.RSAKeyParameters
23-
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters
2421
import org.bouncycastle.crypto.signers.ECDSASigner
2522
import org.bouncycastle.crypto.signers.HMacDSAKCalculator
2623
import org.bouncycastle.crypto.util.PrivateKeyFactory
@@ -49,7 +46,7 @@ internal fun ecdsaP384Sign(sig: ByteArray, m: ByteArray, sk: ByteArray, enforceL
4946

5047
val d = BigInteger(1, sk)
5148
if (d.signum() <= 0 || d >= params.n) {
52-
throw KeyV3Exception("Invalid P-384 private key")
49+
throw EcKeyException("Invalid P-384 private key")
5350
}
5451
val secretKey = ECPrivateKeyParameters(d, params)
5552

@@ -134,7 +131,7 @@ internal fun p384SkToPk(sk: ByteArray): ByteArray {
134131
val params = CustomNamedCurves.getByOID(SECObjectIdentifiers.secp384r1)
135132
val d = BigInteger(1, sk)
136133
if (d.signum() <= 0 || d >= params.n) {
137-
throw KeyV3Exception("Invalid P-384 private key")
134+
throw EcKeyException("Invalid P-384 private key")
138135
}
139136
val q = params.g.multiply(d).normalize()
140137
return q.getEncoded(true)
@@ -145,21 +142,21 @@ internal fun p384VerifyPk(pk: ByteArray): ECPoint {
145142
throw ByteArrayLengthException("pk", pk.size, ECDSA_P384_PUBLICKEYBYTES)
146143
}
147144
if (pk[0] != 0x02.toByte() && pk[0] != 0x03.toByte()) {
148-
throw KeyV3Exception("must use point compression")
145+
throw EcKeyException("must use point compression")
149146
}
150147

151148
val params = CustomNamedCurves.getByOID(SECObjectIdentifiers.secp384r1)
152149
val q = try {
153150
params.curve.decodePoint(pk)
154151
} catch (ex: IllegalArgumentException) {
155-
throw KeyV3Exception("decode point", ex)
152+
throw EcKeyException("decode point", ex)
156153
}
157154

158155
if (q.isInfinity) {
159-
throw KeyV3Exception("Point at infinity")
156+
throw EcKeyException("Point at infinity")
160157
}
161158
if (!q.isValid) {
162-
throw KeyV3Exception("Point not on curve")
159+
throw EcKeyException("Point not on curve")
163160
}
164161

165162
return q
@@ -173,7 +170,7 @@ internal fun p384EncodeSkPkcs8(sk: ByteArray): ByteArray {
173170
val d = BigInteger(1, sk)
174171

175172
if (d.signum() <= 0 || d >= params.n) {
176-
throw KeyV3Exception("Invalid P-384 private key")
173+
throw EcKeyException("Invalid P-384 private key")
177174
}
178175

179176
@Suppress("MagicNumber")
@@ -190,23 +187,23 @@ internal fun p384EncodeSkPkcs8(sk: ByteArray): ByteArray {
190187
internal fun p384DecodeSkPkcs8(der: ByteArray): ByteArray {
191188
try {
192189
val params = PrivateKeyFactory.createKey(der) as? ECPrivateKeyParameters
193-
?: throw KeyV3Exception("Private key is not on secp384r1")
190+
?: throw EcKeyException("Private key is not on secp384r1")
194191
val domain = params.parameters
195192
val expected = CustomNamedCurves.getByOID(SECObjectIdentifiers.secp384r1)
196193

197194
if (domain.curve != expected.curve || domain.g != expected.g || domain.n != expected.n ||
198195
domain.h != expected.h
199196
) {
200-
throw KeyV3Exception("Private key is not on secp384r1")
197+
throw EcKeyException("Private key is not on secp384r1")
201198
}
202199

203200
if (params.d.signum() <= 0 || params.d >= domain.n) {
204-
throw KeyV3Exception("Invalid private key")
201+
throw EcKeyException("Invalid private key")
205202
}
206203

207204
return BigIntegers.asUnsignedByteArray(ECDSA_P384_SECRETKEYBYTES, params.d)
208205
} catch (ex: Throwable) {
209-
throw KeyV3Exception("invalid private key", ex)
206+
throw EcKeyException("invalid private key", ex)
210207
}
211208
}
212209

@@ -218,7 +215,7 @@ internal fun p384EncodeSkSec1(sk: ByteArray): ByteArray {
218215
val params = CustomNamedCurves.getByOID(SECObjectIdentifiers.secp384r1)
219216
val d = BigInteger(1, sk)
220217
if (d.signum() <= 0 || d >= params.n) {
221-
throw KeyV3Exception("Invalid P-384 private key")
218+
throw EcKeyException("Invalid P-384 private key")
222219
}
223220

224221
val publicKey = DERBitString(params.g.multiply(d).normalize().getEncoded(false))
@@ -232,31 +229,31 @@ internal fun p384EncodeSkSec1(sk: ByteArray): ByteArray {
232229
internal fun p384DecodeSkSec1(der: ByteArray): ByteArray {
233230
try {
234231
val key = ECPrivateKey.getInstance(ASN1Primitive.fromByteArray(der))
235-
?: throw KeyV3Exception("Invalid private key")
232+
?: throw EcKeyException("Invalid private key")
236233
val curveParams = CustomNamedCurves.getByOID(SECObjectIdentifiers.secp384r1)
237234

238235
key.parametersObject?.let { params ->
239236
when (params) {
240237
is ASN1ObjectIdentifier -> {
241238
if (params != SECObjectIdentifiers.secp384r1) {
242-
throw KeyV3Exception("SEC1 key not on secp384r1")
239+
throw EcKeyException("SEC1 key not on secp384r1")
243240
}
244241
}
245242

246243
else -> {
247-
throw KeyV3Exception("Unsupported curve parameters")
244+
throw EcKeyException("Unsupported curve parameters")
248245
}
249246
}
250-
} ?: throw KeyV3Exception("SEC1 key must include curve parameters")
247+
} ?: throw EcKeyException("SEC1 key must include curve parameters")
251248

252249
val d = key.key
253250
if (d.signum() <= 0 || d >= curveParams.n) {
254-
throw KeyV3Exception("Invalid P-384 private key")
251+
throw EcKeyException("Invalid P-384 private key")
255252
}
256253

257254
return BigIntegers.asUnsignedByteArray(ECDSA_P384_SECRETKEYBYTES, d)
258255
} catch (ex: Throwable) {
259-
throw KeyV3Exception("Invalid private key", ex)
256+
throw EcKeyException("Invalid private key", ex)
260257
}
261258
}
262259

@@ -272,21 +269,21 @@ internal fun p384EncodePkSpki(pk: ByteArray): ByteArray {
272269
internal fun p384DecodePkSpki(der: ByteArray): ByteArray {
273270
try {
274271
val params = PublicKeyFactory.createKey(der) as? ECPublicKeyParameters
275-
?: throw KeyV3Exception("Public key is not on secp384r1")
272+
?: throw EcKeyException("Public key is not on secp384r1")
276273
val domain = params.parameters
277274
val expected = CustomNamedCurves.getByOID(SECObjectIdentifiers.secp384r1)
278275

279276
if (domain.curve != expected.curve || domain.g != expected.g || domain.n != expected.n ||
280277
domain.h != expected.h
281278
) {
282-
throw KeyV3Exception("Public key is not on secp384r1")
279+
throw EcKeyException("Public key is not on secp384r1")
283280
}
284281

285282
return params.q.getEncoded(true).also {
286283
p384VerifyPk(it)
287284
}
288285
} catch (ex: Throwable) {
289-
throw KeyV3Exception("invalid public key", ex)
286+
throw EcKeyException("invalid public key", ex)
290287
}
291288
}
292289

paseto/src/main/kotlin/net/aholbrook/paseto/crypto/RsaPssSha384.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package net.aholbrook.paseto.crypto
22

33
import net.aholbrook.paseto.exception.ByteArrayLengthException
4-
import net.aholbrook.paseto.exception.CryptoProviderException
4+
import net.aholbrook.paseto.exception.CryptoException as PasetoCryptoException
55
import org.bouncycastle.asn1.ASN1Primitive
66
import org.bouncycastle.asn1.DERNull
77
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers
@@ -50,7 +50,7 @@ internal fun pssSha384(forSigning: Boolean, key: ByteArray): PSSSigner {
5050

5151
return pss
5252
} catch (e: IOException) {
53-
throw CryptoProviderException("IOException", e)
53+
throw PasetoCryptoException("IOException", e)
5454
}
5555
}
5656

@@ -68,7 +68,7 @@ internal fun rsaSign(m: ByteArray, privateKey: ByteArray): ByteArray {
6868
return pss.generateSignature()
6969
} catch (e: CryptoException) {
7070
// Not documented
71-
throw CryptoProviderException("CryptoException", e)
71+
throw PasetoCryptoException("CryptoException", e)
7272
}
7373
}
7474

paseto/src/main/kotlin/net/aholbrook/paseto/exception/ByteArrayExceptions.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ class ByteArrayLengthException @InternalApi constructor(
88
val required: Int,
99
val isExact: Boolean = true,
1010
cause: Throwable? = null,
11-
) : CryptoProviderException(
11+
) : PasetoException(
1212
"$arg: $required ${if (isExact) "exact " else ""}bytes required, given $len bytes.",
1313
cause,
1414
)
@@ -19,4 +19,4 @@ class ByteArrayRangeException @InternalApi constructor(
1919
val minBound: Int,
2020
val maxBound: Int,
2121
throwable: Throwable? = null,
22-
) : CryptoProviderException("$arg: length outside of range $minBound..$maxBound.", throwable)
22+
) : PasetoException("$arg: length outside of range $minBound..$maxBound.", throwable)

paseto/src/main/kotlin/net/aholbrook/paseto/exception/Exceptions.kt

Lines changed: 11 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,37 +4,31 @@ import net.aholbrook.paseto.InternalApi
44
import net.aholbrook.paseto.Token
55
import net.aholbrook.paseto.protocol.Version
66

7-
open class CryptoProviderException @InternalApi constructor(s: String?, throwable: Throwable?) :
8-
RuntimeException(s, throwable)
9-
107
open class PasetoException @InternalApi constructor(msg: String, cause: Throwable? = null) :
118
RuntimeException(msg, cause)
129

10+
open class CryptoException @InternalApi constructor(s: String, throwable: Throwable?) :
11+
PasetoException(s, throwable)
12+
1313
class ImplicitAssertionsNotSupportedException @InternalApi constructor(actual: Version) :
1414
PasetoException("Implicit assertions are not supported for " + actual.name + " tokens.")
1515

1616
class CannotSignWithoutSecretKey @InternalApi constructor() :
1717
PasetoException("Token services without a secret key do not support signing.")
1818

19-
open class PasetoStringException @InternalApi constructor(s: String, val token: String, cause: Throwable? = null) :
19+
open class EncodedTokenException @InternalApi constructor(s: String, val token: String, cause: Throwable? = null) :
2020
PasetoException(s, cause)
2121

22-
open class PasetoPayloadException @InternalApi constructor(
23-
s: String,
24-
val payload: ByteArray,
25-
cause: Throwable? = null,
26-
) : PasetoException(s, cause)
27-
2822
class EncryptionException @InternalApi constructor() : PasetoException("Failed to encrypt payload.")
2923

3024
class DecryptionException @InternalApi constructor(token: String) :
31-
PasetoStringException("Failed to decrypt token.", token)
25+
EncodedTokenException("Failed to decrypt token.", token)
3226

3327
open class InvalidFooterException @InternalApi constructor(msg: String, cause: Throwable? = null) :
3428
PasetoException(msg, cause)
3529

3630
class IncorrectFooterException @InternalApi constructor(val given: String?, val expected: String) :
37-
PasetoException("Invalid footer in token: \"$given\" expected: \"$expected\".")
31+
InvalidFooterException("Invalid footer in token: \"$given\" expected: \"$expected\".")
3832

3933
class FooterExceedsMaxLengthException @InternalApi constructor(val length: Int, val max: Int) :
4034
InvalidFooterException("Footer of length $length exceeds maximum length $max.")
@@ -49,27 +43,18 @@ class FooterJsonParseException @InternalApi constructor(message: String?, cause:
4943
InvalidFooterException(message ?: "", cause)
5044

5145
class InvalidHeaderException @InternalApi constructor(val given: String?, val expected: String, token: String) :
52-
PasetoStringException("Invalid header in token: \"$given\", expected: \"$expected\".", token)
46+
EncodedTokenException("Invalid header in token: \"$given\", expected: \"$expected\".", token)
5347

54-
class SigningException @InternalApi constructor(payload: ByteArray) :
55-
PasetoPayloadException("Failed to sign payload.", payload)
48+
class SigningException @InternalApi constructor(val payload: ByteArray) :
49+
PasetoException("Failed to sign payload.")
5650

5751
class SignatureVerificationException @InternalApi constructor(token: String) :
58-
PasetoStringException("Failed to verify token signature.", token)
59-
60-
open class PasetoTokenException @InternalApi constructor(s: String, val token: Token) : PasetoException(s)
61-
62-
class TokenExpiresBeforeIssuedException @InternalApi constructor(token: Token) :
63-
PasetoTokenException("token would expire (${token.expiresAt}) before it was issued (${token.issuedAt})", token)
52+
EncodedTokenException("Failed to verify token signature.", token)
6453

65-
class TokenIsNotValidUntilAfterExpiration @InternalApi constructor(token: Token) :
66-
PasetoTokenException("token is not valid (${token.notBefore}) until after it expires (${token.expiresAt})", token)
6754

68-
class MissingClaimException @InternalApi constructor(val claim: String, token: Token) :
69-
PasetoTokenException("Token is missing required claim $claim.", token)
7055

7156
class PasetoParseException @InternalApi constructor(val reason: Reason, token: String) :
72-
PasetoStringException(
57+
EncodedTokenException(
7358
when (reason) {
7459
Reason.MISSING_SECTIONS ->
7560
"Invalid token: \"$token\" unable to locate 3-4 paseto sections."

paseto/src/main/kotlin/net/aholbrook/paseto/exception/KeyExceptions.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ class KeyVersionException @InternalApi constructor(val expected: Version, val ac
1313
PasetoException("Got wrong Key version: $actual given, expected: $expected.")
1414

1515
class KeyClearedException @InternalApi constructor() :
16-
PasetoException("Key instance has already been consumed and cleared. Lpad a new key for each operation.")
16+
PasetoException("Key instance has already been consumed and cleared. Load a new key for each operation.")
1717

1818
class KeyPemUnsupportedTypeException @InternalApi constructor(val type: String) :
1919
PasetoException("Unsupported PEM type: $type")
2020

21-
class KeyV3Exception @InternalApi constructor(msg: String, cause: Throwable? = null) : PasetoException(msg, cause)
21+
class EcKeyException @InternalApi constructor(msg: String, cause: Throwable? = null) : PasetoException(msg, cause)

paseto/src/main/kotlin/net/aholbrook/paseto/exception/RuleValidationExceptions.kt

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,57 +5,65 @@ import net.aholbrook.paseto.Token
55
import net.aholbrook.paseto.rules.Rule
66
import java.time.Instant
77

8+
89
open class RuleValidationException @InternalApi constructor(
910
msg: String,
1011
val claim: String,
11-
val rule: Rule?,
12-
token: Token,
13-
) : PasetoTokenException(msg, token)
12+
val token: Token,
13+
) : PasetoException(msg) {
14+
lateinit var rule: Rule
15+
internal set
16+
}
17+
18+
class TokenExpiresBeforeIssuedException @InternalApi constructor(token: Token) :
19+
RuleValidationException("token would expire (${token.expiresAt}) before it was issued (${token.issuedAt})", "iat", token)
1420

15-
class ExpiredTokenException @InternalApi constructor(time: Instant, rule: Rule, token: Token) :
16-
RuleValidationException("Token expired at $time.", "exp", rule, token)
21+
class TokenIsNotValidUntilAfterExpiration @InternalApi constructor(token: Token, ) :
22+
RuleValidationException("token is not valid (${token.notBefore}) until after it expires (${token.expiresAt})", "exp", token)
23+
24+
class MissingClaimException @InternalApi constructor(claim: String, token: Token, ) :
25+
RuleValidationException("Token is missing required claim $claim.", claim, token)
26+
27+
class ExpiredTokenException @InternalApi constructor(time: Instant, token: Token) :
28+
RuleValidationException("Token expired at $time.", "exp", token)
1729

1830
class IncorrectAudienceException @InternalApi constructor(
1931
val expected: String,
2032
val audience: String?,
21-
rule: Rule,
2233
token: Token,
23-
) : RuleValidationException("Token audience is \"$audience\", required: \"$expected\"", "aud", rule, token)
34+
) : RuleValidationException("Token audience is \"$audience\", required: \"$expected\"", "aud", token)
2435

2536
class IncorrectTokenIdException @InternalApi constructor(
2637
val expected: String,
2738
val tokenId: String?,
28-
rule: Rule,
2939
token: Token,
30-
) : RuleValidationException("Token ID is \"$tokenId\", required: \"$expected\"", "jti", rule, token)
40+
) : RuleValidationException("Token ID is \"$tokenId\", required: \"$expected\"", "jti", token)
3141

3242
class IncorrectIssuerException @InternalApi constructor(
3343
val expected: String,
3444
val issuer: String?,
35-
rule: Rule,
3645
token: Token,
37-
) : RuleValidationException("Token issued by \"$issuer\", required: \"$expected\"", "iss", rule, token)
46+
) : RuleValidationException("Token issued by \"$issuer\", required: \"$expected\"", "iss", token)
3847

3948
class IncorrectSubjectException @InternalApi constructor(
40-
val expected: String?,
49+
val expected: String,
4150
val subject: String,
42-
rule: Rule,
4351
token: Token,
44-
) : RuleValidationException("Token subject is \"$subject\", required: \"$expected\"", "sub", rule, token)
52+
) : RuleValidationException("Token subject is \"$subject\", required: \"$expected\"", "sub", token)
4553

46-
class IssuedInFutureException @InternalApi constructor(now: Instant, issuedAt: Instant?, rule: Rule, token: Token) :
47-
RuleValidationException("Token was issued at a future date/time $issuedAt, currently: $now", "iat", rule, token)
54+
class IssuedInFutureException @InternalApi constructor(now: Instant, issuedAt: Instant?, token: Token) :
55+
RuleValidationException("Token was issued at a future date/time $issuedAt, currently: $now", "iat", token)
4856

49-
class NotYetValidTokenException @InternalApi constructor(time: Instant, rule: Rule, token: Token) :
50-
RuleValidationException("Token is not valid until $time.", "nbf", rule, token)
57+
class NotYetValidException @InternalApi constructor(time: Instant, token: Token) :
58+
RuleValidationException("Token is not valid until $time.", "nbf", token)
5159

52-
class MultipleValidationExceptions @InternalApi constructor(token: Token) :
53-
PasetoTokenException("Multiple verification errors.", token) {
60+
class MultipleValidationErrorsException @InternalApi constructor(val token: Token) :
61+
PasetoException("Multiple verification errors.") {
5462

55-
private val internalExceptions = mutableListOf<PasetoTokenException>()
56-
val exceptions: List<PasetoTokenException> get() = internalExceptions
63+
private val internalExceptions = mutableListOf<RuleValidationException>()
64+
val exceptions: List<RuleValidationException> get() = internalExceptions
5765

58-
fun add(e: PasetoTokenException) {
66+
internal fun add(e: RuleValidationException) {
5967
internalExceptions.add(e)
6068
}
6169

0 commit comments

Comments
 (0)