Skip to content

Commit

Permalink
Fix: Wallet unit attestation changes
Browse files Browse the repository at this point in the history
  • Loading branch information
lijogeorgep authored and josmilan committed Jan 10, 2025
1 parent b043f64 commit 24ffa5d
Show file tree
Hide file tree
Showing 9 changed files with 191 additions and 99 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ package com.ewc.eudi_wallet_oidc_android


import com.google.gson.annotations.SerializedName
import com.nimbusds.jose.jwk.ECKey

data class WalletAttestationResult(
@SerializedName("credentialOffer") var credentialOffer: String? = null,
@SerializedName("clientAssertion") var clientAssertion: String? = null
@SerializedName("clientAssertion") var clientAssertion: String? = null,
@SerializedName("did") var did: String? = null,
@SerializedName("ecKey") var ecKey: ECKey? = null
)
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@ data class AuthorisationServerWellKnownConfiguration(
@SerializedName("subject_syntax_types_supported") var subjectSyntaxTypesSupported: ArrayList<String> = arrayListOf(),
@SerializedName("subject_syntax_types_discriminations") var subjectSyntaxTypesDiscriminations: ArrayList<String> = arrayListOf(),
@SerializedName("subject_trust_frameworks_supported") var subjectTrustFrameworksSupported: ArrayList<String> = arrayListOf(),
@SerializedName("id_token_signing_alg_values_supported") var idTokenTypesSupported: ArrayList<String> = arrayListOf(),
@SerializedName("id_token_types_supported") var idTokenTypesSupported: ArrayList<String> = arrayListOf(),
@SerializedName("require_pushed_authorization_requests") var requirePushedAuthorizationRequests: Boolean = false,
@SerializedName("pushed_authorization_request_endpoint") var pushedAuthorizationRequestEndpoint: String? = null,
)
@SerializedName("id_token_signing_alg_values_supported") var idTokenSigningAlgValuesSupported: ArrayList<String> = arrayListOf(),
)

