Skip to content

Commit

Permalink
Add properties to allow configuring the key used to sign metadata.
Browse files Browse the repository at this point in the history
  • Loading branch information
dzarras committed Feb 25, 2025
1 parent 3303d8b commit c8c65c5
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 20 deletions.
37 changes: 31 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,28 +212,53 @@ Description: URI to use when generating Credential Offers.
Default value: `openid-credential-offer://`

Variable: `ISSUER_SIGNING_KEY`
Description: Whether to generate a new, or use an existing key-pair for signing.
Description: Whether to generate a new, or use an existing key-pair for signing verifiable credentials.
Possible values: `GenerateRandom`, `LoadFromKeystore`
Default value: `GenerateRandom`

Variable: `ISSUER_SIGNING_KEY_KEYSTORE`
Description: Location of the keystore from which to load the key-pair for signing. Uses Spring Resource URL syntax.
Description: Location of the keystore from which to load the key-pair for signing verifiable credentials. Uses Spring Resource URL syntax.
Default value: N/A

Variable: `ISSUER_SIGNING_KEY_KEYSTORE_TYPE`
Description: Type of the keystore from which to load the key-pair for signing.
Description: Type of the keystore from which to load the key-pair for signing verifiable credentials.
Default value: N/A

Variable: `ISSUER_SIGNING_KEY_KEYSTORE_PASSWORD`
Description: Password of the keystore from which to load the key-pair for signing.
Description: Password of the keystore from which to load the key-pair for signing verifiable credentials.
Default value: N/A

Variable: `ISSUER_SIGNING_KEY_ALIAS`
Description: Alias of the key-pair for signing.
Description: Alias of the key-pair for signing verifiable credentials.
Default value: N/A

Variable: `ISSUER_SIGNING_KEY_PASSWORD`
Description: Password of the key-pair for signing.
Description: Password of the key-pair for signing verifiable credentials.
Default value: N/A

Variable: `ISSUER_METADATA_SIGNING_KEY`
Description: Whether to generate a new, or use an existing key-pair for signing metadata.
Possible values: `GenerateRandom`, `LoadFromKeystore`
Default value: `GenerateRandom`

Variable: `ISSUER_METADATA_SIGNING_KEY_KEYSTORE`
Description: Location of the keystore from which to load the key-pair for signing metadata. Uses Spring Resource URL syntax.
Default value: N/A

Variable: `ISSUER_METADATA_SIGNING_KEY_KEYSTORE_TYPE`
Description: Type of the keystore from which to load the key-pair for signing metadata.
Default value: N/A

Variable: `ISSUER_METADATA_SIGNING_KEY_KEYSTORE_PASSWORD`
Description: Password of the keystore from which to load the key-pair for signing metadata.
Default value: N/A

Variable: `ISSUER_METADATA_SIGNING_KEY_ALIAS`
Description: Alias of the key-pair for signing metadata.
Default value: N/A

Variable: `ISSUER_METADATA_SIGNING_KEY_PASSWORD`
Description: Password of the key-pair for signing metadata.
Default value: N/A

Variable: `ISSUER_KEYCLOAK_SERVER_URL`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,26 @@ fun beans(clock: Clock) = beans {
encryptionKey
}

//
// Signed metadata signing key
//
bean(name = "metadata-signing-key") {
when (env.getProperty<KeyOption>("issuer.metadata.signing-key")) {
null, KeyOption.GenerateRandom -> {
log.info("Generating random signing key for metadata")
ECKeyGenerator(Curve.P_256)
.keyID("issuer-kid-1")
.keyUse(KeyUse.SIGNATURE)
.generate()
}

KeyOption.LoadFromKeystore -> {
log.info("Loading signing key and certificate for metadata from keystore")
loadJwkFromKeystore(env, "issuer.metadata.signing-key")
}
}
}

