{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "This is a Jupyter Notebook which uses openSSL, Python 3.7, and the Python jcs and jose libraries to create a JSON Web Signature (JWS)(see RFC 7515), attach it to a FHIR Bundle and validate it. Its source code be found [here](https://github.com/HL7/davinci-ecdx/blob/master/CDEX-Signatures/Digsig_Document_Bundle_Example.ipynb)\n", "\n", "*Although self-signed certificates are used for the purpose of these examples, they are not recommended for production systems.*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Sender/Signer Steps" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**1. Generate RSA256 public and private keys for signing the bundle**\n", "\n", "*DO THIS STEP ONLY ONCE*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**2. Create a self-signed certificate for authenticating the signer**\n", "\n", "create the public and private keys and X.509 self-signed certificate for authenticating the signer using the openSSL command line tool.\n", "\n", "1. pre-configure the self-signed cert with a configuration file\n", "\n", "~~~\n", "[req]\n", "default_bit = 4096\n", "distinguished_name = req_distinguished_name\n", "prompt = no\n", "x509_extensions = v3_ca\n", "\n", "# Subject details\n", "[req_distinguished_name]\n", "countryName = US\n", "stateOrProvinceName = Massachusetts\n", "localityName = Boston\n", "organizationName = Example Organization\n", "commonName = CDEX Example Organization\n", "emailAddress = customer-service@example.org\n", "\n", "[v3_ca]\n", "basicConstraints = CA:FALSE\n", "keyUsage=nonRepudiation, digitalSignature, keyEncipherment\n", "# 1.2.840.113549.1.9.16.2.47 = ASN1:SEQUENCE:commitment_type # custom extensio\n", "\n", "# SAN extension\n", "subjectAltName = @alt_names\n", "\n", "# SAN entries for FHIR and NPI\n", "[alt_names]\n", "DNS.1 = www.example.org\n", "otherName.1 = 2.16.840.1.113883.4.6;UTF8:1234567893\n", "URI.1 = https://example.org/fhir/Organization/123\n", "~~~" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "2\\. generate the public and private keys and cert" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "writing RSA key\n" ] } ], "source": [ "!openssl genrsa -out private-key.pem 3072\n", "!openssl rsa -in private-key.pem -pubout -out public-key.pem\n", "!openssl req -new -x509 -key private-key.pem -outform DER -out cert.der -days 360 -config cert.config" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*For the purpose of this example display the keys (normally would never share the private key)*" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-----BEGIN PRIVATE KEY-----\n", "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\n", "2q/lprgQWdm+cxzJBhU7fD7eGQ==\n", "-----END PRIVATE KEY-----\n", "\n", "-----BEGIN PUBLIC KEY-----\n", "MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEArtyHIeEmm1Mi2iR7lRW9\n", "NPxAyS9Bh8PxE1bFKPbRo1BWdFYosDADMcxdh9juycsihFEm/t9ncBeBeLI1UuzE\n", "b/K+FW1aJnfk+aZzA21pg1z0rRj7iShpKw8f0aihzaTiaBOlSscoYDWeBy7pe5Q/\n", "eL7VRuqglZhVk7ZLSpw8xbVToFPYy2Ih56wmd4x+w4I9DSCsmiEE1wtWuZteVlge\n", "cfMsY/XzozHBTkk4Frh8Pxj/3kvYTYU52jsczAILDlpUK4ga7XGMo23QouXdFXWI\n", "8KM6XfORWCqWU+2V4B9MnjjG8jrO+OCDHQHJqBxrkMYW+GkbhBq8YOngQQH/tZ8C\n", "j8vf0ZXEQou0LWmoVNfZYuqCGDJ5Ig0lADmm+lBwtSeM9Ppjq0fVX4/u++oo36LY\n", "inwNoBAm3rQlBNI5MUwVOrrvOhiWdYvYSj3fwCkb1aKBofFqPMr3/nS+3VOLgGp7\n", "v7atCTfWG7fxf5E8vh27y1jq3FPKPY00rNws6V3QZuNXAgMBAAE=\n", "-----END PUBLIC KEY-----\n" ] } ], "source": [ "!cat private-key.pem\n", "!echo\n", "!cat public-key.pem" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Display DER Format of Certificate" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Certificate:\n", " Data:\n", " Version: 3 (0x2)\n", " Serial Number:\n", " 39:c1:6a:2c:e0:66:b7:b5:51:eb:2e:05:1a:7d:34:41:21:4c:5c:98\n", " Signature Algorithm: sha256WithRSAEncryption\n", " Issuer: C=US, ST=Massachusetts, L=Boston, O=Example Organization, CN=CDEX Example Organization, emailAddress=customer-service@example.org\n", " Validity\n", " Not Before: Jul 24 18:14:40 2025 GMT\n", " Not After : Jul 19 18:14:40 2026 GMT\n", " Subject: C=US, ST=Massachusetts, L=Boston, O=Example Organization, CN=CDEX Example Organization, emailAddress=customer-service@example.org\n", " Subject Public Key Info:\n", " Public Key Algorithm: rsaEncryption\n", " Public-Key: (3072 bit)\n", " Modulus:\n", " 00:ae:dc:87:21:e1:26:9b:53:22:da:24:7b:95:15:\n", " bd:34:fc:40:c9:2f:41:87:c3:f1:13:56:c5:28:f6:\n", " d1:a3:50:56:74:56:28:b0:30:03:31:cc:5d:87:d8:\n", " ee:c9:cb:22:84:51:26:fe:df:67:70:17:81:78:b2:\n", " 35:52:ec:c4:6f:f2:be:15:6d:5a:26:77:e4:f9:a6:\n", " 73:03:6d:69:83:5c:f4:ad:18:fb:89:28:69:2b:0f:\n", " 1f:d1:a8:a1:cd:a4:e2:68:13:a5:4a:c7:28:60:35:\n", " 9e:07:2e:e9:7b:94:3f:78:be:d5:46:ea:a0:95:98:\n", " 55:93:b6:4b:4a:9c:3c:c5:b5:53:a0:53:d8:cb:62:\n", " 21:e7:ac:26:77:8c:7e:c3:82:3d:0d:20:ac:9a:21:\n", " 04:d7:0b:56:b9:9b:5e:56:58:1e:71:f3:2c:63:f5:\n", " f3:a3:31:c1:4e:49:38:16:b8:7c:3f:18:ff:de:4b:\n", " d8:4d:85:39:da:3b:1c:cc:02:0b:0e:5a:54:2b:88:\n", " 1a:ed:71:8c:a3:6d:d0:a2:e5:dd:15:75:88:f0:a3:\n", " 3a:5d:f3:91:58:2a:96:53:ed:95:e0:1f:4c:9e:38:\n", " c6:f2:3a:ce:f8:e0:83:1d:01:c9:a8:1c:6b:90:c6:\n", " 16:f8:69:1b:84:1a:bc:60:e9:e0:41:01:ff:b5:9f:\n", " 02:8f:cb:df:d1:95:c4:42:8b:b4:2d:69:a8:54:d7:\n", " d9:62:ea:82:18:32:79:22:0d:25:00:39:a6:fa:50:\n", " 70:b5:27:8c:f4:fa:63:ab:47:d5:5f:8f:ee:fb:ea:\n", " 28:df:a2:d8:8a:7c:0d:a0:10:26:de:b4:25:04:d2:\n", " 39:31:4c:15:3a:ba:ef:3a:18:96:75:8b:d8:4a:3d:\n", " df:c0:29:1b:d5:a2:81:a1:f1:6a:3c:ca:f7:fe:74:\n", " be:dd:53:8b:80:6a:7b:bf:b6:ad:09:37:d6:1b:b7:\n", " f1:7f:91:3c:be:1d:bb:cb:58:ea:dc:53:ca:3d:8d:\n", " 34:ac:dc:2c:e9:5d:d0:66:e3:57\n", " Exponent: 65537 (0x10001)\n", " X509v3 extensions:\n", " X509v3 Basic Constraints: \n", " CA:FALSE\n", " X509v3 Key Usage: \n", " Digital Signature, Non Repudiation, Key Encipherment\n", " X509v3 Subject Alternative Name: \n", " DNS:www.example.org, othername: 2.16.840.1.113883.4.6:1234567893, URI:https://example.org/fhir/Organization/123\n", " X509v3 Subject Key Identifier: \n", " E6:EF:DB:35:0B:69:B3:69:A4:3A:E6:01:54:E1:7F:39:AC:75:EB:58\n", " Signature Algorithm: sha256WithRSAEncryption\n", " Signature Value:\n", " 18:8b:39:4d:fd:34:4c:92:cd:94:86:cf:66:8d:85:b3:33:51:\n", " 5e:51:69:3c:2b:a4:3c:43:bd:88:c3:5f:78:c4:3f:f8:ec:9a:\n", " 3e:3f:a4:df:8b:e5:16:01:5e:c0:5f:63:14:94:b9:b4:0b:79:\n", " 5b:e4:7f:97:ef:fa:81:ab:99:e0:96:f9:f5:fc:c8:4d:6b:97:\n", " ea:bc:d4:20:8b:f9:0f:0b:38:ec:c0:64:5b:84:79:81:3d:89:\n", " e7:33:63:b7:ce:d7:c3:29:17:c9:c2:d7:80:83:41:be:83:37:\n", " 5d:10:68:0b:5b:85:31:5a:91:97:8e:a9:96:94:81:3a:03:7c:\n", " 83:6c:9f:b8:f3:6b:f6:e9:b7:52:9e:bb:9b:d4:b2:ed:6a:16:\n", " 08:c0:a7:30:3a:f8:c6:a5:20:d5:24:1e:66:b6:14:af:b3:d9:\n", " 87:f2:d1:6f:cd:86:ea:5b:2d:c5:84:9f:54:72:b9:40:53:43:\n", " 0b:2c:9b:dc:11:3c:31:3f:2e:84:94:03:7a:66:9a:a3:c3:97:\n", " ce:dd:f6:d1:85:0c:af:f2:95:04:ee:6a:a9:79:b4:5d:36:96:\n", " 3c:fc:c1:84:22:49:17:f9:9f:3c:6a:4e:6b:67:30:29:af:87:\n", " 26:b1:ef:99:f9:d2:da:3f:4e:7e:25:87:f8:f5:8a:4a:3e:c0:\n", " 20:16:4c:c0:8d:91:bf:a6:e0:6d:66:b1:da:14:62:71:18:9f:\n", " f4:e2:cd:6f:6f:2b:72:e1:55:35:b9:65:d2:3e:b9:5c:9a:b1:\n", " d0:61:44:ba:32:97:06:22:75:41:82:6a:1b:c9:7c:34:86:93:\n", " 4c:52:ef:88:54:5d:bd:b6:dc:09:b3:89:22:84:dd:31:4f:c5:\n", " 29:d9:12:fd:f3:8b:c9:8e:93:3b:0c:4a:e6:e3:9e:92:6a:ae:\n", " 74:17:a0:19:cd:23:cb:3e:8f:42:32:65:0d:bd:66:67:7c:08:\n", " b2:ea:9a:09:08:39:53:ae:69:c0:a8:91:7b:ca:0d:69:14:9a:\n", " 40:72:44:ee:8b:c0\n", "-----BEGIN CERTIFICATE-----\n", "MIIFeTCCA+GgAwIBAgIUOcFqLOBmt7VR6y4FGn00QSFMXJgwDQYJKoZIhvcNAQEL\n", "BQAwgaYxCzAJBgNVBAYTAlVTMRYwFAYDVQQIDA1NYXNzYWNodXNldHRzMQ8wDQYD\n", "VQQHDAZCb3N0b24xHTAbBgNVBAoMFEV4YW1wbGUgT3JnYW5pemF0aW9uMSIwIAYD\n", "VQQDDBlDREVYIEV4YW1wbGUgT3JnYW5pemF0aW9uMSswKQYJKoZIhvcNAQkBFhxj\n", "dXN0b21lci1zZXJ2aWNlQGV4YW1wbGUub3JnMB4XDTI1MDcyNDE4MTQ0MFoXDTI2\n", "MDcxOTE4MTQ0MFowgaYxCzAJBgNVBAYTAlVTMRYwFAYDVQQIDA1NYXNzYWNodXNl\n", "dHRzMQ8wDQYDVQQHDAZCb3N0b24xHTAbBgNVBAoMFEV4YW1wbGUgT3JnYW5pemF0\n", "aW9uMSIwIAYDVQQDDBlDREVYIEV4YW1wbGUgT3JnYW5pemF0aW9uMSswKQYJKoZI\n", "hvcNAQkBFhxjdXN0b21lci1zZXJ2aWNlQGV4YW1wbGUub3JnMIIBojANBgkqhkiG\n", "9w0BAQEFAAOCAY8AMIIBigKCAYEArtyHIeEmm1Mi2iR7lRW9NPxAyS9Bh8PxE1bF\n", "KPbRo1BWdFYosDADMcxdh9juycsihFEm/t9ncBeBeLI1UuzEb/K+FW1aJnfk+aZz\n", "A21pg1z0rRj7iShpKw8f0aihzaTiaBOlSscoYDWeBy7pe5Q/eL7VRuqglZhVk7ZL\n", "Spw8xbVToFPYy2Ih56wmd4x+w4I9DSCsmiEE1wtWuZteVlgecfMsY/XzozHBTkk4\n", "Frh8Pxj/3kvYTYU52jsczAILDlpUK4ga7XGMo23QouXdFXWI8KM6XfORWCqWU+2V\n", "4B9MnjjG8jrO+OCDHQHJqBxrkMYW+GkbhBq8YOngQQH/tZ8Cj8vf0ZXEQou0LWmo\n", "VNfZYuqCGDJ5Ig0lADmm+lBwtSeM9Ppjq0fVX4/u++oo36LYinwNoBAm3rQlBNI5\n", "MUwVOrrvOhiWdYvYSj3fwCkb1aKBofFqPMr3/nS+3VOLgGp7v7atCTfWG7fxf5E8\n", "vh27y1jq3FPKPY00rNws6V3QZuNXAgMBAAGjgZwwgZkwCQYDVR0TBAIwADALBgNV\n", "HQ8EBAMCBeAwYAYDVR0RBFkwV4IPd3d3LmV4YW1wbGUub3JnoBkGCWCGSAGG+VsE\n", "BqAMDAoxMjM0NTY3ODkzhilodHRwczovL2V4YW1wbGUub3JnL2ZoaXIvT3JnYW5p\n", "emF0aW9uLzEyMzAdBgNVHQ4EFgQU5u/bNQtps2mkOuYBVOF/Oax161gwDQYJKoZI\n", "hvcNAQELBQADggGBABiLOU39NEySzZSGz2aNhbMzUV5RaTwrpDxDvYjDX3jEP/js\n", "mj4/pN+L5RYBXsBfYxSUubQLeVvkf5fv+oGrmeCW+fX8yE1rl+q81CCL+Q8LOOzA\n", "ZFuEeYE9ieczY7fO18MpF8nC14CDQb6DN10QaAtbhTFakZeOqZaUgToDfINsn7jz\n", "a/bpt1Keu5vUsu1qFgjApzA6+MalINUkHma2FK+z2Yfy0W/NhupbLcWEn1RyuUBT\n", "Qwssm9wRPDE/LoSUA3pmmqPDl87d9tGFDK/ylQTuaql5tF02ljz8wYQiSRf5nzxq\n", "TmtnMCmvhyax75n50to/Tn4lh/j1iko+wCAWTMCNkb+m4G1msdoUYnEYn/TizW9v\n", "K3LhVTW5ZdI+uVyasdBhRLoylwYidUGCahvJfDSGk0xS74hUXb223AmziSKE3TFP\n", "xSnZEv3zi8mOkzsMSubjnpJqrnQXoBnNI8s+j0IyZQ29Zmd8CLLqmgkIOVOuacCo\n", "kXvKDWkUmkByRO6LwA==\n", "-----END CERTIFICATE-----\n" ] } ], "source": [ "!openssl x509 -in cert.der -inform DER -text" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Display PEM Format of Certificate" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-----BEGIN CERTIFICATE-----\n", "MIIFeTCCA+GgAwIBAgIUOcFqLOBmt7VR6y4FGn00QSFMXJgwDQYJKoZIhvcNAQEL\n", "BQAwgaYxCzAJBgNVBAYTAlVTMRYwFAYDVQQIDA1NYXNzYWNodXNldHRzMQ8wDQYD\n", "VQQHDAZCb3N0b24xHTAbBgNVBAoMFEV4YW1wbGUgT3JnYW5pemF0aW9uMSIwIAYD\n", "VQQDDBlDREVYIEV4YW1wbGUgT3JnYW5pemF0aW9uMSswKQYJKoZIhvcNAQkBFhxj\n", "dXN0b21lci1zZXJ2aWNlQGV4YW1wbGUub3JnMB4XDTI1MDcyNDE4MTQ0MFoXDTI2\n", "MDcxOTE4MTQ0MFowgaYxCzAJBgNVBAYTAlVTMRYwFAYDVQQIDA1NYXNzYWNodXNl\n", "dHRzMQ8wDQYDVQQHDAZCb3N0b24xHTAbBgNVBAoMFEV4YW1wbGUgT3JnYW5pemF0\n", "aW9uMSIwIAYDVQQDDBlDREVYIEV4YW1wbGUgT3JnYW5pemF0aW9uMSswKQYJKoZI\n", "hvcNAQkBFhxjdXN0b21lci1zZXJ2aWNlQGV4YW1wbGUub3JnMIIBojANBgkqhkiG\n", "9w0BAQEFAAOCAY8AMIIBigKCAYEArtyHIeEmm1Mi2iR7lRW9NPxAyS9Bh8PxE1bF\n", "KPbRo1BWdFYosDADMcxdh9juycsihFEm/t9ncBeBeLI1UuzEb/K+FW1aJnfk+aZz\n", "A21pg1z0rRj7iShpKw8f0aihzaTiaBOlSscoYDWeBy7pe5Q/eL7VRuqglZhVk7ZL\n", "Spw8xbVToFPYy2Ih56wmd4x+w4I9DSCsmiEE1wtWuZteVlgecfMsY/XzozHBTkk4\n", "Frh8Pxj/3kvYTYU52jsczAILDlpUK4ga7XGMo23QouXdFXWI8KM6XfORWCqWU+2V\n", "4B9MnjjG8jrO+OCDHQHJqBxrkMYW+GkbhBq8YOngQQH/tZ8Cj8vf0ZXEQou0LWmo\n", "VNfZYuqCGDJ5Ig0lADmm+lBwtSeM9Ppjq0fVX4/u++oo36LYinwNoBAm3rQlBNI5\n", "MUwVOrrvOhiWdYvYSj3fwCkb1aKBofFqPMr3/nS+3VOLgGp7v7atCTfWG7fxf5E8\n", "vh27y1jq3FPKPY00rNws6V3QZuNXAgMBAAGjgZwwgZkwCQYDVR0TBAIwADALBgNV\n", "HQ8EBAMCBeAwYAYDVR0RBFkwV4IPd3d3LmV4YW1wbGUub3JnoBkGCWCGSAGG+VsE\n", "BqAMDAoxMjM0NTY3ODkzhilodHRwczovL2V4YW1wbGUub3JnL2ZoaXIvT3JnYW5p\n", "emF0aW9uLzEyMzAdBgNVHQ4EFgQU5u/bNQtps2mkOuYBVOF/Oax161gwDQYJKoZI\n", "hvcNAQELBQADggGBABiLOU39NEySzZSGz2aNhbMzUV5RaTwrpDxDvYjDX3jEP/js\n", "mj4/pN+L5RYBXsBfYxSUubQLeVvkf5fv+oGrmeCW+fX8yE1rl+q81CCL+Q8LOOzA\n", "ZFuEeYE9ieczY7fO18MpF8nC14CDQb6DN10QaAtbhTFakZeOqZaUgToDfINsn7jz\n", "a/bpt1Keu5vUsu1qFgjApzA6+MalINUkHma2FK+z2Yfy0W/NhupbLcWEn1RyuUBT\n", "Qwssm9wRPDE/LoSUA3pmmqPDl87d9tGFDK/ylQTuaql5tF02ljz8wYQiSRf5nzxq\n", "TmtnMCmvhyax75n50to/Tn4lh/j1iko+wCAWTMCNkb+m4G1msdoUYnEYn/TizW9v\n", "K3LhVTW5ZdI+uVyasdBhRLoylwYidUGCahvJfDSGk0xS74hUXb223AmziSKE3TFP\n", "xSnZEv3zi8mOkzsMSubjnpJqrnQXoBnNI8s+j0IyZQ29Zmd8CLLqmgkIOVOuacCo\n", "kXvKDWkUmkByRO6LwA==\n", "-----END CERTIFICATE-----\n" ] } ], "source": [ "!openssl x509 -in cert.der -inform DER -outform PEM -out cert.pem\n", "!cat cert.pem" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**3. Create JWS to Attach to Bundle**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**3.1. Prepare Header**\n", "\n", "- SHALL include an \"alg\" parameter for the JSON Web Algorithms (JWA) (see RFC 7518). \"alg\": \"RS256\" is preferred.\n", "- SHALL include a \"kty\" parameter corresponding to the cryptographic algorithm family in \"alg\" ( e.g., \"kty\": \"RSA\" for \"alg\": \"RS256\" ).\n", "- - SHALL include a \"srCms\" signer commitments.\n", "- SHALL include a \"sigT\" header parameter with a timestamp of the signature.\n", "- MAY include a \"kid\"\n", "- SHALL have \"x5c\" (X.509 certificate chain) equal to an array of one or more base64-encoded (not base64url-encoded) DER representations of the public certificate or certificate chain (see RFC 7517). The public key is listed in the first certificate in the \"x5c\" specified by the entry's \"Modulus\" and \"Exponent\" parameters.\n", "\n", " note the base64 DER is Cert PEM file wihout the footer and header and line returns\n" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "with open('cert.pem') as f:\n", " der = (f.read()) # base64 DER is PEM wihout the footer and header and line returns\n", "der = der.replace('-----BEGIN CERTIFICATE-----','')\n", "der = der.replace('-----END CERTIFICATE-----','')\n", "der = der.replace('\\n','')" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'alg': 'RS256',\n", " 'kty': 'RS',\n", " 'srCms': [{'commId': {'id': 'urn:oid:1.2.840.10065.1.12.1.5',\n", " 'desc': 'Verification Signature'},\n", " 'commQuals': ['Verification of medical record integrity']}],\n", " 'sigT': '2020-10-23T04:54:56.048+00:00',\n", " 'kid': 'bfbe3e5c0470444576548113928d5f1e4e3f2eeb',\n", " 'x5c': ['MIIFeTCCA+GgAwIBAgIUOcFqLOBmt7VR6y4FGn00QSFMXJgwDQYJKoZIhvcNAQELBQAwgaYxCzAJBgNVBAYTAlVTMRYwFAYDVQQIDA1NYXNzYWNodXNldHRzMQ8wDQYDVQQHDAZCb3N0b24xHTAbBgNVBAoMFEV4YW1wbGUgT3JnYW5pemF0aW9uMSIwIAYDVQQDDBlDREVYIEV4YW1wbGUgT3JnYW5pemF0aW9uMSswKQYJKoZIhvcNAQkBFhxjdXN0b21lci1zZXJ2aWNlQGV4YW1wbGUub3JnMB4XDTI1MDcyNDE4MTQ0MFoXDTI2MDcxOTE4MTQ0MFowgaYxCzAJBgNVBAYTAlVTMRYwFAYDVQQIDA1NYXNzYWNodXNldHRzMQ8wDQYDVQQHDAZCb3N0b24xHTAbBgNVBAoMFEV4YW1wbGUgT3JnYW5pemF0aW9uMSIwIAYDVQQDDBlDREVYIEV4YW1wbGUgT3JnYW5pemF0aW9uMSswKQYJKoZIhvcNAQkBFhxjdXN0b21lci1zZXJ2aWNlQGV4YW1wbGUub3JnMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEArtyHIeEmm1Mi2iR7lRW9NPxAyS9Bh8PxE1bFKPbRo1BWdFYosDADMcxdh9juycsihFEm/t9ncBeBeLI1UuzEb/K+FW1aJnfk+aZzA21pg1z0rRj7iShpKw8f0aihzaTiaBOlSscoYDWeBy7pe5Q/eL7VRuqglZhVk7ZLSpw8xbVToFPYy2Ih56wmd4x+w4I9DSCsmiEE1wtWuZteVlgecfMsY/XzozHBTkk4Frh8Pxj/3kvYTYU52jsczAILDlpUK4ga7XGMo23QouXdFXWI8KM6XfORWCqWU+2V4B9MnjjG8jrO+OCDHQHJqBxrkMYW+GkbhBq8YOngQQH/tZ8Cj8vf0ZXEQou0LWmoVNfZYuqCGDJ5Ig0lADmm+lBwtSeM9Ppjq0fVX4/u++oo36LYinwNoBAm3rQlBNI5MUwVOrrvOhiWdYvYSj3fwCkb1aKBofFqPMr3/nS+3VOLgGp7v7atCTfWG7fxf5E8vh27y1jq3FPKPY00rNws6V3QZuNXAgMBAAGjgZwwgZkwCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwYAYDVR0RBFkwV4IPd3d3LmV4YW1wbGUub3JnoBkGCWCGSAGG+VsEBqAMDAoxMjM0NTY3ODkzhilodHRwczovL2V4YW1wbGUub3JnL2ZoaXIvT3JnYW5pemF0aW9uLzEyMzAdBgNVHQ4EFgQU5u/bNQtps2mkOuYBVOF/Oax161gwDQYJKoZIhvcNAQELBQADggGBABiLOU39NEySzZSGz2aNhbMzUV5RaTwrpDxDvYjDX3jEP/jsmj4/pN+L5RYBXsBfYxSUubQLeVvkf5fv+oGrmeCW+fX8yE1rl+q81CCL+Q8LOOzAZFuEeYE9ieczY7fO18MpF8nC14CDQb6DN10QaAtbhTFakZeOqZaUgToDfINsn7jza/bpt1Keu5vUsu1qFgjApzA6+MalINUkHma2FK+z2Yfy0W/NhupbLcWEn1RyuUBTQwssm9wRPDE/LoSUA3pmmqPDl87d9tGFDK/ylQTuaql5tF02ljz8wYQiSRf5nzxqTmtnMCmvhyax75n50to/Tn4lh/j1iko+wCAWTMCNkb+m4G1msdoUYnEYn/TizW9vK3LhVTW5ZdI+uVyasdBhRLoylwYidUGCahvJfDSGk0xS74hUXb223AmziSKE3TFPxSnZEv3zi8mOkzsMSubjnpJqrnQXoBnNI8s+j0IyZQ29Zmd8CLLqmgkIOVOuacCokXvKDWkUmkByRO6LwA==']}" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "header = {\n", " 'alg': 'RS256',\n", " 'kty': 'RS',\n", " 'srCms': [{'commId': {'id': 'urn:oid:1.2.840.10065.1.12.1.5',\n", " 'desc': 'Verification Signature'},\n", " 'commQuals': ['Verification of medical record integrity']}],\n", " 'sigT': '2020-10-23T04:54:56.048+00:00',\n", " 'kid': 'bfbe3e5c0470444576548113928d5f1e4e3f2eeb',\n", " 'x5c': [der]\n", "}\n", "header" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**3.2. Prepare Payload**\n", "\n", "The payload is the base64_url form of the canonicalized version of the searchset Bundle before attaching the signature\n", " \n", "\n", "***Canonicalize the bundle using IETF JSON Canonicalization Scheme (JCS) before adding the signature element:***\n", "\n", "- Remove the id and meta elements if present before canonicalization\n", "- The base64_url of the payload entry is combined with 3.3 below using the jws.sign method." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "b'{\"entry\":[{\"fullUrl\":\"http://hapi.fhir.org/baseR4/Condition/4ac41715-fcbd-421c-8796-9b2c9706dd3f\",\"resource\":{\"category\":[{\"coding\":[{\"code\":\"encounter-diagnosis\",\"display\":\"Encounter Diagnosis\",\"system\":\"http://terminology.hl7.org/CodeSystem/condition-category\"}]}],\"clinicalStatus\":{\"coding\":[{\"code\":\"active\",\"system\":\"http://terminology.hl7.org/CodeSystem/condition-clinical\"}]},\"code\":{\"coding\":[{\"code\":\"122481008\",\"display\":\"Hammer toe (disorder)\",\"system\":\"http://snomed.info/sct\"}],\"text\":\"Hammer Toe\"},\"encounter\":{\"reference\":\"http://example.org/cdex/provider/fhir/Encounter/5fe62cd5-bfcf-4d3b-a1e9-80d6f75d6f82\"},\"id\":\"4ac41715-fcbd-421c-8796-9b2c9706dd3f\",\"meta\":{\"lastUpdated\":\"2020-04-28T20:28:00.008+00:00\",\"versionId\":\"10\"},\"onsetDateTime\":\"2018-10-21T21:22:15-07:00\",\"recordedDate\":\"2018-10-21T21:22:15-07:00\",\"resourceType\":\"Condition\",\"subject\":{\"reference\":\"http://example.org/cdex/provider/fhir/Patient/06e1f0dd-5fbe-4480-9bb4-6b54ec02d31b\"},\"text\":{\"div\":\"
Generated Narrative: Condition 4ac41715-fcbd-421c-8796-9b2c9706dd3f
version: 10; Last updated: 2020-04-28 20:28:00+0000;
Information Source: #cabiJIK51sD2iz4N
clinicalStatus: Active
verificationStatus: Confirmed
category: Encounter Diagnosis
code: Hammer Toe
subject: http://example.org/cdex/provider/fhir/Patient/06e1f0dd-5fbe-4480-9bb4-6b54ec02d31b
encounter: http://example.org/cdex/provider/fhir/Encounter/5fe62cd5-bfcf-4d3b-a1e9-80d6f75d6f82
onset: 2018-10-21 21:22:15-0700
recordedDate: 2018-10-21 21:22:15-0700
Generated Narrative: Condition 4ac41715-fcbd-421c-8796-9b2c9706dd3f
version: 10; Last updated: 2020-04-28 20:28:00+0000;
Information Source: #cabiJIK51sD2iz4N
clinicalStatus: Active
verificationStatus: Confirmed
category: Encounter Diagnosis
code: Hammer Toe
subject: http://example.org/cdex/provider/fhir/Patient/06e1f0dd-5fbe-4480-9bb4-6b54ec02d31b
encounter: http://example.org/cdex/provider/fhir/Encounter/5fe62cd5-bfcf-4d3b-a1e9-80d6f75d6f82
onset: 2018-10-21 21:22:15-0700
recordedDate: 2018-10-21 21:22:15-0700
Generated Narrative: Condition 4ac41715-fcbd-421c-8796-9b2c9706dd3f
version: 10; Last updated: 2020-04-28 20:28:00+0000;
Information Source: #cabiJIK51sD2iz4N
clinicalStatus: Active
verificationStatus: Confirmed
category: Encounter Diagnosis
code: Hammer Toe
subject: http://example.org/cdex/provider/fhir/Patient/06e1f0dd-5fbe-4480-9bb4-6b54ec02d31b
encounter: http://example.org/cdex/provider/fhir/Encounter/5fe62cd5-bfcf-4d3b-a1e9-80d6f75d6f82
onset: 2018-10-21 21:22:15-0700
recordedDate: 2018-10-21 21:22:15-0700
Generated Narrative: Condition 4ac41715-fcbd-421c-8796-9b2c9706dd3f
version: 10; Last updated: 2020-04-28 20:28:00+0000;
Information Source: #cabiJIK51sD2iz4N
clinicalStatus: Active
verificationStatus: Confirmed
category: Encounter Diagnosis
code: Hammer Toe
subject: http://example.org/cdex/provider/fhir/Patient/06e1f0dd-5fbe-4480-9bb4-6b54ec02d31b
encounter: http://example.org/cdex/provider/fhir/Encounter/5fe62cd5-bfcf-4d3b-a1e9-80d6f75d6f82
onset: 2018-10-21 21:22:15-0700
recordedDate: 2018-10-21 21:22:15-0700