Getting PKCS7 signer chain in python - python

I have PKCS7 message which is signed. It contains a data and a signing certificate (with the whole chain of trust).
I have a code which uses m2crypto to get a certificate out of it.
bio = BIO.MemoryBuffer(pkcs7message)
p7 = SMIME.PKCS7(m2.pkcs7_read_bio_der(bio._ptr()))
sk = X509.X509_Stack()
certStack = p7.get0_signers(sk)
It works. However, certStack returns only one certificate (instead of returning the whole chain of certificates.
Two questions:
Am I missing something (may be there is an option to let it know that I need the whole chain)
Are there other methods how to get the whole chain (may be using pyopenssl)?

I guess you are making a confusion between signers and certificate chain of a signer. PKCS7_get0_signers return the list of signers.
In order to building a PKCS7 message with 2 signers, you can use following steps:
Build key and certificate for first signer:
openssl genrsa -out key1.pem
openssl req -new -key key1.pem -subj "/CN=key1" | openssl x509 -req -signkey key1.pem -out cert1.pem
Build key and certificate for second signer:
openssl genrsa -out key2.pem
openssl req -new -key key2.pem -subj "/CN=key2" | openssl x509 -req -signkey key2.pem -out cert2.pem
Create an PKCS7 message using both signers :
echo "Hello" | openssl smime -sign -nodetach \
-out signature.der -outform DER \
-inkey key1.pem -signer cert1.pem -inkey key2.pem -signer cert2.pem
Then signers could be printed running your python script:
from M2Crypto import *
bio=BIO.File(open('signature.der'))
smime_object = SMIME.PKCS7(m2.pkcs7_read_bio_der(bio._ptr()))
signers = smime_object.get0_signers(X509.X509_Stack())
for cert in signers:
print(cert.get_issuer().as_text())
It give the signers' issuer:
CN=key1
CN=key2

Related

no start line:crypto/pem/pem_lib.c:745:Expecting: CERTIFICATE REQUEST

Full code below.
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes
import datetime
encryptedpassword = b"yokedicicaner31" #Kullanıcı inputu al, yokedicicaner31, kopyala yapıştır.
key = rsa.generate_private_key(public_exponent=65537,key_size=2048,backend=default_backend())
with open("rsakey.pem","wb") as f:
f.write(key.private_bytes(encoding=serialization.Encoding.PEM,
format = serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.BestAvailableEncryption(encryptedpassword)))
subject = issuer = x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME,u"TR"),
x509.NameAttribute(NameOID.LOCALITY_NAME,u"damacaner"),
x509.NameAttribute(NameOID.ORGANIZATION_NAME, u"damacana ve erikli su sevenler derneği"),
x509.NameAttribute(NameOID.COMMON_NAME, u"damacaner.tr")])
cert = x509.CertificateBuilder().subject_name(subject).issuer_name(issuer).public_key(key.public_key()).serial_number(x509.random_serial_number()).not_valid_before(datetime.datetime.utcnow()).not_valid_after(datetime.datetime.utcnow() + datetime.timedelta(days=10)
).add_extension(x509.SubjectAlternativeName([x509.DNSName(u"localhost")]),critical=False).sign(key, hashes.SHA256(), default_backend())
with open("certificate.pem","wb") as f:
f.write(cert.public_bytes(serialization.Encoding.PEM))
Full output below.
unable to load X509 request
34359836736:error:0909006C:PEM routines:get_name:no start line:crypto/pem/pem_lib.c:745:
Expecting: CERTIFICATE REQUEST
I tried to open the certificate file called certificate.pem with "openssl req -text -in certificate.pem" commands but it shooted the error that I wrote at output. This error didnt happen when I built certificate with x509.CertificateSigningRequestBuilder but I get an error when I try to build a self-signed certificate with x509.CertificateBuilder. Thanks for all help.
Check if the first line of your certificate request starts with:
-----BEGIN CERTIFICATE REQUEST-----
It is unclear what you are trying to do here, since you only describe the problems you run into and not what task you are trying to implement at the end. Anyway ...
openssl req -text -in certificate.pem
This line expects a certificate request. Your code instead creates a certificate (CertificateBuilder), not a certificate request. The latter would be created with x509.CertificateSigningRequestBuilder, which as expected works with the openssl req command above.
... I get an error when I try to build a self-signed certificate with x509.CertificateBuilder.
It does not look like you get an error when building the self-signed certificate, i.e. the code to build the certificate works. Instead you get an error when using it with openssl req. This error is expected since you did not provide a certificate request but instead a certificate. For certificates use the x509 openssl command not req:
openssl x509 -text -in certificate.pem

Extract public-key modulus from PrivateKey/CertificateRequest/Certificate in Python , with the same format as OpenSSL

