keylime: Python 3 Port - TypeError: Object of type bytes is not JSON serializable
I am running into the following issue using Python 3.6 and Python 3.7 (I thought 3.7 might have resolved this)
2019-04-18 14:02:17.059 - keylime.cloudverifier - INFO - Starting Cloud Verifier (tornado) on port 8881, use <Ctrl-C> to stop
2019-04-18 14:02:17.059 - keylime.cloudverifier_common - INFO - Setting up TLS...
2019-04-18 14:02:17.059 - keylime.cloudverifier_common - INFO - Generating a new CA in /var/lib/keylime/cv_ca and a client certificate for connecting
2019-04-18 14:02:17.060 - keylime.cloudverifier_common - INFO - use keylime_ca -d /var/lib/keylime/cv_ca to manage this CA
2019-04-18 14:02:17.060 - keylime.cloudverifier_common - WARNING - CAUTION: using default password for CA, please set private_key_pw to a strong password
Traceback (most recent call last):
File "/usr/local/bin/keylime_verifier", line 11, in <module>
load_entry_point('keylime==1.2', 'console_scripts', 'keylime_verifier')()
File "/usr/local/lib/python3.7/site-packages/keylime-1.2-py3.7.egg/keylime/cloud_verifier_tornado.py", line 495, in main
context = cloud_verifier_common.init_mtls()
File "/usr/local/lib/python3.7/site-packages/keylime-1.2-py3.7.egg/keylime/cloud_verifier_common.py", line 122, in init_mtls
ca_util.cmd_init(tls_dir)
File "/usr/local/lib/python3.7/site-packages/keylime-1.2-py3.7.egg/keylime/ca_util.py", line 153, in cmd_init
write_private(priv)
File "/usr/local/lib/python3.7/site-packages/keylime-1.2-py3.7.egg/keylime/ca_util.py", line 423, in write_private
priv_encoded = json.dumps(priv)
File "/usr/lib64/python3.7/json/__init__.py", line 231, in dumps
return _default_encoder.encode(obj)
File "/usr/lib64/python3.7/json/encoder.py", line 199, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/usr/lib64/python3.7/json/encoder.py", line 257, in iterencode
return _iterencode(o, 0)
File "/usr/lib64/python3.7/json/encoder.py", line 179, in default
raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type bytes is not JSON serializable
Set up steps:
- Install dependencies:
# dnf install python3-devel python3-pip python3-setuptools python3-tornado python3-virtualenv python3-zmq python3-yaml python3-m2crypto python3-pycryptodomex libselinux-python3
# dnf install procps libtool gcc make automake m2crypto redhat-rpm-config libselinux-python gnulib glib2-devel glib2-static uthash-devel wget which
- Run
2to3
pm code base - Install keylime
python3 setup.py install
- Start the
keylime_verifier
From what I can tell the issue starts here:
This takes the return from crypto.generate_random_key
, encodes it as base64 and attempts to load that into a JSON object, this is then refused with TypeError: Object of type bytes is not JSON serializable
Opening this issue, not as a bug, but a means to discuss a way forwards.
Tagging @jetwhiz
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Comments: 76 (75 by maintainers)
Hi @lukehinds
It looks like py3 now exports byte arrays from
base64.b64encode
instead of ASCII strings when performing its base64 encoding. We will need to convert this byte array back to ASCII for this to be JSON serializeable, using.decode('ascii')
.For https://github.com/keylime/keylime/blob/e7c153a16fa47e3b411ddbcd18f04a66b37e8898/keylime/ca_util.py#L448
Change
base64.b64encode(crypto.generate_random_key())
tobase64.b64encode(crypto.generate_random_key()).decode('ascii')
so it can be serialized.Can you see if that fixes the issue for you? We might need to do this everywhere base64 is performed …
@lukehinds – can you try
bytes(nonce, encoding="utf8").hex()
and see if that works?@jetwhiz, yep. Just encoding. Almost have all the tests passing, so will be making a PR shortly I hope.
@lukehinds – does this mean the issue you posted is fixed now? was it another encoding issue?
Hi @lukehinds
Have you updated the fork arguments for the testing script:
https://github.com/keylime/keylime/blob/94328329d2dad5d5a659168865d2e73347a48ce4/test/test_restful.py#L69-L70
This should be changed to
python3
so that the services are all kicked off with the python3 interpreter.Hi @lukehinds
Apparently py3 now returns a float when dividing two integers, so you’ll have to switch to using floor division to get py2 behavior back. Try updating this line and see if that works:
Note that this same problem will likely pop up in check_quote as well (and maybe other places): https://github.com/keylime/keylime/blob/94328329d2dad5d5a659168865d2e73347a48ce4/keylime/tpm2.py#L967-L973
Bravo! I’m sure you can breathe a sigh of relief now :p The
tpm1.py
changes should be pretty much the same astpm2.py
, and after that will be the WebApp: we’ll need to switch to using a yaml parser now it sounds, maybe https://github.com/nodeca/js-yaml? I can help with that part after everything else stabilizes.Thanks Charlie, that did it. I was using
application/x-yaml
, andtext/x-yaml
resolved it!I think sockserver is trying to return a string that is encoded with a particular encoding (e.g,. UTF-8) as a browser response for the REST call. You’ll have to export dict as a yaml string and then encode that as UTF-8 before passing this into
json_response
(such as withyaml.dump
).So for instance:
(untested, but something along those lines)
Note in the code above that you need to change the
Content-type
headers being returned in these locations (L225 and L231) totext/x-yaml; charset=utf-8
so the requesters know how to deal with the response correctly.All of the receivers must be changed as well to parse YAML instead of JSON, such as here: cloud_agent.py#L190. Probably with something like
yaml_body = yaml.load(post_body)
.Support for YAML in the
tornado_requests
class would also be a good idea: tornado_requests.py#L61 so that these calls are still possible: registrar_client.py#L104.due an update.
So we can ignore the above woes, which have all been solved by having yaml handle private.json and tmpdata.json. This works well as it accepts strings and bytes, unlike json, so we are no loner encoding and decoding every time.
I am not towards the end of the registration process. Adding this as I might have appeared to have gone quiet and taking some time over this migration.
i think it isn’t deep into the c code. It’s in the callback to provide the password. i think this is what is causing the problem https://github.com/keylime/keylime/blob/a5473dca8ce500182b95f41e2cc291d825c50075/keylime/ca_util.py#L77