pyopenssl can't set x509 certificate [cert must be an X509 instance] - python

I'm using pyopenssl lib and I want to generate a p12 file using their crypto.PKCS12 object apis.
so this certificate value is obtained from an API and saved in a file as below:
echo -e "-----cert text with begin & end-----" > cert.crt
which creates the file and when I run below command, there's a proper output and even when I verify it online, it shows all good:
openssl x509 -in cert.crt -text -noout
now the problem is when used the below to set the certificate to PKCS12 object, it gives an error:
from OpenSSL import crypto
p12 = crypto.PKCS12()
p12.set_certificate("/home/someuser/Documents/path/to/cert.crt")
then it throws an error:
File
"/home/someuser/.local/lib/python3.6/site-packages/OpenSSL/crypto.py",
line 2429, in set_certificate
raise TypeError("cert must be an X509 instance")
I can't understand why the lib is complaining about the certificate. Is there anything I'm missing here?

It's required to load the certificate as an X509 object before setting it to a PKCS12 container.
So in the first place you should:
Read the content of the certificate file into a buffer
Create an X509 from the buffer using load_certificate
As a result it may look like as follows:
from OpenSSL import crypto
with open("/home/someuser/Documents/path/to/cert.crt", "r") as file:
data = file.read()
x509 = crypto.load_certificate(crypto.FILETYPE_PEM, data);
p12 = crypto.PKCS12()
p12.set_certificate(x509)

Related

Generating fingerprint from X509 certificate using Pycryptodome

I'm trying to generate the same SHA1 fingerprint for a X509 certificate using pycryptodome that I get from the openssl command:
openssl x509 -noout -fingerprint -sha1 -inform pem -in certificate.crt
My certificate is in PEM format on disk
However, the code snippet below gives me a different value.
from Crypto.PublicKey import RSA
import hashlib
contents = open("/home/ubuntu/certificate.crt", "r").read().encode()
certificate = RSA.import_key(contents)
bytes = certificate.export_key("DER")
hashlib.sha1(bytes).hexdigest()
Anyone any idea what I'm doing wrong?
Still don't know how to do it using Pycryptodome, but I found there's no need for it at all. The following code fragment generates the same fingerprint as openssl does
pem = open("/home/ubuntu/certificate.crt", "r").read().encode()
pem = pem.removeprefix("-----BEGIN CERTIFICATE-----\n")
pem = pem.removesuffix("-----END CERTIFICATE-----\n")
public_bytes = base64.b64decode(pem)
sha1digest = hashlib.sha1(public_bytes).hexdigest()
fingerprint = ":".join(sha1digest[i : i + 2] for i in range(0, len(sha1digest), 2))

Python: ValueError: Could not deserialize key data

I generated a self-siged certificate like so:
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365
The file cert.pem contains my public key. I wish to extract this public key from this file.
The way I tried to do is:
f = open('cert.pem', "rb")
pem_data = f.read()
f.close()
print(pem_data)
key = serialization.load_pem_public_key(pem_data, backend=default_backend())
However, after running the code, I get this error:
ValueError: Could not deserialize key data.
As a result I unable to extract the public key.
How do I fix this in order to extract the public key?
Note in the document
A PEM block which starts with -----BEGIN CERTIFICATE----- is not a public or private key, it’s an X.509 Certificate. You can load it using load_pem_x509_certificate() and extract the public key with Certificate.public_key.
Just try this:
from cryptography.hazmat.backends import default_backend
from cryptography import x509
f = open('cert.pem', "rb")
pem_data = f.read()
f.close()
key = x509.load_pem_x509_certificate(pem_data, backend=default_backend())
public_key = key.public_key()
In the first place check cryptography library is installed if it's no like that so:
pip install cryptography
You have to create your RSA keys with OpenSSL:
openssl genrsa -out jwt-key 4096
openssl rsa -in jwt-key -pubout > jwt-key.pub
reference : enter link description here

Pyopenssl to verify the file signature

I want to verify the downloaded file's signature and cert using pyopenssl, but the documentation is not clear and Google is of no help.
I have a root CA cert in user's machine, now when user download the file then I will send a certificate and signature along with it. First I need to verify the certificate with rootCA on machine then I need to verify the signature with file
In openssl I can use following to verify the ca cert
openssl verify -CAfile <root_pem> <cert_pem>
and following to verify the file
openssl dgst <algo> -verify <cert_pub_key> -signature <signature> <file>
I am looking for equivalent way to do it using python, most preferably pyopenssl
I'm still learning about OpenSSL in general, let alone PyOpenSSL. Having said that, I was able to verify a file (your second command) in PyOpenSSL with the following:
from OpenSSL.crypto import load_publickey, FILETYPE_PEM, verify, X509
with open(file_to_verify, 'rb') as f:
file_data = f.read()
with open(signature_filename, 'rb') as f:
signature = f.read()
with open(public_key_filename) as f:
public_key_data = f.read()
# load in the publickey file, in my case, I had a .pem file.
# If the file starts with
# "-----BEGIN PUBLIC KEY-----"
# then it is of the PEM type. The only other FILETYPE is
# "FILETYPE_ASN1".
pkey = load_publickey(FILETYPE_PEM, public_key_data)
# the verify() function expects that the public key is
# wrapped in an X.509 certificate
x509 = X509()
x509.set_pubkey(pkey)
# perform the actual verification. We need the X509 object,
# the signature to verify, the file to verify, and the
# algorithm used when signing.
verify(x509, signature, file_data, 'sha256')
The verify() function will return None in the event that verification is successful (i.e. it does nothing) or it will raise an Exception if something went wrong.

