diff --git a/cpa-repo/src/main/kotlin/no/nav/emottak/cpa/App.kt b/cpa-repo/src/main/kotlin/no/nav/emottak/cpa/App.kt index 0955da2c..22832c80 100644 --- a/cpa-repo/src/main/kotlin/no/nav/emottak/cpa/App.kt +++ b/cpa-repo/src/main/kotlin/no/nav/emottak/cpa/App.kt @@ -38,22 +38,24 @@ fun Application.myApplicationModule() { call.respond(HttpStatusCode.OK,ValidationResult(true)) } - get("/cpa/{$CPA_ID}/her/{$HER_ID}/encryption/certificate") { + get("/cpa/{$CPA_ID}/party/{$PARTY_TYPE}/{$PARTY_ID}encryption/certificate") { val cpaId = call.parameters[CPA_ID] ?: throw BadRequestException("Mangler $CPA_ID") - val herId = call.parameters[HER_ID] ?: throw BadRequestException("Mangler $HER_ID") + val partyType = call.parameters[PARTY_TYPE] ?: throw BadRequestException("Mangler $PARTY_TYPE") + val partyId = call.parameters[PARTY_ID] ?: throw BadRequestException("Mangler $PARTY_ID") val cpa = getCpa(cpaId) ?: throw NotFoundException("Ingen CPA med ID $cpaId funnet") - val partyInfo = cpa.getHERPartyInfo(herId) + val partyInfo = cpa.getPartyInfoByTypeAndID(partyType, partyId) call.respond(partyInfo.getCertificateForEncryption()) } - get("/cpa/{$CPA_ID}/her/{$HER_ID}/signing/certificate/{$ROLE}/{$SERVICE}/{$ACTION}/") { + get("/cpa/{$CPA_ID}/party/{$PARTY_TYPE}/{$PARTY_ID}/signing/certificate/{$ROLE}/{$SERVICE}/{$ACTION}") { val cpaId = call.parameters[CPA_ID] ?: throw BadRequestException("Mangler $CPA_ID") - val herId = call.parameters[HER_ID] ?: throw BadRequestException("Mangler $HER_ID") + val partyType = call.parameters[PARTY_TYPE] ?: throw BadRequestException("Mangler $PARTY_TYPE") + val partyId = call.parameters[PARTY_ID] ?: throw BadRequestException("Mangler $PARTY_ID") val role = call.parameters[ROLE] ?: throw BadRequestException("Mangler $ROLE") val service = call.parameters[SERVICE] ?: throw BadRequestException("Mangler $SERVICE") val action = call.parameters[ACTION] ?: throw BadRequestException("Mangler $ACTION") val cpa = getCpa(cpaId) ?: throw NotFoundException("Ingen CPA med ID $cpaId funnet") - val partyInfo = cpa.getHERPartyInfo(herId) + val partyInfo = cpa.getPartyInfoByTypeAndID(partyType, partyId) call.respond(partyInfo.getCertificateForSignatureValidation(role, service, action)) } @@ -61,7 +63,8 @@ fun Application.myApplicationModule() { } private const val CPA_ID = "cpaId" -private const val HER_ID = "herId" +private const val PARTY_TYPE = "partyType" +private const val PARTY_ID = "partyId" private const val ROLE = "role" private const val SERVICE = "service" private const val ACTION = "action" diff --git a/cpa-repo/src/main/kotlin/no/nav/emottak/cpa/CPAUtil.kt b/cpa-repo/src/main/kotlin/no/nav/emottak/cpa/CPAUtil.kt index 1b3f9ce7..b4d468cd 100644 --- a/cpa-repo/src/main/kotlin/no/nav/emottak/cpa/CPAUtil.kt +++ b/cpa-repo/src/main/kotlin/no/nav/emottak/cpa/CPAUtil.kt @@ -104,13 +104,13 @@ fun DeliveryChannel.getHashFunction(): String throw BadRequestException("Hash Function eksisterer ikke for DeliveryChannel") } -fun CollaborationProtocolAgreement.getHERPartyInfo(herId: String): PartyInfo +fun CollaborationProtocolAgreement.getPartyInfoByTypeAndID(partyType: String, partyId: String): PartyInfo { return this.partyInfo.firstOrNull { partyInfo -> - partyInfo.partyId.any { partyId -> - partyId.type == "HER" && partyId.value == herId + partyInfo.partyId.any { party -> + party.type == partyType && party.value == partyId } - } ?: throw NotFoundException("HER ID $herId eksisterer ikke i CPA") + } ?: throw NotFoundException("PartyID med type $partyType og id $partyId eksisterer ikke i CPA") } fun Certificate.getX509Certificate(): ByteArray { diff --git a/ebms-provider/src/main/kotlin/no/nav/emottak/ebms/HttpClientUtil.kt b/ebms-provider/src/main/kotlin/no/nav/emottak/ebms/HttpClientUtil.kt index 744cc683..2b5e56d5 100644 --- a/ebms-provider/src/main/kotlin/no/nav/emottak/ebms/HttpClientUtil.kt +++ b/ebms-provider/src/main/kotlin/no/nav/emottak/ebms/HttpClientUtil.kt @@ -15,37 +15,24 @@ import no.nav.emottak.melding.model.PayloadRequest import no.nav.emottak.melding.model.PayloadResponse import no.nav.emottak.melding.model.SignatureDetails import no.nav.emottak.melding.model.ValidationResult -import no.nav.emottak.util.createX509Certificate -import no.nav.emottak.util.decodeBase64 -import org.apache.xml.security.algorithms.MessageDigestAlgorithm -import org.apache.xml.security.signature.XMLSignature import org.oasis_open.committees.ebxml_msg.schema.msg_header_2_0.MessageHeader -import java.security.cert.X509Certificate private val httpClientUtil = HttpClientUtil() private const val payloadProcessorEndpoint = "http://payload-processor/payload" -private const val validatorEndpoint = "https://cpa-repo.intern.dev.nav.no/validate" +private const val cpaRepoEndpoint = "http://cpa-repo" +private const val validatorEndpoint = "$cpaRepoEndpoint/validate" fun postPayloadRequest(payloadRequest: PayloadRequest): PayloadResponse = runBlocking { httpClientUtil.postPayloadRequest(payloadRequest) } - -fun SignatureDetails.getPublicSigningCertificate(): X509Certificate { - return createX509Certificate(this.certificate) +fun getPublicSigningDetails(messageHeader: MessageHeader): SignatureDetails = runBlocking { + getPublicSigningDetails(messageHeader.cpaId, messageHeader.from.partyId[0].type, messageHeader.from.partyId[0].value, messageHeader.service.value, messageHeader.action, messageHeader.from.role) } -fun MessageHeader.getPublicSigningDetails(): SignatureDetails { - //TODO hent og valider sertifikat - val cert = decodeBase64("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".toByteArray()) - //val timestamp = messageHeader.messageData.timestamp - //SecurityUtils.validateCertificate(trustStore, certificate, timestamp) - return SignatureDetails( - certificate = cert, - signatureAlgorithm = XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256, - hashFunction = MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA256 - ) +suspend fun getPublicSigningDetails(cpaId: String, partyType: String, partyId: String, service: String, action: String, role: String): SignatureDetails { + return httpClientUtil.makeHttpRequest("/cpa/$cpaId/party/$partyType/$partyId/signing/certificate/$role/$service/$action").body() } class HttpClientUtil { diff --git a/ebms-provider/src/main/kotlin/no/nav/emottak/ebms/model/EbMSDocument.kt b/ebms-provider/src/main/kotlin/no/nav/emottak/ebms/model/EbMSDocument.kt index 22047c86..507858f4 100644 --- a/ebms-provider/src/main/kotlin/no/nav/emottak/ebms/model/EbMSDocument.kt +++ b/ebms-provider/src/main/kotlin/no/nav/emottak/ebms/model/EbMSDocument.kt @@ -15,7 +15,7 @@ */ package no.nav.emottak.ebms.model -import no.nav.emottak.ebms.processing.SignatursjekkProcessor +import no.nav.emottak.ebms.processing.SignaturValidator import no.nav.emottak.ebms.xml.xmlMarshaller import no.nav.emottak.melding.model.SignatureDetails import no.nav.emottak.util.marker @@ -48,7 +48,7 @@ enum class DokumentType { } fun EbMSDocument.sjekkSignature(signatureDetails: SignatureDetails) { - SignatursjekkProcessor().validate(signatureDetails, this.dokument, this.attachments) + SignaturValidator().validate(signatureDetails, this.dokument, this.attachments) } @@ -67,13 +67,9 @@ fun EbMSDocument.buildEbmMessage(): EbMSBaseMessage { } } -fun EbMSDocument.checkSignature(signatureDetails: SignatureDetails, dokument: Document, attachments: List) { - SignatursjekkProcessor().validate(signatureDetails, dokument, attachments) -} - fun EbMSDocument.sendResponse(messageHeader: MessageHeader) { log.info(messageHeader.marker(), "TODO return response message") } fun EbMSDocument.sendErrorResponse(messageHeader: MessageHeader) { - log.error(messageHeader.marker(), "TODO return response message") + log.warn(messageHeader.marker(), "TODO return error response message") } \ No newline at end of file diff --git a/ebms-provider/src/main/kotlin/no/nav/emottak/ebms/model/EbmsAcknowledgment.kt b/ebms-provider/src/main/kotlin/no/nav/emottak/ebms/model/EbmsAcknowledgment.kt index 23d8213d..4830585e 100644 --- a/ebms-provider/src/main/kotlin/no/nav/emottak/ebms/model/EbmsAcknowledgment.kt +++ b/ebms-provider/src/main/kotlin/no/nav/emottak/ebms/model/EbmsAcknowledgment.kt @@ -1,8 +1,9 @@ package no.nav.emottak.ebms.model +import no.nav.emottak.ebms.getPublicSigningDetails import no.nav.emottak.ebms.processing.CPAValidationProcessor import no.nav.emottak.ebms.processing.SertifikatsjekkProcessor -import no.nav.emottak.ebms.processing.SignatursjekkProcessor +import no.nav.emottak.ebms.processing.SignaturValidator import no.nav.emottak.ebms.processing.signer import no.nav.emottak.ebms.xml.xmlMarshaller import no.nav.emottak.util.marker @@ -25,14 +26,15 @@ class EbmsAcknowledgment(override val messageHeader: MessageHeader, SertifikatsjekkProcessor(this) ) .forEach { it.processWithEvents() } - + val signatureDetails = getPublicSigningDetails(messageHeader) + SignaturValidator().validate(signatureDetails, this.dokument!!, emptyList()) }catch (ex: Exception) { return } } fun toEbmsDokument(): EbMSDocument { - log.info(this.messageHeader.marker(), "Oppretter Acknowledgment soap response") + log.info(this.messageHeader.marker(), "Oppretter Acknowledgment") return ObjectFactory().createEnvelope()!!.also { it.header = Header().also { it.any.add(this.messageHeader) @@ -41,8 +43,9 @@ class EbmsAcknowledgment(override val messageHeader: MessageHeader, }.let { xmlMarshaller.marshal(it) }.let { - log.info(this.messageHeader.marker(), "Signerer Acknowledgment soap response") - EbMSDocument("contentID",it, emptyList()).signer(this.messageHeader) + log.info(this.messageHeader.marker(), "Signerer Acknowledgment (TODO)") + val signatureDetails = getPublicSigningDetails(this.messageHeader) + EbMSDocument("contentID",it, emptyList()).signer(signatureDetails) } } diff --git a/ebms-provider/src/main/kotlin/no/nav/emottak/ebms/model/EbmsMessageError.kt b/ebms-provider/src/main/kotlin/no/nav/emottak/ebms/model/EbmsMessageError.kt index 23e41275..23b576e8 100644 --- a/ebms-provider/src/main/kotlin/no/nav/emottak/ebms/model/EbmsMessageError.kt +++ b/ebms-provider/src/main/kotlin/no/nav/emottak/ebms/model/EbmsMessageError.kt @@ -1,13 +1,14 @@ package no.nav.emottak.ebms.model +import no.nav.emottak.ebms.getPublicSigningDetails import no.nav.emottak.ebms.processing.CPAValidationProcessor import no.nav.emottak.ebms.processing.SertifikatsjekkProcessor -import no.nav.emottak.ebms.processing.SignatursjekkProcessor +import no.nav.emottak.ebms.processing.SignaturValidator import no.nav.emottak.ebms.processing.signer import no.nav.emottak.ebms.xml.xmlMarshaller +import no.nav.emottak.util.marker import org.oasis_open.committees.ebxml_msg.schema.msg_header_2_0.ErrorList import org.oasis_open.committees.ebxml_msg.schema.msg_header_2_0.MessageHeader -import org.w3._2000._09.xmldsig_.SignatureType import org.w3c.dom.Document import org.xmlsoap.schemas.soap.envelope.Header import org.xmlsoap.schemas.soap.envelope.ObjectFactory @@ -23,15 +24,18 @@ class EbMSMessageError( try { listOf( CPAValidationProcessor(this), - SertifikatsjekkProcessor(this), + SertifikatsjekkProcessor(this) ) .forEach { it.processWithEvents() } + val signatureDetails = getPublicSigningDetails(messageHeader) + SignaturValidator().validate(signatureDetails, this.dokument!!, emptyList()) }catch (ex: Exception) { return } } fun toEbmsDokument(): EbMSDocument { + log.warn(this.messageHeader.marker(), "Oppretter ErrorList") return ObjectFactory().createEnvelope()!!.also { it.header = Header().also { it.any.add(this.messageHeader) @@ -40,7 +44,9 @@ class EbMSMessageError( }.let { xmlMarshaller.marshal(it) }.let { - EbMSDocument("contentID",it, emptyList()).signer(this.messageHeader) + log.info(this.messageHeader.marker(), "Signerer ErrorList (TODO)") + val signatureDetails = getPublicSigningDetails(this.messageHeader) + EbMSDocument("contentID",it, emptyList()).signer(signatureDetails) } } diff --git a/ebms-provider/src/main/kotlin/no/nav/emottak/ebms/processing/SignaturGenerator.kt b/ebms-provider/src/main/kotlin/no/nav/emottak/ebms/processing/SignaturGenerator.kt index da690847..ff12e32b 100644 --- a/ebms-provider/src/main/kotlin/no/nav/emottak/ebms/processing/SignaturGenerator.kt +++ b/ebms-provider/src/main/kotlin/no/nav/emottak/ebms/processing/SignaturGenerator.kt @@ -2,21 +2,20 @@ package no.nav.emottak.ebms.processing import no.nav.emottak.ebms.model.EbMSDocument import no.nav.emottak.ebms.xml.EbMSSigning +import no.nav.emottak.melding.model.SignatureDetails import no.nav.emottak.util.marker import no.nav.emottak.util.signatur.SignatureException import org.apache.xml.security.exceptions.XMLSecurityException -import org.oasis_open.committees.ebxml_msg.schema.msg_header_2_0.MessageHeader import org.slf4j.LoggerFactory private val ebMSSigning = EbMSSigning() val log = LoggerFactory.getLogger("no.nav.emottak.ebms.processing") -fun EbMSDocument.signer(messageHeader: MessageHeader): EbMSDocument { +fun EbMSDocument.signer(signatureDetails: SignatureDetails): EbMSDocument { try { - //TODO Do something with signed document - ebMSSigning.sign(this.dokument, messageHeader, this.attachments) + ebMSSigning.sign(this, signatureDetails) return this } catch (e: XMLSecurityException) { - log.error(messageHeader.marker(), "Signering av ebms envelope feilet", e) + log.error(this.messageHeader().marker(), "Signering av ebms envelope feilet", e) throw SignatureException("Signering av ebms envelope feilet", e) } } diff --git a/ebms-provider/src/main/kotlin/no/nav/emottak/ebms/processing/SignatursjekkProcessor.kt b/ebms-provider/src/main/kotlin/no/nav/emottak/ebms/processing/SignaturValidator.kt similarity index 86% rename from ebms-provider/src/main/kotlin/no/nav/emottak/ebms/processing/SignatursjekkProcessor.kt rename to ebms-provider/src/main/kotlin/no/nav/emottak/ebms/processing/SignaturValidator.kt index f8dcdc88..c09237e1 100644 --- a/ebms-provider/src/main/kotlin/no/nav/emottak/ebms/processing/SignatursjekkProcessor.kt +++ b/ebms-provider/src/main/kotlin/no/nav/emottak/ebms/processing/SignaturValidator.kt @@ -1,10 +1,6 @@ package no.nav.emottak.ebms.processing -import no.nav.emottak.ebms.getPublicSigningCertificate import no.nav.emottak.ebms.model.EbMSAttachment -import no.nav.emottak.ebms.model.EbMSBaseMessage -import no.nav.emottak.ebms.model.EbMSDocument -import no.nav.emottak.ebms.model.EbMSPayloadMessage import no.nav.emottak.ebms.validation.CID_PREFIX import no.nav.emottak.ebms.validation.EbMSAttachmentResolver import no.nav.emottak.melding.model.SignatureDetails @@ -19,7 +15,6 @@ import org.apache.xml.security.signature.SignedInfo import org.apache.xml.security.signature.XMLSignature import org.apache.xml.security.transforms.Transforms import org.apache.xml.security.utils.Constants -import org.oasis_open.committees.ebxml_msg.schema.msg_header_2_0.MessageHeader import org.w3c.dom.Document import java.security.cert.X509Certificate @@ -31,22 +26,22 @@ import java.security.cert.X509Certificate * Mangler: 104 (sertifikatsjekk), 105 (sertifikatsjekk) //TODO * */ -class SignatursjekkProcessor() { +class SignaturValidator() { init { org.apache.xml.security.Init.init() } @Throws(SignatureException::class) - public fun validate(signatureDetails: SignatureDetails, dokument: Document, attachments: List) { + fun validate(signatureDetails: SignatureDetails, dokument: Document, attachments: List) { //TODO Sjekk isNonRepudiation? - val xmlSignature = retrieveSignatureElement(dokument) - val certificateFraCPA = signatureDetails.getPublicSigningCertificate() - val certificateFraSignatur = xmlSignature.retrievePublicX509Certificate() - if (certificateFraSignatur != certificateFraCPA) throw SignatureException("Signert med annet sertifikat enn definert i CPA") + val xmlSignature = dokument.retrieveSignatureElement() + val sertfikatFraCPA = signatureDetails.retrievePublicX509Certificate() + val sertifikatFraSignatur = xmlSignature.retrievePublicX509Certificate() + if (sertifikatFraSignatur != sertfikatFraCPA) throw SignatureException("Signert med annet sertifikat enn definert i CPA") try { if (!verify( - certificateFraSignatur, + sertifikatFraSignatur, xmlSignature, attachments ) diff --git a/ebms-provider/src/main/kotlin/no/nav/emottak/ebms/validation/DokumentValidator.kt b/ebms-provider/src/main/kotlin/no/nav/emottak/ebms/validation/DokumentValidator.kt index 9b81fea9..ca046957 100644 --- a/ebms-provider/src/main/kotlin/no/nav/emottak/ebms/validation/DokumentValidator.kt +++ b/ebms-provider/src/main/kotlin/no/nav/emottak/ebms/validation/DokumentValidator.kt @@ -17,7 +17,7 @@ class DokumentValidator { fun validate(dokument: EbMSDocument) { val messageHeader = dokument.messageHeader() - val signaturedetails: SignatureDetails = messageHeader.getPublicSigningDetails() + val signaturedetails: SignatureDetails = getPublicSigningDetails(messageHeader) val header = Header(messageHeader.messageData.messageId, messageHeader.conversationId, messageHeader.cpaId, @@ -30,9 +30,5 @@ class DokumentValidator { } dokument.sjekkSignature(signaturedetails) - - - - } } \ No newline at end of file diff --git a/ebms-provider/src/main/kotlin/no/nav/emottak/ebms/xml/EbMSSigning.kt b/ebms-provider/src/main/kotlin/no/nav/emottak/ebms/xml/EbMSSigning.kt index 5ef170fd..a0050074 100644 --- a/ebms-provider/src/main/kotlin/no/nav/emottak/ebms/xml/EbMSSigning.kt +++ b/ebms-provider/src/main/kotlin/no/nav/emottak/ebms/xml/EbMSSigning.kt @@ -1,10 +1,11 @@ package no.nav.emottak.ebms.xml import jakarta.xml.soap.SOAPConstants -import no.nav.emottak.ebms.getPublicSigningDetails import no.nav.emottak.ebms.model.EbMSAttachment +import no.nav.emottak.ebms.model.EbMSDocument import no.nav.emottak.ebms.validation.CID_PREFIX import no.nav.emottak.ebms.validation.EbMSAttachmentResolver +import no.nav.emottak.melding.model.SignatureDetails import no.nav.emottak.util.createX509Certificate import no.nav.emottak.util.crypto.getCertificateAlias import no.nav.emottak.util.crypto.getKeyPair @@ -14,7 +15,6 @@ import org.apache.xml.security.exceptions.XMLSecurityException import org.apache.xml.security.signature.XMLSignature import org.apache.xml.security.transforms.Transforms import org.apache.xml.security.transforms.params.XPathContainer -import org.oasis_open.committees.ebxml_msg.schema.msg_header_2_0.MessageHeader import org.w3c.dom.Document import org.w3c.dom.NodeList import java.security.cert.X509Certificate @@ -25,14 +25,13 @@ class EbMSSigning { private val SOAP_ENVELOPE = SOAPConstants.URI_NS_SOAP_1_1_ENVELOPE private val SOAP_NEXT_ACTOR = SOAPConstants.URI_SOAP_ACTOR_NEXT - fun sign(document: Document, messageHeader: MessageHeader, attachments: List = emptyList()) { - val certificateDetails = messageHeader.getPublicSigningDetails() + fun sign(ebMSDocument: EbMSDocument, signatureDetails: SignatureDetails) { sign( - document, - attachments, - createX509Certificate(certificateDetails.certificate), - certificateDetails.signatureAlgorithm, - certificateDetails.hashFunction + ebMSDocument.dokument, + ebMSDocument.attachments, + createX509Certificate(signatureDetails.certificate), + signatureDetails.signatureAlgorithm, + signatureDetails.hashFunction ) } diff --git a/ebms-provider/src/test/kotlin/no/nav/emottak/ebms/processing/SignatursjekkProcessorTest.kt b/ebms-provider/src/test/kotlin/no/nav/emottak/ebms/processing/SignatursjekkProcessorTest.kt deleted file mode 100644 index f427f254..00000000 --- a/ebms-provider/src/test/kotlin/no/nav/emottak/ebms/processing/SignatursjekkProcessorTest.kt +++ /dev/null @@ -1,53 +0,0 @@ -package no.nav.emottak.ebms.processing - -import no.nav.emottak.ebms.getPublicSigningDetails -import no.nav.emottak.ebms.model.EbMSAttachment -import no.nav.emottak.ebms.model.EbMSDocument -import no.nav.emottak.ebms.model.buildEbmMessage -import no.nav.emottak.ebms.xml.getDocumentBuilder -import no.nav.emottak.melding.model.SignatureDetails -import no.nav.emottak.util.signatur.SignatureException -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertThrows - -class SignatursjekkProcessorTest { - @Test - fun `Validering av signatur`() { - - val dokument = getDocumentBuilder().parse(this::class.java.classLoader - .getResourceAsStream("oppgjørsmelding/2023_08_29T12_56_58_328.xml")) - val attachment = this::class.java.classLoader - .getResourceAsStream("oppgjørsmelding/2023_08_29T12_56_58_328.p7m").readAllBytes() - val ebMSDocument = EbMSDocument( - "Test", - dokument, - listOf( - EbMSAttachment( - attachment, - "application/pkcs7-mime", - "3CTGI8UKUKU4.ADHEUDMDCY3Q3@speare.no" - ) - ) - ) - val signatureDetails: SignatureDetails = ebMSDocument.messageHeader().getPublicSigningDetails() - val signatursjekk = SignatursjekkProcessor().validate(signatureDetails,dokument,ebMSDocument.attachments) - } - - @Test - fun `Validering av signatur uten attachments feiler`() { - - val dokument = getDocumentBuilder().parse(this::class.java.classLoader - .getResourceAsStream("oppgjørsmelding/2023_08_29T12_56_58_328.xml")) - val ebMSDocument = EbMSDocument( - "Test", - dokument, - listOf() - ) - val signatureDetails: SignatureDetails = ebMSDocument.messageHeader().getPublicSigningDetails() - - val signatursjekk = SignatursjekkProcessor() - assertThrows { - signatursjekk.validate(signatureDetails,dokument,ebMSDocument.attachments) - } - } -} \ No newline at end of file diff --git a/ebms-provider/src/test/kotlin/no/nav/emottak/ebms/processing/SignaturvalidatorTest.kt b/ebms-provider/src/test/kotlin/no/nav/emottak/ebms/processing/SignaturvalidatorTest.kt new file mode 100644 index 00000000..03e7b7e2 --- /dev/null +++ b/ebms-provider/src/test/kotlin/no/nav/emottak/ebms/processing/SignaturvalidatorTest.kt @@ -0,0 +1,59 @@ +package no.nav.emottak.ebms.processing + +import no.nav.emottak.ebms.model.EbMSAttachment +import no.nav.emottak.ebms.model.EbMSDocument +import no.nav.emottak.ebms.xml.getDocumentBuilder +import no.nav.emottak.melding.model.SignatureDetails +import no.nav.emottak.util.decodeBase64 +import no.nav.emottak.util.signatur.SignatureException +import org.apache.xml.security.algorithms.MessageDigestAlgorithm +import org.apache.xml.security.signature.XMLSignature +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows + +class SignaturvalidatorTest { + @Test + fun `Validering av signatur`() { + + val dokument = getDocumentBuilder().parse(this::class.java.classLoader + .getResourceAsStream("oppgjørsmelding/2023_08_29T12_56_58_328.xml")) + val attachment = this::class.java.classLoader + .getResourceAsStream("oppgjørsmelding/2023_08_29T12_56_58_328.p7m").readAllBytes() + val ebMSDocument = EbMSDocument( + "Test", + dokument, + listOf( + EbMSAttachment( + attachment, + "application/pkcs7-mime", + "3CTGI8UKUKU4.ADHEUDMDCY3Q3@speare.no" + ) + ) + ) + SignaturValidator().validate(getSignatureDetailsForTest(),dokument,ebMSDocument.attachments) + } + + @Test + fun `Validering av signatur uten attachments feiler`() { + + val dokument = getDocumentBuilder().parse(this::class.java.classLoader + .getResourceAsStream("oppgjørsmelding/2023_08_29T12_56_58_328.xml")) + val ebMSDocument = EbMSDocument( + "Test", + dokument, + listOf() + ) + + val signatursjekk = SignaturValidator() + assertThrows { + signatursjekk.validate(getSignatureDetailsForTest(),dokument,ebMSDocument.attachments) + } + } +} + +fun getSignatureDetailsForTest(): SignatureDetails = + SignatureDetails( + certificate = decodeBase64("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".toByteArray()), + signatureAlgorithm = XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256, + hashFunction = MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA256 + ) \ No newline at end of file diff --git a/felles/src/main/kotlin/no/nav/emottak/util/XMLUtil.kt b/felles/src/main/kotlin/no/nav/emottak/util/XMLUtil.kt index 1f60c8c8..6916484a 100644 --- a/felles/src/main/kotlin/no/nav/emottak/util/XMLUtil.kt +++ b/felles/src/main/kotlin/no/nav/emottak/util/XMLUtil.kt @@ -1,5 +1,6 @@ package no.nav.emottak.util +import no.nav.emottak.melding.model.SignatureDetails import no.nav.emottak.util.signatur.SignatureException import org.apache.xml.security.signature.XMLSignature import org.apache.xml.security.utils.Constants @@ -15,14 +16,18 @@ import javax.xml.transform.TransformerFactory import javax.xml.transform.dom.DOMSource import javax.xml.transform.stream.StreamResult -fun retrieveSignatureElement(document: Document): XMLSignature { - val nodeList: NodeList = document.getElementsByTagNameNS(Constants.SignatureSpecNS, Constants._TAG_SIGNATURE) +fun Document.retrieveSignatureElement(): XMLSignature { + val nodeList: NodeList = this.getElementsByTagNameNS(Constants.SignatureSpecNS, Constants._TAG_SIGNATURE) //Regel ID 45, 52 if (nodeList.length != 1) throw SignatureException("${nodeList.length} signaturer i dokumentet! Skal være nøyaktig 1") //Regel ID 363, 42, 32 return XMLSignature(nodeList.item(0) as Element, Constants.SignatureSpecNS) } +fun SignatureDetails.retrievePublicX509Certificate(): X509Certificate { + return createX509Certificate(this.certificate) +} + fun XMLSignature.retrievePublicX509Certificate(): X509Certificate { return this.keyInfo.x509Certificate } diff --git a/felles/src/main/kotlin/no/nav/emottak/util/signatur/SignaturVerifisering.kt b/felles/src/main/kotlin/no/nav/emottak/util/signatur/SignaturVerifisering.kt index d6a904d4..c0888c44 100644 --- a/felles/src/main/kotlin/no/nav/emottak/util/signatur/SignaturVerifisering.kt +++ b/felles/src/main/kotlin/no/nav/emottak/util/signatur/SignaturVerifisering.kt @@ -11,7 +11,8 @@ class SignaturVerifisering { @Throws(SignatureException::class) fun validate(document: ByteArray) { //TODO Sjekk isNonRepudiation? - val signature = retrieveSignatureElement(createDocument(ByteArrayInputStream(document))) + val dom = createDocument(ByteArrayInputStream(document)) + val signature = dom.retrieveSignatureElement() val certificateFromSignature = signature.keyInfo.x509Certificate try {