//
// Adapters (out ports)
//
Expand Down Expand Up @@ -349,7 +369,7 @@ fun beans(clock: Clock) = beans {
GenerateSignedMetadataWithNimbus(
clock = ref(),
credentialIssuerId = ref<CredentialIssuerMetaData>().id,
signingKey = ref(),
signingKey = ref(name = "metadata-signing-key"),
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,17 @@
*/
package eu.europa.ec.eudi.pidissuer.adapter.out.jose

import com.nimbusds.jose.JWSHeader
import com.nimbusds.jose.JWSObject
import com.nimbusds.jose.JWSSigner
import com.nimbusds.jose.Payload
import com.nimbusds.jose.*
import com.nimbusds.jose.crypto.ECDSASigner
import com.nimbusds.jose.crypto.Ed25519Signer
import com.nimbusds.jose.crypto.RSASSASigner
import com.nimbusds.jose.jwk.*
import com.nimbusds.jose.util.JSONObjectUtils
import eu.europa.ec.eudi.pidissuer.adapter.out.IssuerSigningKey
import eu.europa.ec.eudi.pidissuer.adapter.out.signingAlgorithm
import eu.europa.ec.eudi.pidissuer.domain.CredentialIssuerId
import eu.europa.ec.eudi.pidissuer.port.out.jose.GenerateSignedMetadata
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.*
import org.bouncycastle.jce.provider.BouncyCastleProvider
import java.time.Clock

/**
Expand All @@ -35,8 +34,12 @@ import java.time.Clock
internal class GenerateSignedMetadataWithNimbus(
private val clock: Clock,
private val credentialIssuerId: CredentialIssuerId,
private val signingKey: IssuerSigningKey,
private val signingKey: JWK,
) : GenerateSignedMetadata {
init {
require(signingKey is AsymmetricJWK) { "only asymmetric keys are supported" }
require(signingKey.isPrivate) { "a private key is required for signing metadata" }
}

override fun invoke(metadata: JsonObject): String {
val payload = (metadata - "signed_metadata").buildUpon {
Expand All @@ -60,12 +63,39 @@ private fun Map<String, JsonElement>.buildUpon(builder: JsonObjectBuilder.() ->

private fun JsonObject.toPayload(): Payload = Payload(JSONObjectUtils.parse(Json.encodeToString(this)))

private val IssuerSigningKey.jwsHeader: JWSHeader
private val JWK.signingAlgorithm: JWSAlgorithm
get() = when (this) {
is ECKey -> when (curve) {
Curve.P_256 -> JWSAlgorithm.ES256
Curve.P_256K, Curve.SECP256K1 -> JWSAlgorithm.ES256K
Curve.P_384 -> JWSAlgorithm.ES384
Curve.P_521 -> JWSAlgorithm.ES512
else -> error("unsupported curve '$curve' for ECKey")
}
is RSAKey -> JWSAlgorithm.RS256
is OctetKeyPair -> when (curve) {
Curve.Ed25519 -> JWSAlgorithm.Ed25519
else -> error("unsupported curve '$curve' for OctetKeyPair")
}
else -> error("unsupported key type '$javaClass'")
}

private val JWK.jwsHeader: JWSHeader
get() = JWSHeader.Builder(signingAlgorithm)
.jwk(key.toPublicJWK())
.keyID(key.keyID)
.x509CertChain(key.x509CertChain)
.jwk(toPublicJWK())
.keyID(keyID)
.x509CertChain(x509CertChain)
.build()

private val IssuerSigningKey.jwsSigner: JWSSigner
get() = ECDSASigner(key)
private val JWK.jwsSigner: JWSSigner
get() = when (this) {
is ECKey -> ECDSASigner(this)
.apply {
if (Curve.P_256K == curve || Curve.SECP256K1 == curve) {
jcaContext.provider = BouncyCastleProvider()
}
}
is RSAKey -> RSASSASigner(this)
is OctetKeyPair -> Ed25519Signer(this)
else -> error("unsupported key type '$javaClass'")
}
6 changes: 6 additions & 0 deletions src/main/resources/application-keystore.properties
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,9 @@ issuer.signing-key.keystore.type=JKS
issuer.signing-key.keystore.password=sd-jwt
issuer.signing-key.alias=sd-jwt-issuance
issuer.signing-key.password=sd-jwt-issuance
issuer.metadata.signing-key=LoadFromKeystore
issuer.metadata.signing-key.keystore=classpath:sd-jwt.jks
issuer.metadata.signing-key.keystore.type=JKS
issuer.metadata.signing-key.keystore.password=sd-jwt
issuer.metadata.signing-key.alias=sd-jwt-issuance
issuer.metadata.signing-key.password=sd-jwt-issuance
1 change: 1 addition & 0 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ issuer.dpop.nonce.enabled=false
issuer.dpop.nonce.expiration=PT5M
issuer.credentialEndpoint.batchIssuance.enabled=true
issuer.credentialEndpoint.batchIssuance.batchSize=10
issuer.metadata.signing-key=GenerateRandom
issuer.metadata.display[0].name=Digital Credentials Issuer
issuer.metadata.display[0].locale=en
issuer.metadata.display[0].logo.uri=https://eudiw.dev/ic-logo.svg
Expand Down

0 comments on commit c8c65c5

Please sign in to comment.