问题
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