Skip to content

Commit

Permalink
Include the 'x5c' header claim in issued SD-JWT-VCs only when the con…
Browse files Browse the repository at this point in the history
…figured Signing Key has a Certificate that contains the Issuer as a SAN DNS name or SAN URI. (#252)
  • Loading branch information
dzarras authored Nov 25, 2024
1 parent abd357b commit e058610
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ import com.nimbusds.jose.JWSAlgorithm
import com.nimbusds.jose.jwk.Curve
import com.nimbusds.jose.jwk.ECKey
import com.nimbusds.jose.util.X509CertChainUtils
import com.nimbusds.jose.util.X509CertUtils
import id.walt.mdoc.COSECryptoProviderKeyInfo
import id.walt.mdoc.SimpleCOSECryptoProvider
import java.security.cert.X509Certificate

@JvmInline
value class IssuerSigningKey(val key: ECKey) {
Expand Down Expand Up @@ -62,3 +64,6 @@ internal fun IssuerSigningKey.cryptoProvider(): SimpleCOSECryptoProvider {
),
)
}

internal val IssuerSigningKey.certificate: X509Certificate
get() = X509CertUtils.parse(key.x509CertChain.first().decode())
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,24 @@ import com.nimbusds.jose.jwk.ECKey
import com.nimbusds.jose.jwk.JWK
import com.nimbusds.jwt.SignedJWT
import eu.europa.ec.eudi.pidissuer.adapter.out.IssuerSigningKey
import eu.europa.ec.eudi.pidissuer.adapter.out.certificate
import eu.europa.ec.eudi.pidissuer.adapter.out.oauth.*
import eu.europa.ec.eudi.pidissuer.adapter.out.signingAlgorithm
import eu.europa.ec.eudi.pidissuer.domain.CredentialIssuerId
import eu.europa.ec.eudi.pidissuer.domain.SdJwtVcType
import eu.europa.ec.eudi.pidissuer.port.input.IssueCredentialError
import eu.europa.ec.eudi.pidissuer.port.input.IssueCredentialError.Unexpected
import eu.europa.ec.eudi.sdjwt.*
import eu.europa.ec.eudi.sdjwt.vc.sanOfDNSName
import eu.europa.ec.eudi.sdjwt.vc.sanOfUniformResourceIdentifier
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.add
import kotlinx.serialization.json.buildJsonArray
import org.slf4j.LoggerFactory
import java.net.URL
import java.security.cert.X509Certificate
import java.time.Clock
import java.time.Instant
import java.time.ZonedDateTime
Expand Down Expand Up @@ -65,11 +70,20 @@ class EncodePidInSdJwtVc(
// SD-JWT VC requires no decoys
val sdJwtFactory = SdJwtFactory(hashAlgorithm = hashAlgorithm, fallbackMinimumDigests = null)
val signer = ECDSASigner(issuerSigningKey.key)
val x509CertChain = run {
val certificate = issuerSigningKey.certificate
if (certificate.containsSanUri(credentialIssuerId.value) || certificate.containsSanDns(credentialIssuerId.value)) {
issuerSigningKey.key.x509CertChain
} else {
null
}
}

SdJwtIssuer.nimbus(sdJwtFactory, signer, issuerSigningKey.signingAlgorithm) {
// TODO: This will change to dc+sd-jwt in a future release
type(JOSEObjectType("vc+sd-jwt"))
keyID(issuerSigningKey.key.keyID)
x509CertChain(issuerSigningKey.key.x509CertChain)
x509CertChain(x509CertChain)
}
}

Expand Down Expand Up @@ -220,3 +234,9 @@ private object Printer {
return str
}
}

private fun X509Certificate.containsSanDns(url: URL): Boolean =
url.host in sanOfDNSName().getOrDefault(emptyList())

private fun X509Certificate.containsSanUri(url: URL): Boolean =
url.toExternalForm() in sanOfUniformResourceIdentifier().getOrDefault(emptyList())

0 comments on commit e058610

Please sign in to comment.