This page is part of the Da Vinci Clinical Documentation Exchange (v2.0.0-ballot: STU2 Ballot 1) based on FHIR R4. The current version which supercedes this version is 1.1.0. For a full list of available versions, see the Directory of published versions
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
Although self-signed certificates are used for the purpose of these examples, they are not recommended for production systems.
1. Generate RSA256 public and private keys for signing the bundle
DO THIS STEP ONLY ONCE
2. Create a self-signed certificate for authenticating the signer
create the public and private keys and cert using openssl on the command line.
[req]
default_bit = 4096
distinguished_name = req_distinguished_name
prompt = no
x509_extensions = v3_ca
[req_distinguished_name]
countryName = US
stateOrProvinceName = California
localityName = Sausalito
organizationName = HealtheData1
commonName = Eric Haas, DVM
emailAddress = ehaas@healthedata1.org
[v3_ca]
basicConstraints = CA:TRUE
keyUsage=nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = www.healthedatainc.com
2. generate the public and private keys and cert
!openssl genrsa -out private-key.pem 3072
!openssl rsa -in private-key.pem -pubout -out public-key.pem
!openssl req -new -x509 -key private-key.pem -outform DER -out cert.der -days 360 -config cert.config
For the purpose of this example display the keys (normally would never share the private key)
!cat private-key.pem
!echo
!cat public-key.pem
-----BEGIN RSA PRIVATE KEY----- MIIG4wIBAAKCAYEA6SnEpKADOrFttfr1k3iFThsddDFmrEMu1R4nes8qlwATPs53 wZ13p8lNI9RU7z5kXzg6Dg11bj1MA6JoQh4fm3JVvSjNqOet3MUShLwZ2h67I8Oc jZsTuWIxEW4bR3UHqpLXcN1WBEUfR6MSztxZLM0dvdh0weMVt8lpVd4E5DEKMz0n CSh92xvD6qugGDyewuGASJVEnQTFZd6p3hH4O37sYhX16H3U1Zu6zIohu1/c+Nz3 4pamnorH5rUcQJUcBDV6x9zrzgz8i9K05xvArGwF2FSDJnXR3uGRfaZYfebI+KTE 4S7XCV/6PVxy44exJmcoCR1hEKuD8BcGXZm3H4Qpjq/PB/AW1K7v+1es27BtTdQl pZ3ZW1c5y/tyDDq/JF2h3Gp6n3JIBVeBK534xSatTiGgJrDI/OcTJI8ly8nCy/7u Z9qOgYPd/1EX6rjqEiBjgkduQ2mc6cNpN7O6BPXTMBFl7X14GLYdm5Y8ubRR9Bo6 TpMdO4+2U+R58Z5bAgMBAAECggGANf/QZPgSB2PULtNCULcW2HH7Lk/KoZaloAHt zslv6azAyEj0/0hCz/8U+HlSel4OzOauu1ZunetgUW8pijaDx3KBXN+4UafmYjzZ /xe5PQTk/nFtLnZ96O9OweSoOLJn5h8/+gmoxDBmACdKUdJCbNfMTY117Pl0rC3f UV2r8FVTMW62Pa69ByO1CgJZf4N6mVO0bBr12w+hz+fzm1S6Er1gbY78dq29vwLk Dj7ndQfMm25Bkp6lVA58IXhMZMCjXSbei1aHxYBXAcAJP5bouiAxqnb2rZ5QM1W1 CpLuJ0HbGGl0y6aWZenV/C5JEDKqqh62KUGPnTeJLgpJpnuK59y7K+0dcFFKji5C 0d61lTaOKxHz3X11043j9+pJYJ8bEpxwimO+1i6boBNrB++i5cC8UKxK0Zw6o3HW Xfko57EJR6oCiWeorgHZTF6wud4WlRkOMrt7EkrhbPQF8lcahCKGCwI63wxcCtE6 Wf784Dto+kQSQj6+G2V385utiXExAoHBAP95t1kQdTQl3ASwA3wvnU1oRzsj83DS Qrg2vhJlhTUwKIsxKYIvL/KQQFsd4/ejr5nGurlAcFsRlA6cR94LXL2DWvvy52uP r1UeOPeJ7DiFu2IY8ehtX9wEbt1dLYkgwTmkwASQIJsaNCgMH+1y5jcWdWGmHqf8 Y4z3/JerrT1FRT/Sgsp34HrzeCAajyRLK/qzDU1ieXYWVMnv+ZGEl5DFMvFRf0dP IJHT7uuHdAvXw1tRcvsYtGIdiHyNDGjcpQKBwQDppFL2n50Fx3oWanXIspWS4Whq PgBm2wTz5o+LGQIRj0m6qD5q+/mXdxxzj8zY3qlkQj1YGT2Bog9cYL2+PuNqnHeq coi6uVf0zruq9XcrCoYs5sT4GT57LdRQK3xtGXURFbrVc/wjn7rU1/XhqThQADGx cHvUVc37Pkvirf0/hAkW3KwOBEsXn8IYJ5JydBOm957NvoEAGCcI9tc0FM7xl4I7 CMzSYl+i/tXy/sec45Y514LXun8Tvm09uj8Qnv8CgcBX7HDwgxyDLQBy0IzygYSW rmvNa8sNqh9yPMzfkfbtXjyl4u6RMmJDDehIM5pQkRIPT3jV5tqETSFygdCuF6T8 SCfZDDkfKJ1EIxmh/+K/dS8PTNx8jJ/wHcp1/up8BjzZ9Nxs9ZlzJ+qJWdrnIqMe lGkjiUOFtvQgAPz6ygfeTWfO1klTGzyzs/VEvz9CU2i4aEUMu/ZncLoPobp3nXV4 SpYEvXKbfR0Ncy4H+18x8Dj4xahXyKHUHqvpibWapU0CgcEAinvgxNd0neFPZwvx BmV7rJS4bAiV+mElPV/SgzLue/P/Uoi4fncdyH5MOd7pHz5TDt8INzi2sSiajDm3 HZVu/FkDwN6kVnDXRn5m0/0shjF1uBWMeDWWSDKw3lf4Jz5omhjUJgLaV08s0U20 Ku4/N4P18GNoskGtlpalKhXQvp4HOSrRPHmk/Lqvs9t4vSg6IcQxt2eMVL78HB8b DX6r7pzMDyu3I5g1cYo0zBPhwwdOmrg3kKC1A8HiRC0phjOHAoHAbayWoC7XWsKx 1XzirFof87u47oEAcu0VlOJOwCr270J2Q1jyLMRCvgNQYvZz6nTJt0jcXazZrBTQ jkwHgb7kFFSTqrE3Uj8Bmm6O+WnoY2+zi4leSe8yz3SRpLL1w9S1p40XQGLJhIX+ GJr5shr9osadWap/vzl244Do4Od/NMehLl6ibyu1UteRexDp8JjyUBwAAC50kMYP OavUzEG9Ymb4t4yNjaso6C7ZNVcbJTJeI1A153p0uH3xJqFefai2 -----END RSA PRIVATE KEY----- -----BEGIN PUBLIC KEY----- MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA6SnEpKADOrFttfr1k3iF ThsddDFmrEMu1R4nes8qlwATPs53wZ13p8lNI9RU7z5kXzg6Dg11bj1MA6JoQh4f m3JVvSjNqOet3MUShLwZ2h67I8OcjZsTuWIxEW4bR3UHqpLXcN1WBEUfR6MSztxZ LM0dvdh0weMVt8lpVd4E5DEKMz0nCSh92xvD6qugGDyewuGASJVEnQTFZd6p3hH4 O37sYhX16H3U1Zu6zIohu1/c+Nz34pamnorH5rUcQJUcBDV6x9zrzgz8i9K05xvA rGwF2FSDJnXR3uGRfaZYfebI+KTE4S7XCV/6PVxy44exJmcoCR1hEKuD8BcGXZm3 H4Qpjq/PB/AW1K7v+1es27BtTdQlpZ3ZW1c5y/tyDDq/JF2h3Gp6n3JIBVeBK534 xSatTiGgJrDI/OcTJI8ly8nCy/7uZ9qOgYPd/1EX6rjqEiBjgkduQ2mc6cNpN7O6 BPXTMBFl7X14GLYdm5Y8ubRR9Bo6TpMdO4+2U+R58Z5bAgMBAAE= -----END PUBLIC KEY-----
Display DER Format of Certificate
!openssl x509 -in cert.der -inform DER -text
Certificate: Data: Version: 3 (0x2) Serial Number: 16322561221100825744 (0xe28562f33047ec90) Signature Algorithm: sha256WithRSAEncryption Issuer: C=US, ST=California, L=Sausalito, O=HealtheData1, CN=Eric Haas, DVM/emailAddress=ehaas@healthedata1.org Validity Not Before: Oct 27 17:42:04 2021 GMT Not After : Oct 22 17:42:04 2022 GMT Subject: C=US, ST=California, L=Sausalito, O=HealtheData1, CN=Eric Haas, DVM/emailAddress=ehaas@healthedata1.org Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (3072 bit) Modulus: 00:e9:29:c4:a4:a0:03:3a:b1:6d:b5:fa:f5:93:78: 85:4e:1b:1d:74:31:66:ac:43:2e:d5:1e:27:7a:cf: 2a:97:00:13:3e:ce:77:c1:9d:77:a7:c9:4d:23:d4: 54:ef:3e:64:5f:38:3a:0e:0d:75:6e:3d:4c:03:a2: 68:42:1e:1f:9b:72:55:bd:28:cd:a8:e7:ad:dc:c5: 12:84:bc:19:da:1e:bb:23:c3:9c:8d:9b:13:b9:62: 31:11:6e:1b:47:75:07:aa:92:d7:70:dd:56:04:45: 1f:47:a3:12:ce:dc:59:2c:cd:1d:bd:d8:74:c1:e3: 15:b7:c9:69:55:de:04:e4:31:0a:33:3d:27:09:28: 7d:db:1b:c3:ea:ab:a0:18:3c:9e:c2:e1:80:48:95: 44:9d:04:c5:65:de:a9:de:11:f8:3b:7e:ec:62:15: f5:e8:7d:d4:d5:9b:ba:cc:8a:21:bb:5f:dc:f8:dc: f7:e2:96:a6:9e:8a:c7:e6:b5:1c:40:95:1c:04:35: 7a:c7:dc:eb:ce:0c:fc:8b:d2:b4:e7:1b:c0:ac:6c: 05:d8:54:83:26:75:d1:de:e1:91:7d:a6:58:7d:e6: c8:f8:a4:c4:e1:2e:d7:09:5f:fa:3d:5c:72:e3:87: b1:26:67:28:09:1d:61:10:ab:83:f0:17:06:5d:99: b7:1f:84:29:8e:af:cf:07:f0:16:d4:ae:ef:fb:57: ac:db:b0:6d:4d:d4:25:a5:9d:d9:5b:57:39:cb:fb: 72:0c:3a:bf:24:5d:a1:dc:6a:7a:9f:72:48:05:57: 81:2b:9d:f8:c5:26:ad:4e:21:a0:26:b0:c8:fc:e7: 13:24:8f:25:cb:c9:c2:cb:fe:ee:67:da:8e:81:83: dd:ff:51:17:ea:b8:ea:12:20:63:82:47:6e:43:69: 9c:e9:c3:69:37:b3:ba:04:f5:d3:30:11:65:ed:7d: 78:18:b6:1d:9b:96:3c:b9:b4:51:f4:1a:3a:4e:93: 1d:3b:8f:b6:53:e4:79:f1:9e:5b Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:TRUE X509v3 Key Usage: Digital Signature, Non Repudiation, Key Encipherment X509v3 Subject Alternative Name: DNS:www.healthedatainc.com Signature Algorithm: sha256WithRSAEncryption 0a:e3:14:36:af:5a:cb:ef:9e:e5:80:bb:40:53:bd:e2:b7:f3: c4:64:27:17:71:a4:95:93:40:5e:62:2b:ec:f5:46:76:21:98: d8:64:f1:ff:d4:6d:1c:2c:13:2b:39:0b:fb:2b:ca:a2:37:99: f5:d5:4a:f3:0a:c6:56:24:64:3b:f8:d4:c9:9f:8a:71:64:68: 91:48:ec:e7:d9:dc:24:64:4c:49:24:71:b5:e0:90:ba:3b:78: 85:fd:be:fe:a5:7e:7f:6b:0c:42:d1:2b:c0:f1:37:d2:f6:ea: 45:85:0d:34:d0:55:11:0a:5a:43:1f:da:70:90:d4:bf:db:fb: b2:31:e2:24:3a:97:c1:0f:ab:ce:3f:79:88:70:08:69:e1:07: a8:5f:cc:b3:6d:a9:d9:b7:99:ba:ab:c8:40:a7:8c:97:eb:2f: 56:a1:ed:8a:ec:d6:9c:5e:14:e9:52:26:a6:4a:f8:6c:79:7b: 7a:05:7d:1f:a9:7a:4f:64:8c:92:3e:aa:0d:4e:5e:f4:d8:34: 66:52:d3:b6:8b:2c:84:12:e6:a2:91:7b:7b:b1:f2:ad:31:00: 99:f3:8f:29:07:b4:12:0f:44:da:ea:f3:c6:a0:6e:1b:9e:24: e7:41:b6:27:41:62:3e:c4:09:02:11:62:34:6c:12:83:84:b7: 1f:25:43:1b:bb:9e:29:dd:0b:f7:7c:0a:38:d3:98:1a:f3:0a: 8b:30:87:07:ea:4a:bc:43:09:a1:9f:32:f6:e8:81:f8:71:57: 72:9f:51:68:9a:89:f7:b1:e9:65:31:2f:fa:58:82:a7:63:d2: 5f:37:0a:d2:bd:b9:49:cc:a3:17:a7:4b:a2:e2:b6:48:1d:f4: c4:0b:c9:f2:d1:39:f3:8f:a3:a9:0e:82:19:e7:14:f5:78:ef: 94:08:ee:25:d0:ab:0d:e5:4f:b2:39:27:ec:e3:d7:1b:ef:17: 65:4e:f3:a8:76:4d:99:75:f5:61:8e:07:e6:b8:04:27:8f:25: ad:4a:cf:dc:8f:11 -----BEGIN CERTIFICATE----- MIIE3zCCA0egAwIBAgIJAOKFYvMwR+yQMA0GCSqGSIb3DQEBCwUAMIGNMQswCQYD VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJU2F1c2FsaXRv MRUwEwYDVQQKDAxIZWFsdGhlRGF0YTExFzAVBgNVBAMMDkVyaWMgSGFhcywgRFZN MSUwIwYJKoZIhvcNAQkBFhZlaGFhc0BoZWFsdGhlZGF0YTEub3JnMB4XDTIxMTAy NzE3NDIwNFoXDTIyMTAyMjE3NDIwNFowgY0xCzAJBgNVBAYTAlVTMRMwEQYDVQQI DApDYWxpZm9ybmlhMRIwEAYDVQQHDAlTYXVzYWxpdG8xFTATBgNVBAoMDEhlYWx0 aGVEYXRhMTEXMBUGA1UEAwwORXJpYyBIYWFzLCBEVk0xJTAjBgkqhkiG9w0BCQEW FmVoYWFzQGhlYWx0aGVkYXRhMS5vcmcwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAw ggGKAoIBgQDpKcSkoAM6sW21+vWTeIVOGx10MWasQy7VHid6zyqXABM+znfBnXen yU0j1FTvPmRfODoODXVuPUwDomhCHh+bclW9KM2o563cxRKEvBnaHrsjw5yNmxO5 YjERbhtHdQeqktdw3VYERR9HoxLO3FkszR292HTB4xW3yWlV3gTkMQozPScJKH3b G8Pqq6AYPJ7C4YBIlUSdBMVl3qneEfg7fuxiFfXofdTVm7rMiiG7X9z43Pfilqae isfmtRxAlRwENXrH3OvODPyL0rTnG8CsbAXYVIMmddHe4ZF9plh95sj4pMThLtcJ X/o9XHLjh7EmZygJHWEQq4PwFwZdmbcfhCmOr88H8BbUru/7V6zbsG1N1CWlndlb VznL+3IMOr8kXaHcanqfckgFV4ErnfjFJq1OIaAmsMj85xMkjyXLycLL/u5n2o6B g93/URfquOoSIGOCR25DaZzpw2k3s7oE9dMwEWXtfXgYth2bljy5tFH0GjpOkx07 j7ZT5HnxnlsCAwEAAaNAMD4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCBeAwIQYD VR0RBBowGIIWd3d3LmhlYWx0aGVkYXRhaW5jLmNvbTANBgkqhkiG9w0BAQsFAAOC AYEACuMUNq9ay++e5YC7QFO94rfzxGQnF3GklZNAXmIr7PVGdiGY2GTx/9RtHCwT KzkL+yvKojeZ9dVK8wrGViRkO/jUyZ+KcWRokUjs59ncJGRMSSRxteCQujt4hf2+ /qV+f2sMQtErwPE30vbqRYUNNNBVEQpaQx/acJDUv9v7sjHiJDqXwQ+rzj95iHAI aeEHqF/Ms22p2beZuqvIQKeMl+svVqHtiuzWnF4U6VImpkr4bHl7egV9H6l6T2SM kj6qDU5e9Ng0ZlLTtosshBLmopF7e7HyrTEAmfOPKQe0Eg9E2urzxqBuG54k50G2 J0FiPsQJAhFiNGwSg4S3HyVDG7ueKd0L93wKONOYGvMKizCHB+pKvEMJoZ8y9uiB +HFXcp9RaJqJ97HpZTEv+liCp2PSXzcK0r25ScyjF6dLouK2SB30xAvJ8tE584+j qQ6CGecU9XjvlAjuJdCrDeVPsjkn7OPXG+8XZU7zqHZNmXX1YY4H5rgEJ48lrUrP 3I8R -----END CERTIFICATE-----
Display PEM Format of Certificate
!openssl x509 -in cert.der -inform DER -outform PEM -out cert.pem
!cat cert.pem
-----BEGIN CERTIFICATE----- MIIE3zCCA0egAwIBAgIJAOKFYvMwR+yQMA0GCSqGSIb3DQEBCwUAMIGNMQswCQYD VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJU2F1c2FsaXRv MRUwEwYDVQQKDAxIZWFsdGhlRGF0YTExFzAVBgNVBAMMDkVyaWMgSGFhcywgRFZN MSUwIwYJKoZIhvcNAQkBFhZlaGFhc0BoZWFsdGhlZGF0YTEub3JnMB4XDTIxMTAy NzE3NDIwNFoXDTIyMTAyMjE3NDIwNFowgY0xCzAJBgNVBAYTAlVTMRMwEQYDVQQI DApDYWxpZm9ybmlhMRIwEAYDVQQHDAlTYXVzYWxpdG8xFTATBgNVBAoMDEhlYWx0 aGVEYXRhMTEXMBUGA1UEAwwORXJpYyBIYWFzLCBEVk0xJTAjBgkqhkiG9w0BCQEW FmVoYWFzQGhlYWx0aGVkYXRhMS5vcmcwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAw ggGKAoIBgQDpKcSkoAM6sW21+vWTeIVOGx10MWasQy7VHid6zyqXABM+znfBnXen yU0j1FTvPmRfODoODXVuPUwDomhCHh+bclW9KM2o563cxRKEvBnaHrsjw5yNmxO5 YjERbhtHdQeqktdw3VYERR9HoxLO3FkszR292HTB4xW3yWlV3gTkMQozPScJKH3b G8Pqq6AYPJ7C4YBIlUSdBMVl3qneEfg7fuxiFfXofdTVm7rMiiG7X9z43Pfilqae isfmtRxAlRwENXrH3OvODPyL0rTnG8CsbAXYVIMmddHe4ZF9plh95sj4pMThLtcJ X/o9XHLjh7EmZygJHWEQq4PwFwZdmbcfhCmOr88H8BbUru/7V6zbsG1N1CWlndlb VznL+3IMOr8kXaHcanqfckgFV4ErnfjFJq1OIaAmsMj85xMkjyXLycLL/u5n2o6B g93/URfquOoSIGOCR25DaZzpw2k3s7oE9dMwEWXtfXgYth2bljy5tFH0GjpOkx07 j7ZT5HnxnlsCAwEAAaNAMD4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCBeAwIQYD VR0RBBowGIIWd3d3LmhlYWx0aGVkYXRhaW5jLmNvbTANBgkqhkiG9w0BAQsFAAOC AYEACuMUNq9ay++e5YC7QFO94rfzxGQnF3GklZNAXmIr7PVGdiGY2GTx/9RtHCwT KzkL+yvKojeZ9dVK8wrGViRkO/jUyZ+KcWRokUjs59ncJGRMSSRxteCQujt4hf2+ /qV+f2sMQtErwPE30vbqRYUNNNBVEQpaQx/acJDUv9v7sjHiJDqXwQ+rzj95iHAI aeEHqF/Ms22p2beZuqvIQKeMl+svVqHtiuzWnF4U6VImpkr4bHl7egV9H6l6T2SM kj6qDU5e9Ng0ZlLTtosshBLmopF7e7HyrTEAmfOPKQe0Eg9E2urzxqBuG54k50G2 J0FiPsQJAhFiNGwSg4S3HyVDG7ueKd0L93wKONOYGvMKizCHB+pKvEMJoZ8y9uiB +HFXcp9RaJqJ97HpZTEv+liCp2PSXzcK0r25ScyjF6dLouK2SB30xAvJ8tE584+j qQ6CGecU9XjvlAjuJdCrDeVPsjkn7OPXG+8XZU7zqHZNmXX1YY4H5rgEJ48lrUrP 3I8R -----END CERTIFICATE-----
3. Create JWS to Attach to Bundle
3.1. Prepare Header
note the base64 DER is Cert PEM file wihout the footer and header and line returns
with open('cert.pem') as f:
der = (f.read()) # base64 DER is PEM wihout the footer and header and line returns
der = der.replace('-----BEGIN CERTIFICATE-----','')
der = der.replace('-----END CERTIFICATE-----','')
der = der.replace('\n','')
header = {"alg": "RS256","kty": "RS", "x5c": [der]}
header
{'alg': 'RS256', 'kty': 'RS', 'x5c': ['MIIE3zCCA0egAwIBAgIJAOKFYvMwR+yQMA0GCSqGSIb3DQEBCwUAMIGNMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJU2F1c2FsaXRvMRUwEwYDVQQKDAxIZWFsdGhlRGF0YTExFzAVBgNVBAMMDkVyaWMgSGFhcywgRFZNMSUwIwYJKoZIhvcNAQkBFhZlaGFhc0BoZWFsdGhlZGF0YTEub3JnMB4XDTIxMTAyNzE3NDIwNFoXDTIyMTAyMjE3NDIwNFowgY0xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlTYXVzYWxpdG8xFTATBgNVBAoMDEhlYWx0aGVEYXRhMTEXMBUGA1UEAwwORXJpYyBIYWFzLCBEVk0xJTAjBgkqhkiG9w0BCQEWFmVoYWFzQGhlYWx0aGVkYXRhMS5vcmcwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDpKcSkoAM6sW21+vWTeIVOGx10MWasQy7VHid6zyqXABM+znfBnXenyU0j1FTvPmRfODoODXVuPUwDomhCHh+bclW9KM2o563cxRKEvBnaHrsjw5yNmxO5YjERbhtHdQeqktdw3VYERR9HoxLO3FkszR292HTB4xW3yWlV3gTkMQozPScJKH3bG8Pqq6AYPJ7C4YBIlUSdBMVl3qneEfg7fuxiFfXofdTVm7rMiiG7X9z43PfilqaeisfmtRxAlRwENXrH3OvODPyL0rTnG8CsbAXYVIMmddHe4ZF9plh95sj4pMThLtcJX/o9XHLjh7EmZygJHWEQq4PwFwZdmbcfhCmOr88H8BbUru/7V6zbsG1N1CWlndlbVznL+3IMOr8kXaHcanqfckgFV4ErnfjFJq1OIaAmsMj85xMkjyXLycLL/u5n2o6Bg93/URfquOoSIGOCR25DaZzpw2k3s7oE9dMwEWXtfXgYth2bljy5tFH0GjpOkx07j7ZT5HnxnlsCAwEAAaNAMD4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCBeAwIQYDVR0RBBowGIIWd3d3LmhlYWx0aGVkYXRhaW5jLmNvbTANBgkqhkiG9w0BAQsFAAOCAYEACuMUNq9ay++e5YC7QFO94rfzxGQnF3GklZNAXmIr7PVGdiGY2GTx/9RtHCwTKzkL+yvKojeZ9dVK8wrGViRkO/jUyZ+KcWRokUjs59ncJGRMSSRxteCQujt4hf2+/qV+f2sMQtErwPE30vbqRYUNNNBVEQpaQx/acJDUv9v7sjHiJDqXwQ+rzj95iHAIaeEHqF/Ms22p2beZuqvIQKeMl+svVqHtiuzWnF4U6VImpkr4bHl7egV9H6l6T2SMkj6qDU5e9Ng0ZlLTtosshBLmopF7e7HyrTEAmfOPKQe0Eg9E2urzxqBuG54k50G2J0FiPsQJAhFiNGwSg4S3HyVDG7ueKd0L93wKONOYGvMKizCHB+pKvEMJoZ8y9uiB+HFXcp9RaJqJ97HpZTEv+liCp2PSXzcK0r25ScyjF6dLouK2SB30xAvJ8tE584+jqQ6CGecU9XjvlAjuJdCrDeVPsjkn7OPXG+8XZU7zqHZNmXX1YY4H5rgEJ48lrUrP3I8R']}
3.2. Prepare Payload
The payload is the base64_url form of the canonicalized version of the searchset Bundle before attaching the signature
Canonicalize the bundle using IETF JSON Canonicalization Scheme (JCS) before adding the signature element:
from jcs import canonicalize #package for a JCS (RFC 8785) compliant canonicalizer.
from json import loads
searchset_bundle = r'''{
"resourceType": "Bundle",
"id": "d88e2910-3c95-469d-b1f4-ab5553b471fb",
"meta": {
"lastUpdated": "2020-10-23T04:54:56.048+00:00"
},
"type": "searchset",
"total": 1,
"link": [ {
"relation": "self",
"url": "http://hapi.fhir.org/baseR4/Condition?patient=06e1f0dd-5fbe-4480-9bb4-6b54ec02d31b&clinical-status=active,recurrance,remission"
} ],
"entry": [ {
"fullUrl": "http://hapi.fhir.org/baseR4/Condition/4ac41715-fcbd-421c-8796-9b2c9706dd3f",
"resource": {
"resourceType": "Condition",
"id": "4ac41715-fcbd-421c-8796-9b2c9706dd3f",
"meta": {
"versionId": "10",
"lastUpdated": "2020-04-28T20:28:00.008+00:00",
"source": "#cabiJIK51sD2iz4N",
"profile": [ "http://hl7.org/fhir/us/core/StructureDefinition/us-core-condition" ]
},
"clinicalStatus": {
"coding": [ {
"system": "http://terminology.hl7.org/CodeSystem/condition-clinical",
"code": "active"
} ]
},
"verificationStatus": {
"coding": [ {
"system": "http://terminology.hl7.org/CodeSystem/condition-ver-status",
"code": "confirmed"
} ]
},
"category": [ {
"coding": [ {
"system": "http://terminology.hl7.org/CodeSystem/condition-category",
"code": "encounter-diagnosis",
"display": "Encounter Diagnosis"
} ]
} ],
"code": {
"coding": [ {
"system": "http://snomed.info/sct",
"code": "1234",
"display": "Examplitis"
} ],
"text": "Examplitis"
},
"subject": {
"reference": "https://example.org/Patient/06e1f0dd-5fbe-4480-9bb4-6b54ec02d31b"
},
"encounter": {
"reference": "https://example.org/Encounter/5fe62cd5-bfcf-4d3b-a1e9-80d6f75d6f82"
},
"onsetDateTime": "2018-10-21T21:22:15-07:00",
"recordedDate": "2018-10-21T21:22:15-07:00"
},
"search": {
"mode": "match"
}
} ]
}
'''
searchset_bundle = loads(searchset_bundle) #convert to Python object
searchset_bundle_id = searchset_bundle.pop("id") # remove id
searchset_bundle_meta = searchset_bundle.pop("meta") # remove meta
payload = canonicalize(searchset_bundle)
payload
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":"1234","display":"Examplitis","system":"http://snomed.info/sct"}],"text":"Examplitis"},"encounter":{"reference":"https://example.org/Encounter/5fe62cd5-bfcf-4d3b-a1e9-80d6f75d6f82"},"id":"4ac41715-fcbd-421c-8796-9b2c9706dd3f","meta":{"lastUpdated":"2020-04-28T20:28:00.008+00:00","profile":["http://hl7.org/fhir/us/core/StructureDefinition/us-core-condition"],"source":"#cabiJIK51sD2iz4N","versionId":"10"},"onsetDateTime":"2018-10-21T21:22:15-07:00","recordedDate":"2018-10-21T21:22:15-07:00","resourceType":"Condition","subject":{"reference":"https://example.org/Patient/06e1f0dd-5fbe-4480-9bb4-6b54ec02d31b"},"verificationStatus":{"coding":[{"code":"confirmed","system":"http://terminology.hl7.org/CodeSystem/condition-ver-status"}]}},"search":{"mode":"match"}}],"link":[{"relation":"self","url":"http://hapi.fhir.org/baseR4/Condition?patient=06e1f0dd-5fbe-4480-9bb4-6b54ec02d31b&clinical-status=active,recurrance,remission"}],"resourceType":"Bundle","total":1,"type":"searchset"}'
3.3 Create Signature using private key and the RS256 algorithm to get the JWS compact serialization format
note the signature is displayed with the parts labeled and separated with line breaks for easier viewing.
from jose import jws
with open('private-key.pem') as f:
private_key = (f.read())
signature = jws.sign(payload,private_key,algorithm='RS256',headers=header)
labels = ['header', 'payload', 'signature']
for i,j in enumerate(signature.split('.')):
print(f'{labels[i]}:')
print(f'{j}')
print()
header: eyJhbGciOiJSUzI1NiIsImt0eSI6IlJTIiwidHlwIjoiSldUIiwieDVjIjpbIk1JSUUzekNDQTBlZ0F3SUJBZ0lKQU9LRll2TXdSK3lRTUEwR0NTcUdTSWIzRFFFQkN3VUFNSUdOTVFzd0NRWURWUVFHRXdKVlV6RVRNQkVHQTFVRUNBd0tRMkZzYVdadmNtNXBZVEVTTUJBR0ExVUVCd3dKVTJGMWMyRnNhWFJ2TVJVd0V3WURWUVFLREF4SVpXRnNkR2hsUkdGMFlURXhGekFWQmdOVkJBTU1Ea1Z5YVdNZ1NHRmhjeXdnUkZaTk1TVXdJd1lKS29aSWh2Y05BUWtCRmhabGFHRmhjMEJvWldGc2RHaGxaR0YwWVRFdWIzSm5NQjRYRFRJeE1UQXlOekUzTkRJd05Gb1hEVEl5TVRBeU1qRTNOREl3TkZvd2dZMHhDekFKQmdOVkJBWVRBbFZUTVJNd0VRWURWUVFJREFwRFlXeHBabTl5Ym1saE1SSXdFQVlEVlFRSERBbFRZWFZ6WVd4cGRHOHhGVEFUQmdOVkJBb01ERWhsWVd4MGFHVkVZWFJoTVRFWE1CVUdBMVVFQXd3T1JYSnBZeUJJWVdGekxDQkVWazB4SlRBakJna3Foa2lHOXcwQkNRRVdGbVZvWVdGelFHaGxZV3gwYUdWa1lYUmhNUzV2Y21jd2dnR2lNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJqd0F3Z2dHS0FvSUJnUURwS2NTa29BTTZzVzIxK3ZXVGVJVk9HeDEwTVdhc1F5N1ZIaWQ2enlxWEFCTSt6bmZCblhlbnlVMGoxRlR2UG1SZk9Eb09EWFZ1UFV3RG9taENIaCtiY2xXOUtNMm81NjNjeFJLRXZCbmFIcnNqdzV5Tm14TzVZakVSYmh0SGRRZXFrdGR3M1ZZRVJSOUhveExPM0Zrc3pSMjkySFRCNHhXM3lXbFYzZ1RrTVFvelBTY0pLSDNiRzhQcXE2QVlQSjdDNFlCSWxVU2RCTVZsM3FuZUVmZzdmdXhpRmZYb2ZkVFZtN3JNaWlHN1g5ejQzUGZpbHFhZWlzZm10UnhBbFJ3RU5YckgzT3ZPRFB5TDByVG5HOENzYkFYWVZJTW1kZEhlNFpGOXBsaDk1c2o0cE1UaEx0Y0pYL285WEhMamg3RW1aeWdKSFdFUXE0UHdGd1pkbWJjZmhDbU9yODhIOEJiVXJ1LzdWNnpic0cxTjFDV2xuZGxiVnpuTCszSU1PcjhrWGFIY2FucWZja2dGVjRFcm5makZKcTFPSWFBbXNNajg1eE1ranlYTHljTEwvdTVuMm82Qmc5My9VUmZxdU9vU0lHT0NSMjVEYVp6cHcyazNzN29FOWRNd0VXWHRmWGdZdGgyYmxqeTV0RkgwR2pwT2t4MDdqN1pUNUhueG5sc0NBd0VBQWFOQU1ENHdEQVlEVlIwVEJBVXdBd0VCL3pBTEJnTlZIUThFQkFNQ0JlQXdJUVlEVlIwUkJCb3dHSUlXZDNkM0xtaGxZV3gwYUdWa1lYUmhhVzVqTG1OdmJUQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FZRUFDdU1VTnE5YXkrK2U1WUM3UUZPOTRyZnp4R1FuRjNHa2xaTkFYbUlyN1BWR2RpR1kyR1R4LzlSdEhDd1RLemtMK3l2S29qZVo5ZFZLOHdyR1ZpUmtPL2pVeVorS2NXUm9rVWpzNTluY0pHUk1TU1J4dGVDUXVqdDRoZjIrL3FWK2Yyc01RdEVyd1BFMzB2YnFSWVVOTk5CVkVRcGFReC9hY0pEVXY5djdzakhpSkRxWHdRK3J6ajk1aUhBSWFlRUhxRi9NczIycDJiZVp1cXZJUUtlTWwrc3ZWcUh0aXV6V25GNFU2VkltcGtyNGJIbDdlZ1Y5SDZsNlQyU01rajZxRFU1ZTlOZzBabExUdG9zc2hCTG1vcEY3ZTdIeXJURUFtZk9QS1FlMEVnOUUydXJ6eHFCdUc1NGs1MEcySjBGaVBzUUpBaEZpTkd3U2c0UzNIeVZERzd1ZUtkMEw5M3dLT05PWUd2TUtpekNIQitwS3ZFTUpvWjh5OXVpQitIRlhjcDlSYUpxSjk3SHBaVEV2K2xpQ3AyUFNYemNLMHIyNVNjeWpGNmRMb3VLMlNCMzB4QXZKOHRFNTg0K2pxUTZDR2VjVTlYanZsQWp1SmRDckRlVlBzamtuN09QWEcrOFhaVTd6cUhaTm1YWDFZWTRINXJnRUo0OGxyVXJQM0k4UiJdfQ payload: eyJlbnRyeSI6W3siZnVsbFVybCI6Imh0dHA6Ly9oYXBpLmZoaXIub3JnL2Jhc2VSNC9Db25kaXRpb24vNGFjNDE3MTUtZmNiZC00MjFjLTg3OTYtOWIyYzk3MDZkZDNmIiwicmVzb3VyY2UiOnsiY2F0ZWdvcnkiOlt7ImNvZGluZyI6W3siY29kZSI6ImVuY291bnRlci1kaWFnbm9zaXMiLCJkaXNwbGF5IjoiRW5jb3VudGVyIERpYWdub3NpcyIsInN5c3RlbSI6Imh0dHA6Ly90ZXJtaW5vbG9neS5obDcub3JnL0NvZGVTeXN0ZW0vY29uZGl0aW9uLWNhdGVnb3J5In1dfV0sImNsaW5pY2FsU3RhdHVzIjp7ImNvZGluZyI6W3siY29kZSI6ImFjdGl2ZSIsInN5c3RlbSI6Imh0dHA6Ly90ZXJtaW5vbG9neS5obDcub3JnL0NvZGVTeXN0ZW0vY29uZGl0aW9uLWNsaW5pY2FsIn1dfSwiY29kZSI6eyJjb2RpbmciOlt7ImNvZGUiOiIxMjM0IiwiZGlzcGxheSI6IkV4YW1wbGl0aXMiLCJzeXN0ZW0iOiJodHRwOi8vc25vbWVkLmluZm8vc2N0In1dLCJ0ZXh0IjoiRXhhbXBsaXRpcyJ9LCJlbmNvdW50ZXIiOnsicmVmZXJlbmNlIjoiaHR0cHM6Ly9leGFtcGxlLm9yZy9FbmNvdW50ZXIvNWZlNjJjZDUtYmZjZi00ZDNiLWExZTktODBkNmY3NWQ2ZjgyIn0sImlkIjoiNGFjNDE3MTUtZmNiZC00MjFjLTg3OTYtOWIyYzk3MDZkZDNmIiwibWV0YSI6eyJsYXN0VXBkYXRlZCI6IjIwMjAtMDQtMjhUMjA6Mjg6MDAuMDA4KzAwOjAwIiwicHJvZmlsZSI6WyJodHRwOi8vaGw3Lm9yZy9maGlyL3VzL2NvcmUvU3RydWN0dXJlRGVmaW5pdGlvbi91cy1jb3JlLWNvbmRpdGlvbiJdLCJzb3VyY2UiOiIjY2FiaUpJSzUxc0QyaXo0TiIsInZlcnNpb25JZCI6IjEwIn0sIm9uc2V0RGF0ZVRpbWUiOiIyMDE4LTEwLTIxVDIxOjIyOjE1LTA3OjAwIiwicmVjb3JkZWREYXRlIjoiMjAxOC0xMC0yMVQyMToyMjoxNS0wNzowMCIsInJlc291cmNlVHlwZSI6IkNvbmRpdGlvbiIsInN1YmplY3QiOnsicmVmZXJlbmNlIjoiaHR0cHM6Ly9leGFtcGxlLm9yZy9QYXRpZW50LzA2ZTFmMGRkLTVmYmUtNDQ4MC05YmI0LTZiNTRlYzAyZDMxYiJ9LCJ2ZXJpZmljYXRpb25TdGF0dXMiOnsiY29kaW5nIjpbeyJjb2RlIjoiY29uZmlybWVkIiwic3lzdGVtIjoiaHR0cDovL3Rlcm1pbm9sb2d5LmhsNy5vcmcvQ29kZVN5c3RlbS9jb25kaXRpb24tdmVyLXN0YXR1cyJ9XX19LCJzZWFyY2giOnsibW9kZSI6Im1hdGNoIn19XSwibGluayI6W3sicmVsYXRpb24iOiJzZWxmIiwidXJsIjoiaHR0cDovL2hhcGkuZmhpci5vcmcvYmFzZVI0L0NvbmRpdGlvbj9wYXRpZW50PTA2ZTFmMGRkLTVmYmUtNDQ4MC05YmI0LTZiNTRlYzAyZDMxYiZjbGluaWNhbC1zdGF0dXM9YWN0aXZlLHJlY3VycmFuY2UscmVtaXNzaW9uIn1dLCJyZXNvdXJjZVR5cGUiOiJCdW5kbGUiLCJ0b3RhbCI6MSwidHlwZSI6InNlYXJjaHNldCJ9 signature: rE5gfhbdbkmuYpKPb87Tpg1nRdRJTyNfWAOmXR2AA63FGKz2br_aAFtXj2UwIVHjp_AmgOZrpKmUFZnibBRcRTBUVfPWVrgRHleP1Dd1QL2qiaz0Pxw38odIVKQw88pFXBfIASsnrFMEJ_x07XQLWaXLOcEYVBb2s1SoULIW_McJCeCVKEnhrrsmNhXvAHLxYm2y8lUdTYYMH7rCM2FEIglavxLA4QI1nPv5i5ZwSOZDI1OoPtK4dHbbvggsKnAtBJL890AJ7JD9h1QTmw8vSWjydCBNilgGiyffPmfSGXFvGQ9tEcETHW0NlUEF649Zt-k71aMhkjooCsRwM9Dmb4STqO7Fy0MzWbvdi6K46W_rf77gv75Xr_cQyvSubWumRTMompgG1qOz5LbClfKHoWWyIzBxM2u7wqBukJTAIm10DSDgFg79-5oLPIDOj19VYsnLcyYFdYIx2G3gkBhcbExDdytlKGIZ8YvIEojDfNibC3wLWwNvmptBww-hPdT7
3.4. Create detached payload by removing the payload from the JWS
note the signature is displayed with the parts labeled and separated with line breaks for easier viewing then as compact serialization format
split_sig = signature.split('.')
split_sig[1] = ''
signature = '.'.join(split_sig)
for i,j in enumerate(signature.split('.')):
print(f'{labels[i]}:')
print(f'{j}')
print()
print(f'\nSignature in compact serialization format:\n{"="*80}\n{signature}')
header: eyJhbGciOiJSUzI1NiIsImt0eSI6IlJTIiwidHlwIjoiSldUIiwieDVjIjpbIk1JSUUzekNDQTBlZ0F3SUJBZ0lKQU9LRll2TXdSK3lRTUEwR0NTcUdTSWIzRFFFQkN3VUFNSUdOTVFzd0NRWURWUVFHRXdKVlV6RVRNQkVHQTFVRUNBd0tRMkZzYVdadmNtNXBZVEVTTUJBR0ExVUVCd3dKVTJGMWMyRnNhWFJ2TVJVd0V3WURWUVFLREF4SVpXRnNkR2hsUkdGMFlURXhGekFWQmdOVkJBTU1Ea1Z5YVdNZ1NHRmhjeXdnUkZaTk1TVXdJd1lKS29aSWh2Y05BUWtCRmhabGFHRmhjMEJvWldGc2RHaGxaR0YwWVRFdWIzSm5NQjRYRFRJeE1UQXlOekUzTkRJd05Gb1hEVEl5TVRBeU1qRTNOREl3TkZvd2dZMHhDekFKQmdOVkJBWVRBbFZUTVJNd0VRWURWUVFJREFwRFlXeHBabTl5Ym1saE1SSXdFQVlEVlFRSERBbFRZWFZ6WVd4cGRHOHhGVEFUQmdOVkJBb01ERWhsWVd4MGFHVkVZWFJoTVRFWE1CVUdBMVVFQXd3T1JYSnBZeUJJWVdGekxDQkVWazB4SlRBakJna3Foa2lHOXcwQkNRRVdGbVZvWVdGelFHaGxZV3gwYUdWa1lYUmhNUzV2Y21jd2dnR2lNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJqd0F3Z2dHS0FvSUJnUURwS2NTa29BTTZzVzIxK3ZXVGVJVk9HeDEwTVdhc1F5N1ZIaWQ2enlxWEFCTSt6bmZCblhlbnlVMGoxRlR2UG1SZk9Eb09EWFZ1UFV3RG9taENIaCtiY2xXOUtNMm81NjNjeFJLRXZCbmFIcnNqdzV5Tm14TzVZakVSYmh0SGRRZXFrdGR3M1ZZRVJSOUhveExPM0Zrc3pSMjkySFRCNHhXM3lXbFYzZ1RrTVFvelBTY0pLSDNiRzhQcXE2QVlQSjdDNFlCSWxVU2RCTVZsM3FuZUVmZzdmdXhpRmZYb2ZkVFZtN3JNaWlHN1g5ejQzUGZpbHFhZWlzZm10UnhBbFJ3RU5YckgzT3ZPRFB5TDByVG5HOENzYkFYWVZJTW1kZEhlNFpGOXBsaDk1c2o0cE1UaEx0Y0pYL285WEhMamg3RW1aeWdKSFdFUXE0UHdGd1pkbWJjZmhDbU9yODhIOEJiVXJ1LzdWNnpic0cxTjFDV2xuZGxiVnpuTCszSU1PcjhrWGFIY2FucWZja2dGVjRFcm5makZKcTFPSWFBbXNNajg1eE1ranlYTHljTEwvdTVuMm82Qmc5My9VUmZxdU9vU0lHT0NSMjVEYVp6cHcyazNzN29FOWRNd0VXWHRmWGdZdGgyYmxqeTV0RkgwR2pwT2t4MDdqN1pUNUhueG5sc0NBd0VBQWFOQU1ENHdEQVlEVlIwVEJBVXdBd0VCL3pBTEJnTlZIUThFQkFNQ0JlQXdJUVlEVlIwUkJCb3dHSUlXZDNkM0xtaGxZV3gwYUdWa1lYUmhhVzVqTG1OdmJUQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FZRUFDdU1VTnE5YXkrK2U1WUM3UUZPOTRyZnp4R1FuRjNHa2xaTkFYbUlyN1BWR2RpR1kyR1R4LzlSdEhDd1RLemtMK3l2S29qZVo5ZFZLOHdyR1ZpUmtPL2pVeVorS2NXUm9rVWpzNTluY0pHUk1TU1J4dGVDUXVqdDRoZjIrL3FWK2Yyc01RdEVyd1BFMzB2YnFSWVVOTk5CVkVRcGFReC9hY0pEVXY5djdzakhpSkRxWHdRK3J6ajk1aUhBSWFlRUhxRi9NczIycDJiZVp1cXZJUUtlTWwrc3ZWcUh0aXV6V25GNFU2VkltcGtyNGJIbDdlZ1Y5SDZsNlQyU01rajZxRFU1ZTlOZzBabExUdG9zc2hCTG1vcEY3ZTdIeXJURUFtZk9QS1FlMEVnOUUydXJ6eHFCdUc1NGs1MEcySjBGaVBzUUpBaEZpTkd3U2c0UzNIeVZERzd1ZUtkMEw5M3dLT05PWUd2TUtpekNIQitwS3ZFTUpvWjh5OXVpQitIRlhjcDlSYUpxSjk3SHBaVEV2K2xpQ3AyUFNYemNLMHIyNVNjeWpGNmRMb3VLMlNCMzB4QXZKOHRFNTg0K2pxUTZDR2VjVTlYanZsQWp1SmRDckRlVlBzamtuN09QWEcrOFhaVTd6cUhaTm1YWDFZWTRINXJnRUo0OGxyVXJQM0k4UiJdfQ payload: signature: rE5gfhbdbkmuYpKPb87Tpg1nRdRJTyNfWAOmXR2AA63FGKz2br_aAFtXj2UwIVHjp_AmgOZrpKmUFZnibBRcRTBUVfPWVrgRHleP1Dd1QL2qiaz0Pxw38odIVKQw88pFXBfIASsnrFMEJ_x07XQLWaXLOcEYVBb2s1SoULIW_McJCeCVKEnhrrsmNhXvAHLxYm2y8lUdTYYMH7rCM2FEIglavxLA4QI1nPv5i5ZwSOZDI1OoPtK4dHbbvggsKnAtBJL890AJ7JD9h1QTmw8vSWjydCBNilgGiyffPmfSGXFvGQ9tEcETHW0NlUEF649Zt-k71aMhkjooCsRwM9Dmb4STqO7Fy0MzWbvdi6K46W_rf77gv75Xr_cQyvSubWumRTMompgG1qOz5LbClfKHoWWyIzBxM2u7wqBukJTAIm10DSDgFg79-5oLPIDOj19VYsnLcyYFdYIx2G3gkBhcbExDdytlKGIZ8YvIEojDfNibC3wLWwNvmptBww-hPdT7 Signature in compact serialization format: ================================================================================ eyJhbGciOiJSUzI1NiIsImt0eSI6IlJTIiwidHlwIjoiSldUIiwieDVjIjpbIk1JSUUzekNDQTBlZ0F3SUJBZ0lKQU9LRll2TXdSK3lRTUEwR0NTcUdTSWIzRFFFQkN3VUFNSUdOTVFzd0NRWURWUVFHRXdKVlV6RVRNQkVHQTFVRUNBd0tRMkZzYVdadmNtNXBZVEVTTUJBR0ExVUVCd3dKVTJGMWMyRnNhWFJ2TVJVd0V3WURWUVFLREF4SVpXRnNkR2hsUkdGMFlURXhGekFWQmdOVkJBTU1Ea1Z5YVdNZ1NHRmhjeXdnUkZaTk1TVXdJd1lKS29aSWh2Y05BUWtCRmhabGFHRmhjMEJvWldGc2RHaGxaR0YwWVRFdWIzSm5NQjRYRFRJeE1UQXlOekUzTkRJd05Gb1hEVEl5TVRBeU1qRTNOREl3TkZvd2dZMHhDekFKQmdOVkJBWVRBbFZUTVJNd0VRWURWUVFJREFwRFlXeHBabTl5Ym1saE1SSXdFQVlEVlFRSERBbFRZWFZ6WVd4cGRHOHhGVEFUQmdOVkJBb01ERWhsWVd4MGFHVkVZWFJoTVRFWE1CVUdBMVVFQXd3T1JYSnBZeUJJWVdGekxDQkVWazB4SlRBakJna3Foa2lHOXcwQkNRRVdGbVZvWVdGelFHaGxZV3gwYUdWa1lYUmhNUzV2Y21jd2dnR2lNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJqd0F3Z2dHS0FvSUJnUURwS2NTa29BTTZzVzIxK3ZXVGVJVk9HeDEwTVdhc1F5N1ZIaWQ2enlxWEFCTSt6bmZCblhlbnlVMGoxRlR2UG1SZk9Eb09EWFZ1UFV3RG9taENIaCtiY2xXOUtNMm81NjNjeFJLRXZCbmFIcnNqdzV5Tm14TzVZakVSYmh0SGRRZXFrdGR3M1ZZRVJSOUhveExPM0Zrc3pSMjkySFRCNHhXM3lXbFYzZ1RrTVFvelBTY0pLSDNiRzhQcXE2QVlQSjdDNFlCSWxVU2RCTVZsM3FuZUVmZzdmdXhpRmZYb2ZkVFZtN3JNaWlHN1g5ejQzUGZpbHFhZWlzZm10UnhBbFJ3RU5YckgzT3ZPRFB5TDByVG5HOENzYkFYWVZJTW1kZEhlNFpGOXBsaDk1c2o0cE1UaEx0Y0pYL285WEhMamg3RW1aeWdKSFdFUXE0UHdGd1pkbWJjZmhDbU9yODhIOEJiVXJ1LzdWNnpic0cxTjFDV2xuZGxiVnpuTCszSU1PcjhrWGFIY2FucWZja2dGVjRFcm5makZKcTFPSWFBbXNNajg1eE1ranlYTHljTEwvdTVuMm82Qmc5My9VUmZxdU9vU0lHT0NSMjVEYVp6cHcyazNzN29FOWRNd0VXWHRmWGdZdGgyYmxqeTV0RkgwR2pwT2t4MDdqN1pUNUhueG5sc0NBd0VBQWFOQU1ENHdEQVlEVlIwVEJBVXdBd0VCL3pBTEJnTlZIUThFQkFNQ0JlQXdJUVlEVlIwUkJCb3dHSUlXZDNkM0xtaGxZV3gwYUdWa1lYUmhhVzVqTG1OdmJUQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FZRUFDdU1VTnE5YXkrK2U1WUM3UUZPOTRyZnp4R1FuRjNHa2xaTkFYbUlyN1BWR2RpR1kyR1R4LzlSdEhDd1RLemtMK3l2S29qZVo5ZFZLOHdyR1ZpUmtPL2pVeVorS2NXUm9rVWpzNTluY0pHUk1TU1J4dGVDUXVqdDRoZjIrL3FWK2Yyc01RdEVyd1BFMzB2YnFSWVVOTk5CVkVRcGFReC9hY0pEVXY5djdzakhpSkRxWHdRK3J6ajk1aUhBSWFlRUhxRi9NczIycDJiZVp1cXZJUUtlTWwrc3ZWcUh0aXV6V25GNFU2VkltcGtyNGJIbDdlZ1Y5SDZsNlQyU01rajZxRFU1ZTlOZzBabExUdG9zc2hCTG1vcEY3ZTdIeXJURUFtZk9QS1FlMEVnOUUydXJ6eHFCdUc1NGs1MEcySjBGaVBzUUpBaEZpTkd3U2c0UzNIeVZERzd1ZUtkMEw5M3dLT05PWUd2TUtpekNIQitwS3ZFTUpvWjh5OXVpQitIRlhjcDlSYUpxSjk3SHBaVEV2K2xpQ3AyUFNYemNLMHIyNVNjeWpGNmRMb3VLMlNCMzB4QXZKOHRFNTg0K2pxUTZDR2VjVTlYanZsQWp1SmRDckRlVlBzamtuN09QWEcrOFhaVTd6cUhaTm1YWDFZWTRINXJnRUo0OGxyVXJQM0k4UiJdfQ..rE5gfhbdbkmuYpKPb87Tpg1nRdRJTyNfWAOmXR2AA63FGKz2br_aAFtXj2UwIVHjp_AmgOZrpKmUFZnibBRcRTBUVfPWVrgRHleP1Dd1QL2qiaz0Pxw38odIVKQw88pFXBfIASsnrFMEJ_x07XQLWaXLOcEYVBb2s1SoULIW_McJCeCVKEnhrrsmNhXvAHLxYm2y8lUdTYYMH7rCM2FEIglavxLA4QI1nPv5i5ZwSOZDI1OoPtK4dHbbvggsKnAtBJL890AJ7JD9h1QTmw8vSWjydCBNilgGiyffPmfSGXFvGQ9tEcETHW0NlUEF649Zt-k71aMhkjooCsRwM9Dmb4STqO7Fy0MzWbvdi6K46W_rf77gv75Xr_cQyvSubWumRTMompgG1qOz5LbClfKHoWWyIzBxM2u7wqBukJTAIm10DSDgFg79-5oLPIDOj19VYsnLcyYFdYIx2G3gkBhcbExDdytlKGIZ8YvIEojDfNibC3wLWwNvmptBww-hPdT7
4. base64 the JWS and add the Signature element to the Bundle
this is what would be returned in response to a direct query over-the-wire
from base64 import b64encode
from json import loads,dumps
b64_jws = b64encode(signature.encode()).decode()
sig_element = {
"type": [ # Signature.type = Verification Signature
{
"system": "urn:iso-astm:E1762-95:2013",
"code": "1.2.840.10065.1.12.1.5",
"display": "Verification Signature"
}
],
"when": "2021-10-05T22:42:19-07:00", #system timestamp when signature created
"who": { #Reference to the Organization who signed the Bundle
"reference": "Organization/123"
},
"data": b64_jws,
}
searchset_bundle = loads(payload)
searchset_bundle['id'] = searchset_bundle_id # add id back in
searchset_bundle['meta'] = searchset_bundle_meta # add meta back in
searchset_bundle['signature'] = sig_element
print(dumps(searchset_bundle, indent=2))
{ "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": "1234", "display": "Examplitis", "system": "http://snomed.info/sct" } ], "text": "Examplitis" }, "encounter": { "reference": "https://example.org/Encounter/5fe62cd5-bfcf-4d3b-a1e9-80d6f75d6f82" }, "id": "4ac41715-fcbd-421c-8796-9b2c9706dd3f", "meta": { "lastUpdated": "2020-04-28T20:28:00.008+00:00", "profile": [ "http://hl7.org/fhir/us/core/StructureDefinition/us-core-condition" ], "source": "#cabiJIK51sD2iz4N", "versionId": "10" }, "onsetDateTime": "2018-10-21T21:22:15-07:00", "recordedDate": "2018-10-21T21:22:15-07:00", "resourceType": "Condition", "subject": { "reference": "https://example.org/Patient/06e1f0dd-5fbe-4480-9bb4-6b54ec02d31b" }, "verificationStatus": { "coding": [ { "code": "confirmed", "system": "http://terminology.hl7.org/CodeSystem/condition-ver-status" } ] } }, "search": { "mode": "match" } } ], "link": [ { "relation": "self", "url": "http://hapi.fhir.org/baseR4/Condition?patient=06e1f0dd-5fbe-4480-9bb4-6b54ec02d31b&clinical-status=active,recurrance,remission" } ], "resourceType": "Bundle", "total": 1, "type": "searchset", "id": "d88e2910-3c95-469d-b1f4-ab5553b471fb", "meta": { "lastUpdated": "2020-10-23T04:54:56.048+00:00" }, "signature": { "type": [ { "system": "urn:iso-astm:E1762-95:2013", "code": "1.2.840.10065.1.12.1.5", "display": "Verification Signature" } ], "when": "2021-10-05T22:42:19-07:00", "who": { "reference": "Organization/123" }, "data": "ZXlKaGJHY2lPaUpTVXpJMU5pSXNJbXQwZVNJNklsSlRJaXdpZEhsd0lqb2lTbGRVSWl3aWVEVmpJanBiSWsxSlNVVXpla05EUVRCbFowRjNTVUpCWjBsS1FVOUxSbGwyVFhkU0szbFJUVUV3UjBOVGNVZFRTV0l6UkZGRlFrTjNWVUZOU1VkT1RWRnpkME5SV1VSV1VWRkhSWGRLVmxWNlJWUk5Ra1ZIUVRGVlJVTkJkMHRSTWtaellWZGFkbU50TlhCWlZFVlRUVUpCUjBFeFZVVkNkM2RLVlRKR01XTXlSbk5oV0ZKMlRWSlZkMFYzV1VSV1VWRkxSRUY0U1ZwWFJuTmtSMmhzVWtkR01GbFVSWGhHZWtGV1FtZE9Wa0pCVFUxRWExWjVZVmROWjFOSFJtaGplWGRuVWtaYVRrMVRWWGRKZDFsS1MyOWFTV2gyWTA1QlVXdENSbWhhYkdGSFJtaGpNRUp2V2xkR2MyUkhhR3hhUjBZd1dWUkZkV0l6U201TlFqUllSRlJKZUUxVVFYbE9la1V6VGtSSmQwNUdiMWhFVkVsNVRWUkJlVTFxUlROT1JFbDNUa1p2ZDJkWk1IaERla0ZLUW1kT1ZrSkJXVlJCYkZaVVRWSk5kMFZSV1VSV1VWRkpSRUZ3UkZsWGVIQmFiVGw1WW0xc2FFMVNTWGRGUVZsRVZsRlJTRVJCYkZSWldGWjZXVmQ0Y0dSSE9IaEdWRUZVUW1kT1ZrSkJiMDFFUldoc1dWZDRNR0ZIVmtWWldGSm9UVlJGV0UxQ1ZVZEJNVlZGUVhkM1QxSllTbkJaZVVKSldWZEdla3hEUWtWV2F6QjRTbFJCYWtKbmEzRm9hMmxIT1hjd1FrTlJSVmRHYlZadldWZEdlbEZIYUd4WlYzZ3dZVWRXYTFsWVVtaE5VelYyWTIxamQyZG5SMmxOUVRCSFExTnhSMU5KWWpORVVVVkNRVkZWUVVFMFNVSnFkMEYzWjJkSFMwRnZTVUpuVVVSd1MyTlRhMjlCVFRaelZ6SXhLM1pYVkdWSlZrOUhlREV3VFZkaGMxRjVOMVpJYVdRMmVubHhXRUZDVFN0NmJtWkNibGhsYm5sVk1Hb3hSbFIyVUcxU1prOUViMDlFV0ZaMVVGVjNSRzl0YUVOSWFDdGlZMnhYT1V0Tk1tODFOak5qZUZKTFJYWkNibUZJY25OcWR6VjVUbTE0VHpWWmFrVlNZbWgwU0dSUlpYRnJkR1IzTTFaWlJWSlNPVWh2ZUV4UE0wWnJjM3BTTWpreVNGUkNOSGhYTTNsWGJGWXpaMVJyVFZGdmVsQlRZMHBMU0ROaVJ6aFFjWEUyUVZsUVNqZERORmxDU1d4VlUyUkNUVlpzTTNGdVpVVm1aemRtZFhocFJtWlliMlprVkZadE4zSk5hV2xITjFnNWVqUXpVR1pwYkhGaFpXbHpabTEwVW5oQmJGSjNSVTVZY2tnelQzWlBSRkI1VERCeVZHNUhPRU56WWtGWVdWWkpUVzFrWkVobE5GcEdPWEJzYURrMWMybzBjRTFVYUV4MFkwcFlMMjg1V0VoTWFtZzNSVzFhZVdkS1NGZEZVWEUwVUhkR2QxcGtiV0pqWm1oRGJVOXlPRGhJT0VKaVZYSjFMemRXTm5waWMwY3hUakZEVjJ4dVpHeGlWbnB1VENzelNVMVBjamhyV0dGSVkyRnVjV1pqYTJkR1ZqUkZjbTVtYWtaS2NURlBTV0ZCYlhOTmFqZzFlRTFyYW5sWVRIbGpURXd2ZFRWdU1tODJRbWM1TXk5VlVtWnhkVTl2VTBsSFQwTlNNalZFWVZwNmNIY3lhek56TjI5Rk9XUk5kMFZYV0hSbVdHZFpkR2d5WW14cWVUVjBSa2d3UjJwd1QydDRNRGRxTjFwVU5VaHVlRzVzYzBOQmQwVkJRV0ZPUVUxRU5IZEVRVmxFVmxJd1ZFSkJWWGRCZDBWQ0wzcEJURUpuVGxaSVVUaEZRa0ZOUTBKbFFYZEpVVmxFVmxJd1VrSkNiM2RIU1VsWFpETmtNMHh0YUd4WlYzZ3dZVWRXYTFsWVVtaGhWelZxVEcxT2RtSlVRVTVDWjJ0eGFHdHBSemwzTUVKQlVYTkdRVUZQUTBGWlJVRkRkVTFWVG5FNVlYa3JLMlUxV1VNM1VVWlBPVFJ5Wm5wNFIxRnVSak5IYTJ4YVRrRlliVWx5TjFCV1IyUnBSMWt5UjFSNEx6bFNkRWhEZDFSTGVtdE1LM2wyUzI5cVpWbzVaRlpMT0hkeVIxWnBVbXRQTDJwVmVWb3JTMk5YVW05clZXcHpOVGx1WTBwSFVrMVRVMUo0ZEdWRFVYVnFkRFJvWmpJckwzRldLMll5YzAxUmRFVnlkMUJGTXpCMlluRlNXVlZPVGs1Q1ZrVlJjR0ZSZUM5aFkwcEVWWFk1ZGpkemFraHBTa1J4V0hkUkszSjZhamsxYVVoQlNXRmxSVWh4Umk5TmN6SXljREppWlZwMWNYWkpVVXRsVFd3cmMzWldjVWgwYVhWNlYyNUdORlUyVmtsdGNHdHlOR0pJYkRkbFoxWTVTRFpzTmxReVUwMXJhalp4UkZVMVpUbE9aekJhYkV4VWRHOXpjMmhDVEcxdmNFWTNaVGRJZVhKVVJVRnRaazlRUzFGbE1FVm5PVVV5ZFhKNmVIRkNkVWMxTkdzMU1FY3lTakJHYVZCelVVcEJhRVpwVGtkM1UyYzBVek5JZVZaRVJ6ZDFaVXRrTUV3NU0zZExUMDVQV1VkMlRVdHBla05JUWl0d1MzWkZUVXB2V2poNU9YVnBRaXRJUmxoamNEbFNZVXB4U2prM1NIQmFWRVYySzJ4cFEzQXlVRk5ZZW1OTE1ISXlOVk5qZVdwR05tUk1iM1ZMTWxOQ016QjRRWFpLT0hSRk5UZzBLMnB4VVRaRFIyVmpWVGxZYW5ac1FXcDFTbVJEY2tSbFZsQnphbXR1TjA5UVdFY3JPRmhhVlRkNmNVaGFUbTFZV0RGWldUUklOWEpuUlVvME9HeHlWWEpRTTBrNFVpSmRmUS4uckU1Z2ZoYmRia211WXBLUGI4N1RwZzFuUmRSSlR5TmZXQU9tWFIyQUE2M0ZHS3oyYnJfYUFGdFhqMlV3SVZIanBfQW1nT1pycEttVUZabmliQlJjUlRCVVZmUFdWcmdSSGxlUDFEZDFRTDJxaWF6MFB4dzM4b2RJVktRdzg4cEZYQmZJQVNzbnJGTUVKX3gwN1hRTFdhWExPY0VZVkJiMnMxU29VTElXX01jSkNlQ1ZLRW5ocnJzbU5oWHZBSEx4WW0yeThsVWRUWVlNSDdyQ00yRkVJZ2xhdnhMQTRRSTFuUHY1aTVad1NPWkRJMU9vUHRLNGRIYmJ2Z2dzS25BdEJKTDg5MEFKN0pEOWgxUVRtdzh2U1dqeWRDQk5pbGdHaXlmZlBtZlNHWEZ2R1E5dEVjRVRIVzBObFVFRjY0OVp0LWs3MWFNaGtqb29Dc1J3TTlEbWI0U1RxTzdGeTBNeldidmRpNks0NldfcmY3N2d2NzVYcl9jUXl2U3ViV3VtUlRNb21wZ0cxcU96NUxiQ2xmS0hvV1d5SXpCeE0ydTd3cUJ1a0pUQUltMTBEU0RnRmc3OS01b0xQSURPajE5VllzbkxjeVlGZFlJeDJHM2drQmhjYkV4RGR5dGxLR0laOFl2SUVvakRmTmliQzN3TFd3TnZtcHRCd3ctaFBkVDc=" } }
1. Remove the Bundle.signature
element from the Search Bundle resource
try:
recd_signature = searchset_bundle.pop("signature")
except:
pass
recd_signature
{'type': [{'system': 'urn:iso-astm:E1762-95:2013', 'code': '1.2.840.10065.1.12.1.5', 'display': 'Verification Signature'}], 'when': '2021-10-05T22:42:19-07:00', 'who': {'reference': 'Organization/123'}, 'data': 'ZXlKaGJHY2lPaUpTVXpJMU5pSXNJbXQwZVNJNklsSlRJaXdpZEhsd0lqb2lTbGRVSWl3aWVEVmpJanBiSWsxSlNVVXpla05EUVRCbFowRjNTVUpCWjBsS1FVOUxSbGwyVFhkU0szbFJUVUV3UjBOVGNVZFRTV0l6UkZGRlFrTjNWVUZOU1VkT1RWRnpkME5SV1VSV1VWRkhSWGRLVmxWNlJWUk5Ra1ZIUVRGVlJVTkJkMHRSTWtaellWZGFkbU50TlhCWlZFVlRUVUpCUjBFeFZVVkNkM2RLVlRKR01XTXlSbk5oV0ZKMlRWSlZkMFYzV1VSV1VWRkxSRUY0U1ZwWFJuTmtSMmhzVWtkR01GbFVSWGhHZWtGV1FtZE9Wa0pCVFUxRWExWjVZVmROWjFOSFJtaGplWGRuVWtaYVRrMVRWWGRKZDFsS1MyOWFTV2gyWTA1QlVXdENSbWhhYkdGSFJtaGpNRUp2V2xkR2MyUkhhR3hhUjBZd1dWUkZkV0l6U201TlFqUllSRlJKZUUxVVFYbE9la1V6VGtSSmQwNUdiMWhFVkVsNVRWUkJlVTFxUlROT1JFbDNUa1p2ZDJkWk1IaERla0ZLUW1kT1ZrSkJXVlJCYkZaVVRWSk5kMFZSV1VSV1VWRkpSRUZ3UkZsWGVIQmFiVGw1WW0xc2FFMVNTWGRGUVZsRVZsRlJTRVJCYkZSWldGWjZXVmQ0Y0dSSE9IaEdWRUZVUW1kT1ZrSkJiMDFFUldoc1dWZDRNR0ZIVmtWWldGSm9UVlJGV0UxQ1ZVZEJNVlZGUVhkM1QxSllTbkJaZVVKSldWZEdla3hEUWtWV2F6QjRTbFJCYWtKbmEzRm9hMmxIT1hjd1FrTlJSVmRHYlZadldWZEdlbEZIYUd4WlYzZ3dZVWRXYTFsWVVtaE5VelYyWTIxamQyZG5SMmxOUVRCSFExTnhSMU5KWWpORVVVVkNRVkZWUVVFMFNVSnFkMEYzWjJkSFMwRnZTVUpuVVVSd1MyTlRhMjlCVFRaelZ6SXhLM1pYVkdWSlZrOUhlREV3VFZkaGMxRjVOMVpJYVdRMmVubHhXRUZDVFN0NmJtWkNibGhsYm5sVk1Hb3hSbFIyVUcxU1prOUViMDlFV0ZaMVVGVjNSRzl0YUVOSWFDdGlZMnhYT1V0Tk1tODFOak5qZUZKTFJYWkNibUZJY25OcWR6VjVUbTE0VHpWWmFrVlNZbWgwU0dSUlpYRnJkR1IzTTFaWlJWSlNPVWh2ZUV4UE0wWnJjM3BTTWpreVNGUkNOSGhYTTNsWGJGWXpaMVJyVFZGdmVsQlRZMHBMU0ROaVJ6aFFjWEUyUVZsUVNqZERORmxDU1d4VlUyUkNUVlpzTTNGdVpVVm1aemRtZFhocFJtWlliMlprVkZadE4zSk5hV2xITjFnNWVqUXpVR1pwYkhGaFpXbHpabTEwVW5oQmJGSjNSVTVZY2tnelQzWlBSRkI1VERCeVZHNUhPRU56WWtGWVdWWkpUVzFrWkVobE5GcEdPWEJzYURrMWMybzBjRTFVYUV4MFkwcFlMMjg1V0VoTWFtZzNSVzFhZVdkS1NGZEZVWEUwVUhkR2QxcGtiV0pqWm1oRGJVOXlPRGhJT0VKaVZYSjFMemRXTm5waWMwY3hUakZEVjJ4dVpHeGlWbnB1VENzelNVMVBjamhyV0dGSVkyRnVjV1pqYTJkR1ZqUkZjbTVtYWtaS2NURlBTV0ZCYlhOTmFqZzFlRTFyYW5sWVRIbGpURXd2ZFRWdU1tODJRbWM1TXk5VlVtWnhkVTl2VTBsSFQwTlNNalZFWVZwNmNIY3lhek56TjI5Rk9XUk5kMFZYV0hSbVdHZFpkR2d5WW14cWVUVjBSa2d3UjJwd1QydDRNRGRxTjFwVU5VaHVlRzVzYzBOQmQwVkJRV0ZPUVUxRU5IZEVRVmxFVmxJd1ZFSkJWWGRCZDBWQ0wzcEJURUpuVGxaSVVUaEZRa0ZOUTBKbFFYZEpVVmxFVmxJd1VrSkNiM2RIU1VsWFpETmtNMHh0YUd4WlYzZ3dZVWRXYTFsWVVtaGhWelZxVEcxT2RtSlVRVTVDWjJ0eGFHdHBSemwzTUVKQlVYTkdRVUZQUTBGWlJVRkRkVTFWVG5FNVlYa3JLMlUxV1VNM1VVWlBPVFJ5Wm5wNFIxRnVSak5IYTJ4YVRrRlliVWx5TjFCV1IyUnBSMWt5UjFSNEx6bFNkRWhEZDFSTGVtdE1LM2wyUzI5cVpWbzVaRlpMT0hkeVIxWnBVbXRQTDJwVmVWb3JTMk5YVW05clZXcHpOVGx1WTBwSFVrMVRVMUo0ZEdWRFVYVnFkRFJvWmpJckwzRldLMll5YzAxUmRFVnlkMUJGTXpCMlluRlNXVlZPVGs1Q1ZrVlJjR0ZSZUM5aFkwcEVWWFk1ZGpkemFraHBTa1J4V0hkUkszSjZhamsxYVVoQlNXRmxSVWh4Umk5TmN6SXljREppWlZwMWNYWkpVVXRsVFd3cmMzWldjVWgwYVhWNlYyNUdORlUyVmtsdGNHdHlOR0pJYkRkbFoxWTVTRFpzTmxReVUwMXJhalp4UkZVMVpUbE9aekJhYkV4VWRHOXpjMmhDVEcxdmNFWTNaVGRJZVhKVVJVRnRaazlRUzFGbE1FVm5PVVV5ZFhKNmVIRkNkVWMxTkdzMU1FY3lTakJHYVZCelVVcEJhRVpwVGtkM1UyYzBVek5JZVZaRVJ6ZDFaVXRrTUV3NU0zZExUMDVQV1VkMlRVdHBla05JUWl0d1MzWkZUVXB2V2poNU9YVnBRaXRJUmxoamNEbFNZVXB4U2prM1NIQmFWRVYySzJ4cFEzQXlVRk5ZZW1OTE1ISXlOVk5qZVdwR05tUk1iM1ZMTWxOQ016QjRRWFpLT0hSRk5UZzBLMnB4VVRaRFIyVmpWVGxZYW5ac1FXcDFTbVJEY2tSbFZsQnphbXR1TjA5UVdFY3JPRmhhVlRkNmNVaGFUbTFZV0RGWldUUklOWEpuUlVvME9HeHlWWEpRTTBrNFVpSmRmUS4uckU1Z2ZoYmRia211WXBLUGI4N1RwZzFuUmRSSlR5TmZXQU9tWFIyQUE2M0ZHS3oyYnJfYUFGdFhqMlV3SVZIanBfQW1nT1pycEttVUZabmliQlJjUlRCVVZmUFdWcmdSSGxlUDFEZDFRTDJxaWF6MFB4dzM4b2RJVktRdzg4cEZYQmZJQVNzbnJGTUVKX3gwN1hRTFdhWExPY0VZVkJiMnMxU29VTElXX01jSkNlQ1ZLRW5ocnJzbU5oWHZBSEx4WW0yeThsVWRUWVlNSDdyQ00yRkVJZ2xhdnhMQTRRSTFuUHY1aTVad1NPWkRJMU9vUHRLNGRIYmJ2Z2dzS25BdEJKTDg5MEFKN0pEOWgxUVRtdzh2U1dqeWRDQk5pbGdHaXlmZlBtZlNHWEZ2R1E5dEVjRVRIVzBObFVFRjY0OVp0LWs3MWFNaGtqb29Dc1J3TTlEbWI0U1RxTzdGeTBNeldidmRpNks0NldfcmY3N2d2NzVYcl9jUXl2U3ViV3VtUlRNb21wZ0cxcU96NUxiQ2xmS0hvV1d5SXpCeE0ydTd3cUJ1a0pUQUltMTBEU0RnRmc3OS01b0xQSURPajE5VllzbkxjeVlGZFlJeDJHM2drQmhjYkV4RGR5dGxLR0laOFl2SUVvakRmTmliQzN3TFd3TnZtcHRCd3ctaFBkVDc='}
2. Canonicalize the bundle using IETF JSON Canonicalization Scheme (JCS):
searchset_bundle_id = searchset_bundle.pop("id") # remove id
searchset_bundle_meta = searchset_bundle.pop("meta") # remove meta
canonical_bundle = canonicalize(searchset_bundle)
canonical_bundle
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":"1234","display":"Examplitis","system":"http://snomed.info/sct"}],"text":"Examplitis"},"encounter":{"reference":"https://example.org/Encounter/5fe62cd5-bfcf-4d3b-a1e9-80d6f75d6f82"},"id":"4ac41715-fcbd-421c-8796-9b2c9706dd3f","meta":{"lastUpdated":"2020-04-28T20:28:00.008+00:00","profile":["http://hl7.org/fhir/us/core/StructureDefinition/us-core-condition"],"source":"#cabiJIK51sD2iz4N","versionId":"10"},"onsetDateTime":"2018-10-21T21:22:15-07:00","recordedDate":"2018-10-21T21:22:15-07:00","resourceType":"Condition","subject":{"reference":"https://example.org/Patient/06e1f0dd-5fbe-4480-9bb4-6b54ec02d31b"},"verificationStatus":{"coding":[{"code":"confirmed","system":"http://terminology.hl7.org/CodeSystem/condition-ver-status"}]}},"search":{"mode":"match"}}],"link":[{"relation":"self","url":"http://hapi.fhir.org/baseR4/Condition?patient=06e1f0dd-5fbe-4480-9bb4-6b54ec02d31b&clinical-status=active,recurrance,remission"}],"resourceType":"Bundle","total":1,"type":"searchset"}'
3. Transform canonicalize Bundle to a base64 format using the Base64-URL algorithm.
from base64 import urlsafe_b64encode
recd_b64_canonical_bundle = urlsafe_b64encode(canonical_bundle).decode()
recd_b64_canonical_bundle = recd_b64_canonical_bundle.replace("=","") #remove end padding to normalize
recd_b64_canonical_bundle
'eyJlbnRyeSI6W3siZnVsbFVybCI6Imh0dHA6Ly9oYXBpLmZoaXIub3JnL2Jhc2VSNC9Db25kaXRpb24vNGFjNDE3MTUtZmNiZC00MjFjLTg3OTYtOWIyYzk3MDZkZDNmIiwicmVzb3VyY2UiOnsiY2F0ZWdvcnkiOlt7ImNvZGluZyI6W3siY29kZSI6ImVuY291bnRlci1kaWFnbm9zaXMiLCJkaXNwbGF5IjoiRW5jb3VudGVyIERpYWdub3NpcyIsInN5c3RlbSI6Imh0dHA6Ly90ZXJtaW5vbG9neS5obDcub3JnL0NvZGVTeXN0ZW0vY29uZGl0aW9uLWNhdGVnb3J5In1dfV0sImNsaW5pY2FsU3RhdHVzIjp7ImNvZGluZyI6W3siY29kZSI6ImFjdGl2ZSIsInN5c3RlbSI6Imh0dHA6Ly90ZXJtaW5vbG9neS5obDcub3JnL0NvZGVTeXN0ZW0vY29uZGl0aW9uLWNsaW5pY2FsIn1dfSwiY29kZSI6eyJjb2RpbmciOlt7ImNvZGUiOiIxMjM0IiwiZGlzcGxheSI6IkV4YW1wbGl0aXMiLCJzeXN0ZW0iOiJodHRwOi8vc25vbWVkLmluZm8vc2N0In1dLCJ0ZXh0IjoiRXhhbXBsaXRpcyJ9LCJlbmNvdW50ZXIiOnsicmVmZXJlbmNlIjoiaHR0cHM6Ly9leGFtcGxlLm9yZy9FbmNvdW50ZXIvNWZlNjJjZDUtYmZjZi00ZDNiLWExZTktODBkNmY3NWQ2ZjgyIn0sImlkIjoiNGFjNDE3MTUtZmNiZC00MjFjLTg3OTYtOWIyYzk3MDZkZDNmIiwibWV0YSI6eyJsYXN0VXBkYXRlZCI6IjIwMjAtMDQtMjhUMjA6Mjg6MDAuMDA4KzAwOjAwIiwicHJvZmlsZSI6WyJodHRwOi8vaGw3Lm9yZy9maGlyL3VzL2NvcmUvU3RydWN0dXJlRGVmaW5pdGlvbi91cy1jb3JlLWNvbmRpdGlvbiJdLCJzb3VyY2UiOiIjY2FiaUpJSzUxc0QyaXo0TiIsInZlcnNpb25JZCI6IjEwIn0sIm9uc2V0RGF0ZVRpbWUiOiIyMDE4LTEwLTIxVDIxOjIyOjE1LTA3OjAwIiwicmVjb3JkZWREYXRlIjoiMjAxOC0xMC0yMVQyMToyMjoxNS0wNzowMCIsInJlc291cmNlVHlwZSI6IkNvbmRpdGlvbiIsInN1YmplY3QiOnsicmVmZXJlbmNlIjoiaHR0cHM6Ly9leGFtcGxlLm9yZy9QYXRpZW50LzA2ZTFmMGRkLTVmYmUtNDQ4MC05YmI0LTZiNTRlYzAyZDMxYiJ9LCJ2ZXJpZmljYXRpb25TdGF0dXMiOnsiY29kaW5nIjpbeyJjb2RlIjoiY29uZmlybWVkIiwic3lzdGVtIjoiaHR0cDovL3Rlcm1pbm9sb2d5LmhsNy5vcmcvQ29kZVN5c3RlbS9jb25kaXRpb24tdmVyLXN0YXR1cyJ9XX19LCJzZWFyY2giOnsibW9kZSI6Im1hdGNoIn19XSwibGluayI6W3sicmVsYXRpb24iOiJzZWxmIiwidXJsIjoiaHR0cDovL2hhcGkuZmhpci5vcmcvYmFzZVI0L0NvbmRpdGlvbj9wYXRpZW50PTA2ZTFmMGRkLTVmYmUtNDQ4MC05YmI0LTZiNTRlYzAyZDMxYiZjbGluaWNhbC1zdGF0dXM9YWN0aXZlLHJlY3VycmFuY2UscmVtaXNzaW9uIn1dLCJyZXNvdXJjZVR5cGUiOiJCdW5kbGUiLCJ0b3RhbCI6MSwidHlwZSI6InNlYXJjaHNldCJ9'
4. Get the base64 encoded JWS from the Bundle.signature.data
element
recd_b64_jws = recd_signature['data']
recd_b64_jws
'ZXlKaGJHY2lPaUpTVXpJMU5pSXNJbXQwZVNJNklsSlRJaXdpZEhsd0lqb2lTbGRVSWl3aWVEVmpJanBiSWsxSlNVVXpla05EUVRCbFowRjNTVUpCWjBsS1FVOUxSbGwyVFhkU0szbFJUVUV3UjBOVGNVZFRTV0l6UkZGRlFrTjNWVUZOU1VkT1RWRnpkME5SV1VSV1VWRkhSWGRLVmxWNlJWUk5Ra1ZIUVRGVlJVTkJkMHRSTWtaellWZGFkbU50TlhCWlZFVlRUVUpCUjBFeFZVVkNkM2RLVlRKR01XTXlSbk5oV0ZKMlRWSlZkMFYzV1VSV1VWRkxSRUY0U1ZwWFJuTmtSMmhzVWtkR01GbFVSWGhHZWtGV1FtZE9Wa0pCVFUxRWExWjVZVmROWjFOSFJtaGplWGRuVWtaYVRrMVRWWGRKZDFsS1MyOWFTV2gyWTA1QlVXdENSbWhhYkdGSFJtaGpNRUp2V2xkR2MyUkhhR3hhUjBZd1dWUkZkV0l6U201TlFqUllSRlJKZUUxVVFYbE9la1V6VGtSSmQwNUdiMWhFVkVsNVRWUkJlVTFxUlROT1JFbDNUa1p2ZDJkWk1IaERla0ZLUW1kT1ZrSkJXVlJCYkZaVVRWSk5kMFZSV1VSV1VWRkpSRUZ3UkZsWGVIQmFiVGw1WW0xc2FFMVNTWGRGUVZsRVZsRlJTRVJCYkZSWldGWjZXVmQ0Y0dSSE9IaEdWRUZVUW1kT1ZrSkJiMDFFUldoc1dWZDRNR0ZIVmtWWldGSm9UVlJGV0UxQ1ZVZEJNVlZGUVhkM1QxSllTbkJaZVVKSldWZEdla3hEUWtWV2F6QjRTbFJCYWtKbmEzRm9hMmxIT1hjd1FrTlJSVmRHYlZadldWZEdlbEZIYUd4WlYzZ3dZVWRXYTFsWVVtaE5VelYyWTIxamQyZG5SMmxOUVRCSFExTnhSMU5KWWpORVVVVkNRVkZWUVVFMFNVSnFkMEYzWjJkSFMwRnZTVUpuVVVSd1MyTlRhMjlCVFRaelZ6SXhLM1pYVkdWSlZrOUhlREV3VFZkaGMxRjVOMVpJYVdRMmVubHhXRUZDVFN0NmJtWkNibGhsYm5sVk1Hb3hSbFIyVUcxU1prOUViMDlFV0ZaMVVGVjNSRzl0YUVOSWFDdGlZMnhYT1V0Tk1tODFOak5qZUZKTFJYWkNibUZJY25OcWR6VjVUbTE0VHpWWmFrVlNZbWgwU0dSUlpYRnJkR1IzTTFaWlJWSlNPVWh2ZUV4UE0wWnJjM3BTTWpreVNGUkNOSGhYTTNsWGJGWXpaMVJyVFZGdmVsQlRZMHBMU0ROaVJ6aFFjWEUyUVZsUVNqZERORmxDU1d4VlUyUkNUVlpzTTNGdVpVVm1aemRtZFhocFJtWlliMlprVkZadE4zSk5hV2xITjFnNWVqUXpVR1pwYkhGaFpXbHpabTEwVW5oQmJGSjNSVTVZY2tnelQzWlBSRkI1VERCeVZHNUhPRU56WWtGWVdWWkpUVzFrWkVobE5GcEdPWEJzYURrMWMybzBjRTFVYUV4MFkwcFlMMjg1V0VoTWFtZzNSVzFhZVdkS1NGZEZVWEUwVUhkR2QxcGtiV0pqWm1oRGJVOXlPRGhJT0VKaVZYSjFMemRXTm5waWMwY3hUakZEVjJ4dVpHeGlWbnB1VENzelNVMVBjamhyV0dGSVkyRnVjV1pqYTJkR1ZqUkZjbTVtYWtaS2NURlBTV0ZCYlhOTmFqZzFlRTFyYW5sWVRIbGpURXd2ZFRWdU1tODJRbWM1TXk5VlVtWnhkVTl2VTBsSFQwTlNNalZFWVZwNmNIY3lhek56TjI5Rk9XUk5kMFZYV0hSbVdHZFpkR2d5WW14cWVUVjBSa2d3UjJwd1QydDRNRGRxTjFwVU5VaHVlRzVzYzBOQmQwVkJRV0ZPUVUxRU5IZEVRVmxFVmxJd1ZFSkJWWGRCZDBWQ0wzcEJURUpuVGxaSVVUaEZRa0ZOUTBKbFFYZEpVVmxFVmxJd1VrSkNiM2RIU1VsWFpETmtNMHh0YUd4WlYzZ3dZVWRXYTFsWVVtaGhWelZxVEcxT2RtSlVRVTVDWjJ0eGFHdHBSemwzTUVKQlVYTkdRVUZQUTBGWlJVRkRkVTFWVG5FNVlYa3JLMlUxV1VNM1VVWlBPVFJ5Wm5wNFIxRnVSak5IYTJ4YVRrRlliVWx5TjFCV1IyUnBSMWt5UjFSNEx6bFNkRWhEZDFSTGVtdE1LM2wyUzI5cVpWbzVaRlpMT0hkeVIxWnBVbXRQTDJwVmVWb3JTMk5YVW05clZXcHpOVGx1WTBwSFVrMVRVMUo0ZEdWRFVYVnFkRFJvWmpJckwzRldLMll5YzAxUmRFVnlkMUJGTXpCMlluRlNXVlZPVGs1Q1ZrVlJjR0ZSZUM5aFkwcEVWWFk1ZGpkemFraHBTa1J4V0hkUkszSjZhamsxYVVoQlNXRmxSVWh4Umk5TmN6SXljREppWlZwMWNYWkpVVXRsVFd3cmMzWldjVWgwYVhWNlYyNUdORlUyVmtsdGNHdHlOR0pJYkRkbFoxWTVTRFpzTmxReVUwMXJhalp4UkZVMVpUbE9aekJhYkV4VWRHOXpjMmhDVEcxdmNFWTNaVGRJZVhKVVJVRnRaazlRUzFGbE1FVm5PVVV5ZFhKNmVIRkNkVWMxTkdzMU1FY3lTakJHYVZCelVVcEJhRVpwVGtkM1UyYzBVek5JZVZaRVJ6ZDFaVXRrTUV3NU0zZExUMDVQV1VkMlRVdHBla05JUWl0d1MzWkZUVXB2V2poNU9YVnBRaXRJUmxoamNEbFNZVXB4U2prM1NIQmFWRVYySzJ4cFEzQXlVRk5ZZW1OTE1ISXlOVk5qZVdwR05tUk1iM1ZMTWxOQ016QjRRWFpLT0hSRk5UZzBLMnB4VVRaRFIyVmpWVGxZYW5ac1FXcDFTbVJEY2tSbFZsQnphbXR1TjA5UVdFY3JPRmhhVlRkNmNVaGFUbTFZV0RGWldUUklOWEpuUlVvME9HeHlWWEpRTTBrNFVpSmRmUS4uckU1Z2ZoYmRia211WXBLUGI4N1RwZzFuUmRSSlR5TmZXQU9tWFIyQUE2M0ZHS3oyYnJfYUFGdFhqMlV3SVZIanBfQW1nT1pycEttVUZabmliQlJjUlRCVVZmUFdWcmdSSGxlUDFEZDFRTDJxaWF6MFB4dzM4b2RJVktRdzg4cEZYQmZJQVNzbnJGTUVKX3gwN1hRTFdhWExPY0VZVkJiMnMxU29VTElXX01jSkNlQ1ZLRW5ocnJzbU5oWHZBSEx4WW0yeThsVWRUWVlNSDdyQ00yRkVJZ2xhdnhMQTRRSTFuUHY1aTVad1NPWkRJMU9vUHRLNGRIYmJ2Z2dzS25BdEJKTDg5MEFKN0pEOWgxUVRtdzh2U1dqeWRDQk5pbGdHaXlmZlBtZlNHWEZ2R1E5dEVjRVRIVzBObFVFRjY0OVp0LWs3MWFNaGtqb29Dc1J3TTlEbWI0U1RxTzdGeTBNeldidmRpNks0NldfcmY3N2d2NzVYcl9jUXl2U3ViV3VtUlRNb21wZ0cxcU96NUxiQ2xmS0hvV1d5SXpCeE0ydTd3cUJ1a0pUQUltMTBEU0RnRmc3OS01b0xQSURPajE5VllzbkxjeVlGZFlJeDJHM2drQmhjYkV4RGR5dGxLR0laOFl2SUVvakRmTmliQzN3TFd3TnZtcHRCd3ctaFBkVDc='
5. Base64 decode the encoded JWS
note the signature is displayed with the parts labeled and separated with line breaks for easier viewing
from base64 import b64decode
recd_jws = b64decode(recd_b64_jws.encode()).decode()
for i,j in enumerate(recd_jws.split('.')):
print(f'{labels[i]}:')
print(f'{j}')
print()
header: eyJhbGciOiJSUzI1NiIsImt0eSI6IlJTIiwidHlwIjoiSldUIiwieDVjIjpbIk1JSUUzekNDQTBlZ0F3SUJBZ0lKQU9LRll2TXdSK3lRTUEwR0NTcUdTSWIzRFFFQkN3VUFNSUdOTVFzd0NRWURWUVFHRXdKVlV6RVRNQkVHQTFVRUNBd0tRMkZzYVdadmNtNXBZVEVTTUJBR0ExVUVCd3dKVTJGMWMyRnNhWFJ2TVJVd0V3WURWUVFLREF4SVpXRnNkR2hsUkdGMFlURXhGekFWQmdOVkJBTU1Ea1Z5YVdNZ1NHRmhjeXdnUkZaTk1TVXdJd1lKS29aSWh2Y05BUWtCRmhabGFHRmhjMEJvWldGc2RHaGxaR0YwWVRFdWIzSm5NQjRYRFRJeE1UQXlOekUzTkRJd05Gb1hEVEl5TVRBeU1qRTNOREl3TkZvd2dZMHhDekFKQmdOVkJBWVRBbFZUTVJNd0VRWURWUVFJREFwRFlXeHBabTl5Ym1saE1SSXdFQVlEVlFRSERBbFRZWFZ6WVd4cGRHOHhGVEFUQmdOVkJBb01ERWhsWVd4MGFHVkVZWFJoTVRFWE1CVUdBMVVFQXd3T1JYSnBZeUJJWVdGekxDQkVWazB4SlRBakJna3Foa2lHOXcwQkNRRVdGbVZvWVdGelFHaGxZV3gwYUdWa1lYUmhNUzV2Y21jd2dnR2lNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJqd0F3Z2dHS0FvSUJnUURwS2NTa29BTTZzVzIxK3ZXVGVJVk9HeDEwTVdhc1F5N1ZIaWQ2enlxWEFCTSt6bmZCblhlbnlVMGoxRlR2UG1SZk9Eb09EWFZ1UFV3RG9taENIaCtiY2xXOUtNMm81NjNjeFJLRXZCbmFIcnNqdzV5Tm14TzVZakVSYmh0SGRRZXFrdGR3M1ZZRVJSOUhveExPM0Zrc3pSMjkySFRCNHhXM3lXbFYzZ1RrTVFvelBTY0pLSDNiRzhQcXE2QVlQSjdDNFlCSWxVU2RCTVZsM3FuZUVmZzdmdXhpRmZYb2ZkVFZtN3JNaWlHN1g5ejQzUGZpbHFhZWlzZm10UnhBbFJ3RU5YckgzT3ZPRFB5TDByVG5HOENzYkFYWVZJTW1kZEhlNFpGOXBsaDk1c2o0cE1UaEx0Y0pYL285WEhMamg3RW1aeWdKSFdFUXE0UHdGd1pkbWJjZmhDbU9yODhIOEJiVXJ1LzdWNnpic0cxTjFDV2xuZGxiVnpuTCszSU1PcjhrWGFIY2FucWZja2dGVjRFcm5makZKcTFPSWFBbXNNajg1eE1ranlYTHljTEwvdTVuMm82Qmc5My9VUmZxdU9vU0lHT0NSMjVEYVp6cHcyazNzN29FOWRNd0VXWHRmWGdZdGgyYmxqeTV0RkgwR2pwT2t4MDdqN1pUNUhueG5sc0NBd0VBQWFOQU1ENHdEQVlEVlIwVEJBVXdBd0VCL3pBTEJnTlZIUThFQkFNQ0JlQXdJUVlEVlIwUkJCb3dHSUlXZDNkM0xtaGxZV3gwYUdWa1lYUmhhVzVqTG1OdmJUQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FZRUFDdU1VTnE5YXkrK2U1WUM3UUZPOTRyZnp4R1FuRjNHa2xaTkFYbUlyN1BWR2RpR1kyR1R4LzlSdEhDd1RLemtMK3l2S29qZVo5ZFZLOHdyR1ZpUmtPL2pVeVorS2NXUm9rVWpzNTluY0pHUk1TU1J4dGVDUXVqdDRoZjIrL3FWK2Yyc01RdEVyd1BFMzB2YnFSWVVOTk5CVkVRcGFReC9hY0pEVXY5djdzakhpSkRxWHdRK3J6ajk1aUhBSWFlRUhxRi9NczIycDJiZVp1cXZJUUtlTWwrc3ZWcUh0aXV6V25GNFU2VkltcGtyNGJIbDdlZ1Y5SDZsNlQyU01rajZxRFU1ZTlOZzBabExUdG9zc2hCTG1vcEY3ZTdIeXJURUFtZk9QS1FlMEVnOUUydXJ6eHFCdUc1NGs1MEcySjBGaVBzUUpBaEZpTkd3U2c0UzNIeVZERzd1ZUtkMEw5M3dLT05PWUd2TUtpekNIQitwS3ZFTUpvWjh5OXVpQitIRlhjcDlSYUpxSjk3SHBaVEV2K2xpQ3AyUFNYemNLMHIyNVNjeWpGNmRMb3VLMlNCMzB4QXZKOHRFNTg0K2pxUTZDR2VjVTlYanZsQWp1SmRDckRlVlBzamtuN09QWEcrOFhaVTd6cUhaTm1YWDFZWTRINXJnRUo0OGxyVXJQM0k4UiJdfQ payload: signature: rE5gfhbdbkmuYpKPb87Tpg1nRdRJTyNfWAOmXR2AA63FGKz2br_aAFtXj2UwIVHjp_AmgOZrpKmUFZnibBRcRTBUVfPWVrgRHleP1Dd1QL2qiaz0Pxw38odIVKQw88pFXBfIASsnrFMEJ_x07XQLWaXLOcEYVBb2s1SoULIW_McJCeCVKEnhrrsmNhXvAHLxYm2y8lUdTYYMH7rCM2FEIglavxLA4QI1nPv5i5ZwSOZDI1OoPtK4dHbbvggsKnAtBJL890AJ7JD9h1QTmw8vSWjydCBNilgGiyffPmfSGXFvGQ9tEcETHW0NlUEF649Zt-k71aMhkjooCsRwM9Dmb4STqO7Fy0MzWbvdi6K46W_rf77gv75Xr_cQyvSubWumRTMompgG1qOz5LbClfKHoWWyIzBxM2u7wqBukJTAIm10DSDgFg79-5oLPIDOj19VYsnLcyYFdYIx2G3gkBhcbExDdytlKGIZ8YvIEojDfNibC3wLWwNvmptBww-hPdT7
**6. reattach the payload - the base64 encoded Bundle - into the JWS payload element. **
note the signature is displayed with the parts labeled and separated with line breaks for easier viewing
split_sig = recd_jws.split('.')
split_sig[1] = recd_b64_canonical_bundle
recd_jws = '.'.join(split_sig)
for i,j in enumerate(recd_jws.split('.')):
print(f'{labels[i]}:')
print(f'{j}')
print()
header: eyJhbGciOiJSUzI1NiIsImt0eSI6IlJTIiwidHlwIjoiSldUIiwieDVjIjpbIk1JSUUzekNDQTBlZ0F3SUJBZ0lKQU9LRll2TXdSK3lRTUEwR0NTcUdTSWIzRFFFQkN3VUFNSUdOTVFzd0NRWURWUVFHRXdKVlV6RVRNQkVHQTFVRUNBd0tRMkZzYVdadmNtNXBZVEVTTUJBR0ExVUVCd3dKVTJGMWMyRnNhWFJ2TVJVd0V3WURWUVFLREF4SVpXRnNkR2hsUkdGMFlURXhGekFWQmdOVkJBTU1Ea1Z5YVdNZ1NHRmhjeXdnUkZaTk1TVXdJd1lKS29aSWh2Y05BUWtCRmhabGFHRmhjMEJvWldGc2RHaGxaR0YwWVRFdWIzSm5NQjRYRFRJeE1UQXlOekUzTkRJd05Gb1hEVEl5TVRBeU1qRTNOREl3TkZvd2dZMHhDekFKQmdOVkJBWVRBbFZUTVJNd0VRWURWUVFJREFwRFlXeHBabTl5Ym1saE1SSXdFQVlEVlFRSERBbFRZWFZ6WVd4cGRHOHhGVEFUQmdOVkJBb01ERWhsWVd4MGFHVkVZWFJoTVRFWE1CVUdBMVVFQXd3T1JYSnBZeUJJWVdGekxDQkVWazB4SlRBakJna3Foa2lHOXcwQkNRRVdGbVZvWVdGelFHaGxZV3gwYUdWa1lYUmhNUzV2Y21jd2dnR2lNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJqd0F3Z2dHS0FvSUJnUURwS2NTa29BTTZzVzIxK3ZXVGVJVk9HeDEwTVdhc1F5N1ZIaWQ2enlxWEFCTSt6bmZCblhlbnlVMGoxRlR2UG1SZk9Eb09EWFZ1UFV3RG9taENIaCtiY2xXOUtNMm81NjNjeFJLRXZCbmFIcnNqdzV5Tm14TzVZakVSYmh0SGRRZXFrdGR3M1ZZRVJSOUhveExPM0Zrc3pSMjkySFRCNHhXM3lXbFYzZ1RrTVFvelBTY0pLSDNiRzhQcXE2QVlQSjdDNFlCSWxVU2RCTVZsM3FuZUVmZzdmdXhpRmZYb2ZkVFZtN3JNaWlHN1g5ejQzUGZpbHFhZWlzZm10UnhBbFJ3RU5YckgzT3ZPRFB5TDByVG5HOENzYkFYWVZJTW1kZEhlNFpGOXBsaDk1c2o0cE1UaEx0Y0pYL285WEhMamg3RW1aeWdKSFdFUXE0UHdGd1pkbWJjZmhDbU9yODhIOEJiVXJ1LzdWNnpic0cxTjFDV2xuZGxiVnpuTCszSU1PcjhrWGFIY2FucWZja2dGVjRFcm5makZKcTFPSWFBbXNNajg1eE1ranlYTHljTEwvdTVuMm82Qmc5My9VUmZxdU9vU0lHT0NSMjVEYVp6cHcyazNzN29FOWRNd0VXWHRmWGdZdGgyYmxqeTV0RkgwR2pwT2t4MDdqN1pUNUhueG5sc0NBd0VBQWFOQU1ENHdEQVlEVlIwVEJBVXdBd0VCL3pBTEJnTlZIUThFQkFNQ0JlQXdJUVlEVlIwUkJCb3dHSUlXZDNkM0xtaGxZV3gwYUdWa1lYUmhhVzVqTG1OdmJUQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FZRUFDdU1VTnE5YXkrK2U1WUM3UUZPOTRyZnp4R1FuRjNHa2xaTkFYbUlyN1BWR2RpR1kyR1R4LzlSdEhDd1RLemtMK3l2S29qZVo5ZFZLOHdyR1ZpUmtPL2pVeVorS2NXUm9rVWpzNTluY0pHUk1TU1J4dGVDUXVqdDRoZjIrL3FWK2Yyc01RdEVyd1BFMzB2YnFSWVVOTk5CVkVRcGFReC9hY0pEVXY5djdzakhpSkRxWHdRK3J6ajk1aUhBSWFlRUhxRi9NczIycDJiZVp1cXZJUUtlTWwrc3ZWcUh0aXV6V25GNFU2VkltcGtyNGJIbDdlZ1Y5SDZsNlQyU01rajZxRFU1ZTlOZzBabExUdG9zc2hCTG1vcEY3ZTdIeXJURUFtZk9QS1FlMEVnOUUydXJ6eHFCdUc1NGs1MEcySjBGaVBzUUpBaEZpTkd3U2c0UzNIeVZERzd1ZUtkMEw5M3dLT05PWUd2TUtpekNIQitwS3ZFTUpvWjh5OXVpQitIRlhjcDlSYUpxSjk3SHBaVEV2K2xpQ3AyUFNYemNLMHIyNVNjeWpGNmRMb3VLMlNCMzB4QXZKOHRFNTg0K2pxUTZDR2VjVTlYanZsQWp1SmRDckRlVlBzamtuN09QWEcrOFhaVTd6cUhaTm1YWDFZWTRINXJnRUo0OGxyVXJQM0k4UiJdfQ payload: eyJlbnRyeSI6W3siZnVsbFVybCI6Imh0dHA6Ly9oYXBpLmZoaXIub3JnL2Jhc2VSNC9Db25kaXRpb24vNGFjNDE3MTUtZmNiZC00MjFjLTg3OTYtOWIyYzk3MDZkZDNmIiwicmVzb3VyY2UiOnsiY2F0ZWdvcnkiOlt7ImNvZGluZyI6W3siY29kZSI6ImVuY291bnRlci1kaWFnbm9zaXMiLCJkaXNwbGF5IjoiRW5jb3VudGVyIERpYWdub3NpcyIsInN5c3RlbSI6Imh0dHA6Ly90ZXJtaW5vbG9neS5obDcub3JnL0NvZGVTeXN0ZW0vY29uZGl0aW9uLWNhdGVnb3J5In1dfV0sImNsaW5pY2FsU3RhdHVzIjp7ImNvZGluZyI6W3siY29kZSI6ImFjdGl2ZSIsInN5c3RlbSI6Imh0dHA6Ly90ZXJtaW5vbG9neS5obDcub3JnL0NvZGVTeXN0ZW0vY29uZGl0aW9uLWNsaW5pY2FsIn1dfSwiY29kZSI6eyJjb2RpbmciOlt7ImNvZGUiOiIxMjM0IiwiZGlzcGxheSI6IkV4YW1wbGl0aXMiLCJzeXN0ZW0iOiJodHRwOi8vc25vbWVkLmluZm8vc2N0In1dLCJ0ZXh0IjoiRXhhbXBsaXRpcyJ9LCJlbmNvdW50ZXIiOnsicmVmZXJlbmNlIjoiaHR0cHM6Ly9leGFtcGxlLm9yZy9FbmNvdW50ZXIvNWZlNjJjZDUtYmZjZi00ZDNiLWExZTktODBkNmY3NWQ2ZjgyIn0sImlkIjoiNGFjNDE3MTUtZmNiZC00MjFjLTg3OTYtOWIyYzk3MDZkZDNmIiwibWV0YSI6eyJsYXN0VXBkYXRlZCI6IjIwMjAtMDQtMjhUMjA6Mjg6MDAuMDA4KzAwOjAwIiwicHJvZmlsZSI6WyJodHRwOi8vaGw3Lm9yZy9maGlyL3VzL2NvcmUvU3RydWN0dXJlRGVmaW5pdGlvbi91cy1jb3JlLWNvbmRpdGlvbiJdLCJzb3VyY2UiOiIjY2FiaUpJSzUxc0QyaXo0TiIsInZlcnNpb25JZCI6IjEwIn0sIm9uc2V0RGF0ZVRpbWUiOiIyMDE4LTEwLTIxVDIxOjIyOjE1LTA3OjAwIiwicmVjb3JkZWREYXRlIjoiMjAxOC0xMC0yMVQyMToyMjoxNS0wNzowMCIsInJlc291cmNlVHlwZSI6IkNvbmRpdGlvbiIsInN1YmplY3QiOnsicmVmZXJlbmNlIjoiaHR0cHM6Ly9leGFtcGxlLm9yZy9QYXRpZW50LzA2ZTFmMGRkLTVmYmUtNDQ4MC05YmI0LTZiNTRlYzAyZDMxYiJ9LCJ2ZXJpZmljYXRpb25TdGF0dXMiOnsiY29kaW5nIjpbeyJjb2RlIjoiY29uZmlybWVkIiwic3lzdGVtIjoiaHR0cDovL3Rlcm1pbm9sb2d5LmhsNy5vcmcvQ29kZVN5c3RlbS9jb25kaXRpb24tdmVyLXN0YXR1cyJ9XX19LCJzZWFyY2giOnsibW9kZSI6Im1hdGNoIn19XSwibGluayI6W3sicmVsYXRpb24iOiJzZWxmIiwidXJsIjoiaHR0cDovL2hhcGkuZmhpci5vcmcvYmFzZVI0L0NvbmRpdGlvbj9wYXRpZW50PTA2ZTFmMGRkLTVmYmUtNDQ4MC05YmI0LTZiNTRlYzAyZDMxYiZjbGluaWNhbC1zdGF0dXM9YWN0aXZlLHJlY3VycmFuY2UscmVtaXNzaW9uIn1dLCJyZXNvdXJjZVR5cGUiOiJCdW5kbGUiLCJ0b3RhbCI6MSwidHlwZSI6InNlYXJjaHNldCJ9 signature: rE5gfhbdbkmuYpKPb87Tpg1nRdRJTyNfWAOmXR2AA63FGKz2br_aAFtXj2UwIVHjp_AmgOZrpKmUFZnibBRcRTBUVfPWVrgRHleP1Dd1QL2qiaz0Pxw38odIVKQw88pFXBfIASsnrFMEJ_x07XQLWaXLOcEYVBb2s1SoULIW_McJCeCVKEnhrrsmNhXvAHLxYm2y8lUdTYYMH7rCM2FEIglavxLA4QI1nPv5i5ZwSOZDI1OoPtK4dHbbvggsKnAtBJL890AJ7JD9h1QTmw8vSWjydCBNilgGiyffPmfSGXFvGQ9tEcETHW0NlUEF649Zt-k71aMhkjooCsRwM9Dmb4STqO7Fy0MzWbvdi6K46W_rf77gv75Xr_cQyvSubWumRTMompgG1qOz5LbClfKHoWWyIzBxM2u7wqBukJTAIm10DSDgFg79-5oLPIDOj19VYsnLcyYFdYIx2G3gkBhcbExDdytlKGIZ8YvIEojDfNibC3wLWwNvmptBww-hPdT7
7. Obtain public Key from the first certificate in JWS header "x5c"
key
recd_header = jws.get_unverified_header(recd_jws)
recd_header
{'alg': 'RS256', 'kty': 'RS', 'typ': 'JWT', 'x5c': ['MIIE3zCCA0egAwIBAgIJAOKFYvMwR+yQMA0GCSqGSIb3DQEBCwUAMIGNMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJU2F1c2FsaXRvMRUwEwYDVQQKDAxIZWFsdGhlRGF0YTExFzAVBgNVBAMMDkVyaWMgSGFhcywgRFZNMSUwIwYJKoZIhvcNAQkBFhZlaGFhc0BoZWFsdGhlZGF0YTEub3JnMB4XDTIxMTAyNzE3NDIwNFoXDTIyMTAyMjE3NDIwNFowgY0xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlTYXVzYWxpdG8xFTATBgNVBAoMDEhlYWx0aGVEYXRhMTEXMBUGA1UEAwwORXJpYyBIYWFzLCBEVk0xJTAjBgkqhkiG9w0BCQEWFmVoYWFzQGhlYWx0aGVkYXRhMS5vcmcwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDpKcSkoAM6sW21+vWTeIVOGx10MWasQy7VHid6zyqXABM+znfBnXenyU0j1FTvPmRfODoODXVuPUwDomhCHh+bclW9KM2o563cxRKEvBnaHrsjw5yNmxO5YjERbhtHdQeqktdw3VYERR9HoxLO3FkszR292HTB4xW3yWlV3gTkMQozPScJKH3bG8Pqq6AYPJ7C4YBIlUSdBMVl3qneEfg7fuxiFfXofdTVm7rMiiG7X9z43PfilqaeisfmtRxAlRwENXrH3OvODPyL0rTnG8CsbAXYVIMmddHe4ZF9plh95sj4pMThLtcJX/o9XHLjh7EmZygJHWEQq4PwFwZdmbcfhCmOr88H8BbUru/7V6zbsG1N1CWlndlbVznL+3IMOr8kXaHcanqfckgFV4ErnfjFJq1OIaAmsMj85xMkjyXLycLL/u5n2o6Bg93/URfquOoSIGOCR25DaZzpw2k3s7oE9dMwEWXtfXgYth2bljy5tFH0GjpOkx07j7ZT5HnxnlsCAwEAAaNAMD4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCBeAwIQYDVR0RBBowGIIWd3d3LmhlYWx0aGVkYXRhaW5jLmNvbTANBgkqhkiG9w0BAQsFAAOCAYEACuMUNq9ay++e5YC7QFO94rfzxGQnF3GklZNAXmIr7PVGdiGY2GTx/9RtHCwTKzkL+yvKojeZ9dVK8wrGViRkO/jUyZ+KcWRokUjs59ncJGRMSSRxteCQujt4hf2+/qV+f2sMQtErwPE30vbqRYUNNNBVEQpaQx/acJDUv9v7sjHiJDqXwQ+rzj95iHAIaeEHqF/Ms22p2beZuqvIQKeMl+svVqHtiuzWnF4U6VImpkr4bHl7egV9H6l6T2SMkj6qDU5e9Ng0ZlLTtosshBLmopF7e7HyrTEAmfOPKQe0Eg9E2urzxqBuG54k50G2J0FiPsQJAhFiNGwSg4S3HyVDG7ueKd0L93wKONOYGvMKizCHB+pKvEMJoZ8y9uiB+HFXcp9RaJqJ97HpZTEv+liCp2PSXzcK0r25ScyjF6dLouK2SB30xAvJ8tE584+jqQ6CGecU9XjvlAjuJdCrDeVPsjkn7OPXG+8XZU7zqHZNmXX1YY4H5rgEJ48lrUrP3I8R']}
recd_cert = b64decode(recd_header['x5c'][0])
with open('recd_cert.der', 'wb') as f:
f.write(recd_cert)
!openssl x509 -in recd_cert.der -inform DER -text
Certificate: Data: Version: 3 (0x2) Serial Number: 16322561221100825744 (0xe28562f33047ec90) Signature Algorithm: sha256WithRSAEncryption Issuer: C=US, ST=California, L=Sausalito, O=HealtheData1, CN=Eric Haas, DVM/emailAddress=ehaas@healthedata1.org Validity Not Before: Oct 27 17:42:04 2021 GMT Not After : Oct 22 17:42:04 2022 GMT Subject: C=US, ST=California, L=Sausalito, O=HealtheData1, CN=Eric Haas, DVM/emailAddress=ehaas@healthedata1.org Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (3072 bit) Modulus: 00:e9:29:c4:a4:a0:03:3a:b1:6d:b5:fa:f5:93:78: 85:4e:1b:1d:74:31:66:ac:43:2e:d5:1e:27:7a:cf: 2a:97:00:13:3e:ce:77:c1:9d:77:a7:c9:4d:23:d4: 54:ef:3e:64:5f:38:3a:0e:0d:75:6e:3d:4c:03:a2: 68:42:1e:1f:9b:72:55:bd:28:cd:a8:e7:ad:dc:c5: 12:84:bc:19:da:1e:bb:23:c3:9c:8d:9b:13:b9:62: 31:11:6e:1b:47:75:07:aa:92:d7:70:dd:56:04:45: 1f:47:a3:12:ce:dc:59:2c:cd:1d:bd:d8:74:c1:e3: 15:b7:c9:69:55:de:04:e4:31:0a:33:3d:27:09:28: 7d:db:1b:c3:ea:ab:a0:18:3c:9e:c2:e1:80:48:95: 44:9d:04:c5:65:de:a9:de:11:f8:3b:7e:ec:62:15: f5:e8:7d:d4:d5:9b:ba:cc:8a:21:bb:5f:dc:f8:dc: f7:e2:96:a6:9e:8a:c7:e6:b5:1c:40:95:1c:04:35: 7a:c7:dc:eb:ce:0c:fc:8b:d2:b4:e7:1b:c0:ac:6c: 05:d8:54:83:26:75:d1:de:e1:91:7d:a6:58:7d:e6: c8:f8:a4:c4:e1:2e:d7:09:5f:fa:3d:5c:72:e3:87: b1:26:67:28:09:1d:61:10:ab:83:f0:17:06:5d:99: b7:1f:84:29:8e:af:cf:07:f0:16:d4:ae:ef:fb:57: ac:db:b0:6d:4d:d4:25:a5:9d:d9:5b:57:39:cb:fb: 72:0c:3a:bf:24:5d:a1:dc:6a:7a:9f:72:48:05:57: 81:2b:9d:f8:c5:26:ad:4e:21:a0:26:b0:c8:fc:e7: 13:24:8f:25:cb:c9:c2:cb:fe:ee:67:da:8e:81:83: dd:ff:51:17:ea:b8:ea:12:20:63:82:47:6e:43:69: 9c:e9:c3:69:37:b3:ba:04:f5:d3:30:11:65:ed:7d: 78:18:b6:1d:9b:96:3c:b9:b4:51:f4:1a:3a:4e:93: 1d:3b:8f:b6:53:e4:79:f1:9e:5b Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:TRUE X509v3 Key Usage: Digital Signature, Non Repudiation, Key Encipherment X509v3 Subject Alternative Name: DNS:www.healthedatainc.com Signature Algorithm: sha256WithRSAEncryption 0a:e3:14:36:af:5a:cb:ef:9e:e5:80:bb:40:53:bd:e2:b7:f3: c4:64:27:17:71:a4:95:93:40:5e:62:2b:ec:f5:46:76:21:98: d8:64:f1:ff:d4:6d:1c:2c:13:2b:39:0b:fb:2b:ca:a2:37:99: f5:d5:4a:f3:0a:c6:56:24:64:3b:f8:d4:c9:9f:8a:71:64:68: 91:48:ec:e7:d9:dc:24:64:4c:49:24:71:b5:e0:90:ba:3b:78: 85:fd:be:fe:a5:7e:7f:6b:0c:42:d1:2b:c0:f1:37:d2:f6:ea: 45:85:0d:34:d0:55:11:0a:5a:43:1f:da:70:90:d4:bf:db:fb: b2:31:e2:24:3a:97:c1:0f:ab:ce:3f:79:88:70:08:69:e1:07: a8:5f:cc:b3:6d:a9:d9:b7:99:ba:ab:c8:40:a7:8c:97:eb:2f: 56:a1:ed:8a:ec:d6:9c:5e:14:e9:52:26:a6:4a:f8:6c:79:7b: 7a:05:7d:1f:a9:7a:4f:64:8c:92:3e:aa:0d:4e:5e:f4:d8:34: 66:52:d3:b6:8b:2c:84:12:e6:a2:91:7b:7b:b1:f2:ad:31:00: 99:f3:8f:29:07:b4:12:0f:44:da:ea:f3:c6:a0:6e:1b:9e:24: e7:41:b6:27:41:62:3e:c4:09:02:11:62:34:6c:12:83:84:b7: 1f:25:43:1b:bb:9e:29:dd:0b:f7:7c:0a:38:d3:98:1a:f3:0a: 8b:30:87:07:ea:4a:bc:43:09:a1:9f:32:f6:e8:81:f8:71:57: 72:9f:51:68:9a:89:f7:b1:e9:65:31:2f:fa:58:82:a7:63:d2: 5f:37:0a:d2:bd:b9:49:cc:a3:17:a7:4b:a2:e2:b6:48:1d:f4: c4:0b:c9:f2:d1:39:f3:8f:a3:a9:0e:82:19:e7:14:f5:78:ef: 94:08:ee:25:d0:ab:0d:e5:4f:b2:39:27:ec:e3:d7:1b:ef:17: 65:4e:f3:a8:76:4d:99:75:f5:61:8e:07:e6:b8:04:27:8f:25: ad:4a:cf:dc:8f:11 -----BEGIN CERTIFICATE----- MIIE3zCCA0egAwIBAgIJAOKFYvMwR+yQMA0GCSqGSIb3DQEBCwUAMIGNMQswCQYD VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJU2F1c2FsaXRv MRUwEwYDVQQKDAxIZWFsdGhlRGF0YTExFzAVBgNVBAMMDkVyaWMgSGFhcywgRFZN MSUwIwYJKoZIhvcNAQkBFhZlaGFhc0BoZWFsdGhlZGF0YTEub3JnMB4XDTIxMTAy NzE3NDIwNFoXDTIyMTAyMjE3NDIwNFowgY0xCzAJBgNVBAYTAlVTMRMwEQYDVQQI DApDYWxpZm9ybmlhMRIwEAYDVQQHDAlTYXVzYWxpdG8xFTATBgNVBAoMDEhlYWx0 aGVEYXRhMTEXMBUGA1UEAwwORXJpYyBIYWFzLCBEVk0xJTAjBgkqhkiG9w0BCQEW FmVoYWFzQGhlYWx0aGVkYXRhMS5vcmcwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAw ggGKAoIBgQDpKcSkoAM6sW21+vWTeIVOGx10MWasQy7VHid6zyqXABM+znfBnXen yU0j1FTvPmRfODoODXVuPUwDomhCHh+bclW9KM2o563cxRKEvBnaHrsjw5yNmxO5 YjERbhtHdQeqktdw3VYERR9HoxLO3FkszR292HTB4xW3yWlV3gTkMQozPScJKH3b G8Pqq6AYPJ7C4YBIlUSdBMVl3qneEfg7fuxiFfXofdTVm7rMiiG7X9z43Pfilqae isfmtRxAlRwENXrH3OvODPyL0rTnG8CsbAXYVIMmddHe4ZF9plh95sj4pMThLtcJ X/o9XHLjh7EmZygJHWEQq4PwFwZdmbcfhCmOr88H8BbUru/7V6zbsG1N1CWlndlb VznL+3IMOr8kXaHcanqfckgFV4ErnfjFJq1OIaAmsMj85xMkjyXLycLL/u5n2o6B g93/URfquOoSIGOCR25DaZzpw2k3s7oE9dMwEWXtfXgYth2bljy5tFH0GjpOkx07 j7ZT5HnxnlsCAwEAAaNAMD4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCBeAwIQYD VR0RBBowGIIWd3d3LmhlYWx0aGVkYXRhaW5jLmNvbTANBgkqhkiG9w0BAQsFAAOC AYEACuMUNq9ay++e5YC7QFO94rfzxGQnF3GklZNAXmIr7PVGdiGY2GTx/9RtHCwT KzkL+yvKojeZ9dVK8wrGViRkO/jUyZ+KcWRokUjs59ncJGRMSSRxteCQujt4hf2+ /qV+f2sMQtErwPE30vbqRYUNNNBVEQpaQx/acJDUv9v7sjHiJDqXwQ+rzj95iHAI aeEHqF/Ms22p2beZuqvIQKeMl+svVqHtiuzWnF4U6VImpkr4bHl7egV9H6l6T2SM kj6qDU5e9Ng0ZlLTtosshBLmopF7e7HyrTEAmfOPKQe0Eg9E2urzxqBuG54k50G2 J0FiPsQJAhFiNGwSg4S3HyVDG7ueKd0L93wKONOYGvMKizCHB+pKvEMJoZ8y9uiB +HFXcp9RaJqJ97HpZTEv+liCp2PSXzcK0r25ScyjF6dLouK2SB30xAvJ8tE584+j qQ6CGecU9XjvlAjuJdCrDeVPsjkn7OPXG+8XZU7zqHZNmXX1YY4H5rgEJ48lrUrP 3I8R -----END CERTIFICATE-----
10. Verify Signature using the public key or the X.509 Certificate
Alternatively:
recd_jws
'eyJhbGciOiJSUzI1NiIsImt0eSI6IlJTIiwidHlwIjoiSldUIiwieDVjIjpbIk1JSUUzekNDQTBlZ0F3SUJBZ0lKQU9LRll2TXdSK3lRTUEwR0NTcUdTSWIzRFFFQkN3VUFNSUdOTVFzd0NRWURWUVFHRXdKVlV6RVRNQkVHQTFVRUNBd0tRMkZzYVdadmNtNXBZVEVTTUJBR0ExVUVCd3dKVTJGMWMyRnNhWFJ2TVJVd0V3WURWUVFLREF4SVpXRnNkR2hsUkdGMFlURXhGekFWQmdOVkJBTU1Ea1Z5YVdNZ1NHRmhjeXdnUkZaTk1TVXdJd1lKS29aSWh2Y05BUWtCRmhabGFHRmhjMEJvWldGc2RHaGxaR0YwWVRFdWIzSm5NQjRYRFRJeE1UQXlOekUzTkRJd05Gb1hEVEl5TVRBeU1qRTNOREl3TkZvd2dZMHhDekFKQmdOVkJBWVRBbFZUTVJNd0VRWURWUVFJREFwRFlXeHBabTl5Ym1saE1SSXdFQVlEVlFRSERBbFRZWFZ6WVd4cGRHOHhGVEFUQmdOVkJBb01ERWhsWVd4MGFHVkVZWFJoTVRFWE1CVUdBMVVFQXd3T1JYSnBZeUJJWVdGekxDQkVWazB4SlRBakJna3Foa2lHOXcwQkNRRVdGbVZvWVdGelFHaGxZV3gwYUdWa1lYUmhNUzV2Y21jd2dnR2lNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJqd0F3Z2dHS0FvSUJnUURwS2NTa29BTTZzVzIxK3ZXVGVJVk9HeDEwTVdhc1F5N1ZIaWQ2enlxWEFCTSt6bmZCblhlbnlVMGoxRlR2UG1SZk9Eb09EWFZ1UFV3RG9taENIaCtiY2xXOUtNMm81NjNjeFJLRXZCbmFIcnNqdzV5Tm14TzVZakVSYmh0SGRRZXFrdGR3M1ZZRVJSOUhveExPM0Zrc3pSMjkySFRCNHhXM3lXbFYzZ1RrTVFvelBTY0pLSDNiRzhQcXE2QVlQSjdDNFlCSWxVU2RCTVZsM3FuZUVmZzdmdXhpRmZYb2ZkVFZtN3JNaWlHN1g5ejQzUGZpbHFhZWlzZm10UnhBbFJ3RU5YckgzT3ZPRFB5TDByVG5HOENzYkFYWVZJTW1kZEhlNFpGOXBsaDk1c2o0cE1UaEx0Y0pYL285WEhMamg3RW1aeWdKSFdFUXE0UHdGd1pkbWJjZmhDbU9yODhIOEJiVXJ1LzdWNnpic0cxTjFDV2xuZGxiVnpuTCszSU1PcjhrWGFIY2FucWZja2dGVjRFcm5makZKcTFPSWFBbXNNajg1eE1ranlYTHljTEwvdTVuMm82Qmc5My9VUmZxdU9vU0lHT0NSMjVEYVp6cHcyazNzN29FOWRNd0VXWHRmWGdZdGgyYmxqeTV0RkgwR2pwT2t4MDdqN1pUNUhueG5sc0NBd0VBQWFOQU1ENHdEQVlEVlIwVEJBVXdBd0VCL3pBTEJnTlZIUThFQkFNQ0JlQXdJUVlEVlIwUkJCb3dHSUlXZDNkM0xtaGxZV3gwYUdWa1lYUmhhVzVqTG1OdmJUQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FZRUFDdU1VTnE5YXkrK2U1WUM3UUZPOTRyZnp4R1FuRjNHa2xaTkFYbUlyN1BWR2RpR1kyR1R4LzlSdEhDd1RLemtMK3l2S29qZVo5ZFZLOHdyR1ZpUmtPL2pVeVorS2NXUm9rVWpzNTluY0pHUk1TU1J4dGVDUXVqdDRoZjIrL3FWK2Yyc01RdEVyd1BFMzB2YnFSWVVOTk5CVkVRcGFReC9hY0pEVXY5djdzakhpSkRxWHdRK3J6ajk1aUhBSWFlRUhxRi9NczIycDJiZVp1cXZJUUtlTWwrc3ZWcUh0aXV6V25GNFU2VkltcGtyNGJIbDdlZ1Y5SDZsNlQyU01rajZxRFU1ZTlOZzBabExUdG9zc2hCTG1vcEY3ZTdIeXJURUFtZk9QS1FlMEVnOUUydXJ6eHFCdUc1NGs1MEcySjBGaVBzUUpBaEZpTkd3U2c0UzNIeVZERzd1ZUtkMEw5M3dLT05PWUd2TUtpekNIQitwS3ZFTUpvWjh5OXVpQitIRlhjcDlSYUpxSjk3SHBaVEV2K2xpQ3AyUFNYemNLMHIyNVNjeWpGNmRMb3VLMlNCMzB4QXZKOHRFNTg0K2pxUTZDR2VjVTlYanZsQWp1SmRDckRlVlBzamtuN09QWEcrOFhaVTd6cUhaTm1YWDFZWTRINXJnRUo0OGxyVXJQM0k4UiJdfQ.eyJlbnRyeSI6W3siZnVsbFVybCI6Imh0dHA6Ly9oYXBpLmZoaXIub3JnL2Jhc2VSNC9Db25kaXRpb24vNGFjNDE3MTUtZmNiZC00MjFjLTg3OTYtOWIyYzk3MDZkZDNmIiwicmVzb3VyY2UiOnsiY2F0ZWdvcnkiOlt7ImNvZGluZyI6W3siY29kZSI6ImVuY291bnRlci1kaWFnbm9zaXMiLCJkaXNwbGF5IjoiRW5jb3VudGVyIERpYWdub3NpcyIsInN5c3RlbSI6Imh0dHA6Ly90ZXJtaW5vbG9neS5obDcub3JnL0NvZGVTeXN0ZW0vY29uZGl0aW9uLWNhdGVnb3J5In1dfV0sImNsaW5pY2FsU3RhdHVzIjp7ImNvZGluZyI6W3siY29kZSI6ImFjdGl2ZSIsInN5c3RlbSI6Imh0dHA6Ly90ZXJtaW5vbG9neS5obDcub3JnL0NvZGVTeXN0ZW0vY29uZGl0aW9uLWNsaW5pY2FsIn1dfSwiY29kZSI6eyJjb2RpbmciOlt7ImNvZGUiOiIxMjM0IiwiZGlzcGxheSI6IkV4YW1wbGl0aXMiLCJzeXN0ZW0iOiJodHRwOi8vc25vbWVkLmluZm8vc2N0In1dLCJ0ZXh0IjoiRXhhbXBsaXRpcyJ9LCJlbmNvdW50ZXIiOnsicmVmZXJlbmNlIjoiaHR0cHM6Ly9leGFtcGxlLm9yZy9FbmNvdW50ZXIvNWZlNjJjZDUtYmZjZi00ZDNiLWExZTktODBkNmY3NWQ2ZjgyIn0sImlkIjoiNGFjNDE3MTUtZmNiZC00MjFjLTg3OTYtOWIyYzk3MDZkZDNmIiwibWV0YSI6eyJsYXN0VXBkYXRlZCI6IjIwMjAtMDQtMjhUMjA6Mjg6MDAuMDA4KzAwOjAwIiwicHJvZmlsZSI6WyJodHRwOi8vaGw3Lm9yZy9maGlyL3VzL2NvcmUvU3RydWN0dXJlRGVmaW5pdGlvbi91cy1jb3JlLWNvbmRpdGlvbiJdLCJzb3VyY2UiOiIjY2FiaUpJSzUxc0QyaXo0TiIsInZlcnNpb25JZCI6IjEwIn0sIm9uc2V0RGF0ZVRpbWUiOiIyMDE4LTEwLTIxVDIxOjIyOjE1LTA3OjAwIiwicmVjb3JkZWREYXRlIjoiMjAxOC0xMC0yMVQyMToyMjoxNS0wNzowMCIsInJlc291cmNlVHlwZSI6IkNvbmRpdGlvbiIsInN1YmplY3QiOnsicmVmZXJlbmNlIjoiaHR0cHM6Ly9leGFtcGxlLm9yZy9QYXRpZW50LzA2ZTFmMGRkLTVmYmUtNDQ4MC05YmI0LTZiNTRlYzAyZDMxYiJ9LCJ2ZXJpZmljYXRpb25TdGF0dXMiOnsiY29kaW5nIjpbeyJjb2RlIjoiY29uZmlybWVkIiwic3lzdGVtIjoiaHR0cDovL3Rlcm1pbm9sb2d5LmhsNy5vcmcvQ29kZVN5c3RlbS9jb25kaXRpb24tdmVyLXN0YXR1cyJ9XX19LCJzZWFyY2giOnsibW9kZSI6Im1hdGNoIn19XSwibGluayI6W3sicmVsYXRpb24iOiJzZWxmIiwidXJsIjoiaHR0cDovL2hhcGkuZmhpci5vcmcvYmFzZVI0L0NvbmRpdGlvbj9wYXRpZW50PTA2ZTFmMGRkLTVmYmUtNDQ4MC05YmI0LTZiNTRlYzAyZDMxYiZjbGluaWNhbC1zdGF0dXM9YWN0aXZlLHJlY3VycmFuY2UscmVtaXNzaW9uIn1dLCJyZXNvdXJjZVR5cGUiOiJCdW5kbGUiLCJ0b3RhbCI6MSwidHlwZSI6InNlYXJjaHNldCJ9.rE5gfhbdbkmuYpKPb87Tpg1nRdRJTyNfWAOmXR2AA63FGKz2br_aAFtXj2UwIVHjp_AmgOZrpKmUFZnibBRcRTBUVfPWVrgRHleP1Dd1QL2qiaz0Pxw38odIVKQw88pFXBfIASsnrFMEJ_x07XQLWaXLOcEYVBb2s1SoULIW_McJCeCVKEnhrrsmNhXvAHLxYm2y8lUdTYYMH7rCM2FEIglavxLA4QI1nPv5i5ZwSOZDI1OoPtK4dHbbvggsKnAtBJL890AJ7JD9h1QTmw8vSWjydCBNilgGiyffPmfSGXFvGQ9tEcETHW0NlUEF649Zt-k71aMhkjooCsRwM9Dmb4STqO7Fy0MzWbvdi6K46W_rf77gv75Xr_cQyvSubWumRTMompgG1qOz5LbClfKHoWWyIzBxM2u7wqBukJTAIm10DSDgFg79-5oLPIDOj19VYsnLcyYFdYIx2G3gkBhcbExDdytlKGIZ8YvIEojDfNibC3wLWwNvmptBww-hPdT7'
!openssl x509 -in recd_cert.der -inform DER -pubkey -noout > recd-public-key.pem
with open('recd-public-key.pem') as f:
pem_public = f.read()
pem_public
'-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA6SnEpKADOrFttfr1k3iF\nThsddDFmrEMu1R4nes8qlwATPs53wZ13p8lNI9RU7z5kXzg6Dg11bj1MA6JoQh4f\nm3JVvSjNqOet3MUShLwZ2h67I8OcjZsTuWIxEW4bR3UHqpLXcN1WBEUfR6MSztxZ\nLM0dvdh0weMVt8lpVd4E5DEKMz0nCSh92xvD6qugGDyewuGASJVEnQTFZd6p3hH4\nO37sYhX16H3U1Zu6zIohu1/c+Nz34pamnorH5rUcQJUcBDV6x9zrzgz8i9K05xvA\nrGwF2FSDJnXR3uGRfaZYfebI+KTE4S7XCV/6PVxy44exJmcoCR1hEKuD8BcGXZm3\nH4Qpjq/PB/AW1K7v+1es27BtTdQlpZ3ZW1c5y/tyDDq/JF2h3Gp6n3JIBVeBK534\nxSatTiGgJrDI/OcTJI8ly8nCy/7uZ9qOgYPd/1EX6rjqEiBjgkduQ2mc6cNpN7O6\nBPXTMBFl7X14GLYdm5Y8ubRR9Bo6TpMdO4+2U+R58Z5bAgMBAAE=\n-----END PUBLIC KEY-----\n'
try:
verify = jws.verify(recd_jws, pem_public , algorithms=['RS256'])
print('# # ### ')
print('# # ###### ##### # ###### # ###### ##### ### ')
print('# # # # # # # # # # # ### ')
print('# # ##### # # # ##### # ##### # # # ')
print(' # # # ##### # # # # # # ')
print(' # # # # # # # # # # # ### ')
print(' # ###### # # # # # ###### ##### ### ')
print(' ')
except Exception as e:
print('# # #### ##### # # ###### ##### # ###### # ###### ##### ### # ')
print('## # # # # # # # # # # # # # # # # # ')
print('# # # # # # # # ##### # # # ##### # ##### # # ##### # ')
print('# # # # # # # # # ##### # # # # # # # # ')
print('# ## # # # # # # # # # # # # # # ### # ')
print('# # #### # ## ###### # # # # # ###### ##### # ## ')
print(' ')
print(f"not verified: {e}")
# # ### # # ###### ##### # ###### # ###### ##### ### # # # # # # # # # # # ### # # ##### # # # ##### # ##### # # # # # # ##### # # # # # # # # # # # # # # # # # ### # ###### # # # # # ###### ##### ###