Parakstīšanas prasības

Nozīmīga papildus informācija

  • Ar JWS specifikāciju var iepazīties šeit.

  • Ar JSON objekta veidošanu par iepazīties šeit.

  • Base64URL kodēšanas specifika ir aprakstīta šeit.

  • X-provenace galvenas laukā provenaces profilam atbilstošajos datos nepieciešams obligāti norādī provenaces profilu!

    Piemērs:

{
    "meta": {
        "profile": [
            "https://vvis.gov.lv/fhir/StructureDefinition/Provenance/SignatureProvenance-v1"
        ]
    }
    <<<Biznesa dati>>>
}

  • .Net provenaces un paraksta izveidošanas piemērs aprakstīts zemāk.

Provenaces profils

NVD FHIR API nodrošina, ka atgriezto datu struktūra atbilst paraksta provinaces porfilam profilam Provenance for signed request validations:

idΣ0..1id
metaΣ0..1Meta
implicitRulesΣ ?!0..1uri
language0..1codeBinding
text0..1Narrative
containedI0..*Resource
extensionI0..*Extension
modifierExtension?! I0..*Extension
id0..1id
extensionI0..*Extension
referenceΣ I0..1string
typeΣ1..1uriBinding
identifierΣ0..0Identifier
displayΣ0..0string
recordedΣ1..1instant
policy0..0uri
locationI0..0Reference(Location)
id0..1id
extensionI0..*Extension
id0..1id
extensionI0..*Extension
systemΣ1..1uriFixed Value
versionΣ0..0string
codeΣ1..1codeFixed Value
displayΣ1..1stringFixed Value
userSelectedΣ0..0boolean
textΣ0..0string
id0..1id
extensionI0..*Extension
modifierExtensionΣ ?! I0..*Extension
id0..1id
extensionI0..*Extension
id0..1id
extensionI0..*Extension
systemΣ1..1uriFixed Value
versionΣ0..0string
codeΣ1..1codeFixed Value
displayΣ1..1stringFixed Value
userSelectedΣ0..0boolean
textΣ0..0string
id0..1id
extensionI0..*Extension
referenceΣ I1..1string
typeΣ0..0uriBinding
displayΣ0..0string
id0..1id
extensionI0..*Extension
referenceΣ I1..1string
typeΣ0..0uriBinding
identifierΣ0..0Identifier
displayΣ0..0string
id0..1id
extensionI0..*Extension
id0..1id
extensionI0..*Extension
systemΣ1..1uriFixed Value
versionΣ0..0string
codeΣ1..1codeFixed Value
displayΣ1..1stringFixed Value
userSelectedΣ0..0boolean
whenΣ1..1instant
id0..1id
extensionI0..*Extension
referenceΣ I1..1string
typeΣ0..0uriBinding
identifierΣ0..0Identifier
displayΣ0..0string
id0..1id
extensionI0..*Extension
referenceΣ I1..1string
typeΣ0..0uriBinding
identifierΣ0..0Identifier
displayΣ0..0string
targetFormat1..1codeBindingFixed Value
sigFormat1..1codeBindingFixed Value
data1..1base64Binary

