From 1d86034347fdb69d00727a10cabd7fd02ae14f4f Mon Sep 17 00:00:00 2001 From: Simon Mueller Date: Thu, 3 Oct 2024 11:03:05 +0200 Subject: [PATCH] Integrate indispensable data classes --- .../CscDocumentDigest.kt | 29 ++++++++++++--- .../dif/rqes/SignatureRequestParameters.kt | 36 ++++++++++++++----- .../at/asitplus/openid/rqes/RqesRequest.kt | 14 ++++---- .../wallet/lib/oidvci/RqesWalletService.kt | 4 +-- 4 files changed, 61 insertions(+), 22 deletions(-) diff --git a/dif-data-classes/src/commonMain/kotlin/at/asitplus/dif/rqes/CollectionEntries/DocumentDigestEntries/CscDocumentDigest.kt b/dif-data-classes/src/commonMain/kotlin/at/asitplus/dif/rqes/CollectionEntries/DocumentDigestEntries/CscDocumentDigest.kt index 0fbeb338..8467fb12 100644 --- a/dif-data-classes/src/commonMain/kotlin/at/asitplus/dif/rqes/CollectionEntries/DocumentDigestEntries/CscDocumentDigest.kt +++ b/dif-data-classes/src/commonMain/kotlin/at/asitplus/dif/rqes/CollectionEntries/DocumentDigestEntries/CscDocumentDigest.kt @@ -7,8 +7,11 @@ import at.asitplus.dif.rqes.Hashes import at.asitplus.dif.rqes.Serializer.Asn1EncodableBase64Serializer import at.asitplus.dif.rqes.contentEquals import at.asitplus.dif.rqes.contentHashCode +import at.asitplus.signum.indispensable.Digest +import at.asitplus.signum.indispensable.X509SignatureAlgorithm import at.asitplus.signum.indispensable.asn1.Asn1Element import at.asitplus.signum.indispensable.asn1.ObjectIdentifier +import io.github.aakira.napier.Napier import io.ktor.util.reflect.* import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -55,14 +58,14 @@ data class CscDocumentDigest( * The OID of the algorithm to use for signing */ @SerialName("signAlgo") - val signAlgo: ObjectIdentifier, + val signAlgoOid: ObjectIdentifier, /** * The Base64-encoded DER-encoded ASN.1 signature algorithm parameters if required by * the signature algorithm - Necessary for RSASSA-PSS for example */ @SerialName("signAlgoParams") - @Serializable(Asn1EncodableBase64Serializer::class) + @Serializable(with = Asn1EncodableBase64Serializer::class) val signAlgoParams: Asn1Element? = null, /** @@ -80,6 +83,24 @@ data class CscDocumentDigest( @SerialName("signed_envelope_property") val signedEnvelopeProperty: SignedEnvelopeProperty? = null, ) { + + val signAlgorithm: X509SignatureAlgorithm? = + run { + val DERencoded = signAlgoOid.encodeToTlv().asSequence() + kotlin.runCatching { X509SignatureAlgorithm.doDecode(DERencoded) }.getOrElse { + Napier.d { "Could not deserialize signature algorithm from OID $signAlgoOid. Reason: $it" } + null + }.also { + require(it?.digest != Digest.SHA1) + } + } + + val hashAlgorithm: Digest? by lazy { + hashAlgorithmOid?.let { + Digest.entries.find { digest -> digest.oid == it } + } + } + override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -90,7 +111,7 @@ data class CscDocumentDigest( if (hashAlgorithmOid != other.hashAlgorithmOid) return false if (signatureFormat != other.signatureFormat) return false if (conformanceLevel != other.conformanceLevel) return false - if (signAlgo != other.signAlgo) return false + if (signAlgoOid != other.signAlgoOid) return false if (signAlgoParams != other.signAlgoParams) return false if (signedProps != other.signedProps) return false if (signedEnvelopeProperty != other.signedEnvelopeProperty) return false @@ -103,7 +124,7 @@ data class CscDocumentDigest( result = 31 * result + (hashAlgorithmOid?.hashCode() ?: 0) result = 31 * result + signatureFormat.hashCode() result = 31 * result + conformanceLevel.hashCode() - result = 31 * result + signAlgo.hashCode() + result = 31 * result + signAlgoOid.hashCode() result = 31 * result + (signAlgoParams?.hashCode() ?: 0) result = 31 * result + (signedProps?.hashCode() ?: 0) result = 31 * result + signedEnvelopeProperty.hashCode() diff --git a/dif-data-classes/src/commonMain/kotlin/at/asitplus/dif/rqes/SignatureRequestParameters.kt b/dif-data-classes/src/commonMain/kotlin/at/asitplus/dif/rqes/SignatureRequestParameters.kt index a987fd5b..9b058a92 100644 --- a/dif-data-classes/src/commonMain/kotlin/at/asitplus/dif/rqes/SignatureRequestParameters.kt +++ b/dif-data-classes/src/commonMain/kotlin/at/asitplus/dif/rqes/SignatureRequestParameters.kt @@ -6,8 +6,13 @@ import at.asitplus.dif.rqes.CollectionEntries.Document import at.asitplus.dif.rqes.CollectionEntries.DocumentDigestEntries.CscDocumentDigest import at.asitplus.dif.rqes.Enums.OperationModeEnum import at.asitplus.dif.rqes.Enums.SignatureQualifierEnum +import at.asitplus.dif.rqes.Serializer.Asn1EncodableBase64Serializer import at.asitplus.dif.rqes.Serializer.SignatureRequestParameterSerializer +import at.asitplus.signum.indispensable.Digest +import at.asitplus.signum.indispensable.X509SignatureAlgorithm +import at.asitplus.signum.indispensable.asn1.Asn1Element import at.asitplus.signum.indispensable.asn1.ObjectIdentifier +import io.github.aakira.napier.Napier import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.UseSerializers @@ -51,8 +56,9 @@ sealed interface SignatureRequestParameters { val responseUri: String? /** - * The clientData as defined in the Input parameter table in `oauth2/authorize` - * TODO double check + * Arbitrary data from the signature application. It can be used to handle a + * transaction identifier or other application-spe cific data that may be useful for + * debugging purposes */ val clientData: String? } @@ -97,17 +103,29 @@ data class SignHashParameters( * in `credentials/list` */ @SerialName("signAlgo") - val signAlgo: ObjectIdentifier? = null, + val signAlgoOid: ObjectIdentifier? = null, /** - * TODO: The Base64-encoded DER-encoded ASN.1 signature parameters, if required by - * the signature algorithm. Some algorithms like RSASSA-PSS, as defined in RFC8017, - * may require additional parameters + * The Base64-encoded DER-encoded ASN.1 signature algorithm parameters if required by + * the signature algorithm - Necessary for RSASSA-PSS for example */ @SerialName("signAlgoParams") - val signAlgoParams: String? = null, + @Serializable(with = Asn1EncodableBase64Serializer::class) + val signAlgoParams: Asn1Element? = null, ) : SignatureRequestParameters { + + val signAlgorithm: X509SignatureAlgorithm? = + run { + val DERencoded = signAlgoOid?.encodeToTlv()?.asSequence() + kotlin.runCatching { X509SignatureAlgorithm.doDecode(DERencoded) }.getOrElse { + Napier.d { "Could not deserialize signature algorithm from OID $signAlgoOid. Reason: $it" } + null + }.also { + require(it?.digest != Digest.SHA1) + } + } + override fun equals(other: Any?): Boolean { if (this === other) return true if (other == null || this::class != other::class) return false @@ -121,7 +139,7 @@ data class SignHashParameters( if (responseUri != other.responseUri) return false if (clientData != other.clientData) return false if (hashAlgorithmOid != other.hashAlgorithmOid) return false - if (signAlgo != other.signAlgo) return false + if (signAlgoOid != other.signAlgoOid) return false if (signAlgoParams != other.signAlgoParams) return false return true @@ -136,7 +154,7 @@ data class SignHashParameters( result = 31 * result + (responseUri?.hashCode() ?: 0) result = 31 * result + (clientData?.hashCode() ?: 0) result = 31 * result + (hashAlgorithmOid?.hashCode() ?: 0) - result = 31 * result + (signAlgo?.hashCode() ?: 0) + result = 31 * result + (signAlgoOid?.hashCode() ?: 0) result = 31 * result + (signAlgoParams?.hashCode() ?: 0) return result } diff --git a/openid-data-classes/src/commonMain/kotlin/at/asitplus/openid/rqes/RqesRequest.kt b/openid-data-classes/src/commonMain/kotlin/at/asitplus/openid/rqes/RqesRequest.kt index 0b638415..ff597498 100644 --- a/openid-data-classes/src/commonMain/kotlin/at/asitplus/openid/rqes/RqesRequest.kt +++ b/openid-data-classes/src/commonMain/kotlin/at/asitplus/openid/rqes/RqesRequest.kt @@ -9,6 +9,8 @@ import at.asitplus.dif.rqes.Enums.SignatureQualifierEnum import at.asitplus.dif.rqes.Enums.SignedEnvelopeProperty import at.asitplus.openid.AuthorizationDetails import at.asitplus.openid.OpenIdConstants +import at.asitplus.signum.indispensable.Digest +import at.asitplus.signum.indispensable.X509SignatureAlgorithm import at.asitplus.signum.indispensable.asn1.Asn1Element import at.asitplus.signum.indispensable.asn1.KnownOIDs.sha_256 import at.asitplus.signum.indispensable.asn1.ObjectIdentifier @@ -18,6 +20,7 @@ import kotlinx.serialization.json.JsonObject /** * TODO: Find new home (different subfolder most likely) + * TODO: Describe vars * * In the Wallet centric model this is the request * coming from the Driving application to the wallet which starts @@ -47,18 +50,15 @@ data class RqesRequest( @SerialName("response_uri") val responseUri: String? = null, - @SerialName("nonce") val nonce: String, @SerialName("state") val state: String? = null, - @SerialName("signatureQualifier") val signatureQualifier: SignatureQualifierEnum = SignatureQualifierEnum.EU_EIDAS_QES, - @SerialName("documentDigests") val documentDigests: List, @@ -66,7 +66,7 @@ data class RqesRequest( val documentLocations: List, @SerialName("hashAlgorithmOID") - val hashAlgorithmOid: ObjectIdentifier = sha_256, + val hashAlgorithmOid: ObjectIdentifier = Digest.SHA256.oid, @SerialName("clientData") val clientData: String?, @@ -82,10 +82,10 @@ data class RqesRequest( fun getCscDocumentDigests( signatureFormat: SignatureFormat, - conformanceLevelEnum: ConformanceLevelEnum? = ConformanceLevelEnum.ADESBB, - signAlgorithm: ObjectIdentifier, + signAlgorithm: X509SignatureAlgorithm, signAlgoParam: Asn1Element? = null, signedProps: List? = null, + conformanceLevelEnum: ConformanceLevelEnum? = ConformanceLevelEnum.ADESBB, signedEnvelopeProperty: SignedEnvelopeProperty? = SignedEnvelopeProperty.defaultProperty(signatureFormat) ): CscDocumentDigest = CscDocumentDigest( @@ -93,7 +93,7 @@ data class RqesRequest( hashAlgorithmOid = this.hashAlgorithmOid, signatureFormat = signatureFormat, conformanceLevel = conformanceLevelEnum, - signAlgo = signAlgorithm, + signAlgoOid = signAlgorithm.oid, signAlgoParams = signAlgoParam, signedProps = signedProps, signedEnvelopeProperty = signedEnvelopeProperty diff --git a/vck-openid/src/commonMain/kotlin/at/asitplus/wallet/lib/oidvci/RqesWalletService.kt b/vck-openid/src/commonMain/kotlin/at/asitplus/wallet/lib/oidvci/RqesWalletService.kt index bfaa1d5a..a1413a06 100644 --- a/vck-openid/src/commonMain/kotlin/at/asitplus/wallet/lib/oidvci/RqesWalletService.kt +++ b/vck-openid/src/commonMain/kotlin/at/asitplus/wallet/lib/oidvci/RqesWalletService.kt @@ -7,7 +7,7 @@ import at.asitplus.dif.rqes.SignHashParameters import at.asitplus.dif.rqes.SignatureRequestParameters import at.asitplus.openid.AuthenticationRequestParameters import at.asitplus.openid.rqes.RqesRequest -import at.asitplus.signum.indispensable.asn1.KnownOIDs.ecdsaWithSHA256 +import at.asitplus.signum.indispensable.X509SignatureAlgorithm import at.asitplus.wallet.lib.oauth2.OAuth2Client import com.benasher44.uuid.uuid4 @@ -38,7 +38,7 @@ class RqesWalletService( documentDigests = listOf( rqesRequest.getCscDocumentDigests( signatureFormat = SignatureFormat.CADES, - signAlgorithm = ecdsaWithSHA256, + signAlgorithm = X509SignatureAlgorithm.ES256, ) ), responseUri = this.redirectUrl, //TODO double check