data class RequestAuthenticationMethodsSupported(

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ data class PresentationRequest(
@SerializedName("presentation_definition_uri") var presentationDefinitionUri: String? = null,
@SerializedName("client_metadata") var clientMetaDetails: Any? = null,
@SerializedName("client_metadata_uri") var clientMetadataUri: String? = null,
@SerializedName("client_id_scheme") var clientIdScheme: String? = null
@SerializedName("client_id_scheme") var clientIdScheme: String? = null,
@SerializedName("transaction_data") var transactionDdata: ArrayList<String>? = null

)
data class WrappedPresentationRequest(
var presentationRequest: PresentationRequest?=null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -444,8 +444,19 @@ class IssueService : IssueServiceInterface {
isPreAuthorisedCodeFlow: Boolean?,
userPin: String?,
version: Int?,
clientAssertion: String?
clientAssertion: String?,
walletUnitAttestationJWT: String? ,
walletUnitProofOfPossession: String?,
): WrappedTokenResponse? {
val redirectUri = "http://localhost:8080"
val headers = mutableMapOf<String, String>().apply {
if (!walletUnitAttestationJWT.isNullOrEmpty()) {
this["OAuth-Client-Attestation"] = walletUnitAttestationJWT
}
if (!walletUnitProofOfPossession.isNullOrEmpty()) {
this["OAuth-Client-Attestation-PoP"] = walletUnitProofOfPossession
}
}
val response = ApiManager.api.getService()?.getAccessTokenFromCode(
tokenEndPoint ?: "",
if (isPreAuthorisedCodeFlow == true) {
Expand All @@ -466,14 +477,16 @@ class IssueService : IssueServiceInterface {
"grant_type" to "authorization_code",
"code" to (code ?: ""),
"client_id" to (did ?: ""),
"code_verifier" to (codeVerifier ?: "")
"code_verifier" to (codeVerifier ?: ""),
"redirect_uri" to (redirectUri ?: "")
).apply {
if (clientAssertion != null) {
this["clientAssertion"] = clientAssertion ?: ""
this["clientAssertionType"] = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
this["client_assertion"] = clientAssertion ?: ""
this["client_assertion_type"] = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
}
}
}
},
headers
)

val tokenResponse = when {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ interface IssueServiceInterface {
isPreAuthorisedCodeFlow: Boolean?,
userPin: String?,
version: Int?,
clientAssertion: String?
clientAssertion: String?,
walletUnitAttestationJWT: String? ,
walletUnitProofOfPossession: String?,
): WrappedTokenResponse?

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import retrofit2.http.FieldMap
import retrofit2.http.FormUrlEncoded
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.HeaderMap
import retrofit2.http.POST
import retrofit2.http.QueryMap
import retrofit2.http.Url
Expand Down Expand Up @@ -58,7 +59,8 @@ interface ApiService {
@POST("")
suspend fun getAccessTokenFromCode(
@Url url: String,
@FieldMap map: Map<String, String?>
@FieldMap map: Map<String, String?>,
@HeaderMap headers: Map<String, String> = emptyMap()
): Response<TokenResponse>

@POST
Expand Down Expand Up @@ -92,7 +94,8 @@ interface ApiService {
@POST("")
suspend fun sendVPToken(
@Url url: String,
@FieldMap map: Map<String, String>
@FieldMap map: Map<String, String>,
@HeaderMap headers: Map<String, String> = emptyMap()
): Response<ResponseBody>

@GET
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ object WalletAttestationUtil {
val baseUrl =
"https://staging-oid4vc.igrant.io/organisation/4264f05a-e0cd-49cb-bb32-b664e1d0f448/service"


suspend fun initiateWalletUnitAttestation(
context: Context,
cloudProjectNumber: Long
Expand All @@ -70,7 +71,8 @@ object WalletAttestationUtil {

Log.d(TAG, "generated privateKey With Attestation:$privateKey")
Log.d(TAG, "generated publicKey With Attestation:$publicKey")

val did = DIDService().createDID(ecKey)
Log.d(TAG, "Generated DID: $did")
// Step 2: Prepare the integrity token provider
val tokenProvider = prepareIntegrityTokenProvider(context, cloudProjectNumber)
Log.d(TAG, "Prepare tokenProvider: $tokenProvider")
Expand All @@ -89,7 +91,7 @@ object WalletAttestationUtil {
Log.d(TAG, "integrity token:$token ")

// Step 6: Generate client assertion
clientAssertion = generateClientAssertion(baseUrl, ecKey)
clientAssertion = generateClientAssertion(ecKey,did)
Log.d(TAG, "clientAssertion:$clientAssertion ")


Expand All @@ -105,7 +107,9 @@ object WalletAttestationUtil {

WalletAttestationResult(
walletUnitAttestationCredential?.credentialOffer,
clientAssertion
clientAssertion,
did,
ecKey
)

} catch (e: Exception) {
Expand Down Expand Up @@ -240,13 +244,11 @@ object WalletAttestationUtil {


private fun generateClientAssertion(
aud: String,
ecKey: ECKey,
did: String?
): String {
try {

val did = DIDService().createDID(ecKey)
//val aud = "aud url"
Log.d(TAG, "Client assertion did:$did")
val now = Date()
val expTime = Date(now.time + 3600 * 1000)
Expand All @@ -260,7 +262,7 @@ object WalletAttestationUtil {

// Create JWT Payload
val payload = JWTClaimsSet.Builder()
.audience(aud)
.audience(baseUrl)
.claim("client_id", did)
.claim("cnf", mapOf("jwk" to ecKey.toJSONObject()))
.expirationTime(expTime)
Expand Down Expand Up @@ -336,41 +338,42 @@ object WalletAttestationUtil {


suspend fun generateWUAProofOfPossession(
iss: String,
aud: String,
jwk: JWK,
validityDuration: Long = 24 * 60 * 60 * 1000 // Default: 24 hours
): String {
val now = Date()
val expirationTime = Date(now.time + validityDuration)

// Create the JWT claims
val claimsSet = JWTClaimsSet.Builder()
.issuer(iss)
.audience(aud)
.notBeforeTime(now)
.expirationTime(expirationTime)
.jwtID(UUID.randomUUID().toString()) // Unique identifier for replay protection
.build()
ecKey: ECKey,
did: String?,
aud: String?
): String? {
try {
val now = Date()
val expirationTime = Date(now.time + 6 * 60 * 1000)

// Create the JWS header
val jwsHeader =
JWSHeader.Builder(JWSAlgorithm.ES256) // Use ES256 or the appropriate algorithm
.type(JOSEObjectType.JWT)
.keyID(jwk.keyID) // Include key ID in the header
// Create the JWT claims
val claimsSet = JWTClaimsSet.Builder()
.issuer(did)
.audience(aud)
.notBeforeTime(now)
.expirationTime(expirationTime)
.jwtID("urn:uuid:${UUID.randomUUID().toString()}")
.build()

// Sign the JWT
val signedJWT = SignedJWT(jwsHeader, claimsSet)
// Create the JWS header
val header = JWSHeader.Builder(JWSAlgorithm.ES256).build()

// Sign the JWT
val signedJWT = SignedJWT(header, claimsSet)

// Create signer with the private key
val signer = ECDSASigner(jwk.toECKey())
// Create signer with the private key
val signer = ECDSASigner(ecKey)

// Sign the JWT
signedJWT.sign(signer)

// Sign the JWT
signedJWT.sign(signer)
// Return the serialized JWT
return signedJWT.serialize()
}catch (e:Exception){
Log.d("Error",e.message.toString())
return null
}

// Return the serialized JWT
return signedJWT.serialize()
}


Expand Down
Loading

0 comments on commit 24ffa5d

Please sign in to comment.