📝 Papildus: "Provenance" resursa validācijas:

  1. Lauka "Provenance.agent.who.reference" vērtībai jābūt vienādai ar lauka "Provenance.signature.who.reference" vērtību – abos laukos tiek sagaidīts vienmēr iestādes identifikators no FHIR
  2. Lauka "Provenance.agent.onBehalfOf.reference" vērtībai jābūt vienādai ar lauka "Provenance.signature.onBehalfOf.reference" vērtību – Ja laukos "Provenance.signature.onBehalfOf" un "Provenance.agent.onBehalfOf" norādiet resursu:
    • "PractitionerRole", tad abos laukos "Provenance.agent.onBehalfOf.reference" un "Provenance.signature.onBehalfOf.reference" tiek sagaidīts ĀP darba vietas (2.37 klasifikators) identifikators no FHIR;
    • "Organization", tad abos laukos "Provenance.agent.onBehalfOf.reference" un "Provenance.signature.onBehalfOf.reference" tiek sagaidīts Iestādes (2.23 klasifikators) identifikators no FHIR;
    • "Patient", tad abos laukos "Provenance.agent.onBehalfOf.reference" un "Provenance.signature.onBehalfOf.reference" tiek sagaidīts Pacienta identifikators no FHIR;
    • "Practitioner", tad abos laukos "Provenance.agent.onBehalfOf.reference" un "Provenance.signature.onBehalfOf.reference" tiek sagaidīts ĀP (2.1 klasifikators) identifikators no FHIR;
  3. Norādītajiem references resursu datiem ir jāsakrīt ar pieprasījuma sūtīšanā izmantotā JWT talona datiem - Ja laukos "Provenance.signature.onBehalfOf" un "Provenance.agent.onBehalfOf" norādiet resursu:
    • "PractitionerRole", tad JWT talona "sub" lauka vērtībai (tiek paņemts ĀP darba vietas kods) ir jāsakrīt ar ĀP darba vietas kodu, kas tiek iegūts no FHIR pēc norādīto lauku "Provenance.agent.onBehalfOf.reference" un "Provenance.signature.onBehalfOf.reference" identifikatora vērtībām;
    • "Organization", tad JWT talona "VIAuthorityCode" kodam ir jāsakrīt ar Iestādes VI kodu, kas tiek iegūts no FHIR pēc norādīto lauku "Provenance.agent.onBehalfOf.reference" un "Provenance.signature.onBehalfOf.reference" identifikatora vērtībām;
    • "Patient", tad JWT talona "privatePersonalIdentifier" kodam ir jāsakrīt ar Pacienta personas kodu, kas tiek iegūts no FHIR pēc norādīto lauku "Provenance.agent.onBehalfOf.reference" un "Provenance.signature.onBehalfOf.reference" identifikatora vērtībām;
    • "Practitioner", tad JWT talona "VIMedicalCode" kodam ir jāsakrīt ar ĀP VI kodu, kas tiek iegūts no FHIR pēc norādīto lauku "Provenance.agent.onBehalfOf.reference" un "Provenance.signature.onBehalfOf.reference" identifikatora vērtībām;

Pieprasījuma izveide un parakstīšana

LAB IS FHIR API reģistrācijas vai labošanas pieprasījumiem ir sekojoša struktūra: RequestStructure Veidojot pieprasījumu LAB IS FHIR API, tā saturiskā informācija ir jāparaksta, lai nodrošinātu tās uzticamību un izvairītos no ziņojumu viltošanas.

Ar saturisko informāciju saprotam pieprasījuma Body daļas informāciju.

Vispārējā informācija par sniedzamo datu parakstīšanu

Parakstīšana ir nepieciešama nenoliedzamības prasību izpildes nodrošināšanai.

  1. Datu parakstīšana ir obligāta CREATE un UPDATE operācijām LAB IS (izņemot gadījumus, kur pierasījumā tiek strādāts ar paceita resursu "Patient").
  2. LAB IS sistēmas galapunkti, kuru izmantošana paredz datu parakstīšanu:
  • POST pieprasījumi {Host}/fhir/api/{resouce};
  • PUT, PATCH pieprasījumi {Host}/fhir/api/{resouce}/{resouce system id}.
  1. Parakstīšanā tiek izmantots JWS standarts, kura formāts ir: {JWS_Header}.{JWS_Payload}.{JWS_Signature}:
  • kur {JWS_Header} ietver tehnisko informāciju par parakstu. Sadaļa ir kodēta BASE64URL formātā;
  • kur {JWS_Payload} ir pati parakstāmā daļa (biznesa/pieprasījuma dati), kodēta BASE64URL formātā. JWS Payload netiek pievienots saskaņā ar Detached content prasību;
  • kur {JWS_Signature} ir paraksts, kas tika izmantots {JWS_Header} un {JWS_Payload} parakstīšanai, kodēts BASE64URL formātā.
  1. Apstrādājot JSON datus JWS paraksta ietvaros datu formatējums ir vienmēr “minified”.

Pieprasījuma izveides process

  1. Izveido pieprasījuma JSON struktūru UTF8 kodējumā ar unescaped simboliem.
  2. Izveido JWS Header JSON struktūru. Struktūra satur parametrus, kuri apraksta izmantoto šifrēšanas pieeju.

