{ "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", "\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 sef-signed certificate for authenticating the signer**\n", "\n", "create the public and private keys and cert using openssl on the command line.\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 = California\n", "localityName = Sausalito\n", "organizationName = Example Organization\n", "commonName = John Hancock, MD\n", "emailAddress = jhancock@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:9941339100\n", "URI.1 = https://example.org/fhir/Practitioner/123\n", "~~~" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "2\\. generate the public and private keys and cert\n", "\n", "~~~\n", "!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\n", "~~~" ] }, { "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": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-----BEGIN PRIVATE KEY-----\n", "MIIG/wIBADANBgkqhkiG9w0BAQEFAASCBukwggblAgEAAoIBgQCu3Ich4SabUyLa\n", "JHuVFb00/EDJL0GHw/ETVsUo9tGjUFZ0ViiwMAMxzF2H2O7JyyKEUSb+32dwF4F4\n", "sjVS7MRv8r4VbVomd+T5pnMDbWmDXPStGPuJKGkrDx/RqKHNpOJoE6VKxyhgNZ4H\n", "Lul7lD94vtVG6qCVmFWTtktKnDzFtVOgU9jLYiHnrCZ3jH7Dgj0NIKyaIQTXC1a5\n", "m15WWB5x8yxj9fOjMcFOSTgWuHw/GP/eS9hNhTnaOxzMAgsOWlQriBrtcYyjbdCi\n", "5d0VdYjwozpd85FYKpZT7ZXgH0yeOMbyOs744IMdAcmoHGuQxhb4aRuEGrxg6eBB\n", "Af+1nwKPy9/RlcRCi7QtaahU19li6oIYMnkiDSUAOab6UHC1J4z0+mOrR9Vfj+77\n", "6ijfotiKfA2gECbetCUE0jkxTBU6uu86GJZ1i9hKPd/AKRvVooGh8Wo8yvf+dL7d\n", "U4uAanu/tq0JN9Ybt/F/kTy+HbvLWOrcU8o9jTSs3CzpXdBm41cCAwEAAQKCAYBJ\n", "JUG3x92k8sFs+/7gLdBQdkbJgaWJW8sf+leOG7U0+jm3/4SUsvjbH3Buj63PptQh\n", "AmtsCVrVFlgX+3/32MgRRjsCbpRb7CJR1jFdWSregwds0zsBNHDNzM1UIBTTF6qH\n", "u9QUdDvtBvC8c4DCq5Bje3xu5l3XRfpiSEq1gqafU4sQUZKp/TpOlYIf1xr9wKC2\n", "OZlJ/g7uv7T+/kGXn9PYec7zX6KTfRAuJc27H2AF6vi5bgOk5dp98eVJZ39leR3z\n", "kfuAB3lAvLbWVbMhx0piXQ7z4T4xRaKGyJ6plk6nyONhp4qIz84l6mfVhrzr1SET\n", "fdXetyUxzgHLd+lIPD4Ggx6B22u3h+0TXe12vzJYTOJASyslq0XGoqK/bl/ruplw\n", "z5EirSAV2XInZPGjCuL82KfKOZxy1iQUhV1htfowYB26wQTlQyGfB+0U5QO5YgS7\n", "2psK0ScX5Wzo6tfC1rtN9wJpSnm/USKWtVObth4iYlshnvvIGh8fi6Zuo0XyKbUC\n", "gcEA6fTarXF2/Dt8UmkAXsrnmapO4xk5kbBHakYYkYkVBVf2D1uRrsdhCc01PSz6\n", "q06qyvkei5PqGujOwDYYcMQ+1ZGbphdxCTXZR614NXS6fYgpEA11YEH0Wa1eR5i8\n", "lmAvGfwOZWt9BVNPLaD45pXMOwm31Hh49z0NjfcJb8K5uxf7k1EofyjXnPgkm6Fq\n", "u92QAFLx9gwIC6/3t2Dw4SZ7tnIbCZs2s748swlibynxrSfVXM21pChAhDcm7Ej1\n", "sUT7AoHBAL9WRboJLWJM27d8pc9sMHkajYUwOZSRLeAMcvjwE1+tVodECIotiYtG\n", "RLxzqPUF+XxLSALxdEpVzmZLAJQdxvTAwPb9kzRe7kRAOwq60Z5QcjSrZT+gLKsx\n", "zHQpDRaWzCYb+ju2YOgMyPXdV1Lm9SUbMfYa8GRgMzTSeZi0+NjrjzKko5Mc5dQG\n", "cNrcVguqnl1NhMMb8iM87vGxn3xQJwHMkTYWOS8DkqagxfSi82k+CSrYNc4FLzwf\n", "E9pf2Rg0VQKBwQCxAcAxWZdcXuVAtJDDJ2DyshfdWkhkIarmjQIpmj19PX+9PtqK\n", "Ee8pK0kMb+t3kJ1H1BN4JwEIOvuyETuMle20R+YrU7EB9uvdfzFjwF0YfNwUeRpF\n", "KaFl9/VM1hJY84yvbDS4Jwr/7HgLXa7zRoKuaDvdVQiwhlCrCCzrkbhUBWEhpFWv\n", "X4dCC7wmw4mteYRpule2gIPV09znsUCOGD+hWdN7ASPx+gySqJcA5Aslpu2WuUyk\n", "Vo/5eIDKZKj+5eECgcEAmVPjUG+mRM3ejK2AmjXSqlmS6xZ4LgwhPRf80mxguh1H\n", "5+GnDkProwZOcs4kqSV+hhI1xNYFIMSeP+7+qbMrClukxsjxu9gPC/aE2dZXwIwq\n", "2PY4jsImyZGAi92RtXZmZmupHUzLX2lPaWdUYQTfkjq20MdJuMY2gq/f7XWorPwn\n", "pqe0xWE087GtolVLRtIVUiOarleotIBR4rE6Yv5AI/rwqu0oKfqs/IZ928rxUHb8\n", "Fa9pfo09CurEmAyTBgh5AoHBAL1DOIEpT0a2DCGREJrR8GwqkqpW9tiYOmc/6KQV\n", "VJ44pRd8g9xRYvReg8fnpnj2vNr8TK6OhH13CMscO1GWOydW3Fn7VqK5J9/5imkM\n", "fVHJ9la+Fh2uGCbsqK+etmaRTf+O43b8rfQtJx0HuOKugAGG7tkj4YCDB2zsP2HS\n", "l7btElZnlqgZtl0tVmT0FxLgMeLIZbtC/8+ecVWWlgsZk6q/ckeIA0TXoDQuZ/5F\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": [ "Show the Certificate in DER Format" ] }, { "cell_type": "code", "execution_count": 4, "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": [ "Show the Certicate in PEM format" ] }, { "cell_type": "code", "execution_count": 5, "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" ] }, { "cell_type": "code", "execution_count": 6, "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": 7, "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': 'e6efdb350b69b369a43ae60154e17f39ac75eb58',\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": 7, "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': 'e6efdb350b69b369a43ae60154e17f39ac75eb58',\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 document 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": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "b'{\"entry\":[{\"fullUrl\":\"urn:uuid:17a80a8d-4cf1-4deb-a1fd-2db1130e5f76\",\"resource\":{\"attester\":[{\"mode\":\"legal\",\"party\":{\"display\":\"Example Practitioner\",\"reference\":\"urn:uuid:0820c16d-91de-4dfa-a3a6-f140a516a9bc\"},\"time\":\"2021-10-25T20:16:29-07:00\"}],\"author\":[{\"display\":\"Example Practitioner\",\"reference\":\"urn:uuid:0820c16d-91de-4dfa-a3a6-f140a516a9bc\"}],\"date\":\"2021-10-25T20:16:29-07:00\",\"encounter\":{\"display\":\"Example Encounter\",\"reference\":\"urn:uuid:5ce5c83a-000f-47d2-941c-039358cc9112\"},\"id\":\"17a80a8d-4cf1-4deb-a1fd-2db1130e5f76\",\"resourceType\":\"Composition\",\"section\":[{\"entry\":[{\"reference\":\"urn:uuid:014a68ec-d691-49e0-b980-91b0d924e570\"}],\"title\":\"Active Condition 1\"}],\"status\":\"final\",\"subject\":{\"display\":\"Example Patient\",\"reference\":\"urn:uuid:970af6c9-5bbd-4067-b6c1-d9b2c823aece\"},\"text\":{\"div\":\"
Generated Narrative
Resource \\\\\"17a80a8d-4cf1-4deb-a1fd-2db1130e5f76\\\\\"
status: final
type: Medical records (LOINC#11503-0)
encounter: See above (urn:uuid:5ce5c83a-000f-47d2-941c-039358cc9112: Example Encounter)
date: 2021-10-25T20:16:29-07:00
author: See above (urn:uuid:0820c16d-91de-4dfa-a3a6-f140a516a9bc: Example Practitioner)
title: Active Conditions
| - | Mode | Time | Party |
| * | legal | 2021-10-25T20:16:29-07:00 | See above (urn:uuid:0820c16d-91de-4dfa-a3a6-f140a516a9bc: Example Practitioner) |
Generated Narrative
Resource \\\\\"0820c16d-91de-4dfa-a3a6-f140a516a9bc\\\\\" Updated \\\\\"2013-05-05T16:13:03Z\\\\\"
name: John Hancock
Generated Narrative
Resource \\\\\"970af6c9-5bbd-4067-b6c1-d9b2c823aece\\\\\"
active: true
name: CDEX Example Patient
Generated Narrative
Resource \\\\\"014a68ec-d691-49e0-b980-91b0d924e570\\\\\"
identifier: id: 1
clinicalStatus: Active (Condition Clinical Status Codes#active)
category: Problem (SNOMED CT#55607006; LOINC#75326-9)
code: Type 2 Diabetes Mellitus (SNOMED CT#44054006)
subject: See above (urn:uuid:970af6c9-5bbd-4067-b6c1-d9b2c823aece)
onset: 2006-01-01
asserter: See above (urn:uuid:0820c16d-91de-4dfa-a3a6-f140a516a9bc)
Generated Narrative
Resource \\\\\"5ce5c83a-000f-47d2-941c-039358cc9112\\\\\"
status: finished
class: emergency (Details: http://terminology.hl7.org/CodeSystem/v3-ActCode code EMER = \\'emergency\\', stated as \\'null\\')
type: Unknown (qualifier value) (SNOMED CT#261665006)
subject: See above (urn:uuid:970af6c9-5bbd-4067-b6c1-d9b2c823aece: CDEX Example Patient)
| - | Individual |
| * | See above (urn:uuid:0820c16d-91de-4dfa-a3a6-f140a516a9bc: John Hancock) |
period: 2021-10-25T20:10:29-07:00 --> 2021-10-25T20:16:29-07:00
serviceProvider: See above (urn:uuid:e37f004b-dc10-422b-b833-cdaa10a055a3: CDEX Example Organization)
Generated Narrative
Resource \\\\\"e37f004b-dc10-422b-b833-cdaa10a055a3\\\\\"
active: true
name: CDEX Example Organization
telecom: ph: (+1) 555-555-5555, customer-service@example.org
address: 1 CDEX Lane Boston MA 01002 USA
Generated Narrative
Resource \\\"17a80a8d-4cf1-4deb-a1fd-2db1130e5f76\\\"
status: final
type: Medical records (LOINC#11503-0)
encounter: See above (urn:uuid:5ce5c83a-000f-47d2-941c-039358cc9112: Example Encounter)
date: 2021-10-25T20:16:29-07:00
author: See above (urn:uuid:0820c16d-91de-4dfa-a3a6-f140a516a9bc: Example Practitioner)
title: Active Conditions
| - | Mode | Time | Party |
| * | legal | 2021-10-25T20:16:29-07:00 | See above (urn:uuid:0820c16d-91de-4dfa-a3a6-f140a516a9bc: Example Practitioner) |
Generated Narrative
Resource \\\"0820c16d-91de-4dfa-a3a6-f140a516a9bc\\\" Updated \\\"2013-05-05T16:13:03Z\\\"
name: John Hancock
Generated Narrative
Resource \\\"970af6c9-5bbd-4067-b6c1-d9b2c823aece\\\"
active: true
name: CDEX Example Patient
Generated Narrative
Resource \\\"014a68ec-d691-49e0-b980-91b0d924e570\\\"
identifier: id: 1
clinicalStatus: Active (Condition Clinical Status Codes#active)
category: Problem (SNOMED CT#55607006; LOINC#75326-9)
code: Type 2 Diabetes Mellitus (SNOMED CT#44054006)
subject: See above (urn:uuid:970af6c9-5bbd-4067-b6c1-d9b2c823aece)
onset: 2006-01-01
asserter: See above (urn:uuid:0820c16d-91de-4dfa-a3a6-f140a516a9bc)
Generated Narrative
Resource \\\"5ce5c83a-000f-47d2-941c-039358cc9112\\\"
status: finished
class: emergency (Details: http://terminology.hl7.org/CodeSystem/v3-ActCode code EMER = 'emergency', stated as 'null')
type: Unknown (qualifier value) (SNOMED CT#261665006)
subject: See above (urn:uuid:970af6c9-5bbd-4067-b6c1-d9b2c823aece: CDEX Example Patient)
| - | Individual |
| * | See above (urn:uuid:0820c16d-91de-4dfa-a3a6-f140a516a9bc: John Hancock) |
period: 2021-10-25T20:10:29-07:00 --> 2021-10-25T20:16:29-07:00
serviceProvider: See above (urn:uuid:e37f004b-dc10-422b-b833-cdaa10a055a3: CDEX Example Organization)
Generated Narrative
Resource \\\"e37f004b-dc10-422b-b833-cdaa10a055a3\\\"
active: true
name: CDEX Example Organization
telecom: ph: (+1) 555-555-5555, customer-service@example.org
address: 1 CDEX Lane Boston MA 01002 USA
Generated Narrative
Resource \\\"17a80a8d-4cf1-4deb-a1fd-2db1130e5f76\\\"
status: final
type: Medical records (LOINC#11503-0)
encounter: See above (urn:uuid:5ce5c83a-000f-47d2-941c-039358cc9112: Example Encounter)
date: 2021-10-25T20:16:29-07:00
author: See above (urn:uuid:0820c16d-91de-4dfa-a3a6-f140a516a9bc: Example Practitioner)
title: Active Conditions
| - | Mode | Time | Party |
| * | legal | 2021-10-25T20:16:29-07:00 | See above (urn:uuid:0820c16d-91de-4dfa-a3a6-f140a516a9bc: Example Practitioner) |
Generated Narrative
Resource \\\"0820c16d-91de-4dfa-a3a6-f140a516a9bc\\\" Updated \\\"2013-05-05T16:13:03Z\\\"
name: John Hancock
Generated Narrative
Resource \\\"970af6c9-5bbd-4067-b6c1-d9b2c823aece\\\"
active: true
name: CDEX Example Patient
Generated Narrative
Resource \\\"014a68ec-d691-49e0-b980-91b0d924e570\\\"
identifier: id: 1
clinicalStatus: Active (Condition Clinical Status Codes#active)
category: Problem (SNOMED CT#55607006; LOINC#75326-9)
code: Type 2 Diabetes Mellitus (SNOMED CT#44054006)
subject: See above (urn:uuid:970af6c9-5bbd-4067-b6c1-d9b2c823aece)
onset: 2006-01-01
asserter: See above (urn:uuid:0820c16d-91de-4dfa-a3a6-f140a516a9bc)
Generated Narrative
Resource \\\"5ce5c83a-000f-47d2-941c-039358cc9112\\\"
status: finished
class: emergency (Details: http://terminology.hl7.org/CodeSystem/v3-ActCode code EMER = 'emergency', stated as 'null')
type: Unknown (qualifier value) (SNOMED CT#261665006)
subject: See above (urn:uuid:970af6c9-5bbd-4067-b6c1-d9b2c823aece: CDEX Example Patient)
| - | Individual |
| * | See above (urn:uuid:0820c16d-91de-4dfa-a3a6-f140a516a9bc: John Hancock) |
period: 2021-10-25T20:10:29-07:00 --> 2021-10-25T20:16:29-07:00
serviceProvider: See above (urn:uuid:e37f004b-dc10-422b-b833-cdaa10a055a3: CDEX Example Organization)
Generated Narrative
Resource \\\"e37f004b-dc10-422b-b833-cdaa10a055a3\\\"
active: true
name: CDEX Example Organization
telecom: ph: (+1) 555-555-5555, customer-service@example.org
address: 1 CDEX Lane Boston MA 01002 USA
Generated Narrative
Resource \\\\\"17a80a8d-4cf1-4deb-a1fd-2db1130e5f76\\\\\"
status: final
type: Medical records (LOINC#11503-0)
encounter: See above (urn:uuid:5ce5c83a-000f-47d2-941c-039358cc9112: Example Encounter)
date: 2021-10-25T20:16:29-07:00
author: See above (urn:uuid:0820c16d-91de-4dfa-a3a6-f140a516a9bc: Example Practitioner)
title: Active Conditions
| - | Mode | Time | Party |
| * | legal | 2021-10-25T20:16:29-07:00 | See above (urn:uuid:0820c16d-91de-4dfa-a3a6-f140a516a9bc: Example Practitioner) |
Generated Narrative
Resource \\\\\"0820c16d-91de-4dfa-a3a6-f140a516a9bc\\\\\" Updated \\\\\"2013-05-05T16:13:03Z\\\\\"
name: John Hancock
Generated Narrative
Resource \\\\\"970af6c9-5bbd-4067-b6c1-d9b2c823aece\\\\\"
active: true
name: CDEX Example Patient
Generated Narrative
Resource \\\\\"014a68ec-d691-49e0-b980-91b0d924e570\\\\\"
identifier: id: 1
clinicalStatus: Active (Condition Clinical Status Codes#active)
category: Problem (SNOMED CT#55607006; LOINC#75326-9)
code: Type 2 Diabetes Mellitus (SNOMED CT#44054006)
subject: See above (urn:uuid:970af6c9-5bbd-4067-b6c1-d9b2c823aece)
onset: 2006-01-01
asserter: See above (urn:uuid:0820c16d-91de-4dfa-a3a6-f140a516a9bc)
Generated Narrative
Resource \\\\\"5ce5c83a-000f-47d2-941c-039358cc9112\\\\\"
status: finished
class: emergency (Details: http://terminology.hl7.org/CodeSystem/v3-ActCode code EMER = \\'emergency\\', stated as \\'null\\')
type: Unknown (qualifier value) (SNOMED CT#261665006)
subject: See above (urn:uuid:970af6c9-5bbd-4067-b6c1-d9b2c823aece: CDEX Example Patient)
| - | Individual |
| * | See above (urn:uuid:0820c16d-91de-4dfa-a3a6-f140a516a9bc: John Hancock) |
period: 2021-10-25T20:10:29-07:00 --> 2021-10-25T20:16:29-07:00
serviceProvider: See above (urn:uuid:e37f004b-dc10-422b-b833-cdaa10a055a3: CDEX Example Organization)
Generated Narrative
Resource \\\\\"e37f004b-dc10-422b-b833-cdaa10a055a3\\\\\"
active: true
name: CDEX Example Organization
telecom: ph: (+1) 555-555-5555, customer-service@example.org
address: 1 CDEX Lane Boston MA 01002 USA