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.
Related
So I have a credit card looking like smart card with a chip. This card logins on a website after the card is inserted into the card reader.
Now I have to write a program in python which can read the card and login on that website. After research on internet I found out that I need to extract :
Certificate and
Public key (since private key cannot be extracted)
from the card and then use these 2 things to create a HTTPs connection (example here) . So far I am able to extract certificate in pem format. But i cant find a way to extract key in pem format till now. I used PyKCS11 to read the card. Below is my code:
from asn1crypto import pem, x509
from PyKCS11 import *
import binascii
pkcs11 = PyKCS11Lib()
pkcs11.load(r'C:\Windows\System32\XXXX.dll')
print(pkcs11.getSlotList(tokenPresent=False))
slot = pkcs11.getSlotList(tokenPresent=False)[0]
print(pkcs11.getTokenInfo(slot))
session = pkcs11.openSession(0, CKF_SERIAL_SESSION | CKF_RW_SESSION)
session.login('123456')
result = []
result_pem = []
# find public key and print modulus
pubKey = session.findObjects([(CKA_CLASS, CKO_PUBLIC_KEY)])[0]
modulus = session.getAttributeValue(pubKey, [CKA_MODULUS])[0]
print("\nmodulus: {}".format(binascii.hexlify(bytearray(modulus))))
#find certificates
certs = session.findObjects([(CKA_CLASS, CKO_CERTIFICATE)])
for cert in certs:
cka_value, cka_id = session.getAttributeValue(cert, [CKA_VALUE, CKA_ID])
cert_der = bytes(cka_value)
cert = x509.Certificate.load(cert_der)
# Write out a PEM encoded value
cert_pem = pem.armor('CERTIFICATE', cert_der)
result.append(cert)
result_pem.append(cert_pem)
with open('cert.pem','wb') as f:
f.write(cert_pem)
print(result)
So here are my questions:
1. Is my approach right?
If yes, then how to extract public key in pem format?
How this smart card authentication actually works on client side and server side?
Public key extraxction
If you already have exported the certificate, it is probably easier to extract the public key from there, instead of from the smartcard. You can use openssl for that:
openssl x509 -in cert.pem -pubkey -out pubkey.pem -noout
Authentication
What you are trying to achieve is to open a TLS connection with mutual authentication using a client certificate. If you do this, the private key of your client certificate signs parts of the handshake to authenticate itself towards the server.
Extracting the certificate and the public key from the smartcard won't help you here. You need to find a library, which allows you to use your private key straight from your PKCS#11 token.
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)
I try to use pyOpenSSL for signed a data, I create key pair (private and publique) and certificate.
I'm a beginner with this technology, I use OpenSSl, but if you have suggestions for generate a signed message with private and public key in python, I'm take !
I want to use RSA and DSA algorithm for my tests.
I find m2Crypto, pyCrypto and other. I do not know what is the best for this.
gnupg for python and pyOpenSSl are more recent visibly.
I used function for signed a message with my private key, and I verify the data.
But when I see the function for verify the signature, in parameters I need :
private key, signature, data and digest type.
I do not know where I am wrong in this code, I find some examples, but I do not understand how this can work because the first parameters for the verify function is a X509 object "certificate is a X509 instance corresponding to the private key which generated the signature." and the second is the signature generated with the private key..
This code work perfectly with the private key :
from OpenSSL import crypto
_k = crypto.PKey()
_cert = crypto.X509()
# Create keys
_k.generate_key(crypto.TYPE_RSA, 2048)
# Add argument for create certificate
_cert.gmtime_adj_notBefore(0)
_cert.gmtime_adj_notAfter(0*365*24*60*60) #10 years expiry date
_cert.set_pubkey(_k)
_cert.sign(_k, 'sha256')
# Create key's file
with open("public_key.pem",'w') as f:
f.write(crypto.dump_publickey(crypto.FILETYPE_PEM, _k))
with open("private_key.pem",'w') as f:
f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, _k))
with open("certificate.pem",'w') as f:
f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, _cert))
#-------------------------------------------------------------------------------
# Open key and load in var
with open("private_key.pem",'r') as f:
priv_key = crypto.load_privatekey(crypto.FILETYPE_PEM, f.read())
with open("public_key.pem",'r') as f:
pub_key = crypto.load_publickey(crypto.FILETYPE_PEM, f.read())
with open("certificate.pem",'r') as f:
cert = crypto.load_certificate(crypto.FILETYPE_PEM, f.read())
# sign message 'hello world' with private key and certificate
sign = crypto.sign(priv_key, "hello world", 'sha256')
print crypto.verify(cert, sign, "hello world", 'sha256')
So, my question is, how use the public key for verify the data ?
If Bob give a public key to alice, How it checks the message with this public key ?
You have a idea ?
Thanks a lot,
Romain
I found a answer in this post.
from OpenSSL.crypto import load_publickey, FILETYPE_PEM, verify, X509
# ... code ...
x509 = X509()
x509.set_pubkey(pub_key)
# ... code ...
print verify(x509, sign, sha, 'sha256')
I'm wondering.. When I get a message, I use the public key for authenticating the transmitter, but why I have to use the signature to do the verification ? To generate the signature, I need the private key ..
Is there something I did not understand in the use of the library ?
ok I understood my mistake : Cryptography Digital signatures
source
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)
This is for a homework assignment!
I get the server's certificate using get_peer_certificate()
and the calling dump_certificate to dump the certificate in a variable. The format is PEM and looks right to me.
-----BEGIN CERTIFICATE-----
GIBBERISH................
......................
........................
-----END CERTIFICATE-----
How do I extract the server's public key from this file ('server.pubkey') and encrypt plaintext using RSA algorithm and any python library. At the time of writing this, I am using pyOpenSSL
I'd recommend using a more broad crypto library such as M2Crypto which has the X509 certificate functions as well as RSA encryption:
from M2Crypto import RSA, X509
data = ssl_sock.getpeercert(1)
# load the certificate into M2Crypto to manipulate it
cert = X509.load_cert_string(data, X509.FORMAT_DER)
pub_key = cert.get_pubkey()
rsa_key = pub_key.get_rsa()
cipher = rsa_key.public_encrypt('plaintext', RSA.pkcs1_padding)
from OpenSSL import crypto
crtObj = crypto.load_certificate(crypto.FILETYPE_ASN1, config.x509_certificate)
pubKeyObject = crtObj.get_pubkey()
pubKeyString = crypto.dump_publickey(crypto.FILETYPE_PEM, pubKeyObject)
from cryptography.x509 import load_pem_x509_certificate
cert_str = b"-----BEGIN CERTIFICATE-----MIIDETCCAfm..."
cert_obj = load_pem_x509_certificate(cert_str)
public_key = cert_obj.public_key()
private_key = cert_obj.private_key()
Source: https://pyjwt.readthedocs.io/en/stable/faq.html
Note that OpenSSL library is not recommended to be used for those purposes. Instead, cryptography library is pointed. It is maintained and regularly updated.
Assuming you have the certificate in Pem format, the following code block will give you public key in string.
from cryptography import x509
from cryptography.hazmat.primitives import serialization
def read_pub_key_from_cert()
# Read certificate file.
with open("tls.crt") as certificate:
cert = certificate.read()
# Convert it into bytes.
cert_in_bytes = bytes(cert, 'utf-8')
# Create x509 certificate object.
cert_obj = x509.load_pem_x509_certificate(cert_in_bytes)
# Create Public key object.
public_key_obj = cert_obj.public_key()
# Convert Public key object into Pem format in bytes.
public_pem = public_key_obj.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
# Convert Public key into string.
pub_key_string = public_pem.decode("utf-8")
return(pub_key_string)