Prasības pret šo struktūru:

  1. struktūrai jābūt pareizam JSON objektam (skat. https://datatracker.ietf.org/doc/html/rfc7159) “minified” formatējumā;
  2. JSON objektam jābūt UTF-8 kodējumā ar unescaped simboliem;
  3. struktūras parametri:

Lauks Kardinalitāte Apraksts Komentāri
alg 1..1 Kriptogrāfisks algoritms, kurš tika izmantots paraksta veidošanā Sagaidāma vērtība “RS256”. Case-sensitive ASCII string.
keys[] 1..1 Informācija par publisko atslēgu, kas atbilst atslēgai, kura tika izmantota parakstīšanā JSON objekts
keys[].kty 1..1 Atslēgas tips, apraksta kriptogrāfisko algoritmu saimi Sagaidāma vērtība “RSA”. Case-sensitive string.
keys[].use 1..1 Pielietojuma parametrs, apraksta publiskās atslēgas mērķa pielietojumu. Sagaidāma vērtība "sig" – (signature). Case-sensitive string.
keys[].x5t 1..1 Publiskās atslēgas thumbprint Publiskās atslēgas thumbprint vērtība Base64url kodējumā.
keys[].e 1..1 RSA publiskās atslēgas parametrs exponent e Sagaidāma RSA publiskās atslēgas "e" (exponent) parametra vērtība Base64urlUInt kodējumā.
keys[].n 1..1 RSA publiskās atslēgas parametrs modulus n Sagaidāma RSA publiskās atslēgas "n" (modulus) parametra vērtība Base64urlUInt kodējumā.
sig_type 1..1 Paraksta tipa apraksts JSON objekts.
sig_type.system 1..1 HL7 klasifikators "Parakstu tipi" Sagaidāma vērtība “urn:iso-astm:E1762-95:2013”.
sig_type.code 1..1 Klasifikatora kods Sagaidāma vērtība “1.2.840.10065.1.12.1.1”.
sig_type.display 1..1 Klasifikatora koda nosaukums Sagaidāma vērtība “Author's Signature”. Case-sensitive string.

Piemērta JWS header struktūra ar reducētiem sertifikāta datiem

{
    "alg": "RS256",
    "keys": [
        {
            "e": "",
            "kty": "RSA",
            "n": "",
            "use": "sig",
            "x5t": ""
        }
    ],
    "sig_type": {
        "code": "1.2.840.10065.1.12.1.1",
        "display": "Author's Signature",
        "system": "urn:iso-astm:E1762-95:2013"
    }
}


  1. JWS Header struktūra tiek pārkodēta uz Base64URL.
  1. Izveido JSON struktūru, kura būs jāparaksta (JWS Payload):
  1. Struktūrai jābūt valīdam JSON (skat. https://datatracker.ietf.org/doc/html/rfc7159) “minified” formatējumā;
  2. JSON jābūt UTF-8 kodējumā ar unescaped simboliem;
  3. JSON pieprasījuma Body ir vienīgie dati kuri tiek iekļaujami JWS Payload.
  4. Šādi izveidoto JSON dokumentu kodē Base64URL.

Lai izvairītos no satura pārsūtīšanas dubultā apjomā, JWS Payload struktūra nav paredzēta pārsūtīšanai, tā tiks izmantota tālākiem aprēķiniem.

  1. Izveido JWS Signature struktūru:
  1. Apvieno struktūras JWS Header un JWS Payload, atdalot tos ar punktu

ASCII( BASE64URL(JWS Header) || ‘.’ || BASE64URL(JWS Payload) )

Datiem ir jābūt ASCII kodējumā.

  1. Apvienoto Base64URL stringu hašo ar SHA256 algoritmu.
  2. Hash funkcijas rezultāts (hash summa) tiek parakstīts (šifrēts) izmantojot RSA asimetriskās kriptogrāfijas algoritmu (kas tiek definēts JWS Header parametrā "alg") ar padding " RSASSA-PKCS1-v1_5", kur kā parakstīšanas atslēga tiek izmantota pieprasījuma sūtītāja sertifikāta privātā atslēga.
  3. Iegūtos parakstītos datus kodē Base64URL.
  1. Daļas tiek savienotas kopā sekojošā struktūrā

BASE64URL(JWS Header) || ‘.’ || ‘ ’ || ‘.’ || BASE64URL(JWS Signature)

  1. JWS Payload netiek pievienots atbilstoši JWS dokumentācijai (https://www.rfc-editor.org/rfc/rfc7515.html#appendix-F) detached content prasības dēļ.

“Detached content” norāda, ka, sūtot pieprasījumu, paraksta datos netiek iekļauts parakstītais pieprasījuma JWS Payload.

Paraksta formātā {JWS_Header}.{JWS_Payload}.{JWS_Signature}" formāta daļa tiek aizstāta ar tukšu string, lai izvairītos no satura pārsūtīšanas dubultā apjomā.


  1. Iegūtā struktūra jānokodē uz Base64.
  2. Iepriekšējā punktā iegūtais string ievieto Provenance resursa objektā Provenance.Signature.Data (http://hl7.org/fhir/R4B/datatypes.html#Signature)
  1. Sagatavoto pieprasījumu nosūta FHIR API
  1. Pieprasījuma Body daļai ir jāatbilst definētajam resursu izsaukuma profilam un jāsatur visa nepieciešamā biznesa informācija.
  2. Pieprasījuma Header laukā “X-Provenance” ir jāievieto paraksta Provenance profilam atbilstošajā JSON objektā, ieskaitot iepriekšējā punkta c. apakšpunktā pieminētā string vērtība.

Piemēra pierasījuma json ko paraksta

{
    "resourceType": "DiagnosticReport",
    "meta": {
        "profile": [
            "https://lab.vvis.gov.lv/fhir/StructureDefinition/DiagnosticReport/LaboratoryReport-v1"
        ]
    },
    "identifier": {
            "assigner": {
            "reference": "Organization/01H0JKDZ1FFX0YQ408ZRDRA1VF/_history/1",
            "type": "Organization"
        },
        "value": "Pārskats 1.1.1."
    },
    "basedOn": {
        "type": "ServiceRequest",
        "display": "EGL"
    },
    "status": "preliminary",
    "category": [
        {
            "coding": {
                "system": "https://vvis.gov.lv/fhir/ValueSet/1.3.6.1.4.1.38760.2.801",
                "code": "CG",
                "display": "Citoģenētika"
            }
        },
        {
            "coding": {
                "system": "https://vvis.gov.lv/fhir/ValueSet/1.3.6.1.4.1.38760.2.801",
                "code": "BLB",
                "display": "Asins banka"
            }
        }
    ],
    "code": {
        "coding": {
            "system": "https://vvis.gov.lv/fhir/ValueSet/1.3.6.1.4.1.38760.2.805",
            "code": "LAB",
            "display": "Laboratorisko rezultātu pārskats"
        }
    },
    "subject": {
        "reference": "Patient/01GZX3V188FWEDYME2PDRC4B5W",
        "type": "Patient"
    },
    "effectivePeriod": {
        "start": "2023-09-10T01:25:43.511Z",
        "end": "2023-09-10T01:25:43.511Z"
    },
    "issued": "2023-06-15T01:25:43.511Z",
    "performer": {
        "reference": "Organization/01H0JKDZ1FFX0YQ408ZRDRA1VF/_history/1",
        "type": "Organization"
    },
    "resultsInterpreter": {
        "reference": "PractitionerRole/01H0N8DZYBDG0SBMVBRENZSWHQ/_history/13",
        "type": "PractitionerRole"
    },
    "conclusion": "Mērijumu nenoteiktības, testēšanas metodes un privātuma politika mājas lapā: www.egl.lv. Testēšanas rezultāti attiecas tikai uz konkrētajiem testēšanas objektiem.Testēšanas pārskats pārbaudīts elektroniski un ir derīgs bez ārsta paraksta.",
    "conclusionCode": {
        "coding": {
            "system": "https://vvis.gov.lv/fhir/ValueSet/1.3.6.1.4.1.38760.2.806",
            "code": "critical",
            "display": "Kristisks"
        }
    },
    "presentedForm": [
        {
            "contentType": "application/pdf",
            "url": "Binary/01H8XS4MCAHBVD4854X49YPJ7C/_history/1",
            "size": "12000",
            "title": "Rezultātu pārskata PDF"
        }
    ]
}

Piemēra provenaces json, kas satur praksta informāciju (lasāmības nolūkiem formatēts pretty-print)

{
    "activity": {
        "coding": [
            {
                "code": "LA",
                "display": "legally authenticated",
                "system": "http://terminology.hl7.org/CodeSystem/v3-DocumentCompletion"
            }
        ]
    },
    "agent": [
        {
            "onBehalfOf": {
                "reference": "Organization/01H0JKDZ1FPQN126V7CJ1MXVZ2"
            },
            "type": {
                "coding": [
                    {
                        "code": "author",
                        "display": "Author",
                        "system": "http://terminology.hl7.org/CodeSystem/provenance-participant-type"
                    }
                ]
            },
            "who": {
                "reference": "Organization/01H0JKDZ1FPQN126V7CJ1MXVZ2"
            }
        }
    ],
    "meta": {
        "profile": [
            "https://vvis.gov.lv/fhir/StructureDefinition/Provenance/SignatureProvenance-v1"
        ]
    },
    "recorded": "2024-01-12T07:23:35.0645358+00:00",
    "resourceType": "Provenance",
    "signature": [
        {
            "data": "ZXlKaGJHY2lPaUpTVXpJMU5pSXNJbXRsZVhNaU9sdDdJbXQwZVNJNklsSlRRU0lzSW5WelpTSTZJbk5wWnlJc0luZzFkQ0k2SWpJNVlVSmplRGR1VG1wWFpERkxlRFV0TWs1bmVUaHZNR2h0V1NJc0ltVWlPaUpCVVVGQ0lpd2liaUk2SW1wV1ZGUkxUVTAxZVc1VWRIQkdUMVJGU0RSMGVsVjFURTluVEVaeFRHRk5Wbk50TFhSTVZITXRWVVpxZERKdU9VOXBSVWRFVTBaMlEyOWxPRkEwUkhSQ1kyRTJXVEJFZWpOaVJsZExUMFJUZVZKVU9DMVdWMWxFYUhwWVdUWmxjR1ZTTWxaYWJEVnhZbE4yVDJWSGNVNXFZWG8zWXpsRU1HbFpka1JCUjFOYVkxaGFTbFUxZEUxb04zUjFZakJQV1ZSb05ISjROVGd3TWtKMlVWTmFjMmN6VVhoT2RuVk1OR2RGZGpjNFpUZG9XR0l0ZEc5UllWbHJjVEZrWldSemNGUkVaRkp4ZG1oM2REQlRWSGhTYTJSd01GRmpPRTlKWVc5SVh6SlJUR2xZWWxWcGVFY3RkM1JNUmtaaGJsRnZVbE50V0RSSVkyRXljamswUlROR1pYbFJYMmwyUkZoNlgzWjZNekJEYmxCR2NYQTBabUV5Wm5kTlZrUnJRMDVHTnpGWlZqaGlTRFZOT1doRWIyZHhTakJNTVUxZlpFdEdaMlI1Y2t0TlVVNVdhSGx3TWpWVVFtbDFibDlvZDJoRGFHSTNabDh4VjJneGQySnpXa1YzTkVSS05URlpNV1V0Y0hwbWQzbG9abTkzVVRCM2VtZDBWRFIyUkV0eldXNHhaSGhMV1RWaGExTkJjVEZmWVVGMGNtd3RPVWhRY0RGSloxSnJNR1ZSVHkxU2ExVkpkRTU2VDFsc1gzQlNTMVpvUWxCR1FucFJNbk5KWldkcWFVOWpOa1ZMYVROQk1HTnJOM2hUYUROSWNUYzBOalZLVjFRM2JHeGxXbEk0YW5wRFNuQnZSa2N0TXkxWlozRnRSM3BtY0hCM2VIQnhjMHQ2VlVGYWVUSnlUVmhVT1RCNlgxUklOV3h6V1UxTmNYQXllQzAyYTBscE1EZzJiRVIxZVZvd0xUZFBPVWhqVkRKcVVuVTBSRGxVVGpoaVR5MWpkekp6V2xvM2Rub3pPV3RJU1hoeE1uUnViR1Z4V25KV2JXNUpZWE5FVWpaUGJsaEViV2hMVDNZdGVVSjZSM0ZIVkRGSWRFY3lWa2gxVEVNeE1IbzBRWEp5Vm1KWU1ESkNSVkZ2VkZKbmJFWlpWMTg1WDJKTVdGODBlVzVSUkU1WGNFNVdZbDlKU1RaMVh6bEhaV050T0dSUmFEQk1Ua3BySW4xZExDSnphV2RmZEhsd1pTSTZleUp6ZVhOMFpXMGlPaUoxY200NmFYTnZMV0Z6ZEcwNlJURTNOakl0T1RVNk1qQXhNeUlzSW1OdlpHVWlPaUl4TGpJdU9EUXdMakV3TURZMUxqRXVNVEl1TVM0eElpd2laR2x6Y0d4aGVTSTZJa0YxZEdodmNpZHpJRk5wWjI1aGRIVnlaU0o5ZlEuLlczenp6eUJKS1FodkFiZ0NTc3JhWWZ6b3l5SVFwVVZfdnJacUthS2NOSHBJaGkxaE9EdkxiNUhyQTc2cVItT2dtZm45ZkhUcGhYVlVrOEJpeVNkQ3hpS2tjcHZLZTlBUGFTeDdPWWwzZ2FOVGlRei05YnBZcU4tN1BoZ2xaV2U3X0pFTGo1M0E5VmhDMkNBMV9oNWxnZmlPNkkwWDU2Z3MxTW5HdjVQWmNCV3hnY0s1UHY2d3Y4V1Y3Nk5HRUNXbVJtaTBmbS16c25wWGl3RDJXNjhkenpJZ2RfdEk1OG5vTXl6M083b0N0LUNuU3E0RGtDTUZxSHFZM1RKZThSVlZ5T0RZM1E3Vm9tdWFwOXRQZFJySmVHRE1ra2tZMHoyelJKWkdTVGlGdk9fcHZ6ZWlDMVMyN3lSMldhbWRmWkdiV0xueG16Nnh1ZGtpbl81cDRKQ2JVWng5eUdEMEhwbk9Bak95RW9QUjdUc1hvM3dDRWZLU0hKYU5CQ002Z2FsSWVjRm9mSzlMSkQxaGd2N3ZQV0tzSVpoVTFuQ2lCbFY2SzJvYzNmelJlRm95SjBGc0drX09ZekxQUjRGdlRaNHZZeXJLNUJvSk9CU1ZIUlpFcVRJV3Y3Ty00S1g4VEN5S3dzc1d6enBYUmxELTNKQzdlQjBNYkQ1Ym05OHhKQXZtNjRxTE5YcjhZTHB2cklDM09uTGg3SXVHdkdEM0Z1dXNST2VlNHVOeXd5Vlg1dVR3Z1ZGdzFfQlZxRmRlTENXMmY5bmtGZU8xSmU2ZkZBNmJHbzRXeXluZmdxT1dkOFQ1NVhWbTQ2eWFwLVItNWFWYTBGOS1iTXlHMzBWMTEydjRjWURMc08tTnlGOHIxZlNYNzRVUTh6UkUxYV8wSHdKNDAxRTZMVDZGU1dZ",
            "onBehalfOf": {
                "reference": "Organization/01H0JKDZ1FPQN126V7CJ1MXVZ2"
            },
            "sigFormat": "application/jose",
            "targetFormat": "application/fhir+json",
            "type": [
                {
                    "code": "1.2.840.10065.1.12.1.1",
                    "display": "Author's Signature",
                    "system": "urn:iso-astm:E1762-95:2013"
                }
            ],
            "when": "2024-01-12T07:23:35.0645358+00:00",
            "who": {
                "reference": "Organization/01H0JKDZ1FPQN126V7CJ1MXVZ2"
            }
        }
    ],
    "target": [
        {
            "type": "DiagnosticReport"
        }
    ]
}


📝 Informācijai: Gadījumā, ja prasību informācija ir nesalasāma aizveriet JSON piemēra paplašinājuma skatu.

Provenance un paraksta izveidošana .NET

Lai iegūtu parakstu priekš FHIR API Provenance resursa, kuru nepieciešams iesūtīt kopā ar sistēmā reģistrējamiem datiem ir sniegts zemāk redzams piemērs .Net.

1. Nepieciešamie konfigurācijas parametri, kur:

  • Certificate - parakstītāja privātās un publiskās daļas sertifikāts X509 formātā, atbilstoši .Net izmantotās bibliotēkas specifikācijai

.Net piemērs:

using System.Security.Cryptography.X509Certificates;
public class JwsServiceConfiguration
{
    public X509Certificate2? Certificate { get; set; }
}

2. Nepieciešams izmantot metodi CreateProvenanceHeader, kur:

  • resourceType - FHIR resursa tips, piemēram, Binary, DiagnosticReport, utt.
  • payload - iesūtāmo datu body daļa
  • who - atsauce uz FHIR reģistrētu ārstniecības iestādi, piemēram, Organization/01H0JGAZN40TAN0TCMWSXD9PEQ
  • behalfOf - attiecībā no situācijas jānorāda atsauce uz FHIR reģistrētu ārstniecības personu vai ārstniecības personas darba vietu, piemēram, Practitioner/ABH0JGAZN40TAN0TCMWSXD9PCD, PractitionerRole/BCH0JGAZN40TAN0TCMWSXD9PEF
  • time - parakstīšanas datums un laiks

.Net piemērs:

using Hl7.Fhir.Model;
using Hl7.Fhir.Serialization;
using Jose;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;

public class JwsService
{
    private readonly ILogger<JwsService> _logger;
    private readonly JwsServiceConfiguration _config;
    public JwsService(ILogger<JwsService> logger, JwsServiceConfiguration config)
    {
        _logger = logger;
        _config = config;
    }

	
    public string CreateProvenanceHeader(string resourceType, string payload, string who, string behalfOf, DateTime? time = null)
    {
        return CreateProvenance(resourceType, payload, who, behalfOf, time);
    }

    private string CreateProvenance(string resourceType, string payload, string who, string behalfOf, DateTime? time = null)
    {
        var date = time ?? DateTime.Now;

        var provenance = new Provenance
        {
            Meta = new Meta
            {
                Profile = new[] { "https://vvis.gov.lv/fhir/StructureDefinition/Provenance/SignatureProvenance-v1" }
            },
            Target = new List<ResourceReference>
            {
                new() { Type = resourceType }
            },
            Recorded = new DateTimeOffset(date),
            Activity = new CodeableConcept
            {
                Coding = new List<Coding>
                {
                    new()
                    {
                        System = "http://terminology.hl7.org/CodeSystem/v3-DocumentCompletion",
                        Code = "LA",
                        Display = "legally authenticated"
                    }
                }
            },
            Agent = new List<Provenance.AgentComponent>
            {
                new()
                {
                    Type = new CodeableConcept
                    {
                        Coding = new List<Coding>
                        {
                            new()
                            {
                                System = "http://terminology.hl7.org/CodeSystem/provenance-participant-type",
                                Code = "author",
                                Display = "Author"
                            }
                        }
                    },
                    Who = new ResourceReference { Reference = who },
                    OnBehalfOf = new ResourceReference { Reference = behalfOf }
                }
            },
            Signature = new List<Signature>
            {
                new()
                {
                    Type = new List<Coding>
                    {
                        new()
                        {
                            System = "urn:iso-astm:E1762-95:2013",
                            Code = "1.2.840.10065.1.12.1.1",
                            Display = "Author's Signature"
                        }
                    },
                    When = new DateTimeOffset(date),
                    Who = new ResourceReference { Reference = who },
                    OnBehalfOf = new ResourceReference { Reference = behalfOf },
                    TargetFormat = "application/fhir+json",
                    SigFormat = "application/jose",
                    Data = Encoding.UTF8.GetBytes(Sign(payload))
                }
            }
        };

        return provenance.ToJson();
    }

    public string Sign(string payload)
    {
        payload = Minify(payload);
        var privateKey = _config.Certificate.GetRSAPrivateKey();
        var rsaParams = privateKey.ExportParameters(false);

        var modulus = Base64UrlEncode(rsaParams.Modulus);
        var publicExponent = Base64UrlEncode(rsaParams.Exponent);
        var x5t = Base64UrlEncode(_config.Certificate.GetCertHash(HashAlgorithmName.SHA1));

        var jwsHeaders = new Dictionary<string, object>
        {
            { "alg", "RS256" },
            { "keys", new JwsKey[] { new("RSA", "sig", x5t, publicExponent, modulus) } },
            { "sig_type", new SigType("urn:iso-astm:E1762-95:2013", "1.2.840.10065.1.12.1.1", "Author's Signature") }
        };

        return JWT.Encode(
            payload,
            privateKey,
            JwsAlgorithm.RS256,
            extraHeaders: jwsHeaders,
            options: new JwtOptions { DetachPayload = true }
        );
    }

    private static string Minify(string json)
    {
        var options =
            new JsonWriterOptions
            {
                Indented = false,
                Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
            };
        using var document = JsonDocument.Parse(json);
        using var stream = new MemoryStream();
        using var writer = new Utf8JsonWriter(stream, options);
        document.WriteTo(writer);
        writer.Flush();
        return Encoding.UTF8.GetString(stream.ToArray());
    }
}

public record JwsKey(string Kty, string Use, string X5t, string E, string N);
public record SigType(string System, string Code, string Display);