Skip to content

Commit

Permalink
Change credentialID to bytearray
Browse files Browse the repository at this point in the history
  • Loading branch information
n0900 committed Oct 2, 2024
1 parent c3c90a2 commit 50fb66a
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import at.asitplus.KmmResult.Companion.wrap
import at.asitplus.dif.PresentationDefinition
import at.asitplus.dif.rqes.Enums.SignatureQualifierEnum
import at.asitplus.dif.rqes.Serializer.HashesSerializer
import at.asitplus.signum.indispensable.asn1.ObjectIdentifier
import at.asitplus.signum.indispensable.io.ByteArrayBase64UrlSerializer
import at.asitplus.signum.indispensable.josef.JsonWebToken
import at.asitplus.signum.indispensable.josef.io.InstantLongSerializer
import kotlinx.datetime.Instant
Expand Down Expand Up @@ -271,10 +273,14 @@ data class AuthenticationRequestParameters(

/**
* CSC: REQUIRED-"credential"
* The identifier associated to the credential to authorize
* The identifier associated to the credential to authorize.
* This parameter value may contain characters that are reserved, unsafe or
* forbidden in URLs and therefore SHALL be url-encoded by the signature
* application
*/
@SerialName("credentialID")
val credentialID: String? = null,
@Serializable(ByteArrayBase64UrlSerializer::class)
val credentialID: ByteArray? = null,

/**
* CSC: Required-"credential"
Expand Down Expand Up @@ -304,7 +310,7 @@ data class AuthenticationRequestParameters(
* String containing the OID of the hash algorithm used to generate the hashes
*/
@SerialName("hashAlgorithmOID")
val hashAlgorithmOid: String? = null,
val hashAlgorithmOid: ObjectIdentifier? = null,

/**
* CSC: OPTIONAL
Expand Down Expand Up @@ -335,6 +341,97 @@ data class AuthenticationRequestParameters(
val clientData: String? = null,
) {

override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || this::class != other::class) return false

other as AuthenticationRequestParameters

if (responseType != other.responseType) return false
if (clientId != other.clientId) return false
if (redirectUrl != other.redirectUrl) return false
if (scope != other.scope) return false
if (state != other.state) return false
if (nonce != other.nonce) return false
if (claims != other.claims) return false
if (clientMetadata != other.clientMetadata) return false
if (clientMetadataUri != other.clientMetadataUri) return false
if (idTokenHint != other.idTokenHint) return false
if (request != other.request) return false
if (requestUri != other.requestUri) return false
if (idTokenType != other.idTokenType) return false
if (presentationDefinition != other.presentationDefinition) return false
if (presentationDefinitionUrl != other.presentationDefinitionUrl) return false
if (authorizationDetails != other.authorizationDetails) return false
if (clientIdScheme != other.clientIdScheme) return false
if (walletIssuer != other.walletIssuer) return false
if (userHint != other.userHint) return false
if (issuerState != other.issuerState) return false
if (responseMode != other.responseMode) return false
if (responseUrl != other.responseUrl) return false
if (audience != other.audience) return false
if (issuer != other.issuer) return false
if (issuedAt != other.issuedAt) return false
if (resource != other.resource) return false
if (codeChallenge != other.codeChallenge) return false
if (codeChallengeMethod != other.codeChallengeMethod) return false
if (lang != other.lang) return false
if (credentialID != null) {
if (other.credentialID == null) return false
if (!credentialID.contentEquals(other.credentialID)) return false
} else if (other.credentialID != null) return false
if (signatureQualifier != other.signatureQualifier) return false
if (numSignatures != other.numSignatures) return false
if (hashes != other.hashes) return false
if (hashAlgorithmOid != other.hashAlgorithmOid) return false
if (description != other.description) return false
if (accountToken != other.accountToken) return false
if (clientData != other.clientData) return false

return true
}

override fun hashCode(): Int {
var result = responseType?.hashCode() ?: 0
result = 31 * result + (clientId?.hashCode() ?: 0)
result = 31 * result + (redirectUrl?.hashCode() ?: 0)
result = 31 * result + (scope?.hashCode() ?: 0)
result = 31 * result + (state?.hashCode() ?: 0)
result = 31 * result + (nonce?.hashCode() ?: 0)
result = 31 * result + (claims?.hashCode() ?: 0)
result = 31 * result + (clientMetadata?.hashCode() ?: 0)
result = 31 * result + (clientMetadataUri?.hashCode() ?: 0)
result = 31 * result + (idTokenHint?.hashCode() ?: 0)
result = 31 * result + (request?.hashCode() ?: 0)
result = 31 * result + (requestUri?.hashCode() ?: 0)
result = 31 * result + (idTokenType?.hashCode() ?: 0)
result = 31 * result + (presentationDefinition?.hashCode() ?: 0)
result = 31 * result + (presentationDefinitionUrl?.hashCode() ?: 0)
result = 31 * result + (authorizationDetails?.hashCode() ?: 0)
result = 31 * result + (clientIdScheme?.hashCode() ?: 0)
result = 31 * result + (walletIssuer?.hashCode() ?: 0)
result = 31 * result + (userHint?.hashCode() ?: 0)
result = 31 * result + (issuerState?.hashCode() ?: 0)
result = 31 * result + (responseMode?.hashCode() ?: 0)
result = 31 * result + (responseUrl?.hashCode() ?: 0)
result = 31 * result + (audience?.hashCode() ?: 0)
result = 31 * result + (issuer?.hashCode() ?: 0)
result = 31 * result + (issuedAt?.hashCode() ?: 0)
result = 31 * result + (resource?.hashCode() ?: 0)
result = 31 * result + (codeChallenge?.hashCode() ?: 0)
result = 31 * result + (codeChallengeMethod?.hashCode() ?: 0)
result = 31 * result + (lang?.hashCode() ?: 0)
result = 31 * result + (credentialID?.contentHashCode() ?: 0)
result = 31 * result + (signatureQualifier?.hashCode() ?: 0)
result = 31 * result + (numSignatures ?: 0)
result = 31 * result + (hashes?.hashCode() ?: 0)
result = 31 * result + (hashAlgorithmOid?.hashCode() ?: 0)
result = 31 * result + (description?.hashCode() ?: 0)
result = 31 * result + (accountToken?.hashCode() ?: 0)
result = 31 * result + (clientData?.hashCode() ?: 0)
return result
}

fun serialize() = jsonSerializer.encodeToString(this)

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import at.asitplus.signum.indispensable.io.Base64UrlStrict
import at.asitplus.wallet.lib.iso.sha256
import at.asitplus.wallet.lib.jws.JwsService
import at.asitplus.wallet.lib.oidvci.*
import io.ktor.util.*
import io.matthewnelson.encoding.core.Decoder.Companion.decodeToByteArray
import io.matthewnelson.encoding.core.Encoder.Companion.encodeToString
import kotlin.random.Random

Expand Down Expand Up @@ -52,6 +54,7 @@ class OAuth2Client(
* @param authorizationDetails from RFC 9396 OAuth 2.0 Rich Authorization Requests
* @param resource from RFC 8707 Resource Indicators for OAuth 2.0, in OID4VCI flows the value
* @param requestUri from CSC API v2.0.0.2: URI pointing to a pushed authorization request previously uploaded by the client
* @param credentialId from CSC API v2.0.0.2: The identifier associated to the credential to authorize
* of [IssuerMetadata.credentialIssuer]
*/
suspend fun createAuthRequest(
Expand All @@ -60,6 +63,7 @@ class OAuth2Client(
scope: String? = null,
resource: String? = null,
requestUri: String? = null,
credentialId: ByteArray? = null,
) = AuthenticationRequestParameters(
responseType = GRANT_TYPE_CODE,
state = state,
Expand All @@ -71,6 +75,7 @@ class OAuth2Client(
codeChallenge = generateCodeVerifier(state),
codeChallengeMethod = CODE_CHALLENGE_METHOD_SHA256,
requestUri = requestUri,
credentialID = credentialId
)

@OptIn(ExperimentalStdlibApi::class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,17 @@ class RqesWalletService(
private val oauth2Client: OAuth2Client = OAuth2Client(clientId = clientId, redirectUrl = redirectUrl),
) {


suspend fun createOAuth2AuthenticationRequest(rqesRequest: RqesRequest): AuthenticationRequestParameters =
suspend fun createOAuth2AuthenticationRequest(
rqesRequest: RqesRequest,
credentialId: ByteArray,
): AuthenticationRequestParameters =
oauth2Client.createAuthRequest(
state = uuid4().toString(),
authorizationDetails = setOf(rqesRequest.toAuthorizationDetails()),
scope = RqesConstants.SCOPE
scope = RqesConstants.SCOPE,
credentialId = credentialId,
)


/**
* TODO: could also use [Document] instead of [CscDocumentDigest], also [credential_id] instead of [SAD]
*/
Expand Down

0 comments on commit 50fb66a

Please sign in to comment.