Skip to content

Commit

Permalink
v2.3.0 fix P-256 support
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelavoyan committed Feb 18, 2024
1 parent 2cdc224 commit 3c6ff37
Show file tree
Hide file tree
Showing 28 changed files with 152 additions and 89 deletions.
4 changes: 2 additions & 2 deletions VCL/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ android {
defaultConfig {
minSdk 24
targetSdk 33
versionName "2.2.1"
versionCode 128
versionName "2.3.0"
versionCode 129
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
}
Expand Down
2 changes: 1 addition & 1 deletion VCL/src/main/java/io/velocitycareerlabs/api/VCL.kt
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ interface VCL {
)

fun generateDidJwk(
remoteCryptoServicesToken: VCLToken? = null,
didJwkDescriptor: VCLDidJwkDescriptor = VCLDidJwkDescriptor(),
successHandler: (VCLDidJwk) -> Unit,
errorHandler: (VCLError) -> Unit
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ data class VCLDidJwk(
*/
val keyId: String
) {
val curve: String get() = publicJwk.curve

companion object Utils {
const val DidJwkPrefix = "did:jwk:"
const val DidJwkSuffix = "#0"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* Created by Michael Avoyan on 15/02/24.
*
* Copyright 2022 Velocity Career Labs inc.
* SPDX-License-Identifier: Apache-2.0
*/

package io.velocitycareerlabs.api.entities

import io.velocitycareerlabs.api.VCLSignatureAlgorithm

data class VCLDidJwkDescriptor(
val signatureAlgorithm: VCLSignatureAlgorithm = VCLSignatureAlgorithm.ES256,
val remoteCryptoServicesToken: VCLToken? = null
)
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ class VCLPublicJwk {
this.valueStr = this.valueJson.toString()
}

val curve: String get() = valueJson.optString("crv")

internal enum class Format(val value: String) {
jwk("jwk"),
hex("hex"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import io.velocitycareerlabs.api.VCLSignatureAlgorithm

data class VCLCryptoServicesDescriptor(
val cryptoServiceType: VCLCryptoServiceType = VCLCryptoServiceType.Local,
val signatureAlgorithm: VCLSignatureAlgorithm = VCLSignatureAlgorithm.SECP256k1,
val injectedCryptoServicesDescriptor: VCLInjectedCryptoServicesDescriptor? = null,
val remoteCryptoServicesUrlsDescriptor: VCLRemoteCryptoServicesUrlsDescriptor? = null
)
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,24 @@
package io.velocitycareerlabs.api.keys

import com.nimbusds.jose.jwk.ECKey
import io.velocitycareerlabs.api.VCLSignatureAlgorithm
import io.velocitycareerlabs.api.entities.VCLDidJwk
import io.velocitycareerlabs.api.entities.VCLDidJwkDescriptor
import io.velocitycareerlabs.api.entities.VCLResult
import io.velocitycareerlabs.api.entities.VCLToken
import io.velocitycareerlabs.api.entities.error.VCLError

interface VCLKeyService {
fun generateDidJwk(
remoteCryptoServicesToken: VCLToken?,
didJwkDescriptor: VCLDidJwkDescriptor = VCLDidJwkDescriptor(),
completionBlock: (VCLResult<VCLDidJwk>) -> Unit
)

/**
* implemented for local crypto services only
*/
fun generateSecret(
signatureAlgorithm: VCLSignatureAlgorithm,
completionBlock: (VCLResult<ECKey>) -> Unit
) {
completionBlock(VCLResult.Failure(VCLError(payload = "implemented for local crypto services only")))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ internal object GlobalConfig {

var CurrentEnvironment = VCLEnvironment.Prod
var XVnfProtocolVersion = VCLXVnfProtocolVersion.XVnfProtocolVersion1
var SignatureAlgorithm = VCLSignatureAlgorithm.SECP256k1

var IsDebugOn = false //BuildConfig.DEBUG

Expand Down
6 changes: 2 additions & 4 deletions VCL/src/main/java/io/velocitycareerlabs/impl/VCLImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,6 @@ internal class VCLImpl: VCL {
private fun initGlobalConfigurations() {
GlobalConfig.CurrentEnvironment = initializationDescriptor.environment
GlobalConfig.XVnfProtocolVersion = initializationDescriptor.xVnfProtocolVersion
GlobalConfig.SignatureAlgorithm =
initializationDescriptor.cryptoServicesDescriptor.signatureAlgorithm
GlobalConfig.IsDebugOn = initializationDescriptor.isDebugOn
}

Expand Down Expand Up @@ -532,11 +530,11 @@ internal class VCLImpl: VCL {
}

override fun generateDidJwk(
remoteCryptoServicesToken: VCLToken?,
didJwkDescriptor: VCLDidJwkDescriptor,
successHandler: (VCLDidJwk) -> Unit,
errorHandler: (VCLError) -> Unit
) {
keyServiceUseCase.generateDidJwk(remoteCryptoServicesToken) { didJwkResult ->
keyServiceUseCase.generateDidJwk(didJwkDescriptor) { didJwkResult ->
didJwkResult.handleResult(
{
successHandler(it)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
package io.velocitycareerlabs.impl.data.repositories

import io.velocitycareerlabs.api.entities.VCLDidJwk
import io.velocitycareerlabs.api.entities.VCLDidJwkDescriptor
import io.velocitycareerlabs.api.entities.VCLResult
import io.velocitycareerlabs.api.entities.VCLToken
import io.velocitycareerlabs.api.keys.VCLKeyService
Expand All @@ -17,11 +18,11 @@ internal class KeyServiceRepositoryImpl(
private val keyService: VCLKeyService
): KeyServiceRepository {
override fun generateDidJwk(
remoteCryptoServicesToken: VCLToken?,
didJwkDescriptor: VCLDidJwkDescriptor,
completionBlock: (VCLResult<VCLDidJwk>) -> Unit
) {
keyService.generateDidJwk(
remoteCryptoServicesToken,
didJwkDescriptor,
) {
completionBlock(it)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
package io.velocitycareerlabs.impl.data.usecases

import io.velocitycareerlabs.api.entities.VCLDidJwk
import io.velocitycareerlabs.api.entities.VCLDidJwkDescriptor
import io.velocitycareerlabs.api.entities.VCLResult
import io.velocitycareerlabs.api.entities.VCLToken
import io.velocitycareerlabs.impl.domain.infrastructure.executors.Executor
Expand All @@ -20,12 +21,12 @@ internal class KeyServiceUseCaseImpl(
): KeyServiceUseCase {

override fun generateDidJwk(
remoteCryptoServicesToken: VCLToken?,
didJwkDescriptor: VCLDidJwkDescriptor,
completionBlock: (VCLResult<VCLDidJwk>) -> Unit
) {
executor.runOnBackground {
keyServiceRepository.generateDidJwk(
remoteCryptoServicesToken,
didJwkDescriptor,
) {
executor.runOnMain {
completionBlock(it)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@
package io.velocitycareerlabs.impl.domain.repositories

import io.velocitycareerlabs.api.entities.VCLDidJwk
import io.velocitycareerlabs.api.entities.VCLDidJwkDescriptor
import io.velocitycareerlabs.api.entities.VCLResult
import io.velocitycareerlabs.api.entities.VCLToken

internal interface KeyServiceRepository {
fun generateDidJwk(
remoteCryptoServicesToken: VCLToken?,
didJwkDescriptor: VCLDidJwkDescriptor,
completionBlock: (VCLResult<VCLDidJwk>) -> Unit
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
package io.velocitycareerlabs.impl.domain.usecases

import io.velocitycareerlabs.api.entities.VCLDidJwk
import io.velocitycareerlabs.api.entities.VCLDidJwkDescriptor
import io.velocitycareerlabs.api.entities.VCLResult
import io.velocitycareerlabs.api.entities.VCLToken

internal interface KeyServiceUseCase {
fun generateDidJwk(
remoteCryptoServicesToken: VCLToken?,
didJwkDescriptor: VCLDidJwkDescriptor,
completionBlock: (VCLResult<VCLDidJwk>) -> Unit
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,6 @@ internal fun String.toJsonArray(): JSONArray? {
}
}

internal fun String.toPublicJwk() =
VCLPublicJwk(this.removePrefix(VCLDidJwk.DidJwkPrefix).decodeBase64())

internal fun String.toJwtList(): List<VCLJwt>? {
this.toJsonArray()?.toList()?.let { encodedCredentialList ->
val jwtCredentials = mutableListOf<VCLJwt>()
Expand All @@ -148,6 +145,13 @@ internal fun String.toJwtList(): List<VCLJwt>? {
return null
}

internal fun String.toPublicJwk() =
VCLPublicJwk(
this.removePrefix(VCLDidJwk.DidJwkPrefix)
.removeSuffix(VCLDidJwk.DidJwkSuffix)
.decodeBase64()
)

internal fun randomString(length: Int): String =
List(length) {
(('a'..'z') + ('A'..'Z') + ('0'..'9')).random()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,15 @@
package io.velocitycareerlabs.impl.jwt.local

import com.nimbusds.jose.JOSEObjectType
import com.nimbusds.jose.JWSAlgorithm
import com.nimbusds.jose.JWSHeader
import com.nimbusds.jose.crypto.ECDSASigner
import com.nimbusds.jose.jwk.ECKey
import com.nimbusds.jwt.JWTClaimsSet
import com.nimbusds.jwt.SignedJWT
import io.velocitycareerlabs.api.VCLSignatureAlgorithm
import io.velocitycareerlabs.api.entities.VCLDidJwk
import io.velocitycareerlabs.api.entities.VCLJwt
import io.velocitycareerlabs.api.entities.VCLJwtDescriptor
import io.velocitycareerlabs.api.entities.VCLPublicJwk
import io.velocitycareerlabs.api.entities.VCLResult
import io.velocitycareerlabs.api.entities.VCLToken
import io.velocitycareerlabs.api.entities.error.VCLError
Expand Down Expand Up @@ -45,7 +44,9 @@ class VCLJwtSignServiceLocalImpl(
ecKeyResult.handleResult(
successHandler = { ecKey ->
try {
val header = JWSHeader.Builder(GlobalConfig.SignatureAlgorithm.jwsAlgorithm)
val header = JWSHeader.Builder(
VCLSignatureAlgorithm.fromString(didJwk.publicJwk.curve).jwsAlgorithm
)
.type(JOSEObjectType(GlobalConfig.TypeJwt))
// HeaderValues.XVnfProtocolVersion == VCLXVnfProtocolVersion.XVnfProtocolVersion1
.jwk(ecKey.toPublicJWK())
Expand All @@ -60,6 +61,8 @@ class VCLJwtSignServiceLocalImpl(
signedJWT.sign(ECDSASigner(ecKey))

completionBlock(VCLResult.Success(VCLJwt(signedJWT)))
} catch (error: VCLError) {
completionBlock(VCLResult.Failure(error))
} catch (ex: Exception) {
completionBlock(VCLResult.Failure(VCLError(ex)))
}
Expand All @@ -72,14 +75,10 @@ class VCLJwtSignServiceLocalImpl(
}

private fun getSecretReference(
keyId: String?,
keyId: String,
completionBlock: (VCLResult<ECKey>) -> Unit
) {
keyId?.let {
keyService.retrieveSecretReference(keyId = it, completionBlock = completionBlock)
} ?: run {
keyService.generateSecret(completionBlock = completionBlock)
}
keyService.retrieveSecretReference(keyId, completionBlock = completionBlock)
}

private fun generateClaims(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import com.nimbusds.jose.jwk.Curve
import com.nimbusds.jose.jwk.ECKey
import com.nimbusds.jose.jwk.KeyUse
import com.nimbusds.jose.jwk.gen.ECKeyGenerator
import io.velocitycareerlabs.api.VCLSignatureAlgorithm
import io.velocitycareerlabs.api.entities.VCLDidJwk
import io.velocitycareerlabs.api.entities.VCLDidJwkDescriptor
import io.velocitycareerlabs.api.entities.VCLPublicJwk
import io.velocitycareerlabs.api.entities.error.VCLError
import io.velocitycareerlabs.api.entities.VCLResult
Expand All @@ -23,10 +25,12 @@ internal class VCLKeyServiceLocalImpl(
private val secretStoreService: SecretStoreService,
): VCLKeyService {
override fun generateDidJwk(
remoteCryptoServicesToken: VCLToken?,
didJwkDescriptor: VCLDidJwkDescriptor,
completionBlock: (VCLResult<VCLDidJwk>) -> Unit
) {
generateSecret { ecKeyResult ->
generateSecret(
signatureAlgorithm = didJwkDescriptor.signatureAlgorithm
) { ecKeyResult ->
ecKeyResult.handleResult(
successHandler = { ecKey ->
completionBlock(
Expand All @@ -47,11 +51,12 @@ internal class VCLKeyServiceLocalImpl(
}

override fun generateSecret(
signatureAlgorithm: VCLSignatureAlgorithm,
completionBlock: (VCLResult<ECKey>) -> Unit
) {
try {
val keyId = UUID.randomUUID().toString()
val ecKey = ECKeyGenerator(GlobalConfig.SignatureAlgorithm.curve)
val ecKey = ECKeyGenerator(signatureAlgorithm.curve)
.keyUse(KeyUse.SIGNATURE)
.keyID(keyId) // must be provided, otherwise ecKey.keyID is null
// .keyStore(KeyStoreProvider.Instance.keyStore)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@

package io.velocitycareerlabs.impl.keys

import io.velocitycareerlabs.api.VCLSignatureAlgorithm
import io.velocitycareerlabs.api.entities.VCLDidJwk
import io.velocitycareerlabs.api.entities.VCLDidJwkDescriptor
import io.velocitycareerlabs.api.entities.VCLPublicJwk
import io.velocitycareerlabs.api.entities.VCLResult
import io.velocitycareerlabs.api.entities.VCLToken
import io.velocitycareerlabs.api.entities.error.VCLError
import io.velocitycareerlabs.api.entities.handleResult
import io.velocitycareerlabs.api.entities.initialization.VCLKeyServiceUrls
import io.velocitycareerlabs.api.keys.VCLKeyService
import io.velocitycareerlabs.impl.GlobalConfig
import io.velocitycareerlabs.impl.data.infrastructure.network.Request
import io.velocitycareerlabs.impl.data.repositories.HeaderKeys
import io.velocitycareerlabs.impl.data.repositories.HeaderValues
Expand All @@ -28,17 +28,17 @@ internal class VCLKeyServiceRemoteImpl(
private val keyServiceUrls: VCLKeyServiceUrls
) : VCLKeyService {
override fun generateDidJwk(
remoteCryptoServicesToken: VCLToken?,
didJwkDescriptor: VCLDidJwkDescriptor,
completionBlock: (VCLResult<VCLDidJwk>) -> Unit
) {
networkService.sendRequest(
endpoint = keyServiceUrls.createDidKeyServiceUrl,
body = generatePayloadToCreateDidJwk().toString(),
body = generatePayloadToCreateDidJwk(didJwkDescriptor.signatureAlgorithm).toString(),
contentType = Request.ContentTypeApplicationJson,
method = Request.HttpMethod.POST,
headers = listOf(
Pair(HeaderKeys.XVnfProtocolVersion, HeaderValues.XVnfProtocolVersion),
Pair(HeaderKeys.Authorization, "${HeaderKeys.Bearer} ${remoteCryptoServicesToken?.value}")
Pair(HeaderKeys.Authorization, "${HeaderKeys.Bearer} ${didJwkDescriptor.remoteCryptoServicesToken?.value}")
),
completionBlock = { didJwkResult ->
didJwkResult.handleResult(
Expand Down Expand Up @@ -74,9 +74,11 @@ internal class VCLKeyServiceRemoteImpl(
)
}

private fun generatePayloadToCreateDidJwk(): JSONObject {
private fun generatePayloadToCreateDidJwk(
signatureAlgorithm: VCLSignatureAlgorithm
): JSONObject {
val retVal = JSONObject()
retVal.putOpt(CodingKeys.KeyCrv, GlobalConfig.SignatureAlgorithm.curve)
retVal.putOpt(CodingKeys.KeyCrv, signatureAlgorithm.curve)
return retVal
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* Created by Michael Avoyan on 08/02/2024.
*
* Copyright 2022 Velocity Career Labs inc.
* SPDX-License-Identifier: Apache-2.0
*/

package io.velocitycareerlabs

import io.velocitycareerlabs.api.VCLSignatureAlgorithm
import org.junit.Test

class VCLSignatureAlgorithmTest {
@Test
fun fromStringTest() {
assert(VCLSignatureAlgorithm.fromString(value = "P-256") == VCLSignatureAlgorithm.ES256)
assert(VCLSignatureAlgorithm.fromString(value = "secp256k1") == VCLSignatureAlgorithm.SECP256k1)
assert(VCLSignatureAlgorithm.fromString(value = "") == VCLSignatureAlgorithm.SECP256k1)
assert(VCLSignatureAlgorithm.fromString(value = "wrong alg") == VCLSignatureAlgorithm.SECP256k1)
}
}
Loading

0 comments on commit 3c6ff37

Please sign in to comment.