What is special for a private key to be PEM-formatted?

馋奶兔 提交于 2019-12-11 02:13:15

问题


I am trying to use the Google API with a oAuth service account, with Python 3.4. One of the steps is to generate a JSON Web Token, for which I use PyJWT.

My code for the generation is the following:

# opening the certificate downloaded from the Google API console
# it is password protected by the standard password ('notasecret')
p12 = OpenSSL.crypto.load_pkcs12(open('certfromgoogle.p12', 'rb').read(), 'notasecret')

# extracting the private key from the certificate and dumping it to a PEM
# format (FILETYPE_PEM)
private_key = OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, p12.get_privatekey())

# at that stage, private_key contains the private key as
# b'-----BEGIN PRIVATE KEY-----\nMIICdg(...)FIyw==\n-----END PRIVATE KEY-----\n'

# trying to get the JWT
encoded = jwt.encode(claim, private_key, algorithm='RS256', headers={"alg": "RS256", "typ": "JWT"})

The call to jwt.encode crashes with TypeError: Expecting a PEM-formatted key. The full traceback:

Traceback (most recent call last):
  File "C:/Users/w_000/PycharmProjects/syncmagazines/testcrypto.py", line 20, in <module>
    encoded = jwt.encode(claim, private_key, algorithm='RS256', headers={"alg": "RS256", "typ": "JWT"})
  File "C:\Python34\lib\site-packages\jwt\api.py", line 118, in encode
    key = alg_obj.prepare_key(key)
  File "C:\Python34\lib\site-packages\jwt\algorithms.py", line 170, in prepare_key
    raise TypeError('Expecting a PEM-formatted key.')
TypeError: Expecting a PEM-formatted key.

The private key, however, seems to be extracted correctly.

Why isn't this format correct?


回答1:


Having examined the PyJWT source code, it is apparent that the library expects the PEM data to be a string type, but you are providing a bytestring (evident in your question by the b'...' literal). The offending function is prepare_key, along with the definition of acceptable string types.

You must decode the private key data into the native str type:

private_key_bytes = OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, p12.get_privatekey())
private_key = private_key_bytes.decode('utf-8')

This only seems to be required for Python 3, but the above code should work for Python 2 as well.




回答2:


What is special for a private key to be PEM-formatted?

PEM is a presentation encoding. It has the familiar -----BEGIN XXX----- and -----END XXX-----.

I think BEGIN PRIVATE KEY is a PKCS #8 private key. Perhaps the library wants a PKCS #1 private key with BEGIN RSA PRIVATE KEY. BEGIN RSA PRIVATE KEY is also known as a Traditional key encoding (as opposed to PKCS #8).

You should check the relevant documentation and provide the key in the correct format.

To convert from a traditional key to a PKCS #8 key, see the OpenSSL man pages for pkcs(1). -topk8 is of interest. Also see How to convert PKCS#8-formatted PEM private key to the tranditional format?

To convert from a PKCS #8 key to a a traditional key, see the OpenSSL man pages for rsa(1). Also see Convert PEM traditional private key to PKCS8 private key?



来源:https://stackoverflow.com/questions/30102007/what-is-special-for-a-private-key-to-be-pem-formatted

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!