using OpenSSL, i can extract the modulus of the public key from various objects with these commands:
openssl rsa -noout -modulus -in {KEY}
openssl req -noout -modulus -in {CSR}
openssl x509 -noout -modulus -in {CERT}
I am trying to replicate this within python, using cryptography or the pyopenssl package.
I can extract the public key from all of these objects in Python, but I can not figure out how to encode the modulus to match the OpenSSL commandline output -- which appears to be a base64 encoded version of a format that I can't figure out from the docs or source code of any of the 3 projects.
The RSAPublicNumbers class (link) in cryptography has what you are looking for. You can get it using to_cryptography_key method (link) of PKey class in pyopenssl.
from OpenSSL.crypto import load_certificate
from OpenSSL.crypto import FILETYPE_PEM
with open(certfile, 'rb') as fp:
cert = load_certificate(FILETYPE_PEM, fp.read())
# This gives you the modulus in integer form
modn = cert.get_pubkey().to_cryptography_key().public_numbers().n
# Convert it to hex
print('{:X}'.format(modn))

How to authenticate self signed certificate with password using Python requests

I am trying to send https request to IIS server using python request and fetch the response for parsing.Authentication is done using self signed certificates.I have generated certificate with password and key by using following commands. I am using TestPublicKey.pem and plainkey.pem as inputs to cert attribute in requests.get method. Can someone guide me how to achieve this ?
C:\OpenSSL-Win64\bin>openssl req -x509 -newkey rsa:2048 -keyout TestPrivateKey.pem -out TestPublicKey.pem -days 9999
C:\OpenSSL-Win64\bin>openssl pkcs12 -inkey TestPrivateKey.pem -in TestPublicKey.pem -export -out Test.pfx
Enter pass phrase for cTestPrivateKey.pem:
Enter Export Password:
Verifying - Enter Export Password:
C:\OpenSSL-Win64\bin>openssl rsa -in TestPrivateKey.pem -out plainkey.pem
Enter pass phrase for TestPrivateKey.pem:
writing RSA key
import requests
url = "https://10.110.20.75/REST/getxml"
r = requests.request("GET", url, verify=False,cert=('TestPublicKey.pem','plainkey.pem'))
print r.status_code
if verify is set to False , then getting 403 status_code. If verify is set to True then SSL Error exception is raised.
raise SSLError(e, request=request)
requests.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:661)
I got this resolved by trying with following openssl commands and python code.
Note: This answer is certificate without password, if any answers or comments.I am glad to see.
Open SSL commands
Generate the self signed certificate
openssl req -x509 -nodes -days 30 -newkey rsa:2048 -keyout test_Private.key -out test_certificate.cer -subj "/CN=*.hpe.com"
Convert certificate and private key to .PFX
openssl pkcs12 -export -out test_PFX.pfx -inkey test_Private.key -in test_certificate.cer -name "*.hpe.com" -passout pass:
Python code
import requests
url = "https://10.110.20.75/REST/getxml"
webServiceResponse=requests.request("GET",url,verify='test_certificate.cer)
print webServiceResponse.status_code
print webServiceResponse.json()

Python p12 to pem

I am trying to understand about openssl and certificates and also Python.
So I have this .cert.p12 file. I would like to convert it to .pem format.
I use
openssl -in input.cert.p12 -out output.pem -nodes
This creates the pem file.
How would I do the same process in Python? Take in a p12 file and covert it to a pem format?
Try using an OpenSSL for Python library like "pyOpenSSL"
https://pyopenssl.org/en/stable/api/crypto.html#pkcs12-objects
from OpenSSL import crypto
p12 = crypto.load_pkcs12(file("push.p12", 'rb').read(), [password])
# PEM formatted private key
print crypto.dump_privatekey(crypto.FILETYPE_PEM, p12.get_privatekey())
# PEM formatted certificate
print crypto.dump_certificate(crypto.FILETYPE_PEM, p12.get_certificate())
from here.

Validate Certificate using Python

I want to access a web service over HTTPS.
I have been given a client certificate (p12 file) in order to access it.
Previously we were using basic authentication.
Using python I am unsure how to access it.
I want to use httplib2
h = Http()
#h.add_credentials("testuser", "testpass")
#h.add_certificate(keyfile, certfile, '')
resp, content = h.request("https://example.com/webservice", "POST", xml_data)
print content
Now, I am quite new to SSL, Can I just call add_cert or somethign similar and give it the p12 file.
Do I need to convert it to a PEM file?
The answer to my question was IN my question
h.add_certificate(keyfile, certfile, '')
I had a pkcs12 file, I just needed to extract out the key and cert from the p12 file.
openssl pkcs12 -in file.p12 -out key.pem -nodes -nocerts
openssl pkcs12 -in file.p12 -out cert.pem -nodes -nokeys

Categories

Resources