Verify signed message with M2Crypto for a self signed certificate

I am trying to replicate this openssl command with M2Crypto
openssl smime -verify -in local_files/auth_data.pem.pk7 -inform PEM -certfile certificate.crt -noverify
My code looks like this:
smime = M2Crypto.SMIME.SMIME()
x509_store = M2Crypto.X509.X509_Store()
x509_store.load_info(ca_file)
smime.set_x509_store(x509_store)
x509_stack = M2Crypto.X509.X509_Stack()
x509_cert = M2Crypto.X509.load_cert(cert_file)
x509_stack.push(x509_cert)
smime.set_x509_stack(x509_stack)
p7 = M2Crypto.SMIME.load_pkcs7_bio(M2Crypto.BIO.MemoryBuffer(cipher_text))
decrypted_data = smime.verify(p7)
But I get this error in the last line:
PKCS7_Error: certificate verify error
I can't make M2Crypto to behave like openssl with '-noverify' flag.
I tried loading the same certificate in the X509_Store but it was the same result.
I took me a while but I found the answer in this source code https://pythonhosted.org/pysmime/pysmime.core-pysrc.html#verify
This is the code to allow a self signed certificate:
decrypted_data = smime.verify(p7, flags=M2Crypto.SMIME.PKCS7_NOVERIFY)

Parsing a certificate for its keyid - Python

I did a Google search but I didn't find anything that would help me on that.I'm trying to authenticate my app in Microsoft Azure, so I created some self signed certificates. They give a tutorial of how to parse the crt however it's in PowerShell. I use only Ubuntu / OS X. Here's the code:
$cer = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$cer.Import("mycer.cer")
$bin = $cer.GetRawCertData()
$base64Value = [System.Convert]::ToBase64String($bin)
$bin = $cer.GetCertHash()
$base64Thumbprint = [System.Convert]::ToBase64String($bin)
$keyid = [System.Guid]::NewGuid().ToString()
How would I go about writing the same code in Python? I have the .crt, .key, .csr, .pass.key and pkcs8_key files.
Update:
I want to extract the keyId and customKeyIdentifier from the certificates.
#philippe,
According to your description, if you want to get the certificate information using python, please refer to this simple code. I used the .cer as testing file:
import OpenSSL.crypto
f=open("tested.cer", "rb")
der = f.read()
x509=OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_ASN1, der)
print("serial number",x509.get_serial_number());
print("Issue Name",x509.get_issuer());
print("subject_name_hash",x509.subject_name_hash());
idif=x509.get_extension(0)
print("extension",x509.get_extension(0))
print("id",idif.get_data(),idif.get_short_name())
print("get_subject",x509.get_subject());
pkey = x509.get_pubkey()
print("Public Key ",pkey)
listdir=dir(pkey)
print(listdir)
print(pkey.bits())
print(pkey.type())
print(pkey._pkey)
Meanwhile, if you want to get a certificate information as keyId and customKeyIdentifier , I recommend you refer to the define of these properties of certificate and this sample. You can find the corresponding properties on that page. With these properties, you can get your certificate and its extension information. And you also can refer to this API documents. If I misunderstood, please feel free to let me know.
You don’t need neither python or powershell to parse certificates for Microsoft Azure.
The documentation describe 3 properties that are needed :
"keyCredentials": [
{
"customKeyIdentifier": "$base64Thumbprint_from_above",
"keyId": "$keyid_from_above",
"type": "AsymmetricX509Cert",
"usage": "Verify",
"value": "$base64Value_from_above"
}],
$base64Thumbprint is the base64 encoding of the sha1 hash of the certificate (in der format)
$keyid is just a random guuid
$base64Value is the base64 encoding of the whole certificate (in der format)
Generate the certificate
To generate a self-signed certificate (x509 with rsa 2048)
$ openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout privateKey.key -out certificate.crt
Compute the base64 thumbprint
$ openssl x509 -outform der -in certificate.crt | openssl dgst -binary -sha1 | openssl base64
Compute the base64
$ openssl x509 -outform der -in certificate.crt | openssl base64 -A
Generate a random uuid
$ python -c "import uuid; print(uuid.uuid4())"
I checked against results generated with powershell and there are the same

Categories